Repository: linkerd/linkerd2
Pull request #4244 (2020-04-10 17:39:11)

Improve proxy version diagnostics
It can be difficult to know which versions of the proxy are running in your cluster, especially when you have pods running at multiple different proxy versions.

We add two pieces of CLI functionality to assist with this:

The `linkerd check --proxy` command will now list all data plane pods which are not up-to-date rather than just printing the first one it encounters:

```
‼ data plane is up-to-date
    Some data plane pods are not running the current version:
	* default/books-84958fff5-95j75 (git-ca760bdd)
	* default/authors-57c6dc9b47-djldq (git-ca760bdd)
	* default/traffic-85f58ccb66-vxr49 (git-ca760bdd)
	* default/release-name-smi-metrics-899c68958-5ctpz (git-ca760bdd)
	* default/webapp-6975dc796f-2ngh4 (git-ca760bdd)
	* default/webapp-6975dc796f-z4bc4 (git-ca760bdd)
	* emojivoto/voting-54ffc5787d-wj6cp (git-ca760bdd)
	* emojivoto/vote-bot-7b54d6999b-57srw (git-ca760bdd)
	* emojivoto/emoji-5cb99f85d8-5bhvm (git-ca760bdd)
	* emojivoto/web-7988674b8b-zfvvm (git-ca760bdd)
	* default/webapp-6975dc796f-d2fbc (git-ca760bdd)
	* default/curl (git-7f6bbc73)
    see https://linkerd.io/checks/#l5d-data-plane-version for hints
```

The `linkerd version` command now supports a `--proxy` flag which will list all proxy versions running in the cluster and the number of pods running each version:

```
linkerd version --proxy
Client version: dev-7b9d475f-alex
Server version: edge-20.4.1
Proxy versions:
	edge-20.4.1 (10 pods)
	git-ca760bdd (11 pods)
	git-7f6bbc73 (1 pods)
```

Signed-off-by: Alex Leong <alex@buoyant.io>



Patch:
diff --git a/.proxy-version b/.proxy-version
index e2a057197..cf15f54ef 100644
--- a/.proxy-version
+++ b/.proxy-version
@@ -1,1 +1,1 @@
-v2.91.0
+v2.92.0
diff --git a/ADOPTERS.md b/ADOPTERS.md
index 45d7b23b7..3a03cde01 100644
--- a/ADOPTERS.md
+++ b/ADOPTERS.md
@@ -23,6 +23,7 @@
 - [Studyo](https://studyo.co)
 - [Transit](https://transit.app)
 - [Vernacular.ai](https://vernacular.ai/)
+- [HomeChoice](https://www.homechoice.co.za/)
 
 If you're using Linkerd 2.x and aren't on this list, please [submit a pull
 request](https://github.com/linkerd/linkerd2/pulls)!
diff --git a/CHANGES.md b/CHANGES.md
index aba033ffb..bf186db41 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,3 +1,29 @@
+## edge-20.4.2
+
+This release brings a number of CLI fixes and Controller improvements.
+
+* CLI
+  * Fixed a bug that caused pods to crash after upgrade if
+    `--skip-outbound-ports` or `--skip-inbound-ports` were used
+  * Added `unmeshed` flag to the `stat` command, such that unmeshed resources
+    are only displayed if the user opts-in
+  * Added a `--smi-metrics` flag to `install`, to allow installation of the
+    experimental `linkerd-smi-metrics` component
+  * Fixed a bug in `linkerd stat`, causing incorrect output formatting when using
+    the `--o wide` flag
+  * Fixed a bug, causing `linkerd uninstall` to fail when attempting to delete
+    PSPs
+* Controller
+  * Improved the anti-affinity of `linkerd-smi-metrics` deployment to avoid
+    pod scheduling problems during `upgrade`
+  * Improved endpoints change detection in the `linkerd-destination` service, enabling
+    mirrored remote services to change cluster gateways
+  * Added `operationID` field to tap OpenAPI response to prevent issues during
+    upgrade from 2.6 to 2.7 
+* Proxy
+  * Added a new protocol detection timeout to prevent clients from consuming
+    resources indefinitely when not sending any data
+
 ## edge-20.4.1
 
 This release introduces some cool new functionalities, all provided by our
diff --git a/charts/linkerd2/templates/smi-metrics.yaml b/charts/linkerd2/templates/smi-metrics.yaml
index f396f29e2..f08d802da 100644
--- a/charts/linkerd2/templates/smi-metrics.yaml
+++ b/charts/linkerd2/templates/smi-metrics.yaml
@@ -49,7 +49,7 @@ spec:
     spec:
       {{- include "linkerd.node-selector" . | nindent 6 }}
       {{- if .Values.enablePodAntiAffinity -}}
-      {{- $local := dict "component" "tap" "label" .Values.global.controllerComponentLabel -}}
+      {{- $local := dict "component" "smi-metrics" "label" .Values.global.controllerComponentLabel -}}
       {{- include "linkerd.pod-affinity" $local | nindent 6 -}}
       {{- end }}
       serviceAccountName: linkerd-smi-metrics
diff --git a/cli/cmd/stat.go b/cli/cmd/stat.go
index fdefa4729..cb3ca5239 100644
--- a/cli/cmd/stat.go
+++ b/cli/cmd/stat.go
@@ -26,6 +26,7 @@ type statOptions struct {
 	fromResource  string
 	allNamespaces bool
 	labelSelector string
+	unmeshed      bool
 }
 
 type indexedResults struct {
@@ -43,6 +44,7 @@ func newStatOptions() *statOptions {
 		fromResource:    "",
 		allNamespaces:   false,
 		labelSelector:   "",
+		unmeshed:        false,
 	}
 }
 
@@ -184,6 +186,7 @@ If no resource name is specified, displays stats about all resources of the spec
 	cmd.PersistentFlags().BoolVarP(&options.allNamespaces, "all-namespaces", "A", options.allNamespaces, "If present, returns stats across all namespaces, ignoring the \"--namespace\" flag")
 	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")
 	return cmd
 }
 
@@ -277,6 +280,10 @@ func writeStatsToBuffer(rows []*pb.StatTable_PodGroup_Row, w *tabwriter.Writer,
 	}
 
 	for _, r := range rows {
+		if !options.unmeshed && r.GetMeshedPodCount() == 0 {
+			continue
+		}
+
 		name := r.Resource.Name
 		nameWithPrefix := name
 		if usePrefix {
diff --git a/cli/cmd/upgrade.go b/cli/cmd/upgrade.go
index 430af7977..d55424225 100644
--- a/cli/cmd/upgrade.go
+++ b/cli/cmd/upgrade.go
@@ -381,7 +381,17 @@ func (options *upgradeOptions) validateAndBuild(stage string, k kubernetes.Inter
 func setFlagsFromInstall(flags *pflag.FlagSet, installFlags []*pb.Install_Flag) {
 	for _, i := range installFlags {
 		if f := flags.Lookup(i.GetName()); f != nil && !f.Changed {
-			f.Value.Set(i.GetValue())
+
+			// The function recordFlags() stores the string representation of flags in the ConfigMap
+			// so a stringSlice is stored e.g. as [a,b].
+			// To avoid having f.Value.Set() interpreting that as a string we need to remove
+			// the brackets
+			value := i.GetValue()
+			if f.Value.Type() == "stringSlice" {
+				value = strings.Trim(value, "[]")
+			}
+
+			f.Value.Set(value)
 			f.Changed = true
 		}
 	}
diff --git a/cli/cmd/version.go b/cli/cmd/version.go
index 49097bb3e..5ce59587e 100644
--- a/cli/cmd/version.go
+++ b/cli/cmd/version.go
@@ -18,12 +18,16 @@ const defaultVersionString = "unavailable"
 type versionOptions struct {
 	shortVersion      bool
 	onlyClientVersion bool
+	proxy             bool
+	namespace         string
 }
 
 func newVersionOptions() *versionOptions {
 	return &versionOptions{
 		shortVersion:      false,
 		onlyClientVersion: false,
+		proxy:             false,
+		namespace:         "",
 	}
 }
 
@@ -41,6 +45,8 @@ func newCmdVersion() *cobra.Command {
 
 	cmd.PersistentFlags().BoolVar(&options.shortVersion, "short", options.shortVersion, "Print the version number(s) only, with no additional output")
 	cmd.PersistentFlags().BoolVar(&options.onlyClientVersion, "client", options.onlyClientVersion, "Print the client version only")
+	cmd.PersistentFlags().BoolVar(&options.proxy, "proxy", options.proxy, "Print data-plane versions")
+	cmd.PersistentFlags().StringVarP(&options.namespace, "namespace", "n", options.namespace, "Namespace to use for --proxy versions (default: all namespaces)")
 
 	return cmd
 }
@@ -59,10 +65,11 @@ func configureAndRunVersion(
 
 	if !options.onlyClientVersion {
 		serverVersion := defaultVersionString
-		client, err := mkClient()
-		if err == nil {
+		client, clientErr := mkClient()
+		if clientErr == nil {
 			ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
 			defer cancel()
+			var err error
 			serverVersion, err = healthcheck.GetServerVersion(ctx, client)
 			if err != nil {
 				serverVersion = defaultVersionString
@@ -74,5 +81,43 @@ func configureAndRunVersion(
 		} else {
 			fmt.Fprintf(stdout, "Server version: %s\n", serverVersion)
 		}
+
+		if options.proxy {
+
+			if clientErr != nil {
+				fmt.Fprintln(stdout, "Proxy versions: unavailable")
+			} else {
+				req := &pb.ListPodsRequest{}
+				if options.namespace != "" {
+					req.Selector = &pb.ResourceSelection{
+						Resource: &pb.Resource{
+							Namespace: options.namespace,
+						},
+					}
+				}
+
+				ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
+				defer cancel()
+				resp, err := client.ListPods(ctx, req)
+				if err != nil {
+					fmt.Fprintln(stdout, "Proxy versions: unavailable")
+				} else {
+					counts := make(map[string]int)
+					for _, pod := range resp.GetPods() {
+						if pod.ControllerNamespace == controlPlaneNamespace {
+							counts[pod.GetProxyVersion()]++
+						}
+					}
+					if len(counts) == 0 {
+						fmt.Fprintln(stdout, "Proxy versions: unavailable")
+					} else {
+						fmt.Fprintln(stdout, "Proxy versions:")
+						for version, count := range counts {
+							fmt.Fprintf(stdout, "\t%s (%d pods)\n", version, count)
+						}
+					}
+				}
+			}
+		}
 	}
 }
diff --git a/controller/tap/handlers.go b/controller/tap/handlers.go
index d5100d384..1250f9277 100644
--- a/controller/tap/handlers.go
+++ b/controller/tap/handlers.go
@@ -330,6 +330,7 @@ func mkPathItem(desc string) spec.PathItem {
 							},
 						},
 					},
+					ID: "tapResourceV0",
 				},
 			},
 		},
diff --git a/pkg/healthcheck/healthcheck.go b/pkg/healthcheck/healthcheck.go
index d2a33ecc0..c53882073 100644
--- a/pkg/healthcheck/healthcheck.go
+++ b/pkg/healthcheck/healthcheck.go
@@ -1147,12 +1147,17 @@ func (hc *HealthChecker) allCategories() []category {
 							return err
 						}
 
+						outdatedPods := []string{}
 						for _, pod := range pods {
 							err = hc.latestVersions.Match(pod.ProxyVersion)
 							if err != nil {
-								return fmt.Errorf("%s: %s", pod.Name, err)
+								outdatedPods = append(outdatedPods, fmt.Sprintf("\t* %s (%s)", pod.Name, pod.ProxyVersion))
 							}
 						}
+						if len(outdatedPods) > 0 {
+							podList := strings.Join(outdatedPods, "\n")
+							return fmt.Errorf("Some data plane pods are not running the current version:\n%s", podList)
+						}
 						return nil
 					},
 				},


Test patch:
diff --git a/cli/cmd/testdata/upgrade_default.golden b/cli/cmd/testdata/upgrade_default.golden
index c37605adb..5624d2054 100644
--- a/cli/cmd/testdata/upgrade_default.golden
+++ b/cli/cmd/testdata/upgrade_default.golden
@@ -853,9 +853,9 @@ data:
   global: |
     {"linkerdNamespace":"linkerd","cniEnabled":false,"version":"UPGRADE-CONTROL-PLANE-VERSION","identityContext":{"trustDomain":"cluster.local","trustAnchorsPem":"-----BEGIN CERTIFICATE-----\nMIIBwDCCAWagAwIBAgIQMvd1QnGUJzXVUt3gNh7rWjAKBggqhkjOPQQDAjApMScw\nJQYDVQQDEx5pZGVudGl0eS5saW5rZXJkLmNsdXN0ZXIubG9jYWwwHhcNMjAwNDA2\nMTAzOTUxWhcNMzAwNDA0MTAzOTUxWjApMScwJQYDVQQDEx5pZGVudGl0eS5saW5r\nZXJkLmNsdXN0ZXIubG9jYWwwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQ19nmg\nQ8l+EMofPxas7HUlOJE5avps6b6Q97Y71Waw3rdXYNCPqMxa4PedPc5VKGje6eqJ\nAo5mX29HeMcUw/y3o3AwbjAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB\n/wIBATAdBgNVHQ4EFgQUfxv+BcCt5v7oF7PXJ9xY+JambdwwKQYDVR0RBCIwIIIe\naWRlbnRpdHkubGlua2VyZC5jbHVzdGVyLmxvY2FsMAoGCCqGSM49BAMCA0gAMEUC\nIQCM8UfevR53SVGDd/4MgXMlVqC3Vh8oDiM0UToj2wsjNgIgLnZgogrqjK0KRo9R\nSxZLbJKt6SJIIY9dw5gzQpUQR2U=\n-----END CERTIFICATE-----\n","issuanceLifetime":"86400s","clockSkewAllowance":"20s","scheme":"linkerd.io/tls"},"autoInjectContext":null,"omitWebhookSideEffects":false,"clusterDomain":"cluster.local"}
   proxy: |
-    {"proxyImage":{"imageName":"gcr.io/linkerd-io/proxy","pullPolicy":"IfNotPresent"},"proxyInitImage":{"imageName":"gcr.io/linkerd-io/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":"UPGRADE-PROXY-VERSION","proxyInitImageVersion":"v1.3.2","debugImage":{"imageName":"gcr.io/linkerd-io/debug","pullPolicy":"IfNotPresent"},"debugImageVersion":"UPGRADE-DEBUG-VERSION"}
+    {"proxyImage":{"imageName":"gcr.io/linkerd-io/proxy","pullPolicy":"IfNotPresent"},"proxyInitImage":{"imageName":"gcr.io/linkerd-io/proxy-init","pullPolicy":"IfNotPresent"},"controlPort":{"port":4190},"ignoreInboundPorts":[{"portRange":"2525-2527"},{"portRange":"2529"}],"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":"UPGRADE-PROXY-VERSION","proxyInitImageVersion":"v1.3.2","debugImage":{"imageName":"gcr.io/linkerd-io/debug","pullPolicy":"IfNotPresent"},"debugImageVersion":"UPGRADE-DEBUG-VERSION"}
   install: |
-    {"cliVersion":"dev-undefined","flags":[]}
+    {"cliVersion":"dev-undefined","flags":[{"name":"skip-inbound-ports","value":"[2525-2527,2529]"}]}
 ---
 ###
 ### Identity Controller Service
@@ -1056,7 +1056,7 @@ spec:
         - --proxy-uid
         - "2102"
         - --inbound-ports-to-ignore
-        - 4190,4191
+        - 4190,4191,2525-2527,2529
         - --outbound-ports-to-ignore
         - "443"
         image: gcr.io/linkerd-io/proxy-init:v1.3.2
@@ -1277,7 +1277,7 @@ spec:
         - --proxy-uid
         - "2102"
         - --inbound-ports-to-ignore
-        - 4190,4191
+        - 4190,4191,2525-2527,2529
         - --outbound-ports-to-ignore
         - "443"
         image: gcr.io/linkerd-io/proxy-init:v1.3.2
@@ -1495,7 +1495,7 @@ spec:
         - --proxy-uid
         - "2102"
         - --inbound-ports-to-ignore
-        - 4190,4191
+        - 4190,4191,2525-2527,2529
         - --outbound-ports-to-ignore
         - "443"
         image: gcr.io/linkerd-io/proxy-init:v1.3.2
@@ -1761,7 +1761,7 @@ spec:
         - --proxy-uid
         - "2102"
         - --inbound-ports-to-ignore
-        - 4190,4191
+        - 4190,4191,2525-2527,2529
         - --outbound-ports-to-ignore
         - "443"
         image: gcr.io/linkerd-io/proxy-init:v1.3.2
@@ -2113,7 +2113,7 @@ spec:
         - --proxy-uid
         - "2102"
         - --inbound-ports-to-ignore
-        - 4190,4191
+        - 4190,4191,2525-2527,2529
         - --outbound-ports-to-ignore
         - "443"
         image: gcr.io/linkerd-io/proxy-init:v1.3.2
@@ -2390,7 +2390,7 @@ spec:
         - --proxy-uid
         - "2102"
         - --inbound-ports-to-ignore
-        - 4190,4191
+        - 4190,4191,2525-2527,2529
         - --outbound-ports-to-ignore
         - "443"
         image: gcr.io/linkerd-io/proxy-init:v1.3.2
@@ -2596,7 +2596,7 @@ spec:
         - --proxy-uid
         - "2102"
         - --inbound-ports-to-ignore
-        - 4190,4191
+        - 4190,4191,2525-2527,2529
         - --outbound-ports-to-ignore
         - "443"
         image: gcr.io/linkerd-io/proxy-init:v1.3.2
@@ -2832,7 +2832,7 @@ spec:
         - --proxy-uid
         - "2102"
         - --inbound-ports-to-ignore
-        - 4190,4191
+        - 4190,4191,2525-2527,2529
         - --outbound-ports-to-ignore
         - "443"
         image: gcr.io/linkerd-io/proxy-init:v1.3.2
@@ -3056,7 +3056,7 @@ spec:
         - --proxy-uid
         - "2102"
         - --inbound-ports-to-ignore
-        - 4190,4191
+        - 4190,4191,2525-2527,2529
         - --outbound-ports-to-ignore
         - "443"
         image: gcr.io/linkerd-io/proxy-init:v1.3.2
diff --git a/cli/cmd/upgrade_test.go b/cli/cmd/upgrade_test.go
index db6dd1854..c7ef69d5f 100644
--- a/cli/cmd/upgrade_test.go
+++ b/cli/cmd/upgrade_test.go
@@ -57,9 +57,9 @@ data:
   global: |
     {"linkerdNamespace":"linkerd","cniEnabled":false,"version":"edge-19.4.1","identityContext":{"trustDomain":"cluster.local","trustAnchorsPem":"-----BEGIN CERTIFICATE-----\nMIIBwDCCAWagAwIBAgIQMvd1QnGUJzXVUt3gNh7rWjAKBggqhkjOPQQDAjApMScw\nJQYDVQQDEx5pZGVudGl0eS5saW5rZXJkLmNsdXN0ZXIubG9jYWwwHhcNMjAwNDA2\nMTAzOTUxWhcNMzAwNDA0MTAzOTUxWjApMScwJQYDVQQDEx5pZGVudGl0eS5saW5r\nZXJkLmNsdXN0ZXIubG9jYWwwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQ19nmg\nQ8l+EMofPxas7HUlOJE5avps6b6Q97Y71Waw3rdXYNCPqMxa4PedPc5VKGje6eqJ\nAo5mX29HeMcUw/y3o3AwbjAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB\n/wIBATAdBgNVHQ4EFgQUfxv+BcCt5v7oF7PXJ9xY+JambdwwKQYDVR0RBCIwIIIe\naWRlbnRpdHkubGlua2VyZC5jbHVzdGVyLmxvY2FsMAoGCCqGSM49BAMCA0gAMEUC\nIQCM8UfevR53SVGDd/4MgXMlVqC3Vh8oDiM0UToj2wsjNgIgLnZgogrqjK0KRo9R\nSxZLbJKt6SJIIY9dw5gzQpUQR2U=\n-----END CERTIFICATE-----\n","issuanceLifetime":"86400s","clockSkewAllowance":"20s","scheme":"linkerd.io/tls"}, "clusterDomain":"cluster.local"}
   proxy: |
-    {"proxyImage":{"imageName":"gcr.io/linkerd-io/proxy","pullPolicy":"IfNotPresent"},"proxyInitImage":{"imageName":"gcr.io/linkerd-io/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,"debugImage":{"imageName":"gcr.io/linkerd-io/debug","pullPolicy":"IfNotPresent"},"debugImageVersion":"UPGRADE-DEBUG-VERSION"}
+    {"proxyImage":{"imageName":"gcr.io/linkerd-io/proxy","pullPolicy":"IfNotPresent"},"proxyInitImage":{"imageName":"gcr.io/linkerd-io/proxy-init","pullPolicy":"IfNotPresent"},"controlPort":{"port":4190},"ignoreInboundPorts":[{"portRange":"2525-2527"},{"portRange":"25259"}],"ignoreOutboundPorts":[],"inboundPort":{"port":4143},"adminPort":{"port":4191},"outboundPort":{"port":4140},"resource":{"requestCpu":"","requestMemory":"","limitCpu":"","limitMemory":""},"proxyUid":"2102","logLevel":{"level":"warn,linkerd=info"},"disableExternalProfiles":true,"debugImage":{"imageName":"gcr.io/linkerd-io/debug","pullPolicy":"IfNotPresent"},"debugImageVersion":"UPGRADE-DEBUG-VERSION"}
   install: |
-    {"cliVersion":"edge-19.4.1","flags":[]}`,
+    {"cliVersion":"edge-19.4.1","flags":[{"name":"skip-inbound-ports","value":"[2525-2527,2529]"}]}`,
 				`
 kind: Secret
 apiVersion: v1
diff --git a/cli/cmd/version_test.go b/cli/cmd/version_test.go
index 0371a15dc..8b3e826bd 100644
--- a/cli/cmd/version_test.go
+++ b/cli/cmd/version_test.go
@@ -34,17 +34,17 @@ func TestConfigureAndRunVersion(t *testing.T) {
 			fmt.Sprintf("Client version: %s\nServer version: %s\n", version.Version, "server-version"),
 		},
 		{
-			&versionOptions{false, true},
+			&versionOptions{false, true, false, ""},
 			mkMockClient("", nil, nil),
 			fmt.Sprintf("Client version: %s\n", version.Version),
 		},
 		{
-			&versionOptions{true, true},
+			&versionOptions{true, true, false, ""},
 			mkMockClient("", nil, nil),
 			fmt.Sprintf("%s\n", version.Version),
 		},
 		{
-			&versionOptions{true, false},
+			&versionOptions{true, false, false, ""},
 			mkMockClient("server-version", nil, nil),
 			fmt.Sprintf("%s\n%s\n", version.Version, "server-version"),
 		},
diff --git a/test/trafficsplit/trafficsplit_test.go b/test/trafficsplit/trafficsplit_test.go
index f8579aacc..670f7d408 100644
--- a/test/trafficsplit/trafficsplit_test.go
+++ b/test/trafficsplit/trafficsplit_test.go
@@ -67,7 +67,7 @@ func parseStatTsRow(out string, expectedRowCount, expectedColumnCount int) (map[
 }
 
 func statTrafficSplit(from string, ns string) (map[string]*statTsRow, error) {
-	cmd := []string{"stat", "ts", "--from", from, "--namespace", ns, "-t", "30s"}
+	cmd := []string{"stat", "ts", "--from", from, "--namespace", ns, "-t", "30s", "--unmeshed"}
 	stdOut, _, err := TestHelper.LinkerdRun(cmd...)
 	if err != nil {
 		return nil, err