From 1bc71f33586ff3b4ae13a4505df8f956713ffe60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn?= Date: Thu, 21 Oct 2021 00:11:12 +0200 Subject: [PATCH] Add tests of multicluster install command (#7111) Currently there are no tests of the output of the multicluster install command unlike the install and viz install commands. This makes it error prone to hard to validate changes. This is motivated by the addition of an ha mode to the multicluster components discussed in #7082. This change adds two test cases and refactors the install command to look like viz install making it easily testable. This means in practice that the body of the command is moved into an install function. Here we extract external data, eg. values, and delegates the values to a render function that handles the actual rendering. This is a non-functional change and the output used for the install_default.golden file is based of the main branch to validate this. Signed-off-by: Crevil (cherry picked from commit fddfb749c1b1fc0d7421f0f8d4c48efbbd7e48a9) Signed-off-by: Oliver Gould --- multicluster/cmd/install.go | 173 ++++---- multicluster/cmd/install_test.go | 46 ++ multicluster/cmd/main_test.go | 23 + .../cmd/testdata/install_default.golden | 366 ++++++++++++++++ multicluster/cmd/testdata/install_psp.golden | 397 ++++++++++++++++++ 5 files changed, 922 insertions(+), 83 deletions(-) create mode 100644 multicluster/cmd/install_test.go create mode 100644 multicluster/cmd/main_test.go create mode 100644 multicluster/cmd/testdata/install_default.golden create mode 100644 multicluster/cmd/testdata/install_psp.golden diff --git a/multicluster/cmd/install.go b/multicluster/cmd/install.go index 638d432f447d0..dd6f1d1bfd3bc 100644 --- a/multicluster/cmd/install.go +++ b/multicluster/cmd/install.go @@ -5,6 +5,7 @@ import ( "context" "errors" "fmt" + "io" "os" "path" "time" @@ -68,89 +69,7 @@ A full list of configurable values can be found at https://github.com/linkerd/li APIAddr: apiAddr, RetryDeadline: time.Now().Add(wait), }) - - values, err := buildMulticlusterInstallValues(cmd.Context(), options) - - if err != nil { - return err - } - - // Render raw values and create chart config - rawValues, err := yaml.Marshal(values) - if err != nil { - return err - } - - files := []*chartloader.BufferedFile{ - {Name: chartutil.ChartfileName}, - {Name: "templates/namespace.yaml"}, - {Name: "templates/gateway.yaml"}, - {Name: "templates/proxy-admin-policy.yaml"}, - {Name: "templates/gateway-policy.yaml"}, - {Name: "templates/psp.yaml"}, - {Name: "templates/remote-access-service-mirror-rbac.yaml"}, - {Name: "templates/link-crd.yaml"}, - {Name: "templates/service-mirror-policy.yaml"}, - } - - var partialFiles []*loader.BufferedFile - for _, template := range charts.L5dPartials { - partialFiles = append(partialFiles, - &loader.BufferedFile{Name: template}, - ) - } - - // Load all multicluster install chart files into buffer - if err := charts.FilesReader(static.Templates, helmMulticlusterDefaultChartName+"/", files); err != nil { - return err - } - - // Load all partial chart files into buffer - if err := charts.FilesReader(partials.Templates, "", partialFiles); err != nil { - return err - } - - // Create a Chart obj from the files - chart, err := loader.LoadFiles(append(files, partialFiles...)) - if err != nil { - return err - } - - // Store final Values generated from values.yaml and CLI flags - err = yaml.Unmarshal(rawValues, &chart.Values) - if err != nil { - return err - } - - // Create values override - valuesOverrides, err := valuesOptions.MergeValues(nil) - if err != nil { - return err - } - - vals, err := chartutil.CoalesceValues(chart, valuesOverrides) - if err != nil { - return err - } - - // Attach the final values into the `Values` field for rendering to work - renderedTemplates, err := engine.Render(chart, map[string]interface{}{"Values": vals}) - if err != nil { - return err - } - - // Merge templates and inject - var buf bytes.Buffer - for _, tmpl := range chart.Templates { - t := path.Join(chart.Metadata.Name, tmpl.Name) - if _, err := buf.WriteString(renderedTemplates[t]); err != nil { - return err - } - } - stdout.Write(buf.Bytes()) - stdout.Write([]byte("---\n")) - - return nil + return install(cmd.Context(), stdout, options, valuesOptions) }, } @@ -178,6 +97,94 @@ A full list of configurable values can be found at https://github.com/linkerd/li return cmd } +func install(ctx context.Context, w io.Writer, options *multiclusterInstallOptions, valuesOptions valuespkg.Options) error { + values, err := buildMulticlusterInstallValues(ctx, options) + if err != nil { + return err + } + + // Create values override + valuesOverrides, err := valuesOptions.MergeValues(nil) + if err != nil { + return err + } + + return render(w, values, valuesOverrides) +} + +func render(w io.Writer, values *multicluster.Values, valuesOverrides map[string]interface{}) error { + files := []*chartloader.BufferedFile{ + {Name: chartutil.ChartfileName}, + {Name: chartutil.ValuesfileName}, + {Name: "templates/namespace.yaml"}, + {Name: "templates/gateway.yaml"}, + {Name: "templates/proxy-admin-policy.yaml"}, + {Name: "templates/gateway-policy.yaml"}, + {Name: "templates/psp.yaml"}, + {Name: "templates/remote-access-service-mirror-rbac.yaml"}, + {Name: "templates/link-crd.yaml"}, + {Name: "templates/service-mirror-policy.yaml"}, + } + + var partialFiles []*loader.BufferedFile + for _, template := range charts.L5dPartials { + partialFiles = append(partialFiles, + &loader.BufferedFile{Name: template}, + ) + } + + // Load all multicluster install chart files into buffer + if err := charts.FilesReader(static.Templates, helmMulticlusterDefaultChartName+"/", files); err != nil { + return err + } + + // Load all partial chart files into buffer + if err := charts.FilesReader(partials.Templates, "", partialFiles); err != nil { + return err + } + + // Create a Chart obj from the files + chart, err := loader.LoadFiles(append(files, partialFiles...)) + if err != nil { + return err + } + + // Render raw values and create chart config + rawValues, err := yaml.Marshal(values) + if err != nil { + return err + } + // Store final Values generated from values.yaml and CLI flags + err = yaml.Unmarshal(rawValues, &chart.Values) + if err != nil { + return err + } + + vals, err := chartutil.CoalesceValues(chart, valuesOverrides) + if err != nil { + return err + } + + // Attach the final values into the `Values` field for rendering to work + renderedTemplates, err := engine.Render(chart, map[string]interface{}{"Values": vals}) + if err != nil { + return err + } + + // Merge templates and inject + var buf bytes.Buffer + for _, tmpl := range chart.Templates { + t := path.Join(chart.Metadata.Name, tmpl.Name) + if _, err := buf.WriteString(renderedTemplates[t]); err != nil { + return err + } + } + w.Write(buf.Bytes()) + w.Write([]byte("---\n")) + + return nil +} + func newMulticlusterInstallOptionsWithDefault() (*multiclusterInstallOptions, error) { defaults, err := multicluster.NewInstallValues() if err != nil { diff --git a/multicluster/cmd/install_test.go b/multicluster/cmd/install_test.go new file mode 100644 index 0000000000000..849167a11acac --- /dev/null +++ b/multicluster/cmd/install_test.go @@ -0,0 +1,46 @@ +package cmd + +import ( + "bytes" + "fmt" + "testing" + + multicluster "github.com/linkerd/linkerd2/multicluster/values" + "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{}{} + + testCases := []struct { + values map[string]interface{} + multiclusterValues *multicluster.Values + goldenFileName string + }{ + { + nil, + nil, + "install_default.golden", + }, + { + map[string]interface{}{ + "enablePSP": "true", + }, + nil, + "install_psp.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, tc.multiclusterValues, 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/multicluster/cmd/main_test.go b/multicluster/cmd/main_test.go new file mode 100644 index 0000000000000..676a7e0af7e5d --- /dev/null +++ b/multicluster/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/multicluster/cmd/testdata/install_default.golden b/multicluster/cmd/testdata/install_default.golden new file mode 100644 index 0000000000000..816e50914b9aa --- /dev/null +++ b/multicluster/cmd/testdata/install_default.golden @@ -0,0 +1,366 @@ +kind: Namespace +apiVersion: v1 +metadata: + name: linkerd-multicluster + labels: + linkerd.io/extension: multicluster +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + annotations: + linkerd.io/created-by: linkerd/helm linkerdVersionValue + labels: + app.kubernetes.io/name: gateway + app.kubernetes.io/part-of: Linkerd + app.kubernetes.io/version: linkerdVersionValue + linkerd.io/control-plane-component: gateway + app: linkerd-gateway + linkerd.io/extension: multicluster + name: linkerd-gateway + namespace: linkerd-multicluster +spec: + replicas: 1 + selector: + matchLabels: + app: linkerd-gateway + template: + metadata: + annotations: + linkerd.io/created-by: linkerd/helm linkerdVersionValue + linkerd.io/inject: enabled + config.linkerd.io/proxy-require-identity-inbound-ports: "4143" + config.linkerd.io/enable-gateway: "true" + labels: + app: linkerd-gateway + spec: + containers: + - name: pause + image: gcr.io/google_containers/pause + serviceAccountName: linkerd-gateway +--- +apiVersion: v1 +kind: Service +metadata: + name: linkerd-gateway + namespace: linkerd-multicluster + labels: + linkerd.io/extension: multicluster + annotations: + mirror.linkerd.io/gateway-identity: linkerd-gateway.linkerd-multicluster.serviceaccount.identity.linkerd.cluster.local + mirror.linkerd.io/probe-period: "3" + mirror.linkerd.io/probe-path: /ready + mirror.linkerd.io/multicluster-gateway: "true" + linkerd.io/control-plane-component: gateway + linkerd.io/created-by: linkerd/helm linkerdVersionValue +spec: + ports: + - name: mc-gateway + port: 4143 + protocol: TCP + - name: mc-probe + port: 4191 + protocol: TCP + selector: + app: linkerd-gateway + type: LoadBalancer +--- +kind: ServiceAccount +apiVersion: v1 +metadata: + name: linkerd-gateway + namespace: linkerd-multicluster + labels: + linkerd.io/extension: multicluster +--- +apiVersion: policy.linkerd.io/v1beta1 +kind: Server +metadata: + namespace: linkerd-multicluster + name: gateway-proxy-admin + labels: + linkerd.io/extension: multicluster + annotations: + linkerd.io/created-by: linkerd/helm linkerdVersionValue +spec: + podSelector: + matchLabels: + app: linkerd-gateway + port: linkerd-admin + proxyProtocol: HTTP/1 +--- +apiVersion: policy.linkerd.io/v1beta1 +kind: ServerAuthorization +metadata: + namespace: linkerd-multicluster + name: proxy-admin + labels: + linkerd.io/extension: multicluster + annotations: + linkerd.io/created-by: linkerd/helm linkerdVersionValue +spec: + server: + name: gateway-proxy-admin + client: + # for kubelet probes + unauthenticated: true +--- +apiVersion: policy.linkerd.io/v1beta1 +kind: Server +metadata: + namespace: linkerd-multicluster + name: service-mirror-proxy-admin + labels: + linkerd.io/extension: multicluster +spec: + podSelector: + matchLabels: + linkerd.io/control-plane-component: linkerd-service-mirror + port: linkerd-admin + proxyProtocol: HTTP/1 +--- +apiVersion: policy.linkerd.io/v1beta1 +kind: ServerAuthorization +metadata: + namespace: linkerd-multicluster + name: service-mirror-proxy-admin + labels: + linkerd.io/extension: multicluster +spec: + server: + name: service-mirror-proxy-admin + client: + # for kubelet probes + unauthenticated: true +--- +apiVersion: policy.linkerd.io/v1beta1 +kind: Server +metadata: + namespace: linkerd-multicluster + name: linkerd-gateway + labels: + linkerd.io/extension: multicluster + app: linkerd-gateway + annotations: + linkerd.io/created-by: linkerd/helm linkerdVersionValue +spec: + podSelector: + matchLabels: + app: linkerd-gateway + port: linkerd-proxy + proxyProtocol: HTTP/1 +--- +apiVersion: policy.linkerd.io/v1beta1 +kind: ServerAuthorization +metadata: + namespace: linkerd-multicluster + name: linkerd-gateway + labels: + linkerd.io/extension: multicluster + app: linkerd-gateway + annotations: + linkerd.io/created-by: linkerd/helm linkerdVersionValue +spec: + server: + name: linkerd-gateway + client: + meshTLS: + identities: + - '*' + networks: + # Change this to the source cluster cidrs pointing to this gateway. + # Note that the source IP in some providers (e.g. GKE) will be the local + # node's IP and not the source cluster's + - cidr: 0.0.0.0/0 + - cidr: ::/0 +--- +apiVersion: policy.linkerd.io/v1beta1 +kind: ServerAuthorization +metadata: + namespace: linkerd-multicluster + name: linkerd-gateway-probe + labels: + linkerd.io/extension: multicluster + app: linkerd-gateway + annotations: + linkerd.io/created-by: linkerd/helm linkerdVersionValue +spec: + server: + name: gateway-proxy-admin + client: + # allows probes from outside the cluster, as long as they have an identity + meshTLS: + identities: + - '*' + networks: + # cf note for linkerd-gateway ServerAuthorization + - cidr: 0.0.0.0/0 + - cidr: ::/0 +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: linkerd-service-mirror-remote-access-default + namespace: linkerd-multicluster + labels: + linkerd.io/extension: multicluster + annotations: + linkerd.io/created-by: linkerd/helm linkerdVersionValue +rules: +- apiGroups: [""] + resources: ["services", "endpoints"] + verbs: ["list", "get", "watch"] +- apiGroups: [""] + resources: ["configmaps"] + verbs: ["get"] + resourceNames: ["linkerd-config"] +- apiGroups: [""] + resources: ["events"] + verbs: ["create", "patch"] +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: linkerd-service-mirror-remote-access-default + namespace: linkerd-multicluster + labels: + linkerd.io/extension: multicluster + annotations: + linkerd.io/created-by: linkerd/helm linkerdVersionValue +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: linkerd-service-mirror-remote-access-default + namespace: linkerd-multicluster + labels: + linkerd.io/extension: multicluster + annotations: + linkerd.io/created-by: linkerd/helm linkerdVersionValue +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: linkerd-service-mirror-remote-access-default +subjects: +- kind: ServiceAccount + name: linkerd-service-mirror-remote-access-default + namespace: linkerd-multicluster +--- +### +### Link CRD +### +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: links.multicluster.linkerd.io + labels: + linkerd.io/extension: multicluster + annotations: + linkerd.io/created-by: linkerd/helm linkerdVersionValue +spec: + group: multicluster.linkerd.io + versions: + - name: v1alpha1 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + clusterCredentialsSecret: + description: Kubernetes secret of target cluster + type: string + gatewayAddress: + description: Gateway address of target cluster + type: string + gatewayIdentity: + description: Gateway Identity FQDN + type: string + gatewayPort: + description: Gateway Port + type: string + probeSpec: + description: Spec for gateway health probe + type: object + properties: + path: + description: Path of remote gateway health endpoint + type: string + period: + description: Interval in between probe requests + type: string + port: + description: Port of remote gateway health endpoint + type: string + selector: + description: Kubernetes Label Selector + type: object + properties: + matchExpressions: + description: List of selector requirements + type: array + items: + description: A selector item requires a key and an operator + type: object + required: + - key + - operator + properties: + key: + description: Label key that selector should apply to + type: string + operator: + description: Evaluation of a label in relation to set + type: string + targetClusterName: + description: Name of target cluster to link to + type: string + targetClusterDomain: + description: Domain name of target cluster to link to + type: string + targetClusterLinkerdNamespace: + description: Name of namespace Linkerd control plane is installed in on target cluster + type: string + scope: Namespaced + names: + plural: links + singular: link + kind: Link +--- +apiVersion: policy.linkerd.io/v1beta1 +kind: Server +metadata: + namespace: linkerd-multicluster + name: service-mirror + labels: + linkerd.io/control-plane-component: linkerd-service-mirror +spec: + podSelector: + matchLabels: + linkerd.io/control-plane-component: linkerd-service-mirror + port: admin-http + proxyProtocol: HTTP/1 +--- +apiVersion: policy.linkerd.io/v1beta1 +kind: ServerAuthorization +metadata: + namespace: linkerd-multicluster + name: service-mirror + labels: + linkerd.io/control-plane-component: linkerd-service-mirror +spec: + server: + name: service-mirror + client: + # In order to use `linkerd mc gateways` you need viz' Prometheus instance + # to be able to reach the service-mirror. In order to also have a separate + # Prometheus scrape the service-mirror an additional ServerAuthorization + # resource should be created. + meshTLS: + serviceAccounts: + - name: prometheus + namespace: linkerd-viz +--- diff --git a/multicluster/cmd/testdata/install_psp.golden b/multicluster/cmd/testdata/install_psp.golden new file mode 100644 index 0000000000000..3cf9557f6047d --- /dev/null +++ b/multicluster/cmd/testdata/install_psp.golden @@ -0,0 +1,397 @@ +kind: Namespace +apiVersion: v1 +metadata: + name: linkerd-multicluster + labels: + linkerd.io/extension: multicluster +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + annotations: + linkerd.io/created-by: linkerd/helm linkerdVersionValue + labels: + app.kubernetes.io/name: gateway + app.kubernetes.io/part-of: Linkerd + app.kubernetes.io/version: linkerdVersionValue + linkerd.io/control-plane-component: gateway + app: linkerd-gateway + linkerd.io/extension: multicluster + name: linkerd-gateway + namespace: linkerd-multicluster +spec: + replicas: 1 + selector: + matchLabels: + app: linkerd-gateway + template: + metadata: + annotations: + linkerd.io/created-by: linkerd/helm linkerdVersionValue + linkerd.io/inject: enabled + config.linkerd.io/proxy-require-identity-inbound-ports: "4143" + config.linkerd.io/enable-gateway: "true" + labels: + app: linkerd-gateway + spec: + containers: + - name: pause + image: gcr.io/google_containers/pause + serviceAccountName: linkerd-gateway +--- +apiVersion: v1 +kind: Service +metadata: + name: linkerd-gateway + namespace: linkerd-multicluster + labels: + linkerd.io/extension: multicluster + annotations: + mirror.linkerd.io/gateway-identity: linkerd-gateway.linkerd-multicluster.serviceaccount.identity.linkerd.cluster.local + mirror.linkerd.io/probe-period: "3" + mirror.linkerd.io/probe-path: /ready + mirror.linkerd.io/multicluster-gateway: "true" + linkerd.io/control-plane-component: gateway + linkerd.io/created-by: linkerd/helm linkerdVersionValue +spec: + ports: + - name: mc-gateway + port: 4143 + protocol: TCP + - name: mc-probe + port: 4191 + protocol: TCP + selector: + app: linkerd-gateway + type: LoadBalancer +--- +kind: ServiceAccount +apiVersion: v1 +metadata: + name: linkerd-gateway + namespace: linkerd-multicluster + labels: + linkerd.io/extension: multicluster +--- +apiVersion: policy.linkerd.io/v1beta1 +kind: Server +metadata: + namespace: linkerd-multicluster + name: gateway-proxy-admin + labels: + linkerd.io/extension: multicluster + annotations: + linkerd.io/created-by: linkerd/helm linkerdVersionValue +spec: + podSelector: + matchLabels: + app: linkerd-gateway + port: linkerd-admin + proxyProtocol: HTTP/1 +--- +apiVersion: policy.linkerd.io/v1beta1 +kind: ServerAuthorization +metadata: + namespace: linkerd-multicluster + name: proxy-admin + labels: + linkerd.io/extension: multicluster + annotations: + linkerd.io/created-by: linkerd/helm linkerdVersionValue +spec: + server: + name: gateway-proxy-admin + client: + # for kubelet probes + unauthenticated: true +--- +apiVersion: policy.linkerd.io/v1beta1 +kind: Server +metadata: + namespace: linkerd-multicluster + name: service-mirror-proxy-admin + labels: + linkerd.io/extension: multicluster +spec: + podSelector: + matchLabels: + linkerd.io/control-plane-component: linkerd-service-mirror + port: linkerd-admin + proxyProtocol: HTTP/1 +--- +apiVersion: policy.linkerd.io/v1beta1 +kind: ServerAuthorization +metadata: + namespace: linkerd-multicluster + name: service-mirror-proxy-admin + labels: + linkerd.io/extension: multicluster +spec: + server: + name: service-mirror-proxy-admin + client: + # for kubelet probes + unauthenticated: true +--- +apiVersion: policy.linkerd.io/v1beta1 +kind: Server +metadata: + namespace: linkerd-multicluster + name: linkerd-gateway + labels: + linkerd.io/extension: multicluster + app: linkerd-gateway + annotations: + linkerd.io/created-by: linkerd/helm linkerdVersionValue +spec: + podSelector: + matchLabels: + app: linkerd-gateway + port: linkerd-proxy + proxyProtocol: HTTP/1 +--- +apiVersion: policy.linkerd.io/v1beta1 +kind: ServerAuthorization +metadata: + namespace: linkerd-multicluster + name: linkerd-gateway + labels: + linkerd.io/extension: multicluster + app: linkerd-gateway + annotations: + linkerd.io/created-by: linkerd/helm linkerdVersionValue +spec: + server: + name: linkerd-gateway + client: + meshTLS: + identities: + - '*' + networks: + # Change this to the source cluster cidrs pointing to this gateway. + # Note that the source IP in some providers (e.g. GKE) will be the local + # node's IP and not the source cluster's + - cidr: 0.0.0.0/0 + - cidr: ::/0 +--- +apiVersion: policy.linkerd.io/v1beta1 +kind: ServerAuthorization +metadata: + namespace: linkerd-multicluster + name: linkerd-gateway-probe + labels: + linkerd.io/extension: multicluster + app: linkerd-gateway + annotations: + linkerd.io/created-by: linkerd/helm linkerdVersionValue +spec: + server: + name: gateway-proxy-admin + client: + # allows probes from outside the cluster, as long as they have an identity + meshTLS: + identities: + - '*' + networks: + # cf note for linkerd-gateway ServerAuthorization + - cidr: 0.0.0.0/0 + - cidr: ::/0 +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: psp + namespace: linkerd-multicluster + labels: + linkerd.io/extension: multicluster +rules: +- apiGroups: ['policy', 'extensions'] + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: + - linkerd-linkerd-control-plane +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: multicluster-psp + namespace: linkerd-multicluster + labels: + linkerd.io/extension: multicluster + namespace: linkerd-multicluster +roleRef: + kind: Role + name: psp + apiGroup: rbac.authorization.k8s.io +subjects: +- kind: ServiceAccount + name: linkerd-gateway + namespace: linkerd-multicluster +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: linkerd-service-mirror-remote-access-default + namespace: linkerd-multicluster + labels: + linkerd.io/extension: multicluster + annotations: + linkerd.io/created-by: linkerd/helm linkerdVersionValue +rules: +- apiGroups: [""] + resources: ["services", "endpoints"] + verbs: ["list", "get", "watch"] +- apiGroups: [""] + resources: ["configmaps"] + verbs: ["get"] + resourceNames: ["linkerd-config"] +- apiGroups: [""] + resources: ["events"] + verbs: ["create", "patch"] +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: linkerd-service-mirror-remote-access-default + namespace: linkerd-multicluster + labels: + linkerd.io/extension: multicluster + annotations: + linkerd.io/created-by: linkerd/helm linkerdVersionValue +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: linkerd-service-mirror-remote-access-default + namespace: linkerd-multicluster + labels: + linkerd.io/extension: multicluster + annotations: + linkerd.io/created-by: linkerd/helm linkerdVersionValue +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: linkerd-service-mirror-remote-access-default +subjects: +- kind: ServiceAccount + name: linkerd-service-mirror-remote-access-default + namespace: linkerd-multicluster +--- +### +### Link CRD +### +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: links.multicluster.linkerd.io + labels: + linkerd.io/extension: multicluster + annotations: + linkerd.io/created-by: linkerd/helm linkerdVersionValue +spec: + group: multicluster.linkerd.io + versions: + - name: v1alpha1 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + clusterCredentialsSecret: + description: Kubernetes secret of target cluster + type: string + gatewayAddress: + description: Gateway address of target cluster + type: string + gatewayIdentity: + description: Gateway Identity FQDN + type: string + gatewayPort: + description: Gateway Port + type: string + probeSpec: + description: Spec for gateway health probe + type: object + properties: + path: + description: Path of remote gateway health endpoint + type: string + period: + description: Interval in between probe requests + type: string + port: + description: Port of remote gateway health endpoint + type: string + selector: + description: Kubernetes Label Selector + type: object + properties: + matchExpressions: + description: List of selector requirements + type: array + items: + description: A selector item requires a key and an operator + type: object + required: + - key + - operator + properties: + key: + description: Label key that selector should apply to + type: string + operator: + description: Evaluation of a label in relation to set + type: string + targetClusterName: + description: Name of target cluster to link to + type: string + targetClusterDomain: + description: Domain name of target cluster to link to + type: string + targetClusterLinkerdNamespace: + description: Name of namespace Linkerd control plane is installed in on target cluster + type: string + scope: Namespaced + names: + plural: links + singular: link + kind: Link +--- +apiVersion: policy.linkerd.io/v1beta1 +kind: Server +metadata: + namespace: linkerd-multicluster + name: service-mirror + labels: + linkerd.io/control-plane-component: linkerd-service-mirror +spec: + podSelector: + matchLabels: + linkerd.io/control-plane-component: linkerd-service-mirror + port: admin-http + proxyProtocol: HTTP/1 +--- +apiVersion: policy.linkerd.io/v1beta1 +kind: ServerAuthorization +metadata: + namespace: linkerd-multicluster + name: service-mirror + labels: + linkerd.io/control-plane-component: linkerd-service-mirror +spec: + server: + name: service-mirror + client: + # In order to use `linkerd mc gateways` you need viz' Prometheus instance + # to be able to reach the service-mirror. In order to also have a separate + # Prometheus scrape the service-mirror an additional ServerAuthorization + # resource should be created. + meshTLS: + serviceAccounts: + - name: prometheus + namespace: linkerd-viz +---