fn_addons.go 8.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
// +build integration

/*
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 integration

import (
22
	"bufio"
23
	"fmt"
24
	"io/ioutil"
25
	"net"
26
	"net/http"
27
	"net/url"
K
kairen 已提交
28
	"path/filepath"
29
	"strings"
30 31 32
	"testing"
	"time"

33 34
	"github.com/pkg/errors"

35
	retryablehttp "github.com/hashicorp/go-retryablehttp"
36
	"k8s.io/apimachinery/pkg/labels"
37
	commonutil "k8s.io/minikube/pkg/util"
M
Matt Rickard 已提交
38
	pkgutil "k8s.io/minikube/pkg/util"
39 40 41
	"k8s.io/minikube/test/integration/util"
)

42 43
func testAddons(t *testing.T) {
	t.Parallel()
M
Medya Gh 已提交
44 45
	p := "minikube"
	client, err := pkgutil.GetClient(p)
46
	if err != nil {
47
		t.Fatalf("Could not get kubernetes client: %v", err)
48
	}
49
	selector := labels.SelectorFromSet(labels.Set(map[string]string{"component": "kube-addon-manager"}))
M
Matt Rickard 已提交
50
	if err := pkgutil.WaitForPodsWithLabelRunning(client, "kube-system", selector); err != nil {
51
		t.Errorf("Error waiting for addon manager to be up")
52 53 54
	}
}

55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
func readLineWithTimeout(b *bufio.Reader, timeout time.Duration) (string, error) {
	s := make(chan string)
	e := make(chan error)
	go func() {
		read, err := b.ReadString('\n')
		if err != nil {
			e <- err
		} else {
			s <- read
		}
		close(s)
		close(e)
	}()

	select {
	case line := <-s:
		return line, nil
	case err := <-e:
		return "", err
	case <-time.After(timeout):
		return "", fmt.Errorf("timeout after %s", timeout)
	}
}

79 80
func testDashboard(t *testing.T) {
	t.Parallel()
M
Medya Gh 已提交
81 82
	p := "minikube"
	mk := NewMinikubeRunner(t, p, "--wait=false")
83
	cmd, out := mk.RunDaemon("dashboard --url")
84 85
	defer func() {
		err := cmd.Process.Kill()
86
		if err != nil {
87
			t.Logf("Failed to kill dashboard command: %v", err)
88
		}
89 90
	}()

91
	s, err := readLineWithTimeout(out, 240*time.Second)
92 93
	if err != nil {
		t.Fatalf("failed to read url: %v", err)
94
	}
95

96 97 98
	u, err := url.Parse(strings.TrimSpace(s))
	if err != nil {
		t.Fatalf("failed to parse %q: %v", s, err)
99
	}
100

101
	if u.Scheme != "http" {
102
		t.Errorf("got Scheme %s, expected http", u.Scheme)
103
	}
104
	host, _, err := net.SplitHostPort(u.Host)
105
	if err != nil {
106
		t.Fatalf("failed SplitHostPort: %v", err)
107 108
	}
	if host != "127.0.0.1" {
109 110 111
		t.Errorf("got host %s, expected 127.0.0.1", host)
	}

112
	resp, err := retryablehttp.Get(u.String())
113 114 115 116 117 118 119 120 121
	if err != nil {
		t.Fatalf("failed get: %v", err)
	}
	if resp.StatusCode != http.StatusOK {
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			t.Fatalf("Unable to read http response body: %v", err)
		}
		t.Errorf("%s returned status code %d, expected %d.\nbody:\n%s", u, resp.StatusCode, http.StatusOK, body)
122
	}
123
}
124

K
kairen 已提交
125 126
func testIngressController(t *testing.T) {
	t.Parallel()
M
Medya Gh 已提交
127 128 129
	p := "minikube"
	mk := NewMinikubeRunner(t, p, "--wait=false")
	kr := util.NewKubectlRunner(t, p)
K
kairen 已提交
130

131
	mk.RunCommand("addons enable ingress", true)
132
	if err := waitForIngressControllerRunning(p); err != nil {
133
		t.Fatalf("Failed waiting for ingress-controller to be up: %v", err)
K
kairen 已提交
134 135
	}

M
Medya Gh 已提交
136
	ingressPath := filepath.Join(*testdataDir, "nginx-ing.yaml")
137
	if _, err := kr.RunCommand([]string{"create", "-f", ingressPath}); err != nil {
138
		t.Fatalf("Failed creating nginx ingress resource: %v", err)
K
kairen 已提交
139 140
	}

M
Medya Gh 已提交
141
	podPath := filepath.Join(*testdataDir, "nginx-pod-svc.yaml")
142
	if _, err := kr.RunCommand([]string{"create", "-f", podPath}); err != nil {
143
		t.Fatalf("Failed creating nginx ingress resource: %v", err)
K
kairen 已提交
144 145
	}

146
	if err := waitForNginxRunning(t, p); err != nil {
147
		t.Fatalf("Failed waiting for nginx to be up: %v", err)
K
kairen 已提交
148 149
	}

150 151 152
	checkIngress := func() error {
		expectedStr := "Welcome to nginx!"
		runCmd := fmt.Sprintf("curl http://127.0.0.1:80 -H 'Host: nginx.example.com'")
153
		sshCmdOutput, _ := mk.SSH(runCmd)
154 155 156 157 158 159
		if !strings.Contains(sshCmdOutput, expectedStr) {
			return fmt.Errorf("ExpectedStr sshCmdOutput to be: %s. Output was: %s", expectedStr, sshCmdOutput)
		}
		return nil
	}

160
	if err := util.Retry(t, checkIngress, 2*time.Second, 5); err != nil {
161
		t.Fatalf(err.Error())
K
kairen 已提交
162 163
	}

164 165
	defer func() {
		for _, p := range []string{podPath, ingressPath} {
166
			if out, err := kr.RunCommand([]string{"delete", "-f", p}); err != nil {
167 168 169 170
				t.Logf("delete -f %s failed: %v\noutput: %s\n", p, err, out)
			}
		}
	}()
171
	mk.RunCommand("addons disable ingress", true)
K
kairen 已提交
172 173
}

174 175
func testServicesList(t *testing.T) {
	t.Parallel()
M
Medya Gh 已提交
176 177
	p := "minikube"
	mk := NewMinikubeRunner(t, p)
178

179
	checkServices := func() error {
M
Medya Gh 已提交
180
		output, stderr := mk.RunCommand("service list", false)
181
		if !strings.Contains(output, "kubernetes") {
M
Medya Gh 已提交
182
			return fmt.Errorf("error, kubernetes service missing from output: %s, \n stderr: %s", output, stderr)
183
		}
184 185
		return nil
	}
186
	if err := util.Retry(t, checkServices, 2*time.Second, 5); err != nil {
187
		t.Fatalf(err.Error())
188 189
	}
}
190 191
func testRegistry(t *testing.T) {
	t.Parallel()
M
Medya Gh 已提交
192 193
	p := "minikube"
	mk := NewMinikubeRunner(t, p)
194
	mk.RunCommand("addons enable registry", true)
M
Medya Gh 已提交
195
	client, err := pkgutil.GetClient(p)
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
	if err != nil {
		t.Fatalf("getting kubernetes client: %v", err)
	}
	if err := pkgutil.WaitForRCToStabilize(client, "kube-system", "registry", time.Minute*5); err != nil {
		t.Fatalf("waiting for registry replicacontroller to stabilize: %v", err)
	}
	rs := labels.SelectorFromSet(labels.Set(map[string]string{"actual-registry": "true"}))
	if err := pkgutil.WaitForPodsWithLabelRunning(client, "kube-system", rs); err != nil {
		t.Fatalf("waiting for registry pods: %v", err)
	}
	ps, err := labels.Parse("kubernetes.io/minikube-addons=registry,actual-registry!=true")
	if err != nil {
		t.Fatalf("Unable to parse selector: %v", err)
	}
	if err := pkgutil.WaitForPodsWithLabelRunning(client, "kube-system", ps); err != nil {
		t.Fatalf("waiting for registry-proxy pods: %v", err)
	}
M
Medya Gh 已提交
213 214
	ip, stderr := mk.RunCommand("ip", true)
	ip = strings.TrimSpace(ip)
215 216 217
	endpoint := fmt.Sprintf("http://%s:%d", ip, 5000)
	u, err := url.Parse(endpoint)
	if err != nil {
M
Medya Gh 已提交
218
		t.Fatalf("failed to parse %q: %v stderr : %s", endpoint, err, stderr)
219
	}
220
	t.Log("checking registry access from outside cluster")
B
Ben Ebsworth 已提交
221

222 223
	// Check access from outside the cluster on port 5000, validing connectivity via registry-proxy
	checkExternalAccess := func() error {
B
Ben Ebsworth 已提交
224 225
		resp, err := retryablehttp.Get(u.String())
		if err != nil {
226
			t.Errorf("failed get: %v", err)
B
Ben Ebsworth 已提交
227 228 229
		}

		if resp.StatusCode != http.StatusOK {
230
			t.Errorf("%s returned status code %d, expected %d.\n", u, resp.StatusCode, http.StatusOK)
B
Ben Ebsworth 已提交
231
		}
232 233
		return nil
	}
234

235 236 237
	if err := util.Retry(t, checkExternalAccess, 2*time.Second, 5); err != nil {
		t.Fatalf(err.Error())
	}
238

239
	t.Log("checking registry access from inside cluster")
M
Medya Gh 已提交
240 241
	kr := util.NewKubectlRunner(t, p)
	// TODO: Fix this
242
	out, _ := kr.RunCommand([]string{
243 244 245 246 247 248 249 250 251 252
		"run",
		"registry-test",
		"--restart=Never",
		"--image=busybox",
		"-it",
		"--",
		"sh",
		"-c",
		"wget --spider -S 'http://registry.kube-system.svc.cluster.local' 2>&1 | grep 'HTTP/' | awk '{print $2}'"})
	internalCheckOutput := string(out)
253
	expectedStr := "200"
254 255 256
	if !strings.Contains(internalCheckOutput, expectedStr) {
		t.Fatalf("ExpectedStr internalCheckOutput to be: %s. Output was: %s", expectedStr, internalCheckOutput)
	}
257

258
	defer func() {
259
		if _, err := kr.RunCommand([]string{"delete", "pod", "registry-test"}); err != nil {
260
			t.Fatalf("failed to delete pod registry-test")
B
Ben Ebsworth 已提交
261
		}
262
	}()
263
	mk.RunCommand("addons disable registry", true)
264
}
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302

// waitForNginxRunning waits for nginx service to be up
func waitForNginxRunning(t *testing.T, miniProfile string) error {
	client, err := commonutil.GetClient(miniProfile)

	if err != nil {
		return errors.Wrap(err, "getting kubernetes client")
	}

	selector := labels.SelectorFromSet(labels.Set(map[string]string{"run": "nginx"}))
	if err := commonutil.WaitForPodsWithLabelRunning(client, "default", selector); err != nil {
		return errors.Wrap(err, "waiting for nginx pods")
	}

	if err := commonutil.WaitForService(client, "default", "nginx", true, time.Millisecond*500, time.Minute*10); err != nil {
		t.Errorf("Error waiting for nginx service to be up")
	}
	return nil
}

// waitForIngressControllerRunning waits until ingress controller pod to be running
func waitForIngressControllerRunning(miniProfile string) error {
	client, err := commonutil.GetClient(miniProfile)
	if err != nil {
		return errors.Wrap(err, "getting kubernetes client")
	}

	if err := commonutil.WaitForDeploymentToStabilize(client, "kube-system", "nginx-ingress-controller", time.Minute*10); err != nil {
		return errors.Wrap(err, "waiting for ingress-controller deployment to stabilize")
	}

	selector := labels.SelectorFromSet(labels.Set(map[string]string{"app.kubernetes.io/name": "nginx-ingress-controller"}))
	if err := commonutil.WaitForPodsWithLabelRunning(client, "kube-system", selector); err != nil {
		return errors.Wrap(err, "waiting for ingress-controller pods")
	}

	return nil
}