Repository: linkerd/linkerd2
Pull request #5781 (2021-02-19 15:03:51)

Properly list orphaned resources when attempting to run integration tests
When running `bin/tests`, if there were linkerd resources already in the cluster an error was thrown, but the offending resources weren't shown.

Before:
```console
$ bin/tests --skip-cluster-create ~/.linkerd2/bin/linkerd
==================RUNNING ALL TESTS==================
Note: cluster-domain, cni-calico-deep and multicluster require a specific cluster configuration and are skipped by default

Checking the linkerd binary...[ok]
Checking if there is a Kubernetes cluster available...[ok]
Checking if Linkerd resources exist on cluster...
Linkerd resources exist on cluster:

/home/alpeb/.linkerd2/bin/linkerd

Help:
    Run: [/test-cleanup]
```

After:
```console
$ bin/tests --images skip --skip-cluster-create ~/.linkerd2/bin/linkerd
==================RUNNING ALL TESTS==================
Note: cluster-domain, cni-calico-deep and multicluster require a specific cluster configuration and are skipped by default

Checking the linkerd binary...[ok]
Checking if there is a Kubernetes cluster available...[ok]
Checking if Linkerd resources exist on cluster...
Linkerd resources exist on cluster:

pod/linkerd-identity-6fc8449776-t2vmj
pod/linkerd-proxy-injector-fb4b5ffb7-xdqxh
pod/linkerd-controller-7b9f9d458b-fbhz2
service/linkerd-proxy-injector
service/linkerd-sp-validator
deployment.apps/linkerd-identity
deployment.apps/linkerd-proxy-injector
clusterrole.rbac.authorization.k8s.io/linkerd-linkerd-identity
clusterrole.rbac.authorization.k8s.io/linkerd-linkerd-controller
clusterrole.rbac.authorization.k8s.io/linkerd-linkerd-destination
clusterrolebinding.rbac.authorization.k8s.io/linkerd-linkerd-identity
validatingwebhookconfiguration.admissionregistration.k8s.io/linkerd-sp-validator-webhook-config
podsecuritypolicy.policy/linkerd-linkerd-control-plane
customresourcedefinition.apiextensions.k8s.io/serviceprofiles.linkerd.io
Help:
    Run: [/home/alpeb/.linkerd2/bin/linkerd/test-cleanup]
```



Patch:
diff --git a/charts/linkerd2/templates/heartbeat-rbac.yaml b/charts/linkerd2/templates/heartbeat-rbac.yaml
index 44a448690..0126d24f4 100644
--- a/charts/linkerd2/templates/heartbeat-rbac.yaml
+++ b/charts/linkerd2/templates/heartbeat-rbac.yaml
@@ -42,6 +42,9 @@ rules:
 - apiGroups: [""]
   resources: ["namespaces"]
   verbs: ["list"]
+- apiGroups: ["linkerd.io"]
+  resources: ["serviceprofiles"]
+  verbs: ["list"]
 ---
 apiVersion: rbac.authorization.k8s.io/v1
 kind: ClusterRoleBinding
diff --git a/cli/cmd/endpoints.go b/cli/cmd/endpoints.go
index f988567c5..ee0e248c0 100644
--- a/cli/cmd/endpoints.go
+++ b/cli/cmd/endpoints.go
@@ -98,7 +98,8 @@ destination.`,
 				APIAddr:               apiAddr,
 			}), args)
 			if err != nil {
-				return fmt.Errorf("Destination API error: %s", err)
+				fmt.Fprint(os.Stderr, fmt.Errorf("Destination API error: %s", err))
+				os.Exit(1)
 			}
 
 			output := renderEndpoints(endpoints, options)
diff --git a/controller/heartbeat/heartbeat.go b/controller/heartbeat/heartbeat.go
index 675115852..96cec1741 100644
--- a/controller/heartbeat/heartbeat.go
+++ b/controller/heartbeat/heartbeat.go
@@ -10,12 +10,14 @@ import (
 	"strconv"
 	"time"
 
+	pkgK8s "github.com/linkerd/linkerd2/controller/k8s"
 	"github.com/linkerd/linkerd2/pkg/healthcheck"
 	"github.com/linkerd/linkerd2/pkg/k8s"
 	"github.com/linkerd/linkerd2/pkg/version"
 	promv1 "github.com/prometheus/client_golang/api/prometheus/v1"
 	"github.com/prometheus/common/model"
 	log "github.com/sirupsen/logrus"
+	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
 
 type containerMeta struct {
@@ -52,6 +54,26 @@ func K8sValues(ctx context.Context, kubeAPI *k8s.KubernetesAPI, controlPlaneName
 		}
 	}
 
+	err = k8s.ServiceProfilesAccess(ctx, kubeAPI)
+	if err != nil {
+		log.Errorf("Failed to verify service profile access: %s", err)
+		return v
+	}
+
+	spClient, err := pkgK8s.NewSpClientSet(kubeAPI.Config)
+	if err != nil {
+		log.Errorf("Failed to create service profile client: %s", err)
+		return v
+	}
+
+	spList, err := spClient.LinkerdV1alpha2().ServiceProfiles("").List(ctx, v1.ListOptions{})
+	if err != nil {
+		log.Errorf("Failed to get service profiles: %s", err)
+		return v
+	}
+
+	v.Set("service-profile-count", strconv.Itoa(len(spList.Items)))
+
 	return v
 }
 
diff --git a/multicluster/cmd/gateways.go b/multicluster/cmd/gateways.go
index 758cfd9c0..4c99bcb1e 100644
--- a/multicluster/cmd/gateways.go
+++ b/multicluster/cmd/gateways.go
@@ -4,6 +4,7 @@ import (
 	"context"
 	"fmt"
 	"io"
+	"os"
 
 	"github.com/linkerd/linkerd2/cli/table"
 	labels "github.com/linkerd/linkerd2/multicluster/pkg"
@@ -57,7 +58,8 @@ func newGatewaysCommand() *cobra.Command {
 
 			resp, err := requestGatewaysFromAPI(client, req)
 			if err != nil {
-				return err
+				fmt.Fprint(os.Stderr, err.Error())
+				os.Exit(1)
 			}
 
 			renderGateways(resp.GetOk().GatewaysTable.Rows, stdout)
diff --git a/viz/cmd/edges.go b/viz/cmd/edges.go
index 02dedfe90..701234264 100644
--- a/viz/cmd/edges.go
+++ b/viz/cmd/edges.go
@@ -119,7 +119,8 @@ func NewCmdEdges() *cobra.Command {
 			i := 0
 			for res := range c {
 				if res.err != nil {
-					return res.err
+					fmt.Fprint(os.Stderr, res.err.Error())
+					os.Exit(1)
 				}
 				totalRows = append(totalRows, res.rows...)
 				if i++; i == len(reqs) {
diff --git a/viz/cmd/routes.go b/viz/cmd/routes.go
index 1420e568b..5d7698bbb 100644
--- a/viz/cmd/routes.go
+++ b/viz/cmd/routes.go
@@ -6,6 +6,7 @@ import (
 	"encoding/json"
 	"errors"
 	"fmt"
+	"os"
 	"sort"
 	"strings"
 	"text/tabwriter"
@@ -87,7 +88,8 @@ This command will only display traffic which is sent to a service that has a Ser
 				options,
 			)
 			if err != nil {
-				return err
+				fmt.Fprint(os.Stderr, err.Error())
+				os.Exit(1)
 			}
 
 			_, err = fmt.Print(output)


Test patch:
diff --git a/bin/_test-helpers.sh b/bin/_test-helpers.sh
index 70d69ff67..aeedc4ffb 100644
--- a/bin/_test-helpers.sh
+++ b/bin/_test-helpers.sh
@@ -262,7 +262,7 @@ check_if_l5d_exists() {
 Linkerd resources exist on cluster:
 \n%s\n
 Help:
-    Run: [%s/test-cleanup] ' "$linkerd_path"
+    Run: [%s/test-cleanup] ' "$resources" "$linkerd_path"
     exit 1
   fi
   printf '[ok]\n'
diff --git a/cli/cmd/testdata/install_config.golden b/cli/cmd/testdata/install_config.golden
index 6b50e296b..96348d16e 100644
--- a/cli/cmd/testdata/install_config.golden
+++ b/cli/cmd/testdata/install_config.golden
@@ -210,6 +210,9 @@ rules:
 - apiGroups: [""]
   resources: ["namespaces"]
   verbs: ["list"]
+- apiGroups: ["linkerd.io"]
+  resources: ["serviceprofiles"]
+  verbs: ["list"]
 ---
 apiVersion: rbac.authorization.k8s.io/v1
 kind: ClusterRoleBinding
diff --git a/cli/cmd/testdata/install_controlplane_tracing_output.golden b/cli/cmd/testdata/install_controlplane_tracing_output.golden
index 0737ead9f..63f0af78e 100644
--- a/cli/cmd/testdata/install_controlplane_tracing_output.golden
+++ b/cli/cmd/testdata/install_controlplane_tracing_output.golden
@@ -205,6 +205,9 @@ rules:
 - apiGroups: [""]
   resources: ["namespaces"]
   verbs: ["list"]
+- apiGroups: ["linkerd.io"]
+  resources: ["serviceprofiles"]
+  verbs: ["list"]
 ---
 apiVersion: rbac.authorization.k8s.io/v1
 kind: ClusterRoleBinding
diff --git a/cli/cmd/testdata/install_custom_domain.golden b/cli/cmd/testdata/install_custom_domain.golden
index 70b0ecb79..28da31ab4 100644
--- a/cli/cmd/testdata/install_custom_domain.golden
+++ b/cli/cmd/testdata/install_custom_domain.golden
@@ -205,6 +205,9 @@ rules:
 - apiGroups: [""]
   resources: ["namespaces"]
   verbs: ["list"]
+- apiGroups: ["linkerd.io"]
+  resources: ["serviceprofiles"]
+  verbs: ["list"]
 ---
 apiVersion: rbac.authorization.k8s.io/v1
 kind: ClusterRoleBinding
diff --git a/cli/cmd/testdata/install_custom_registry.golden b/cli/cmd/testdata/install_custom_registry.golden
index ba23ec7b7..4693f7cac 100644
--- a/cli/cmd/testdata/install_custom_registry.golden
+++ b/cli/cmd/testdata/install_custom_registry.golden
@@ -205,6 +205,9 @@ rules:
 - apiGroups: [""]
   resources: ["namespaces"]
   verbs: ["list"]
+- apiGroups: ["linkerd.io"]
+  resources: ["serviceprofiles"]
+  verbs: ["list"]
 ---
 apiVersion: rbac.authorization.k8s.io/v1
 kind: ClusterRoleBinding
diff --git a/cli/cmd/testdata/install_default.golden b/cli/cmd/testdata/install_default.golden
index 002c501f5..0e50f6a4e 100644
--- a/cli/cmd/testdata/install_default.golden
+++ b/cli/cmd/testdata/install_default.golden
@@ -205,6 +205,9 @@ rules:
 - apiGroups: [""]
   resources: ["namespaces"]
   verbs: ["list"]
+- apiGroups: ["linkerd.io"]
+  resources: ["serviceprofiles"]
+  verbs: ["list"]
 ---
 apiVersion: rbac.authorization.k8s.io/v1
 kind: ClusterRoleBinding
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 86e17ad80..be6375fa6 100644
--- a/cli/cmd/testdata/install_default_override_dst_get_nets.golden
+++ b/cli/cmd/testdata/install_default_override_dst_get_nets.golden
@@ -205,6 +205,9 @@ rules:
 - apiGroups: [""]
   resources: ["namespaces"]
   verbs: ["list"]
+- apiGroups: ["linkerd.io"]
+  resources: ["serviceprofiles"]
+  verbs: ["list"]
 ---
 apiVersion: rbac.authorization.k8s.io/v1
 kind: ClusterRoleBinding
diff --git a/cli/cmd/testdata/install_ha_output.golden b/cli/cmd/testdata/install_ha_output.golden
index 559824947..511f4c900 100644
--- a/cli/cmd/testdata/install_ha_output.golden
+++ b/cli/cmd/testdata/install_ha_output.golden
@@ -205,6 +205,9 @@ rules:
 - apiGroups: [""]
   resources: ["namespaces"]
   verbs: ["list"]
+- apiGroups: ["linkerd.io"]
+  resources: ["serviceprofiles"]
+  verbs: ["list"]
 ---
 apiVersion: rbac.authorization.k8s.io/v1
 kind: ClusterRoleBinding
diff --git a/cli/cmd/testdata/install_ha_with_overrides_output.golden b/cli/cmd/testdata/install_ha_with_overrides_output.golden
index a97d04df2..8c3f4534b 100644
--- a/cli/cmd/testdata/install_ha_with_overrides_output.golden
+++ b/cli/cmd/testdata/install_ha_with_overrides_output.golden
@@ -205,6 +205,9 @@ rules:
 - apiGroups: [""]
   resources: ["namespaces"]
   verbs: ["list"]
+- apiGroups: ["linkerd.io"]
+  resources: ["serviceprofiles"]
+  verbs: ["list"]
 ---
 apiVersion: rbac.authorization.k8s.io/v1
 kind: ClusterRoleBinding
diff --git a/cli/cmd/testdata/install_helm_output.golden b/cli/cmd/testdata/install_helm_output.golden
index cc7cc4da5..6f1ba71d1 100644
--- a/cli/cmd/testdata/install_helm_output.golden
+++ b/cli/cmd/testdata/install_helm_output.golden
@@ -215,6 +215,9 @@ rules:
 - apiGroups: [""]
   resources: ["namespaces"]
   verbs: ["list"]
+- apiGroups: ["linkerd.io"]
+  resources: ["serviceprofiles"]
+  verbs: ["list"]
 ---
 apiVersion: rbac.authorization.k8s.io/v1
 kind: ClusterRoleBinding
diff --git a/cli/cmd/testdata/install_helm_output_ha.golden b/cli/cmd/testdata/install_helm_output_ha.golden
index 0adce7eea..f22da7ab2 100644
--- a/cli/cmd/testdata/install_helm_output_ha.golden
+++ b/cli/cmd/testdata/install_helm_output_ha.golden
@@ -215,6 +215,9 @@ rules:
 - apiGroups: [""]
   resources: ["namespaces"]
   verbs: ["list"]
+- apiGroups: ["linkerd.io"]
+  resources: ["serviceprofiles"]
+  verbs: ["list"]
 ---
 apiVersion: rbac.authorization.k8s.io/v1
 kind: ClusterRoleBinding
diff --git a/cli/cmd/testdata/install_helm_output_ha_labels.golden b/cli/cmd/testdata/install_helm_output_ha_labels.golden
index ec317420e..2161df679 100644
--- a/cli/cmd/testdata/install_helm_output_ha_labels.golden
+++ b/cli/cmd/testdata/install_helm_output_ha_labels.golden
@@ -215,6 +215,9 @@ rules:
 - apiGroups: [""]
   resources: ["namespaces"]
   verbs: ["list"]
+- apiGroups: ["linkerd.io"]
+  resources: ["serviceprofiles"]
+  verbs: ["list"]
 ---
 apiVersion: rbac.authorization.k8s.io/v1
 kind: ClusterRoleBinding
diff --git a/cli/cmd/testdata/install_helm_output_ha_namespace_selector.golden b/cli/cmd/testdata/install_helm_output_ha_namespace_selector.golden
index a244d8e49..b670a8090 100644
--- a/cli/cmd/testdata/install_helm_output_ha_namespace_selector.golden
+++ b/cli/cmd/testdata/install_helm_output_ha_namespace_selector.golden
@@ -215,6 +215,9 @@ rules:
 - apiGroups: [""]
   resources: ["namespaces"]
   verbs: ["list"]
+- apiGroups: ["linkerd.io"]
+  resources: ["serviceprofiles"]
+  verbs: ["list"]
 ---
 apiVersion: rbac.authorization.k8s.io/v1
 kind: ClusterRoleBinding
diff --git a/cli/cmd/testdata/install_no_init_container.golden b/cli/cmd/testdata/install_no_init_container.golden
index 1b8a76f80..68f4ec69a 100644
--- a/cli/cmd/testdata/install_no_init_container.golden
+++ b/cli/cmd/testdata/install_no_init_container.golden
@@ -205,6 +205,9 @@ rules:
 - apiGroups: [""]
   resources: ["namespaces"]
   verbs: ["list"]
+- apiGroups: ["linkerd.io"]
+  resources: ["serviceprofiles"]
+  verbs: ["list"]
 ---
 apiVersion: rbac.authorization.k8s.io/v1
 kind: ClusterRoleBinding
diff --git a/cli/cmd/testdata/install_output.golden b/cli/cmd/testdata/install_output.golden
index 70e97a55e..e1ab0b5c7 100644
--- a/cli/cmd/testdata/install_output.golden
+++ b/cli/cmd/testdata/install_output.golden
@@ -205,6 +205,9 @@ rules:
 - apiGroups: [""]
   resources: ["namespaces"]
   verbs: ["list"]
+- apiGroups: ["linkerd.io"]
+  resources: ["serviceprofiles"]
+  verbs: ["list"]
 ---
 apiVersion: rbac.authorization.k8s.io/v1
 kind: ClusterRoleBinding
diff --git a/cli/cmd/testdata/install_proxy_ignores.golden b/cli/cmd/testdata/install_proxy_ignores.golden
index 45fe6a303..da96f92df 100644
--- a/cli/cmd/testdata/install_proxy_ignores.golden
+++ b/cli/cmd/testdata/install_proxy_ignores.golden
@@ -205,6 +205,9 @@ rules:
 - apiGroups: [""]
   resources: ["namespaces"]
   verbs: ["list"]
+- apiGroups: ["linkerd.io"]
+  resources: ["serviceprofiles"]
+  verbs: ["list"]
 ---
 apiVersion: rbac.authorization.k8s.io/v1
 kind: ClusterRoleBinding
diff --git a/cli/cmd/testdata/install_values_file.golden b/cli/cmd/testdata/install_values_file.golden
index deb2b31af..315e8a7ba 100644
--- a/cli/cmd/testdata/install_values_file.golden
+++ b/cli/cmd/testdata/install_values_file.golden
@@ -191,6 +191,9 @@ rules:
 - apiGroups: [""]
   resources: ["namespaces"]
   verbs: ["list"]
+- apiGroups: ["linkerd.io"]
+  resources: ["serviceprofiles"]
+  verbs: ["list"]
 ---
 apiVersion: rbac.authorization.k8s.io/v1
 kind: ClusterRoleBinding
diff --git a/test/integration/endpoints/endpoints_test.go b/test/integration/endpoints/endpoints_test.go
index 1f5a488b8..3e033edb7 100644
--- a/test/integration/endpoints/endpoints_test.go
+++ b/test/integration/endpoints/endpoints_test.go
@@ -77,7 +77,7 @@ func TestBadEndpoints(t *testing.T) {
 	if len(stderrOut) == 0 {
 		testutil.AnnotatedFatalf(t, "unexpected output", "unexpected output: %s", stderr)
 	}
-	if stderrOut[0] != "Error: Destination API error: Invalid authority: foo" {
+	if stderrOut[0] != "Destination API error: Invalid authority: foo" {
 		testutil.AnnotatedErrorf(t, "unexpected error string", "unexpected error string: %s", stderrOut[0])
 	}
 }