From c3a59b4da4db51b537e3d806094e18106ee93dd7 Mon Sep 17 00:00:00 2001 From: Tarun Pothulapati Date: Tue, 10 Nov 2020 12:15:51 +0530 Subject: [PATCH] cli: Remove get cmd and relevant tests Fixes #5190 `linkerd get` is not used currently and works only for pods. This can be removed instead as per the issue. This branch removes the command and also the associated unit and integration tests. Signed-off-by: Tarun Pothulapati --- cli/cmd/get.go | 102 --------- cli/cmd/get_test.go | 70 ------- cli/cmd/root.go | 1 - test/integration/get/get_test.go | 195 ------------------ .../not_to_be_injected_application.yaml | 47 ----- .../testdata/to_be_injected_application.yaml | 47 ----- 6 files changed, 462 deletions(-) delete mode 100644 cli/cmd/get.go delete mode 100644 cli/cmd/get_test.go delete mode 100644 test/integration/get/get_test.go delete mode 100644 test/integration/get/testdata/not_to_be_injected_application.yaml delete mode 100644 test/integration/get/testdata/to_be_injected_application.yaml diff --git a/cli/cmd/get.go b/cli/cmd/get.go deleted file mode 100644 index 976a3fbf07eb9..0000000000000 --- a/cli/cmd/get.go +++ /dev/null @@ -1,102 +0,0 @@ -package cmd - -import ( - "context" - "errors" - "fmt" - "os" - - pb "github.com/linkerd/linkerd2/controller/gen/public" - "github.com/linkerd/linkerd2/pkg/k8s" - "github.com/spf13/cobra" -) - -type getOptions struct { - namespace string - allNamespaces bool -} - -func newGetOptions() *getOptions { - return &getOptions{ - namespace: defaultNamespace, - allNamespaces: false, - } -} - -func newCmdGet() *cobra.Command { - options := newGetOptions() - - cmd := &cobra.Command{ - Use: "get [flags] pods", - Short: "Display one or many mesh resources", - Long: `Display one or many mesh resources. - -Only pod resources (aka pods, po) are supported.`, - Example: ` # get all pods - linkerd get pods - - # get pods from namespace linkerd - linkerd get pods --namespace linkerd`, - Args: cobra.ExactArgs(1), - ValidArgs: []string{k8s.Pod}, - RunE: func(cmd *cobra.Command, args []string) error { - if len(args) < 1 { - return errors.New("please specify a resource type") - } - - if len(args) > 1 { - return errors.New("please specify only one resource type") - } - - friendlyName := args[0] - resourceType, err := k8s.CanonicalResourceNameFromFriendlyName(friendlyName) - - if err != nil || resourceType != k8s.Pod { - return fmt.Errorf("invalid resource type %s, valid types: %s", friendlyName, k8s.Pod) - } - - podNames, err := getPods(checkPublicAPIClientOrExit(), options) - if err != nil { - return err - } - - if len(podNames) == 0 { - fmt.Fprintln(os.Stderr, "No resources found.") - os.Exit(0) - } - - for _, podName := range podNames { - fmt.Println(podName) - } - - return nil - }, - } - - cmd.PersistentFlags().StringVarP(&options.namespace, "namespace", "n", options.namespace, "Namespace of pods") - cmd.PersistentFlags().BoolVarP(&options.allNamespaces, "all-namespaces", "A", options.allNamespaces, "If present, returns pods across all namespaces, ignoring the \"--namespace\" flag") - return cmd -} - -func getPods(apiClient pb.ApiClient, options *getOptions) ([]string, error) { - req := &pb.ListPodsRequest{} - if !options.allNamespaces { - req.Selector = &pb.ResourceSelection{ - Resource: &pb.Resource{ - Namespace: options.namespace, - }, - } - } - - resp, err := apiClient.ListPods(context.Background(), req) - if err != nil { - return nil, err - } - - names := make([]string, 0) - for _, pod := range resp.GetPods() { - names = append(names, pod.Name) - } - - return names, nil -} diff --git a/cli/cmd/get_test.go b/cli/cmd/get_test.go deleted file mode 100644 index 46b401dedb43a..0000000000000 --- a/cli/cmd/get_test.go +++ /dev/null @@ -1,70 +0,0 @@ -package cmd - -import ( - "errors" - "testing" - - "github.com/linkerd/linkerd2/controller/api/public" - pb "github.com/linkerd/linkerd2/controller/gen/public" -) - -func TestGetPods(t *testing.T) { - t.Run("Returns names of existing pods if everything went ok", func(t *testing.T) { - mockClient := &public.MockAPIClient{} - - pods := []*pb.Pod{ - {Name: "pod-a"}, - {Name: "pod-b"}, - {Name: "pod-c"}, - } - - expectedPodNames := []string{ - "pod-a", - "pod-b", - "pod-c", - } - response := &pb.ListPodsResponse{ - Pods: pods, - } - - mockClient.ListPodsResponseToReturn = response - actualPodNames, err := getPods(mockClient, newGetOptions()) - if err != nil { - t.Fatalf("Unexpected error: %v", err) - } - - for i, actualName := range actualPodNames { - expectedName := expectedPodNames[i] - if expectedName != actualName { - t.Fatalf("Expected %dth element on %v to be [%s], but was [%s]", i, actualPodNames, expectedName, actualName) - } - } - }) - - t.Run("Returns empty list if no pods found", func(t *testing.T) { - mockClient := &public.MockAPIClient{} - - mockClient.ListPodsResponseToReturn = &pb.ListPodsResponse{ - Pods: []*pb.Pod{}, - } - - actualPodNames, err := getPods(mockClient, newGetOptions()) - if err != nil { - t.Fatalf("Unexpected error: %v", err) - } - - if len(actualPodNames) != 0 { - t.Fatalf("Expecting no pod names, got %v", actualPodNames) - } - }) - - t.Run("Returns error if can't find pods in API", func(t *testing.T) { - mockClient := &public.MockAPIClient{} - mockClient.ErrorToReturn = errors.New("expected") - - _, err := getPods(mockClient, newGetOptions()) - if err == nil { - t.Fatalf("Expecting error, got noting") - } - }) -} diff --git a/cli/cmd/root.go b/cli/cmd/root.go index b401b33643d18..9dcb84bed94a1 100644 --- a/cli/cmd/root.go +++ b/cli/cmd/root.go @@ -113,7 +113,6 @@ func init() { RootCmd.AddCommand(newCmdDoc()) RootCmd.AddCommand(newCmdEdges()) RootCmd.AddCommand(newCmdEndpoints()) - RootCmd.AddCommand(newCmdGet()) RootCmd.AddCommand(newCmdInject()) RootCmd.AddCommand(newCmdInstall()) RootCmd.AddCommand(newCmdInstallCNIPlugin()) diff --git a/test/integration/get/get_test.go b/test/integration/get/get_test.go deleted file mode 100644 index aa2a04f884901..0000000000000 --- a/test/integration/get/get_test.go +++ /dev/null @@ -1,195 +0,0 @@ -package get - -import ( - "context" - "fmt" - "io/ioutil" - "os" - "reflect" - "regexp" - "sort" - "strings" - "testing" - - "github.com/linkerd/linkerd2/testutil" -) - -////////////////////// -/// TEST SETUP /// -////////////////////// - -var TestHelper *testutil.TestHelper - -func TestMain(m *testing.M) { - TestHelper = testutil.NewTestHelper() - os.Exit(testutil.Run(m, TestHelper)) -} - -var ( - deployReplicas = map[string]int{ - "cli-get-test-d1": 2, - "cli-get-test-d2": 1, - "cli-get-test-not-injected-d1": 2, - "cli-get-test-not-injected-d2": 1, - } - - linkerdPods = map[string]int{ - "linkerd-controller": 1, - "linkerd-destination": 1, - "linkerd-grafana": 1, - "linkerd-identity": 1, - "linkerd-prometheus": 1, - "linkerd-proxy-injector": 1, - "linkerd-sp-validator": 1, - "linkerd-tap": 1, - "linkerd-web": 1, - } -) - -////////////////////// -/// TEST EXECUTION /// -////////////////////// - -func TestCliGet(t *testing.T) { - out, err := TestHelper.LinkerdRun("inject", "testdata/to_be_injected_application.yaml") - if err != nil { - testutil.AnnotatedFatal(t, "unexpected error", err) - } - - ctx := context.Background() - TestHelper.WithDataPlaneNamespace(ctx, "get-test", map[string]string{}, t, func(t *testing.T, prefixedNs string) { - - out, err = TestHelper.KubectlApply(out, prefixedNs) - if err != nil { - testutil.AnnotatedFatalf(t, "unexpected error", "unexpected error: %v output:\n%s", err, out) - } - - bytes, err := ioutil.ReadFile("testdata/not_to_be_injected_application.yaml") - if err != nil { - testutil.AnnotatedFatalf(t, "unexpected error", "unexpected error: %v", err) - } - - out, err = TestHelper.KubectlApply(string(bytes), prefixedNs) - if err != nil { - testutil.AnnotatedFatalf(t, "unexpected error", "unexpected error: %v output:\n%s", err, out) - } - - // wait for pods to start - for deploy, replicas := range deployReplicas { - if err := TestHelper.CheckPods(ctx, prefixedNs, deploy, replicas); err != nil { - if rce, ok := err.(*testutil.RestartCountError); ok { - testutil.AnnotatedWarn(t, "CheckPods timed-out", rce) - } else { - testutil.AnnotatedError(t, "CheckPods timed-out", err) - } - } - } - - t.Run("get pods from --all-namespaces", func(t *testing.T) { - out, err = TestHelper.LinkerdRun("get", "pods", "--all-namespaces") - if err != nil { - testutil.AnnotatedFatal(t, "unexpected error", err) - } - - err := checkPodOutput(out, deployReplicas, "", prefixedNs) - if err != nil { - testutil.AnnotatedFatalf(t, "pod output check failed", "pod output check failed:\n%s\nCommand output:\n%s", err, out) - } - }) - - t.Run("get pods from the linkerd namespace", func(t *testing.T) { - out, err = TestHelper.LinkerdRun("get", "pods", "-n", TestHelper.GetLinkerdNamespace()) - if err != nil { - testutil.AnnotatedFatal(t, "unexpected error", err) - } - - err := checkPodOutput(out, linkerdPods, "linkerd-heartbeat", TestHelper.GetLinkerdNamespace()) - if err != nil { - testutil.AnnotatedFatalf(t, "pod output check failed", "pod output check failed:\n%s\nCommand output:\n%s", err, out) - } - }) - - t.Run("get pods from the default namespace of current context", func(t *testing.T) { - out, err := TestHelper.Kubectl("", "config", "set-context", "--namespace="+TestHelper.GetLinkerdNamespace(), "--current") - if err != nil { - testutil.AnnotatedFatalf(t, "unexpected error", "unexpected error: %v output:\n%s", err, out) - } - - out, err = TestHelper.LinkerdRun("get", "pods") - if err != nil { - testutil.AnnotatedFatal(t, "unexpected error", err) - } - - err = checkPodOutput(out, linkerdPods, "linkerd-heartbeat", TestHelper.GetLinkerdNamespace()) - if err != nil { - testutil.AnnotatedFatalf(t, "pod output check failed", "pod output check failed:\n%s\nCommand output:\n%s", err, out) - } - - out, err = TestHelper.Kubectl("", "config", "set-context", "--namespace=default", "--current") - if err != nil { - testutil.AnnotatedFatalf(t, "unexpected error", "unexpected error: %v output:\n%s", err, out) - } - }) - }) -} - -func checkPodOutput(cmdOutput string, expectedPodCounts map[string]int, optionalPod string, namespace string) error { - expectedPods := []string{} - for podName, replicas := range expectedPodCounts { - for i := 0; i < replicas; i++ { - expectedPods = append(expectedPods, podName) - } - } - - lines := strings.Split(cmdOutput, "\n") - if len(lines) == 0 { - return fmt.Errorf("Expecting linkerd get pods to return something, got nothing") - } - - var actualPods []string - for _, line := range lines { - sanitizedLine := strings.TrimSpace(line) - if sanitizedLine == "" { - continue - } - - ns, pod, err := TestHelper.ParseNamespacedResource(sanitizedLine) - if err != nil { - return fmt.Errorf("Unexpected error: %v", err) - } - - if ns == namespace { - podPrefix, err := parsePodPrefix(pod) - - if err != nil { - return fmt.Errorf("Unexpected error: %v", err) - } - actualPods = append(actualPods, podPrefix) - } - } - - sort.Strings(expectedPods) - sort.Strings(actualPods) - if !reflect.DeepEqual(expectedPods, actualPods) { - if optionalPod == "" { - return fmt.Errorf("Expected linkerd get to return:\n%v\nBut got:\n%v", expectedPods, actualPods) - } - - expectedPlusOptionalPods := append(expectedPods, optionalPod) - sort.Strings(expectedPlusOptionalPods) - if !reflect.DeepEqual(expectedPlusOptionalPods, actualPods) { - return fmt.Errorf("Expected linkerd get to return:\n%v\nor:\n%v\nBut got:\n%v", expectedPods, expectedPlusOptionalPods, actualPods) - } - } - - return nil -} - -func parsePodPrefix(pod string) (string, error) { - r := regexp.MustCompile("^(.+)-.+-.+$") - matches := r.FindAllStringSubmatch(pod, 1) - if len(matches) == 0 { - return "", fmt.Errorf("string [%s] didn't contain expected format for pod name, extracted: %v", pod, matches) - } - return matches[0][1], nil -} diff --git a/test/integration/get/testdata/not_to_be_injected_application.yaml b/test/integration/get/testdata/not_to_be_injected_application.yaml deleted file mode 100644 index c63482630b971..0000000000000 --- a/test/integration/get/testdata/not_to_be_injected_application.yaml +++ /dev/null @@ -1,47 +0,0 @@ ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: cli-get-test-not-injected-d1 -spec: - replicas: 2 - selector: - matchLabels: - app: cli-get-test-not-injected-d1 - template: - metadata: - labels: - app: cli-get-test-not-injected-d1 - spec: - containers: - - name: http-to-grpc - image: buoyantio/bb:v0.0.6 - args: ["terminus", "--grpc-server-port", "9090", "--response-text", "BANANA"] - ports: - - containerPort: 9090 - - name: http-to-grpc-2 - image: buoyantio/bb:v0.0.6 - args: ["terminus", "--grpc-server-port", "90", "--response-text", "BANANA"] - ports: - - containerPort: 90 ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: cli-get-test-not-injected-d2 -spec: - replicas: 1 - selector: - matchLabels: - app: cli-get-test-not-injected-d2 - template: - metadata: - labels: - app: cli-get-test-not-injected-d2 - spec: - containers: - - name: http-to-grpc - image: buoyantio/bb:v0.0.6 - args: ["terminus", "--grpc-server-port", "90", "--response-text", "BANANA"] - ports: - - containerPort: 90 diff --git a/test/integration/get/testdata/to_be_injected_application.yaml b/test/integration/get/testdata/to_be_injected_application.yaml deleted file mode 100644 index 79fcde82e4b79..0000000000000 --- a/test/integration/get/testdata/to_be_injected_application.yaml +++ /dev/null @@ -1,47 +0,0 @@ ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: cli-get-test-d1 -spec: - replicas: 2 - selector: - matchLabels: - app: cli-get-test-d1 - template: - metadata: - labels: - app: cli-get-test-d1 - spec: - containers: - - name: http-to-grpc - image: buoyantio/bb:v0.0.6 - args: ["terminus", "--grpc-server-port", "9090", "--response-text", "BANANA"] - ports: - - containerPort: 9090 - - name: http-to-grpc-2 - image: buoyantio/bb:v0.0.6 - args: ["terminus", "--grpc-server-port", "90", "--response-text", "BANANA"] - ports: - - containerPort: 90 ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: cli-get-test-d2 -spec: - replicas: 1 - selector: - matchLabels: - app: cli-get-test-d2 - template: - metadata: - labels: - app: cli-get-test-d2 - spec: - containers: - - name: http-to-grpc - image: buoyantio/bb:v0.0.6 - args: ["terminus", "--grpc-server-port", "90", "--response-text", "BANANA"] - ports: - - containerPort: 90