Repository: linkerd/linkerd2
Pull request #6120 (2021-05-13 13:22:46)

Add flags to Jaeger helm chart to exclude Jaeger and opencensus collector
Improve linkerd-jaeger helm chart with additional flags.

Signed-off-by: Tarvi Pillessaar <tarvip@gmail.com>

<!--  Thanks for sending a pull request!

If you already have a well-structured git commit message, chances are GitHub
set the title and description of this PR to the git commit message subject and
body, respectively. If so, you may delete these instructions and submit your PR.

If this is your first time, please read our contributor guide:
https://github.com/linkerd/linkerd2/blob/main/CONTRIBUTING.md

The title and description of your Pull Request should match the git commit
subject and body, respectively. Git commit messages are structured as follows:

```
Subject

Problem

Solution

Validation

Fixes #[GitHub issue ID]

DCO Sign off
```

Example git commit message:

```
Introduce Pull Request Template

GitHub's community guidelines recommend a pull request template, the repo was
lacking one.

Introduce a `PULL_REQUEST_TEMPLATE.md` file.

Once merged, the
[Community profile checklist](https://github.com/linkerd/linkerd2/community)
should indicate the repo now provides a pull request template.

Fixes #3321

Signed-off-by: Jane Smith <jane.smith@example.com>
```

Note the git commit message subject becomes the pull request title.

For more details around git commits, see the section on Committing in our
contributor guide:
https://github.com/linkerd/linkerd2/blob/main/CONTRIBUTING.md#committing
-->


Pothulapati: Should we have a new `jaeger.enabled` flag instead based on which jaeger install can be toggled? @alpeb 

We currently follow this pattern with `promethus`, `grafana` 🤔 
tarvip: > Should we have a new `jaeger.enabled` flag instead based on which jaeger install can be toggled? @alpeb
> 
> We currently follow this pattern with `promethus`, `grafana` 🤔

I was also thinking about that approach.
tarvip: Maybe there should be also `collector.enabled` flag for cases when using also existing collector.
alpeb: Agreed, `collector.enabled` and `jaeger.enabled` are more consistent with viz' approach :+1: 
tarvip: Updated pull request.

Patch:
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
new file mode 100644
index 000000000..1691af43a
--- /dev/null
+++ b/.github/workflows/codeql.yml
@@ -0,0 +1,39 @@
+# See https://github.com/github/codeql-action/tree/v1 for more information.
+
+name: CodeQL
+
+on:
+  push:
+    branches: [ main, stable-* ]
+  pull_request:
+    # The branches below must be a subset of the branches above
+    branches: [ main, stable-* ]
+  schedule:
+    - cron: '40 5 * * 3'
+
+jobs:
+  analyze:
+    name: Analyze
+    runs-on: ubuntu-latest
+    permissions:
+      actions: read
+      contents: read
+      security-events: write
+
+    strategy:
+      fail-fast: false
+      matrix:
+        language: [ 'go', 'javascript' ]
+
+    steps:
+    - name: Checkout
+      uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4
+
+    - name: Initialize
+      # Unpinned action version so that we automatically get analyzer updates.
+      uses: github/codeql-action/init@v1
+      with:
+        languages: ${{ matrix.language }}
+
+    - name: Analyze
+      uses: github/codeql-action/analyze@v1
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 951116263..33ed139d0 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -16,8 +16,7 @@ jobs:
     timeout-minutes: 30
     steps:
     - name: Checkout code
-      # actions/checkout@v2
-      uses: actions/checkout@722adc63f1aa60a57ec37892e133b1d319cae598
+      uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4
     - name: Set environment variables from scripts
       run: |
         . bin/_tag.sh
@@ -77,8 +76,7 @@ jobs:
     needs: [docker_build]
     steps:
     - name: Checkout code
-      # actions/checkout@v2
-      uses: actions/checkout@722adc63f1aa60a57ec37892e133b1d319cae598
+      uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4
     - name: Try to load cached Go modules
       # actions/cache@v1.1.2
       uses: actions/cache@70655ec8323daeeaa7ef06d7c56e1b9191396cbe
@@ -110,12 +108,11 @@ jobs:
         - cni-calico-deep
     needs: [docker_build]
     name: Integration tests (${{ matrix.integration_test }})
-    timeout-minutes: 30
+    timeout-minutes: 60
     runs-on: ubuntu-20.04
     steps:
     - name: Checkout code
-      # actions/checkout@v2
-      uses: actions/checkout@722adc63f1aa60a57ec37892e133b1d319cae598
+      uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4
     - name: Try to load cached Go modules
       # actions/cache@v1.1.2
       uses: actions/cache@70655ec8323daeeaa7ef06d7c56e1b9191396cbe
@@ -144,8 +141,7 @@ jobs:
     steps:
     - name: Checkout code
       #if: startsWith(github.ref, 'refs/tags/stable')
-      # actions/checkout@v2
-      uses: actions/checkout@722adc63f1aa60a57ec37892e133b1d319cae598
+      uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4
     - name: Try to load cached Go modules
       #if: startsWith(github.ref, 'refs/tags/stable')
       # actions/cache@v1.1.2
@@ -197,8 +193,7 @@ jobs:
     steps:
     - name: Checkout code
       if: startsWith(github.ref, 'refs/tags/stable')
-      # actions/checkout@v2
-      uses: actions/checkout@722adc63f1aa60a57ec37892e133b1d319cae598
+      uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4
     - name: Chocolatey - update nuspec
       if: startsWith(github.ref, 'refs/tags/stable')
       run: |
@@ -225,8 +220,7 @@ jobs:
     needs: [choco_pack]
     steps:
     - name: Checkout code
-      # actions/checkout@v2
-      uses: actions/checkout@722adc63f1aa60a57ec37892e133b1d319cae598
+      uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4
     - name: Set environment variables from scripts
       run: |
         . bin/_tag.sh
@@ -286,8 +280,7 @@ jobs:
     needs: [website_publish]
     steps:
     - name: Checkout code
-      # actions/checkout@v2
-      uses: actions/checkout@722adc63f1aa60a57ec37892e133b1d319cae598
+      uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4
     - name: Set environment variables from scripts
       run: |
         . bin/_tag.sh
@@ -316,8 +309,7 @@ jobs:
     needs: [gh_release]
     steps:
     - name: Checkout code
-      # actions/checkout@v2
-      uses: actions/checkout@722adc63f1aa60a57ec37892e133b1d319cae598
+      uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4
     - name: Configure gsutils
       # linkerd/linkerd2-action-gcloud@v1.0.1
       uses: linkerd/linkerd2-action-gcloud@308c4df7314264c90d240e77e27d0d875d3c8ec1
diff --git a/.github/workflows/static_checks.yml b/.github/workflows/static_checks.yml
index f84593bbf..a7754b738 100644
--- a/.github/workflows/static_checks.yml
+++ b/.github/workflows/static_checks.yml
@@ -13,11 +13,10 @@ jobs:
     timeout-minutes: 10
     runs-on: ubuntu-20.04
     container:
-      image: golang:1.16.2
+      image: golang:1.16.4
     steps:
     - name: Checkout code
-      # actions/checkout@v2
-      uses: actions/checkout@722adc63f1aa60a57ec37892e133b1d319cae598
+      uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4
     - name: Go lint
       run: bin/lint --verbose
   go_format:
@@ -25,11 +24,10 @@ jobs:
     timeout-minutes: 10
     runs-on: ubuntu-20.04
     container:
-      image: golang:1.16.2
+      image: golang:1.16.4
     steps:
     - name: Checkout code
-      # actions/checkout@v2
-      uses: actions/checkout@722adc63f1aa60a57ec37892e133b1d319cae598
+      uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4
     - name: Format
       run: bin/fmt
   proto_diff:
@@ -37,13 +35,12 @@ 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
       - name: Checkout code
-        # actions/checkout@v2
-        uses: actions/checkout@722adc63f1aa60a57ec37892e133b1d319cae598
+        uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4
       - name: Diff proto files
         run: bin/protoc-diff
   shellcheck:
@@ -52,8 +49,7 @@ jobs:
     runs-on: ubuntu-20.04
     steps:
     - name: Checkout code
-      # actions/checkout@v2
-      uses: actions/checkout@722adc63f1aa60a57ec37892e133b1d319cae598
+      uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4
     - name: shellcheck
       # For more information on shellcheck failures:
       # https://github.com/koalaman/shellcheck/wiki/Checks
@@ -65,8 +61,7 @@ jobs:
     runs-on: ubuntu-20.04
     steps:
     - name: Checkout code
-      # actions/checkout@v2
-      uses: actions/checkout@722adc63f1aa60a57ec37892e133b1d319cae598
+      uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4
     - name: Chocolatey - lint
       # devblackops/github-action-psscriptanalyzer@v2.3.0
       uses: devblackops/github-action-psscriptanalyzer@819c15c7d02dec0611fe3ded6f8e259b0b925754
@@ -82,8 +77,7 @@ jobs:
     runs-on: ubuntu-20.04
     steps:
     - name: Checkout code
-      # actions/checkout@v2
-      uses: actions/checkout@722adc63f1aa60a57ec37892e133b1d319cae598
+      uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4
     - name: Markdown lint
       run: bin/markdownlint-all
   chart_docs_diff:
@@ -91,7 +85,6 @@ jobs:
     runs-on: ubuntu-20.04
     steps:
     - name: Checkout code
-      # actions/checkout@v2
-      uses: actions/checkout@722adc63f1aa60a57ec37892e133b1d319cae598
+      uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4
     - name: Check docs for diff
       run: bin/helm-docs-diff
diff --git a/.proxy-version b/.proxy-version
index e2d4912bb..fb741f89d 100644
--- a/.proxy-version
+++ b/.proxy-version
@@ -1,1 +1,1 @@
-v2.141.1
+v2.144.0
\ No newline at end of file
diff --git a/ADOPTERS.md b/ADOPTERS.md
index d5fcf111d..87340f747 100644
--- a/ADOPTERS.md
+++ b/ADOPTERS.md
@@ -35,6 +35,7 @@
 - [Mulligan Funding](https://www.mulliganfunding.com/)
 - [Mythical Games](https://mythicalgames.com/)
 - [National Information Solutions Cooperative (NISC)](https://nisc.coop/)
+- [Nexxiot](https://www.nexxiot.com)
 - [Nordstrom](https://nordstrom.com/)
 - [Novolabs](https://novolabs.com)
 - [Paybase](https://paybase.io/)
diff --git a/BUILD.md b/BUILD.md
index 56a7f716c..0259d872f 100644
--- a/BUILD.md
+++ b/BUILD.md
@@ -422,6 +422,27 @@ proxy binary:
 bin/docker-build-proxy
 ```
 
+#### Locally built proxy
+
+If you want to deploy a locally built proxy, you can build it in the
+[`linkerd2-proxy`](https://github.com/linkerd/linkerd2-proxy) repo by running:
+
+```bash
+DOCKER_TAG=cr.l5d.io/linkerd/proxy:dev make docker
+```
+
+Then, in this repo, run:
+
+```bash
+./bin/k3d image import cr.l5d.io/linkerd/proxy:dev
+```
+
+Now, to make a pod use your image, add the following annotations to it:
+
+```yaml
+config.linkerd.io/proxy-version: dev
+```
+
 ### Multi-architecture builds
 
 Besides the default Linux/amd64 architecture, you can build controller images
diff --git a/CHANGES.md b/CHANGES.md
index 3a1e53f34..d5ea14f6e 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,5 +1,58 @@
 # Changes
 
+## edge-21.5.2
+
+This edge release updates the proxy-init container to check whether the iptables
+rules have already been added, which prevents errors if the proxy-init container
+is restarted. Also, the `viz stat` command now has tab completion for Kubernetes
+resources, saving you precious keystrokes! Finally, the proxy has been updated
+with several fixes and improvements.
+
+* Added instructions to `build.md` for using a locally built proxy
+  (thanks @jroper!)
+* Added support for Kubernetes resource aware tab completion to the `viz stat`
+  command
+* Updated `proxy-init` to skip configuring firewall if rules exists
+* Fixed `viz uninstall` to delete all RBAC objects (thanks @aryan9600!)
+* Improved diagnostics for rejected profile discovery
+* Added the `l5d-client-id` header on mutually-authenticated inbound requests so
+  that applications can discover the client's identity.
+* Reduced proxy resource usage when there are no profiles
+* Changed the admin server to assume all meshed connections are HTTP/2 and fail
+  connections when that is not the case
+* Updated the proxy to require the `l5d-dst-override` header on outbound
+  requests when the proxy is in ingress-mode
+* Removed support for TCP-forwarding in ingress-mode
+
+## edge-21.5.1
+
+This edge release adds support for versioned hint URLs in `linkerd check` and
+support for traffic splitting through ServiceProfiles, among other fixes and
+improvements. Additionally, more options have been added to the
+linkerd-multicluster and linkerd-jaeger helm charts.
+
+* Added support for traffic splitting through a ServiceProfile's `dstOverrides`
+  field.
+* Added `nodePorts` option to the multicluster helm chart (thanks @psmit!).
+* Added `nodeSelector` and toleration options to the linkerd-jaeger helm chart
+  (thanks @aatarasoff!).
+* Added versioned hint URLs to the CLI `check` command when encountering an
+  error; each major CLI version will now point to that version's relevant
+  section in the Linkerd troubleshooting page.
+* Fixed an issue in the CLI `check` command where error messages for
+  healthchecks that were being retried would be outputted repeatedly instead of
+  just once.
+* Fixed an issue in the proxy injector where a namespace annotated with opaque
+  ports would overwrite all service annotations.
+* Fixed a regression in the proxy that caused all logs to be output with ANSI
+  control characters, by default logs are output in plaintext now.
+* Simplified proxy internals in order to distinguish endpoint-forwarding logic
+  from the handling of load balanced services.
+* Simplified the ingress-mode outbound proxy by requiring the
+  `l5d-dst-override` header and by failing non-HTTP communication. Proxies
+  running in ingress-mode will not unexpectedly revert to insecure
+  communication as a result.
+
 ## edge-21.4.5
 
 This edge release adds a new output format `short` for `linkerd check` to show a
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/charts/linkerd2/README.md b/charts/linkerd2/README.md
index 412c3048c..b799c893e 100644
--- a/charts/linkerd2/README.md
+++ b/charts/linkerd2/README.md
@@ -192,7 +192,7 @@ Kubernetes: `>=1.16.0-0`
 | proxyInit.ignoreOutboundPorts | string | `""` | Default set of outbound ports to skip via itpables |
 | proxyInit.image.name | string | `"cr.l5d.io/linkerd/proxy-init"` | Docker image for the proxy-init container |
 | proxyInit.image.pullPolicy | string | imagePullPolicy | Pull policy for the proxy-init container Docker image |
-| proxyInit.image.version | string | `"v1.3.11"` | Tag for the proxy-init container Docker image |
+| proxyInit.image.version | string | `"v1.3.12"` | Tag for the proxy-init container Docker image |
 | proxyInit.resources.cpu.limit | string | `"100m"` | Maximum amount of CPU units that the proxy-init container can use |
 | proxyInit.resources.cpu.request | string | `"10m"` | Amount of CPU units that the proxy-init container requests |
 | proxyInit.resources.memory.limit | string | `"50Mi"` | Maximum amount of memory that the proxy-init container can use |
diff --git a/charts/linkerd2/values.yaml b/charts/linkerd2/values.yaml
index bbb60d928..08ba652be 100644
--- a/charts/linkerd2/values.yaml
+++ b/charts/linkerd2/values.yaml
@@ -122,7 +122,7 @@ proxyInit:
     # @default -- imagePullPolicy
     pullPolicy: ""
     # -- Tag for the proxy-init container Docker image
-    version: v1.3.11
+    version: v1.3.12
   resources:
     cpu:
       # -- Maximum amount of CPU units that the proxy-init container can use
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/cli/cmd/completion.go b/cli/cmd/completion.go
index 28fb3f9ca..58d6511a5 100644
--- a/cli/cmd/completion.go
+++ b/cli/cmd/completion.go
@@ -12,11 +12,13 @@ import (
 // enabling linkerd auto completion
 func newCmdCompletion() *cobra.Command {
 	example := `  # bash <= 3.2:
+  # To load shell completion into your current shell session
   source /dev/stdin <<< "$(linkerd completion bash)"
 
   # bash >= 4.0:
   source <(linkerd completion bash)
 
+  # To load shell completion for every shell session
   # bash <= 3.2 on osx:
   brew install bash-completion # ensure you have bash-completion 1.3+
   linkerd completion bash > $(brew --prefix)/etc/bash_completion.d/linkerd
@@ -25,14 +27,22 @@ func newCmdCompletion() *cobra.Command {
   brew install bash-completion@2
   linkerd completion bash > $(brew --prefix)/etc/bash_completion.d/linkerd
 
+  # bash >= 4.0 on linux:
+  linkerd completion bash > /etc/bash_completion.d/linkerd
+
+  # You will need to start a new shell for this setup to take effect.
+
   # zsh:
   # If shell completion is not already enabled in your environment you will need
   # to enable it.  You can execute the following once:
 
-  echo "autoload -U compinit; compinit" >> ~/.zshrc
+  echo "autoload -U compinit && compinit" >> ~/.zshrc
+
+  # create a linkerd 'plugins' folder and add it to your $fpath
+  mkdir $ZSH/plugins/linkerd && echo "fpath=($ZSH/plugins/linkerd $fpath)" >> ~/.zshrc
 
   # To load completions for each session, execute once:
-  linkerd completion zsh > "${fpath[1]}/_linkerd"
+  linkerd completion zsh > "${fpath[1]}/_linkerd" && exec $SHELL
 
   # You will need to start a new shell for this setup to take effect.
 
diff --git a/cli/cmd/diagnostics.go b/cli/cmd/diagnostics.go
index 9866f5a39..b19872e26 100644
--- a/cli/cmd/diagnostics.go
+++ b/cli/cmd/diagnostics.go
@@ -27,16 +27,12 @@ This command provides subcommands to diagnose the functionality of Linkerd.`,
  
   # Get the endpoints for authorities in Linkerd's control-plane itself
   linkerd diagnostics endpoints web.linkerd-viz.svc.cluster.local:8084
-
-  # Install service profiles for the control-plane components.
-  linkerd diagnostics install-sp
   `,
 	}
 
 	diagnosticsCmd.AddCommand(newCmdControllerMetrics())
 	diagnosticsCmd.AddCommand(newCmdEndpoints())
 	diagnosticsCmd.AddCommand(newCmdMetrics())
-	diagnosticsCmd.AddCommand(newCmdInstallSP())
 
 	return diagnosticsCmd
 }
diff --git a/cli/cmd/install-sp.go b/cli/cmd/install-sp.go
deleted file mode 100644
index 5713c1464..000000000
--- a/cli/cmd/install-sp.go
+++ /dev/null
@@ -1,62 +0,0 @@
-package cmd
-
-import (
-	"bytes"
-	"io"
-	"os"
-	"text/template"
-
-	"github.com/linkerd/linkerd2/cli/installsp"
-	"github.com/linkerd/linkerd2/pkg/healthcheck"
-	"github.com/linkerd/linkerd2/pkg/k8s"
-	"github.com/spf13/cobra"
-)
-
-func newCmdInstallSP() *cobra.Command {
-	cmd := &cobra.Command{
-		Use:   "install-sp [flags]",
-		Short: "Output Kubernetes configs to install Linkerd Service Profiles",
-		Long: `Output Kubernetes configs to install Linkerd Service Profiles.
-
-This command installs Service Profiles into the Linkerd control plane. A
-cluster-wide Linkerd control-plane is a prerequisite. To confirm Service Profile
-support, verify "kubectl api-versions" outputs "linkerd.io/v1alpha2".`,
-		RunE: func(cmd *cobra.Command, args []string) error {
-			k8sAPI, err := k8s.NewAPI(kubeconfigPath, kubeContext, impersonate, impersonateGroup, 0)
-			if err != nil {
-				return err
-			}
-
-			_, values, err := healthcheck.FetchCurrentConfiguration(cmd.Context(), k8sAPI, controlPlaneNamespace)
-			if err != nil {
-				return err
-			}
-
-			clusterDomain := values.ClusterDomain
-			if clusterDomain == "" {
-				clusterDomain = defaultClusterDomain
-			}
-
-			return renderSP(os.Stdout, controlPlaneNamespace, clusterDomain)
-		},
-	}
-
-	return cmd
-}
-
-func renderSP(w io.Writer, namespace, clusterDomain string) error {
-	template, err := template.New("linkerd").Parse(installsp.Template)
-	if err != nil {
-		return err
-	}
-	buf := &bytes.Buffer{}
-	err = template.Execute(buf, map[string]string{"Namespace": namespace, "ClusterDomain": clusterDomain})
-	if err != nil {
-		return err
-	}
-
-	w.Write(buf.Bytes())
-	w.Write([]byte("---\n"))
-
-	return nil
-}
diff --git a/cli/cmd/upgrade.go b/cli/cmd/upgrade.go
index 4d6287bb3..79cf64f99 100644
--- a/cli/cmd/upgrade.go
+++ b/cli/cmd/upgrade.go
@@ -33,9 +33,8 @@ const (
 )
 
 var (
-	addOnOverwrite bool
-	manifests      string
-	force          bool
+	manifests string
+	force     bool
 )
 
 /* The upgrade commands all follow the same flow:
@@ -231,10 +230,6 @@ func makeUpgradeFlags() *pflag.FlagSet {
 		&force, "force", false,
 		"Force upgrade operation even when issuer certificate does not work with the trust anchors of all proxies",
 	)
-	upgradeFlags.BoolVar(
-		&addOnOverwrite, "addon-overwrite", false,
-		"Overwrite add-on configuration instead of loading the existing config (or reset to defaults if no new config is specified)",
-	)
 	return upgradeFlags
 }
 
diff --git a/cli/installsp/template.go b/cli/installsp/template.go
deleted file mode 100644
index 30914a32e..000000000
--- a/cli/installsp/template.go
+++ /dev/null
@@ -1,139 +0,0 @@
-package installsp
-
-// Template provides the base template for the `linkerd install-sp` command.
-const Template = `apiVersion: linkerd.io/v1alpha2
-kind: ServiceProfile
-metadata:
-  name: linkerd-controller-api.{{.Namespace}}.svc.{{.ClusterDomain}}
-  namespace: {{.Namespace}}
-spec:
-  routes:
-  - name: POST /api/v1/StatSummary
-    condition:
-      method: POST
-      pathRegex: /api/v1/StatSummary
-  - name: POST /api/v1/TopRoutes
-    condition:
-      method: POST
-      pathRegex: /api/v1/TopRoutes
-  - name: POST /api/v1/ListPods
-    condition:
-      method: POST
-      pathRegex: /api/v1/ListPods
-  - name: POST /api/v1/ListServices
-    condition:
-      method: POST
-      pathRegex: /api/v1/ListServices
-  - name: POST /api/v1/Version
-    condition:
-      method: POST
-      pathRegex: /api/v1/Version
-  - name: POST /api/v1/SelfCheck
-    condition:
-      method: POST
-      pathRegex: /api/v1/SelfCheck
----
-apiVersion: linkerd.io/v1alpha2
-kind: ServiceProfile
-metadata:
-  name: linkerd-dst.{{.Namespace}}.svc.{{.ClusterDomain}}
-  namespace: {{.Namespace}}
-spec:
-  routes:
-  - name: POST /io.linkerd.proxy.destination.Destination/Get
-    condition:
-      method: POST
-      pathRegex: /io\.linkerd\.proxy\.destination\.Destination/Get
-  - name: POST /io.linkerd.proxy.destination.Destination/GetProfile
-    condition:
-      method: POST
-      pathRegex: /io\.linkerd\.proxy\.destination\.Destination/GetProfile
----
-apiVersion: linkerd.io/v1alpha2
-kind: ServiceProfile
-metadata:
-  name: linkerd-dst-headless.{{.Namespace}}.svc.{{.ClusterDomain}}
-  namespace: {{.Namespace}}
-spec:
-  routes:
-  - name: POST /io.linkerd.proxy.destination.Destination/Get
-    condition:
-      method: POST
-      pathRegex: /io\.linkerd\.proxy\.destination\.Destination/Get
-  - name: POST /io.linkerd.proxy.destination.Destination/GetProfile
-    condition:
-      method: POST
-      pathRegex: /io\.linkerd\.proxy\.destination\.Destination/GetProfile
----
-apiVersion: linkerd.io/v1alpha2
-kind: ServiceProfile
-metadata:
-  name: linkerd-prometheus.{{.Namespace}}.svc.{{.ClusterDomain}}
-  namespace: {{.Namespace}}
-spec:
-  routes:
-  - name: POST /api/v1/query
-    condition:
-      method: POST
-      pathRegex: /api/v1/query
-  - name: GET /api/v1/query_range
-    condition:
-      method: GET
-      pathRegex: /api/v1/query_range
-  - name: GET /api/v1/series
-    condition:
-      method: GET
-      pathRegex: /api/v1/series
----
-apiVersion: linkerd.io/v1alpha2
-kind: ServiceProfile
-metadata:
-  name: linkerd-grafana.{{.Namespace}}.svc.{{.ClusterDomain}}
-  namespace: {{.Namespace}}
-spec:
-  routes:
-  - name: GET /api/annotations
-    condition:
-      method: GET
-      pathRegex: /api/annotations
-  - name: GET /api/dashboards/tags
-    condition:
-      method: GET
-      pathRegex: /api/dashboards/tags
-  - name: GET /api/dashboards/uid/{uid}
-    condition:
-      method: GET
-      pathRegex: /api/dashboards/uid/.*
-  - name: GET /api/dashboard/{dashboard}
-    condition:
-      method: GET
-      pathRegex: /api/dashboard/.*
-  - name: GET /api/datasources/proxy/1/api/v1/series
-    condition:
-      method: GET
-      pathRegex: /api/datasources/proxy/1/api/v1/series
-  - name: GET /api/datasources/proxy/1/api/v1/query_range
-    condition:
-      method: GET
-      pathRegex: /api/datasources/proxy/1/api/v1/query_range
-  - name: GET /api/search
-    condition:
-      method: GET
-      pathRegex: /api/search
-  - name: GET /d/{uid}/{dashboard-name}
-    condition:
-      method: GET
-      pathRegex: /d/[^/]*/.*
-  - name: GET /public/build/{style}.css
-    condition:
-      method: GET
-      pathRegex: /public/build/.*\.css
-  - name: GET /public/fonts/{font}
-    condition:
-      method: GET
-      pathRegex: /public/fonts/.*
-  - name: GET /public/img/{img}
-    condition:
-      method: GET
-      pathRegex: /public/img/.*
-`
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/controller/proxy-injector/fake/data/pod-with-debug.patch.json b/controller/proxy-injector/fake/data/pod-with-debug.patch.json
index 384b9b782..95dd0ed35 100644
--- a/controller/proxy-injector/fake/data/pod-with-debug.patch.json
+++ b/controller/proxy-injector/fake/data/pod-with-debug.patch.json
@@ -56,7 +56,7 @@
         "--inbound-ports-to-ignore",
         "4190,4191"
       ],
-      "image": "cr.l5d.io/linkerd/proxy-init:v1.3.11",
+      "image": "cr.l5d.io/linkerd/proxy-init:v1.3.12",
       "imagePullPolicy": "IfNotPresent",
       "name": "linkerd-init",
       "resources": {
diff --git a/controller/proxy-injector/fake/data/pod-with-ns-annotations.patch.json b/controller/proxy-injector/fake/data/pod-with-ns-annotations.patch.json
index 197ddc9a2..540d3e585 100644
--- a/controller/proxy-injector/fake/data/pod-with-ns-annotations.patch.json
+++ b/controller/proxy-injector/fake/data/pod-with-ns-annotations.patch.json
@@ -68,7 +68,7 @@
         "--outbound-ports-to-ignore",
         "34567"
       ],
-      "image": "cr.l5d.io/linkerd/proxy-init:v1.3.11",
+      "image": "cr.l5d.io/linkerd/proxy-init:v1.3.12",
       "imagePullPolicy": "IfNotPresent",
       "name": "linkerd-init",
       "resources": {
diff --git a/controller/proxy-injector/fake/data/pod.patch.json b/controller/proxy-injector/fake/data/pod.patch.json
index d48c17f4c..7fb38c840 100644
--- a/controller/proxy-injector/fake/data/pod.patch.json
+++ b/controller/proxy-injector/fake/data/pod.patch.json
@@ -56,7 +56,7 @@
         "--inbound-ports-to-ignore",
         "4190,4191"
       ],
-      "image": "cr.l5d.io/linkerd/proxy-init:v1.3.11",
+      "image": "cr.l5d.io/linkerd/proxy-init:v1.3.12",
       "imagePullPolicy": "IfNotPresent",
       "name": "linkerd-init",
       "resources": {
diff --git a/go.mod b/go.mod
index 310a63b1c..be8e0b82a 100644
--- a/go.mod
+++ b/go.mod
@@ -16,13 +16,13 @@ require (
 	github.com/ghodss/yaml v1.0.0
 	github.com/go-openapi/spec v0.19.3
 	github.com/golang/protobuf v1.4.3
-	github.com/gorilla/websocket v1.4.0
+	github.com/gorilla/websocket v1.4.2
 	github.com/grantae/certinfo v0.0.0-20170412194111-59d56a35515b
 	github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
 	github.com/imdario/mergo v0.3.8
 	github.com/julienschmidt/httprouter v1.2.0
 	github.com/linkerd/linkerd2-proxy-api v0.1.16
-	github.com/linkerd/linkerd2-proxy-init v1.3.11
+	github.com/linkerd/linkerd2-proxy-init v1.3.12
 	github.com/mattn/go-isatty v0.0.12
 	github.com/mattn/go-runewidth v0.0.4
 	github.com/nsf/termbox-go v0.0.0-20180613055208-5c94acc5e6eb
@@ -36,7 +36,7 @@ require (
 	github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 // indirect
 	github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd
 	github.com/sirupsen/logrus v1.7.0
-	github.com/spf13/cobra v1.0.0
+	github.com/spf13/cobra v1.1.3
 	github.com/spf13/pflag v1.0.5
 	go.opencensus.io v0.22.2
 	golang.org/x/net v0.0.0-20200707034311-ab3426394381
diff --git a/go.sum b/go.sum
index eef3ec7d9..98a1e014d 100644
--- a/go.sum
+++ b/go.sum
@@ -10,6 +10,7 @@ cloud.google.com/go v0.51.0 h1:PvKAVQWCtlGUSlZkGW3QLelKaWq7KYv/MW1EboG8bfM=
 cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw=
 cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
 cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
+cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
 cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
 cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
 contrib.go.opencensus.io/exporter/ocagent v0.6.0 h1:Z1n6UAyr0QwM284yUuh5Zd8JlvxUGAhFZcgMJkMPrGM=
@@ -103,6 +104,7 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
 github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
 github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
 github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA=
+github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
 github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
 github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
 github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
@@ -146,6 +148,7 @@ github.com/containernetworking/cni v0.6.1-0.20180218032124-142cde0c766c h1:X6Gxg
 github.com/containernetworking/cni v0.6.1-0.20180218032124-142cde0c766c/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
 github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
 github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
+github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
 github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
 github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
 github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
@@ -228,6 +231,7 @@ github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
 github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
 github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
 github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
+github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
 github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
 github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
@@ -367,8 +371,9 @@ github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2z
 github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
 github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
 github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
-github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
 github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
+github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
+github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
 github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo=
 github.com/grantae/certinfo v0.0.0-20170412194111-59d56a35515b h1:NGgE5ELokSf2tZ/bydyDUKrvd/jP8lrAoPNeBuMOTOk=
 github.com/grantae/certinfo v0.0.0-20170412194111-59d56a35515b/go.mod h1:zT/uzhdQGTqlwTq7Lpbj3JoJQWfPfIJ1tE0OidAmih8=
@@ -380,7 +385,9 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92Bcuy
 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
 github.com/grpc-ecosystem/grpc-gateway v1.14.8 h1:hXClj+iFpmLM8i3lkO6i4Psli4P2qObQuQReiII26U8=
 github.com/grpc-ecosystem/grpc-gateway v1.14.8/go.mod h1:NZE8t6vs6TnwLL/ITkaK8W3ecMLGAbh2jXTclvpiwYo=
+github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
 github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
+github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
 github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
 github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
 github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
@@ -458,11 +465,12 @@ github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-b
 github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
 github.com/linkerd/linkerd2-proxy-api v0.1.16 h1:Qjqbw5Bw3QYUJpUSpYHr4nkJqBRnTlsFUwncCtCdOEs=
 github.com/linkerd/linkerd2-proxy-api v0.1.16/go.mod h1:yFz+DCCEomC3vpsChFzfCuOuSJtzx7jMNNHBIlbFil0=
-github.com/linkerd/linkerd2-proxy-init v1.3.11 h1:RVwHgkOVVVQWoZqiFURsXZFjXvtOG8/+v9kqb+XEmoE=
-github.com/linkerd/linkerd2-proxy-init v1.3.11/go.mod h1:iYv3JOgCBpOr6T5qjfE1IeO9/33oaq349kOFMNyvoeM=
+github.com/linkerd/linkerd2-proxy-init v1.3.12 h1:/8fuDFLaa+dq1hZYuL06Fo6kHuq2T+VC10m3goVf3t0=
+github.com/linkerd/linkerd2-proxy-init v1.3.12/go.mod h1:iYv3JOgCBpOr6T5qjfE1IeO9/33oaq349kOFMNyvoeM=
 github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc=
 github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
 github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
+github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
 github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
 github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
 github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
@@ -667,8 +675,9 @@ github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU
 github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
 github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
 github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
-github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8=
 github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
+github.com/spf13/cobra v1.1.3 h1:xghbfqPkxzxP3C/f3n5DdpAbdKLj4ZE4BWQI362l53M=
+github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo=
 github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
 github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
 github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
@@ -678,6 +687,7 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
 github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
 github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
 github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
+github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
 github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
 github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
 github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
@@ -690,6 +700,7 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
 github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
 github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
 github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
 github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
 github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
@@ -762,6 +773,7 @@ golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
 golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
+golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
 golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
 golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
 golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
@@ -907,6 +919,7 @@ golang.org/x/tools v0.0.0-20191004055002-72853e10c5a3/go.mod h1:b+2E5dAYhXwXZwtn
 golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
@@ -923,6 +936,7 @@ google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEt
 google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
 google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
 google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
 google.golang.org/api v0.15.0 h1:yzlyyDW/J0w8yNFJIhiAJy4kq74S+1DOLdawELNxFMA=
 google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
 google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
@@ -943,6 +957,7 @@ google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610/go.mod h1:DMBHOl98
 google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
 google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
 google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
+google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
 google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
 google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
 google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY=
@@ -991,6 +1006,7 @@ gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKW
 gopkg.in/gorp.v1 v1.7.2/go.mod h1:Wo3h+DBQZIxATwftsglhdD/62zRFPhGhTiu5jUJmCaw=
 gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
 gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
+gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
 gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
 gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
@@ -1001,8 +1017,9 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
 gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
diff --git a/jaeger/charts/linkerd-jaeger/README.md b/jaeger/charts/linkerd-jaeger/README.md
index 437f46036..dad473aa5 100644
--- a/jaeger/charts/linkerd-jaeger/README.md
+++ b/jaeger/charts/linkerd-jaeger/README.md
@@ -71,6 +71,7 @@ Kubernetes: `>=1.16.0-0`
 
 | Key | Type | Default | Description |
 |-----|------|---------|-------------|
+| collector.enabled | bool | `true` | Set to false to exclude collector installation |
 | collector.image.name | string | `"omnition/opencensus-collector"` |  |
 | collector.image.pullPolicy | string | `"Always"` |  |
 | collector.image.version | string | `"0.1.11"` |  |
@@ -78,6 +79,7 @@ Kubernetes: `>=1.16.0-0`
 | collector.nodeSelector | object | `{"beta.kubernetes.io/os":"linux"}` | NodeSelector section, See the [K8S documentation](https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector) for more information |
 | collector.tolerations | string | `nil` | Tolerations section, See the [K8S documentation](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/) for more information |
 | installNamespace | bool | `true` | Set to false when installing in a custom namespace. |
+| jaeger.enabled | bool | `true` | Set to false to exclude all-in-one Jaeger installation |
 | jaeger.image.name | string | `"jaegertracing/all-in-one"` |  |
 | jaeger.image.pullPolicy | string | `"Always"` |  |
 | jaeger.image.version | string | `"1.19.2"` |  |
diff --git a/jaeger/charts/linkerd-jaeger/templates/rbac.yaml b/jaeger/charts/linkerd-jaeger/templates/rbac.yaml
index 342ff9646..622e6c6e1 100644
--- a/jaeger/charts/linkerd-jaeger/templates/rbac.yaml
+++ b/jaeger/charts/linkerd-jaeger/templates/rbac.yaml
@@ -1,3 +1,4 @@
+{{- if .Values.collector.enabled }}
 ---
 ###
 ### collector RBAC
@@ -7,6 +8,8 @@ apiVersion: v1
 metadata:
   name: collector
   namespace: {{.Values.namespace}}
+{{- end }}
+{{- if .Values.jaeger.enabled }}
 ---
 ###
 ### jaeger RBAC
@@ -16,7 +19,7 @@ apiVersion: v1
 metadata:
   name: jaeger
   namespace: {{.Values.namespace}}
-
+{{- end }}
 ---
 ###
 ### Jaeger Injector RBAC
diff --git a/jaeger/charts/linkerd-jaeger/templates/tracing.yaml b/jaeger/charts/linkerd-jaeger/templates/tracing.yaml
index b16bcdc89..41ac41f19 100644
--- a/jaeger/charts/linkerd-jaeger/templates/tracing.yaml
+++ b/jaeger/charts/linkerd-jaeger/templates/tracing.yaml
@@ -1,3 +1,4 @@
+{{- if .Values.collector.enabled }}
 ---
 ###
 ### Tracing Collector Service
@@ -119,6 +120,8 @@ spec:
             path: collector-config.yaml
           name: collector-config
         name: collector-config-val
+{{- end }}
+{{- if .Values.jaeger.enabled }}
 ---
 ###
 ### Tracing Jaeger Service
@@ -186,3 +189,4 @@ spec:
         {{- end }}
       dnsPolicy: ClusterFirst
       serviceAccountName: jaeger
+{{- end }}
diff --git a/jaeger/charts/linkerd-jaeger/values.yaml b/jaeger/charts/linkerd-jaeger/values.yaml
index 0b8e48f43..904e5bca8 100644
--- a/jaeger/charts/linkerd-jaeger/values.yaml
+++ b/jaeger/charts/linkerd-jaeger/values.yaml
@@ -15,6 +15,8 @@ nodeSelector: &default_node_selector
 tolerations: &default_tolerations
 
 collector:
+  # -- Set to false to exclude collector installation
+  enabled: true
   image:
     name: omnition/opencensus-collector
     version: 0.1.11
@@ -32,6 +34,8 @@ collector:
   jaegerAddr:
 
 jaeger:
+  # -- Set to false to exclude all-in-one Jaeger installation
+  enabled: true
   image:
     name: jaegertracing/all-in-one
     version: 1.19.2
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/pkg/k8s/completion.go b/pkg/k8s/completion.go
new file mode 100644
index 000000000..35ff5e4e3
--- /dev/null
+++ b/pkg/k8s/completion.go
@@ -0,0 +1,180 @@
+package k8s
+
+import (
+	"context"
+	"fmt"
+	"strings"
+	"time"
+
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/runtime/schema"
+)
+
+// CommandCompletion generates CLI suggestions from resources in a given cluster
+// It uses a list of arguments and a substring from the CLI to filter suggestions.
+type CommandCompletion struct {
+	k8sAPI    *KubernetesAPI
+	namespace string
+}
+
+// NewCommandCompletion creates a command completion module
+func NewCommandCompletion(
+	k8sAPI *KubernetesAPI,
+	namespace string,
+) *CommandCompletion {
+	return &CommandCompletion{
+		k8sAPI:    k8sAPI,
+		namespace: namespace,
+	}
+}
+
+// Complete accepts a list of arguments and a substring to generate CLI suggestions.
+// `args` represent a list of arguments a user has already enterd in the CLI. These
+// arguments are used for determining what resource type we'd like to receive
+// suggestions for as well as a list of resources names that have already provided.
+// `toComplete` represents the string prefix of a resource name that we'd like to
+// use to search for suggestions
+//
+// If `args` is empty, send back a list of all resource types support by the CLI.
+// If `args` has at least one or more items, assume that the first item in `args`
+// is the resource type we are trying to get suggestions for e.g. Deployment, StatefulSets.
+//
+// Complete is generic enough so that it can find suggestions for any type of resource
+// in a Kubernetes cluster. It does this by first querying what GroupVersion a resource
+// belongs to and then does a dynamic `List` query to get resources under that GroupVersion
+func (c *CommandCompletion) Complete(args []string, toComplete string) ([]string, error) {
+	ctx, cancelFn := context.WithTimeout(context.Background(), 5*time.Second)
+	defer cancelFn()
+
+	suggestions := []string{}
+	if len(args) == 0 && toComplete == "" {
+		return StatAllResourceTypes, nil
+	}
+
+	if len(args) == 0 && toComplete != "" {
+		for _, t := range StatAllResourceTypes {
+			if strings.HasPrefix(t, toComplete) {
+				suggestions = append(suggestions, t)
+			}
+		}
+		return suggestions, nil
+	}
+
+	resType, err := CanonicalResourceNameFromFriendlyName(args[0])
+	if err != nil {
+		return nil, fmt.Errorf("%s is not a valid resource name", args)
+	}
+
+	// if we are looking for namespace suggestions clear namespace selector
+	if resType == "namespace" {
+		c.namespace = ""
+	}
+
+	// Similar to kubectl's completion for bash and zsh only, we don't provide
+	// resource completion when the resource provided is in format
+	// <kind>/<resourceName>.
+	if strings.Contains(args[0], "/") {
+		return []string{}, nil
+	}
+
+	gvr, err := c.getGroupVersionKindForResource(resType)
+	if err != nil {
+		return nil, err
+	}
+
+	uList, err := c.k8sAPI.DynamicClient.
+		Resource(*gvr).
+		Namespace(c.namespace).
+		List(ctx, metav1.ListOptions{})
+	if err != nil {
+		return nil, err
+	}
+
+	otherResources := args[1:]
+	for _, u := range uList.Items {
+		name := u.GetName()
+
+		// Filter out the list of resource items returned from k8s API to
+		// only include items that have the prefix `toComplete` and items
+		// that aren't in the list of resources already provided in the
+		// list of arguments.
+		//
+		// This is useful so that we avoid duplicate suggestions if they
+		// are already in the list of args
+		if strings.HasPrefix(name, toComplete) &&
+			!containsResource(name, otherResources) {
+			suggestions = append(suggestions, name)
+		}
+	}
+
+	return suggestions, nil
+}
+
+func (c *CommandCompletion) getGroupVersionKindForResource(resourceName string) (*schema.GroupVersionResource, error) {
+	_, apiResourceList, err := c.k8sAPI.Discovery().ServerGroupsAndResources()
+	if err != nil {
+		return nil, err
+	}
+
+	// find the plural name to ensure the resource we are searching for is not a subresource
+	// i.e. deployment/scale
+	pluralResourceName, err := PluralResourceNameFromFriendlyName(resourceName)
+	if err != nil {
+		return nil, fmt.Errorf("%s not a valid resource name", resourceName)
+	}
+
+	gvr, err := findGroupVersionResource(resourceName, pluralResourceName, apiResourceList)
+	if err != nil {
+		return nil, fmt.Errorf("could not find GroupVersionResource for %s", resourceName)
+	}
+
+	return gvr, nil
+}
+
+func findGroupVersionResource(singularName string, pluralName string, apiResourceList []*metav1.APIResourceList) (*schema.GroupVersionResource, error) {
+	err := fmt.Errorf("could not find the requested resource")
+	for _, res := range apiResourceList {
+		for _, r := range res.APIResources {
+
+			// Make sure we get a resource type where its Kind matches the
+			// singularName passed into this function and its Name (which is always
+			// the pluralName of an api resource) matches the pluralName passed
+			// into this function. Skip further processing of this APIResource
+			// if this is not the case.
+			if strings.ToLower(r.Kind) != singularName || r.Name != pluralName {
+				continue
+			}
+
+			gv := strings.Split(res.GroupVersion, "/")
+
+			if len(gv) == 1 && gv[0] == "v1" {
+				return &schema.GroupVersionResource{
+					Version:  gv[0],
+					Resource: r.Name,
+				}, nil
+			}
+
+			if len(gv) != 2 {
+				return nil, err
+			}
+
+			return &schema.GroupVersionResource{
+				Group:    gv[0],
+				Version:  gv[1],
+				Resource: r.Name,
+			}, nil
+		}
+	}
+
+	return nil, err
+}
+
+func containsResource(resource string, otherResources []string) bool {
+	for _, r := range otherResources {
+		if r == resource {
+			return true
+		}
+	}
+
+	return false
+}
diff --git a/pkg/k8s/k8s.go b/pkg/k8s/k8s.go
index e480d3375..aa989b3c5 100644
--- a/pkg/k8s/k8s.go
+++ b/pkg/k8s/k8s.go
@@ -62,7 +62,7 @@ var AllResources = []string{
 
 // StatAllResourceTypes represents the resources to query in StatSummary when Resource.Type is "all"
 var StatAllResourceTypes = []string{
-	// TODO: add Namespace here to decrease queries from the web process
+	Namespace,
 	DaemonSet,
 	StatefulSet,
 	Job,
diff --git a/pkg/k8s/resource/resource.go b/pkg/k8s/resource/resource.go
index f03cf503a..798c66511 100644
--- a/pkg/k8s/resource/resource.go
+++ b/pkg/k8s/resource/resource.go
@@ -89,9 +89,15 @@ func FetchKubernetesResources(ctx context.Context, k *k8s.KubernetesAPI, options
 	}
 	resources = append(resources, clusterRoleBindings...)
 
-	roleBindings, err := fetchKubeSystemRoleBindings(ctx, k, options)
+	roles, err := fetchRoles(ctx, k, options)
 	if err != nil {
-		return nil, fmt.Errorf("could not fetch RoleBindings from kube-system namespace:%v", err)
+		return nil, fmt.Errorf("could not fetch Roles:%v", err)
+	}
+	resources = append(resources, roles...)
+
+	roleBindings, err := fetchRoleBindings(ctx, k, options)
+	if err != nil {
+		return nil, fmt.Errorf("could not fetch RoleBindings:%v", err)
 	}
 	resources = append(resources, roleBindings...)
 
@@ -162,11 +168,23 @@ func fetchClusterRoleBindings(ctx context.Context, k *k8s.KubernetesAPI, options
 	return resources, nil
 }
 
-// Although role bindings are namespaced resources in nature
-// some admin role bindings are created and persisted in the kube-system namespace and will not be deleted
-// when the namespace is deleted
-func fetchKubeSystemRoleBindings(ctx context.Context, k *k8s.KubernetesAPI, options metav1.ListOptions) ([]Kubernetes, error) {
-	list, err := k.RbacV1().RoleBindings("kube-system").List(ctx, options)
+func fetchRoles(ctx context.Context, k *k8s.KubernetesAPI, options metav1.ListOptions) ([]Kubernetes, error) {
+	list, err := k.RbacV1().Roles("").List(ctx, options)
+	if err != nil {
+		return nil, err
+	}
+
+	resources := make([]Kubernetes, len(list.Items))
+	for i, item := range list.Items {
+		r := New(rbac.SchemeGroupVersion.String(), "Role", item.Name)
+		r.Namespace = item.Namespace
+		resources[i] = r
+	}
+	return resources, nil
+}
+
+func fetchRoleBindings(ctx context.Context, k *k8s.KubernetesAPI, options metav1.ListOptions) ([]Kubernetes, error) {
+	list, err := k.RbacV1().RoleBindings("").List(ctx, options)
 	if err != nil {
 		return nil, err
 	}
diff --git a/pkg/version/version.go b/pkg/version/version.go
index 66a4492ca..1db8c21ef 100644
--- a/pkg/version/version.go
+++ b/pkg/version/version.go
@@ -16,7 +16,7 @@ var Version = undefinedVersion
 // https://github.com/linkerd/linkerd2-proxy-init
 // This has to be kept in sync with the constraint version for
 // github.com/linkerd/linkerd2-proxy-init in /go.mod
-var ProxyInitVersion = "v1.3.11"
+var ProxyInitVersion = "v1.3.12"
 
 const (
 	// undefinedVersion should take the form `channel-version` to conform to
diff --git a/viz/charts/linkerd-viz/templates/prometheus.yaml b/viz/charts/linkerd-viz/templates/prometheus.yaml
index 18cd008a2..554a34ff8 100644
--- a/viz/charts/linkerd-viz/templates/prometheus.yaml
+++ b/viz/charts/linkerd-viz/templates/prometheus.yaml
@@ -224,7 +224,7 @@ spec:
         {{- with .Values.prometheus.proxy }}
         {{- include "partials.proxy.config.annotations" .resources | nindent 8 }}
         {{- end }}
-        {{- with .Values.podAnnotations }}{{  . | trim | nindent 8 }}{{- end }}
+        {{- with .Values.podAnnotations }}{{ toYaml . | trim | nindent 8 }}{{- end }}
       labels:
         linkerd.io/extension: viz
         component: prometheus
diff --git a/viz/cmd/install.go b/viz/cmd/install.go
index a5ed3cb57..82d78f70a 100644
--- a/viz/cmd/install.go
+++ b/viz/cmd/install.go
@@ -21,7 +21,7 @@ import (
 )
 
 var (
-	templatesVIz = []string{
+	templatesViz = []string{
 		"templates/namespace.yaml",
 		"templates/metrics-api-rbac.yaml",
 		"templates/grafana-rbac.yaml",
@@ -36,6 +36,7 @@ var (
 		"templates/tap-injector-rbac.yaml",
 		"templates/tap-injector.yaml",
 		"templates/web.yaml",
+		"templates/service-profiles.yaml",
 	}
 )
 
@@ -116,7 +117,7 @@ func render(w io.Writer, valuesOverrides map[string]interface{}) error {
 		{Name: chartutil.ValuesfileName},
 	}
 
-	for _, template := range templatesVIz {
+	for _, template := range templatesViz {
 		files = append(files,
 			&loader.BufferedFile{Name: template},
 		)
diff --git a/viz/cmd/stat.go b/viz/cmd/stat.go
index 05039a661..9c80a59a1 100644
--- a/viz/cmd/stat.go
+++ b/viz/cmd/stat.go
@@ -18,10 +18,10 @@ import (
 	"github.com/linkerd/linkerd2/pkg/k8s"
 	pb "github.com/linkerd/linkerd2/viz/metrics-api/gen/viz"
 	"github.com/linkerd/linkerd2/viz/metrics-api/util"
-	"github.com/linkerd/linkerd2/viz/pkg"
 	"github.com/linkerd/linkerd2/viz/pkg/api"
 	log "github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
+	v1 "k8s.io/api/core/v1"
 )
 
 type statOptions struct {
@@ -167,8 +167,31 @@ If no resource name is specified, displays stats about all resources of the spec
 
   # Get all inbound stats to the test namespace.
   linkerd viz stat ns/test`,
-		Args:      cobra.MinimumNArgs(1),
-		ValidArgs: pkg.ValidTargets,
+		Args: cobra.MinimumNArgs(1),
+		ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+
+			k8sAPI, err := k8s.NewAPI(kubeconfigPath, kubeContext, impersonate, impersonateGroup, 0)
+			if err != nil {
+				return nil, cobra.ShellCompDirectiveError
+			}
+
+			if options.namespace == "" {
+				options.namespace = pkgcmd.GetDefaultNamespace(kubeconfigPath, kubeContext)
+			}
+
+			if options.allNamespaces {
+				options.namespace = v1.NamespaceAll
+			}
+
+			cc := k8s.NewCommandCompletion(k8sAPI, options.namespace)
+
+			results, err := cc.Complete(args, toComplete)
+			if err != nil {
+				return nil, cobra.ShellCompDirectiveError
+			}
+
+			return results, cobra.ShellCompDirectiveDefault
+		},
 		RunE: func(cmd *cobra.Command, args []string) error {
 			if options.namespace == "" {
 				options.namespace = pkgcmd.GetDefaultNamespace(kubeconfigPath, kubeContext)
@@ -229,9 +252,33 @@ If no resource name is specified, displays stats about all resources of the spec
 	cmd.PersistentFlags().StringVarP(&options.outputFormat, "output", "o", options.outputFormat, "Output format; one of: \"table\" or \"json\" or \"wide\"")
 	cmd.PersistentFlags().StringVarP(&options.labelSelector, "selector", "l", options.labelSelector, "Selector (label query) to filter on, supports '=', '==', and '!='")
 	cmd.PersistentFlags().BoolVar(&options.unmeshed, "unmeshed", options.unmeshed, "If present, include unmeshed resources in the output")
+
+	configureFlagCompletions(cmd)
 	return cmd
 }
 
+func configureFlagCompletions(cmd *cobra.Command) {
+	flagNames := []string{"namespace", "to-namespace", "from-namespace"}
+	for _, flagName := range flagNames {
+		cmd.RegisterFlagCompletionFunc(flagName,
+			func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+				k8sAPI, err := k8s.NewAPI(kubeconfigPath, kubeContext, impersonate, impersonateGroup, 0)
+				if err != nil {
+					return nil, cobra.ShellCompDirectiveError
+				}
+
+				cc := k8s.NewCommandCompletion(k8sAPI, "")
+				results, err := cc.Complete([]string{"namespaces"}, toComplete)
+				if err != nil {
+					cobra.CompErrorln(err.Error())
+					return nil, cobra.ShellCompDirectiveError
+				}
+
+				return results, cobra.ShellCompDirectiveDefault
+			})
+	}
+}
+
 func respToRows(resp *pb.StatSummaryResponse) []*pb.StatTable_PodGroup_Row {
 	rows := make([]*pb.StatTable_PodGroup_Row, 0)
 	if resp != nil {
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 2096eb970..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'
@@ -20,8 +23,7 @@ jobs:
     timeout-minutes: 30
     steps:
     - name: Checkout code
-      # actions/checkout@v2
-      uses: actions/checkout@722adc63f1aa60a57ec37892e133b1d319cae598
+      uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4
     - name: Set environment variables from scripts
       run: |
         . bin/_tag.sh
@@ -75,8 +77,7 @@ jobs:
     timeout-minutes: 30
     steps:
     - name: Checkout code
-      # actions/checkout@v2
-      uses: actions/checkout@722adc63f1aa60a57ec37892e133b1d319cae598
+      uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4
     - name: Try to load cached Go modules
       # actions/cache@v1.1.2
       uses: actions/cache@70655ec8323daeeaa7ef06d7c56e1b9191396cbe
@@ -112,11 +113,10 @@ jobs:
     needs: [docker_build]
     name: Integration tests (${{ matrix.integration_test }})
     runs-on: ubuntu-20.04
-    timeout-minutes: 30
+    timeout-minutes: 60
     steps:
     - name: Checkout code
-      # actions/checkout@v2
-      uses: actions/checkout@722adc63f1aa60a57ec37892e133b1d319cae598
+      uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4
     - name: Try to load cached Go modules
       # actions/cache@v1.1.2
       uses: actions/cache@70655ec8323daeeaa7ef06d7c56e1b9191396cbe
diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml
index 094e3d9d7..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,11 +16,10 @@ jobs:
     timeout-minutes: 30
     runs-on: ubuntu-20.04
     container:
-      image: golang:1.16.2
+      image: golang:1.16.4
     steps:
     - name: Checkout code
-      # actions/checkout@v2
-      uses: actions/checkout@722adc63f1aa60a57ec37892e133b1d319cae598
+      uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4
     - name: Go unit tests
       run: |
         go get gotest.tools/gotestsum@v0.4.2
@@ -31,8 +33,7 @@ jobs:
       image: node:14-stretch
     steps:
     - name: Checkout code
-      # actions/checkout@v2
-      uses: actions/checkout@722adc63f1aa60a57ec37892e133b1d319cae598
+      uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4
     - name: Yarn setup
       run: curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version 1.21.1 --network-concurrency 1
     - name: JS unit tests
diff --git a/bin/_test-helpers.sh b/bin/_test-helpers.sh
index 0d7d84fa4..d9c0828b9 100644
--- a/bin/_test-helpers.sh
+++ b/bin/_test-helpers.sh
@@ -348,7 +348,7 @@ run_test(){
 
   printf 'Test script: [%s] Params: [%s]\n' "${filename##*/}" "$*"
   # Exit on failure here
-  GO111MODULE=on go test --failfast --mod=readonly "$filename" --linkerd="$linkerd_path" --helm-path="$helm_path" --k8s-context="$context" --integration-tests "$@" || exit 1
+  GO111MODULE=on go test -test.timeout=60m --failfast --mod=readonly "$filename" --linkerd="$linkerd_path" --helm-path="$helm_path" --k8s-context="$context" --integration-tests "$@" || exit 1
 }
 
 # Returns the latest version for the release channel
@@ -386,7 +386,7 @@ install_version() {
 
     (
         set -x
-        "$linkerd_path" check 2>&1
+        "$linkerd_path" check --wait 60m 2>&1
     )
     exit_on_err 'install_version() - linkerd check failed'
 
diff --git a/bin/test-scale b/bin/test-scale
index 40fc40b59..24d5cec8b 100755
--- a/bin/test-scale
+++ b/bin/test-scale
@@ -70,7 +70,6 @@ linkerd_namespace=${2:-l5d-scale}
 
 "$linkerd_path" -l "$linkerd_namespace" install | kubectl apply -f -
 "$linkerd_path" -l "$linkerd_namespace" check --expected-version="$linkerd_version"
-"$linkerd_path" -l "$linkerd_namespace" install-sp | kubectl apply -f -
 
 #
 # Deploy Books
diff --git a/cli/cmd/install-sp_test.go b/cli/cmd/install-sp_test.go
deleted file mode 100644
index edf94b505..000000000
--- a/cli/cmd/install-sp_test.go
+++ /dev/null
@@ -1,30 +0,0 @@
-package cmd
-
-import (
-	"bytes"
-	"fmt"
-	"testing"
-)
-
-func TestRenderSP(t *testing.T) {
-	testCases := []struct {
-		controlPlaneNamespace string
-		clusterDomain         string
-		goldenFileName        string
-	}{
-		{controlPlaneNamespace, "cluster.local", "install-sp_default.golden"},
-		{"NAMESPACE", "CLUSTERDOMAIN", "install-sp_output.golden"},
-	}
-
-	for i, tc := range testCases {
-		tc := tc // pin
-		t.Run(fmt.Sprintf("%d: %s", i, "testdata/"+tc.goldenFileName), func(t *testing.T) {
-			var buf bytes.Buffer
-			err := renderSP(&buf, tc.controlPlaneNamespace, tc.clusterDomain)
-			if err != nil {
-				t.Fatalf("Unexpected error: %v", err)
-			}
-			testDataDiffer.DiffTestdata(t, tc.goldenFileName, buf.String())
-		})
-	}
-}
diff --git a/cli/cmd/testdata/inject-filepath/expected/injected_nginx.yaml b/cli/cmd/testdata/inject-filepath/expected/injected_nginx.yaml
index 2e709be36..38c19c8b0 100644
--- a/cli/cmd/testdata/inject-filepath/expected/injected_nginx.yaml
+++ b/cli/cmd/testdata/inject-filepath/expected/injected_nginx.yaml
@@ -139,7 +139,7 @@ spec:
         - "2102"
         - --inbound-ports-to-ignore
         - 4190,4191
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
diff --git a/cli/cmd/testdata/inject-filepath/expected/injected_nginx_redis.yaml b/cli/cmd/testdata/inject-filepath/expected/injected_nginx_redis.yaml
index c925700e4..8763eade2 100644
--- a/cli/cmd/testdata/inject-filepath/expected/injected_nginx_redis.yaml
+++ b/cli/cmd/testdata/inject-filepath/expected/injected_nginx_redis.yaml
@@ -139,7 +139,7 @@ spec:
         - "2102"
         - --inbound-ports-to-ignore
         - 4190,4191
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
@@ -311,7 +311,7 @@ spec:
         - "2102"
         - --inbound-ports-to-ignore
         - 4190,4191
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
diff --git a/cli/cmd/testdata/inject-filepath/expected/injected_redis.yaml b/cli/cmd/testdata/inject-filepath/expected/injected_redis.yaml
index b8a344b42..796079179 100644
--- a/cli/cmd/testdata/inject-filepath/expected/injected_redis.yaml
+++ b/cli/cmd/testdata/inject-filepath/expected/injected_redis.yaml
@@ -139,7 +139,7 @@ spec:
         - "2102"
         - --inbound-ports-to-ignore
         - 4190,4191
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
diff --git a/cli/cmd/testdata/inject_contour.golden.yml b/cli/cmd/testdata/inject_contour.golden.yml
index a6a13e8b5..158590e7a 100644
--- a/cli/cmd/testdata/inject_contour.golden.yml
+++ b/cli/cmd/testdata/inject_contour.golden.yml
@@ -179,7 +179,7 @@ spec:
         - "2102"
         - --inbound-ports-to-ignore
         - 4190,4191
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
diff --git a/cli/cmd/testdata/inject_emojivoto_already_injected.golden.yml b/cli/cmd/testdata/inject_emojivoto_already_injected.golden.yml
index 617ce627f..605e18abb 100644
--- a/cli/cmd/testdata/inject_emojivoto_already_injected.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_already_injected.golden.yml
@@ -150,7 +150,7 @@ spec:
         - "2102"
         - --inbound-ports-to-ignore
         - 4190,4191
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
@@ -333,7 +333,7 @@ spec:
         - "2102"
         - --inbound-ports-to-ignore
         - 4190,4191
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
@@ -516,7 +516,7 @@ spec:
         - "2102"
         - --inbound-ports-to-ignore
         - 4190,4191
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
@@ -699,7 +699,7 @@ spec:
         - "2102"
         - --inbound-ports-to-ignore
         - 4190,4191
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
diff --git a/cli/cmd/testdata/inject_emojivoto_deployment.golden.yml b/cli/cmd/testdata/inject_emojivoto_deployment.golden.yml
index e4e50c1ec..6a899c192 100644
--- a/cli/cmd/testdata/inject_emojivoto_deployment.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_deployment.golden.yml
@@ -150,7 +150,7 @@ spec:
         - "2102"
         - --inbound-ports-to-ignore
         - 4190,4191
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
diff --git a/cli/cmd/testdata/inject_emojivoto_deployment_capabilities.golden.yml b/cli/cmd/testdata/inject_emojivoto_deployment_capabilities.golden.yml
index fdc6de618..6bc19e083 100644
--- a/cli/cmd/testdata/inject_emojivoto_deployment_capabilities.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_deployment_capabilities.golden.yml
@@ -163,7 +163,7 @@ spec:
         - "2102"
         - --inbound-ports-to-ignore
         - 4190,4191
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
diff --git a/cli/cmd/testdata/inject_emojivoto_deployment_config_overrides.golden.yml b/cli/cmd/testdata/inject_emojivoto_deployment_config_overrides.golden.yml
index 3cf3dc9b8..70d5f3cde 100644
--- a/cli/cmd/testdata/inject_emojivoto_deployment_config_overrides.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_deployment_config_overrides.golden.yml
@@ -169,7 +169,7 @@ spec:
         - 4190,9998,7777,8888
         - --outbound-ports-to-ignore
         - "9999"
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
diff --git a/cli/cmd/testdata/inject_emojivoto_deployment_controller_name.golden.yml b/cli/cmd/testdata/inject_emojivoto_deployment_controller_name.golden.yml
index aa2005756..c9bc00546 100644
--- a/cli/cmd/testdata/inject_emojivoto_deployment_controller_name.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_deployment_controller_name.golden.yml
@@ -150,7 +150,7 @@ spec:
         - "2102"
         - --inbound-ports-to-ignore
         - 4190,4191
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
@@ -333,7 +333,7 @@ spec:
         - "2102"
         - --inbound-ports-to-ignore
         - 4190,4191
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
diff --git a/cli/cmd/testdata/inject_emojivoto_deployment_debug.golden.yml b/cli/cmd/testdata/inject_emojivoto_deployment_debug.golden.yml
index 2c514f94d..5fa4e4240 100644
--- a/cli/cmd/testdata/inject_emojivoto_deployment_debug.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_deployment_debug.golden.yml
@@ -155,7 +155,7 @@ spec:
         - "2102"
         - --inbound-ports-to-ignore
         - 4190,4191
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
diff --git a/cli/cmd/testdata/inject_emojivoto_deployment_empty_resources.golden.yml b/cli/cmd/testdata/inject_emojivoto_deployment_empty_resources.golden.yml
index 088d2b3bc..bb04a634e 100644
--- a/cli/cmd/testdata/inject_emojivoto_deployment_empty_resources.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_deployment_empty_resources.golden.yml
@@ -150,7 +150,7 @@ spec:
         - "2102"
         - --inbound-ports-to-ignore
         - 4190,4191
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
diff --git a/cli/cmd/testdata/inject_emojivoto_deployment_hostNetwork_false.golden.yml b/cli/cmd/testdata/inject_emojivoto_deployment_hostNetwork_false.golden.yml
index f0f25c0c0..3dadd6556 100644
--- a/cli/cmd/testdata/inject_emojivoto_deployment_hostNetwork_false.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_deployment_hostNetwork_false.golden.yml
@@ -151,7 +151,7 @@ spec:
         - "2102"
         - --inbound-ports-to-ignore
         - 4190,4191
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
diff --git a/cli/cmd/testdata/inject_emojivoto_deployment_opaque_ports.golden.yml b/cli/cmd/testdata/inject_emojivoto_deployment_opaque_ports.golden.yml
index 6344bda01..4872de2d6 100644
--- a/cli/cmd/testdata/inject_emojivoto_deployment_opaque_ports.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_deployment_opaque_ports.golden.yml
@@ -151,7 +151,7 @@ spec:
         - "2102"
         - --inbound-ports-to-ignore
         - 4190,4191
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
diff --git a/cli/cmd/testdata/inject_emojivoto_deployment_overridden.golden.yml b/cli/cmd/testdata/inject_emojivoto_deployment_overridden.golden.yml
index 1e4ef9a03..f8f2f4baa 100644
--- a/cli/cmd/testdata/inject_emojivoto_deployment_overridden.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_deployment_overridden.golden.yml
@@ -151,7 +151,7 @@ spec:
         - "2102"
         - --inbound-ports-to-ignore
         - 4190,1234
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
diff --git a/cli/cmd/testdata/inject_emojivoto_deployment_proxyignores.golden.yml b/cli/cmd/testdata/inject_emojivoto_deployment_proxyignores.golden.yml
index 145e908ab..c8b0dc10c 100644
--- a/cli/cmd/testdata/inject_emojivoto_deployment_proxyignores.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_deployment_proxyignores.golden.yml
@@ -154,7 +154,7 @@ spec:
         - 4190,4191,22,8100-8102
         - --outbound-ports-to-ignore
         - "5432"
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
diff --git a/cli/cmd/testdata/inject_emojivoto_deployment_udp.golden.yml b/cli/cmd/testdata/inject_emojivoto_deployment_udp.golden.yml
index 597ca579d..bbce1860b 100644
--- a/cli/cmd/testdata/inject_emojivoto_deployment_udp.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_deployment_udp.golden.yml
@@ -152,7 +152,7 @@ spec:
         - "2102"
         - --inbound-ports-to-ignore
         - 4190,4191
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
diff --git a/cli/cmd/testdata/inject_emojivoto_list.golden.yml b/cli/cmd/testdata/inject_emojivoto_list.golden.yml
index ae4c33b6a..ca9a3da14 100644
--- a/cli/cmd/testdata/inject_emojivoto_list.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_list.golden.yml
@@ -152,7 +152,7 @@ items:
           - "2102"
           - --inbound-ports-to-ignore
           - 4190,4191
-          image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+          image: cr.l5d.io/linkerd/proxy-init:v1.3.12
           imagePullPolicy: IfNotPresent
           name: linkerd-init
           resources:
@@ -329,7 +329,7 @@ items:
           - "2102"
           - --inbound-ports-to-ignore
           - 4190,4191
-          image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+          image: cr.l5d.io/linkerd/proxy-init:v1.3.12
           imagePullPolicy: IfNotPresent
           name: linkerd-init
           resources:
diff --git a/cli/cmd/testdata/inject_emojivoto_list_empty_resources.golden.yml b/cli/cmd/testdata/inject_emojivoto_list_empty_resources.golden.yml
index c35595ebe..6c1749c74 100644
--- a/cli/cmd/testdata/inject_emojivoto_list_empty_resources.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_list_empty_resources.golden.yml
@@ -152,7 +152,7 @@ items:
           - "2102"
           - --inbound-ports-to-ignore
           - 4190,4191
-          image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+          image: cr.l5d.io/linkerd/proxy-init:v1.3.12
           imagePullPolicy: IfNotPresent
           name: linkerd-init
           resources:
@@ -329,7 +329,7 @@ items:
           - "2102"
           - --inbound-ports-to-ignore
           - 4190,4191
-          image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+          image: cr.l5d.io/linkerd/proxy-init:v1.3.12
           imagePullPolicy: IfNotPresent
           name: linkerd-init
           resources:
diff --git a/cli/cmd/testdata/inject_emojivoto_pod.golden.yml b/cli/cmd/testdata/inject_emojivoto_pod.golden.yml
index 187967b71..5dcc85b14 100644
--- a/cli/cmd/testdata/inject_emojivoto_pod.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_pod.golden.yml
@@ -135,7 +135,7 @@ spec:
     - "2102"
     - --inbound-ports-to-ignore
     - 4190,4191
-    image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+    image: cr.l5d.io/linkerd/proxy-init:v1.3.12
     imagePullPolicy: IfNotPresent
     name: linkerd-init
     resources:
diff --git a/cli/cmd/testdata/inject_emojivoto_pod_ingress.golden.yml b/cli/cmd/testdata/inject_emojivoto_pod_ingress.golden.yml
index 06eb16526..f26116773 100644
--- a/cli/cmd/testdata/inject_emojivoto_pod_ingress.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_pod_ingress.golden.yml
@@ -138,7 +138,7 @@ spec:
     - "2102"
     - --inbound-ports-to-ignore
     - 4190,4191
-    image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+    image: cr.l5d.io/linkerd/proxy-init:v1.3.12
     imagePullPolicy: IfNotPresent
     name: linkerd-init
     resources:
diff --git a/cli/cmd/testdata/inject_emojivoto_pod_proxyignores.golden.yml b/cli/cmd/testdata/inject_emojivoto_pod_proxyignores.golden.yml
index be6548f32..dcf16e224 100644
--- a/cli/cmd/testdata/inject_emojivoto_pod_proxyignores.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_pod_proxyignores.golden.yml
@@ -139,7 +139,7 @@ spec:
     - 4190,4191,22,8100-8102
     - --outbound-ports-to-ignore
     - "5432"
-    image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+    image: cr.l5d.io/linkerd/proxy-init:v1.3.12
     imagePullPolicy: IfNotPresent
     name: linkerd-init
     resources:
diff --git a/cli/cmd/testdata/inject_emojivoto_pod_with_requests.golden.yml b/cli/cmd/testdata/inject_emojivoto_pod_with_requests.golden.yml
index aa15f284b..9898af462 100644
--- a/cli/cmd/testdata/inject_emojivoto_pod_with_requests.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_pod_with_requests.golden.yml
@@ -146,7 +146,7 @@ spec:
     - "2102"
     - --inbound-ports-to-ignore
     - 4190,4191
-    image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+    image: cr.l5d.io/linkerd/proxy-init:v1.3.12
     imagePullPolicy: IfNotPresent
     name: linkerd-init
     resources:
diff --git a/cli/cmd/testdata/inject_emojivoto_statefulset.golden.yml b/cli/cmd/testdata/inject_emojivoto_statefulset.golden.yml
index 4a924586c..0e21e694c 100644
--- a/cli/cmd/testdata/inject_emojivoto_statefulset.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_statefulset.golden.yml
@@ -151,7 +151,7 @@ spec:
         - "2102"
         - --inbound-ports-to-ignore
         - 4190,4191
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
diff --git a/cli/cmd/testdata/inject_gettest_deployment.good.golden.yml b/cli/cmd/testdata/inject_gettest_deployment.good.golden.yml
index 822e1d756..747d76d1a 100644
--- a/cli/cmd/testdata/inject_gettest_deployment.good.golden.yml
+++ b/cli/cmd/testdata/inject_gettest_deployment.good.golden.yml
@@ -152,7 +152,7 @@ spec:
         - "2102"
         - --inbound-ports-to-ignore
         - 4190,4191
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
@@ -337,7 +337,7 @@ spec:
         - "2102"
         - --inbound-ports-to-ignore
         - 4190,4191
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
diff --git a/cli/cmd/testdata/inject_tap_deployment.input.yml b/cli/cmd/testdata/inject_tap_deployment.input.yml
index 1ad577b54..ffb29bd86 100644
--- a/cli/cmd/testdata/inject_tap_deployment.input.yml
+++ b/cli/cmd/testdata/inject_tap_deployment.input.yml
@@ -203,7 +203,7 @@ spec:
         - 4190,4191
         - --outbound-ports-to-ignore
         - "443"
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
diff --git a/cli/cmd/testdata/inject_tap_deployment_debug.golden.yml b/cli/cmd/testdata/inject_tap_deployment_debug.golden.yml
index 9ade0aef2..bf00d19bb 100644
--- a/cli/cmd/testdata/inject_tap_deployment_debug.golden.yml
+++ b/cli/cmd/testdata/inject_tap_deployment_debug.golden.yml
@@ -204,7 +204,7 @@ spec:
         - "2102"
         - --inbound-ports-to-ignore
         - 4190,4191
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
diff --git a/cli/cmd/testdata/install-sp_output.golden b/cli/cmd/testdata/install-sp_output.golden
deleted file mode 100644
index 3f1db28c1..000000000
--- a/cli/cmd/testdata/install-sp_output.golden
+++ /dev/null
@@ -1,136 +0,0 @@
-apiVersion: linkerd.io/v1alpha2
-kind: ServiceProfile
-metadata:
-  name: linkerd-controller-api.NAMESPACE.svc.CLUSTERDOMAIN
-  namespace: NAMESPACE
-spec:
-  routes:
-  - name: POST /api/v1/StatSummary
-    condition:
-      method: POST
-      pathRegex: /api/v1/StatSummary
-  - name: POST /api/v1/TopRoutes
-    condition:
-      method: POST
-      pathRegex: /api/v1/TopRoutes
-  - name: POST /api/v1/ListPods
-    condition:
-      method: POST
-      pathRegex: /api/v1/ListPods
-  - name: POST /api/v1/ListServices
-    condition:
-      method: POST
-      pathRegex: /api/v1/ListServices
-  - name: POST /api/v1/Version
-    condition:
-      method: POST
-      pathRegex: /api/v1/Version
-  - name: POST /api/v1/SelfCheck
-    condition:
-      method: POST
-      pathRegex: /api/v1/SelfCheck
----
-apiVersion: linkerd.io/v1alpha2
-kind: ServiceProfile
-metadata:
-  name: linkerd-dst.NAMESPACE.svc.CLUSTERDOMAIN
-  namespace: NAMESPACE
-spec:
-  routes:
-  - name: POST /io.linkerd.proxy.destination.Destination/Get
-    condition:
-      method: POST
-      pathRegex: /io\.linkerd\.proxy\.destination\.Destination/Get
-  - name: POST /io.linkerd.proxy.destination.Destination/GetProfile
-    condition:
-      method: POST
-      pathRegex: /io\.linkerd\.proxy\.destination\.Destination/GetProfile
----
-apiVersion: linkerd.io/v1alpha2
-kind: ServiceProfile
-metadata:
-  name: linkerd-dst-headless.NAMESPACE.svc.CLUSTERDOMAIN
-  namespace: NAMESPACE
-spec:
-  routes:
-  - name: POST /io.linkerd.proxy.destination.Destination/Get
-    condition:
-      method: POST
-      pathRegex: /io\.linkerd\.proxy\.destination\.Destination/Get
-  - name: POST /io.linkerd.proxy.destination.Destination/GetProfile
-    condition:
-      method: POST
-      pathRegex: /io\.linkerd\.proxy\.destination\.Destination/GetProfile
----
-apiVersion: linkerd.io/v1alpha2
-kind: ServiceProfile
-metadata:
-  name: linkerd-prometheus.NAMESPACE.svc.CLUSTERDOMAIN
-  namespace: NAMESPACE
-spec:
-  routes:
-  - name: POST /api/v1/query
-    condition:
-      method: POST
-      pathRegex: /api/v1/query
-  - name: GET /api/v1/query_range
-    condition:
-      method: GET
-      pathRegex: /api/v1/query_range
-  - name: GET /api/v1/series
-    condition:
-      method: GET
-      pathRegex: /api/v1/series
----
-apiVersion: linkerd.io/v1alpha2
-kind: ServiceProfile
-metadata:
-  name: linkerd-grafana.NAMESPACE.svc.CLUSTERDOMAIN
-  namespace: NAMESPACE
-spec:
-  routes:
-  - name: GET /api/annotations
-    condition:
-      method: GET
-      pathRegex: /api/annotations
-  - name: GET /api/dashboards/tags
-    condition:
-      method: GET
-      pathRegex: /api/dashboards/tags
-  - name: GET /api/dashboards/uid/{uid}
-    condition:
-      method: GET
-      pathRegex: /api/dashboards/uid/.*
-  - name: GET /api/dashboard/{dashboard}
-    condition:
-      method: GET
-      pathRegex: /api/dashboard/.*
-  - name: GET /api/datasources/proxy/1/api/v1/series
-    condition:
-      method: GET
-      pathRegex: /api/datasources/proxy/1/api/v1/series
-  - name: GET /api/datasources/proxy/1/api/v1/query_range
-    condition:
-      method: GET
-      pathRegex: /api/datasources/proxy/1/api/v1/query_range
-  - name: GET /api/search
-    condition:
-      method: GET
-      pathRegex: /api/search
-  - name: GET /d/{uid}/{dashboard-name}
-    condition:
-      method: GET
-      pathRegex: /d/[^/]*/.*
-  - name: GET /public/build/{style}.css
-    condition:
-      method: GET
-      pathRegex: /public/build/.*\.css
-  - name: GET /public/fonts/{font}
-    condition:
-      method: GET
-      pathRegex: /public/fonts/.*
-  - name: GET /public/img/{img}
-    condition:
-      method: GET
-      pathRegex: /public/img/.*
----
diff --git a/cli/cmd/testdata/install_controlplane_tracing_output.golden b/cli/cmd/testdata/install_controlplane_tracing_output.golden
index 35a15dbef..d94b78bed 100644
--- a/cli/cmd/testdata/install_controlplane_tracing_output.golden
+++ b/cli/cmd/testdata/install_controlplane_tracing_output.golden
@@ -917,7 +917,7 @@ data:
       image:
         name: cr.l5d.io/linkerd/proxy-init
         pullPolicy: ""
-        version: v1.3.11
+        version: v1.3.12
       resources:
         cpu:
           limit: 100m
@@ -1188,7 +1188,7 @@ spec:
         - "4190,4191"
         - --outbound-ports-to-ignore
         - "443"
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
@@ -1496,7 +1496,7 @@ spec:
         - "4190,4191"
         - --outbound-ports-to-ignore
         - "443"
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
@@ -1766,7 +1766,7 @@ spec:
         - "4190,4191"
         - --outbound-ports-to-ignore
         - "443"
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
diff --git a/cli/cmd/testdata/install_custom_domain.golden b/cli/cmd/testdata/install_custom_domain.golden
index 7238a1930..d8b00964c 100644
--- a/cli/cmd/testdata/install_custom_domain.golden
+++ b/cli/cmd/testdata/install_custom_domain.golden
@@ -917,7 +917,7 @@ data:
       image:
         name: cr.l5d.io/linkerd/proxy-init
         pullPolicy: ""
-        version: v1.3.11
+        version: v1.3.12
       resources:
         cpu:
           limit: 100m
@@ -1187,7 +1187,7 @@ spec:
         - "4190,4191"
         - --outbound-ports-to-ignore
         - "443"
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
@@ -1494,7 +1494,7 @@ spec:
         - "4190,4191"
         - --outbound-ports-to-ignore
         - "443"
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
@@ -1764,7 +1764,7 @@ spec:
         - "4190,4191"
         - --outbound-ports-to-ignore
         - "443"
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
diff --git a/cli/cmd/testdata/install_custom_registry.golden b/cli/cmd/testdata/install_custom_registry.golden
index 261927267..140e98f9b 100644
--- a/cli/cmd/testdata/install_custom_registry.golden
+++ b/cli/cmd/testdata/install_custom_registry.golden
@@ -917,7 +917,7 @@ data:
       image:
         name: my.custom.registry/linkerd-io/proxy-init
         pullPolicy: ""
-        version: v1.3.11
+        version: v1.3.12
       resources:
         cpu:
           limit: 100m
@@ -1187,7 +1187,7 @@ spec:
         - "4190,4191"
         - --outbound-ports-to-ignore
         - "443"
-        image: my.custom.registry/linkerd-io/proxy-init:v1.3.11
+        image: my.custom.registry/linkerd-io/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
@@ -1494,7 +1494,7 @@ spec:
         - "4190,4191"
         - --outbound-ports-to-ignore
         - "443"
-        image: my.custom.registry/linkerd-io/proxy-init:v1.3.11
+        image: my.custom.registry/linkerd-io/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
@@ -1764,7 +1764,7 @@ spec:
         - "4190,4191"
         - --outbound-ports-to-ignore
         - "443"
-        image: my.custom.registry/linkerd-io/proxy-init:v1.3.11
+        image: my.custom.registry/linkerd-io/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
diff --git a/cli/cmd/testdata/install_default.golden b/cli/cmd/testdata/install_default.golden
index 114965312..337a8657d 100644
--- a/cli/cmd/testdata/install_default.golden
+++ b/cli/cmd/testdata/install_default.golden
@@ -917,7 +917,7 @@ data:
       image:
         name: cr.l5d.io/linkerd/proxy-init
         pullPolicy: ""
-        version: v1.3.11
+        version: v1.3.12
       resources:
         cpu:
           limit: 100m
@@ -1187,7 +1187,7 @@ spec:
         - "4190,4191"
         - --outbound-ports-to-ignore
         - "443"
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
@@ -1494,7 +1494,7 @@ spec:
         - "4190,4191"
         - --outbound-ports-to-ignore
         - "443"
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
@@ -1764,7 +1764,7 @@ spec:
         - "4190,4191"
         - --outbound-ports-to-ignore
         - "443"
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
diff --git a/cli/cmd/testdata/install_default_override_dst_get_nets.golden b/cli/cmd/testdata/install_default_override_dst_get_nets.golden
index 11d923efa..3ddf83b43 100644
--- a/cli/cmd/testdata/install_default_override_dst_get_nets.golden
+++ b/cli/cmd/testdata/install_default_override_dst_get_nets.golden
@@ -917,7 +917,7 @@ data:
       image:
         name: cr.l5d.io/linkerd/proxy-init
         pullPolicy: ""
-        version: v1.3.11
+        version: v1.3.12
       resources:
         cpu:
           limit: 100m
@@ -1187,7 +1187,7 @@ spec:
         - "4190,4191"
         - --outbound-ports-to-ignore
         - "443"
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
@@ -1494,7 +1494,7 @@ spec:
         - "4190,4191"
         - --outbound-ports-to-ignore
         - "443"
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
@@ -1764,7 +1764,7 @@ spec:
         - "4190,4191"
         - --outbound-ports-to-ignore
         - "443"
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
diff --git a/cli/cmd/testdata/install_ha_output.golden b/cli/cmd/testdata/install_ha_output.golden
index ddcf7f364..629d46b34 100644
--- a/cli/cmd/testdata/install_ha_output.golden
+++ b/cli/cmd/testdata/install_ha_output.golden
@@ -935,7 +935,7 @@ data:
       image:
         name: cr.l5d.io/linkerd/proxy-init
         pullPolicy: ""
-        version: v1.3.11
+        version: v1.3.12
       resources:
         cpu:
           limit: 100m
@@ -1261,7 +1261,7 @@ spec:
         - "4190,4191"
         - --outbound-ports-to-ignore
         - "443"
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
@@ -1618,7 +1618,7 @@ spec:
         - "4190,4191"
         - --outbound-ports-to-ignore
         - "443"
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
@@ -1928,7 +1928,7 @@ spec:
         - "4190,4191"
         - --outbound-ports-to-ignore
         - "443"
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
diff --git a/cli/cmd/testdata/install_ha_with_overrides_output.golden b/cli/cmd/testdata/install_ha_with_overrides_output.golden
index 2cdc83002..fcd4d70d7 100644
--- a/cli/cmd/testdata/install_ha_with_overrides_output.golden
+++ b/cli/cmd/testdata/install_ha_with_overrides_output.golden
@@ -935,7 +935,7 @@ data:
       image:
         name: cr.l5d.io/linkerd/proxy-init
         pullPolicy: ""
-        version: v1.3.11
+        version: v1.3.12
       resources:
         cpu:
           limit: 100m
@@ -1261,7 +1261,7 @@ spec:
         - "4190,4191"
         - --outbound-ports-to-ignore
         - "443"
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
@@ -1618,7 +1618,7 @@ spec:
         - "4190,4191"
         - --outbound-ports-to-ignore
         - "443"
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
@@ -1928,7 +1928,7 @@ spec:
         - "4190,4191"
         - --outbound-ports-to-ignore
         - "443"
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
diff --git a/cli/cmd/testdata/install_heartbeat_disabled_output.golden b/cli/cmd/testdata/install_heartbeat_disabled_output.golden
index 0a5b50069..6fa255e47 100644
--- a/cli/cmd/testdata/install_heartbeat_disabled_output.golden
+++ b/cli/cmd/testdata/install_heartbeat_disabled_output.golden
@@ -845,7 +845,7 @@ data:
       image:
         name: cr.l5d.io/linkerd/proxy-init
         pullPolicy: ""
-        version: v1.3.11
+        version: v1.3.12
       resources:
         cpu:
           limit: 100m
@@ -1115,7 +1115,7 @@ spec:
         - "4190,4191"
         - --outbound-ports-to-ignore
         - "443"
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
@@ -1422,7 +1422,7 @@ spec:
         - "4190,4191"
         - --outbound-ports-to-ignore
         - "443"
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
@@ -1643,7 +1643,7 @@ spec:
         - "4190,4191"
         - --outbound-ports-to-ignore
         - "443"
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
diff --git a/cli/cmd/testdata/install_no_init_container.golden b/cli/cmd/testdata/install_no_init_container.golden
index 8d1dbd75f..cf6fe27b6 100644
--- a/cli/cmd/testdata/install_no_init_container.golden
+++ b/cli/cmd/testdata/install_no_init_container.golden
@@ -914,7 +914,7 @@ data:
       image:
         name: cr.l5d.io/linkerd/proxy-init
         pullPolicy: ""
-        version: v1.3.11
+        version: v1.3.12
       resources:
         cpu:
           limit: 100m
diff --git a/cli/cmd/testdata/install_proxy_ignores.golden b/cli/cmd/testdata/install_proxy_ignores.golden
index 9436150e5..5026b92c9 100644
--- a/cli/cmd/testdata/install_proxy_ignores.golden
+++ b/cli/cmd/testdata/install_proxy_ignores.golden
@@ -917,7 +917,7 @@ data:
       image:
         name: cr.l5d.io/linkerd/proxy-init
         pullPolicy: ""
-        version: v1.3.11
+        version: v1.3.12
       resources:
         cpu:
           limit: 100m
@@ -1187,7 +1187,7 @@ spec:
         - "4190,4191,22,8100-8102"
         - --outbound-ports-to-ignore
         - "5432,443"
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
@@ -1494,7 +1494,7 @@ spec:
         - "4190,4191,22,8100-8102"
         - --outbound-ports-to-ignore
         - "5432,443"
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
@@ -1764,7 +1764,7 @@ spec:
         - "4190,4191,22,8100-8102"
         - --outbound-ports-to-ignore
         - "5432,443"
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
diff --git a/cli/cmd/testdata/install_values_file.golden b/cli/cmd/testdata/install_values_file.golden
index c48d1979a..a9c17916d 100644
--- a/cli/cmd/testdata/install_values_file.golden
+++ b/cli/cmd/testdata/install_values_file.golden
@@ -903,7 +903,7 @@ data:
       image:
         name: cr.l5d.io/linkerd/proxy-init
         pullPolicy: ""
-        version: v1.3.11
+        version: v1.3.12
       resources:
         cpu:
           limit: 100m
@@ -1173,7 +1173,7 @@ spec:
         - "4190,4191"
         - --outbound-ports-to-ignore
         - "443"
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
@@ -1480,7 +1480,7 @@ spec:
         - "4190,4191"
         - --outbound-ports-to-ignore
         - "443"
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
@@ -1750,7 +1750,7 @@ spec:
         - "4190,4191"
         - --outbound-ports-to-ignore
         - "443"
-        image: cr.l5d.io/linkerd/proxy-init:v1.3.11
+        image: cr.l5d.io/linkerd/proxy-init:v1.3.12
         imagePullPolicy: IfNotPresent
         name: linkerd-init
         resources:
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 587be2435..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) {
@@ -2055,7 +2116,7 @@ data:
   global: |
     {"linkerdNamespace":"linkerd","cniEnabled":false,"version":"install-control-plane-version","identityContext":{"trustDomain":"cluster.local","trustAnchorsPem":"fake-trust-anchors-pem","issuanceLifetime":"86400s","clockSkewAllowance":"20s"}}
   proxy: |
-    {"proxyImage":{"imageName":"cr.l5d.io/linkerd/proxy","pullPolicy":"IfNotPresent"},"proxyInitImage":{"imageName":"cr.l5d.io/linkerd/proxy-init","pullPolicy":"IfNotPresent"},"controlPort":{"port":4190},"ignoreInboundPorts":[],"ignoreOutboundPorts":[],"inboundPort":{"port":4143},"adminPort":{"port":4191},"outboundPort":{"port":4140},"resource":{"requestCpu":"","requestMemory":"","limitCpu":"","limitMemory":""},"proxyUid":"2102","logLevel":{"level":"warn,linkerd=info"},"disableExternalProfiles":true,"proxyVersion":"install-proxy-version","proxy_init_image_version":"v1.3.11","debugImage":{"imageName":"cr.l5d.io/linkerd/debug","pullPolicy":"IfNotPresent"},"debugImageVersion":"install-debug-version"}
+    {"proxyImage":{"imageName":"cr.l5d.io/linkerd/proxy","pullPolicy":"IfNotPresent"},"proxyInitImage":{"imageName":"cr.l5d.io/linkerd/proxy-init","pullPolicy":"IfNotPresent"},"controlPort":{"port":4190},"ignoreInboundPorts":[],"ignoreOutboundPorts":[],"inboundPort":{"port":4143},"adminPort":{"port":4191},"outboundPort":{"port":4140},"resource":{"requestCpu":"","requestMemory":"","limitCpu":"","limitMemory":""},"proxyUid":"2102","logLevel":{"level":"warn,linkerd=info"},"disableExternalProfiles":true,"proxyVersion":"install-proxy-version","proxy_init_image_version":"v1.3.12","debugImage":{"imageName":"cr.l5d.io/linkerd/debug","pullPolicy":"IfNotPresent"},"debugImageVersion":"install-debug-version"}
   install: |
     {"cliVersion":"dev-undefined","flags":[]}`,
 			},
@@ -2101,7 +2162,7 @@ data:
 					},
 					DisableExternalProfiles: true,
 					ProxyVersion:            "install-proxy-version",
-					ProxyInitImageVersion:   "v1.3.11",
+					ProxyInitImageVersion:   "v1.3.12",
 					DebugImage: &configPb.Image{
 						ImageName:  "cr.l5d.io/linkerd/debug",
 						PullPolicy: "IfNotPresent",
@@ -2193,7 +2254,7 @@ data:
   global: |
     {"linkerdNamespace":"linkerd","cniEnabled":false,"version":"install-control-plane-version","identityContext":{"trustDomain":"cluster.local","trustAnchorsPem":"fake-trust-anchors-pem","issuanceLifetime":"86400s","clockSkewAllowance":"20s"}}
   proxy: |
-    {"proxyImage":{"imageName":"cr.l5d.io/linkerd/proxy","pullPolicy":"IfNotPresent"},"proxyInitImage":{"imageName":"cr.l5d.io/linkerd/proxy-init","pullPolicy":"IfNotPresent"},"controlPort":{"port":4190},"ignoreInboundPorts":[],"ignoreOutboundPorts":[],"inboundPort":{"port":4143},"adminPort":{"port":4191},"outboundPort":{"port":4140},"resource":{"requestCpu":"","requestMemory":"","limitCpu":"","limitMemory":""},"proxyUid":"2102","logLevel":{"level":"warn,linkerd=info"},"disableExternalProfiles":true,"proxyVersion":"install-proxy-version","proxy_init_image_version":"v1.3.11","debugImage":{"imageName":"cr.l5d.io/linkerd/debug","pullPolicy":"IfNotPresent"},"debugImageVersion":"install-debug-version"}
+    {"proxyImage":{"imageName":"cr.l5d.io/linkerd/proxy","pullPolicy":"IfNotPresent"},"proxyInitImage":{"imageName":"cr.l5d.io/linkerd/proxy-init","pullPolicy":"IfNotPresent"},"controlPort":{"port":4190},"ignoreInboundPorts":[],"ignoreOutboundPorts":[],"inboundPort":{"port":4143},"adminPort":{"port":4191},"outboundPort":{"port":4140},"resource":{"requestCpu":"","requestMemory":"","limitCpu":"","limitMemory":""},"proxyUid":"2102","logLevel":{"level":"warn,linkerd=info"},"disableExternalProfiles":true,"proxyVersion":"install-proxy-version","proxy_init_image_version":"v1.3.12","debugImage":{"imageName":"cr.l5d.io/linkerd/debug","pullPolicy":"IfNotPresent"},"debugImageVersion":"install-debug-version"}
   install: |
     {"cliVersion":"dev-undefined","flags":[]}
   values: |
@@ -2355,7 +2416,7 @@ data:
   global: |
     {"linkerdNamespace":"linkerd","cniEnabled":false,"version":"install-control-plane-version","identityContext":{"trustDomain":"cluster.local","trustAnchorsPem":"fake-trust-anchors-pem","issuanceLifetime":"86400s","clockSkewAllowance":"20s"}}
   proxy: |
-    {"proxyImage":{"imageName":"cr.l5d.io/linkerd/proxy","pullPolicy":"IfNotPresent"},"proxyInitImage":{"imageName":"cr.l5d.io/linkerd/proxy-init","pullPolicy":"IfNotPresent"},"controlPort":{"port":4190},"ignoreInboundPorts":[],"ignoreOutboundPorts":[],"inboundPort":{"port":4143},"adminPort":{"port":4191},"outboundPort":{"port":4140},"resource":{"requestCpu":"","requestMemory":"","limitCpu":"","limitMemory":""},"proxyUid":"2102","logLevel":{"level":"warn,linkerd=info"},"disableExternalProfiles":true,"proxyVersion":"install-proxy-version","proxy_init_image_version":"v1.3.11","debugImage":{"imageName":"cr.l5d.io/linkerd/debug","pullPolicy":"IfNotPresent"},"debugImageVersion":"install-debug-version"}
+    {"proxyImage":{"imageName":"cr.l5d.io/linkerd/proxy","pullPolicy":"IfNotPresent"},"proxyInitImage":{"imageName":"cr.l5d.io/linkerd/proxy-init","pullPolicy":"IfNotPresent"},"controlPort":{"port":4190},"ignoreInboundPorts":[],"ignoreOutboundPorts":[],"inboundPort":{"port":4143},"adminPort":{"port":4191},"outboundPort":{"port":4140},"resource":{"requestCpu":"","requestMemory":"","limitCpu":"","limitMemory":""},"proxyUid":"2102","logLevel":{"level":"warn,linkerd=info"},"disableExternalProfiles":true,"proxyVersion":"install-proxy-version","proxy_init_image_version":"v1.3.12","debugImage":{"imageName":"cr.l5d.io/linkerd/debug","pullPolicy":"IfNotPresent"},"debugImageVersion":"install-debug-version"}
   install: |
     {"cliVersion":"dev-undefined","flags":[]}
   values: |
diff --git a/test/integration/install_test.go b/test/integration/install_test.go
index 29904f84d..924dfce02 100644
--- a/test/integration/install_test.go
+++ b/test/integration/install_test.go
@@ -234,7 +234,7 @@ func TestInstallCNIPlugin(t *testing.T) {
 	// perform a linkerd check with --linkerd-cni-enabled
 	timeout := time.Minute
 	err = TestHelper.RetryFor(timeout, func() error {
-		out, err = TestHelper.LinkerdRun("check", "--pre", "--linkerd-cni-enabled", "--wait=0")
+		out, err = TestHelper.LinkerdRun("check", "--pre", "--linkerd-cni-enabled", "--wait=60m")
 		if err != nil {
 			return err
 		}
@@ -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)
@@ -861,7 +861,7 @@ func testCheckCommand(t *testing.T, stage, expectedVersion, namespace, cliVersio
 	var golden string
 	proxyStage := "proxy"
 	if stage == proxyStage {
-		cmd = []string{"check", "--proxy", "--expected-version", expectedVersion, "--namespace", namespace, "--wait=0"}
+		cmd = []string{"check", "--proxy", "--expected-version", expectedVersion, "--namespace", namespace, "--wait=60m"}
 		// if TestHelper.GetMulticlusterHelmReleaseName() != "" || TestHelper.Multicluster() {
 		// golden = "check.multicluster.proxy.golden"
 		// } else if TestHelper.CNI() {
@@ -871,10 +871,10 @@ func testCheckCommand(t *testing.T, stage, expectedVersion, namespace, cliVersio
 			golden = "check.proxy.golden"
 		}
 	} else if stage == "config" {
-		cmd = []string{"check", "config", "--expected-version", expectedVersion, "--wait=0"}
+		cmd = []string{"check", "config", "--expected-version", expectedVersion, "--wait=60m"}
 		golden = "check.config.golden"
 	} else {
-		cmd = []string{"check", "--expected-version", expectedVersion, "--wait=0"}
+		cmd = []string{"check", "--expected-version", expectedVersion, "--wait=60m"}
 		// if TestHelper.GetMulticlusterHelmReleaseName() != "" || TestHelper.Multicluster() {
 		// golden = "check.multicluster.golden"
 		// } else if TestHelper.CNI() {
@@ -970,7 +970,7 @@ func TestCheckPostInstall(t *testing.T) {
 }
 
 func TestCheckViz(t *testing.T) {
-	cmd := []string{"viz", "check", "--wait=0"}
+	cmd := []string{"viz", "check", "--wait=60m"}
 	golden := "check.viz.golden"
 	if TestHelper.ExternalPrometheus() {
 		golden = "check.viz.external-prometheus.golden"
@@ -1025,21 +1025,6 @@ func TestUpgradeTestAppWorksAfterUpgrade(t *testing.T) {
 	}
 }
 
-func TestInstallSP(t *testing.T) {
-	cmd := []string{"diagnostics", "install-sp"}
-
-	out, err := TestHelper.LinkerdRun(cmd...)
-	if err != nil {
-		testutil.AnnotatedFatal(t, "'linkerd install-sp' command failed", err)
-	}
-
-	out, err = TestHelper.KubectlApply(out, TestHelper.GetLinkerdNamespace())
-	if err != nil {
-		testutil.AnnotatedFatalf(t, "'kubectl apply' command failed",
-			"'kubectl apply' command failed\n%s", out)
-	}
-}
-
 func TestDashboard(t *testing.T) {
 	dashboardPort := 52237
 	dashboardURL := fmt.Sprintf("http://localhost:%d", dashboardPort)
@@ -1213,7 +1198,7 @@ func TestRestarts(t *testing.T) {
 
 func TestCheckMulticluster(t *testing.T) {
 	if TestHelper.GetMulticlusterHelmReleaseName() != "" || TestHelper.Multicluster() {
-		cmd := []string{"multicluster", "check", "--wait=0"}
+		cmd := []string{"multicluster", "check", "--wait=60m"}
 		golden := "check.multicluster.golden"
 		timeout := time.Minute
 		err := TestHelper.RetryFor(timeout, func() error {
diff --git a/test/integration/routes/routes_test.go b/test/integration/routes/routes_test.go
index 167991540..6a03d4198 100644
--- a/test/integration/routes/routes_test.go
+++ b/test/integration/routes/routes_test.go
@@ -20,6 +20,11 @@ func TestMain(m *testing.M) {
 	os.Exit(m.Run())
 }
 
+type testCase struct {
+	s string
+	c int
+}
+
 //////////////////////
 /// TEST EXECUTION ///
 //////////////////////
@@ -35,16 +40,10 @@ func TestRoutes(t *testing.T) {
 		testutil.AnnotatedFatal(t, "'linkerd routes' command failed", err)
 	}
 
-	routeStrings := []struct {
-		s string
-		c int
-	}{
+	routeStrings := []testCase{
 		{"linkerd-destination", 1},
-		{"linkerd-dst", 6},
-		{"linkerd-dst-headless", 3},
 		{"linkerd-identity", 3},
-		{"linkerd-identity-headless", 1},
-		{"POST /io.linkerd.proxy.destination.Destination/Get", 4},
+		{"linkerd-proxy-injector", 2},
 	}
 
 	for _, r := range routeStrings {
@@ -55,6 +54,35 @@ func TestRoutes(t *testing.T) {
 		}
 	}
 
+	// viz routes
+	cmd = []string{"viz", "routes", "--namespace", TestHelper.GetVizNamespace(), "deploy"}
+	out, err = TestHelper.LinkerdRun(cmd...)
+	if err != nil {
+		testutil.AnnotatedFatal(t, "'linkerd routes' command failed", err)
+	}
+
+	vizRouteStrings := []testCase{
+		{"grafana", 13},
+		{"metrics-api", 9},
+		{"tap", 4},
+		{"tap-injector", 2},
+		{"web", 2},
+	}
+
+	if !TestHelper.ExternalPrometheus() {
+		vizRouteStrings = append(vizRouteStrings, testCase{
+			"prometheus",
+			5,
+		})
+	}
+	for _, r := range vizRouteStrings {
+		count := strings.Count(out, r.s)
+		if count != r.c {
+			testutil.AnnotatedFatalf(t, fmt.Sprintf("expected %d occurrences of \"%s\", got %d", r.c, r.s, count),
+				"expected %d occurrences of \"%s\", got %d\n%s", r.c, r.s, count, out)
+		}
+	}
+
 	// smoke test / bb routes
 	prefixedNs := TestHelper.GetTestNamespace("smoke-test")
 	cmd = []string{"viz", "routes", "--namespace", prefixedNs, "deploy"}
diff --git a/test/integration/uninstall/uninstall_test.go b/test/integration/uninstall/uninstall_test.go
index f90f1fead..02489945d 100644
--- a/test/integration/uninstall/uninstall_test.go
+++ b/test/integration/uninstall/uninstall_test.go
@@ -42,7 +42,7 @@ func TestInstall(t *testing.T) {
 	var (
 		vizCmd  = []string{"viz", "install"}
 		vizArgs = []string{
-			"--set", fmt.Sprintf("namespace=%s", TestHelper.GetVizNamespace())}
+			"--set", fmt.Sprintf("namespace=%s", TestHelper.GetVizNamespace()), "--wait", "60m"}
 	)
 
 	// Install Linkerd Viz Extension
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)
 	}
 }
diff --git a/testutil/kubernetes_helper.go b/testutil/kubernetes_helper.go
index 81fe57aa2..8953c7b04 100644
--- a/testutil/kubernetes_helper.go
+++ b/testutil/kubernetes_helper.go
@@ -182,7 +182,7 @@ func (h *KubernetesHelper) GetResources(ctx context.Context, containerName, depl
 func (h *KubernetesHelper) CheckPods(ctx context.Context, namespace string, deploymentName string, replicas int) error {
 	var checkedPods []corev1.Pod
 
-	err := h.retryFor(6*time.Minute, func() error {
+	err := h.retryFor(60*time.Minute, func() error {
 		checkedPods = []corev1.Pod{}
 		pods, err := h.GetPodsForDeployment(ctx, namespace, deploymentName)
 		if err != nil {
@@ -325,7 +325,7 @@ func (h *KubernetesHelper) URLFor(ctx context.Context, namespace, deployName str
 func (h *KubernetesHelper) WaitRollout(t *testing.T) {
 	for deploy, deploySpec := range LinkerdDeployReplicasEdge {
 		if deploySpec.Namespace == "linkerd" {
-			o, err := h.Kubectl("", "--namespace=linkerd", "rollout", "status", "--timeout=120s", "deploy/"+deploy)
+			o, err := h.Kubectl("", "--namespace=linkerd", "rollout", "status", "--timeout=60m", "deploy/"+deploy)
 			if err != nil {
 				AnnotatedFatalf(t,
 					fmt.Sprintf("failed to wait rollout of deploy/%s", deploy),
diff --git a/testutil/test_helper.go b/testutil/test_helper.go
index 7b690d853..899be08cb 100644
--- a/testutil/test_helper.go
+++ b/testutil/test_helper.go
@@ -477,6 +477,8 @@ func (h *TestHelper) HelmUpgrade(chart string, arg ...string) (string, string, e
 		h.helm.releaseName,
 		"--kube-context", h.k8sContext,
 		"--set", "namespace=" + h.namespace,
+		"--timeout", "60m",
+		"--wait",
 		chart,
 	}, arg...)
 	return combinedOutput("", h.helm.path, withParams...)
@@ -490,6 +492,8 @@ func (h *TestHelper) HelmInstall(chart string, arg ...string) (string, string, e
 		chart,
 		"--kube-context", h.k8sContext,
 		"--set", "namespace=" + h.namespace,
+		"--timeout", "60m",
+		"--wait",
 	}, arg...)
 	return combinedOutput("", h.helm.path, withParams...)
 }
diff --git a/cli/cmd/testdata/install-sp_default.golden b/viz/charts/linkerd-viz/templates/service-profiles.yaml
similarity index 65%
rename from cli/cmd/testdata/install-sp_default.golden
rename to viz/charts/linkerd-viz/templates/service-profiles.yaml
index d44585000..868d2e0b0 100644
--- a/cli/cmd/testdata/install-sp_default.golden
+++ b/viz/charts/linkerd-viz/templates/service-profiles.yaml
@@ -1,8 +1,9 @@
+---
 apiVersion: linkerd.io/v1alpha2
 kind: ServiceProfile
 metadata:
-  name: linkerd-controller-api.linkerd.svc.cluster.local
-  namespace: linkerd
+  name: metrics-api.{{.Values.namespace}}.svc.{{.Values.clusterDomain}}
+  namespace: {{.Values.namespace}}
 spec:
   routes:
   - name: POST /api/v1/StatSummary
@@ -21,52 +22,25 @@ spec:
     condition:
       method: POST
       pathRegex: /api/v1/ListServices
-  - name: POST /api/v1/Version
-    condition:
-      method: POST
-      pathRegex: /api/v1/Version
   - name: POST /api/v1/SelfCheck
     condition:
       method: POST
       pathRegex: /api/v1/SelfCheck
----
-apiVersion: linkerd.io/v1alpha2
-kind: ServiceProfile
-metadata:
-  name: linkerd-dst.linkerd.svc.cluster.local
-  namespace: linkerd
-spec:
-  routes:
-  - name: POST /io.linkerd.proxy.destination.Destination/Get
-    condition:
-      method: POST
-      pathRegex: /io\.linkerd\.proxy\.destination\.Destination/Get
-  - name: POST /io.linkerd.proxy.destination.Destination/GetProfile
-    condition:
-      method: POST
-      pathRegex: /io\.linkerd\.proxy\.destination\.Destination/GetProfile
----
-apiVersion: linkerd.io/v1alpha2
-kind: ServiceProfile
-metadata:
-  name: linkerd-dst-headless.linkerd.svc.cluster.local
-  namespace: linkerd
-spec:
-  routes:
-  - name: POST /io.linkerd.proxy.destination.Destination/Get
+  - name: POST /api/v1/Gateways
     condition:
       method: POST
-      pathRegex: /io\.linkerd\.proxy\.destination\.Destination/Get
-  - name: POST /io.linkerd.proxy.destination.Destination/GetProfile
+      pathRegex: /api/v1/Gateways
+  - name: POST /api/v1/Edges
     condition:
       method: POST
-      pathRegex: /io\.linkerd\.proxy\.destination\.Destination/GetProfile
+      pathRegex: /api/v1/Edges
+{{ if .Values.prometheus.enabled -}}
 ---
 apiVersion: linkerd.io/v1alpha2
 kind: ServiceProfile
 metadata:
-  name: linkerd-prometheus.linkerd.svc.cluster.local
-  namespace: linkerd
+  name: prometheus.{{.Values.namespace}}.svc.{{.Values.clusterDomain}}
+  namespace: {{.Values.namespace}}
 spec:
   routes:
   - name: POST /api/v1/query
@@ -81,12 +55,14 @@ spec:
     condition:
       method: GET
       pathRegex: /api/v1/series
+{{ end -}}
+{{ if .Values.grafana.enabled -}}
 ---
 apiVersion: linkerd.io/v1alpha2
 kind: ServiceProfile
 metadata:
-  name: linkerd-grafana.linkerd.svc.cluster.local
-  namespace: linkerd
+  name: grafana.{{.Values.namespace}}.svc.{{.Values.clusterDomain}}
+  namespace: {{.Values.namespace}}
 spec:
   routes:
   - name: GET /api/annotations
@@ -133,4 +109,4 @@ spec:
     condition:
       method: GET
       pathRegex: /public/img/.*
----
+{{ end -}}
diff --git a/viz/cmd/testdata/install_default.golden b/viz/cmd/testdata/install_default.golden
index dc5ade487..9931e13a3 100644
--- a/viz/cmd/testdata/install_default.golden
+++ b/viz/cmd/testdata/install_default.golden
@@ -1250,3 +1250,111 @@ spec:
         securityContext:
           runAsUser: 2103
       serviceAccountName: web
+---
+apiVersion: linkerd.io/v1alpha2
+kind: ServiceProfile
+metadata:
+  name: metrics-api.linkerd-viz.svc.cluster.local
+  namespace: linkerd-viz
+spec:
+  routes:
+  - name: POST /api/v1/StatSummary
+    condition:
+      method: POST
+      pathRegex: /api/v1/StatSummary
+  - name: POST /api/v1/TopRoutes
+    condition:
+      method: POST
+      pathRegex: /api/v1/TopRoutes
+  - name: POST /api/v1/ListPods
+    condition:
+      method: POST
+      pathRegex: /api/v1/ListPods
+  - name: POST /api/v1/ListServices
+    condition:
+      method: POST
+      pathRegex: /api/v1/ListServices
+  - name: POST /api/v1/SelfCheck
+    condition:
+      method: POST
+      pathRegex: /api/v1/SelfCheck
+  - name: POST /api/v1/Gateways
+    condition:
+      method: POST
+      pathRegex: /api/v1/Gateways
+  - name: POST /api/v1/Edges
+    condition:
+      method: POST
+      pathRegex: /api/v1/Edges
+---
+apiVersion: linkerd.io/v1alpha2
+kind: ServiceProfile
+metadata:
+  name: prometheus.linkerd-viz.svc.cluster.local
+  namespace: linkerd-viz
+spec:
+  routes:
+  - name: POST /api/v1/query
+    condition:
+      method: POST
+      pathRegex: /api/v1/query
+  - name: GET /api/v1/query_range
+    condition:
+      method: GET
+      pathRegex: /api/v1/query_range
+  - name: GET /api/v1/series
+    condition:
+      method: GET
+      pathRegex: /api/v1/series
+---
+apiVersion: linkerd.io/v1alpha2
+kind: ServiceProfile
+metadata:
+  name: grafana.linkerd-viz.svc.cluster.local
+  namespace: linkerd-viz
+spec:
+  routes:
+  - name: GET /api/annotations
+    condition:
+      method: GET
+      pathRegex: /api/annotations
+  - name: GET /api/dashboards/tags
+    condition:
+      method: GET
+      pathRegex: /api/dashboards/tags
+  - name: GET /api/dashboards/uid/{uid}
+    condition:
+      method: GET
+      pathRegex: /api/dashboards/uid/.*
+  - name: GET /api/dashboard/{dashboard}
+    condition:
+      method: GET
+      pathRegex: /api/dashboard/.*
+  - name: GET /api/datasources/proxy/1/api/v1/series
+    condition:
+      method: GET
+      pathRegex: /api/datasources/proxy/1/api/v1/series
+  - name: GET /api/datasources/proxy/1/api/v1/query_range
+    condition:
+      method: GET
+      pathRegex: /api/datasources/proxy/1/api/v1/query_range
+  - name: GET /api/search
+    condition:
+      method: GET
+      pathRegex: /api/search
+  - name: GET /d/{uid}/{dashboard-name}
+    condition:
+      method: GET
+      pathRegex: /d/[^/]*/.*
+  - name: GET /public/build/{style}.css
+    condition:
+      method: GET
+      pathRegex: /public/build/.*\.css
+  - name: GET /public/fonts/{font}
+    condition:
+      method: GET
+      pathRegex: /public/fonts/.*
+  - name: GET /public/img/{img}
+    condition:
+      method: GET
+      pathRegex: /public/img/.*
diff --git a/viz/cmd/testdata/install_default_overrides.golden b/viz/cmd/testdata/install_default_overrides.golden
index 4686d572e..6d78faa1e 100644
--- a/viz/cmd/testdata/install_default_overrides.golden
+++ b/viz/cmd/testdata/install_default_overrides.golden
@@ -1250,3 +1250,111 @@ spec:
         securityContext:
           runAsUser: 1234
       serviceAccountName: web
+---
+apiVersion: linkerd.io/v1alpha2
+kind: ServiceProfile
+metadata:
+  name: metrics-api.linkerd-viz.svc.cluster.local
+  namespace: linkerd-viz
+spec:
+  routes:
+  - name: POST /api/v1/StatSummary
+    condition:
+      method: POST
+      pathRegex: /api/v1/StatSummary
+  - name: POST /api/v1/TopRoutes
+    condition:
+      method: POST
+      pathRegex: /api/v1/TopRoutes
+  - name: POST /api/v1/ListPods
+    condition:
+      method: POST
+      pathRegex: /api/v1/ListPods
+  - name: POST /api/v1/ListServices
+    condition:
+      method: POST
+      pathRegex: /api/v1/ListServices
+  - name: POST /api/v1/SelfCheck
+    condition:
+      method: POST
+      pathRegex: /api/v1/SelfCheck
+  - name: POST /api/v1/Gateways
+    condition:
+      method: POST
+      pathRegex: /api/v1/Gateways
+  - name: POST /api/v1/Edges
+    condition:
+      method: POST
+      pathRegex: /api/v1/Edges
+---
+apiVersion: linkerd.io/v1alpha2
+kind: ServiceProfile
+metadata:
+  name: prometheus.linkerd-viz.svc.cluster.local
+  namespace: linkerd-viz
+spec:
+  routes:
+  - name: POST /api/v1/query
+    condition:
+      method: POST
+      pathRegex: /api/v1/query
+  - name: GET /api/v1/query_range
+    condition:
+      method: GET
+      pathRegex: /api/v1/query_range
+  - name: GET /api/v1/series
+    condition:
+      method: GET
+      pathRegex: /api/v1/series
+---
+apiVersion: linkerd.io/v1alpha2
+kind: ServiceProfile
+metadata:
+  name: grafana.linkerd-viz.svc.cluster.local
+  namespace: linkerd-viz
+spec:
+  routes:
+  - name: GET /api/annotations
+    condition:
+      method: GET
+      pathRegex: /api/annotations
+  - name: GET /api/dashboards/tags
+    condition:
+      method: GET
+      pathRegex: /api/dashboards/tags
+  - name: GET /api/dashboards/uid/{uid}
+    condition:
+      method: GET
+      pathRegex: /api/dashboards/uid/.*
+  - name: GET /api/dashboard/{dashboard}
+    condition:
+      method: GET
+      pathRegex: /api/dashboard/.*
+  - name: GET /api/datasources/proxy/1/api/v1/series
+    condition:
+      method: GET
+      pathRegex: /api/datasources/proxy/1/api/v1/series
+  - name: GET /api/datasources/proxy/1/api/v1/query_range
+    condition:
+      method: GET
+      pathRegex: /api/datasources/proxy/1/api/v1/query_range
+  - name: GET /api/search
+    condition:
+      method: GET
+      pathRegex: /api/search
+  - name: GET /d/{uid}/{dashboard-name}
+    condition:
+      method: GET
+      pathRegex: /d/[^/]*/.*
+  - name: GET /public/build/{style}.css
+    condition:
+      method: GET
+      pathRegex: /public/build/.*\.css
+  - name: GET /public/fonts/{font}
+    condition:
+      method: GET
+      pathRegex: /public/fonts/.*
+  - name: GET /public/img/{img}
+    condition:
+      method: GET
+      pathRegex: /public/img/.*
diff --git a/viz/cmd/testdata/install_grafana_disabled.golden b/viz/cmd/testdata/install_grafana_disabled.golden
index 632182ae9..42b0fb037 100644
--- a/viz/cmd/testdata/install_grafana_disabled.golden
+++ b/viz/cmd/testdata/install_grafana_disabled.golden
@@ -1068,3 +1068,59 @@ spec:
         securityContext:
           runAsUser: 2103
       serviceAccountName: web
+---
+apiVersion: linkerd.io/v1alpha2
+kind: ServiceProfile
+metadata:
+  name: metrics-api.linkerd-viz.svc.cluster.local
+  namespace: linkerd-viz
+spec:
+  routes:
+  - name: POST /api/v1/StatSummary
+    condition:
+      method: POST
+      pathRegex: /api/v1/StatSummary
+  - name: POST /api/v1/TopRoutes
+    condition:
+      method: POST
+      pathRegex: /api/v1/TopRoutes
+  - name: POST /api/v1/ListPods
+    condition:
+      method: POST
+      pathRegex: /api/v1/ListPods
+  - name: POST /api/v1/ListServices
+    condition:
+      method: POST
+      pathRegex: /api/v1/ListServices
+  - name: POST /api/v1/SelfCheck
+    condition:
+      method: POST
+      pathRegex: /api/v1/SelfCheck
+  - name: POST /api/v1/Gateways
+    condition:
+      method: POST
+      pathRegex: /api/v1/Gateways
+  - name: POST /api/v1/Edges
+    condition:
+      method: POST
+      pathRegex: /api/v1/Edges
+---
+apiVersion: linkerd.io/v1alpha2
+kind: ServiceProfile
+metadata:
+  name: prometheus.linkerd-viz.svc.cluster.local
+  namespace: linkerd-viz
+spec:
+  routes:
+  - name: POST /api/v1/query
+    condition:
+      method: POST
+      pathRegex: /api/v1/query
+  - name: GET /api/v1/query_range
+    condition:
+      method: GET
+      pathRegex: /api/v1/query_range
+  - name: GET /api/v1/series
+    condition:
+      method: GET
+      pathRegex: /api/v1/series
diff --git a/viz/cmd/testdata/install_prometheus_disabled.golden b/viz/cmd/testdata/install_prometheus_disabled.golden
index 986363c8e..fab13bbc8 100644
--- a/viz/cmd/testdata/install_prometheus_disabled.golden
+++ b/viz/cmd/testdata/install_prometheus_disabled.golden
@@ -960,3 +960,91 @@ spec:
         securityContext:
           runAsUser: 2103
       serviceAccountName: web
+---
+apiVersion: linkerd.io/v1alpha2
+kind: ServiceProfile
+metadata:
+  name: metrics-api.linkerd-viz.svc.cluster.local
+  namespace: linkerd-viz
+spec:
+  routes:
+  - name: POST /api/v1/StatSummary
+    condition:
+      method: POST
+      pathRegex: /api/v1/StatSummary
+  - name: POST /api/v1/TopRoutes
+    condition:
+      method: POST
+      pathRegex: /api/v1/TopRoutes
+  - name: POST /api/v1/ListPods
+    condition:
+      method: POST
+      pathRegex: /api/v1/ListPods
+  - name: POST /api/v1/ListServices
+    condition:
+      method: POST
+      pathRegex: /api/v1/ListServices
+  - name: POST /api/v1/SelfCheck
+    condition:
+      method: POST
+      pathRegex: /api/v1/SelfCheck
+  - name: POST /api/v1/Gateways
+    condition:
+      method: POST
+      pathRegex: /api/v1/Gateways
+  - name: POST /api/v1/Edges
+    condition:
+      method: POST
+      pathRegex: /api/v1/Edges
+---
+apiVersion: linkerd.io/v1alpha2
+kind: ServiceProfile
+metadata:
+  name: grafana.linkerd-viz.svc.cluster.local
+  namespace: linkerd-viz
+spec:
+  routes:
+  - name: GET /api/annotations
+    condition:
+      method: GET
+      pathRegex: /api/annotations
+  - name: GET /api/dashboards/tags
+    condition:
+      method: GET
+      pathRegex: /api/dashboards/tags
+  - name: GET /api/dashboards/uid/{uid}
+    condition:
+      method: GET
+      pathRegex: /api/dashboards/uid/.*
+  - name: GET /api/dashboard/{dashboard}
+    condition:
+      method: GET
+      pathRegex: /api/dashboard/.*
+  - name: GET /api/datasources/proxy/1/api/v1/series
+    condition:
+      method: GET
+      pathRegex: /api/datasources/proxy/1/api/v1/series
+  - name: GET /api/datasources/proxy/1/api/v1/query_range
+    condition:
+      method: GET
+      pathRegex: /api/datasources/proxy/1/api/v1/query_range
+  - name: GET /api/search
+    condition:
+      method: GET
+      pathRegex: /api/search
+  - name: GET /d/{uid}/{dashboard-name}
+    condition:
+      method: GET
+      pathRegex: /d/[^/]*/.*
+  - name: GET /public/build/{style}.css
+    condition:
+      method: GET
+      pathRegex: /public/build/.*\.css
+  - name: GET /public/fonts/{font}
+    condition:
+      method: GET
+      pathRegex: /public/fonts/.*
+  - name: GET /public/img/{img}
+    condition:
+      method: GET
+      pathRegex: /public/img/.*
diff --git a/viz/cmd/testdata/install_prometheus_loglevel_from_args.golden b/viz/cmd/testdata/install_prometheus_loglevel_from_args.golden
index e6c8d7e73..011d21981 100644
--- a/viz/cmd/testdata/install_prometheus_loglevel_from_args.golden
+++ b/viz/cmd/testdata/install_prometheus_loglevel_from_args.golden
@@ -1250,3 +1250,111 @@ spec:
         securityContext:
           runAsUser: 2103
       serviceAccountName: web
+---
+apiVersion: linkerd.io/v1alpha2
+kind: ServiceProfile
+metadata:
+  name: metrics-api.linkerd-viz.svc.cluster.local
+  namespace: linkerd-viz
+spec:
+  routes:
+  - name: POST /api/v1/StatSummary
+    condition:
+      method: POST
+      pathRegex: /api/v1/StatSummary
+  - name: POST /api/v1/TopRoutes
+    condition:
+      method: POST
+      pathRegex: /api/v1/TopRoutes
+  - name: POST /api/v1/ListPods
+    condition:
+      method: POST
+      pathRegex: /api/v1/ListPods
+  - name: POST /api/v1/ListServices
+    condition:
+      method: POST
+      pathRegex: /api/v1/ListServices
+  - name: POST /api/v1/SelfCheck
+    condition:
+      method: POST
+      pathRegex: /api/v1/SelfCheck
+  - name: POST /api/v1/Gateways
+    condition:
+      method: POST
+      pathRegex: /api/v1/Gateways
+  - name: POST /api/v1/Edges
+    condition:
+      method: POST
+      pathRegex: /api/v1/Edges
+---
+apiVersion: linkerd.io/v1alpha2
+kind: ServiceProfile
+metadata:
+  name: prometheus.linkerd-viz.svc.cluster.local
+  namespace: linkerd-viz
+spec:
+  routes:
+  - name: POST /api/v1/query
+    condition:
+      method: POST
+      pathRegex: /api/v1/query
+  - name: GET /api/v1/query_range
+    condition:
+      method: GET
+      pathRegex: /api/v1/query_range
+  - name: GET /api/v1/series
+    condition:
+      method: GET
+      pathRegex: /api/v1/series
+---
+apiVersion: linkerd.io/v1alpha2
+kind: ServiceProfile
+metadata:
+  name: grafana.linkerd-viz.svc.cluster.local
+  namespace: linkerd-viz
+spec:
+  routes:
+  - name: GET /api/annotations
+    condition:
+      method: GET
+      pathRegex: /api/annotations
+  - name: GET /api/dashboards/tags
+    condition:
+      method: GET
+      pathRegex: /api/dashboards/tags
+  - name: GET /api/dashboards/uid/{uid}
+    condition:
+      method: GET
+      pathRegex: /api/dashboards/uid/.*
+  - name: GET /api/dashboard/{dashboard}
+    condition:
+      method: GET
+      pathRegex: /api/dashboard/.*
+  - name: GET /api/datasources/proxy/1/api/v1/series
+    condition:
+      method: GET
+      pathRegex: /api/datasources/proxy/1/api/v1/series
+  - name: GET /api/datasources/proxy/1/api/v1/query_range
+    condition:
+      method: GET
+      pathRegex: /api/datasources/proxy/1/api/v1/query_range
+  - name: GET /api/search
+    condition:
+      method: GET
+      pathRegex: /api/search
+  - name: GET /d/{uid}/{dashboard-name}
+    condition:
+      method: GET
+      pathRegex: /d/[^/]*/.*
+  - name: GET /public/build/{style}.css
+    condition:
+      method: GET
+      pathRegex: /public/build/.*\.css
+  - name: GET /public/fonts/{font}
+    condition:
+      method: GET
+      pathRegex: /public/fonts/.*
+  - name: GET /public/img/{img}
+    condition:
+      method: GET
+      pathRegex: /public/img/.*
diff --git a/viz/cmd/testdata/install_proxy_resources.golden b/viz/cmd/testdata/install_proxy_resources.golden
index b3583e71f..a05273913 100644
--- a/viz/cmd/testdata/install_proxy_resources.golden
+++ b/viz/cmd/testdata/install_proxy_resources.golden
@@ -1266,3 +1266,111 @@ spec:
         securityContext:
           runAsUser: 2103
       serviceAccountName: web
+---
+apiVersion: linkerd.io/v1alpha2
+kind: ServiceProfile
+metadata:
+  name: metrics-api.linkerd-viz.svc.cluster.local
+  namespace: linkerd-viz
+spec:
+  routes:
+  - name: POST /api/v1/StatSummary
+    condition:
+      method: POST
+      pathRegex: /api/v1/StatSummary
+  - name: POST /api/v1/TopRoutes
+    condition:
+      method: POST
+      pathRegex: /api/v1/TopRoutes
+  - name: POST /api/v1/ListPods
+    condition:
+      method: POST
+      pathRegex: /api/v1/ListPods
+  - name: POST /api/v1/ListServices
+    condition:
+      method: POST
+      pathRegex: /api/v1/ListServices
+  - name: POST /api/v1/SelfCheck
+    condition:
+      method: POST
+      pathRegex: /api/v1/SelfCheck
+  - name: POST /api/v1/Gateways
+    condition:
+      method: POST
+      pathRegex: /api/v1/Gateways
+  - name: POST /api/v1/Edges
+    condition:
+      method: POST
+      pathRegex: /api/v1/Edges
+---
+apiVersion: linkerd.io/v1alpha2
+kind: ServiceProfile
+metadata:
+  name: prometheus.linkerd-viz.svc.cluster.local
+  namespace: linkerd-viz
+spec:
+  routes:
+  - name: POST /api/v1/query
+    condition:
+      method: POST
+      pathRegex: /api/v1/query
+  - name: GET /api/v1/query_range
+    condition:
+      method: GET
+      pathRegex: /api/v1/query_range
+  - name: GET /api/v1/series
+    condition:
+      method: GET
+      pathRegex: /api/v1/series
+---
+apiVersion: linkerd.io/v1alpha2
+kind: ServiceProfile
+metadata:
+  name: grafana.linkerd-viz.svc.cluster.local
+  namespace: linkerd-viz
+spec:
+  routes:
+  - name: GET /api/annotations
+    condition:
+      method: GET
+      pathRegex: /api/annotations
+  - name: GET /api/dashboards/tags
+    condition:
+      method: GET
+      pathRegex: /api/dashboards/tags
+  - name: GET /api/dashboards/uid/{uid}
+    condition:
+      method: GET
+      pathRegex: /api/dashboards/uid/.*
+  - name: GET /api/dashboard/{dashboard}
+    condition:
+      method: GET
+      pathRegex: /api/dashboard/.*
+  - name: GET /api/datasources/proxy/1/api/v1/series
+    condition:
+      method: GET
+      pathRegex: /api/datasources/proxy/1/api/v1/series
+  - name: GET /api/datasources/proxy/1/api/v1/query_range
+    condition:
+      method: GET
+      pathRegex: /api/datasources/proxy/1/api/v1/query_range
+  - name: GET /api/search
+    condition:
+      method: GET
+      pathRegex: /api/search
+  - name: GET /d/{uid}/{dashboard-name}
+    condition:
+      method: GET
+      pathRegex: /d/[^/]*/.*
+  - name: GET /public/build/{style}.css
+    condition:
+      method: GET
+      pathRegex: /public/build/.*\.css
+  - name: GET /public/fonts/{font}
+    condition:
+      method: GET
+      pathRegex: /public/fonts/.*
+  - name: GET /public/img/{img}
+    condition:
+      method: GET
+      pathRegex: /public/img/.*
diff --git a/viz/metrics-api/stat_summary_test.go b/viz/metrics-api/stat_summary_test.go
index 755e04a79..e3a4ee59a 100644
--- a/viz/metrics-api/stat_summary_test.go
+++ b/viz/metrics-api/stat_summary_test.go
@@ -1316,6 +1316,13 @@ status:
 										},
 									},
 								},
+								{
+									Table: &pb.StatTable_PodGroup_{
+										PodGroup: &pb.StatTable_PodGroup{
+											Rows: []*pb.StatTable_PodGroup_Row{},
+										},
+									},
+								},
 								{
 									Table: &pb.StatTable_PodGroup_{
 										PodGroup: &pb.StatTable_PodGroup{