Switch to github.com/golang/dep for vendoring
Signed-off-by: Mrunal Patel <mrunalp@gmail.com>
This commit is contained in:
parent
d6ab91be27
commit
8e5b17cf13
15431 changed files with 3971413 additions and 8881 deletions
56
vendor/k8s.io/kubernetes/test/e2e_node/services/BUILD
generated
vendored
Normal file
56
vendor/k8s.io/kubernetes/test/e2e_node/services/BUILD
generated
vendored
Normal file
|
@ -0,0 +1,56 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"apiserver.go",
|
||||
"etcd.go",
|
||||
"internal_services.go",
|
||||
"kubelet.go",
|
||||
"namespace_controller.go",
|
||||
"server.go",
|
||||
"services.go",
|
||||
"util.go",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//cmd/kube-apiserver/app:go_default_library",
|
||||
"//cmd/kube-apiserver/app/options:go_default_library",
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/client/clientset_generated/clientset:go_default_library",
|
||||
"//pkg/client/restclient:go_default_library",
|
||||
"//pkg/client/typed/dynamic:go_default_library",
|
||||
"//pkg/controller/namespace:go_default_library",
|
||||
"//pkg/util/config:go_default_library",
|
||||
"//test/e2e/framework:go_default_library",
|
||||
"//test/e2e_node/builder:go_default_library",
|
||||
"//vendor:github.com/coreos/etcd/etcdserver",
|
||||
"//vendor:github.com/coreos/etcd/etcdserver/api/v2http",
|
||||
"//vendor:github.com/coreos/etcd/pkg/transport",
|
||||
"//vendor:github.com/coreos/etcd/pkg/types",
|
||||
"//vendor:github.com/coreos/pkg/capnslog",
|
||||
"//vendor:github.com/golang/glog",
|
||||
"//vendor:github.com/kardianos/osext",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
89
vendor/k8s.io/kubernetes/test/e2e_node/services/apiserver.go
generated
vendored
Normal file
89
vendor/k8s.io/kubernetes/test/e2e_node/services/apiserver.go
generated
vendored
Normal file
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
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 services
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
apiserver "k8s.io/kubernetes/cmd/kube-apiserver/app"
|
||||
"k8s.io/kubernetes/cmd/kube-apiserver/app/options"
|
||||
)
|
||||
|
||||
const (
|
||||
clusterIPRange = "10.0.0.1/24"
|
||||
apiserverClientURL = "http://localhost:8080"
|
||||
apiserverHealthCheckURL = apiserverClientURL + "/healthz"
|
||||
)
|
||||
|
||||
// APIServer is a server which manages apiserver.
|
||||
type APIServer struct{}
|
||||
|
||||
// NewAPIServer creates an apiserver.
|
||||
func NewAPIServer() *APIServer {
|
||||
return &APIServer{}
|
||||
}
|
||||
|
||||
// Start starts the apiserver, returns when apiserver is ready.
|
||||
func (a *APIServer) Start() error {
|
||||
config := options.NewServerRunOptions()
|
||||
config.Etcd.StorageConfig.ServerList = []string{getEtcdClientURL()}
|
||||
// TODO: Current setup of etcd in e2e-node tests doesn't support etcd v3
|
||||
// protocol. We should migrate it to use the same infrastructure as all
|
||||
// other tests (pkg/storage/etcd/testing).
|
||||
config.Etcd.StorageConfig.Type = "etcd2"
|
||||
_, ipnet, err := net.ParseCIDR(clusterIPRange)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
config.ServiceClusterIPRange = *ipnet
|
||||
config.AllowPrivileged = true
|
||||
errCh := make(chan error)
|
||||
go func() {
|
||||
defer close(errCh)
|
||||
err := apiserver.Run(config)
|
||||
if err != nil {
|
||||
errCh <- fmt.Errorf("run apiserver error: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
err = readinessCheck("apiserver", []string{apiserverHealthCheckURL}, errCh)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Stop stops the apiserver. Currently, there is no way to stop the apiserver.
|
||||
// The function is here only for completion.
|
||||
func (a *APIServer) Stop() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
const apiserverName = "apiserver"
|
||||
|
||||
func (a *APIServer) Name() string {
|
||||
return apiserverName
|
||||
}
|
||||
|
||||
func getAPIServerClientURL() string {
|
||||
return apiserverClientURL
|
||||
}
|
||||
|
||||
func getAPIServerHealthCheckURL() string {
|
||||
return apiserverHealthCheckURL
|
||||
}
|
165
vendor/k8s.io/kubernetes/test/e2e_node/services/etcd.go
generated
vendored
Normal file
165
vendor/k8s.io/kubernetes/test/e2e_node/services/etcd.go
generated
vendored
Normal file
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
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 services
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/coreos/etcd/etcdserver"
|
||||
"github.com/coreos/etcd/etcdserver/api/v2http"
|
||||
"github.com/coreos/etcd/pkg/transport"
|
||||
"github.com/coreos/etcd/pkg/types"
|
||||
"github.com/coreos/pkg/capnslog"
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
// TODO(random-liu): Add service interface to manage services with the same behaviour.
|
||||
|
||||
func init() {
|
||||
// github.com/coreos/etcd/etcdserver/api package is too spammy, set the log level to NOTICE.
|
||||
capnslog.MustRepoLogger("github.com/coreos/etcd/etcdserver/api").SetRepoLogLevel(capnslog.NOTICE)
|
||||
}
|
||||
|
||||
// All following configurations are got from etcd source code.
|
||||
// TODO(random-liu): Use embed.NewConfig after etcd3 is supported.
|
||||
const (
|
||||
etcdName = "etcd"
|
||||
clientURLStr = "http://localhost:4001" // clientURL has listener created and handles etcd API traffic
|
||||
peerURLStr = "http://localhost:7001" // peerURL does't have listener created, it is used to pass Etcd validation
|
||||
snapCount = etcdserver.DefaultSnapCount
|
||||
maxSnapFiles = 5
|
||||
maxWALFiles = 5
|
||||
tickMs = 100
|
||||
electionTicks = 10
|
||||
etcdHealthCheckURL = clientURLStr + "/v2/keys/" // Trailing slash is required,
|
||||
)
|
||||
|
||||
// EtcdServer is a server which manages etcd.
|
||||
type EtcdServer struct {
|
||||
*etcdserver.EtcdServer
|
||||
config *etcdserver.ServerConfig
|
||||
clientListen net.Listener
|
||||
}
|
||||
|
||||
// NewEtcd creates a new default etcd server using 'dataDir' for persistence.
|
||||
func NewEtcd(dataDir string) *EtcdServer {
|
||||
clientURLs, err := types.NewURLs([]string{clientURLStr})
|
||||
if err != nil {
|
||||
glog.Fatalf("Failed to parse client url %q: %v", clientURLStr, err)
|
||||
}
|
||||
peerURLs, err := types.NewURLs([]string{peerURLStr})
|
||||
if err != nil {
|
||||
glog.Fatalf("Failed to parse peer url %q: %v", peerURLStr, err)
|
||||
}
|
||||
|
||||
config := &etcdserver.ServerConfig{
|
||||
Name: etcdName,
|
||||
ClientURLs: clientURLs,
|
||||
PeerURLs: peerURLs,
|
||||
DataDir: dataDir,
|
||||
InitialPeerURLsMap: map[string]types.URLs{etcdName: peerURLs},
|
||||
NewCluster: true,
|
||||
SnapCount: snapCount,
|
||||
MaxSnapFiles: maxSnapFiles,
|
||||
MaxWALFiles: maxWALFiles,
|
||||
TickMs: tickMs,
|
||||
ElectionTicks: electionTicks,
|
||||
}
|
||||
|
||||
return &EtcdServer{
|
||||
config: config,
|
||||
}
|
||||
}
|
||||
|
||||
// Start starts the etcd server and listening for client connections
|
||||
func (e *EtcdServer) Start() error {
|
||||
var err error
|
||||
e.EtcdServer, err = etcdserver.NewServer(e.config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// create client listener, there should be only one url
|
||||
e.clientListen, err = createListener(e.config.ClientURLs[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// start etcd
|
||||
e.EtcdServer.Start()
|
||||
|
||||
// setup client listener
|
||||
ch := v2http.NewClientHandler(e.EtcdServer, e.config.ReqTimeout())
|
||||
errCh := make(chan error)
|
||||
go func(l net.Listener) {
|
||||
defer close(errCh)
|
||||
srv := &http.Server{
|
||||
Handler: ch,
|
||||
ReadTimeout: 5 * time.Minute,
|
||||
}
|
||||
// Serve always returns a non-nil error.
|
||||
errCh <- srv.Serve(l)
|
||||
}(e.clientListen)
|
||||
|
||||
err = readinessCheck("etcd", []string{etcdHealthCheckURL}, errCh)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Stop closes all connections and stops the Etcd server
|
||||
func (e *EtcdServer) Stop() error {
|
||||
if e.EtcdServer != nil {
|
||||
e.EtcdServer.Stop()
|
||||
}
|
||||
if e.clientListen != nil {
|
||||
err := e.clientListen.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Name returns the server's unique name
|
||||
func (e *EtcdServer) Name() string {
|
||||
return etcdName
|
||||
}
|
||||
|
||||
func createListener(url url.URL) (net.Listener, error) {
|
||||
l, err := net.Listen("tcp", url.Host)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
l, err = transport.NewKeepAliveListener(l, url.Scheme, &tls.Config{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return l, nil
|
||||
}
|
||||
|
||||
func getEtcdClientURL() string {
|
||||
return clientURLStr
|
||||
}
|
||||
|
||||
func getEtcdHealthCheckURL() string {
|
||||
return etcdHealthCheckURL
|
||||
}
|
141
vendor/k8s.io/kubernetes/test/e2e_node/services/internal_services.go
generated
vendored
Normal file
141
vendor/k8s.io/kubernetes/test/e2e_node/services/internal_services.go
generated
vendored
Normal file
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
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 services
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
// e2eService manages e2e services in current process.
|
||||
type e2eServices struct {
|
||||
rmDirs []string
|
||||
// statically linked e2e services
|
||||
etcdServer *EtcdServer
|
||||
apiServer *APIServer
|
||||
nsController *NamespaceController
|
||||
}
|
||||
|
||||
func newE2EServices() *e2eServices {
|
||||
return &e2eServices{}
|
||||
}
|
||||
|
||||
// run starts all e2e services and wait for the termination signal. Once receives the
|
||||
// termination signal, it will stop the e2e services gracefully.
|
||||
func (es *e2eServices) run() error {
|
||||
defer es.stop()
|
||||
if err := es.start(); err != nil {
|
||||
return err
|
||||
}
|
||||
// Wait until receiving a termination signal.
|
||||
waitForTerminationSignal()
|
||||
return nil
|
||||
}
|
||||
|
||||
// start starts the tests embedded services or returns an error.
|
||||
func (es *e2eServices) start() error {
|
||||
glog.Info("Starting e2e services...")
|
||||
err := es.startEtcd()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = es.startApiServer()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = es.startNamespaceController()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
glog.Info("E2E services started.")
|
||||
return nil
|
||||
}
|
||||
|
||||
// stop stops the embedded e2e services.
|
||||
func (es *e2eServices) stop() {
|
||||
glog.Info("Stopping e2e services...")
|
||||
// TODO(random-liu): Use a loop to stop all services after introducing
|
||||
// service interface.
|
||||
glog.Info("Stopping namespace controller")
|
||||
if es.nsController != nil {
|
||||
if err := es.nsController.Stop(); err != nil {
|
||||
glog.Errorf("Failed to stop %q: %v", es.nsController.Name(), err)
|
||||
}
|
||||
}
|
||||
|
||||
glog.Info("Stopping API server")
|
||||
if es.apiServer != nil {
|
||||
if err := es.apiServer.Stop(); err != nil {
|
||||
glog.Errorf("Failed to stop %q: %v", es.apiServer.Name(), err)
|
||||
}
|
||||
}
|
||||
|
||||
glog.Info("Stopping etcd")
|
||||
if es.etcdServer != nil {
|
||||
if err := es.etcdServer.Stop(); err != nil {
|
||||
glog.Errorf("Failed to stop %q: %v", es.etcdServer.Name(), err)
|
||||
}
|
||||
}
|
||||
|
||||
for _, d := range es.rmDirs {
|
||||
glog.Info("Deleting directory %v", d)
|
||||
err := os.RemoveAll(d)
|
||||
if err != nil {
|
||||
glog.Errorf("Failed to delete directory %s.\n%v", d, err)
|
||||
}
|
||||
}
|
||||
|
||||
glog.Info("E2E services stopped.")
|
||||
}
|
||||
|
||||
// startEtcd starts the embedded etcd instance or returns an error.
|
||||
func (es *e2eServices) startEtcd() error {
|
||||
glog.Info("Starting etcd")
|
||||
// Create data directory in current working space.
|
||||
dataDir, err := ioutil.TempDir(".", "etcd")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Mark the dataDir as directories to remove.
|
||||
es.rmDirs = append(es.rmDirs, dataDir)
|
||||
es.etcdServer = NewEtcd(dataDir)
|
||||
return es.etcdServer.Start()
|
||||
}
|
||||
|
||||
// startApiServer starts the embedded API server or returns an error.
|
||||
func (es *e2eServices) startApiServer() error {
|
||||
glog.Info("Starting API server")
|
||||
es.apiServer = NewAPIServer()
|
||||
return es.apiServer.Start()
|
||||
}
|
||||
|
||||
// startNamespaceController starts the embedded namespace controller or returns an error.
|
||||
func (es *e2eServices) startNamespaceController() error {
|
||||
glog.Info("Starting namespace controller")
|
||||
es.nsController = NewNamespaceController()
|
||||
return es.nsController.Start()
|
||||
}
|
||||
|
||||
// getServicesHealthCheckURLs returns the health check urls for the internal services.
|
||||
func getServicesHealthCheckURLs() []string {
|
||||
return []string{
|
||||
getEtcdHealthCheckURL(),
|
||||
getAPIServerHealthCheckURL(),
|
||||
}
|
||||
}
|
210
vendor/k8s.io/kubernetes/test/e2e_node/services/kubelet.go
generated
vendored
Normal file
210
vendor/k8s.io/kubernetes/test/e2e_node/services/kubelet.go
generated
vendored
Normal file
|
@ -0,0 +1,210 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
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 services
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
"k8s.io/kubernetes/test/e2e/framework"
|
||||
"k8s.io/kubernetes/test/e2e_node/builder"
|
||||
)
|
||||
|
||||
// TODO(random-liu): Replace this with standard kubelet launcher.
|
||||
|
||||
// args is the type used to accumulate args from the flags with the same name.
|
||||
type args []string
|
||||
|
||||
// String function of flag.Value
|
||||
func (a *args) String() string {
|
||||
return fmt.Sprint(*a)
|
||||
}
|
||||
|
||||
// Set function of flag.Value
|
||||
func (a *args) Set(value string) error {
|
||||
// Someone else is calling flag.Parse after the flags are parsed in the
|
||||
// test framework. Use this to avoid the flag being parsed twice.
|
||||
// TODO(random-liu): Figure out who is parsing the flags.
|
||||
if flag.Parsed() {
|
||||
return nil
|
||||
}
|
||||
// Note that we assume all white space in flag string is separating fields
|
||||
na := strings.Fields(value)
|
||||
*a = append(*a, na...)
|
||||
return nil
|
||||
}
|
||||
|
||||
// kubeletArgs is the override kubelet args specified by the test runner.
|
||||
var kubeletArgs args
|
||||
|
||||
func init() {
|
||||
flag.Var(&kubeletArgs, "kubelet-flags", "Kubelet flags passed to kubelet, this will override default kubelet flags in the test. Flags specified in multiple kubelet-flags will be concatenate.")
|
||||
}
|
||||
|
||||
// RunKubelet starts kubelet and waits for termination signal. Once receives the
|
||||
// termination signal, it will stop the kubelet gracefully.
|
||||
func RunKubelet() {
|
||||
var err error
|
||||
// Enable monitorParent to make sure kubelet will receive termination signal
|
||||
// when test process exits.
|
||||
e := NewE2EServices(true /* monitorParent */)
|
||||
defer e.Stop()
|
||||
e.kubelet, err = e.startKubelet()
|
||||
if err != nil {
|
||||
glog.Fatalf("Failed to start kubelet: %v", err)
|
||||
}
|
||||
// Wait until receiving a termination signal.
|
||||
waitForTerminationSignal()
|
||||
}
|
||||
|
||||
const (
|
||||
// Ports of different e2e services.
|
||||
kubeletPort = "10250"
|
||||
kubeletReadOnlyPort = "10255"
|
||||
// Health check url of kubelet
|
||||
kubeletHealthCheckURL = "http://127.0.0.1:" + kubeletReadOnlyPort + "/healthz"
|
||||
)
|
||||
|
||||
// startKubelet starts the Kubelet in a separate process or returns an error
|
||||
// if the Kubelet fails to start.
|
||||
func (e *E2EServices) startKubelet() (*server, error) {
|
||||
glog.Info("Starting kubelet")
|
||||
// Create pod manifest path
|
||||
manifestPath, err := createPodManifestDirectory()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
e.rmDirs = append(e.rmDirs, manifestPath)
|
||||
var killCommand, restartCommand *exec.Cmd
|
||||
var isSystemd bool
|
||||
// Apply default kubelet flags.
|
||||
cmdArgs := []string{}
|
||||
if systemdRun, err := exec.LookPath("systemd-run"); err == nil {
|
||||
// On systemd services, detection of a service / unit works reliably while
|
||||
// detection of a process started from an ssh session does not work.
|
||||
// Since kubelet will typically be run as a service it also makes more
|
||||
// sense to test it that way
|
||||
isSystemd = true
|
||||
unitName := fmt.Sprintf("kubelet-%d.service", rand.Int31())
|
||||
cmdArgs = append(cmdArgs, systemdRun, "--unit="+unitName, "--remain-after-exit", builder.GetKubeletServerBin())
|
||||
killCommand = exec.Command("systemctl", "kill", unitName)
|
||||
restartCommand = exec.Command("systemctl", "restart", unitName)
|
||||
e.logFiles["kubelet.log"] = logFileData{
|
||||
journalctlCommand: []string{"-u", unitName},
|
||||
}
|
||||
} else {
|
||||
cmdArgs = append(cmdArgs, builder.GetKubeletServerBin())
|
||||
cmdArgs = append(cmdArgs,
|
||||
"--runtime-cgroups=/docker-daemon",
|
||||
"--kubelet-cgroups=/kubelet",
|
||||
"--cgroup-root=/",
|
||||
"--system-cgroups=/system",
|
||||
)
|
||||
}
|
||||
cmdArgs = append(cmdArgs,
|
||||
"--api-servers", getAPIServerClientURL(),
|
||||
"--address", "0.0.0.0",
|
||||
"--port", kubeletPort,
|
||||
"--read-only-port", kubeletReadOnlyPort,
|
||||
"--volume-stats-agg-period", "10s", // Aggregate volumes frequently so tests don't need to wait as long
|
||||
"--allow-privileged", "true",
|
||||
"--serialize-image-pulls", "false",
|
||||
"--config", manifestPath,
|
||||
"--file-check-frequency", "10s", // Check file frequently so tests won't wait too long
|
||||
"--pod-cidr", "10.180.0.0/24", // Assign a fixed CIDR to the node because there is no node controller.
|
||||
"--eviction-pressure-transition-period", "30s",
|
||||
// Apply test framework feature gates by default. This could also be overridden
|
||||
// by kubelet-flags.
|
||||
"--feature-gates", framework.TestContext.FeatureGates,
|
||||
"--eviction-hard", "memory.available<250Mi,nodefs.available<10%,nodefs.inodesFree<5%", // The hard eviction thresholds.
|
||||
"--eviction-minimum-reclaim", "nodefs.available=5%,nodefs.inodesFree=5%", // The minimum reclaimed resources after eviction.
|
||||
"--v", LOG_VERBOSITY_LEVEL, "--logtostderr",
|
||||
)
|
||||
// Enable kubenet by default.
|
||||
cniDir, err := getCNIDirectory()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cmdArgs = append(cmdArgs,
|
||||
"--network-plugin=kubenet",
|
||||
"--network-plugin-dir", cniDir)
|
||||
|
||||
// Keep hostname override for convenience.
|
||||
if framework.TestContext.NodeName != "" { // If node name is specified, set hostname override.
|
||||
cmdArgs = append(cmdArgs, "--hostname-override", framework.TestContext.NodeName)
|
||||
}
|
||||
|
||||
// Override the default kubelet flags.
|
||||
cmdArgs = append(cmdArgs, kubeletArgs...)
|
||||
|
||||
// Adjust the args if we are running kubelet with systemd.
|
||||
if isSystemd {
|
||||
adjustArgsForSystemd(cmdArgs)
|
||||
}
|
||||
|
||||
cmd := exec.Command(cmdArgs[0], cmdArgs[1:]...)
|
||||
server := newServer(
|
||||
"kubelet",
|
||||
cmd,
|
||||
killCommand,
|
||||
restartCommand,
|
||||
[]string{kubeletHealthCheckURL},
|
||||
"kubelet.log",
|
||||
e.monitorParent,
|
||||
true /* restartOnExit */)
|
||||
return server, server.start()
|
||||
}
|
||||
|
||||
// createPodManifestDirectory creates pod manifest directory.
|
||||
func createPodManifestDirectory() (string, error) {
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to get current working directory: %v", err)
|
||||
}
|
||||
path, err := ioutil.TempDir(cwd, "pod-manifest")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to create static pod manifest directory: %v", err)
|
||||
}
|
||||
return path, nil
|
||||
}
|
||||
|
||||
// getCNIDirectory returns CNI directory.
|
||||
func getCNIDirectory() (string, error) {
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
// TODO(random-liu): Make sure the cni directory name is the same with that in remote/remote.go
|
||||
return filepath.Join(cwd, "cni", "bin"), nil
|
||||
}
|
||||
|
||||
// adjustArgsForSystemd escape special characters in kubelet arguments for systemd. Systemd
|
||||
// may try to do auto expansion without escaping.
|
||||
func adjustArgsForSystemd(args []string) {
|
||||
for i := range args {
|
||||
args[i] = strings.Replace(args[i], "%", "%%", -1)
|
||||
args[i] = strings.Replace(args[i], "$", "$$", -1)
|
||||
}
|
||||
}
|
74
vendor/k8s.io/kubernetes/test/e2e_node/services/namespace_controller.go
generated
vendored
Normal file
74
vendor/k8s.io/kubernetes/test/e2e_node/services/namespace_controller.go
generated
vendored
Normal file
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
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 services
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
|
||||
"k8s.io/kubernetes/pkg/client/restclient"
|
||||
"k8s.io/kubernetes/pkg/client/typed/dynamic"
|
||||
namespacecontroller "k8s.io/kubernetes/pkg/controller/namespace"
|
||||
"k8s.io/kubernetes/test/e2e/framework"
|
||||
)
|
||||
|
||||
const (
|
||||
// ncName is the name of namespace controller
|
||||
ncName = "namespace-controller"
|
||||
// ncResyncPeriod is resync period of the namespace controller
|
||||
ncResyncPeriod = 5 * time.Minute
|
||||
// ncConcurrency is concurrency of the namespace controller
|
||||
ncConcurrency = 2
|
||||
)
|
||||
|
||||
// NamespaceController is a server which manages namespace controller.
|
||||
type NamespaceController struct {
|
||||
stopCh chan struct{}
|
||||
}
|
||||
|
||||
// NewNamespaceController creates a new namespace controller.
|
||||
func NewNamespaceController() *NamespaceController {
|
||||
return &NamespaceController{stopCh: make(chan struct{})}
|
||||
}
|
||||
|
||||
// Start starts the namespace controller.
|
||||
func (n *NamespaceController) Start() error {
|
||||
// Use the default QPS
|
||||
config := restclient.AddUserAgent(&restclient.Config{Host: framework.TestContext.Host}, ncName)
|
||||
client, err := clientset.NewForConfig(config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
clientPool := dynamic.NewClientPool(config, api.Registry.RESTMapper(), dynamic.LegacyAPIPathResolverFunc)
|
||||
discoverResourcesFn := client.Discovery().ServerPreferredNamespacedResources
|
||||
nc := namespacecontroller.NewNamespaceController(client, clientPool, discoverResourcesFn, ncResyncPeriod, v1.FinalizerKubernetes)
|
||||
go nc.Run(ncConcurrency, n.stopCh)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Stop stops the namespace controller.
|
||||
func (n *NamespaceController) Stop() error {
|
||||
close(n.stopCh)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Name returns the name of namespace controller.
|
||||
func (n *NamespaceController) Name() string {
|
||||
return ncName
|
||||
}
|
361
vendor/k8s.io/kubernetes/test/e2e_node/services/server.go
generated
vendored
Normal file
361
vendor/k8s.io/kubernetes/test/e2e_node/services/server.go
generated
vendored
Normal file
|
@ -0,0 +1,361 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
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 services
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
"k8s.io/kubernetes/test/e2e/framework"
|
||||
)
|
||||
|
||||
var serverStartTimeout = flag.Duration("server-start-timeout", time.Second*120, "Time to wait for each server to become healthy.")
|
||||
|
||||
// A server manages a separate server process started and killed with
|
||||
// commands.
|
||||
type server struct {
|
||||
// name is the name of the server, it is only used for logging.
|
||||
name string
|
||||
// startCommand is the command used to start the server
|
||||
startCommand *exec.Cmd
|
||||
// killCommand is the command used to stop the server. It is not required. If it
|
||||
// is not specified, `kill` will be used to stop the server.
|
||||
killCommand *exec.Cmd
|
||||
// restartCommand is the command used to restart the server. If provided, it will be used
|
||||
// instead of startCommand when restarting the server.
|
||||
restartCommand *exec.Cmd
|
||||
// healthCheckUrls is the urls used to check whether the server is ready.
|
||||
healthCheckUrls []string
|
||||
// outFilename is the name of the log file. The stdout and stderr of the server
|
||||
// will be redirected to this file.
|
||||
outFilename string
|
||||
// monitorParent determines whether the server should watch its parent process and exit
|
||||
// if its parent is gone.
|
||||
monitorParent bool
|
||||
// restartOnExit determines whether a restart loop is launched with the server
|
||||
restartOnExit bool
|
||||
// Writing to this channel, if it is not nil, stops the restart loop.
|
||||
// When tearing down a server, you should check for this channel and write to it if it exists.
|
||||
stopRestartingCh chan<- bool
|
||||
// Read from this to confirm that the restart loop has stopped.
|
||||
ackStopRestartingCh <-chan bool
|
||||
}
|
||||
|
||||
// newServer returns a new server with the given name, commands, health check
|
||||
// URLs, etc.
|
||||
func newServer(name string, start, kill, restart *exec.Cmd, urls []string, outputFileName string, monitorParent, restartOnExit bool) *server {
|
||||
return &server{
|
||||
name: name,
|
||||
startCommand: start,
|
||||
killCommand: kill,
|
||||
restartCommand: restart,
|
||||
healthCheckUrls: urls,
|
||||
outFilename: outputFileName,
|
||||
monitorParent: monitorParent,
|
||||
restartOnExit: restartOnExit,
|
||||
}
|
||||
}
|
||||
|
||||
// commandToString format command to string.
|
||||
func commandToString(c *exec.Cmd) string {
|
||||
if c == nil {
|
||||
return ""
|
||||
}
|
||||
return strings.Join(append([]string{c.Path}, c.Args[1:]...), " ")
|
||||
}
|
||||
|
||||
func (s *server) String() string {
|
||||
return fmt.Sprintf("server %q start-command: `%s`, kill-command: `%s`, restart-command: `%s`, health-check: %v, output-file: %q", s.name,
|
||||
commandToString(s.startCommand), commandToString(s.killCommand), commandToString(s.restartCommand), s.healthCheckUrls, s.outFilename)
|
||||
}
|
||||
|
||||
// readinessCheck checks whether services are ready via the supplied health
|
||||
// check URLs. Once there is an error in errCh, the function will stop waiting
|
||||
// and return the error.
|
||||
// TODO(random-liu): Move this to util
|
||||
func readinessCheck(name string, urls []string, errCh <-chan error) error {
|
||||
glog.Infof("Running readiness check for service %q", name)
|
||||
endTime := time.Now().Add(*serverStartTimeout)
|
||||
blockCh := make(chan error)
|
||||
defer close(blockCh)
|
||||
for endTime.After(time.Now()) {
|
||||
select {
|
||||
// We *always* want to run the health check if there is no error on the channel.
|
||||
// With systemd, reads from errCh report nil because cmd.Run() waits
|
||||
// on systemd-run, rather than the service process. systemd-run quickly
|
||||
// exits with status 0, causing the channel to be closed with no error. In
|
||||
// this case, you want to wait for the health check to complete, rather
|
||||
// than returning from readinessCheck as soon as the channel is closed.
|
||||
case err, ok := <-errCh:
|
||||
if ok { // The channel is not closed, this is a real error
|
||||
if err != nil { // If there is an error, return it
|
||||
return err
|
||||
}
|
||||
// If not, keep checking readiness.
|
||||
} else { // The channel is closed, this is only a zero value.
|
||||
// Replace the errCh with blockCh to avoid busy loop,
|
||||
// and keep checking readiness.
|
||||
errCh = blockCh
|
||||
}
|
||||
case <-time.After(time.Second):
|
||||
ready := true
|
||||
for _, url := range urls {
|
||||
resp, err := http.Head(url)
|
||||
if err != nil || resp.StatusCode != http.StatusOK {
|
||||
ready = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if ready {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("e2e service %q readiness check timeout %v", name, *serverStartTimeout)
|
||||
}
|
||||
|
||||
// start starts the server by running its commands, monitors it with a health
|
||||
// check, and ensures that it is restarted if applicable.
|
||||
//
|
||||
// Note: restartOnExit == true requires len(s.healthCheckUrls) > 0 to work properly.
|
||||
func (s *server) start() error {
|
||||
glog.Infof("Starting server %q with command %q", s.name, commandToString(s.startCommand))
|
||||
errCh := make(chan error)
|
||||
|
||||
// Set up restart channels if the server is configured for restart on exit.
|
||||
var stopRestartingCh, ackStopRestartingCh chan bool
|
||||
if s.restartOnExit {
|
||||
if len(s.healthCheckUrls) == 0 {
|
||||
return fmt.Errorf("Tried to start %s which has s.restartOnExit == true, but no health check urls provided.", s)
|
||||
}
|
||||
|
||||
stopRestartingCh = make(chan bool)
|
||||
ackStopRestartingCh = make(chan bool)
|
||||
|
||||
s.stopRestartingCh = stopRestartingCh
|
||||
s.ackStopRestartingCh = ackStopRestartingCh
|
||||
}
|
||||
|
||||
// This goroutine actually runs the start command for the server.
|
||||
go func() {
|
||||
defer close(errCh)
|
||||
|
||||
// Create the output filename
|
||||
outPath := path.Join(framework.TestContext.ReportDir, s.outFilename)
|
||||
outfile, err := os.Create(outPath)
|
||||
if err != nil {
|
||||
errCh <- fmt.Errorf("failed to create file %q for `%s` %v.", outPath, s, err)
|
||||
return
|
||||
} else {
|
||||
glog.Infof("Output file for server %q: %v", s.name, outfile.Name())
|
||||
}
|
||||
defer outfile.Close()
|
||||
defer outfile.Sync()
|
||||
|
||||
// Set the command to write the output file
|
||||
s.startCommand.Stdout = outfile
|
||||
s.startCommand.Stderr = outfile
|
||||
|
||||
// If monitorParent is set, set Pdeathsig when starting the server.
|
||||
if s.monitorParent {
|
||||
// Death of this test process should kill the server as well.
|
||||
attrs := &syscall.SysProcAttr{}
|
||||
// Hack to set linux-only field without build tags.
|
||||
deathSigField := reflect.ValueOf(attrs).Elem().FieldByName("Pdeathsig")
|
||||
if deathSigField.IsValid() {
|
||||
deathSigField.Set(reflect.ValueOf(syscall.SIGTERM))
|
||||
} else {
|
||||
errCh <- fmt.Errorf("failed to set Pdeathsig field (non-linux build)")
|
||||
return
|
||||
}
|
||||
s.startCommand.SysProcAttr = attrs
|
||||
}
|
||||
|
||||
// Start the command
|
||||
err = s.startCommand.Start()
|
||||
if err != nil {
|
||||
errCh <- fmt.Errorf("failed to run %s: %v", s, err)
|
||||
return
|
||||
}
|
||||
if !s.restartOnExit {
|
||||
glog.Infof("Waiting for server %q start command to complete", s.name)
|
||||
// If we aren't planning on restarting, ok to Wait() here to release resources.
|
||||
// Otherwise, we Wait() in the restart loop.
|
||||
err = s.startCommand.Wait()
|
||||
if err != nil {
|
||||
errCh <- fmt.Errorf("failed to run start command for server %q: %v", s.name, err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
usedStartCmd := true
|
||||
for {
|
||||
glog.Infof("Running health check for service %q", s.name)
|
||||
// Wait for an initial health check to pass, so that we are sure the server started.
|
||||
err := readinessCheck(s.name, s.healthCheckUrls, nil)
|
||||
if err != nil {
|
||||
if usedStartCmd {
|
||||
glog.Infof("Waiting for server %q start command to complete after initial health check failed", s.name)
|
||||
s.startCommand.Wait() // Release resources if necessary.
|
||||
}
|
||||
// This should not happen, immediately stop the e2eService process.
|
||||
glog.Fatalf("Restart loop readinessCheck failed for %s", s)
|
||||
} else {
|
||||
glog.Infof("Initial health check passed for service %q", s.name)
|
||||
}
|
||||
|
||||
// Initial health check passed, wait until a health check fails again.
|
||||
stillAlive:
|
||||
for {
|
||||
select {
|
||||
case <-stopRestartingCh:
|
||||
ackStopRestartingCh <- true
|
||||
return
|
||||
case <-time.After(time.Second):
|
||||
for _, url := range s.healthCheckUrls {
|
||||
resp, err := http.Head(url)
|
||||
if err != nil || resp.StatusCode != http.StatusOK {
|
||||
break stillAlive
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if usedStartCmd {
|
||||
s.startCommand.Wait() // Release resources from last cmd
|
||||
usedStartCmd = false
|
||||
}
|
||||
if s.restartCommand != nil {
|
||||
// Always make a fresh copy of restartCommand before
|
||||
// running, we may have to restart multiple times
|
||||
s.restartCommand = &exec.Cmd{
|
||||
Path: s.restartCommand.Path,
|
||||
Args: s.restartCommand.Args,
|
||||
Env: s.restartCommand.Env,
|
||||
Dir: s.restartCommand.Dir,
|
||||
Stdin: s.restartCommand.Stdin,
|
||||
Stdout: s.restartCommand.Stdout,
|
||||
Stderr: s.restartCommand.Stderr,
|
||||
ExtraFiles: s.restartCommand.ExtraFiles,
|
||||
SysProcAttr: s.restartCommand.SysProcAttr,
|
||||
}
|
||||
// Run and wait for exit. This command is assumed to have
|
||||
// short duration, e.g. systemctl restart
|
||||
glog.Infof("Restarting server %q with restart command", s.name)
|
||||
err = s.restartCommand.Run()
|
||||
if err != nil {
|
||||
// This should not happen, immediately stop the e2eService process.
|
||||
glog.Fatalf("Restarting server %s with restartCommand failed. Error: %v.", s, err)
|
||||
}
|
||||
} else {
|
||||
s.startCommand = &exec.Cmd{
|
||||
Path: s.startCommand.Path,
|
||||
Args: s.startCommand.Args,
|
||||
Env: s.startCommand.Env,
|
||||
Dir: s.startCommand.Dir,
|
||||
Stdin: s.startCommand.Stdin,
|
||||
Stdout: s.startCommand.Stdout,
|
||||
Stderr: s.startCommand.Stderr,
|
||||
ExtraFiles: s.startCommand.ExtraFiles,
|
||||
SysProcAttr: s.startCommand.SysProcAttr,
|
||||
}
|
||||
glog.Infof("Restarting server %q with start command", s.name)
|
||||
err = s.startCommand.Start()
|
||||
usedStartCmd = true
|
||||
if err != nil {
|
||||
// This should not happen, immediately stop the e2eService process.
|
||||
glog.Fatalf("Restarting server %s with startCommand failed. Error: %v.", s, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return readinessCheck(s.name, s.healthCheckUrls, errCh)
|
||||
}
|
||||
|
||||
// kill runs the server's kill command.
|
||||
func (s *server) kill() error {
|
||||
glog.Infof("Kill server %q", s.name)
|
||||
name := s.name
|
||||
cmd := s.startCommand
|
||||
|
||||
// If s has a restart loop, turn it off.
|
||||
if s.restartOnExit {
|
||||
s.stopRestartingCh <- true
|
||||
<-s.ackStopRestartingCh
|
||||
}
|
||||
|
||||
if s.killCommand != nil {
|
||||
return s.killCommand.Run()
|
||||
}
|
||||
|
||||
if cmd == nil {
|
||||
return fmt.Errorf("could not kill %q because both `killCommand` and `startCommand` are nil", name)
|
||||
}
|
||||
|
||||
if cmd.Process == nil {
|
||||
glog.V(2).Infof("%q not running", name)
|
||||
return nil
|
||||
}
|
||||
pid := cmd.Process.Pid
|
||||
if pid <= 1 {
|
||||
return fmt.Errorf("invalid PID %d for %q", pid, name)
|
||||
}
|
||||
|
||||
// Attempt to shut down the process in a friendly manner before forcing it.
|
||||
waitChan := make(chan error)
|
||||
go func() {
|
||||
_, err := cmd.Process.Wait()
|
||||
waitChan <- err
|
||||
close(waitChan)
|
||||
}()
|
||||
|
||||
const timeout = 10 * time.Second
|
||||
for _, signal := range []string{"-TERM", "-KILL"} {
|
||||
glog.V(2).Infof("Killing process %d (%s) with %s", pid, name, signal)
|
||||
cmd := exec.Command("kill", signal, strconv.Itoa(pid))
|
||||
_, err := cmd.Output()
|
||||
if err != nil {
|
||||
glog.Errorf("Error signaling process %d (%s) with %s: %v", pid, name, signal, err)
|
||||
continue
|
||||
}
|
||||
|
||||
select {
|
||||
case err := <-waitChan:
|
||||
if err != nil {
|
||||
return fmt.Errorf("error stopping %q: %v", name, err)
|
||||
}
|
||||
// Success!
|
||||
return nil
|
||||
case <-time.After(timeout):
|
||||
// Continue.
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf("unable to stop %q", name)
|
||||
}
|
206
vendor/k8s.io/kubernetes/test/e2e_node/services/services.go
generated
vendored
Normal file
206
vendor/k8s.io/kubernetes/test/e2e_node/services/services.go
generated
vendored
Normal file
|
@ -0,0 +1,206 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
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 services
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/kardianos/osext"
|
||||
|
||||
utilconfig "k8s.io/kubernetes/pkg/util/config"
|
||||
"k8s.io/kubernetes/test/e2e/framework"
|
||||
)
|
||||
|
||||
// E2EServices starts and stops e2e services in a separate process. The test
|
||||
// uses it to start and stop all e2e services.
|
||||
type E2EServices struct {
|
||||
// monitorParent determines whether the sub-processes should watch and die with the current
|
||||
// process.
|
||||
rmDirs []string
|
||||
monitorParent bool
|
||||
services *server
|
||||
kubelet *server
|
||||
logFiles map[string]logFileData
|
||||
}
|
||||
|
||||
// logFileData holds data about logfiles to fetch with a journalctl command or
|
||||
// symlink from a node's file system.
|
||||
type logFileData struct {
|
||||
files []string
|
||||
journalctlCommand []string
|
||||
}
|
||||
|
||||
// NewE2EServices returns a new E2EServices instance.
|
||||
func NewE2EServices(monitorParent bool) *E2EServices {
|
||||
return &E2EServices{
|
||||
monitorParent: monitorParent,
|
||||
// Special log files that need to be collected for additional debugging.
|
||||
logFiles: map[string]logFileData{
|
||||
"kern.log": {[]string{"/var/log/kern.log"}, []string{"-k"}},
|
||||
"docker.log": {[]string{"/var/log/docker.log", "/var/log/upstart/docker.log"}, []string{"-u", "docker"}},
|
||||
"cloud-init.log": {[]string{"/var/log/cloud-init.log"}, []string{"-u", "cloud*"}},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Start starts the e2e services in another process by calling back into the
|
||||
// test binary. Returns when all e2e services are ready or an error.
|
||||
//
|
||||
// We want to statically link e2e services into the test binary, but we don't
|
||||
// want their glog output to pollute the test result. So we run the binary in
|
||||
// run-services-mode to start e2e services in another process.
|
||||
// The function starts 2 processes:
|
||||
// * internal e2e services: services which statically linked in the test binary - apiserver, etcd and
|
||||
// namespace controller.
|
||||
// * kubelet: kubelet binary is outside. (We plan to move main kubelet start logic out when we have
|
||||
// standard kubelet launcher)
|
||||
func (e *E2EServices) Start() error {
|
||||
var err error
|
||||
if !framework.TestContext.NodeConformance {
|
||||
// Start kubelet
|
||||
e.kubelet, err = e.startKubelet()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to start kubelet: %v", err)
|
||||
}
|
||||
}
|
||||
e.services, err = e.startInternalServices()
|
||||
return err
|
||||
}
|
||||
|
||||
// Stop stops the e2e services.
|
||||
func (e *E2EServices) Stop() {
|
||||
defer func() {
|
||||
if !framework.TestContext.NodeConformance {
|
||||
// Collect log files.
|
||||
e.getLogFiles()
|
||||
}
|
||||
}()
|
||||
if e.services != nil {
|
||||
if err := e.services.kill(); err != nil {
|
||||
glog.Errorf("Failed to stop services: %v", err)
|
||||
}
|
||||
}
|
||||
if e.kubelet != nil {
|
||||
if err := e.kubelet.kill(); err != nil {
|
||||
glog.Errorf("Failed to stop kubelet: %v", err)
|
||||
}
|
||||
}
|
||||
if e.rmDirs != nil {
|
||||
for _, d := range e.rmDirs {
|
||||
err := os.RemoveAll(d)
|
||||
if err != nil {
|
||||
glog.Errorf("Failed to delete directory %s: %v", d, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// RunE2EServices actually start the e2e services. This function is used to
|
||||
// start e2e services in current process. This is only used in run-services-mode.
|
||||
func RunE2EServices() {
|
||||
// Populate global DefaultFeatureGate with value from TestContext.FeatureGates.
|
||||
// This way, statically-linked components see the same feature gate config as the test context.
|
||||
utilconfig.DefaultFeatureGate.Set(framework.TestContext.FeatureGates)
|
||||
e := newE2EServices()
|
||||
if err := e.run(); err != nil {
|
||||
glog.Fatalf("Failed to run e2e services: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
// services.log is the combined log of all services
|
||||
servicesLogFile = "services.log"
|
||||
// LOG_VERBOSITY_LEVEL is consistent with the level used in a cluster e2e test.
|
||||
LOG_VERBOSITY_LEVEL = "4"
|
||||
)
|
||||
|
||||
// startInternalServices starts the internal services in a separate process.
|
||||
func (e *E2EServices) startInternalServices() (*server, error) {
|
||||
testBin, err := osext.Executable()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't get current binary: %v", err)
|
||||
}
|
||||
// Pass all flags into the child process, so that it will see the same flag set.
|
||||
startCmd := exec.Command(testBin, append([]string{"--run-services-mode"}, os.Args[1:]...)...)
|
||||
server := newServer("services", startCmd, nil, nil, getServicesHealthCheckURLs(), servicesLogFile, e.monitorParent, false)
|
||||
return server, server.start()
|
||||
}
|
||||
|
||||
// getLogFiles gets logs of interest either via journalctl or by creating sym
|
||||
// links. Since we scp files from the remote directory, symlinks will be
|
||||
// treated as normal files and file contents will be copied over.
|
||||
func (e *E2EServices) getLogFiles() {
|
||||
// Nothing to do if report dir is not specified.
|
||||
if framework.TestContext.ReportDir == "" {
|
||||
return
|
||||
}
|
||||
glog.Info("Fetching log files...")
|
||||
journaldFound := isJournaldAvailable()
|
||||
for targetFileName, logFileData := range e.logFiles {
|
||||
targetLink := path.Join(framework.TestContext.ReportDir, targetFileName)
|
||||
if journaldFound {
|
||||
// Skip log files that do not have an equivalent in journald-based machines.
|
||||
if len(logFileData.journalctlCommand) == 0 {
|
||||
continue
|
||||
}
|
||||
glog.Infof("Get log file %q with journalctl command %v.", targetFileName, logFileData.journalctlCommand)
|
||||
out, err := exec.Command("journalctl", logFileData.journalctlCommand...).CombinedOutput()
|
||||
if err != nil {
|
||||
glog.Errorf("failed to get %q from journald: %v, %v", targetFileName, string(out), err)
|
||||
} else {
|
||||
if err = ioutil.WriteFile(targetLink, out, 0644); err != nil {
|
||||
glog.Errorf("failed to write logs to %q: %v", targetLink, err)
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
for _, file := range logFileData.files {
|
||||
if _, err := os.Stat(file); err != nil {
|
||||
// Expected file not found on this distro.
|
||||
continue
|
||||
}
|
||||
if err := copyLogFile(file, targetLink); err != nil {
|
||||
glog.Error(err)
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// isJournaldAvailable returns whether the system executing the tests uses
|
||||
// journald.
|
||||
func isJournaldAvailable() bool {
|
||||
_, err := exec.LookPath("journalctl")
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func copyLogFile(src, target string) error {
|
||||
// If not a journald based distro, then just symlink files.
|
||||
if out, err := exec.Command("cp", src, target).CombinedOutput(); err != nil {
|
||||
return fmt.Errorf("failed to copy %q to %q: %v, %v", src, target, out, err)
|
||||
}
|
||||
if out, err := exec.Command("chmod", "a+r", target).CombinedOutput(); err != nil {
|
||||
return fmt.Errorf("failed to make log file %q world readable: %v, %v", target, out, err)
|
||||
}
|
||||
return nil
|
||||
}
|
34
vendor/k8s.io/kubernetes/test/e2e_node/services/util.go
generated
vendored
Normal file
34
vendor/k8s.io/kubernetes/test/e2e_node/services/util.go
generated
vendored
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
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 services
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// terminationSignals are signals that cause the program to exit in the
|
||||
// supported platforms (linux, darwin, windows).
|
||||
var terminationSignals = []os.Signal{syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT}
|
||||
|
||||
// waitForTerminationSignal waits for termination signal.
|
||||
func waitForTerminationSignal() {
|
||||
sig := make(chan os.Signal, 1)
|
||||
signal.Notify(sig, terminationSignals...)
|
||||
<-sig
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue