kubernetes/test/e2e_node/e2e_service.go
Phillip Wittrock a3623c0c14 Refactor node e2e tests
- Add Makefile targets
- Start services in the test harness and connect locally
- Build test into binary and copy to remote host to start services
- Use tar to copy binaries to remote hosts to simplify design
2016-02-22 20:06:15 -08:00

186 lines
4.5 KiB
Go

/*
Copyright 2016 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package e2e_node
import (
"bytes"
"flag"
"fmt"
"io/ioutil"
"net/http"
"os"
"os/exec"
"strings"
"time"
"github.com/golang/glog"
)
var serverStartTimeout = flag.Duration("server-start-timeout", time.Second*30, "Time to wait for each server to become healthy.")
type e2eService struct {
etcdCmd *exec.Cmd
etcdCombinedOut bytes.Buffer
etcdDataDir string
apiServerCmd *exec.Cmd
apiServerCombinedOut bytes.Buffer
kubeletCmd *exec.Cmd
kubeletCombinedOut bytes.Buffer
}
func newE2eService() *e2eService {
return &e2eService{}
}
func (es *e2eService) start() error {
if _, err := getK8sBin("kubelet"); err != nil {
return err
}
if _, err := getK8sBin("kube-apiserver"); err != nil {
return err
}
cmd, err := es.startEtcd()
if err != nil {
return err
}
es.etcdCmd = cmd
cmd, err = es.startApiServer()
if err != nil {
return err
}
es.apiServerCmd = cmd
cmd, err = es.startKubeletServer()
if err != nil {
return err
}
es.kubeletCmd = cmd
return nil
}
func (es *e2eService) stop() {
if es.kubeletCmd != nil {
err := es.kubeletCmd.Process.Kill()
if err != nil {
glog.Errorf("Failed to stop kubelet.\n%v", err)
}
}
if es.apiServerCmd != nil {
err := es.apiServerCmd.Process.Kill()
if err != nil {
glog.Errorf("Failed to stop be-apiserver.\n%v", err)
}
}
if es.etcdCmd != nil {
err := es.etcdCmd.Process.Kill()
if err != nil {
glog.Errorf("Failed to stop etcd.\n%v", err)
}
}
if es.etcdDataDir != "" {
err := os.RemoveAll(es.etcdDataDir)
if err != nil {
glog.Errorf("Failed to delete etcd data directory %s.\n%v", es.etcdDataDir, err)
}
}
}
func (es *e2eService) startEtcd() (*exec.Cmd, error) {
dataDir, err := ioutil.TempDir("", "node-e2e")
if err != nil {
return nil, err
}
es.etcdDataDir = dataDir
return es.startServer(healthCheckCommand{
combinedOut: &es.etcdCombinedOut,
healthCheckUrl: "http://127.0.0.1:4001/v2/keys",
command: "etcd",
args: []string{"--data-dir", dataDir, "--name", "e2e-node"},
})
}
func (es *e2eService) startApiServer() (*exec.Cmd, error) {
return es.startServer(
healthCheckCommand{
combinedOut: &es.apiServerCombinedOut,
healthCheckUrl: "http://127.0.0.1:8080/healthz",
command: "sudo",
args: []string{getApiServerBin(),
"--v", "2", "--logtostderr", "--log_dir", "./",
"--etcd-servers", "http://127.0.0.1:4001",
"--insecure-bind-address", "0.0.0.0",
"--service-cluster-ip-range", "10.0.0.1/24",
"--kubelet-port", "10250"},
})
}
func (es *e2eService) startKubeletServer() (*exec.Cmd, error) {
return es.startServer(
healthCheckCommand{
combinedOut: &es.kubeletCombinedOut,
healthCheckUrl: "http://127.0.0.1:10255/healthz",
command: "sudo",
args: []string{getKubeletServerBin(),
"--v", "2", "--logtostderr", "--log_dir", "./",
"--api-servers", "http://127.0.0.1:8080",
"--address", "0.0.0.0",
"--port", "10250"},
})
}
func (es *e2eService) startServer(hcc healthCheckCommand) (*exec.Cmd, error) {
cmdErrorChan := make(chan error)
cmd := exec.Command(hcc.command, hcc.args...)
cmd.Stdout = hcc.combinedOut
cmd.Stderr = hcc.combinedOut
go func() {
err := cmd.Run()
if err != nil {
cmdErrorChan <- fmt.Errorf("%v Exited with status %v. Output:\n%s", hcc, err, *hcc.combinedOut)
}
close(cmdErrorChan)
}()
endTime := time.Now().Add(*serverStartTimeout)
for endTime.After(time.Now()) {
select {
case err := <-cmdErrorChan:
return nil, err
case <-time.After(time.Second):
resp, err := http.Get(hcc.healthCheckUrl)
if err == nil && resp.StatusCode == http.StatusOK {
return cmd, nil
}
}
}
return nil, fmt.Errorf("Timeout waiting for service %v", hcc)
}
type healthCheckCommand struct {
healthCheckUrl string
command string
args []string
combinedOut *bytes.Buffer
}
func (hcc *healthCheckCommand) String() string {
return fmt.Sprintf("`%s %s` %s", hcc.command, strings.Join(hcc.args, " "), hcc.healthCheckUrl)
}