Make Start/Stop methods of ProcessState

This commit is contained in:
Hannes Hörl 2018-01-12 17:00:43 +00:00
parent ba978619bc
commit 2c1fea7616
4 changed files with 109 additions and 101 deletions

View File

@ -6,8 +6,6 @@ import (
"net/url"
"os/exec"
"k8s.io/kubectl/pkg/framework/test/internal"
)
@ -38,16 +36,15 @@ type APIServer struct {
StopTimeout time.Duration
StartTimeout time.Duration
processState internal.ProcessState
processState *internal.ProcessState
}
// Start starts the apiserver, waits for it to come up, and returns an error, if occoured.
func (s *APIServer) Start() error {
var err error
err = s.ensureInitialized()
if err != nil {
return err
if s.Etcd == nil {
s.Etcd = &Etcd{}
}
err = s.Etcd.Start()
@ -55,32 +52,6 @@ func (s *APIServer) Start() error {
return err
}
args := []string{
"--authorization-mode=Node,RBAC",
"--runtime-config=admissionregistration.k8s.io/v1alpha1",
"--v=3", "--vmodule=",
"--admission-control=Initializers,NamespaceLifecycle,LimitRanger,ServiceAccount,SecurityContextDeny,DefaultStorageClass,DefaultTolerationSeconds,GenericAdmissionWebhook,ResourceQuota",
"--admission-control-config-file=",
"--bind-address=0.0.0.0",
"--storage-backend=etcd3",
fmt.Sprintf("--etcd-servers=%s", s.Etcd.processState.URL.String()),
fmt.Sprintf("--cert-dir=%s", s.processState.Dir),
fmt.Sprintf("--insecure-port=%s", s.processState.URL.Port()),
fmt.Sprintf("--insecure-bind-address=%s", s.processState.URL.Hostname()),
}
s.processState.Session, err = internal.Start(
exec.Command(s.processState.Path, args...),
fmt.Sprintf("Serving insecurely on %s", s.processState.URL.Host),
s.processState.StartTimeout,
)
return err
}
func (s *APIServer) ensureInitialized() error {
var err error
s.processState, err = internal.NewProcessState(
"kube-apiserver",
s.Path,
@ -92,21 +63,31 @@ func (s *APIServer) ensureInitialized() error {
return err
}
if s.Etcd == nil {
s.Etcd = &Etcd{}
s.processState.Args = []string{
"--authorization-mode=Node,RBAC",
"--runtime-config=admissionregistration.k8s.io/v1alpha1",
"--v=3", "--vmodule=",
"--admission-control=Initializers,NamespaceLifecycle,LimitRanger,ServiceAccount,SecurityContextDeny,DefaultStorageClass,DefaultTolerationSeconds,GenericAdmissionWebhook,ResourceQuota",
"--admission-control-config-file=",
"--bind-address=0.0.0.0",
"--storage-backend=etcd3",
fmt.Sprintf("--etcd-servers=%s", s.Etcd.processState.URL.String()),
fmt.Sprintf("--cert-dir=%s", s.processState.Dir),
fmt.Sprintf("--insecure-port=%s", s.processState.URL.Port()),
fmt.Sprintf("--insecure-bind-address=%s", s.processState.URL.Hostname()),
}
if err != nil {
return err
}
return nil
s.processState.Start(fmt.Sprintf("Serving insecurely on %s", s.processState.URL.Host))
return err
}
// Stop stops this process gracefully, waits for its termination, and cleans up the cert directory.
func (s *APIServer) Stop() error {
err := internal.Stop(
s.processState.Session,
s.processState.StopTimeout,
s.processState.Dir,
s.processState.DirNeedsCleaning,
)
err := s.processState.Stop()
if err != nil {
return err
}

View File

@ -2,7 +2,6 @@ package test
import (
"fmt"
"os/exec"
"time"
"net/url"
@ -21,35 +20,13 @@ type Etcd struct {
StopTimeout time.Duration
StartTimeout time.Duration
processState internal.ProcessState
processState *internal.ProcessState
}
// Start starts the etcd, waits for it to come up, and returns an error, if occoured.
func (e *Etcd) Start() error {
err := e.ensureInitialized()
if err != nil {
return err
}
args := []string{
"--debug",
"--listen-peer-urls=http://localhost:0",
fmt.Sprintf("--advertise-client-urls=%s", e.processState.URL),
fmt.Sprintf("--listen-client-urls=%s", e.processState.URL),
fmt.Sprintf("--data-dir=%s", e.processState.Dir),
}
e.processState.Session, err = internal.Start(
exec.Command(e.processState.Path, args...),
fmt.Sprintf("serving insecure client requests on %s", e.processState.URL.Hostname()),
e.processState.StartTimeout,
)
return err
}
func (e *Etcd) ensureInitialized() error {
var err error
e.processState, err = internal.NewProcessState(
"etcd",
e.Path,
@ -57,15 +34,22 @@ func (e *Etcd) ensureInitialized() error {
e.DataDir,
e.StartTimeout, e.StopTimeout,
)
return err
if err != nil {
return err
}
e.processState.Args = []string{
"--debug",
"--listen-peer-urls=http://localhost:0",
fmt.Sprintf("--advertise-client-urls=%s", e.processState.URL),
fmt.Sprintf("--listen-client-urls=%s", e.processState.URL),
fmt.Sprintf("--data-dir=%s", e.processState.Dir),
}
return e.processState.Start(fmt.Sprintf("serving insecure client requests on %s", e.processState.URL.Hostname()))
}
// Stop stops this process gracefully, waits for its termination, and cleans up the data directory.
func (e *Etcd) Stop() error {
return internal.Stop(
e.processState.Session,
e.processState.StopTimeout,
e.processState.Dir,
e.processState.DirNeedsCleaning,
)
return e.processState.Stop()
}

View File

@ -21,10 +21,56 @@ type ProcessState struct {
Path string
StopTimeout time.Duration
StartTimeout time.Duration
Session *gexec.Session
Session *gexec.Session // TODO private?
Args []string
}
func Start(command *exec.Cmd, startMessage string, startTimeout time.Duration) (*gexec.Session, error) {
// TODO explore ProcessInputs, Defaulter, ProcessState, ...
//type ProcessInput struct {
// URL *url.URL
// Dir string
// DirNeedsCleaning bool
// Path string
// StopTimeout time.Duration
// StartTimeout time.Duration
//}
//
//type ProcessState2 struct {
// ProcessInput
// Args []string
// StartString string
//}
//
//func DoDefaulting(url, *url.URL) ProcessInput {
// return ProcessInput{}
//}
//
//func NewProcessState(input ProcessInput, args []string, startthing string) ProcessState {
// return ProcessState2{input, args, startthing}
//}
func (ps *ProcessState) Start(startMessage string) (err error) {
ps.Session, err = Start(
ps.Path,
ps.Args,
startMessage,
ps.StartTimeout,
)
return
}
func (ps *ProcessState) Stop() error {
return Stop(
ps.Session,
ps.StopTimeout,
ps.Dir,
ps.DirNeedsCleaning,
)
}
func Start(path string, args []string, startMessage string, startTimeout time.Duration) (*gexec.Session, error) {
command := exec.Command(path, args...)
stdErr := gbytes.NewBuffer()
detectedStart := stdErr.Detect(startMessage)
timedOut := time.After(startTimeout)
@ -73,12 +119,12 @@ func NewProcessState(
dir string,
startTimeout time.Duration,
stopTimeout time.Duration,
) (ProcessState, error) {
) (*ProcessState, error) {
if path == "" && symbolicName == "" {
return ProcessState{}, fmt.Errorf("Either a path or a symbolic name need to be set")
return nil, fmt.Errorf("Either a path or a symbolic name need to be set")
}
state := ProcessState{
state := &ProcessState{
Path: path,
URL: listenURL,
Dir: dir,
@ -95,7 +141,7 @@ func NewProcessState(
am := &AddressManager{}
port, host, err := am.Initialize()
if err != nil {
return ProcessState{}, err
return nil, err
}
state.URL = &url.URL{
Scheme: "http",
@ -106,7 +152,7 @@ func NewProcessState(
if dir == "" {
newDir, err := ioutil.TempDir("", "k8s_test_framework_")
if err != nil {
return ProcessState{}, err
return nil, err
}
state.Dir = newDir
state.DirNeedsCleaning = true

View File

@ -15,17 +15,15 @@ import (
var _ = Describe("Start", func() {
var (
command *exec.Cmd
timeout time.Duration
)
BeforeEach(func() {
command = getSimpleCommand()
timeout = 200 * time.Millisecond
})
It("can start a process", func() {
timeout = 5 * time.Second
session, err := Start(command, "loop 3", timeout)
session, err := Start("bash", simpleBashScript, "loop 3", timeout)
Expect(err).NotTo(HaveOccurred())
Consistently(session.ExitCode).Should(BeNumerically("==", -1))
@ -33,7 +31,7 @@ var _ = Describe("Start", func() {
Context("when process takes too long to start", func() {
It("returns an timeout error", func() {
session, err := Start(command, "loop 3000", timeout)
session, err := Start("bash", simpleBashScript, "loop 3000", timeout)
Expect(err).To(MatchError(ContainSubstring("timeout")))
Eventually(session.ExitCode, 10).Should(BeNumerically("==", 143))
@ -41,11 +39,8 @@ var _ = Describe("Start", func() {
})
Context("when command cannot be started", func() {
BeforeEach(func() {
command = exec.Command("/notexistent")
})
It("propagates the error", func() {
_, err := Start(command, "does not matter", timeout)
_, err := Start("/notexeistent", []string{}, "does not matter", timeout)
Expect(os.IsNotExist(err)).To(BeTrue())
})
@ -211,17 +206,19 @@ var _ = Describe("NewProcessState", func() {
})
func getSimpleCommand() *exec.Cmd {
return exec.Command(
"bash", "-c",
`
i=0
while true
do
echo "loop $i" >&2
let 'i += 1'
sleep 0.2
done
`,
)
var simpleBashScript = []string{
"-c",
`
i=0
while true
do
echo "loop $i" >&2
let 'i += 1'
sleep 0.2
done
`,
}
func getSimpleCommand() *exec.Cmd {
return exec.Command("bash", simpleBashScript...)
}