Add e2e tests for nginx
This commit is contained in:
parent
ca0df3a271
commit
123e0d6c05
23 changed files with 806 additions and 162 deletions
7
.gitignore
vendored
7
.gitignore
vendored
|
@ -25,3 +25,10 @@ Session.vim
|
|||
# coverage artifacts
|
||||
.coverprofile
|
||||
/gover.coverprofile
|
||||
|
||||
# skip go tests
|
||||
*/**/*.test
|
||||
|
||||
# skip e2e binaries
|
||||
minikube
|
||||
kubectl
|
||||
|
|
|
@ -9,7 +9,7 @@ notifications:
|
|||
email: true
|
||||
|
||||
go:
|
||||
- 1.8.3
|
||||
- 1.9
|
||||
|
||||
go_import_path: k8s.io/ingress
|
||||
|
||||
|
@ -18,9 +18,10 @@ env:
|
|||
# to add additional secure variables:
|
||||
# docker run --rm caktux/travis-cli encrypt key=value -r kubernetes/ingress
|
||||
- RELEASE="ci-${TRAVIS_BUILD_ID}"
|
||||
- DOCKER=docker
|
||||
|
||||
before_script:
|
||||
- export PATH=$PATH:$PWD/hack/e2e-internal/
|
||||
- export PATH=$PATH:$PWD/controllers/nginx/e2e/e2e-internal
|
||||
|
||||
jobs:
|
||||
include:
|
||||
|
@ -34,4 +35,6 @@ jobs:
|
|||
- go get github.com/modocache/gover
|
||||
- if ! go get github.com/golang/tools/cmd/cover; then go get golang.org/x/tools/cmd/cover; fi
|
||||
- make cover
|
||||
#- make test-e2e
|
||||
- stage: e2e
|
||||
script:
|
||||
- make test-e2e
|
||||
|
|
19
Makefile
19
Makefile
|
@ -2,15 +2,6 @@ all: fmt lint vet
|
|||
|
||||
BUILDTAGS=
|
||||
|
||||
# building inside travis generates a custom version of the
|
||||
# backends in order to run e2e tests agains the build.
|
||||
ifdef TRAVIS_BUILD_ID
|
||||
RELEASE := ci-build-${TRAVIS_BUILD_ID}
|
||||
endif
|
||||
|
||||
# 0.0 shouldn't clobber any release builds
|
||||
RELEASE?=0.0
|
||||
|
||||
# by default build a linux version
|
||||
GOOS?=linux
|
||||
|
||||
|
@ -23,7 +14,7 @@ endif
|
|||
# base package. It contains the common and backends code
|
||||
PKG := "k8s.io/ingress"
|
||||
|
||||
GO_LIST_FILES=$(shell go list ${PKG}/... | grep -v vendor | grep -v -e "test/e2e")
|
||||
GO_LIST_FILES=$(shell go list ${PKG}/... | grep -v vendor | grep -v -e "e2e")
|
||||
|
||||
.PHONY: fmt
|
||||
fmt:
|
||||
|
@ -38,8 +29,8 @@ test:
|
|||
@go test -v -race -tags "$(BUILDTAGS) cgo" ${GO_LIST_FILES}
|
||||
|
||||
.PHONY: test-e2e
|
||||
test-e2e: ginkgo
|
||||
@go run hack/e2e.go -v --up --test --down
|
||||
test-e2e:
|
||||
make -C controllers/nginx test-e2e
|
||||
|
||||
.PHONY: cover
|
||||
cover:
|
||||
|
@ -70,7 +61,3 @@ docker-push:
|
|||
.PHONE: release
|
||||
release:
|
||||
make -C controllers/nginx release
|
||||
|
||||
.PHONY: ginkgo
|
||||
ginkgo:
|
||||
go get github.com/onsi/ginkgo/ginkgo
|
||||
|
|
|
@ -10,6 +10,8 @@ DOCKER?=gcloud docker --
|
|||
SED_I?=sed -i
|
||||
GOHOSTOS ?= $(shell go env GOHOSTOS)
|
||||
|
||||
SKIP_TESTS?=
|
||||
|
||||
ifeq ($(GOHOSTOS),darwin)
|
||||
SED_I=sed -i ''
|
||||
endif
|
||||
|
@ -120,11 +122,14 @@ lint:
|
|||
|
||||
test: fmt lint vet
|
||||
@echo "+ $@"
|
||||
@go test -v -race -tags "$(BUILDTAGS) cgo" $(shell go list ${PKG}/... | grep -v vendor)
|
||||
@go test -v -race -tags "$(BUILDTAGS) cgo" $(shell go list ${PKG}/... | grep -v vendor |grep -v e2e)
|
||||
|
||||
test-e2e: sub-container-amd64
|
||||
@TAG=${TAG} IMAGE=$(MULTI_ARCH_IMG) go run e2e/e2e.go --files=e2e/nginx-ingress-controller.yaml,e2e/default-backend.yaml --verbose --up --test --down
|
||||
|
||||
cover:
|
||||
@echo "+ $@"
|
||||
@go list -f '{{if len .TestGoFiles}}"go test -coverprofile={{.Dir}}/.coverprofile {{.ImportPath}}"{{end}}' $(shell go list ${PKG}/... | grep -v vendor) | xargs -L 1 sh -c
|
||||
@go list -f '{{if len .TestGoFiles}}"go test -skipTest "${SKIP_TESTS}" -coverprofile={{.Dir}}/.coverprofile {{.ImportPath}}"{{end}}' $(shell go list ${PKG}/... | grep -v vendor) | xargs -L 1 sh -c
|
||||
gover
|
||||
goveralls -coverprofile=gover.coverprofile -service travis-ci -repotoken ${COVERALLS_TOKEN}
|
||||
|
||||
|
|
51
controllers/nginx/e2e/default-backend.yaml
Normal file
51
controllers/nginx/e2e/default-backend.yaml
Normal file
|
@ -0,0 +1,51 @@
|
|||
apiVersion: extensions/v1beta1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: default-http-backend
|
||||
labels:
|
||||
k8s-app: default-http-backend
|
||||
namespace: kube-system
|
||||
spec:
|
||||
replicas: 1
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
k8s-app: default-http-backend
|
||||
spec:
|
||||
terminationGracePeriodSeconds: 60
|
||||
containers:
|
||||
- name: default-http-backend
|
||||
# Any image is permissable as long as:
|
||||
# 1. It serves a 404 page at /
|
||||
# 2. It serves 200 on a /healthz endpoint
|
||||
image: gcr.io/google_containers/defaultbackend:1.0
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: 8080
|
||||
scheme: HTTP
|
||||
initialDelaySeconds: 30
|
||||
timeoutSeconds: 5
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
resources:
|
||||
limits:
|
||||
cpu: 10m
|
||||
memory: 20Mi
|
||||
requests:
|
||||
cpu: 10m
|
||||
memory: 20Mi
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: default-http-backend
|
||||
namespace: kube-system
|
||||
labels:
|
||||
k8s-app: default-http-backend
|
||||
spec:
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 8080
|
||||
selector:
|
||||
k8s-app: default-http-backend
|
6
controllers/nginx/e2e/e2e-internal/e2e-down.sh
Executable file
6
controllers/nginx/e2e/e2e-internal/e2e-down.sh
Executable file
|
@ -0,0 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
. ./e2e/e2e-internal/e2e-env.sh
|
||||
|
||||
echo "Destroying running e2e cluster..."
|
||||
${MINIKUBE} --profile ${MINIKUBE_PROFILE} delete || echo "Cluster already destroyed"
|
33
controllers/nginx/e2e/e2e-internal/e2e-env.sh
Executable file
33
controllers/nginx/e2e/e2e-internal/e2e-env.sh
Executable file
|
@ -0,0 +1,33 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
export MINIKUBE_VERSION=0.22.0
|
||||
export K8S_VERSION=v1.7.5
|
||||
|
||||
export PWD=`pwd`
|
||||
export BASEDIR="$(dirname ${BASH_SOURCE})"
|
||||
export KUBECTL="${BASEDIR}/kubectl"
|
||||
export MINIKUBE="${BASEDIR}/minikube"
|
||||
export GOOS="${GOOS:-linux}"
|
||||
|
||||
export MINIKUBE_WANTUPDATENOTIFICATION=false
|
||||
export MINIKUBE_WANTREPORTERRORPROMPT=false
|
||||
export MINIKUBE_HOME=$HOME
|
||||
export CHANGE_MINIKUBE_NONE_USER=true
|
||||
|
||||
export KUBECONFIG=$HOME/.kube/config
|
||||
|
||||
export MINIKUBE_PROFILE="ingress-e2e"
|
||||
|
||||
export PATH=$PATH:$BASEDIR
|
||||
|
||||
if [ ! -e ${KUBECTL} ]; then
|
||||
echo "kubectl binary is missing. downloading..."
|
||||
curl -sSL http://storage.googleapis.com/kubernetes-release/release/${K8S_VERSION}/bin/${GOOS}/amd64/kubectl -o ${KUBECTL}
|
||||
chmod u+x ${KUBECTL}
|
||||
fi
|
||||
|
||||
if [ ! -e ${MINIKUBE} ]; then
|
||||
echo "minikube binary is missing. downloading..."
|
||||
curl -sSLo ${MINIKUBE} https://storage.googleapis.com/minikube/releases/v${MINIKUBE_VERSION}/minikube-linux-amd64
|
||||
chmod +x ${MINIKUBE}
|
||||
fi
|
7
controllers/nginx/e2e/e2e-internal/e2e-status.sh
Executable file
7
controllers/nginx/e2e/e2e-internal/e2e-status.sh
Executable file
|
@ -0,0 +1,7 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -eof pipefail
|
||||
|
||||
. ./e2e/e2e-internal/e2e-env.sh
|
||||
|
||||
${MINIKUBE} --profile ${MINIKUBE_PROFILE} status
|
28
controllers/nginx/e2e/e2e-internal/e2e-up.sh
Executable file
28
controllers/nginx/e2e/e2e-internal/e2e-up.sh
Executable file
|
@ -0,0 +1,28 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -eof pipefail
|
||||
|
||||
. ./e2e/e2e-internal/e2e-env.sh
|
||||
|
||||
mkdir -p $HOME/.kube
|
||||
touch $KUBECONFIG
|
||||
|
||||
if [ "$TRAVIS" = true ] ; then
|
||||
sudo -E ${MINIKUBE} --profile ${MINIKUBE_PROFILE} start --vm-driver=none
|
||||
else
|
||||
${MINIKUBE} --profile ${MINIKUBE_PROFILE} start
|
||||
fi
|
||||
|
||||
# this for loop waits until kubectl can access the api server that minikube has created
|
||||
for i in {1..150} # timeout for 5 minutes
|
||||
do
|
||||
$KUBECTL get po &> /dev/null
|
||||
if [ $? -ne 1 ]; then
|
||||
break
|
||||
fi
|
||||
sleep 10
|
||||
done
|
||||
|
||||
sleep 60
|
||||
|
||||
echo "Kubernetes started"
|
15
controllers/nginx/e2e/e2e-internal/run-e2e.sh
Executable file
15
controllers/nginx/e2e/e2e-internal/run-e2e.sh
Executable file
|
@ -0,0 +1,15 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -eof pipefail
|
||||
|
||||
. ./e2e/e2e-internal/e2e-env.sh
|
||||
|
||||
echo "Creating test tag for image $IMAGE:$TAG"
|
||||
docker tag $IMAGE:$TAG $IMAGE:test
|
||||
|
||||
echo "Uploading test image to minikube"
|
||||
dockerenv=$(${MINIKUBE} --profile ${MINIKUBE_PROFILE} docker-env | sed 's/export//g' | sed 's/^#.*$//g' | sed 's/"//g')
|
||||
docker save $IMAGE:test | env -i $dockerenv docker load
|
||||
|
||||
echo "Running tests..."
|
||||
go test -v k8s.io/ingress/controllers/nginx/e2e/... -run ^TestIngressSuite$ --args --alsologtostderr --v=10
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
Copyright 2017 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.
|
||||
|
@ -31,14 +31,14 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
build = flag.Bool("build", true, "Build the backends images indicated by the env var BACKENDS required to run e2e tests.")
|
||||
up = flag.Bool("up", true, "Creates a kubernetes cluster using hyperkube (containerized kubelet).")
|
||||
down = flag.Bool("down", true, "destroys the created cluster.")
|
||||
test = flag.Bool("test", true, "Run Ginkgo tests.")
|
||||
test = flag.Bool("test", true, "Run tests.")
|
||||
dump = flag.String("dump", "", "If set, dump cluster logs to this location on test or cluster-up failure")
|
||||
testArgs = flag.String("test-args", "", "Space-separated list of arguments to pass to Ginkgo test runner.")
|
||||
testArgs = flag.String("test-args", "", "Space-separated list of arguments to pass to the test runner.")
|
||||
deployment = flag.String("deployment", "bash", "up/down mechanism")
|
||||
verbose = flag.Bool("v", false, "If true, print all command output.")
|
||||
verbose = flag.Bool("verbose", false, "If true, print all command output.")
|
||||
files = flag.String("files", "", "Path to a file/S descriptor that will create an Ingress controller")
|
||||
)
|
||||
|
||||
func appendError(errs []error, err error) []error {
|
||||
|
@ -57,7 +57,7 @@ func validWorkingDirectory() error {
|
|||
if err != nil {
|
||||
return fmt.Errorf("failed to convert %s to an absolute path: %v", cwd, err)
|
||||
}
|
||||
if !strings.Contains(filepath.Base(acwd), "ingress") {
|
||||
if !strings.Contains(filepath.Base(acwd), "nginx") {
|
||||
return fmt.Errorf("must run from git root directory: %v", acwd)
|
||||
}
|
||||
return nil
|
||||
|
@ -139,14 +139,12 @@ func main() {
|
|||
}
|
||||
|
||||
func run(deploy deployer) error {
|
||||
if *dump != "" {
|
||||
defer writeXML(time.Now())
|
||||
if *files == "" {
|
||||
return fmt.Errorf("missing required flag --files")
|
||||
}
|
||||
|
||||
if *build {
|
||||
if err := xmlWrap("Build", Build); err != nil {
|
||||
return fmt.Errorf("error building: %s", err)
|
||||
}
|
||||
if *dump != "" {
|
||||
defer writeXML(time.Now())
|
||||
}
|
||||
|
||||
if *up {
|
||||
|
@ -172,7 +170,7 @@ func run(deploy deployer) error {
|
|||
return fmt.Errorf("starting e2e cluster: %s", err)
|
||||
}
|
||||
if *dump != "" {
|
||||
cmd := exec.Command("./cluster/kubectl.sh", "--match-server-version=false", "get", "nodes", "-oyaml")
|
||||
cmd := kubectlCmd("get", "nodes", "-oyaml")
|
||||
b, err := cmd.CombinedOutput()
|
||||
if *verbose {
|
||||
log.Printf("kubectl get nodes:\n%s", string(b))
|
||||
|
@ -187,17 +185,22 @@ func run(deploy deployer) error {
|
|||
}
|
||||
}
|
||||
|
||||
log.Printf("deploying ingress controller")
|
||||
if err := deploy.SetupController(*files); err != nil {
|
||||
errs = appendError(errs, err)
|
||||
}
|
||||
|
||||
if *test {
|
||||
if err := xmlWrap("IsUp", deploy.IsUp); err != nil {
|
||||
errs = appendError(errs, err)
|
||||
} else {
|
||||
errs = appendError(errs, Test())
|
||||
errs = appendError(errs, runTests())
|
||||
}
|
||||
}
|
||||
|
||||
if len(errs) > 0 && *dump != "" {
|
||||
errs = appendError(errs, xmlWrap("DumpClusterLogs", func() error {
|
||||
return DumpClusterLogs(*dump)
|
||||
return dumpClusterLogs(*dump)
|
||||
}))
|
||||
}
|
||||
|
||||
|
@ -208,24 +211,14 @@ func run(deploy deployer) error {
|
|||
if len(errs) != 0 {
|
||||
return fmt.Errorf("encountered %d errors: %v", len(errs), errs)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Build() error {
|
||||
// The build-release script needs stdin to ask the user whether
|
||||
// it's OK to download the docker image.
|
||||
cmd := exec.Command("make", "docker-build")
|
||||
cmd.Stdin = os.Stdin
|
||||
if err := finishRunning("build-release", cmd); err != nil {
|
||||
return fmt.Errorf("error building: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type deployer interface {
|
||||
Up() error
|
||||
IsUp() error
|
||||
SetupKubecfg() error
|
||||
SetupController(p string) error
|
||||
Down() error
|
||||
}
|
||||
|
||||
|
@ -241,31 +234,36 @@ func getDeployer() (deployer, error) {
|
|||
type bash struct{}
|
||||
|
||||
func (b bash) Up() error {
|
||||
return finishRunning("up", exec.Command("./hack/e2e-internal/e2e-up.sh"))
|
||||
return finishRunning("up", exec.Command("./e2e/e2e-internal/e2e-up.sh"))
|
||||
}
|
||||
|
||||
func (b bash) IsUp() error {
|
||||
return finishRunning("get status", exec.Command("./hack/e2e-internal/e2e-status.sh"))
|
||||
return finishRunning("get status", exec.Command("./e2e/e2e-internal/e2e-status.sh"))
|
||||
}
|
||||
|
||||
func (b bash) SetupKubecfg() error {
|
||||
func (b bash) SetupController(p string) error {
|
||||
files := strings.Split(p, ",")
|
||||
for _, f := range files {
|
||||
err := finishRunning("setup controller", kubectlCmd("create", "-f", f))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b bash) Down() error {
|
||||
return finishRunning("teardown", exec.Command("./hack/e2e-internal/e2e-down.sh"))
|
||||
return finishRunning("teardown", exec.Command("./e2e/e2e-internal/e2e-down.sh"))
|
||||
}
|
||||
|
||||
func DumpClusterLogs(location string) error {
|
||||
func dumpClusterLogs(location string) error {
|
||||
log.Printf("Dumping cluster logs to: %v", location)
|
||||
return finishRunning("dump cluster logs", exec.Command("./hack/e2e-internal/log-dump.sh", location))
|
||||
return finishRunning("dump cluster logs", exec.Command("./e2e/e2e-internal/log-dump.sh", location))
|
||||
}
|
||||
|
||||
func Test() error {
|
||||
if *testArgs == "" {
|
||||
*testArgs = "--ginkgo.focus=\\[Feature:Ingress\\]"
|
||||
}
|
||||
return finishRunning("Ginkgo tests", exec.Command("./hack/e2e-internal/ginkgo-e2e.sh", strings.Fields(*testArgs)...))
|
||||
func runTests() error {
|
||||
return finishRunning("Ingress tests", exec.Command("./e2e/e2e-internal/run-e2e.sh", strings.Fields(*testArgs)...))
|
||||
}
|
||||
|
||||
func finishRunning(stepName string, cmd *exec.Cmd) error {
|
||||
|
@ -283,3 +281,15 @@ func finishRunning(stepName string, cmd *exec.Cmd) error {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func kubectlCmd(arg ...string) *exec.Cmd {
|
||||
args := []string{"--context", "ingress-e2e"}
|
||||
args = append(args, arg...)
|
||||
|
||||
kb := os.Getenv("KUBECTL")
|
||||
if kb == "" {
|
||||
kb = "./e2e/e2e-internal/kubectl"
|
||||
}
|
||||
|
||||
return exec.Command(kb, args...)
|
||||
}
|
62
controllers/nginx/e2e/e2e_types.go
Normal file
62
controllers/nginx/e2e/e2e_types.go
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
Copyright 2017 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
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
apiv1 "k8s.io/api/core/v1"
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
)
|
||||
|
||||
// IngressTestCase defines a test case for Ingress
|
||||
type IngressTestCase struct {
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Ingress *extensions.Ingress `json:"ingress"`
|
||||
ReplicationController *apiv1.ReplicationController `json:"replicationController,omitempty"`
|
||||
Deployment *extensions.Deployment `json:"deployment,omitempty"`
|
||||
Service *apiv1.Service `json:"service"`
|
||||
Assert []*Assert `json:"tests"`
|
||||
}
|
||||
|
||||
// Assert defines a verification over the
|
||||
type Assert struct {
|
||||
Name string `json:"name"`
|
||||
Request Request `json:"request"`
|
||||
Expect []*Expect `json:"expect"`
|
||||
Timeout time.Duration `json:"timeout"`
|
||||
}
|
||||
|
||||
// Request defines a HTTP/s request to be executed against an Ingress
|
||||
type Request struct {
|
||||
Method string `json:"method"`
|
||||
URL string `json:"url"`
|
||||
Query map[string]interface{} `json:"query"`
|
||||
Form map[string]interface{} `json:"form"`
|
||||
Body interface{} `json:"body"`
|
||||
Headers map[string]string `json:"headers"`
|
||||
}
|
||||
|
||||
// Expect defines the required conditions that must be true from a request response
|
||||
type Expect struct {
|
||||
Body []byte `json:"body"`
|
||||
ContentType string `json:"contentType"`
|
||||
Header []string `json:"header"`
|
||||
HeaderAndValue map[string]string `json:"headerAndValue"`
|
||||
Statuscode int `json:"statusCode"`
|
||||
}
|
40
controllers/nginx/e2e/e2e_types_test.go
Normal file
40
controllers/nginx/e2e/e2e_types_test.go
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
Copyright 2017 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
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestReadYamlCase(t *testing.T) {
|
||||
itc, err := parseTestCase("suite/0001.yaml")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error reading test case 0001: %v", err)
|
||||
}
|
||||
|
||||
if itc == nil {
|
||||
t.Fatal("unexpected decoding of test case 0001")
|
||||
}
|
||||
|
||||
if itc.ReplicationController != nil {
|
||||
t.Fatal("unexpected replication controller in test case 0001")
|
||||
}
|
||||
|
||||
if len(itc.Assert) != 1 {
|
||||
t.Fatalf("expected 1 tests but %v returned", len(itc.Assert))
|
||||
}
|
||||
}
|
161
controllers/nginx/e2e/ingress_test.go
Normal file
161
controllers/nginx/e2e/ingress_test.go
Normal file
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
Copyright 2017 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
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
|
||||
"k8s.io/ingress/controllers/nginx/e2e/util"
|
||||
)
|
||||
|
||||
func TestIngressSuite(t *testing.T) {
|
||||
client, err := util.GetClient()
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error creating k8s client: %v", err)
|
||||
}
|
||||
|
||||
pwd, _ := os.Getwd()
|
||||
filepath.Walk(path.Join(pwd, "/suite"),
|
||||
func(path string, info os.FileInfo, err error) error {
|
||||
if strings.HasSuffix(path, ".yaml") {
|
||||
t.Log(path)
|
||||
runTestCase(path, client, t)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func runTestCase(rawtc string, client kubernetes.Interface, t *testing.T) {
|
||||
tc, err := parseTestCase(rawtc)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error reading Ingress test case file %v: %v", rawtc, err)
|
||||
}
|
||||
|
||||
t.Run(tc.Name, func(t *testing.T) {
|
||||
if len(tc.Assert) == 0 {
|
||||
t.Fatal("test case does not contains tests")
|
||||
}
|
||||
|
||||
if tc.Ingress == nil {
|
||||
t.Fatal("the test case does not contains an Ingress rule")
|
||||
}
|
||||
|
||||
t.Logf("starting deploy of requirements for test case '%v'", tc.Name)
|
||||
err := tc.deploy(client)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error in test case deploy process: %v", err)
|
||||
}
|
||||
|
||||
for _, assert := range tc.Assert {
|
||||
t.Logf("running assert %v", assert.Name)
|
||||
}
|
||||
|
||||
err = tc.undeploy(client)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error in test case deploy process: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// parseTestCase parses a test case from a yaml file
|
||||
func parseTestCase(p string) (*IngressTestCase, error) {
|
||||
file, err := ioutil.ReadFile(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var itc IngressTestCase
|
||||
err = yaml.Unmarshal(file, &itc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &itc, nil
|
||||
}
|
||||
|
||||
// deploy creates the kubernetes object specified in the test case
|
||||
func (tc IngressTestCase) deploy(client kubernetes.Interface) error {
|
||||
_, err := client.Extensions().Ingresses(getNamespace(tc.Ingress.Namespace)).Create(tc.Ingress)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if tc.Service != nil {
|
||||
_, err := client.CoreV1().Services(getNamespace(tc.Service.Namespace)).Create(tc.Service)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if tc.ReplicationController != nil {
|
||||
_, err := client.CoreV1().ReplicationControllers(getNamespace(tc.ReplicationController.Namespace)).Create(tc.ReplicationController)
|
||||
return err
|
||||
} else if tc.Deployment != nil {
|
||||
_, err := client.Extensions().Deployments(getNamespace(tc.Deployment.Namespace)).Create(tc.Deployment)
|
||||
return err
|
||||
}
|
||||
|
||||
return fmt.Errorf("invalid deployment option. Please check the test case")
|
||||
}
|
||||
|
||||
// undeploy removes the kubernetes object created by the test case
|
||||
func (tc IngressTestCase) undeploy(client kubernetes.Interface) error {
|
||||
err := client.Extensions().Ingresses(getNamespace(tc.Ingress.Namespace)).Delete(tc.Ingress.Name, &metav1.DeleteOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if tc.Service != nil {
|
||||
err := client.CoreV1().Services(getNamespace(tc.Service.Namespace)).Delete(tc.Service.Name, &metav1.DeleteOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if tc.ReplicationController != nil {
|
||||
err := client.CoreV1().ReplicationControllers(getNamespace(tc.ReplicationController.Namespace)).Delete(tc.ReplicationController.Name, &metav1.DeleteOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if tc.Deployment != nil {
|
||||
err := client.Extensions().Deployments(getNamespace(tc.Deployment.Namespace)).Delete(tc.Deployment.Name, &metav1.DeleteOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getNamespace(ns string) string {
|
||||
if ns == "" {
|
||||
return "default"
|
||||
}
|
||||
|
||||
return ns
|
||||
}
|
47
controllers/nginx/e2e/nginx-ingress-controller.yaml
Normal file
47
controllers/nginx/e2e/nginx-ingress-controller.yaml
Normal file
|
@ -0,0 +1,47 @@
|
|||
apiVersion: extensions/v1beta1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: nginx-ingress-controller
|
||||
labels:
|
||||
k8s-app: nginx-ingress-controller
|
||||
namespace: kube-system
|
||||
spec:
|
||||
replicas: 1
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
k8s-app: nginx-ingress-controller
|
||||
spec:
|
||||
terminationGracePeriodSeconds: 60
|
||||
containers:
|
||||
- image: gcr.io/google_containers/nginx-ingress-controller-amd64:test
|
||||
name: nginx-ingress-controller
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: 10254
|
||||
scheme: HTTP
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: 10254
|
||||
scheme: HTTP
|
||||
initialDelaySeconds: 10
|
||||
timeoutSeconds: 1
|
||||
ports:
|
||||
- containerPort: 80
|
||||
hostPort: 80
|
||||
- containerPort: 443
|
||||
hostPort: 443
|
||||
env:
|
||||
- name: POD_NAME
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.name
|
||||
- name: POD_NAMESPACE
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.namespace
|
||||
args:
|
||||
- /nginx-ingress-controller
|
||||
- --default-backend-service=$(POD_NAMESPACE)/default-http-backend
|
62
controllers/nginx/e2e/suite/0001.yaml
Normal file
62
controllers/nginx/e2e/suite/0001.yaml
Normal file
|
@ -0,0 +1,62 @@
|
|||
name: "001"
|
||||
description: "simple test"
|
||||
ingress:
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: echomap
|
||||
spec:
|
||||
rules:
|
||||
- host: foo.bar.com
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
backend:
|
||||
serviceName: echoheaders
|
||||
servicePort: 80
|
||||
deployment:
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: http-svc
|
||||
labels:
|
||||
k8s-app: http-svc
|
||||
spec:
|
||||
replicas: 1
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
k8s-app: http-svc
|
||||
spec:
|
||||
containers:
|
||||
- name: http-svc
|
||||
image: gcr.io/google_containers/echoserver:1.8
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: 8080
|
||||
scheme: HTTP
|
||||
initialDelaySeconds: 30
|
||||
timeoutSeconds: 5
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
service:
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: http-svc
|
||||
labels:
|
||||
k8s-app: http-svc
|
||||
spec:
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 8080
|
||||
selector:
|
||||
k8s-app: http-svc
|
||||
tests:
|
||||
- name: "get /"
|
||||
expect:
|
||||
- statusCode: 200
|
||||
request:
|
||||
method: GET
|
||||
url: /
|
223
controllers/nginx/e2e/util/util.go
Normal file
223
controllers/nginx/e2e/util/util.go
Normal file
|
@ -0,0 +1,223 @@
|
|||
/*
|
||||
Copyright 2017 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 util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
apierrs "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
|
||||
"k8s.io/client-go/tools/cache"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
)
|
||||
|
||||
type PodStore struct {
|
||||
cache.Store
|
||||
stopCh chan struct{}
|
||||
Reflector *cache.Reflector
|
||||
}
|
||||
|
||||
func (s *PodStore) List() []*v1.Pod {
|
||||
objects := s.Store.List()
|
||||
pods := make([]*v1.Pod, 0)
|
||||
for _, o := range objects {
|
||||
pods = append(pods, o.(*v1.Pod))
|
||||
}
|
||||
return pods
|
||||
}
|
||||
|
||||
func (s *PodStore) Stop() {
|
||||
close(s.stopCh)
|
||||
}
|
||||
|
||||
func GetClient() (kubernetes.Interface, error) {
|
||||
profile := os.Getenv("MINIKUBE_PROFILE")
|
||||
|
||||
loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
|
||||
configOverrides := &clientcmd.ConfigOverrides{}
|
||||
configOverrides.CurrentContext = profile
|
||||
kubeConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, configOverrides)
|
||||
config, err := kubeConfig.ClientConfig()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error creating kubeConfig: %s", err)
|
||||
}
|
||||
client, err := kubernetes.NewForConfig(config)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Error creating new client from kubeConfig.ClientConfig()")
|
||||
}
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func NewPodStore(c kubernetes.Interface, namespace string, label labels.Selector, field fields.Selector) *PodStore {
|
||||
lw := &cache.ListWatch{
|
||||
ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
|
||||
options.LabelSelector = label.String()
|
||||
options.FieldSelector = field.String()
|
||||
obj, err := c.Core().Pods(namespace).List(options)
|
||||
return runtime.Object(obj), err
|
||||
},
|
||||
WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
|
||||
options.LabelSelector = label.String()
|
||||
options.FieldSelector = field.String()
|
||||
return c.Core().Pods(namespace).Watch(options)
|
||||
},
|
||||
}
|
||||
store := cache.NewStore(cache.MetaNamespaceKeyFunc)
|
||||
stopCh := make(chan struct{})
|
||||
reflector := cache.NewReflector(lw, &v1.Pod{}, store, 0)
|
||||
reflector.Run(stopCh)
|
||||
return &PodStore{Store: store, stopCh: stopCh, Reflector: reflector}
|
||||
}
|
||||
|
||||
func StartPods(c kubernetes.Interface, namespace string, pod v1.Pod, waitForRunning bool) error {
|
||||
pod.ObjectMeta.Labels["name"] = pod.Name
|
||||
if waitForRunning {
|
||||
label := labels.SelectorFromSet(labels.Set(map[string]string{"name": pod.Name}))
|
||||
err := WaitForPodsWithLabelRunning(c, namespace, label)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error waiting for pod %s to be running: %v", pod.Name, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Wait up to 10 minutes for all matching pods to become Running and at least one
|
||||
// matching pod exists.
|
||||
func WaitForPodsWithLabelRunning(c kubernetes.Interface, ns string, label labels.Selector) error {
|
||||
running := false
|
||||
PodStore := NewPodStore(c, ns, label, fields.Everything())
|
||||
defer PodStore.Stop()
|
||||
waitLoop:
|
||||
for start := time.Now(); time.Since(start) < 10*time.Minute; time.Sleep(250 * time.Millisecond) {
|
||||
pods := PodStore.List()
|
||||
if len(pods) == 0 {
|
||||
continue waitLoop
|
||||
}
|
||||
for _, p := range pods {
|
||||
if p.Status.Phase != v1.PodRunning {
|
||||
continue waitLoop
|
||||
}
|
||||
}
|
||||
running = true
|
||||
break
|
||||
}
|
||||
if !running {
|
||||
return fmt.Errorf("Timeout while waiting for pods with labels %q to be running", label.String())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// WaitForRCToStabilize waits till the RC has a matching generation/replica count between spec and status.
|
||||
func WaitForRCToStabilize(t *testing.T, c kubernetes.Interface, ns, name string, timeout time.Duration) error {
|
||||
options := metav1.ListOptions{FieldSelector: fields.Set{
|
||||
"metadata.name": name,
|
||||
"metadata.namespace": ns,
|
||||
}.AsSelector().String()}
|
||||
w, err := c.Core().ReplicationControllers(ns).Watch(options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = watch.Until(timeout, w, func(event watch.Event) (bool, error) {
|
||||
switch event.Type {
|
||||
case watch.Deleted:
|
||||
return false, apierrs.NewNotFound(schema.GroupResource{Resource: "replicationcontrollers"}, "")
|
||||
}
|
||||
switch rc := event.Object.(type) {
|
||||
case *v1.ReplicationController:
|
||||
if rc.Name == name && rc.Namespace == ns &&
|
||||
rc.Generation <= rc.Status.ObservedGeneration &&
|
||||
*(rc.Spec.Replicas) == rc.Status.Replicas {
|
||||
return true, nil
|
||||
}
|
||||
t.Logf("Waiting for rc %s to stabilize, generation %v observed generation %v spec.replicas %d status.replicas %d",
|
||||
name, rc.Generation, rc.Status.ObservedGeneration, *(rc.Spec.Replicas), rc.Status.Replicas)
|
||||
}
|
||||
return false, nil
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// WaitForService waits until the service appears (exist == true), or disappears (exist == false)
|
||||
func WaitForService(t *testing.T, c kubernetes.Interface, namespace, name string, exist bool, interval, timeout time.Duration) error {
|
||||
err := wait.PollImmediate(interval, timeout, func() (bool, error) {
|
||||
_, err := c.Core().Services(namespace).Get(name, metav1.GetOptions{})
|
||||
switch {
|
||||
case err == nil:
|
||||
t.Logf("Service %s in namespace %s found.", name, namespace)
|
||||
return exist, nil
|
||||
case apierrs.IsNotFound(err):
|
||||
t.Logf("Service %s in namespace %s disappeared.", name, namespace)
|
||||
return !exist, nil
|
||||
case !IsRetryableAPIError(err):
|
||||
t.Logf("Non-retryable failure while getting service.")
|
||||
return false, err
|
||||
default:
|
||||
t.Logf("Get service %s in namespace %s failed: %v", name, namespace, err)
|
||||
return false, nil
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
stateMsg := map[bool]string{true: "to appear", false: "to disappear"}
|
||||
return fmt.Errorf("error waiting for service %s/%s %s: %v", namespace, name, stateMsg[exist], err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//WaitForServiceEndpointsNum waits until the amount of endpoints that implement service to expectNum.
|
||||
func WaitForServiceEndpointsNum(t *testing.T, c kubernetes.Interface, namespace, serviceName string, expectNum int, interval, timeout time.Duration) error {
|
||||
return wait.Poll(interval, timeout, func() (bool, error) {
|
||||
t.Logf("Waiting for amount of service:%s endpoints to be %d", serviceName, expectNum)
|
||||
list, err := c.Core().Endpoints(namespace).List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
for _, e := range list.Items {
|
||||
if e.Name == serviceName && countEndpointsNum(&e) == expectNum {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
})
|
||||
}
|
||||
|
||||
func countEndpointsNum(e *v1.Endpoints) int {
|
||||
num := 0
|
||||
for _, sub := range e.Subsets {
|
||||
num += len(sub.Addresses)
|
||||
}
|
||||
return num
|
||||
}
|
||||
|
||||
func IsRetryableAPIError(err error) bool {
|
||||
return apierrs.IsTimeout(err) || apierrs.IsServerTimeout(err) || apierrs.IsTooManyRequests(err) || apierrs.IsInternalError(err)
|
||||
}
|
|
@ -19,6 +19,7 @@ package controller
|
|||
import (
|
||||
"github.com/golang/glog"
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
|
||||
"k8s.io/ingress/core/pkg/ingress/annotations/alias"
|
||||
"k8s.io/ingress/core/pkg/ingress/annotations/auth"
|
||||
"k8s.io/ingress/core/pkg/ingress/annotations/authreq"
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
[[ $DEBUG ]] && set -x
|
||||
|
||||
set -eof pipefail
|
||||
|
||||
# include env
|
||||
. hack/e2e-internal/e2e-env.sh
|
||||
|
||||
echo "Destroying running docker containers..."
|
||||
# do not failt if the container is not running
|
||||
docker rm -f kubelet || true
|
||||
docker rm -f apiserver || true
|
||||
docker rm -f etcd || true
|
|
@ -1,21 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
[[ $DEBUG ]] && set -x
|
||||
|
||||
export ETCD_VERSION=3.0.14
|
||||
export K8S_VERSION=1.4.5
|
||||
|
||||
export PWD=`pwd`
|
||||
export BASEDIR="$(dirname ${BASH_SOURCE})"
|
||||
export KUBECTL="${BASEDIR}/kubectl"
|
||||
export GOOS="${GOOS:-linux}"
|
||||
|
||||
if [ ! -e ${KUBECTL} ]; then
|
||||
echo "kubectl binary is missing. downloading..."
|
||||
curl -sSL http://storage.googleapis.com/kubernetes-release/release/v${K8S_VERSION}/bin/${GOOS}/amd64/kubectl -o ${KUBECTL}
|
||||
chmod u+x ${KUBECTL}
|
||||
fi
|
||||
|
||||
${KUBECTL} config set-cluster travis --server=http://0.0.0.0:8080
|
||||
${KUBECTL} config set-context travis --cluster=travis
|
||||
${KUBECTL} config use-context travis
|
|
@ -1,11 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
[[ $DEBUG ]] && set -x
|
||||
|
||||
set -eof pipefail
|
||||
|
||||
# include env
|
||||
. hack/e2e-internal/e2e-env.sh
|
||||
|
||||
echo "Kubernetes information:"
|
||||
${KUBECTL} version
|
|
@ -1,55 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
[[ $DEBUG ]] && set -x
|
||||
|
||||
set -eof pipefail
|
||||
|
||||
# include env
|
||||
. hack/e2e-internal/e2e-env.sh
|
||||
|
||||
echo "Starting etcd..."
|
||||
docker run -d \
|
||||
--net=host \
|
||||
--name=etcd \
|
||||
quay.io/coreos/etcd:v$ETCD_VERSION
|
||||
|
||||
echo "Starting kubernetes..."
|
||||
|
||||
docker run -d --name=apiserver \
|
||||
--net=host \
|
||||
--pid=host \
|
||||
--privileged=true \
|
||||
gcr.io/google_containers/hyperkube:v${K8S_VERSION} \
|
||||
/hyperkube apiserver \
|
||||
--insecure-bind-address=0.0.0.0 \
|
||||
--service-cluster-ip-range=10.0.0.1/24 \
|
||||
--etcd_servers=http://127.0.0.1:4001 \
|
||||
--v=2
|
||||
|
||||
docker run -d --name=kubelet \
|
||||
--volume=/:/rootfs:ro \
|
||||
--volume=/sys:/sys:ro \
|
||||
--volume=/dev:/dev \
|
||||
--volume=/var/lib/docker/:/var/lib/docker:rw \
|
||||
--volume=/var/lib/kubelet/:/var/lib/kubelet:rw \
|
||||
--volume=/var/run:/var/run:rw \
|
||||
--net=host \
|
||||
--pid=host \
|
||||
--privileged=true \
|
||||
gcr.io/google_containers/hyperkube:v${K8S_VERSION} \
|
||||
/hyperkube kubelet \
|
||||
--containerized \
|
||||
--hostname-override="0.0.0.0" \
|
||||
--address="0.0.0.0" \
|
||||
--cluster_dns=10.0.0.10 --cluster_domain=cluster.local \
|
||||
--api-servers=http://localhost:8080 \
|
||||
--config=/etc/kubernetes/manifests-multi
|
||||
|
||||
echo "waiting until api server is available..."
|
||||
until curl -o /dev/null -sIf http://0.0.0.0:8080; do \
|
||||
sleep 10;
|
||||
done;
|
||||
|
||||
echo "Kubernetes started"
|
||||
echo "Kubernetes information:"
|
||||
${KUBECTL} version
|
|
@ -1,3 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
echo "running ginkgo"
|
Loading…
Reference in a new issue