diff --git a/bin/_test-helpers.sh b/bin/_test-helpers.sh index 1081f10efe47b..599bacbf5f039 100644 --- a/bin/_test-helpers.sh +++ b/bin/_test-helpers.sh @@ -14,7 +14,9 @@ testdir="$bindir"/../test/integration export default_test_names=(deep deep-native-sidecar viz external helm-upgrade uninstall upgrade-edge default-policy-deny rsa-ca) export external_resource_test_names=(external-resources) -export all_test_names=(cluster-domain cni-calico-deep multicluster "${default_test_names[*]}" "${external_resource_test_names[*]}") +# TODO(alpeb): add test cni-calico-deep-dual-stack +export dual_stack_test_names=(deep-dual-stack) +export all_test_names=(cluster-domain cni-calico-deep multicluster "${default_test_names[*]}" "${external_resource_test_names[*]}" "${dual_stack_test_names[*]}") images_load_default=(proxy controller policy-controller web metrics-api tap) tests_usage() { @@ -448,6 +450,10 @@ run_deep-native-sidecar_test() { run_test "$testdir/deep/..." --native-sidecar } +run_deep-dual-stack_test() { + run_test "$testdir/deep/..." --dual-stack +} + run_default-policy-deny_test() { export default_inbound_policy='deny' run_test "$testdir/install/..." diff --git a/test/integration/deep/dualstack/dualstack_test.go b/test/integration/deep/dualstack/dualstack_test.go new file mode 100644 index 0000000000000..1a2e072adfc18 --- /dev/null +++ b/test/integration/deep/dualstack/dualstack_test.go @@ -0,0 +1,180 @@ +package dualstack + +import ( + "context" + "encoding/json" + "fmt" + "io" + "os" + "strings" + "testing" + + "github.com/linkerd/linkerd2/testutil" +) + +type IP struct { + IP string `json:"ip"` +} + +var TestHelper *testutil.TestHelper + +func TestMain(m *testing.M) { + TestHelper = testutil.NewTestHelper() + // Block test execution until control plane is running + TestHelper.WaitUntilDeployReady(testutil.LinkerdDeployReplicasEdge) + os.Exit(m.Run()) +} + +// TestDualStack creates an injected pod that starts two servers, one listening +// on the IPv4 wildcard address and serving the string "IPv4", and another +// listening on the IPv6 wildcard address and serving the string "IPv6". They +// are fronted by a DualStack Service. We test that we can reach those two IPs +// directly, and that making a request to the service's FQDN always hits the +// IPv6 endpoint. +func TestDualStack(t *testing.T) { + if !TestHelper.DualStack() { + t.Skip("Skipping Skip DualStack test") + } + + TestHelper.WithDataPlaneNamespace(context.Background(), "dualstack-test", map[string]string{}, t, func(t *testing.T, ns string) { + out, err := TestHelper.Kubectl("", + "create", "configmap", "go-app", + "--from-file=main.go=testdata/ipfamilies-server.go", + "-n", ns, + ) + if err != nil { + testutil.AnnotatedFatalf(t, "unexpected error", "unexpected error: %v\noutput:\n%s", err, out) + } + + out, err = TestHelper.Kubectl("", + "apply", "-f", "testdata/ipfamilies-server-client.yml", + "-n", ns, + ) + if err != nil { + testutil.AnnotatedFatalf(t, "unexpected error", "unexpected error: %v\noutput:\n%s", err, out) + } + + checkPods(t, ns, "ipfamilies-server") + checkPods(t, ns, "client") + + var clientIPv6, serverIPv4, serverIPv6 string + + t.Run("Retrieve pod IPs", func(t *testing.T) { + cmd := []string{ + "get", "po", + "-o", "jsonpath='{.items[*].status.podIPs}'", + "-n", ns, + } + + out, err = TestHelper.Kubectl("", append(cmd, "-l", "app=server")...) + if err != nil { + testutil.AnnotatedFatalf(t, "unexpected error", "unexpected error: %v\noutput:\n%s", err, out) + } + + var IPs []IP + out = strings.Trim(out, "'") + if err = json.Unmarshal([]byte(out), &IPs); err != nil { + testutil.AnnotatedFatalf(t, "error unmarshaling JSON", "error unmarshaling JSON '%s': %s", out, err) + } + if len(IPs) != 2 { + testutil.AnnotatedFatalf(t, "unexpected number of IPs", "expected 2 IPs, got %s", fmt.Sprint(len(IPs))) + } + serverIPv4 = IPs[0].IP + serverIPv6 = IPs[1].IP + + out, err = TestHelper.Kubectl("", append(cmd, "-l", "app=client")...) + if err != nil { + testutil.AnnotatedFatalf(t, "unexpected error", "unexpected error: %v\noutput:\n%s", err, out) + } + + out = strings.Trim(out, "'") + if err = json.Unmarshal([]byte(out), &IPs); err != nil { + testutil.AnnotatedFatalf(t, "error unmarshaling JSON", "error unmarshaling JSON '%s': %s", out, err) + } + if len(IPs) != 2 { + testutil.AnnotatedFatalf(t, "unexpected number of IPs", "expected 2 IPs, got %s", fmt.Sprint(len(IPs))) + } + clientIPv6 = IPs[1].IP + }) + + t.Run("Apply policy", func(t *testing.T) { + file, err := os.Open("testdata/ipfamilies-policy.yml") + if err != nil { + testutil.AnnotatedFatalf(t, "unexpected error", "unexpected error: %v", err) + } + defer file.Close() + manifest, err := io.ReadAll(file) + if err != nil { + testutil.AnnotatedFatalf(t, "unexpected error", "unexpected error: %v", err) + } + in := strings.ReplaceAll(string(manifest), "{IPv6}", clientIPv6) + out, err = TestHelper.KubectlApply(in, ns) + if err != nil { + testutil.AnnotatedFatalf(t, "unexpected error", "unexpected error: %v\noutput:\n%s", err, out) + } + }) + + t.Run("Hit IPv4 addr directly", func(t *testing.T) { + out, err = TestHelper.Kubectl("", + "exec", "deploy/client", + "-c", "curl", + "-n", ns, + "--", + "curl", "-s", "http://"+serverIPv4+":8080", + ) + if err != nil { + testutil.AnnotatedFatalf(t, "unexpected error", "unexpected error: %v\noutput:\n%s", err, out) + } + if out != "IPv4\n" { + testutil.AnnotatedFatalf(t, "unexpected output", "expected 'IPv4', received '%s'", out) + } + }) + + t.Run("Hit IPv6 addr directly", func(t *testing.T) { + out, err = TestHelper.Kubectl("", + "exec", "deploy/client", + "-c", "curl", + "-n", ns, + "--", + "curl", "-s", "http://["+serverIPv6+"]:8080", + ) + if err != nil { + testutil.AnnotatedFatalf(t, "unexpected error", "unexpected error: %v\noutput:\n%s", err, out) + } + if out != "IPv6\n" { + testutil.AnnotatedFatalf(t, "expected 'IPv6', received '%s'", out) + } + }) + + t.Run("Hit FQDN directly (should always resolve to IPv6)", func(t *testing.T) { + for i := 0; i < 10; i++ { + out, err = TestHelper.Kubectl("", + "exec", "deploy/client", + "-c", "curl", + "-n", ns, + "--", + "curl", "-s", "http://ipfamilies-server:8080", + ) + if err != nil { + testutil.AnnotatedFatalf(t, "unexpected error", "unexpected error: %v\noutput:\n%s", err, out) + } + if out != "IPv6\n" { + testutil.AnnotatedFatalf(t, "expected 'IPv6', received '%s'", out) + } + } + }) + }) +} + +func checkPods(t *testing.T, ns, pod string) { + t.Helper() + + if err := TestHelper.CheckPods(context.Background(), ns, pod, 1); err != nil { + //nolint:errorlint + if rce, ok := err.(*testutil.RestartCountError); ok { + testutil.AnnotatedWarn(t, "CheckPods timed-out", rce) + } else { + testutil.AnnotatedError(t, "CheckPods timed-out", err) + } + } +} diff --git a/test/integration/deep/dualstack/testdata/ipfamilies-policy.yml b/test/integration/deep/dualstack/testdata/ipfamilies-policy.yml new file mode 100644 index 0000000000000..7aac133424c3a --- /dev/null +++ b/test/integration/deep/dualstack/testdata/ipfamilies-policy.yml @@ -0,0 +1,32 @@ +apiVersion: policy.linkerd.io/v1beta2 +kind: Server +metadata: + name: ipfamilies +spec: + podSelector: + matchLabels: + app.kubernetes.io/name: ipfamilies-server + port: http + proxyProtocol: HTTP/1 +--- +apiVersion: policy.linkerd.io/v1alpha1 +kind: AuthorizationPolicy +metadata: + name: ipfamilies +spec: + targetRef: + group: policy.linkerd.io + kind: Server + name: ipfamilies + requiredAuthenticationRefs: + - name: ipfamilies + kind: NetworkAuthentication + group: policy.linkerd.io +--- +apiVersion: policy.linkerd.io/v1alpha1 +kind: NetworkAuthentication +metadata: + name: ipfamilies +spec: + networks: + - cidr: {IPv6}/128 diff --git a/test/integration/deep/dualstack/testdata/ipfamilies-server-client.yml b/test/integration/deep/dualstack/testdata/ipfamilies-server-client.yml new file mode 100644 index 0000000000000..30b16582bf093 --- /dev/null +++ b/test/integration/deep/dualstack/testdata/ipfamilies-server-client.yml @@ -0,0 +1,73 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ipfamilies-server +spec: + selector: + matchLabels: + app: server + template: + metadata: + annotations: + linkerd.io/inject: enabled + labels: + app: server + spec: + containers: + - image: ghcr.io/alpeb/family-server:v1 + image: golang:1.22-alpine + name: ipfamilies-server + ports: + - containerPort: 8080 + name: http + protocol: TCP + command: ["/bin/sh"] + args: + - -c + - 'go run /go/src/app/main.go' + volumeMounts: + - name: go-app + mountPath: /go/src/app + volumes: + - name: go-app + configMap: + name: go-app +--- +apiVersion: v1 +kind: Service +metadata: + name: ipfamilies-server +spec: + ipFamilies: + - IPv4 + - IPv6 + ipFamilyPolicy: RequireDualStack + ports: + - name: http + port: 8080 + protocol: TCP + targetPort: http + selector: + app: server + type: ClusterIP +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: client +spec: + selector: + matchLabels: + app: client + template: + metadata: + annotations: + linkerd.io/inject: enabled + labels: + app: client + spec: + containers: + - name: curl + image: curlimages/curl + command: [ "sh", "-c", "--" ] + args: [ "sleep infinity" ] diff --git a/test/integration/deep/dualstack/testdata/ipfamilies-server.go b/test/integration/deep/dualstack/testdata/ipfamilies-server.go new file mode 100644 index 0000000000000..aa216721b5f07 --- /dev/null +++ b/test/integration/deep/dualstack/testdata/ipfamilies-server.go @@ -0,0 +1,41 @@ +package main + +import ( + "fmt" + "log" + "net" + "net/http" +) + +type ( + ipv4Handler struct{} + ipv6Handler struct{} +) + +func (ipv4Handler) ServeHTTP(w http.ResponseWriter, _ *http.Request) { + fmt.Fprintf(w, "IPv4\n") +} + +func (ipv6Handler) ServeHTTP(w http.ResponseWriter, _ *http.Request) { + fmt.Fprintf(w, "IPv6\n") +} + +func main() { + log.Print("Server started") + + go func() { + ln, err := net.Listen("tcp4", "0.0.0.0:8080") + if err != nil { + log.Fatal(err) + } + srv := &http.Server{Handler: ipv4Handler{}} + log.Fatal(srv.Serve(ln)) + }() + + ln, err := net.Listen("tcp6", "[::]:8080") + if err != nil { + log.Fatal(err) + } + srv := &http.Server{Handler: ipv6Handler{}} + log.Fatal(srv.Serve(ln)) +} diff --git a/test/integration/deep/endpoints/endpoints_test.go b/test/integration/deep/endpoints/endpoints_test.go index 02f98cd62afbc..5818ae6473d67 100644 --- a/test/integration/deep/endpoints/endpoints_test.go +++ b/test/integration/deep/endpoints/endpoints_test.go @@ -108,7 +108,7 @@ func createTestCaseTable(controlNs, endpointNs string) []testCase { expectedRE: `\[ \{ "namespace": "(\S*)", - "ip": "\d+\.\d+\.\d+\.\d+", + "ip": "[a-f0-9.:]+", "port": 8086, "pod": "linkerd-destination\-[a-f0-9]+\-[a-z0-9]+", "service": "linkerd-dst\.\S*", @@ -125,7 +125,7 @@ func createTestCaseTable(controlNs, endpointNs string) []testCase { expectedRE: `\[ \{ "namespace": "(\S*)", - "ip": "\d+\.\d+\.\d+\.\d+", + "ip": "[a-f0-9.:]+", "port": 8080, "pod": "linkerd-identity\-[a-f0-9]+\-[a-z0-9]+", "service": "linkerd-identity\.\S*", @@ -142,7 +142,7 @@ func createTestCaseTable(controlNs, endpointNs string) []testCase { expectedRE: `\[ \{ "namespace": "(\S*)", - "ip": "\d+\.\d+\.\d+\.\d+", + "ip": "[a-f0-9.:]+", "port": 8443, "pod": "linkerd-proxy-injector-[a-f0-9]+\-[a-z0-9]+", "service": "linkerd-proxy-injector\.\S*", @@ -159,7 +159,7 @@ func createTestCaseTable(controlNs, endpointNs string) []testCase { expectedRE: `\[ \{ "namespace": "(\S*)", - "ip": "\d+\.\d+\.\d+\.\d+", + "ip": "[a-f0-9.:]+", "port": 8080, "pod": "nginx-[a-f0-9]+\-[a-z0-9]+", "service": "nginx\.\S*", diff --git a/test/integration/deep/install_test.go b/test/integration/deep/install_test.go index d29d9fdefa9f1..5d70e752b89b2 100644 --- a/test/integration/deep/install_test.go +++ b/test/integration/deep/install_test.go @@ -126,6 +126,10 @@ func TestInstall(t *testing.T) { cmd = append(cmd, "--set", "proxy.nativeSidecar=true") } + if TestHelper.DualStack() { + cmd = append(cmd, "--set", "disableIPv6=false") + } + // Pipe cmd & args to `linkerd` out, err = TestHelper.LinkerdRun(cmd...) if err != nil { diff --git a/test/integration/deep/kind-dualstack.yml b/test/integration/deep/kind-dualstack.yml new file mode 100644 index 0000000000000..ab9a0688231a6 --- /dev/null +++ b/test/integration/deep/kind-dualstack.yml @@ -0,0 +1,4 @@ +kind: Cluster +apiVersion: kind.x-k8s.io/v1alpha4 +networking: + ipFamily: dual diff --git a/test/integration/deep/kind-ipv6.yml b/test/integration/deep/kind-ipv6.yml new file mode 100644 index 0000000000000..042732ba61352 --- /dev/null +++ b/test/integration/deep/kind-ipv6.yml @@ -0,0 +1,4 @@ +kind: Cluster +apiVersion: kind.x-k8s.io/v1alpha4 +networking: + ipFamily: ipv6 diff --git a/test/integration/deep/localhost/localhost_test.go b/test/integration/deep/localhost/localhost_test.go index baebf910ae729..ce4053bdcd027 100644 --- a/test/integration/deep/localhost/localhost_test.go +++ b/test/integration/deep/localhost/localhost_test.go @@ -3,6 +3,7 @@ package localhost import ( "context" "fmt" + "net/netip" "os" "regexp" "testing" @@ -163,7 +164,16 @@ func TestLocalhostRouting(t *testing.T) { testutil.AnnotatedFatalf(t, "unexpected error", "unexpected error: no IP address found for %s/%s", ns, podName) } - statusCode, err := TestHelper.Kubectl("", append(execCommand, podIP)...) + addr, err := netip.ParseAddr(podIP) + if err != nil { + testutil.AnnotatedFatalf(t, "Invalid IP", "Invalid IP '%s': %s", podIP, err) + } + if addr.Is6() { + podIP = fmt.Sprintf("[%s]", podIP) + } + url := fmt.Sprintf("http://%s:80", podIP) + + statusCode, err := TestHelper.Kubectl("", append(execCommand, url)...) if err != nil { testutil.AnnotatedFatalf(t, "unexpected error received when calling 'kubectl exec'", "unexpected error received when calling 'kubectl exec': %v", err) } diff --git a/test/integration/deep/localhost/testdata/nginx-and-curl.yaml b/test/integration/deep/localhost/testdata/nginx-and-curl.yaml index dd73b101a3194..5b652fd748279 100644 --- a/test/integration/deep/localhost/testdata/nginx-and-curl.yaml +++ b/test/integration/deep/localhost/testdata/nginx-and-curl.yaml @@ -16,7 +16,7 @@ spec: spec: containers: - name: nginx - image: nginx:1.14.2 + image: nginx:1.25.5 ports: - containerPort: 80 - name: curl diff --git a/test/integration/deep/skipports/skip_ports_test.go b/test/integration/deep/skipports/skip_ports_test.go index 87f11c5d5fbfa..703e990379b54 100644 --- a/test/integration/deep/skipports/skip_ports_test.go +++ b/test/integration/deep/skipports/skip_ports_test.go @@ -14,8 +14,8 @@ import ( var TestHelper *testutil.TestHelper var ( - skipPortsNs = "skip-ports-test" - booksappDeployments = []string{"books", "traffic", "authors", "webapp"} + skipPortsNs = "skip-ports-test" + emojivotoDeployments = []string{"emoji", "vote-bot", "voting", "web"} ) func secureRequestMatcher(dst string) *prommatch.Matcher { @@ -65,8 +65,8 @@ func TestSkipInboundPorts(t *testing.T) { "'kubectl apply' command failed\n%s", out) } - // Check all booksapp deployments are up and running - for _, deploy := range booksappDeployments { + // Check all emojivoto deployments are up and running + for _, deploy := range emojivotoDeployments { if err := TestHelper.CheckPods(ctx, ns, deploy, 1); err != nil { //nolint:errorlint if rce, ok := err.(*testutil.RestartCountError); ok { @@ -81,7 +81,7 @@ func TestSkipInboundPorts(t *testing.T) { // Wait for slow-cookers to start sending requests by using a short // time window through RetryFor. err := testutil.RetryFor(30*time.Second, func() error { - pods, err := TestHelper.GetPods(ctx, ns, map[string]string{"app": "webapp"}) + pods, err := TestHelper.GetPods(ctx, ns, map[string]string{"app": "web-svc"}) if err != nil { return fmt.Errorf("error getting pods\n%w", err) } @@ -94,10 +94,10 @@ func TestSkipInboundPorts(t *testing.T) { return fmt.Errorf("error getting metrics for pod\n%w", err) } s := prommatch.Suite{}. - MustContain("secure requests to authors", secureRequestMatcher("authors")). - MustContain("insecure requests to books", insecureRequestMatcher("books")). - MustNotContain("insecure requests to authors", insecureRequestMatcher("authors")). - MustNotContain("secure requests to books", secureRequestMatcher("books")) + MustContain("secure requests to emoji-svc", secureRequestMatcher("emoji-svc")). + MustContain("insecure requests to voting-svc", insecureRequestMatcher("voting-svc")). + MustNotContain("insecure requests to emoji-svc", insecureRequestMatcher("emoji-svc")). + MustNotContain("secure requests to voting-svc", secureRequestMatcher("voting-svc")) if err := s.CheckString(metrics); err != nil { return fmt.Errorf("error matching metrics\n%w", err) } diff --git a/test/integration/deep/skipports/testdata/skip_ports_application.yaml b/test/integration/deep/skipports/testdata/skip_ports_application.yaml index e1142a3b2a4ef..43ab2cdb203db 100644 --- a/test/integration/deep/skipports/testdata/skip_ports_application.yaml +++ b/test/integration/deep/skipports/testdata/skip_ports_application.yaml @@ -1,191 +1,207 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: emoji +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: voting +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: web --- apiVersion: v1 kind: Service metadata: - name: webapp - labels: - app: webapp - project: booksapp + name: emoji-svc spec: - selector: - app: webapp - type: ClusterIP ports: - - name: service - port: 7000 + - name: grpc + port: 8080 + targetPort: 8080 + - name: prom + port: 8801 + targetPort: 8801 + selector: + app: emoji-svc --- -kind: Deployment -apiVersion: apps/v1 +apiVersion: v1 +kind: Service metadata: - name: webapp - labels: - app: webapp - project: booksapp - app.kubernetes.io/part-of: booksapp + name: voting-svc spec: - replicas: 1 + ports: + - name: grpc + port: 8080 + targetPort: 8080 + - name: prom + port: 8801 + targetPort: 8801 selector: - matchLabels: - app: webapp - project: booksapp - template: - metadata: - labels: - app: webapp - project: booksapp - spec: - dnsPolicy: ClusterFirst - containers: - - name: service - image: buoyantio/booksapp:v0.0.5 - env: - - name: DATABASE_URL - value: sqlite3:db/db.sqlite3 - - name: AUTHORS_SITE - value: http://authors:7001 - - name: BOOKS_SITE - value: http://books:7002 - args: ["prod:webapp"] - readinessProbe: - httpGet: - path: /ping - port: 7000 - ports: - - name: service - containerPort: 7000 + app: voting-svc --- apiVersion: v1 kind: Service metadata: - name: authors - labels: - app: authors - project: booksapp + name: web-svc spec: - selector: - app: authors ports: - - name: service - port: 7001 + - name: http + port: 80 + targetPort: 8080 + selector: + app: web-svc + type: ClusterIP --- -kind: Deployment apiVersion: apps/v1 +kind: Deployment metadata: - name: authors labels: - app: authors - project: booksapp - app.kubernetes.io/part-of: booksapp + app.kubernetes.io/name: emoji + app.kubernetes.io/part-of: emojivoto + app.kubernetes.io/version: v11 + name: emoji spec: replicas: 1 selector: matchLabels: - app: authors - project: booksapp + app: emoji-svc + version: v11 template: metadata: labels: - app: authors - project: booksapp + app: emoji-svc + version: v11 spec: - dnsPolicy: ClusterFirst containers: - - name: service - image: buoyantio/booksapp:v0.0.5 - env: - - name: DATABASE_URL - value: sqlite3:db/db.sqlite3 - - name: BOOKS_SITE - value: http://books:7002 - - name: FAILURE_RATE - value: "0.0" - args: ["prod:authors"] - readinessProbe: - httpGet: - path: /ping - port: 7001 + - env: + - name: GRPC_PORT + value: "8080" + - name: PROM_PORT + value: "8801" + image: docker.l5d.io/buoyantio/emojivoto-emoji-svc:v11 + name: emoji-svc ports: - - name: service - containerPort: 7001 + - containerPort: 8080 + name: grpc + - containerPort: 8801 + name: prom + resources: + requests: + cpu: 100m + serviceAccountName: emoji --- -apiVersion: v1 -kind: Service +apiVersion: apps/v1 +kind: Deployment metadata: - name: books labels: - app: books - project: booksapp + app.kubernetes.io/name: vote-bot + app.kubernetes.io/part-of: emojivoto + app.kubernetes.io/version: v11 + name: vote-bot spec: + replicas: 1 selector: - app: books - ports: - - name: service - port: 7002 + matchLabels: + app: vote-bot + version: v11 + template: + metadata: + labels: + app: vote-bot + version: v11 + spec: + containers: + - command: + - emojivoto-vote-bot + env: + - name: WEB_HOST + value: web-svc:80 + image: docker.l5d.io/buoyantio/emojivoto-web:v11 + name: vote-bot + resources: + requests: + cpu: 10m --- -kind: Deployment apiVersion: apps/v1 +kind: Deployment metadata: - name: books labels: - app: books - project: booksapp - app.kubernetes.io/part-of: booksapp + app.kubernetes.io/name: voting + app.kubernetes.io/part-of: emojivoto + app.kubernetes.io/version: v11 + name: voting spec: replicas: 1 selector: matchLabels: - app: books - project: booksapp + app: voting-svc + version: v11 template: metadata: annotations: - config.linkerd.io/skip-inbound-ports: "7002" + config.linkerd.io/skip-inbound-ports: "8080" labels: - app: books - project: booksapp + app: voting-svc + version: v11 spec: - dnsPolicy: ClusterFirst containers: - - name: service - image: buoyantio/booksapp:v0.0.5 - env: - - name: DATABASE_URL - value: sqlite3:db/db.sqlite3 - - name: AUTHORS_SITE - value: http://authors:7001 - args: ["prod:books"] - readinessProbe: - httpGet: - path: /ping - port: 7002 + - env: + - name: GRPC_PORT + value: "8080" + - name: PROM_PORT + value: "8801" + image: docker.l5d.io/buoyantio/emojivoto-voting-svc:v11 + name: voting-svc ports: - - name: service - containerPort: 7002 + - containerPort: 8080 + name: grpc + - containerPort: 8801 + name: prom + resources: + requests: + cpu: 100m + serviceAccountName: voting --- -kind: Deployment apiVersion: apps/v1 +kind: Deployment metadata: - name: traffic labels: - app: traffic - project: booksapp - app.kubernetes.io/part-of: booksapp + app.kubernetes.io/name: web + app.kubernetes.io/part-of: emojivoto + app.kubernetes.io/version: v11 + name: web spec: replicas: 1 selector: matchLabels: - app: traffic - project: booksapp + app: web-svc + version: v11 template: metadata: labels: - app: traffic - project: booksapp + app: web-svc + version: v11 spec: - dnsPolicy: ClusterFirst containers: - - name: traffic - image: buoyantio/booksapp-traffic:v0.0.3 - args: - - "-initial-delay=30s" - - "webapp:7000" + - env: + - name: WEB_PORT + value: "8080" + - name: EMOJISVC_HOST + value: emoji-svc:8080 + - name: VOTINGSVC_HOST + value: voting-svc:8080 + - name: INDEX_BUNDLE + value: dist/index_bundle.js + image: docker.l5d.io/buoyantio/emojivoto-web:v11 + name: web-svc + ports: + - containerPort: 8080 + name: http + resources: + requests: + cpu: 100m + serviceAccountName: web diff --git a/testutil/test_helper.go b/testutil/test_helper.go index e19e8e233c9b9..b3034e0cdcadd 100644 --- a/testutil/test_helper.go +++ b/testutil/test_helper.go @@ -38,6 +38,7 @@ type TestHelper struct { uninstall bool cni bool calico bool + dualStack bool nativeSidecar bool defaultInboundPolicy string httpClient http.Client @@ -208,6 +209,7 @@ func NewTestHelper() *TestHelper { uninstall := flag.Bool("uninstall", false, "whether to run the 'linkerd uninstall' integration test") cni := flag.Bool("cni", false, "whether to install linkerd with CNI enabled") calico := flag.Bool("calico", false, "whether to install calico CNI plugin") + dualStack := flag.Bool("dual-stack", false, "whether to run the dual-stack tests") nativeSidecar := flag.Bool("native-sidecar", false, "whether to install using native sidecar injection") defaultInboundPolicy := flag.String("default-inbound-policy", "", "if non-empty, passed to --set proxy.defaultInboundPolicy at linkerd's install time") flag.Parse() @@ -254,6 +256,7 @@ func NewTestHelper() *TestHelper { externalPrometheus: *externalPrometheus, cni: *cni, calico: *calico, + dualStack: *dualStack, nativeSidecar: *nativeSidecar, uninstall: *uninstall, defaultInboundPolicy: *defaultInboundPolicy, @@ -399,6 +402,11 @@ func (h *TestHelper) Calico() bool { return h.calico } +// DualStack determines whether the DualStack tests are run +func (h *TestHelper) DualStack() bool { + return h.dualStack +} + // NativeSidecar determines whether native sidecar injection is enabled func (h *TestHelper) NativeSidecar() bool { return h.nativeSidecar