Repository: linkerd/linkerd2
Pull request #6166 (2021-05-24 08:05:48)

jaeger: add install unit tests
Manifests are very prone to go wrong as Helm indentation
changes, etc are very easy to go wrong. This PR adds
unit tests to the render logic, so that changes to the
output manifests are tracked.

This follows the same pattern as that of other render
unit tests in core cp, viz, etc.

Signed-off-by: Tarun Pothulapati <tarunpothulapati@outlook.com>



Patch:
diff --git a/.github/workflows/static_checks.yml b/.github/workflows/static_checks.yml
index 4ed43e34a..a7754b738 100644
--- a/.github/workflows/static_checks.yml
+++ b/.github/workflows/static_checks.yml
@@ -13,7 +13,7 @@ jobs:
     timeout-minutes: 10
     runs-on: ubuntu-20.04
     container:
-      image: golang:1.16.2
+      image: golang:1.16.4
     steps:
     - name: Checkout code
       uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4
@@ -24,7 +24,7 @@ jobs:
     timeout-minutes: 10
     runs-on: ubuntu-20.04
     container:
-      image: golang:1.16.2
+      image: golang:1.16.4
     steps:
     - name: Checkout code
       uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4
@@ -35,7 +35,7 @@ jobs:
     timeout-minutes: 10
     runs-on: ubuntu-20.04
     container:
-      image: golang:1.16.2
+      image: golang:1.16.4
     steps:
       - name: Prerequisites
         run: apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -y --no-install-recommends install unzip
diff --git a/Dockerfile-proxy b/Dockerfile-proxy
index dddcadd08..8650b118a 100644
--- a/Dockerfile-proxy
+++ b/Dockerfile-proxy
@@ -2,7 +2,7 @@ ARG RUNTIME_IMAGE=debian:buster-20210208-slim
 ARG BUILDPLATFORM=linux/amd64
 
 # Precompile key slow-to-build dependencies
-FROM --platform=$BUILDPLATFORM golang:1.16.2-alpine as go-deps
+FROM --platform=$BUILDPLATFORM golang:1.16.4-alpine as go-deps
 WORKDIR /linkerd-build
 COPY go.mod go.sum ./
 COPY bin/install-deps bin/
diff --git a/cli/Dockerfile-bin b/cli/Dockerfile-bin
index d4eba7bb3..c372bdabf 100644
--- a/cli/Dockerfile-bin
+++ b/cli/Dockerfile-bin
@@ -2,7 +2,7 @@ ARG BUILDPLATFORM=linux/amd64
 ARG BUILD_STAGE=single-arch
 
 # Precompile key slow-to-build dependencies
-FROM --platform=$BUILDPLATFORM golang:1.16.2-alpine as go-deps
+FROM --platform=$BUILDPLATFORM golang:1.16.4-alpine as go-deps
 WORKDIR /linkerd-build
 COPY go.mod go.sum ./
 COPY bin/install-deps bin/
diff --git a/cni-plugin/Dockerfile b/cni-plugin/Dockerfile
index 7e974d314..b8455e63c 100644
--- a/cni-plugin/Dockerfile
+++ b/cni-plugin/Dockerfile
@@ -1,7 +1,7 @@
 ARG BUILDPLATFORM=linux/amd64
 
 # Precompile key slow-to-build dependencies
-FROM --platform=$BUILDPLATFORM golang:1.16.2-alpine as go-deps
+FROM --platform=$BUILDPLATFORM golang:1.16.4-alpine as go-deps
 WORKDIR /linkerd-build
 COPY go.mod go.sum ./
 COPY bin/install-deps bin/
diff --git a/controller/Dockerfile b/controller/Dockerfile
index 373d776fb..2be516b13 100644
--- a/controller/Dockerfile
+++ b/controller/Dockerfile
@@ -1,7 +1,7 @@
 ARG BUILDPLATFORM=linux/amd64
 
 # Precompile key slow-to-build dependencies
-FROM --platform=$BUILDPLATFORM golang:1.16.2-alpine as go-deps
+FROM --platform=$BUILDPLATFORM golang:1.16.4-alpine as go-deps
 WORKDIR /linkerd-build
 COPY go.mod go.sum ./
 COPY bin/install-deps bin/
diff --git a/controller/api/destination/endpoint_translator.go b/controller/api/destination/endpoint_translator.go
index 2cd8af5ee..76d8f7064 100644
--- a/controller/api/destination/endpoint_translator.go
+++ b/controller/api/destination/endpoint_translator.go
@@ -329,12 +329,12 @@ func toWeightedAddr(address watcher.Address, opaquePorts, skippedInboundPorts ma
 	// If the pod is controlled by any Linkerd control plane, then it can be
 	// hinted that this destination knows H2 (and handles our orig-proto
 	// translation)
-	var hint *pb.ProtocolHint
-	if enableH2Upgrade && controllerNSLabel != "" && !isSkippedInboundPort {
-		hint = &pb.ProtocolHint{
-			Protocol: &pb.ProtocolHint_H2_{
+	hint := &pb.ProtocolHint{}
+	if controllerNSLabel != "" && !isSkippedInboundPort {
+		if enableH2Upgrade {
+			hint.Protocol = &pb.ProtocolHint_H2_{
 				H2: &pb.ProtocolHint_H2{},
-			},
+			}
 		}
 		if _, ok := opaquePorts[address.Port]; ok {
 			port, err := getInboundPort(&address.Pod.Spec)
diff --git a/controller/api/destination/server.go b/controller/api/destination/server.go
index c9be7f6b6..535be5167 100644
--- a/controller/api/destination/server.go
+++ b/controller/api/destination/server.go
@@ -532,7 +532,7 @@ func getHostAndPort(authority string) (string, watcher.Port, error) {
 	if len(hostPort) == 2 {
 		var err error
 		port, err = strconv.Atoi(hostPort[1])
-		if err != nil {
+		if err != nil || port <= 0 || port > 65535 {
 			return "", 0, fmt.Errorf("Invalid port %s", hostPort[1])
 		}
 	}
diff --git a/jaeger/injector/Dockerfile b/jaeger/injector/Dockerfile
index 67f484fe3..e536ac080 100644
--- a/jaeger/injector/Dockerfile
+++ b/jaeger/injector/Dockerfile
@@ -1,7 +1,7 @@
 ARG BUILDPLATFORM=linux/amd64
 
 # Precompile key slow-to-build dependencies
-FROM --platform=$BUILDPLATFORM golang:1.16.2-alpine as go-deps
+FROM --platform=$BUILDPLATFORM golang:1.16.4-alpine as go-deps
 WORKDIR /linkerd-build
 COPY go.mod go.sum ./
 COPY bin/install-deps bin/
diff --git a/pkg/healthcheck/healthcheck.go b/pkg/healthcheck/healthcheck.go
index 3b53db57b..0664798f8 100644
--- a/pkg/healthcheck/healthcheck.go
+++ b/pkg/healthcheck/healthcheck.go
@@ -2500,6 +2500,12 @@ func validateDataPlanePods(pods []corev1.Pod, targetNamespace string) error {
 
 	for _, pod := range pods {
 		status := k8s.GetPodStatus(pod)
+		// Skip validating meshed pods that are in the `Completed` state
+		// as they do not have a running proxy
+		if status == "Completed" {
+			continue
+		}
+
 		if status != "Running" && status != "Evicted" {
 			return fmt.Errorf("The \"%s\" pod is not running", pod.Name)
 		}
diff --git a/viz/metrics-api/Dockerfile b/viz/metrics-api/Dockerfile
index ef66e7758..4ac473cb5 100644
--- a/viz/metrics-api/Dockerfile
+++ b/viz/metrics-api/Dockerfile
@@ -1,7 +1,7 @@
 ARG BUILDPLATFORM=linux/amd64
 
 # Precompile key slow-to-build dependencies
-FROM --platform=$BUILDPLATFORM golang:1.16.2-alpine as go-deps
+FROM --platform=$BUILDPLATFORM golang:1.16.4-alpine as go-deps
 WORKDIR /linkerd-build
 COPY go.mod go.sum ./
 COPY bin/install-deps bin/
diff --git a/viz/tap/Dockerfile b/viz/tap/Dockerfile
index 3e4402cbf..f58c68ba7 100644
--- a/viz/tap/Dockerfile
+++ b/viz/tap/Dockerfile
@@ -1,7 +1,7 @@
 ARG BUILDPLATFORM=linux/amd64
 
 # Precompile key slow-to-build dependencies
-FROM --platform=$BUILDPLATFORM golang:1.16.2-alpine as go-deps
+FROM --platform=$BUILDPLATFORM golang:1.16.4-alpine as go-deps
 WORKDIR /linkerd-build
 COPY go.mod go.sum ./
 COPY bin/install-deps bin/
diff --git a/viz/tap/api/handlers.go b/viz/tap/api/handlers.go
index 160c57d2a..4a9b3085a 100644
--- a/viz/tap/api/handlers.go
+++ b/viz/tap/api/handlers.go
@@ -120,8 +120,8 @@ func (h *handler) handleTap(w http.ResponseWriter, req *http.Request, p httprout
 		return
 	}
 
-	h.log.Debugf("SubjectAccessReview: namespace: %s, resource: %s, name: %s, user: %s, group: %s",
-		namespace, resource, name, req.Header.Get(h.usernameHeader), req.Header[h.groupHeader],
+	h.log.Debugf("SubjectAccessReview: namespace: %s, resource: %s, name: %s, user: <%s>, group: <%s>",
+		namespace, resource, name, h.usernameHeader, h.groupHeader,
 	)
 
 	// TODO: it's possible this SubjectAccessReview is redundant, consider
@@ -137,7 +137,7 @@ func (h *handler) handleTap(w http.ResponseWriter, req *http.Request, p httprout
 		"tap",
 		name,
 		req.Header.Get(h.usernameHeader),
-		req.Header[h.groupHeader],
+		req.Header.Values(h.groupHeader),
 	)
 	if err != nil {
 		err = fmt.Errorf("tap authorization failed (%s), visit %s for more information", err, pkg.TapRbacURL)
diff --git a/web/Dockerfile b/web/Dockerfile
index 228c6f203..acb4bf728 100644
--- a/web/Dockerfile
+++ b/web/Dockerfile
@@ -1,7 +1,7 @@
 ARG BUILDPLATFORM=linux/amd64
 
 # Precompile key slow-to-build dependencies
-FROM --platform=$BUILDPLATFORM golang:1.16.2-alpine as go-deps
+FROM --platform=$BUILDPLATFORM golang:1.16.4-alpine as go-deps
 WORKDIR /linkerd-build
 COPY go.mod go.sum ./
 COPY bin/install-deps bin/


Test patch:
diff --git a/.github/workflows/integration_tests.yml b/.github/workflows/integration_tests.yml
index 154155876..e12f87344 100644
--- a/.github/workflows/integration_tests.yml
+++ b/.github/workflows/integration_tests.yml
@@ -1,6 +1,9 @@
 name: Integration tests
 on:
-  pull_request: {}
+  pull_request:
+    paths-ignore:
+    - '*.md'
+    - '**/*.md'
   push:
     paths-ignore:
     - '*.md'
diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml
index 3c797664e..3237af44f 100644
--- a/.github/workflows/unit_tests.yml
+++ b/.github/workflows/unit_tests.yml
@@ -1,6 +1,9 @@
 name: Unit tests
 on:
-  pull_request: {}
+  pull_request:
+    paths-ignore:
+    - '*.md'
+    - '**/*.md'
   push:
     paths-ignore:
     - '*.md'
@@ -13,7 +16,7 @@ jobs:
     timeout-minutes: 30
     runs-on: ubuntu-20.04
     container:
-      image: golang:1.16.2
+      image: golang:1.16.4
     steps:
     - name: Checkout code
       uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4
diff --git a/controller/api/destination/server_test.go b/controller/api/destination/server_test.go
index 8ca9d6303..7bddbbe8e 100644
--- a/controller/api/destination/server_test.go
+++ b/controller/api/destination/server_test.go
@@ -413,12 +413,12 @@ func TestGet(t *testing.T) {
 			t.Fatalf("Expected len(addrs) to be > 0")
 		}
 
-		if addrs[0].ProtocolHint != nil {
+		if addrs[0].GetProtocolHint().GetProtocol() != nil || addrs[0].GetProtocolHint().GetOpaqueTransport() != nil {
 			t.Fatalf("Expected protocol hint for %s to be nil but got %+v", path, addrs[0].ProtocolHint)
 		}
 
 		if addrs[0].TlsIdentity != nil {
-			t.Fatalf("Expected protocol hint for %s to be nil but got %+v", path, addrs[0].TlsIdentity)
+			t.Fatalf("Expected TLS identity for %s to be nil but got %+v", path, addrs[0].TlsIdentity)
 		}
 	})
 }
@@ -682,10 +682,10 @@ func TestGetProfiles(t *testing.T) {
 		if !exists {
 			t.Fatalf("Expected 'namespace' metric label to exist but it did not")
 		}
-		if first.Endpoint.ProtocolHint == nil {
+		if first.GetEndpoint().GetProtocolHint() == nil {
 			t.Fatalf("Expected protocol hint but found none")
 		}
-		if first.Endpoint.ProtocolHint.GetOpaqueTransport() != nil {
+		if first.GetEndpoint().GetProtocolHint().GetOpaqueTransport() != nil {
 			t.Fatalf("Expected pod to not support opaque traffic on port %d", port)
 		}
 		if first.Endpoint.Addr.String() != epAddr.String() {
@@ -745,7 +745,7 @@ func TestGetProfiles(t *testing.T) {
 		if first.Endpoint == nil {
 			t.Fatalf("Expected response to have endpoint field")
 		}
-		if first.Endpoint.ProtocolHint != nil {
+		if first.Endpoint.GetProtocolHint().GetProtocol() != nil || first.Endpoint.GetProtocolHint().GetOpaqueTransport() != nil {
 			t.Fatalf("Expected no protocol hint but found one")
 		}
 	})
@@ -884,12 +884,12 @@ func TestGetProfiles(t *testing.T) {
 			t.Fatalf("Expected to not be nil")
 		}
 
-		if addr.ProtocolHint != nil {
+		if addr.GetProtocolHint().GetProtocol() != nil || addr.GetProtocolHint().GetOpaqueTransport() != nil {
 			t.Fatalf("Expected protocol hint for %s to be nil but got %+v", path, addr.ProtocolHint)
 		}
 
 		if addr.TlsIdentity != nil {
-			t.Fatalf("Expected protocol hint for %s to be nil but got %+v", path, addr.TlsIdentity)
+			t.Fatalf("Expected TLS identity for %s to be nil but got %+v", path, addr.TlsIdentity)
 		}
 	})
 }
diff --git a/jaeger/cmd/install_test.go b/jaeger/cmd/install_test.go
new file mode 100644
index 000000000..2a0c5e1b0
--- /dev/null
+++ b/jaeger/cmd/install_test.go
@@ -0,0 +1,43 @@
+package cmd
+
+import (
+	"bytes"
+	"fmt"
+	"testing"
+
+	"github.com/linkerd/linkerd2/pkg/charts"
+)
+
+func TestRender(t *testing.T) {
+
+	// pin values that are changed by render functions on each test run
+	defaultValues := map[string]interface{}{
+		"webhook": map[string]interface{}{
+			"keyPEM":   "test-webhhook-key-pem",
+			"crtPEM":   "test-webhook-crt-pem",
+			"caBundle": "test-webhook-ca-bundle",
+		},
+	}
+
+	testCases := []struct {
+		values         map[string]interface{}
+		goldenFileName string
+	}{
+		{
+			nil,
+			"install_default.golden",
+		},
+	}
+
+	for i, tc := range testCases {
+		tc := tc // pin
+		t.Run(fmt.Sprintf("%d: %s", i, tc.goldenFileName), func(t *testing.T) {
+			var buf bytes.Buffer
+			// Merge overrides with default
+			if err := render(&buf, charts.MergeMaps(defaultValues, tc.values)); err != nil {
+				t.Fatalf("Failed to render templates: %v", err)
+			}
+			testDataDiffer.DiffTestdata(t, tc.goldenFileName, buf.String())
+		})
+	}
+}
diff --git a/jaeger/cmd/main_test.go b/jaeger/cmd/main_test.go
new file mode 100644
index 000000000..676a7e0af
--- /dev/null
+++ b/jaeger/cmd/main_test.go
@@ -0,0 +1,23 @@
+package cmd
+
+import (
+	"flag"
+	"os"
+	"testing"
+
+	"github.com/linkerd/linkerd2/testutil"
+)
+
+var (
+	testDataDiffer testutil.TestDataDiffer
+)
+
+// TestMain parses flags before running tests
+func TestMain(m *testing.M) {
+	flag.BoolVar(&testDataDiffer.UpdateFixtures, "update", false, "update text fixtures in place")
+	prettyDiff := os.Getenv("LINKERD_TEST_PRETTY_DIFF") != ""
+	flag.BoolVar(&testDataDiffer.PrettyDiff, "pretty-diff", prettyDiff, "display the full text when diffing")
+	flag.StringVar(&testDataDiffer.RejectPath, "reject-path", "", "write results for failed tests to this path (path is relative to the test location)")
+	flag.Parse()
+	os.Exit(m.Run())
+}
diff --git a/jaeger/cmd/testdata/install_default.golden b/jaeger/cmd/testdata/install_default.golden
new file mode 100644
index 000000000..abdd26500
--- /dev/null
+++ b/jaeger/cmd/testdata/install_default.golden
@@ -0,0 +1,358 @@
+---
+kind: Namespace
+apiVersion: v1
+metadata:
+  name: linkerd-jaeger
+  labels:
+    linkerd.io/extension: jaeger
+  annotations:
+    linkerd.io/inject: enabled
+    config.linkerd.io/proxy-await: "enabled"
+---
+###
+### Jaeger Injector
+###
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  labels:
+    linkerd.io/extension: jaeger
+    app.kubernetes.io/name: jaeger-injector
+    app.kubernetes.io/part-of: Linkerd
+    app.kubernetes.io/version: dev-undefined
+    component: jaeger-injector
+  name: jaeger-injector
+  namespace: linkerd-jaeger
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      linkerd.io/extension: jaeger
+      component: jaeger-injector
+  template:
+    metadata:
+      annotations:
+        checksum/config: 525d4805deeeee18bbcd97ab075362fcae2250d997ff311665a0b7b464eebdc4
+      labels:
+        linkerd.io/extension: jaeger
+        component: jaeger-injector
+    spec:
+      nodeSelector:
+        beta.kubernetes.io/os: linux
+      containers:
+      - args:
+        - -collector-svc-addr=collector.linkerd-jaeger:55678
+        - -collector-svc-account=collector
+        - -log-level=info
+        image: cr.l5d.io/linkerd/jaeger-webhook:dev-undefined
+        imagePullPolicy: IfNotPresent
+        livenessProbe:
+          httpGet:
+            path: /ping
+            port: 9995
+          initialDelaySeconds: 10
+        name: jaeger-injector
+        ports:
+        - containerPort: 8443
+          name: jaeger-injector
+        - containerPort: 9995
+          name: admin-http
+        readinessProbe:
+          failureThreshold: 7
+          httpGet:
+            path: /ready
+            port: 9995
+        volumeMounts:
+        - mountPath: /var/run/linkerd/tls
+          name: tls
+          readOnly: true
+      serviceAccountName: jaeger-injector
+      volumes:
+      - name: tls
+        secret:
+          secretName: jaeger-injector-k8s-tls
+---
+kind: Service
+apiVersion: v1
+metadata:
+  name: jaeger-injector
+  namespace: linkerd-jaeger
+  labels:
+    linkerd.io/extension: jaeger
+    component: jaeger-injector
+spec:
+  type: ClusterIP
+  selector:
+    linkerd.io/extension: jaeger
+    component: jaeger-injector
+  ports:
+  - name: jaeger-injector
+    port: 443
+    targetPort: jaeger-injector
+---
+###
+### collector RBAC
+###
+kind: ServiceAccount
+apiVersion: v1
+metadata:
+  name: collector
+  namespace: linkerd-jaeger
+---
+###
+### jaeger RBAC
+###
+kind: ServiceAccount
+apiVersion: v1
+metadata:
+  name: jaeger
+  namespace: linkerd-jaeger
+
+---
+###
+### Jaeger Injector RBAC
+###
+kind: ClusterRole
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+  name: linkerd-jaeger-injector
+  labels:
+    linkerd.io/extension: jaeger
+rules:
+- apiGroups: [""]
+  resources: ["namespaces"]
+  verbs: ["get", "list", "watch"]
+---
+kind: ClusterRoleBinding
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+  name: linkerd-jaeger-injector
+  labels:
+    linkerd.io/extension: jaeger
+subjects:
+- kind: ServiceAccount
+  name: jaeger-injector
+  namespace: linkerd-jaeger
+  apiGroup: ""
+roleRef:
+  kind: ClusterRole
+  name: linkerd-jaeger-injector
+  apiGroup: rbac.authorization.k8s.io
+---
+kind: ServiceAccount
+apiVersion: v1
+metadata:
+  name: jaeger-injector
+  namespace: linkerd-jaeger
+---
+kind: Secret
+apiVersion: v1
+metadata:
+  name: jaeger-injector-k8s-tls
+  namespace: linkerd-jaeger
+type: kubernetes.io/tls
+data:
+  tls.crt: dGVzdC13ZWJob29rLWNydC1wZW0=
+  tls.key: dGVzdC13ZWJoaG9vay1rZXktcGVt
+---
+apiVersion: admissionregistration.k8s.io/v1
+kind: MutatingWebhookConfiguration
+metadata:
+  name: linkerd-jaeger-injector-webhook-config
+  labels:
+    linkerd.io/extension: jaeger
+webhooks:
+- name: jaeger-injector.linkerd.io
+  clientConfig:
+    service:
+      name: jaeger-injector
+      namespace: linkerd-jaeger
+      path: "/"
+    caBundle: dGVzdC13ZWJob29rLWNhLWJ1bmRsZQ==
+  failurePolicy: Ignore
+  admissionReviewVersions: ["v1", "v1beta1"]
+  reinvocationPolicy: IfNeeded
+  rules:
+  - operations: [ "CREATE" ]
+    apiGroups: [""]
+    apiVersions: ["v1"]
+    resources: ["pods"]
+  sideEffects: None
+---
+###
+### Tracing Collector Service
+###
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: collector-config
+  namespace: linkerd-jaeger
+  labels:
+    component: collector
+data:
+  collector-config: |
+    receivers:
+      opencensus:
+        port: 55678
+      zipkin:
+        port: 9411
+      jaeger:
+        jaeger-thrift-http-port: 14268
+    queued-exporters:
+      jaeger-all-in-one:
+        num-workers: 4
+        queue-size: 100
+        retry-on-failure: true
+        sender-type: jaeger-thrift-http
+        jaeger-thrift-http:
+          collector-endpoint: http://jaeger.linkerd-jaeger:14268/api/traces
+          timeout: 5s
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: collector
+  namespace: linkerd-jaeger
+  labels:
+    component: collector
+spec:
+  type: ClusterIP
+  ports:
+  - name: opencensus
+    port: 55678
+    protocol: TCP
+    targetPort: 55678
+  - name: zipkin
+    port: 9411
+    protocol: TCP
+    targetPort: 9411
+  - name: jaeger
+    port: 14268
+    protocol: TCP
+    targetPort: 14268
+  selector:
+    component: collector
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  labels:
+    app.kubernetes.io/name: collector
+    app.kubernetes.io/part-of: Linkerd
+    component: collector
+  name: collector
+  namespace: linkerd-jaeger
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      component: collector
+  minReadySeconds: 5
+  progressDeadlineSeconds: 120
+  template:
+    metadata:
+      annotations:
+        prometheus.io/path: /metrics
+        prometheus.io/port: "8888"
+        prometheus.io/scrape: "true"
+      labels:
+        component: collector
+    spec:
+      nodeSelector:
+        beta.kubernetes.io/os: linux
+      containers:
+      - command:
+        - /occollector_linux
+        - --config=/conf/collector-config.yaml
+        env:
+        - name: GOGC
+          value: "80"
+        image: omnition/opencensus-collector:0.1.11
+        imagePullPolicy: Always
+        livenessProbe:
+          httpGet:
+            path: /
+            port: 13133
+        name: oc-collector
+        ports:
+        - containerPort: 55678
+        - containerPort: 9411
+        - containerPort: 14268
+        - containerPort: 8888
+        readinessProbe:
+          httpGet:
+            path: /
+            port: 13133
+        volumeMounts:
+        - mountPath: /conf
+          name: collector-config-val
+      serviceAccountName: collector
+      volumes:
+      - configMap:
+          items:
+          - key: collector-config
+            path: collector-config.yaml
+          name: collector-config
+        name: collector-config-val
+---
+###
+### Tracing Jaeger Service
+###
+apiVersion: v1
+kind: Service
+metadata:
+  name: jaeger
+  namespace: linkerd-jaeger
+  labels:
+    component: jaeger
+spec:
+  type: ClusterIP
+  selector:
+    component: jaeger
+  ports:
+    - name: collection
+      port: 14268
+    - name: ui
+      port: 16686
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  labels:
+    app.kubernetes.io/name: jaeger
+    app.kubernetes.io/part-of: Linkerd
+    component: jaeger
+  name: jaeger
+  namespace: linkerd-jaeger
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      component: jaeger
+  template:
+    metadata:
+      annotations:
+        config.linkerd.io/proxy-await: "enabled"
+        prometheus.io/path: /metrics
+        prometheus.io/port: "14269"
+        prometheus.io/scrape: "true"
+      labels:
+        component: jaeger
+    spec:
+      nodeSelector:
+        beta.kubernetes.io/os: linux
+      containers:
+      - args:
+        - --query.base-path=/jaeger
+        image: jaegertracing/all-in-one:1.19.2
+        imagePullPolicy: Always
+        name: jaeger
+        ports:
+        - containerPort: 14269
+          name: admin
+        - containerPort: 14268
+          name: collection
+        - containerPort: 16686
+          name: ui
+      dnsPolicy: ClusterFirst
+      serviceAccountName: jaeger
diff --git a/pkg/healthcheck/healthcheck_test.go b/pkg/healthcheck/healthcheck_test.go
index 49173eaaf..ee3c9ae8f 100644
--- a/pkg/healthcheck/healthcheck_test.go
+++ b/pkg/healthcheck/healthcheck_test.go
@@ -1645,6 +1645,67 @@ func TestValidateDataPlanePods(t *testing.T) {
 			t.Fatalf("Unexpected error: %s", err)
 		}
 	})
+
+	// This test relates to https://github.com/linkerd/linkerd2/issues/6128
+	t.Run("Returns nil if some pods are in the Succeeded phase and their proxies are no longer ready", func(t *testing.T) {
+		pods := []corev1.Pod{
+			{
+				ObjectMeta: metav1.ObjectMeta{Name: "emoji-d9c7866bb-7v74n"},
+				Status: corev1.PodStatus{
+					Phase:  "Succeeded",
+					Reason: "Completed",
+					ContainerStatuses: []corev1.ContainerStatus{
+						{
+							Name:  k8s.ProxyContainerName,
+							Ready: false,
+						},
+					},
+				},
+			},
+			{
+				ObjectMeta: metav1.ObjectMeta{Name: "vote-bot-644b8cb6b4-g8nlr"},
+				Status: corev1.PodStatus{
+					Phase: "Running",
+					ContainerStatuses: []corev1.ContainerStatus{
+						{
+							Name:  k8s.ProxyContainerName,
+							Ready: true,
+						},
+					},
+				},
+			},
+			{
+				ObjectMeta: metav1.ObjectMeta{Name: "voting-65b9fffd77-rlwsd"},
+				Status: corev1.PodStatus{
+					Phase: "Running",
+					ContainerStatuses: []corev1.ContainerStatus{
+						{
+							Name:  k8s.ProxyContainerName,
+							Ready: true,
+						},
+					},
+				},
+			},
+			{
+				ObjectMeta: metav1.ObjectMeta{Name: "web-6cfbccc48-5g8px"},
+				Status: corev1.PodStatus{
+					Phase:  "Succeeded",
+					Reason: "Completed",
+					ContainerStatuses: []corev1.ContainerStatus{
+						{
+							Name:  k8s.ProxyContainerName,
+							Ready: false,
+						},
+					},
+				},
+			},
+		}
+
+		err := validateDataPlanePods(pods, "emojivoto")
+		if err != nil {
+			t.Fatalf("Unexpected error: %s", err)
+		}
+	})
 }
 
 func TestDataPlanePodLabels(t *testing.T) {
diff --git a/test/integration/install_test.go b/test/integration/install_test.go
index 717044810..28a795e92 100644
--- a/test/integration/install_test.go
+++ b/test/integration/install_test.go
@@ -628,9 +628,10 @@ func TestUpgradeHelm(t *testing.T) {
 		"--set", "proxyInjectorProxyResources.cpu.limit=1060m",
 		"--set", "proxyInjectorProxyResources.memory.request=106Mi",
 		"--atomic",
+		"--timeout", "60m",
 		"--wait",
 	}
-	extraArgs, extraVizArgs := helmOverridesEdge(helmTLSCerts)
+	extraArgs, vizArgs := helmOverridesEdge(helmTLSCerts)
 	args = append(args, extraArgs...)
 	if stdout, stderr, err := TestHelper.HelmUpgrade(TestHelper.GetHelmChart(), args...); err != nil {
 		testutil.AnnotatedFatalf(t, "'helm upgrade' command failed",
@@ -638,7 +639,6 @@ func TestUpgradeHelm(t *testing.T) {
 	}
 
 	vizChart := TestHelper.GetLinkerdVizHelmChart()
-	vizArgs := append(extraVizArgs, "--wait")
 	if stdout, stderr, err := TestHelper.HelmCmdPlain("upgrade", vizChart, "l5d-viz", vizArgs...); err != nil {
 		testutil.AnnotatedFatalf(t, "'helm upgrade' command failed",
 			"'helm upgrade' command failed\n%s\n%s", stdout, stderr)
diff --git a/testutil/annotations_test.go b/testutil/annotations_test.go
index 359ecee38..9866d56fe 100644
--- a/testutil/annotations_test.go
+++ b/testutil/annotations_test.go
@@ -48,7 +48,7 @@ func TestError(t *testing.T) {
 	Error(&testing.T{}, msg)
 	out := restoreStdout(outC, origStdout)
 
-	if strings.TrimSpace(out) != "::error file=testutil/annotations_test.go,line=48:: - This is an error" {
+	if !strings.HasSuffix(strings.TrimSpace(out), "testutil/annotations_test.go,line=48:: - This is an error") {
 		t.Fatalf("unexpected stdout content: %s", out)
 	}
 }
@@ -63,7 +63,7 @@ func TestAnnotatedErrorf(t *testing.T) {
 	AnnotatedErrorf(&testing.T{}, msgDesc, msgFormat, str)
 	out := restoreStdout(outC, origStdout)
 
-	if strings.TrimSpace(out) != "::error file=testutil/annotations_test.go,line=63:: - This is a generic error" {
+	if !strings.HasSuffix(strings.TrimSpace(out), "testutil/annotations_test.go,line=63:: - This is a generic error") {
 		t.Fatalf("unexpected stdout content: %s", out)
 	}
 }