From c244df03b879076ddbae966de6ce75a10378034c Mon Sep 17 00:00:00 2001 From: Alex Leong Date: Mon, 29 Jun 2020 12:06:13 -0700 Subject: [PATCH 01/14] Add Link CRD Signed-off-by: Alex Leong --- .../templates/link-crd.yaml | 22 ++ cli/cmd/multicluster.go | 44 +++- .../cmd/service-mirror/events_formatting.go | 10 +- .../cmd/service-mirror/probe_manager.go | 30 +-- controller/cmd/service-mirror/probe_worker.go | 20 +- pkg/multicluster/link.go | 203 ++++++++++++++++++ 6 files changed, 292 insertions(+), 37 deletions(-) create mode 100644 charts/linkerd2-multicluster/templates/link-crd.yaml create mode 100644 pkg/multicluster/link.go diff --git a/charts/linkerd2-multicluster/templates/link-crd.yaml b/charts/linkerd2-multicluster/templates/link-crd.yaml new file mode 100644 index 0000000000000..c2efffa956377 --- /dev/null +++ b/charts/linkerd2-multicluster/templates/link-crd.yaml @@ -0,0 +1,22 @@ +--- +### +### Link CRD +### +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: links.multicluster.linkerd.io + annotations: + {{.Values.createdByAnnotation}}: {{default (printf "linkerd/helm %s" .Values.linkerdVersion) .Values.cliVersion}} +spec: + group: multicluster.linkerd.io + versions: + - name: v1alpha1 + served: true + storage: true + scope: Namespaced + names: + plural: links + singular: link + kind: Link diff --git a/cli/cmd/multicluster.go b/cli/cmd/multicluster.go index f6a50b9762ba7..346a1d9fec31f 100644 --- a/cli/cmd/multicluster.go +++ b/cli/cmd/multicluster.go @@ -18,6 +18,7 @@ import ( mccharts "github.com/linkerd/linkerd2/pkg/charts/multicluster" "github.com/linkerd/linkerd2/pkg/healthcheck" "github.com/linkerd/linkerd2/pkg/k8s" + mc "github.com/linkerd/linkerd2/pkg/multicluster" "github.com/linkerd/linkerd2/pkg/version" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -34,6 +35,7 @@ import ( const ( defaultMulticlusterNamespace = "linkerd-multicluster" + defaultGatewayName = "linkerd-gateway" helmMulticlusterDefaultChartName = "linkerd2-multicluster" tokenKey = "token" defaultServiceAccountName = "linkerd-service-mirror-remote-access-default" @@ -67,6 +69,8 @@ type ( clusterName string apiServerAddress string serviceAccountName string + gatewayName string + gatewayNamespace string } exportServiceOptions struct { @@ -338,6 +342,7 @@ func newMulticlusterInstallCommand() *cobra.Command { {Name: "templates/gateway.yaml"}, {Name: "templates/service-mirror.yaml"}, {Name: "templates/remote-access-service-mirror-rbac.yaml"}, + {Name: "templates/link-crd.yaml"}, } chart := &charts.Chart{ @@ -497,11 +502,44 @@ func newLinkCommand() *cobra.Command { }, } - out, err := yaml.Marshal(creds) + credsOut, err := yaml.Marshal(creds) if err != nil { return err } - fmt.Println(string(out)) + + gateway, err := k.CoreV1().Services(opts.gatewayNamespace).Get(opts.gatewayName, metav1.GetOptions{}) + if err != nil { + return err + } + + gatewayAddresses := []string{} + for _, ingress := range gateway.Status.LoadBalancer.Ingress { + gatewayAddresses = append(gatewayAddresses, ingress.IP) + } + + probeSpec, err := mc.ExtractProbeSpec(gateway) + if err != nil { + return err + } + + link := mc.Link{ + TargetClusterName: opts.clusterName, + TargetClusterDomain: configMap.Global.ClusterDomain, + TargetClusterLinkerdNamespace: controlPlaneNamespace, + ClusterCredentialsSecret: fmt.Sprintf("cluster-credentials-%s", opts.clusterName), + GatewayAddress: strings.Join(gatewayAddresses, ","), + GatewayIdentity: gateway.Annotations[k8s.GatewayIdentity], + ProbeSpec: probeSpec, + } + + linkOut, err := yaml.Marshal(link.ToUnstructured(opts.clusterName, opts.namespace).Object) + if err != nil { + return err + } + + fmt.Println(string(credsOut)) + fmt.Println("---") + fmt.Println(string(linkOut)) return nil }, @@ -511,6 +549,8 @@ func newLinkCommand() *cobra.Command { cmd.Flags().StringVar(&opts.clusterName, "cluster-name", "", "Cluster name") cmd.Flags().StringVar(&opts.apiServerAddress, "api-server-address", "", "The api server address of the target cluster") cmd.Flags().StringVar(&opts.serviceAccountName, "service-account-name", defaultServiceAccountName, "The name of the service account associated with the credentials") + cmd.Flags().StringVar(&opts.gatewayName, "gateway-name", defaultGatewayName, "The name of the gateway service") + cmd.Flags().StringVar(&opts.gatewayNamespace, "gateway-namespace", defaultMulticlusterNamespace, "The namespace of the gateway service") return cmd } diff --git a/controller/cmd/service-mirror/events_formatting.go b/controller/cmd/service-mirror/events_formatting.go index 02058024c54d3..737e4b5fb8439 100644 --- a/controller/cmd/service-mirror/events_formatting.go +++ b/controller/cmd/service-mirror/events_formatting.go @@ -117,14 +117,8 @@ func (re RepairEndpoints) String() string { return "RepairEndpoints" } -//Events for probe manager - -func (ps probeSpec) String() string { - return fmt.Sprintf("ProbeSpec: {path: %s, port: %d, period: %d}", ps.path, ps.port, ps.periodInSeconds) -} - func (gmc GatewayMirrorCreated) String() string { - return fmt.Sprintf("GatewayMirrorCreated: {gatewayName: %s, gatewayNamespace: %s, clusterName: %s, probeSpec: %s}", gmc.gatewayName, gmc.gatewayNamespace, gmc.clusterName, gmc.probeSpec) + return fmt.Sprintf("GatewayMirrorCreated: {gatewayName: %s, gatewayNamespace: %s, clusterName: %s, probeSpec: %s}", gmc.gatewayName, gmc.gatewayNamespace, gmc.clusterName, gmc.ProbeSpec) } func (gmd GatewayMirrorDeleted) String() string { @@ -132,5 +126,5 @@ func (gmd GatewayMirrorDeleted) String() string { } func (gmu GatewayMirrorUpdated) String() string { - return fmt.Sprintf("GatewayMirrorUpdated: {gatewayName: %s, gatewayNamespace: %s, clusterName: %s, probeSpec: %s}", gmu.gatewayName, gmu.gatewayNamespace, gmu.clusterName, gmu.probeSpec) + return fmt.Sprintf("GatewayMirrorUpdated: {gatewayName: %s, gatewayNamespace: %s, clusterName: %s, probeSpec: %s}", gmu.gatewayName, gmu.gatewayNamespace, gmu.clusterName, gmu.ProbeSpec) } diff --git a/controller/cmd/service-mirror/probe_manager.go b/controller/cmd/service-mirror/probe_manager.go index c2b850fedea7a..efdae03166db4 100644 --- a/controller/cmd/service-mirror/probe_manager.go +++ b/controller/cmd/service-mirror/probe_manager.go @@ -3,8 +3,10 @@ package servicemirror import ( "fmt" "strconv" + "time" consts "github.com/linkerd/linkerd2/pkg/k8s" + "github.com/linkerd/linkerd2/pkg/multicluster" "github.com/prometheus/client_golang/prometheus" log "github.com/sirupsen/logrus" corev1 "k8s.io/api/core/v1" @@ -27,7 +29,7 @@ type GatewayMirrorCreated struct { gatewayName string gatewayNamespace string clusterName string - probeSpec + multicluster.ProbeSpec } // GatewayMirrorDeleted is emitted when a mirror of a remote gateway is deleted @@ -42,7 +44,7 @@ type GatewayMirrorUpdated struct { gatewayName string gatewayNamespace string clusterName string - probeSpec + multicluster.ProbeSpec } // NewProbeManager creates a new probe manager @@ -102,7 +104,7 @@ func (m *ProbeManager) handleGatewayMirrorCreated(event *GatewayMirrorCreated) { worker, ok := m.probeWorkers[probeKey] if ok { log.Infof("There is already a probe worker for %s. Updating instead of creating", probeKey) - worker.UpdateProbeSpec(&event.probeSpec) + worker.UpdateProbeSpec(&event.ProbeSpec) } else { log.Infof("Creating probe worker %s", probeKey) probeMetrics, err := m.metricVecs.newWorkerMetrics(event.gatewayNamespace, event.gatewayName, event.clusterName) @@ -110,7 +112,7 @@ func (m *ProbeManager) handleGatewayMirrorCreated(event *GatewayMirrorCreated) { log.Errorf("Could not crete probe metrics: %s", err) } else { localGatewayName := fmt.Sprintf("%s-%s", event.gatewayName, event.clusterName) - worker = NewProbeWorker(localGatewayName, &event.probeSpec, probeMetrics, probeKey) + worker = NewProbeWorker(localGatewayName, &event.ProbeSpec, probeMetrics, probeKey) m.probeWorkers[probeKey] = worker worker.Start() } @@ -121,8 +123,8 @@ func (m *ProbeManager) handleGatewayMirrorUpdated(event *GatewayMirrorUpdated) { probeKey := probeKey(event.gatewayNamespace, event.gatewayName, event.clusterName) worker, ok := m.probeWorkers[probeKey] if ok { - if worker.probeSpec.port != event.port || worker.probeSpec.periodInSeconds != event.periodInSeconds || worker.probeSpec.path != event.path { - worker.UpdateProbeSpec(&event.probeSpec) + if worker.probeSpec.Port != event.Port || worker.probeSpec.Period != event.Period || worker.probeSpec.Path != event.Path { + worker.UpdateProbeSpec(&event.ProbeSpec) } } else { log.Infof("Could not find a worker for %s while handling GatewayMirrorUpdated event", probeKey) @@ -155,7 +157,7 @@ func (m *ProbeManager) run() { } } -func extractProbeSpec(svc *corev1.Service) (*probeSpec, error) { +func extractProbeSpec(svc *corev1.Service) (*multicluster.ProbeSpec, error) { path, hasPath := svc.Annotations[consts.MirroredGatewayProbePath] if !hasPath { return nil, fmt.Errorf("mirrored Gateway service is missing %s annotation", consts.MirroredGatewayProbePath) @@ -171,15 +173,15 @@ func extractProbeSpec(svc *corev1.Service) (*probeSpec, error) { return nil, fmt.Errorf("mirrored Gateway service is missing %s annotation", consts.MirroredGatewayProbePeriod) } - probePeriod, err := strconv.ParseUint(period, 10, 32) + probePeriodSeconds, err := strconv.ParseUint(period, 10, 32) if err != nil { return nil, err } - return &probeSpec{ - path: path, - port: probePort, - periodInSeconds: uint32(probePeriod), + return &multicluster.ProbeSpec{ + Path: path, + Port: uint32(probePort), + Period: time.Duration(probePeriodSeconds) * time.Second, }, nil } @@ -216,7 +218,7 @@ func (m *ProbeManager) Start() { gatewayName: service.Annotations[consts.MirroredGatewayRemoteName], gatewayNamespace: service.Annotations[consts.MirroredGatewayRemoteNameSpace], clusterName: service.Labels[consts.RemoteClusterNameLabel], - probeSpec: *spec, + ProbeSpec: *spec, }) } }, @@ -254,7 +256,7 @@ func (m *ProbeManager) Start() { gatewayName: newService.Annotations[consts.MirroredGatewayRemoteName], gatewayNamespace: newService.Annotations[consts.MirroredGatewayRemoteNameSpace], clusterName: newService.Labels[consts.RemoteClusterNameLabel], - probeSpec: *spec, + ProbeSpec: *spec, }) } } diff --git a/controller/cmd/service-mirror/probe_worker.go b/controller/cmd/service-mirror/probe_worker.go index 62a4afbb42e35..ed349c434b2b1 100644 --- a/controller/cmd/service-mirror/probe_worker.go +++ b/controller/cmd/service-mirror/probe_worker.go @@ -6,30 +6,25 @@ import ( "sync" "time" + "github.com/linkerd/linkerd2/pkg/multicluster" "github.com/prometheus/client_golang/prometheus" logging "github.com/sirupsen/logrus" ) const httpGatewayTimeoutMillis = 50000 -type probeSpec struct { - path string - port uint32 - periodInSeconds uint32 -} - // ProbeWorker is responsible for monitoring gateways using a probe specification type ProbeWorker struct { localGatewayName string *sync.RWMutex - probeSpec *probeSpec + probeSpec *multicluster.ProbeSpec stopCh chan struct{} metrics *probeMetrics log *logging.Entry } // NewProbeWorker creates a new probe worker associated with a particular gateway -func NewProbeWorker(localGatewayName string, spec *probeSpec, metrics *probeMetrics, probekey string) *ProbeWorker { +func NewProbeWorker(localGatewayName string, spec *multicluster.ProbeSpec, metrics *probeMetrics, probekey string) *ProbeWorker { return &ProbeWorker{ localGatewayName: localGatewayName, RWMutex: &sync.RWMutex{}, @@ -43,7 +38,7 @@ func NewProbeWorker(localGatewayName string, spec *probeSpec, metrics *probeMetr } // UpdateProbeSpec is used to update the probe specification when something about the gateway changes -func (pw *ProbeWorker) UpdateProbeSpec(spec *probeSpec) { +func (pw *ProbeWorker) UpdateProbeSpec(spec *multicluster.ProbeSpec) { pw.Lock() pw.probeSpec = spec pw.Unlock() @@ -63,9 +58,8 @@ func (pw *ProbeWorker) Start() { } func (pw *ProbeWorker) run() { - periodInMillis := pw.probeSpec.periodInSeconds * 1000 - probeTickerPeriod := time.Duration(periodInMillis) * time.Millisecond - maxJitter := time.Duration(periodInMillis/10) * time.Millisecond // max jitter is 10% of period + probeTickerPeriod := pw.probeSpec.Period + maxJitter := pw.probeSpec.Period / 10 // max jitter is 10% of period probeTicker := NewTicker(probeTickerPeriod, maxJitter) probeLoop: @@ -90,7 +84,7 @@ func (pw *ProbeWorker) doProbe() { Timeout: httpGatewayTimeoutMillis * time.Millisecond, } - req, err := http.NewRequest("GET", fmt.Sprintf("http://%s:%d/%s", pw.localGatewayName, pw.probeSpec.port, pw.probeSpec.path), nil) + req, err := http.NewRequest("GET", fmt.Sprintf("http://%s:%d/%s", pw.localGatewayName, pw.probeSpec.Port, pw.probeSpec.Path), nil) if err != nil { pw.log.Errorf("Could not create a GET request to gateway: %s", err) return diff --git a/pkg/multicluster/link.go b/pkg/multicluster/link.go new file mode 100644 index 0000000000000..7376ce2c62594 --- /dev/null +++ b/pkg/multicluster/link.go @@ -0,0 +1,203 @@ +package multicluster + +import ( + "errors" + "fmt" + "strconv" + "time" + + consts "github.com/linkerd/linkerd2/pkg/k8s" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" +) + +type ( + // ProbeSpec x + ProbeSpec struct { + Path string + Port uint32 + Period time.Duration + } + + // Link x + Link struct { + TargetClusterName string + TargetClusterDomain string + TargetClusterLinkerdNamespace string + ClusterCredentialsSecret string + GatewayAddress string + GatewayIdentity string + ProbeSpec ProbeSpec + } +) + +func (ps ProbeSpec) String() string { + return fmt.Sprintf("ProbeSpec: {path: %s, port: %d, period: %s}", ps.Path, ps.Port, ps.Period) +} + +func NewLink(u unstructured.Unstructured) (Link, error) { + + spec, ok := u.Object["spec"] + if !ok { + return Link{}, errors.New("Field 'spec' is missing") + } + specObj, ok := spec.(map[string]interface{}) + if !ok { + return Link{}, errors.New("Field 'spec' is not an object") + } + + ps, ok := specObj["probeSpec"] + if !ok { + return Link{}, errors.New("Field 'probeSpec' is missing") + } + psObj, ok := ps.(map[string]interface{}) + if !ok { + return Link{}, errors.New("Field 'probeSpec' it not an object") + } + + probeSpec, err := newProbeSpec(psObj) + if err != nil { + return Link{}, err + } + + targetClusterName, err := stringField(specObj, "targetClusterName") + if err != nil { + return Link{}, err + } + + targetClusterDomain, err := stringField(specObj, "targetClusterDomain") + if err != nil { + return Link{}, err + } + + targetClusterLinkerdNamespace, err := stringField(specObj, "targetClusterLinkerdDomain") + if err != nil { + return Link{}, err + } + + clusterCredentialsSecret, err := stringField(specObj, "clusterCredentialsSecret") + if err != nil { + return Link{}, err + } + + gatewayAddress, err := stringField(specObj, "gatewayAddress") + if err != nil { + return Link{}, err + } + + gatewayIdentity, err := stringField(specObj, "gatewayIdentity") + if err != nil { + return Link{}, err + } + + return Link{ + TargetClusterName: targetClusterName, + TargetClusterDomain: targetClusterDomain, + TargetClusterLinkerdNamespace: targetClusterLinkerdNamespace, + ClusterCredentialsSecret: clusterCredentialsSecret, + GatewayAddress: gatewayAddress, + GatewayIdentity: gatewayIdentity, + ProbeSpec: probeSpec, + }, nil +} + +func (l Link) ToUnstructured(name, namespace string) unstructured.Unstructured { + return unstructured.Unstructured{ + + Object: map[string]interface{}{ + "apiVersion": "multicluster.linkerd.io/v1alpha1", + "kind": "Link", + "metadata": map[string]interface{}{ + "name": name, + "namespace": namespace, + }, + "spec": map[string]interface{}{ + "targetClusterName": l.TargetClusterName, + "targetClusterDomain": l.TargetClusterDomain, + "targetClusterLinkerdNamespace": l.TargetClusterLinkerdNamespace, + "clusterCredentialsSecret": l.ClusterCredentialsSecret, + "gatewayAddress": l.GatewayAddress, + "probeSpec": map[string]interface{}{ + "path": l.ProbeSpec.Path, + "port": fmt.Sprintf("%d", l.ProbeSpec.Port), + "period": l.ProbeSpec.Period.String(), + }, + }, + }, + } +} + +func ExtractProbeSpec(gateway *corev1.Service) (ProbeSpec, error) { + path := gateway.Annotations[consts.GatewayProbePath] + if path == "" { + return ProbeSpec{}, errors.New("probe path is empty") + } + + port, err := extractPort(gateway.Spec.Ports, consts.ProbePortName) + if err != nil { + return ProbeSpec{}, err + } + + period, err := strconv.ParseUint(gateway.Annotations[consts.GatewayProbePeriod], 10, 32) + if err != nil { + return ProbeSpec{}, err + } + + return ProbeSpec{ + Path: path, + Port: port, + Period: time.Duration(period) * time.Second, + }, nil +} + +func extractPort(port []corev1.ServicePort, portName string) (uint32, error) { + for _, p := range port { + if p.Name == portName { + return uint32(p.Port), nil + } + } + return 0, fmt.Errorf("could not find port with name %s", portName) +} + +func newProbeSpec(obj map[string]interface{}) (ProbeSpec, error) { + periodStr, err := stringField(obj, "period") + if err != nil { + return ProbeSpec{}, err + } + period, err := time.ParseDuration(periodStr) + if err != nil { + return ProbeSpec{}, err + } + + path, err := stringField(obj, "path") + if err != nil { + return ProbeSpec{}, err + } + + portStr, err := stringField(obj, "port") + if err != nil { + return ProbeSpec{}, err + } + port, err := strconv.ParseUint(portStr, 10, 32) + if err != nil { + return ProbeSpec{}, err + } + + return ProbeSpec{ + Path: path, + Port: uint32(port), + Period: period, + }, nil +} + +func stringField(obj map[string]interface{}, key string) (string, error) { + value, ok := obj[key] + if !ok { + return "", fmt.Errorf("Field '%s' is missing", key) + } + str, ok := value.(string) + if !ok { + return "", fmt.Errorf("Field '%s' is not a string", key) + } + return str, nil +} From 87824843d898afabb09eed850fce950eaa1fa525 Mon Sep 17 00:00:00 2001 From: Alex Leong Date: Mon, 29 Jun 2020 16:13:48 -0700 Subject: [PATCH 02/14] Move service mirror to link command Signed-off-by: Alex Leong --- .../templates/service-mirror.yaml | 28 ++-- cli/cmd/multicluster.go | 140 +++++++++++++----- pkg/charts/multicluster/values.go | 1 + 3 files changed, 115 insertions(+), 54 deletions(-) diff --git a/charts/linkerd2-multicluster/templates/service-mirror.yaml b/charts/linkerd2-multicluster/templates/service-mirror.yaml index cd797bb7fc2e7..c11256036caca 100644 --- a/charts/linkerd2-multicluster/templates/service-mirror.yaml +++ b/charts/linkerd2-multicluster/templates/service-mirror.yaml @@ -3,7 +3,7 @@ kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: - name: linkerd-service-mirror-access-local-resources + name: linkerd-service-mirror-access-local-resources-{{.Values.targetClusterName}} labels: {{.Values.controllerComponentLabel}}: linkerd-service-mirror rules: @@ -17,50 +17,51 @@ rules: kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: - name: linkerd-service-mirror-access-local-resources + name: linkerd-service-mirror-access-local-resources-{{.Values.targetClusterName}} labels: {{.Values.controllerComponentLabel}}: linkerd-service-mirror roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: linkerd-service-mirror-access-local-resources + name: linkerd-service-mirror-access-local-resources-{{.Values.targetClusterName}} subjects: - kind: ServiceAccount - name: linkerd-service-mirror + name: linkerd-service-mirror-{{.Values.targetClusterName}} namespace: {{.Values.namespace}} --- kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: - name: linkerd-service-mirror-read-remote-creds + name: linkerd-service-mirror-read-remote-creds-{{.Values.targetClusterName}} namespace: {{.Values.namespace}} labels: {{.Values.controllerComponentLabel}}: linkerd-service-mirror rules: - apiGroups: [""] resources: ["secrets"] + resourceNames: ["{{.Values.targetClusterName}}"] verbs: ["list", "get", "watch"] --- kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: - name: linkerd-service-mirror-read-remote-creds + name: linkerd-service-mirror-read-remote-creds-{{.Values.targetClusterName}} namespace: {{.Values.namespace}} labels: {{.Values.controllerComponentLabel}}: linkerd-service-mirror roleRef: apiGroup: rbac.authorization.k8s.io kind: Role - name: linkerd-service-mirror-read-remote-creds + name: linkerd-service-mirror-read-remote-creds-{{.Values.targetClusterName}} subjects: - kind: ServiceAccount - name: linkerd-service-mirror + name: linkerd-service-mirror-{{.Values.targetClusterName}} namespace: {{.Values.namespace}} --- kind: ServiceAccount apiVersion: v1 metadata: - name: linkerd-service-mirror + name: linkerd-service-mirror-{{.Values.targetClusterName}} namespace: {{.Values.namespace}} labels: {{.Values.controllerComponentLabel}}: linkerd-service-mirror @@ -70,19 +71,19 @@ kind: Deployment metadata: labels: {{.Values.controllerComponentLabel}}: linkerd-service-mirror - name: linkerd-service-mirror + name: linkerd-service-mirror-{{.Values.targetClusterName}} namespace: {{.Values.namespace}} spec: replicas: 1 selector: matchLabels: - {{.Values.controllerComponentLabel}}: linkerd-service-mirror + {{.Values.controllerComponentLabel}}: linkerd-service-mirror-{{.Values.targetClusterName}} template: metadata: annotations: linkerd.io/inject: enabled labels: - {{.Values.controllerComponentLabel}}: linkerd-service-mirror + {{.Values.controllerComponentLabel}}: linkerd-service-mirror-{{.Values.targetClusterName}} spec: containers: - args: @@ -90,6 +91,7 @@ spec: - -log-level={{.Values.logLevel}} - -event-requeue-limit={{.Values.serviceMirrorRetryLimit}} - -namespace={{.Values.namespace}} + - {{.Values.targetClusterName}} image: {{.Values.controllerImage}}:{{.Values.controllerImageVersion}} name: service-mirror securityContext: @@ -97,5 +99,5 @@ spec: ports: - containerPort: 9999 name: admin-http - serviceAccountName: linkerd-service-mirror + serviceAccountName: linkerd-service-mirror-{{.Values.targetClusterName}} {{end -}} diff --git a/cli/cmd/multicluster.go b/cli/cmd/multicluster.go index 346a1d9fec31f..284a53cdb764c 100644 --- a/cli/cmd/multicluster.go +++ b/cli/cmd/multicluster.go @@ -54,23 +54,23 @@ type ( gatewayProbeSeconds uint32 gatewayProbePort uint32 namespace string - serviceMirror bool - serviceMirrorRetryLimit uint32 - logLevel string gatewayNginxImage string gatewayNginxVersion string - controlPlaneVersion string dockerRegistry string remoteMirrorCredentials bool } linkOptions struct { - namespace string - clusterName string - apiServerAddress string - serviceAccountName string - gatewayName string - gatewayNamespace string + namespace string + clusterName string + apiServerAddress string + serviceAccountName string + gatewayName string + gatewayNamespace string + serviceMirrorRetryLimit uint32 + logLevel string + controlPlaneVersion string + dockerRegistry string } exportServiceOptions struct { @@ -93,20 +93,27 @@ func newMulticlusterInstallOptionsWithDefault() (*multiclusterInstallOptions, er return &multiclusterInstallOptions{ gateway: defaults.Gateway, - gatewayPort: defaults.GatewayPort, - gatewayProbeSeconds: defaults.GatewayProbeSeconds, - gatewayProbePort: defaults.GatewayProbePort, namespace: defaults.Namespace, - serviceMirror: defaults.ServiceMirror, - serviceMirrorRetryLimit: defaults.ServiceMirrorRetryLimit, - logLevel: defaults.LogLevel, gatewayNginxImage: defaults.GatewayNginxImage, gatewayNginxVersion: defaults.GatewayNginxImageVersion, - controlPlaneVersion: version.Version, dockerRegistry: defaultDockerRegistry, remoteMirrorCredentials: true, }, nil +} +func newLinkOptionsWithDefault() (*linkOptions, error) { + defaults, err := mccharts.NewValues() + if err != nil { + return nil, err + } + + return &linkOptions{ + controlPlaneVersion: version.Version, + namespace: defaults.Namespace, + dockerRegistry: defaultDockerRegistry, + serviceMirrorRetryLimit: defaults.ServiceMirrorRetryLimit, + logLevel: defaults.LogLevel, + }, nil } func getLinkerdConfigMap() (*configPb.All, error) { @@ -123,15 +130,7 @@ func getLinkerdConfigMap() (*configPb.All, error) { return global, nil } -func buildMulticlusterInstallValues(opts *multiclusterInstallOptions) (*multicluster.Values, error) { - - global, err := getLinkerdConfigMap() - if err != nil { - if kerrors.IsNotFound(err) { - return nil, errors.New("you need Linkerd to be installed in order to install multicluster addons") - } - return nil, err - } +func buildServiceMirrorValues(opts *linkOptions) (*multicluster.Values, error) { if !alphaNumDashDot.MatchString(opts.controlPlaneVersion) { return nil, fmt.Errorf("%s is not a valid version", opts.controlPlaneVersion) @@ -154,8 +153,37 @@ func buildMulticlusterInstallValues(opts *multiclusterInstallOptions) (*multiclu return nil, err } - if opts.gatewayProbePort == defaults.GatewayLocalProbePort { - return nil, fmt.Errorf("The probe port needs to be different from %d which is the multicluster probe port", opts.gatewayProbePort) + defaults.TargetClusterName = opts.clusterName + defaults.Namespace = opts.namespace + defaults.ServiceMirrorRetryLimit = opts.serviceMirrorRetryLimit + defaults.LogLevel = opts.logLevel + defaults.ControllerImageVersion = opts.controlPlaneVersion + defaults.ControllerImage = fmt.Sprintf("%s/controller", opts.dockerRegistry) + + return defaults, nil +} + +func buildMulticlusterInstallValues(opts *multiclusterInstallOptions) (*multicluster.Values, error) { + + global, err := getLinkerdConfigMap() + if err != nil { + if kerrors.IsNotFound(err) { + return nil, errors.New("you need Linkerd to be installed in order to install multicluster addons") + } + return nil, err + } + + if opts.namespace == "" { + return nil, errors.New("you need to specify a namespace") + } + + if opts.namespace == controlPlaneNamespace { + return nil, errors.New("you need to setup the multicluster addons in a namespace different than the Linkerd one") + } + + defaults, err := mccharts.NewValues() + if err != nil { + return nil, err } defaults.Namespace = opts.namespace @@ -163,17 +191,12 @@ func buildMulticlusterInstallValues(opts *multiclusterInstallOptions) (*multiclu defaults.GatewayPort = opts.gatewayPort defaults.GatewayProbeSeconds = opts.gatewayProbeSeconds defaults.GatewayProbePort = opts.gatewayProbePort - defaults.ServiceMirror = opts.serviceMirror - defaults.ServiceMirrorRetryLimit = opts.serviceMirrorRetryLimit - defaults.LogLevel = opts.logLevel defaults.GatewayNginxImage = opts.gatewayNginxImage defaults.GatewayNginxImageVersion = opts.gatewayNginxVersion defaults.IdentityTrustDomain = global.Global.IdentityContext.TrustDomain defaults.LinkerdNamespace = controlPlaneNamespace defaults.ProxyOutboundPort = global.Proxy.OutboundPort.Port defaults.LinkerdVersion = version.Version - defaults.ControllerImageVersion = opts.controlPlaneVersion - defaults.ControllerImage = fmt.Sprintf("%s/controller", opts.dockerRegistry) defaults.RemoteMirrorServiceAccount = opts.remoteMirrorCredentials return defaults, nil @@ -368,12 +391,8 @@ func newMulticlusterInstallCommand() *cobra.Command { cmd.Flags().Uint32Var(&options.gatewayPort, "gateway-port", options.gatewayPort, "The port on the gateway used for all incoming traffic") cmd.Flags().Uint32Var(&options.gatewayProbeSeconds, "gateway-probe-seconds", options.gatewayProbeSeconds, "The interval at which the gateway will be checked for being alive in seconds") cmd.Flags().Uint32Var(&options.gatewayProbePort, "gateway-probe-port", options.gatewayProbePort, "The liveness check port of the gateway") - cmd.Flags().BoolVar(&options.serviceMirror, "service-mirror", options.serviceMirror, "If the service-mirror component should be installed") - cmd.Flags().Uint32Var(&options.serviceMirrorRetryLimit, "service-mirror-retry-limit", options.serviceMirrorRetryLimit, "The number of times a failed update from the target cluster is allowed to be retried") - cmd.Flags().StringVar(&options.logLevel, "log-level", options.logLevel, "Log level for the Multicluster components") cmd.Flags().StringVar(&options.gatewayNginxImage, "gateway-nginx-image", options.gatewayNginxImage, "The nginx image to be used") cmd.Flags().StringVar(&options.gatewayNginxVersion, "gateway-nginx-image-version", options.gatewayNginxVersion, "The version of nginx to be used") - cmd.Flags().StringVarP(&options.controlPlaneVersion, "control-plane-version", "", options.controlPlaneVersion, "(Development) Tag to be used for the control plane component images") cmd.Flags().StringVar(&options.dockerRegistry, "registry", options.dockerRegistry, "Docker registry to pull images from") cmd.Flags().BoolVar(&options.remoteMirrorCredentials, "service-mirror-credentials", options.remoteMirrorCredentials, "Whether to install the service account which can be used by service mirror components in source clusters to discover exported servivces") @@ -392,7 +411,11 @@ func newMulticlusterInstallCommand() *cobra.Command { } func newLinkCommand() *cobra.Command { - opts := linkOptions{} + opts, err := newLinkOptionsWithDefault() + if err != nil { + fmt.Fprintf(os.Stderr, "%s", err) + os.Exit(1) + } cmd := &cobra.Command{ Use: "link", @@ -537,9 +560,41 @@ func newLinkCommand() *cobra.Command { return err } - fmt.Println(string(credsOut)) - fmt.Println("---") - fmt.Println(string(linkOut)) + values, err := buildServiceMirrorValues(opts) + + if err != nil { + return err + } + + // Render raw values and create chart config + rawValues, err := yaml.Marshal(values) + if err != nil { + return err + } + + files := []*chartutil.BufferedFile{ + {Name: chartutil.ChartfileName}, + {Name: "templates/service-mirror.yaml"}, + } + + chart := &charts.Chart{ + Name: helmMulticlusterDefaultChartName, + Dir: helmMulticlusterDefaultChartName, + Namespace: controlPlaneNamespace, + RawValues: rawValues, + Files: files, + } + serviceMirrorOut, err := chart.RenderNoPartials() + if err != nil { + return err + } + + stdout.Write(credsOut) + stdout.Write([]byte("---\n")) + stdout.Write(linkOut) + stdout.Write([]byte("---\n")) + stdout.Write(serviceMirrorOut.Bytes()) + stdout.Write([]byte("---\n")) return nil }, @@ -549,8 +604,11 @@ func newLinkCommand() *cobra.Command { cmd.Flags().StringVar(&opts.clusterName, "cluster-name", "", "Cluster name") cmd.Flags().StringVar(&opts.apiServerAddress, "api-server-address", "", "The api server address of the target cluster") cmd.Flags().StringVar(&opts.serviceAccountName, "service-account-name", defaultServiceAccountName, "The name of the service account associated with the credentials") + cmd.Flags().StringVar(&opts.controlPlaneVersion, "control-plane-version", opts.controlPlaneVersion, "(Development) Tag to be used for the control plane component images") cmd.Flags().StringVar(&opts.gatewayName, "gateway-name", defaultGatewayName, "The name of the gateway service") cmd.Flags().StringVar(&opts.gatewayNamespace, "gateway-namespace", defaultMulticlusterNamespace, "The namespace of the gateway service") + cmd.Flags().Uint32Var(&opts.serviceMirrorRetryLimit, "service-mirror-retry-limit", opts.serviceMirrorRetryLimit, "The number of times a failed update from the target cluster is allowed to be retried") + cmd.Flags().StringVar(&opts.logLevel, "log-level", opts.logLevel, "Log level for the Multicluster components") return cmd } diff --git a/pkg/charts/multicluster/values.go b/pkg/charts/multicluster/values.go index 158265a50c2aa..2eccf9091758c 100644 --- a/pkg/charts/multicluster/values.go +++ b/pkg/charts/multicluster/values.go @@ -40,6 +40,7 @@ type Values struct { ServiceMirrorUID int64 `json:"serviceMirrorUID"` RemoteMirrorServiceAccount bool `json:"remoteMirrorServiceAccount"` RemoteMirrorServiceAccountName string `json:"remoteMirrorServiceAccountName"` + TargetClusterName string `json:"targetClusterName"` } // NewValues returns a new instance of the Values type. From c5fa0e53eb5d2c85adc1adea3a100a2261549e2b Mon Sep 17 00:00:00 2001 From: Alex Leong Date: Tue, 30 Jun 2020 15:58:22 -0700 Subject: [PATCH 03/14] Service mirror can read Link object Signed-off-by: Alex Leong --- .../templates/service-mirror.yaml | 5 +- cli/cmd/multicluster.go | 4 +- controller/cmd/service-mirror/main.go | 80 +++++-------------- pkg/flags/flags.go | 2 +- pkg/multicluster/link.go | 3 +- 5 files changed, 31 insertions(+), 63 deletions(-) diff --git a/charts/linkerd2-multicluster/templates/service-mirror.yaml b/charts/linkerd2-multicluster/templates/service-mirror.yaml index c11256036caca..913c7bd028020 100644 --- a/charts/linkerd2-multicluster/templates/service-mirror.yaml +++ b/charts/linkerd2-multicluster/templates/service-mirror.yaml @@ -39,7 +39,10 @@ metadata: rules: - apiGroups: [""] resources: ["secrets"] - resourceNames: ["{{.Values.targetClusterName}}"] + resourceNames: ["cluster-credentials-{{.Values.targetClusterName}}"] + verbs: ["list", "get", "watch"] + - apiGroups: ["multicluster.linkerd.io"] + resources: ["links"] verbs: ["list", "get", "watch"] --- kind: RoleBinding diff --git a/cli/cmd/multicluster.go b/cli/cmd/multicluster.go index 284a53cdb764c..21f82b56f266b 100644 --- a/cli/cmd/multicluster.go +++ b/cli/cmd/multicluster.go @@ -93,6 +93,9 @@ func newMulticlusterInstallOptionsWithDefault() (*multiclusterInstallOptions, er return &multiclusterInstallOptions{ gateway: defaults.Gateway, + gatewayPort: defaults.GatewayPort, + gatewayProbeSeconds: defaults.GatewayProbeSeconds, + gatewayProbePort: defaults.GatewayProbePort, namespace: defaults.Namespace, gatewayNginxImage: defaults.GatewayNginxImage, gatewayNginxVersion: defaults.GatewayNginxImageVersion, @@ -363,7 +366,6 @@ func newMulticlusterInstallCommand() *cobra.Command { {Name: chartutil.ChartfileName}, {Name: "templates/namespace.yaml"}, {Name: "templates/gateway.yaml"}, - {Name: "templates/service-mirror.yaml"}, {Name: "templates/remote-access-service-mirror-rbac.yaml"}, {Name: "templates/link-crd.yaml"}, } diff --git a/controller/cmd/service-mirror/main.go b/controller/cmd/service-mirror/main.go index 3fc6476e317a7..70271fc100e9c 100644 --- a/controller/cmd/service-mirror/main.go +++ b/controller/cmd/service-mirror/main.go @@ -1,101 +1,63 @@ package servicemirror import ( - "context" "flag" - "fmt" "os" "os/signal" "syscall" - "time" - "k8s.io/client-go/informers" - "k8s.io/client-go/tools/cache" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" - "github.com/linkerd/linkerd2/controller/k8s" "github.com/linkerd/linkerd2/pkg/admin" "github.com/linkerd/linkerd2/pkg/flags" + "github.com/linkerd/linkerd2/pkg/k8s" + "github.com/linkerd/linkerd2/pkg/multicluster" log "github.com/sirupsen/logrus" - "k8s.io/client-go/kubernetes" ) -func initLocalResourceInformer(api kubernetes.Interface, namespace string, resource k8s.APIResource) (cache.SharedIndexInformer, error) { - sharedInformers := informers.NewSharedInformerFactoryWithOptions(api, 10*time.Minute, informers.WithNamespace(namespace)) - - var informer cache.SharedIndexInformer - - switch resource { - case k8s.Svc: - informer = sharedInformers.Core().V1().Services().Informer() - case k8s.Secret: - informer = sharedInformers.Core().V1().Secrets().Informer() - default: - return nil, fmt.Errorf("cannot instantiate local informer for %v", resource) - - } - - sharedInformers.Start(nil) - - ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) - defer cancel() - - log.Infof("waiting for local namespaced %v informer caches to sync", resource) - if !cache.WaitForCacheSync(ctx.Done(), informer.HasSynced) { - return nil, fmt.Errorf("failed to sync local namespaced %v informer caches", resource) - } - log.Infof("local namespaced %v informer caches synced", resource) - return informer, nil -} - -// Main executes the tap service-mirror +// Main executes the service-mirror controller func Main(args []string) { cmd := flag.NewFlagSet("service-mirror", flag.ExitOnError) kubeConfigPath := cmd.String("kubeconfig", "", "path to the local kube config") - requeueLimit := cmd.Int("event-requeue-limit", 3, "requeue limit for events") + _ = cmd.Int("event-requeue-limit", 3, "requeue limit for events") metricsAddr := cmd.String("metrics-addr", ":9999", "address to serve scrapable metrics on") - namespace := cmd.String("namespace", "", "address to serve scrapable metrics on") - repairPeriod := cmd.Duration("endpoint-refresh-period", 1*time.Minute, "frequency to refresh endpoint resolution") + namespace := cmd.String("namespace", "", "namespace containing Link and credentials Secret") + //repairPeriod := cmd.Duration("endpoint-refresh-period", 1*time.Minute, "frequency to refresh endpoint resolution") flags.ConfigureAndParse(cmd, args) + linkName := cmd.Arg(0) stop := make(chan os.Signal, 1) signal.Notify(stop, os.Interrupt, syscall.SIGTERM) - k8sAPI, err := k8s.InitializeAPI( - *kubeConfigPath, - false, - k8s.Svc, - k8s.NS, - k8s.Endpoint, - ) + k8sAPI, err := k8s.NewAPI(*kubeConfigPath, "", "", []string{}, 0) //TODO: Use can-i to check for required permissions if err != nil { log.Fatalf("Failed to initialize K8s API: %s", err) } - secretsInformer, err := initLocalResourceInformer(k8sAPI.Client, *namespace, k8s.Secret) + gvr := schema.GroupVersionResource{ + Group: "multicluster.linkerd.io", + Version: "v1alpha1", + Resource: "links", + } + unstructured, err := k8sAPI.DynamicClient.Resource(gvr).Namespace(*namespace).Get(linkName, metav1.GetOptions{}) if err != nil { - log.Fatalf("Failed to initialize secret informer: %s", err) + log.Fatalf("Failed to fetch Link %s: %s", linkName, err) } - svcInformer, err := initLocalResourceInformer(k8sAPI.Client, *namespace, k8s.Svc) + link, err := multicluster.NewLink(*unstructured) if err != nil { - log.Fatalf("Failed to initialize service informer: %s", err) + log.Fatalf("Failed to parse Link %s: %s", linkName, err) } - probeManager := NewProbeManager(svcInformer) - probeManager.Start() - - k8sAPI.Sync(nil) - watcher := NewRemoteClusterConfigWatcher(*namespace, secretsInformer, k8sAPI, *requeueLimit, *repairPeriod) - log.Info("Started cluster config watcher") + log.Infof("Loaded Link %s: %+v", linkName, link) go admin.StartServer(*metricsAddr) <-stop - log.Info("Stopping cluster config watcher") - watcher.Stop() - probeManager.Stop() + log.Info("Stopping service mirror controller") } diff --git a/pkg/flags/flags.go b/pkg/flags/flags.go index a7ac7952d6b87..b7f74df2a8939 100644 --- a/pkg/flags/flags.go +++ b/pkg/flags/flags.go @@ -51,7 +51,7 @@ func setLogLevel(logLevel string) { if level == log.DebugLevel { flag.Set("stderrthreshold", "INFO") flag.Set("logtostderr", "true") - flag.Set("v", "6") // At 7 and higher, authorization tokens get logged. + flag.Set("v", "12") // At 7 and higher, authorization tokens get logged. // pipe klog entries to logrus klog.SetOutput(log.StandardLogger().Writer()) } diff --git a/pkg/multicluster/link.go b/pkg/multicluster/link.go index 7376ce2c62594..e2a9f463ff7f1 100644 --- a/pkg/multicluster/link.go +++ b/pkg/multicluster/link.go @@ -70,7 +70,7 @@ func NewLink(u unstructured.Unstructured) (Link, error) { return Link{}, err } - targetClusterLinkerdNamespace, err := stringField(specObj, "targetClusterLinkerdDomain") + targetClusterLinkerdNamespace, err := stringField(specObj, "targetClusterLinkerdNamespace") if err != nil { return Link{}, err } @@ -117,6 +117,7 @@ func (l Link) ToUnstructured(name, namespace string) unstructured.Unstructured { "targetClusterLinkerdNamespace": l.TargetClusterLinkerdNamespace, "clusterCredentialsSecret": l.ClusterCredentialsSecret, "gatewayAddress": l.GatewayAddress, + "gatewayIdentity": l.GatewayIdentity, "probeSpec": map[string]interface{}{ "path": l.ProbeSpec.Path, "port": fmt.Sprintf("%d", l.ProbeSpec.Port), From 127f3f0dfd5bb697c6bcdbd29c833dd903259eb1 Mon Sep 17 00:00:00 2001 From: Alex Leong Date: Thu, 2 Jul 2020 15:26:24 -0700 Subject: [PATCH 04/14] Basic service mirroring functionality works Signed-off-by: Alex Leong --- .../cmd/service-mirror/cluster_watcher.go | 2 +- controller/cmd/service-mirror/main.go | 112 ++++++++++++++++-- 2 files changed, 102 insertions(+), 12 deletions(-) diff --git a/controller/cmd/service-mirror/cluster_watcher.go b/controller/cmd/service-mirror/cluster_watcher.go index 883ab190e36fe..66b5f762dfec9 100644 --- a/controller/cmd/service-mirror/cluster_watcher.go +++ b/controller/cmd/service-mirror/cluster_watcher.go @@ -912,7 +912,7 @@ func (rcsw *RemoteClusterServiceWatcher) affectedMirroredServicesForGatewayUpdat affectedServices := []*corev1.Service{} for _, srv := range services { ver, ok := srv.Annotations[consts.RemoteGatewayResourceVersionAnnotation] - if ok && ver != latestResourceVersion { + if !ok || ver != latestResourceVersion { affectedServices = append(affectedServices, srv) } } diff --git a/controller/cmd/service-mirror/main.go b/controller/cmd/service-mirror/main.go index 70271fc100e9c..98a612b83909c 100644 --- a/controller/cmd/service-mirror/main.go +++ b/controller/cmd/service-mirror/main.go @@ -2,29 +2,38 @@ package servicemirror import ( "flag" + "fmt" "os" "os/signal" "syscall" + "time" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + dynamic "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/client-go/tools/clientcmd" + controllerK8s "github.com/linkerd/linkerd2/controller/k8s" "github.com/linkerd/linkerd2/pkg/admin" "github.com/linkerd/linkerd2/pkg/flags" "github.com/linkerd/linkerd2/pkg/k8s" "github.com/linkerd/linkerd2/pkg/multicluster" + "github.com/linkerd/linkerd2/pkg/servicemirror" log "github.com/sirupsen/logrus" ) +var clusterWatcher *RemoteClusterServiceWatcher + // Main executes the service-mirror controller func Main(args []string) { cmd := flag.NewFlagSet("service-mirror", flag.ExitOnError) kubeConfigPath := cmd.String("kubeconfig", "", "path to the local kube config") - _ = cmd.Int("event-requeue-limit", 3, "requeue limit for events") + requeueLimit := cmd.Int("event-requeue-limit", 3, "requeue limit for events") metricsAddr := cmd.String("metrics-addr", ":9999", "address to serve scrapable metrics on") namespace := cmd.String("namespace", "", "namespace containing Link and credentials Secret") - //repairPeriod := cmd.Duration("endpoint-refresh-period", 1*time.Minute, "frequency to refresh endpoint resolution") + repairPeriod := cmd.Duration("endpoint-refresh-period", 1*time.Minute, "frequency to refresh endpoint resolution") flags.ConfigureAndParse(cmd, args) linkName := cmd.Arg(0) @@ -33,31 +42,112 @@ func Main(args []string) { signal.Notify(stop, os.Interrupt, syscall.SIGTERM) k8sAPI, err := k8s.NewAPI(*kubeConfigPath, "", "", []string{}, 0) - //TODO: Use can-i to check for required permissions if err != nil { log.Fatalf("Failed to initialize K8s API: %s", err) } + controllerK8sAPI, err := controllerK8s.InitializeAPI(*kubeConfigPath, false, + controllerK8s.NS, + controllerK8s.Svc, + controllerK8s.Endpoint, + ) + if err != nil { + log.Fatalf("Failed to initialize K8s API: %s", err) + } + gvr := schema.GroupVersionResource{ Group: "multicluster.linkerd.io", Version: "v1alpha1", Resource: "links", } - unstructured, err := k8sAPI.DynamicClient.Resource(gvr).Namespace(*namespace).Get(linkName, metav1.GetOptions{}) + linkClient := k8sAPI.DynamicClient.Resource(gvr).Namespace(*namespace) + + go admin.StartServer(*metricsAddr) + + controllerK8sAPI.Sync(nil) + + // Start link watch + linkWatch, err := linkClient.Watch(metav1.ListOptions{}) if err != nil { - log.Fatalf("Failed to fetch Link %s: %s", linkName, err) + log.Fatalf("Failed to watch Link %s: %s", linkName, err) + } + results := linkWatch.ResultChan() + for { + select { + case event := <-results: + switch obj := event.Object.(type) { + case *dynamic.Unstructured: + if obj.GetName() == linkName { + switch event.Type { + case watch.Added, watch.Modified: + link, err := multicluster.NewLink(*obj) + if err != nil { + log.Errorf("Failed to parse link %s: %s", linkName, err) + continue + } + log.Infof("Got updated link %s: %+v", linkName, link) + creds, err := loadCredentials(link, *namespace, k8sAPI) + if err != nil { + log.Errorf("Failed to load remote cluster credentials: %s", err) + } + restartClusterWatcher(link, *namespace, creds, controllerK8sAPI, *requeueLimit, *repairPeriod) + case watch.Deleted: + log.Infof("Link %s deleted", linkName) + default: + log.Infof("Ignoring event type %s", event.Type) + } + } + default: + log.Errorf("Unknown object type detected: %+v", obj) + } + } } - link, err := multicluster.NewLink(*unstructured) +} +func loadCredentials(link multicluster.Link, namespace string, k8sAPI *k8s.KubernetesAPI) (*servicemirror.WatchedClusterConfig, error) { + // Load the credentials secret + secret, err := k8sAPI.Interface.CoreV1().Secrets(namespace).Get(link.ClusterCredentialsSecret, metav1.GetOptions{}) if err != nil { - log.Fatalf("Failed to parse Link %s: %s", linkName, err) + return nil, fmt.Errorf("Failed to load credentials secret %s: %s", link.ClusterCredentialsSecret, err) } + return servicemirror.ParseRemoteClusterSecret(secret) +} - log.Infof("Loaded Link %s: %+v", linkName, link) +func restartClusterWatcher( + link multicluster.Link, + namespace string, + creds *servicemirror.WatchedClusterConfig, + controllerK8sAPI *controllerK8s.API, + requeueLimit int, + repairPeriod time.Duration, +) { + if clusterWatcher != nil { + clusterWatcher.Stop(false) + } - go admin.StartServer(*metricsAddr) + cfg, err := clientcmd.RESTConfigFromKubeConfig(creds.APIConfig) + if err != nil { + log.Errorf("Unable to parse kube config: %s", err) + return + } - <-stop - log.Info("Stopping service mirror controller") + clusterWatcher, err = NewRemoteClusterServiceWatcher( + namespace, + controllerK8sAPI, + cfg, + link.TargetClusterName, + requeueLimit, + repairPeriod, + link.TargetClusterDomain, + ) + if err != nil { + log.Errorf("Unable to create cluster watcher: %s", err) + return + } + + err = clusterWatcher.Start() + if err != nil { + log.Errorf("Failed to start cluster watcher: %s", err) + } } From 0dedf3337f979d49c173b81c1319b59f14aa0fd4 Mon Sep 17 00:00:00 2001 From: Alex Leong Date: Thu, 2 Jul 2020 17:57:50 -0700 Subject: [PATCH 05/14] cleanup Signed-off-by: Alex Leong --- controller/cmd/service-mirror/main.go | 57 +++++++++++-------- .../cmd/service-mirror/probe_manager.go | 2 +- pkg/multicluster/link.go | 14 ++++- 3 files changed, 45 insertions(+), 28 deletions(-) diff --git a/controller/cmd/service-mirror/main.go b/controller/cmd/service-mirror/main.go index 98a612b83909c..228963bb03029 100644 --- a/controller/cmd/service-mirror/main.go +++ b/controller/cmd/service-mirror/main.go @@ -41,6 +41,12 @@ func Main(args []string) { stop := make(chan os.Signal, 1) signal.Notify(stop, os.Interrupt, syscall.SIGTERM) + // We create two different kubernetes API clients for the local cluster: + // k8sAPI is used as a dynamic client for unstrcutured access to Link custom + // resources. + // + // controllerK8sAPI is used by the cluster watcher to manage + // mirror resources such as services, namespaces, and endpoints. k8sAPI, err := k8s.NewAPI(*kubeConfigPath, "", "", []string{}, 0) //TODO: Use can-i to check for required permissions if err != nil { @@ -73,34 +79,35 @@ func Main(args []string) { log.Fatalf("Failed to watch Link %s: %s", linkName, err) } results := linkWatch.ResultChan() - for { - select { - case event := <-results: - switch obj := event.Object.(type) { - case *dynamic.Unstructured: - if obj.GetName() == linkName { - switch event.Type { - case watch.Added, watch.Modified: - link, err := multicluster.NewLink(*obj) - if err != nil { - log.Errorf("Failed to parse link %s: %s", linkName, err) - continue - } - log.Infof("Got updated link %s: %+v", linkName, link) - creds, err := loadCredentials(link, *namespace, k8sAPI) - if err != nil { - log.Errorf("Failed to load remote cluster credentials: %s", err) - } - restartClusterWatcher(link, *namespace, creds, controllerK8sAPI, *requeueLimit, *repairPeriod) - case watch.Deleted: - log.Infof("Link %s deleted", linkName) - default: - log.Infof("Ignoring event type %s", event.Type) + + // Each time the link resource is updated, reload the config and restart the + // cluster watcher. + for event := range results { + switch obj := event.Object.(type) { + case *dynamic.Unstructured: + if obj.GetName() == linkName { + switch event.Type { + case watch.Added, watch.Modified: + link, err := multicluster.NewLink(*obj) + if err != nil { + log.Errorf("Failed to parse link %s: %s", linkName, err) + continue + } + log.Infof("Got updated link %s: %+v", linkName, link) + creds, err := loadCredentials(link, *namespace, k8sAPI) + if err != nil { + log.Errorf("Failed to load remote cluster credentials: %s", err) } + restartClusterWatcher(link, *namespace, creds, controllerK8sAPI, *requeueLimit, *repairPeriod) + case watch.Deleted: + log.Infof("Link %s deleted", linkName) + // TODO: should we delete all mirror resources? + default: + log.Infof("Ignoring event type %s", event.Type) } - default: - log.Errorf("Unknown object type detected: %+v", obj) } + default: + log.Errorf("Unknown object type detected: %+v", obj) } } } diff --git a/controller/cmd/service-mirror/probe_manager.go b/controller/cmd/service-mirror/probe_manager.go index efdae03166db4..5a45da6288809 100644 --- a/controller/cmd/service-mirror/probe_manager.go +++ b/controller/cmd/service-mirror/probe_manager.go @@ -180,7 +180,7 @@ func extractProbeSpec(svc *corev1.Service) (*multicluster.ProbeSpec, error) { return &multicluster.ProbeSpec{ Path: path, - Port: uint32(probePort), + Port: probePort, Period: time.Duration(probePeriodSeconds) * time.Second, }, nil diff --git a/pkg/multicluster/link.go b/pkg/multicluster/link.go index e2a9f463ff7f1..d89529a740c08 100644 --- a/pkg/multicluster/link.go +++ b/pkg/multicluster/link.go @@ -12,14 +12,19 @@ import ( ) type ( - // ProbeSpec x + // ProbeSpec defines how a gateway should be queried for health. Once per + // period, the probe workers will send an HTTP request to the remote gateway + // on the given port with the given path and expect a HTTP 200 response. ProbeSpec struct { Path string Port uint32 Period time.Duration } - // Link x + // Link is an internal representation of the link.multicluster.linkerd.io + // custom resource. It defines a multicluster link to a gateway in a + // target cluster and is configures the behavior of a service mirror + // controller. Link struct { TargetClusterName string TargetClusterDomain string @@ -35,6 +40,8 @@ func (ps ProbeSpec) String() string { return fmt.Sprintf("ProbeSpec: {path: %s, port: %d, period: %s}", ps.Path, ps.Port, ps.Period) } +// NewLink parses an unstructured link.multicluster.linkerd.io resource and +// converts it to a structured internal representation. func NewLink(u unstructured.Unstructured) (Link, error) { spec, ok := u.Object["spec"] @@ -101,6 +108,8 @@ func NewLink(u unstructured.Unstructured) (Link, error) { }, nil } +// ToUnstructured converts a Link struct into an unstructured resource that can +// be used by a kubernetes dynamic client. func (l Link) ToUnstructured(name, namespace string) unstructured.Unstructured { return unstructured.Unstructured{ @@ -128,6 +137,7 @@ func (l Link) ToUnstructured(name, namespace string) unstructured.Unstructured { } } +// ExtractProbeSpec parses the ProbSpec from a gateway service's annotations. func ExtractProbeSpec(gateway *corev1.Service) (ProbeSpec, error) { path := gateway.Annotations[consts.GatewayProbePath] if path == "" { From f03e6ef87175d30993ed3f3058d34775445c800e Mon Sep 17 00:00:00 2001 From: Alex Leong Date: Wed, 8 Jul 2020 17:36:55 -0700 Subject: [PATCH 06/14] Gateway metrics now working Signed-off-by: Alex Leong --- .../templates/gateway-mirror.yaml | 13 + .../templates/service-mirror.yaml | 7 +- cli/cmd/multicluster.go | 44 +- controller/api/public/gateways.go | 39 +- .../cmd/service-mirror/cluster_watcher.go | 740 ++++-------------- .../cluster_watcher_mirroring_test.go | 299 +------ .../cluster_watcher_test_util.go | 518 +++--------- .../cmd/service-mirror/config_watcher.go | 161 ---- .../cmd/service-mirror/events_formatting.go | 45 +- controller/cmd/service-mirror/main.go | 23 +- controller/cmd/service-mirror/metrics.go | 28 +- .../cmd/service-mirror/probe_manager.go | 273 ------- pkg/multicluster/link.go | 12 + 13 files changed, 396 insertions(+), 1806 deletions(-) create mode 100644 charts/linkerd2-multicluster/templates/gateway-mirror.yaml delete mode 100644 controller/cmd/service-mirror/config_watcher.go delete mode 100644 controller/cmd/service-mirror/probe_manager.go diff --git a/charts/linkerd2-multicluster/templates/gateway-mirror.yaml b/charts/linkerd2-multicluster/templates/gateway-mirror.yaml new file mode 100644 index 0000000000000..f735e6366b229 --- /dev/null +++ b/charts/linkerd2-multicluster/templates/gateway-mirror.yaml @@ -0,0 +1,13 @@ +{{if .Values.serviceMirror -}} +--- +apiVersion: v1 +kind: Service +metadata: + name: probe-gateway-{{.Values.targetClusterName}} + namespace: {{.Values.namespace}} +spec: + ports: + - name: mc-probe + port: {{.Values.gatewayProbePort}} + protocol: TCP +{{end -}} diff --git a/charts/linkerd2-multicluster/templates/service-mirror.yaml b/charts/linkerd2-multicluster/templates/service-mirror.yaml index 913c7bd028020..cfab1b2d12b6e 100644 --- a/charts/linkerd2-multicluster/templates/service-mirror.yaml +++ b/charts/linkerd2-multicluster/templates/service-mirror.yaml @@ -74,19 +74,22 @@ kind: Deployment metadata: labels: {{.Values.controllerComponentLabel}}: linkerd-service-mirror + app: linkerd-service-mirror-{{.Values.targetClusterName}} name: linkerd-service-mirror-{{.Values.targetClusterName}} namespace: {{.Values.namespace}} spec: replicas: 1 selector: matchLabels: - {{.Values.controllerComponentLabel}}: linkerd-service-mirror-{{.Values.targetClusterName}} + {{.Values.controllerComponentLabel}}: linkerd-service-mirror + app: linkerd-service-mirror-{{.Values.targetClusterName}} template: metadata: annotations: linkerd.io/inject: enabled labels: - {{.Values.controllerComponentLabel}}: linkerd-service-mirror-{{.Values.targetClusterName}} + {{.Values.controllerComponentLabel}}: linkerd-service-mirror + app: linkerd-service-mirror-{{.Values.targetClusterName}} spec: containers: - args: diff --git a/cli/cmd/multicluster.go b/cli/cmd/multicluster.go index 21f82b56f266b..7a9c8372c23da 100644 --- a/cli/cmd/multicluster.go +++ b/cli/cmd/multicluster.go @@ -547,12 +547,18 @@ func newLinkCommand() *cobra.Command { return err } + gatewayPort, err := extractGatewayPort(gateway) + if err != nil { + return err + } + link := mc.Link{ TargetClusterName: opts.clusterName, TargetClusterDomain: configMap.Global.ClusterDomain, TargetClusterLinkerdNamespace: controlPlaneNamespace, ClusterCredentialsSecret: fmt.Sprintf("cluster-credentials-%s", opts.clusterName), GatewayAddress: strings.Join(gatewayAddresses, ","), + GatewayPort: gatewayPort, GatewayIdentity: gateway.Annotations[k8s.GatewayIdentity], ProbeSpec: probeSpec, } @@ -577,6 +583,7 @@ func newLinkCommand() *cobra.Command { files := []*chartutil.BufferedFile{ {Name: chartutil.ChartfileName}, {Name: "templates/service-mirror.yaml"}, + {Name: "templates/gateway-mirror.yaml"}, } chart := &charts.Chart{ @@ -896,14 +903,12 @@ func renderGateways(rows []*pb.GatewaysTable_Row, w io.Writer) { } var ( - gatewayNameHeader = "NAME" - gatewayNamespaceHeader = "NAMESPACE" - clusterNameHeader = "CLUSTER" - aliveHeader = "ALIVE" - pairedServicesHeader = "NUM_SVC" - latencyP50Header = "LATENCY_P50" - latencyP95Header = "LATENCY_P95" - latencyP99Header = "LATENCY_P99" + clusterNameHeader = "CLUSTER" + aliveHeader = "ALIVE" + pairedServicesHeader = "NUM_SVC" + latencyP50Header = "LATENCY_P50" + latencyP95Header = "LATENCY_P95" + latencyP99Header = "LATENCY_P99" ) func buildGatewaysTable() table.Table { @@ -914,18 +919,6 @@ func buildGatewaysTable() table.Table { Flexible: true, LeftAlign: true, }, - table.Column{ - Header: gatewayNamespaceHeader, - Width: 9, - Flexible: true, - LeftAlign: true, - }, - table.Column{ - Header: gatewayNameHeader, - Width: 4, - Flexible: true, - LeftAlign: true, - }, table.Column{ Header: aliveHeader, Width: 5, @@ -969,8 +962,6 @@ func gatewaysRowToTableRow(row *pb.GatewaysTable_Row) []string { } return []string{ row.ClusterName, - row.Namespace, - row.Name, alive, fmt.Sprint(row.PairedServices), valueOrPlaceholder(fmt.Sprintf("%dms", row.LatencyMsP50)), @@ -979,3 +970,12 @@ func gatewaysRowToTableRow(row *pb.GatewaysTable_Row) []string { } } + +func extractGatewayPort(gateway *corev1.Service) (uint32, error) { + for _, port := range gateway.Spec.Ports { + if port.Name == k8s.GatewayPortName { + return uint32(port.Port), nil + } + } + return 0, fmt.Errorf("gateway service %s has no gateway port named %s", gateway.Name, k8s.GatewayPortName) +} diff --git a/controller/api/public/gateways.go b/controller/api/public/gateways.go index 564a444b8be76..9d2c8b7d9da8f 100644 --- a/controller/api/public/gateways.go +++ b/controller/api/public/gateways.go @@ -54,7 +54,8 @@ func buildGatewaysRequestLabels(req *pb.GatewaysRequest) (labels model.LabelSet, return labels, groupBy } -// this function returns a map of gateways to the number of services using them +// this function returns a map of target cluster to the number of services mirrored +// from it func (s *grpcServer) getNumServicesMap() (map[string]uint64, error) { results := make(map[string]uint64) @@ -66,11 +67,7 @@ func (s *grpcServer) getNumServicesMap() (map[string]uint64, error) { for _, svc := range services.Items { clusterName := svc.Labels[k8s.RemoteClusterNameLabel] - gatewayName := svc.Labels[k8s.RemoteGatewayNameLabel] - gatewayNs := svc.Labels[k8s.RemoteGatewayNsLabel] - key := fmt.Sprintf("%s-%s-%s", clusterName, gatewayName, gatewayNs) - - results[key]++ + results[clusterName]++ } return results, nil @@ -83,20 +80,14 @@ func processPrometheusResult(results []promResult, numSvcMap map[string]uint64) for _, result := range results { for _, sample := range result.vec { - clusterName := sample.Metric[remoteClusterNameLabel] - gatewayName := sample.Metric[gatewayNameLabel] - gatewayNamespace := sample.Metric[gatewayNamespaceLabel] - numPairedSvc := numSvcMap[fmt.Sprintf("%s-%s-%s", clusterName, gatewayName, gatewayNamespace)] - - key := fmt.Sprintf("%s-%s-%s", clusterName, gatewayNamespace, gatewayName) + clusterName := string(sample.Metric[remoteClusterNameLabel]) + numPairedSvc := numSvcMap[clusterName] addRow := func() { - if rows[key] == nil { - rows[key] = &pb.GatewaysTable_Row{} - rows[key].ClusterName = string(clusterName) - rows[key].Name = string(gatewayName) - rows[key].Namespace = string(gatewayNamespace) - rows[key].PairedServices = numPairedSvc + if rows[clusterName] == nil { + rows[clusterName] = &pb.GatewaysTable_Row{} + rows[clusterName].ClusterName = clusterName + rows[clusterName].PairedServices = numPairedSvc } } @@ -105,16 +96,16 @@ func processPrometheusResult(results []promResult, numSvcMap map[string]uint64) switch result.prom { case promGatewayAlive: addRow() - rows[key].Alive = value > 0 + rows[clusterName].Alive = value > 0 case promLatencyP50: addRow() - rows[key].LatencyMsP50 = value + rows[clusterName].LatencyMsP50 = value case promLatencyP95: addRow() - rows[key].LatencyMsP95 = value + rows[clusterName].LatencyMsP95 = value case promLatencyP99: addRow() - rows[key].LatencyMsP99 = value + rows[clusterName].LatencyMsP99 = value } } } @@ -125,13 +116,11 @@ func processPrometheusResult(results []promResult, numSvcMap map[string]uint64) func (s *grpcServer) getGatewaysMetrics(ctx context.Context, req *pb.GatewaysRequest, timeWindow string) (map[string]*pb.GatewaysTable_Row, error) { labels, groupBy := buildGatewaysRequestLabels(req) - reqLabels := generateLabelStringWithExclusion(labels, string(gatewayNameLabel)) - promQueries := map[promType]string{ promGatewayAlive: gatewayAliveQuery, } - metricsResp, err := s.getPrometheusMetrics(ctx, promQueries, gatewayLatencyQuantileQuery, reqLabels, timeWindow, groupBy.String()) + metricsResp, err := s.getPrometheusMetrics(ctx, promQueries, gatewayLatencyQuantileQuery, labels.String(), timeWindow, groupBy.String()) if err != nil { return nil, err diff --git a/controller/cmd/service-mirror/cluster_watcher.go b/controller/cmd/service-mirror/cluster_watcher.go index 66b5f762dfec9..f6b6e96fde02b 100644 --- a/controller/cmd/service-mirror/cluster_watcher.go +++ b/controller/cmd/service-mirror/cluster_watcher.go @@ -1,15 +1,14 @@ package servicemirror import ( - "errors" "fmt" "net" - "strconv" "strings" "time" "github.com/linkerd/linkerd2/controller/k8s" consts "github.com/linkerd/linkerd2/pkg/k8s" + "github.com/linkerd/linkerd2/pkg/multicluster" "github.com/prometheus/client_golang/prometheus" logging "github.com/sirupsen/logrus" corev1 "k8s.io/api/core/v1" @@ -31,8 +30,7 @@ type ( // problems or general glitch in the Matrix. RemoteClusterServiceWatcher struct { serviceMirrorNamespace string - clusterName string - clusterDomain string + link *multicluster.Link remoteAPIClient *k8s.API localAPIClient *k8s.API stopper chan struct{} @@ -42,30 +40,10 @@ type ( repairPeriod time.Duration } - // ProbeConfig describes the configured probe on particular gateway (if presents) - ProbeConfig struct { - path string - port uint32 - periodInSeconds uint32 - } - - // GatewaySpec contains essential data about the gateway - GatewaySpec struct { - gatewayName string - gatewayNamespace string - clusterName string - addresses []corev1.EndpointAddress - incomingPort uint32 - resourceVersion string - identity string - *ProbeConfig - } - // RemoteServiceCreated is generated whenever a remote service is created Observing // this event means that the service in question is not mirrored atm RemoteServiceCreated struct { - service *corev1.Service - gatewayData gatewayMetadata + service *corev1.Service } // RemoteServiceUpdated is generated when we see something about an already @@ -76,7 +54,6 @@ type ( localService *corev1.Service localEndpoints *corev1.Endpoints remoteUpdate *corev1.Service - gatewayData gatewayMetadata } // RemoteServiceDeleted when a remote service is going away or it is not @@ -86,24 +63,7 @@ type ( Namespace string } - // RemoteGatewayDeleted is observed when a service that is a gateway is deleted - RemoteGatewayDeleted struct { - gatewayData gatewayMetadata - } - - // RemoteGatewayCreated is observed when a gateway service is created on the remote cluster - RemoteGatewayCreated struct { - gatewaySpec GatewaySpec - } - - // RemoteGatewayUpdated happens when a service that is updated. - RemoteGatewayUpdated struct { - gatewaySpec GatewaySpec - affectedServices []*corev1.Service - } - - // ClusterUnregistered is issued when the secret containing the remote cluster - // access information is deleted + // ClusterUnregistered is issued when this ClusterWatcher is shut down. ClusterUnregistered struct{} // OprhanedServicesGcTriggered is a self-triggered event which aims to delete any @@ -144,11 +104,6 @@ type ( // endpoints should be resolved based on the remote gateway and updated. RepairEndpoints struct{} - gatewayMetadata struct { - Name string - Namespace string - } - // RetryableError is an error that should be retried through requeuing events RetryableError struct{ Inner []error } ) @@ -161,26 +116,15 @@ func (re RetryableError) Error() string { return fmt.Sprintf("Inner errors:\n\t%s", strings.Join(errorStrings, "\n\t")) } -// When the gateway is resolved we need to produce a set of endpoint addresses that that -// contain the external IPs that this gateway exposes. Therefore we return the IP addresses -// as well as a single port on which the gateway is accessible. -func (rcsw *RemoteClusterServiceWatcher) resolveGateway(metadata *gatewayMetadata) (*GatewaySpec, error) { - gateway, err := rcsw.remoteAPIClient.Svc().Lister().Services(metadata.Namespace).Get(metadata.Name) - if err != nil { - return nil, err - } - return rcsw.extractGatewaySpec(gateway) -} - // NewRemoteClusterServiceWatcher constructs a new cluster watcher func NewRemoteClusterServiceWatcher( serviceMirrorNamespace string, localAPI *k8s.API, cfg *rest.Config, - clusterName string, + link *multicluster.Link, requeueLimit int, repairPeriod time.Duration, - clusterDomain string, + ) (*RemoteClusterServiceWatcher, error) { remoteAPI, err := k8s.InitializeAPIForConfig(cfg, false, k8s.Svc) if err != nil { @@ -189,8 +133,7 @@ func NewRemoteClusterServiceWatcher( stopper := make(chan struct{}) return &RemoteClusterServiceWatcher{ serviceMirrorNamespace: serviceMirrorNamespace, - clusterName: clusterName, - clusterDomain: clusterDomain, + link: link, remoteAPIClient: remoteAPI, localAPIClient: localAPI, stopper: stopper, @@ -205,26 +148,24 @@ func NewRemoteClusterServiceWatcher( } func (rcsw *RemoteClusterServiceWatcher) mirroredResourceName(remoteName string) string { - return fmt.Sprintf("%s-%s", remoteName, rcsw.clusterName) + return fmt.Sprintf("%s-%s", remoteName, rcsw.link.TargetClusterName) } func (rcsw *RemoteClusterServiceWatcher) originalResourceName(mirroredName string) string { - return strings.TrimSuffix(mirroredName, fmt.Sprintf("-%s", rcsw.clusterName)) + return strings.TrimSuffix(mirroredName, fmt.Sprintf("-%s", rcsw.link.TargetClusterName)) } -func (rcsw *RemoteClusterServiceWatcher) getMirroredServiceLabels(gatewayData *gatewayMetadata) map[string]string { +func (rcsw *RemoteClusterServiceWatcher) getMirroredServiceLabels() map[string]string { return map[string]string{ consts.MirroredResourceLabel: "true", - consts.RemoteClusterNameLabel: rcsw.clusterName, - consts.RemoteGatewayNameLabel: gatewayData.Name, - consts.RemoteGatewayNsLabel: gatewayData.Namespace, + consts.RemoteClusterNameLabel: rcsw.link.TargetClusterName, } } func (rcsw *RemoteClusterServiceWatcher) getMirroredServiceAnnotations(remoteService *corev1.Service) map[string]string { return map[string]string{ consts.RemoteResourceVersionAnnotation: remoteService.ResourceVersion, // needed to detect real changes - consts.RemoteServiceFqName: fmt.Sprintf("%s.%s.svc.%s", remoteService.Name, remoteService.Namespace, rcsw.clusterDomain), + consts.RemoteServiceFqName: fmt.Sprintf("%s.%s.svc.%s", remoteService.Name, remoteService.Namespace, rcsw.link.TargetClusterDomain), } } @@ -239,7 +180,7 @@ func (rcsw *RemoteClusterServiceWatcher) mirrorNamespaceIfNecessary(namespace st ObjectMeta: metav1.ObjectMeta{ Labels: map[string]string{ consts.MirroredResourceLabel: "true", - consts.RemoteClusterNameLabel: rcsw.clusterName, + consts.RemoteClusterNameLabel: rcsw.link.TargetClusterName, }, Name: namespace, }, @@ -261,13 +202,13 @@ func (rcsw *RemoteClusterServiceWatcher) mirrorNamespaceIfNecessary(namespace st // that we should send traffic to and create endpoint ports that bind to the mirrored service ports // (same name, etc) but send traffic to the gateway port. This way we do not need to do any remapping // on the service side of things. It all happens in the endpoints. -func (rcsw *RemoteClusterServiceWatcher) getEndpointsPorts(service *corev1.Service, gatewayPort int32) []corev1.EndpointPort { +func (rcsw *RemoteClusterServiceWatcher) getEndpointsPorts(service *corev1.Service) []corev1.EndpointPort { var endpointsPorts []corev1.EndpointPort for _, remotePort := range service.Spec.Ports { endpointsPorts = append(endpointsPorts, corev1.EndpointPort{ Name: remotePort.Name, Protocol: remotePort.Protocol, - Port: gatewayPort, + Port: int32(rcsw.link.GatewayPort), }) } return endpointsPorts @@ -276,7 +217,7 @@ func (rcsw *RemoteClusterServiceWatcher) getEndpointsPorts(service *corev1.Servi func (rcsw *RemoteClusterServiceWatcher) cleanupOrphanedServices() error { matchLabels := map[string]string{ consts.MirroredResourceLabel: "true", - consts.RemoteClusterNameLabel: rcsw.clusterName, + consts.RemoteClusterNameLabel: rcsw.link.TargetClusterName, } servicesOnLocalCluster, err := rcsw.localAPIClient.Svc().Lister().List(labels.Set(matchLabels).AsSelector()) @@ -320,7 +261,7 @@ func (rcsw *RemoteClusterServiceWatcher) cleanupOrphanedServices() error { func (rcsw *RemoteClusterServiceWatcher) cleanupMirroredResources() error { matchLabels := map[string]string{ consts.MirroredResourceLabel: "true", - consts.RemoteClusterNameLabel: rcsw.clusterName, + consts.RemoteClusterNameLabel: rcsw.link.TargetClusterName, } services, err := rcsw.localAPIClient.Svc().Lister().List(labels.Set(matchLabels).AsSelector()) @@ -399,45 +340,30 @@ func (rcsw *RemoteClusterServiceWatcher) handleRemoteServiceDeleted(ev *RemoteSe // Updates a locally mirrored service. There might have been some pretty fundamental changes such as // new gateway being assigned or additional ports exposed. This method takes care of that. func (rcsw *RemoteClusterServiceWatcher) handleRemoteServiceUpdated(ev *RemoteServiceUpdated) error { - serviceInfo := fmt.Sprintf("%s/%s", ev.remoteUpdate.Namespace, ev.remoteUpdate.Name) rcsw.log.Infof("Updating mirror service %s/%s", ev.localService.Namespace, ev.localService.Name) - gatewaySpec, err := rcsw.resolveGateway(&ev.gatewayData) copiedEndpoints := ev.localEndpoints.DeepCopy() - if err == nil { - copiedEndpoints.Subsets = []corev1.EndpointSubset{ - { - Addresses: gatewaySpec.addresses, - Ports: rcsw.getEndpointsPorts(ev.remoteUpdate, int32(gatewaySpec.incomingPort)), - }, - } - - if gatewaySpec.identity != "" { - copiedEndpoints.Annotations[consts.RemoteGatewayIdentity] = gatewaySpec.identity - } else { - delete(copiedEndpoints.Annotations, consts.RemoteGatewayIdentity) - } + copiedEndpoints.Subsets = []corev1.EndpointSubset{ + { + Addresses: rcsw.resolveGatewayAddress(), + Ports: rcsw.getEndpointsPorts(ev.remoteUpdate), + }, + } + if rcsw.link.GatewayIdentity != "" { + copiedEndpoints.Annotations[consts.RemoteGatewayIdentity] = rcsw.link.GatewayIdentity } else { - rcsw.log.Warnf("Could not resolve gateway for %s: %s, nulling endpoints", serviceInfo, err) - copiedEndpoints.Subsets = nil + delete(copiedEndpoints.Annotations, consts.RemoteGatewayIdentity) } - // we need to set the new name and ns data no matter whether they are valid or not - copiedEndpoints.Labels[consts.RemoteGatewayNameLabel] = ev.gatewayData.Name - copiedEndpoints.Labels[consts.RemoteGatewayNsLabel] = ev.gatewayData.Namespace if _, err := rcsw.localAPIClient.Client.CoreV1().Endpoints(copiedEndpoints.Namespace).Update(copiedEndpoints); err != nil { return RetryableError{[]error{err}} } - ev.localService.Labels = rcsw.getMirroredServiceLabels(&ev.gatewayData) + ev.localService.Labels = rcsw.getMirroredServiceLabels() ev.localService.Annotations = rcsw.getMirroredServiceAnnotations(ev.remoteUpdate) ev.localService.Spec.Ports = remapRemoteServicePorts(ev.remoteUpdate.Spec.Ports) - if gatewaySpec != nil { - ev.localService.Annotations[consts.RemoteGatewayResourceVersionAnnotation] = gatewaySpec.resourceVersion - } - if _, err := rcsw.localAPIClient.Client.CoreV1().Services(ev.localService.Namespace).Update(ev.localService); err != nil { return RetryableError{[]error{err}} } @@ -473,7 +399,7 @@ func (rcsw *RemoteClusterServiceWatcher) handleRemoteServiceCreated(ev *RemoteSe Name: localServiceName, Namespace: remoteService.Namespace, Annotations: rcsw.getMirroredServiceAnnotations(remoteService), - Labels: rcsw.getMirroredServiceLabels(&ev.gatewayData), + Labels: rcsw.getMirroredServiceLabels(), }, Spec: corev1.ServiceSpec{ Ports: remapRemoteServicePorts(remoteService.Spec.Ports), @@ -486,40 +412,30 @@ func (rcsw *RemoteClusterServiceWatcher) handleRemoteServiceCreated(ev *RemoteSe Namespace: ev.service.Namespace, Labels: map[string]string{ consts.MirroredResourceLabel: "true", - consts.RemoteClusterNameLabel: rcsw.clusterName, - consts.RemoteGatewayNameLabel: ev.gatewayData.Name, - consts.RemoteGatewayNsLabel: ev.gatewayData.Namespace, + consts.RemoteClusterNameLabel: rcsw.link.TargetClusterName, }, Annotations: map[string]string{ - consts.RemoteServiceFqName: fmt.Sprintf("%s.%s.svc.%s", remoteService.Name, remoteService.Namespace, rcsw.clusterDomain), + consts.RemoteServiceFqName: fmt.Sprintf("%s.%s.svc.%s", remoteService.Name, remoteService.Namespace, rcsw.link.TargetClusterDomain), }, }, } - // Now we try to resolve the remote gateway - gatewaySpec, err := rcsw.resolveGateway(&ev.gatewayData) - if err == nil { - // only if we resolve it, we are updating the endpoints addresses and ports - rcsw.log.Infof("Resolved gateway [%v:%d] for %s", gatewaySpec.addresses, gatewaySpec.incomingPort, serviceInfo) + gatewayAddress := rcsw.resolveGatewayAddress() + // only if we resolve it, we are updating the endpoints addresses and ports + rcsw.log.Infof("Resolved gateway [%v:%d] for %s", gatewayAddress, rcsw.link.GatewayPort, serviceInfo) - if len(gatewaySpec.addresses) > 0 { - endpointsToCreate.Subsets = []corev1.EndpointSubset{ - { - Addresses: gatewaySpec.addresses, - Ports: rcsw.getEndpointsPorts(ev.service, int32(gatewaySpec.incomingPort)), - }, - } - } else { - rcsw.log.Warnf("gateway for %s: %s does not have ready addresses, skipping subsets", serviceInfo, err) - } - serviceToCreate.Annotations[consts.RemoteGatewayResourceVersionAnnotation] = gatewaySpec.resourceVersion - if gatewaySpec.identity != "" { - endpointsToCreate.Annotations[consts.RemoteGatewayIdentity] = gatewaySpec.identity + if len(gatewayAddress) > 0 { + endpointsToCreate.Subsets = []corev1.EndpointSubset{ + { + Addresses: gatewayAddress, + Ports: rcsw.getEndpointsPorts(ev.service), + }, } - } else { - rcsw.log.Infof("Could not resolve gateway for %s: %s, skipping subsets", serviceInfo, err) - endpointsToCreate.Subsets = nil + rcsw.log.Warnf("gateway for %s does not have ready addresses, skipping subsets", serviceInfo) + } + if rcsw.link.GatewayIdentity != "" { + endpointsToCreate.Annotations[consts.RemoteGatewayIdentity] = rcsw.link.GatewayIdentity } rcsw.log.Infof("Creating a new service mirror for %s", serviceInfo) @@ -540,274 +456,7 @@ func (rcsw *RemoteClusterServiceWatcher) handleRemoteServiceCreated(ev *RemoteSe return nil } -func (rcsw *RemoteClusterServiceWatcher) handleRemoteGatewayDeleted(ev *RemoteGatewayDeleted) error { - - if err := rcsw.localAPIClient.Client.CoreV1().Services(rcsw.serviceMirrorNamespace).Delete(rcsw.mirroredResourceName(ev.gatewayData.Name), &metav1.DeleteOptions{}); err != nil { - rcsw.log.Errorf("Could not delete gateway mirror %s", err) - } - - affectedEndpoints, err := rcsw.endpointsForGateway(&ev.gatewayData) - if err != nil { - // if we cannot find the endpoints, we can give up - if kerrors.IsNotFound(err) { - return err - } - // if it is another error, just retry - return RetryableError{[]error{err}} - } - - var errors []error - if len(affectedEndpoints) > 0 { - rcsw.log.Infof("Nulling %d endpoints due to gateway [%s/%s] deletion", len(affectedEndpoints), ev.gatewayData.Namespace, ev.gatewayData.Name) - for _, ep := range affectedEndpoints { - updated := ep.DeepCopy() - updated.Subsets = nil - if _, err := rcsw.localAPIClient.Client.CoreV1().Endpoints(ep.Namespace).Update(updated); err != nil { - errors = append(errors, err) - } - } - } - if len(errors) > 0 { - // if we have encountered any errors, we can retry the whole operation - return RetryableError{errors} - } - return nil -} - -// the logic here creates a mirror service for the gateway. The only port exposed there is the -// probes port. This enables us to discover the gateways probe endpoints through the dst service -// and apply proper identity -func (rcsw *RemoteClusterServiceWatcher) handleRemoteGatewayCreated(event *RemoteGatewayCreated) error { - localServiceName := rcsw.mirroredResourceName(event.gatewaySpec.gatewayName) - if event.gatewaySpec.ProbeConfig == nil { - rcsw.log.Infof("Skipping creation of gateway mirror as gateway does not specify probe config") - return nil - } - serviceToCreate := &corev1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: localServiceName, - Namespace: rcsw.serviceMirrorNamespace, - Annotations: map[string]string{ - consts.RemoteGatewayResourceVersionAnnotation: event.gatewaySpec.resourceVersion, - consts.MirroredGatewayRemoteName: event.gatewaySpec.gatewayName, - consts.MirroredGatewayRemoteNameSpace: event.gatewaySpec.gatewayNamespace, - consts.MirroredGatewayProbePath: event.gatewaySpec.ProbeConfig.path, - consts.MirroredGatewayProbePeriod: fmt.Sprint(event.gatewaySpec.ProbeConfig.periodInSeconds), - }, - Labels: map[string]string{ - consts.MirroredResourceLabel: "true", - consts.RemoteClusterNameLabel: rcsw.clusterName, - consts.MirroredGatewayLabel: "true", - }, - }, - Spec: corev1.ServiceSpec{ - Ports: []corev1.ServicePort{ - { - Name: consts.ProbePortName, - Protocol: "TCP", - Port: int32(event.gatewaySpec.ProbeConfig.port), - }, - }, - }, - } - - endpointsToCreate := &corev1.Endpoints{ - ObjectMeta: metav1.ObjectMeta{ - Name: localServiceName, - Namespace: rcsw.serviceMirrorNamespace, - Labels: map[string]string{ - consts.MirroredResourceLabel: "true", - consts.RemoteClusterNameLabel: rcsw.clusterName, - }, - Annotations: map[string]string{ - consts.RemoteGatewayIdentity: event.gatewaySpec.identity, - }, - }, - } - - if len(event.gatewaySpec.addresses) > 0 { - endpointsToCreate.Subsets = []corev1.EndpointSubset{ - { - Addresses: event.gatewaySpec.addresses, - Ports: []corev1.EndpointPort{ - { - Name: consts.ProbePortName, - Protocol: "TCP", - Port: int32(event.gatewaySpec.ProbeConfig.port), - }, - }, - }, - } - } - - rcsw.log.Infof("Creating a new gateway mirror Service for %s", localServiceName) - if _, err := rcsw.localAPIClient.Client.CoreV1().Services(rcsw.serviceMirrorNamespace).Create(serviceToCreate); err != nil { - if !kerrors.IsAlreadyExists(err) { - // we might have created it during earlier attempt, if that is not the case, we retry - return RetryableError{[]error{err}} - } - } - - rcsw.log.Infof("Creating a new gateway mirror Endpoints for %s", localServiceName) - if _, err := rcsw.localAPIClient.Client.CoreV1().Endpoints(rcsw.serviceMirrorNamespace).Create(endpointsToCreate); err != nil { - // we clean up after ourselves - rcsw.localAPIClient.Client.CoreV1().Services(rcsw.serviceMirrorNamespace).Delete(event.gatewaySpec.gatewayName, &metav1.DeleteOptions{}) - // and retry - return RetryableError{[]error{err}} - } - - return nil -} - -func (rcsw *RemoteClusterServiceWatcher) updateAffectedServices(gatewaySpec GatewaySpec, affectedServices []*corev1.Service) error { - rcsw.log.Infof("Updating %d services due to gateway [%s/%s] update", len(affectedServices), gatewaySpec.gatewayNamespace, gatewaySpec.gatewayName) - var errors []error - for _, svc := range affectedServices { - updatedService := svc.DeepCopy() - if updatedService.Annotations != nil { - updatedService.Annotations[consts.RemoteGatewayResourceVersionAnnotation] = gatewaySpec.resourceVersion - } - endpoints, err := rcsw.localAPIClient.Endpoint().Lister().Endpoints(svc.Namespace).Get(svc.Name) - if err != nil { - errors = append(errors, fmt.Errorf("Could not get endpoints: %s", err)) - continue - } - - updatedEndpoints := endpoints.DeepCopy() - if len(gatewaySpec.addresses) > 0 { - updatedEndpoints.Subsets = []corev1.EndpointSubset{ - { - Addresses: gatewaySpec.addresses, - Ports: rcsw.getEndpointsPorts(updatedService, int32(gatewaySpec.incomingPort)), - }, - } - } else { - updatedEndpoints.Subsets = nil - } - - if gatewaySpec.identity != "" { - updatedEndpoints.Annotations[consts.RemoteGatewayIdentity] = gatewaySpec.identity - } else { - delete(updatedEndpoints.Annotations, consts.RemoteGatewayIdentity) - } - - _, err = rcsw.localAPIClient.Client.CoreV1().Services(updatedService.Namespace).Update(updatedService) - if err != nil { - errors = append(errors, err) - continue - } - - _, err = rcsw.localAPIClient.Client.CoreV1().Endpoints(updatedService.Namespace).Update(updatedEndpoints) - if err != nil { - errors = append(errors, err) - } - } - - if len(errors) > 0 { - return RetryableError{errors} - } - return nil -} - -func (rcsw *RemoteClusterServiceWatcher) updateGatewayMirrorService(spec *GatewaySpec) error { - localServiceName := rcsw.mirroredResourceName(spec.gatewayName) - service, err := rcsw.localAPIClient.Svc().Lister().Services(rcsw.serviceMirrorNamespace).Get(localServiceName) - if err != nil { - return err - } - - if service.Annotations != nil && service.Annotations[consts.RemoteGatewayResourceVersionAnnotation] != spec.resourceVersion { - updatedService := service.DeepCopy() - if updatedService.Annotations != nil { - updatedService.Annotations[consts.RemoteGatewayResourceVersionAnnotation] = spec.resourceVersion - updatedService.Annotations[consts.MirroredGatewayProbePath] = spec.ProbeConfig.path - updatedService.Annotations[consts.MirroredGatewayProbePeriod] = fmt.Sprint(spec.ProbeConfig.periodInSeconds) - } - - updatedService.Spec.Ports = []corev1.ServicePort{ - { - Name: consts.ProbePortName, - Protocol: "TCP", - Port: int32(spec.ProbeConfig.port), - }, - } - - endpoints, err := rcsw.localAPIClient.Endpoint().Lister().Endpoints(rcsw.serviceMirrorNamespace).Get(localServiceName) - if err != nil { - return err - } - - updatedEndpoints := endpoints.DeepCopy() - if spec.addresses == nil { - updatedEndpoints.Subsets = nil - } else { - updatedEndpoints.Subsets = []corev1.EndpointSubset{ - { - Addresses: spec.addresses, - Ports: []corev1.EndpointPort{ - { - Name: consts.ProbePortName, - Protocol: "TCP", - Port: int32(spec.ProbeConfig.port), - }, - }, - }, - } - } - - updatedEndpoints.Annotations[consts.RemoteGatewayIdentity] = spec.identity - - _, err = rcsw.localAPIClient.Client.CoreV1().Services(rcsw.serviceMirrorNamespace).Update(updatedService) - if err != nil { - return err - } - - _, err = rcsw.localAPIClient.Client.CoreV1().Endpoints(rcsw.serviceMirrorNamespace).Update(updatedEndpoints) - if err != nil { - return err - } - rcsw.log.Infof("%s gateway mirror updated", localServiceName) - } - - return nil -} - -func (rcsw *RemoteClusterServiceWatcher) handleRemoteGatewayUpdated(ev *RemoteGatewayUpdated) error { - if err := rcsw.updateAffectedServices(ev.gatewaySpec, ev.affectedServices); err != nil { - return err - } - - if err := rcsw.updateGatewayMirrorService(&ev.gatewaySpec); err != nil { - return err - } - - return nil -} - -// Retrieves the annotations that indicate this service can be mirrored. -// The values of these annotations help us resolve the gateway to which -// traffic should be sent. -func getGatewayMetadata(annotations map[string]string) *gatewayMetadata { - remoteGatewayName, hasGtwName := annotations[consts.GatewayNameAnnotation] - remoteGatewayNs, hasGtwNs := annotations[consts.GatewayNsAnnotation] - if hasGtwName && hasGtwNs { - return &gatewayMetadata{ - Name: remoteGatewayName, - Namespace: remoteGatewayNs, - } - } - return nil -} - -func isGateway(annotations map[string]string) bool { - if annotations != nil { - _, hasAnnotation := annotations[consts.MulticlusterGatewayAnnotation] - return hasAnnotation - } - return false -} - -func isMirroredService(annotations map[string]string) bool { +func isExportedService(annotations map[string]string) bool { if annotations != nil { _, hasGtwName := annotations[consts.GatewayNameAnnotation] _, hasGtwNs := annotations[consts.GatewayNsAnnotation] @@ -822,48 +471,12 @@ func isMirroredService(annotations map[string]string) bool { func (rcsw *RemoteClusterServiceWatcher) createOrUpdateService(service *corev1.Service) error { localName := rcsw.mirroredResourceName(service.Name) - if isGateway(service.Annotations) { - gatewaySpec, err := rcsw.extractGatewaySpec(service) - if err != nil { - return RetryableError{[]error{err}} - } - - _, err = rcsw.localAPIClient.Svc().Lister().Services(rcsw.serviceMirrorNamespace).Get(localName) - if err != nil { - if kerrors.IsNotFound(err) { - rcsw.eventsQueue.Add(&RemoteGatewayCreated{ - gatewaySpec: *gatewaySpec, - }) - return nil - } - return RetryableError{[]error{err}} - } - - affectedServices, err := rcsw.affectedMirroredServicesForGatewayUpdate(&gatewayMetadata{ - Name: service.Name, - Namespace: service.Namespace, - }, service.ResourceVersion) - if err != nil { - return RetryableError{[]error{err}} - } - - rcsw.eventsQueue.Add(&RemoteGatewayUpdated{ - affectedServices: affectedServices, - gatewaySpec: *gatewaySpec, - }) - return nil - - } else if isMirroredService(service.Annotations) { - gatewayData := getGatewayMetadata(service.Annotations) - if gatewayData == nil { - return fmt.Errorf("got service in invalid state, no gateway metadata %s", service) - } + if isExportedService(service.Annotations) { localService, err := rcsw.localAPIClient.Svc().Lister().Services(service.Namespace).Get(localName) if err != nil { if kerrors.IsNotFound(err) { rcsw.eventsQueue.Add(&RemoteServiceCreated{ - service: service, - gatewayData: *gatewayData, + service: service, }) return nil } @@ -878,53 +491,33 @@ func (rcsw *RemoteClusterServiceWatcher) createOrUpdateService(service *corev1.S localService: localService, localEndpoints: endpoints, remoteUpdate: service, - gatewayData: *gatewayData, }) return nil } return RetryableError{[]error{err}} } return nil - } else { - localSvc, err := rcsw.localAPIClient.Svc().Lister().Services(service.Namespace).Get(localName) - if err == nil { - if localSvc.Labels != nil { - _, isMirroredRes := localSvc.Labels[consts.MirroredResourceLabel] - clusterName := localSvc.Labels[consts.RemoteClusterNameLabel] - if isMirroredRes && (clusterName == rcsw.clusterName) { - rcsw.eventsQueue.Add(&RemoteServiceDeleted{ - Name: service.Name, - Namespace: service.Namespace, - }) - } - } - } - return nil } -} - -func (rcsw *RemoteClusterServiceWatcher) affectedMirroredServicesForGatewayUpdate(gatewayData *gatewayMetadata, latestResourceVersion string) ([]*corev1.Service, error) { - services, err := rcsw.mirroredServicesForGateway(gatewayData) - if err != nil { - return nil, err - } - - affectedServices := []*corev1.Service{} - for _, srv := range services { - ver, ok := srv.Annotations[consts.RemoteGatewayResourceVersionAnnotation] - if !ok || ver != latestResourceVersion { - affectedServices = append(affectedServices, srv) + localSvc, err := rcsw.localAPIClient.Svc().Lister().Services(service.Namespace).Get(localName) + if err == nil { + if localSvc.Labels != nil { + _, isMirroredRes := localSvc.Labels[consts.MirroredResourceLabel] + clusterName := localSvc.Labels[consts.RemoteClusterNameLabel] + if isMirroredRes && (clusterName == rcsw.link.TargetClusterName) { + rcsw.eventsQueue.Add(&RemoteServiceDeleted{ + Name: service.Name, + Namespace: service.Namespace, + }) + } } } - return affectedServices, nil + return nil } -func (rcsw *RemoteClusterServiceWatcher) mirroredServicesForGateway(gatewayData *gatewayMetadata) ([]*corev1.Service, error) { +func (rcsw *RemoteClusterServiceWatcher) getMirrorServices() ([]*corev1.Service, error) { matchLabels := map[string]string{ consts.MirroredResourceLabel: "true", - consts.RemoteGatewayNameLabel: gatewayData.Name, - consts.RemoteGatewayNsLabel: gatewayData.Namespace, - consts.RemoteClusterNameLabel: rcsw.clusterName, + consts.RemoteClusterNameLabel: rcsw.link.TargetClusterName, } services, err := rcsw.localAPIClient.Svc().Lister().List(labels.Set(matchLabels).AsSelector()) @@ -934,33 +527,12 @@ func (rcsw *RemoteClusterServiceWatcher) mirroredServicesForGateway(gatewayData return services, nil } -func (rcsw *RemoteClusterServiceWatcher) endpointsForGateway(gatewayData *gatewayMetadata) ([]*corev1.Endpoints, error) { - matchLabels := map[string]string{ - consts.MirroredResourceLabel: "true", - consts.RemoteGatewayNameLabel: gatewayData.Name, - consts.RemoteGatewayNsLabel: gatewayData.Namespace, - consts.RemoteClusterNameLabel: rcsw.clusterName, - } - - endpoints, err := rcsw.localAPIClient.Endpoint().Lister().List(labels.Set(matchLabels).AsSelector()) - if err != nil { - return nil, err - } - return endpoints, nil -} - func (rcsw *RemoteClusterServiceWatcher) handleOnDelete(service *corev1.Service) { - if isMirroredService(service.Annotations) { + if isExportedService(service.Annotations) { rcsw.eventsQueue.Add(&RemoteServiceDeleted{ Name: service.Name, Namespace: service.Namespace, }) - } else if isGateway(service.Annotations) { - rcsw.eventsQueue.Add(&RemoteGatewayDeleted{ - gatewayData: gatewayMetadata{ - Name: service.Name, - Namespace: service.Namespace, - }}) } else { rcsw.log.Infof("Skipping OnDelete for service %s", service) } @@ -990,12 +562,6 @@ func (rcsw *RemoteClusterServiceWatcher) processNextEvent() (bool, interface{}, err = rcsw.handleRemoteServiceUpdated(ev) case *RemoteServiceDeleted: err = rcsw.handleRemoteServiceDeleted(ev) - case *RemoteGatewayUpdated: - err = rcsw.handleRemoteGatewayUpdated(ev) - case *RemoteGatewayDeleted: - err = rcsw.handleRemoteGatewayDeleted(ev) - case *RemoteGatewayCreated: - err = rcsw.handleRemoteGatewayCreated(ev) case *ClusterUnregistered: err = rcsw.cleanupMirroredResources() case *OprhanedServicesGcTriggered: @@ -1105,126 +671,118 @@ func (rcsw *RemoteClusterServiceWatcher) Stop(cleanupState bool) { rcsw.eventsQueue.ShutDown() } -func extractPort(port []corev1.ServicePort, portName string) (uint32, error) { - for _, p := range port { - if p.Name == portName { - return uint32(p.Port), nil +func (rcsw *RemoteClusterServiceWatcher) resolveGatewayAddress() []corev1.EndpointAddress { + var gatewayEndpoints []corev1.EndpointAddress + for _, addr := range strings.Split(rcsw.link.GatewayAddress, ",") { + resolved := addr + ipAddr, err := net.ResolveIPAddr("ip", addr) + if err == nil { + resolved = ipAddr.String() } + gatewayEndpoints = append(gatewayEndpoints, corev1.EndpointAddress{ + IP: resolved, + }) } - return 0, fmt.Errorf("could not find port with name %s", portName) + return gatewayEndpoints } -func extractProbeConfig(gateway *corev1.Service) (*ProbeConfig, error) { - probePath := gateway.Annotations[consts.GatewayProbePath] +func (rcsw *RemoteClusterServiceWatcher) repairEndpoints() { + endpointRepairCounter.With(prometheus.Labels{ + gatewayClusterName: rcsw.link.TargetClusterName, + }).Inc() - probePort, err := extractPort(gateway.Spec.Ports, consts.ProbePortName) + // Create or update gateway mirror endpoints. + gatewayMirrorName := fmt.Sprintf("probe-gateway-%s", rcsw.link.TargetClusterName) - if err != nil { - return nil, err + gatewayMirrorEndpoints := &corev1.Endpoints{ + ObjectMeta: metav1.ObjectMeta{ + Name: gatewayMirrorName, + Namespace: rcsw.serviceMirrorNamespace, + Labels: map[string]string{ + consts.RemoteClusterNameLabel: rcsw.link.TargetClusterName, + }, + Annotations: map[string]string{ + consts.RemoteGatewayIdentity: rcsw.link.GatewayIdentity, + }, + }, + Subsets: []corev1.EndpointSubset{ + { + Addresses: rcsw.resolveGatewayAddress(), + Ports: []corev1.EndpointPort{ + { + Name: "mc-probe", + Port: int32(rcsw.link.ProbeSpec.Port), + Protocol: "TCP", + }, + }, + }, + }, } - probePeriod, err := strconv.ParseUint(gateway.Annotations[consts.GatewayProbePeriod], 10, 32) + err := rcsw.createOrUpdateEndpoints(gatewayMirrorEndpoints) if err != nil { - return nil, err + rcsw.log.Errorf("Failed to create/update gateway mirror endpoints: %s", err) } - if probePath == "" { - return nil, errors.New("probe path is empty") + // Repair mirror service endpoints. + mirrorServices, err := rcsw.getMirrorServices() + if err != nil { + rcsw.log.Errorf("Failed to list mirror services: %s", err) } + for _, svc := range mirrorServices { + updatedService := svc.DeepCopy() - return &ProbeConfig{ - path: probePath, - port: probePort, - periodInSeconds: uint32(probePeriod), - }, nil -} + endpoints, err := rcsw.localAPIClient.Endpoint().Lister().Endpoints(svc.Namespace).Get(svc.Name) + if err != nil { + rcsw.log.Errorf("Could not get endpoints: %s", err) + continue + } -func (rcsw *RemoteClusterServiceWatcher) extractGatewaySpec(gateway *corev1.Service) (*GatewaySpec, error) { - incomingPort, err := extractPort(gateway.Spec.Ports, consts.GatewayPortName) + updatedEndpoints := endpoints.DeepCopy() + updatedEndpoints.Subsets = []corev1.EndpointSubset{ + { + Addresses: rcsw.resolveGatewayAddress(), + Ports: rcsw.getEndpointsPorts(updatedService), + }, + } - if err != nil { - return nil, err - } + if rcsw.link.GatewayIdentity != "" { + updatedEndpoints.Annotations[consts.RemoteGatewayIdentity] = rcsw.link.GatewayIdentity + } else { + delete(updatedEndpoints.Annotations, consts.RemoteGatewayIdentity) + } - var gatewayEndpoints []corev1.EndpointAddress - for _, ingress := range gateway.Status.LoadBalancer.Ingress { - ip := ingress.IP - if ip == "" { - ipAddr, err := net.ResolveIPAddr("ip", ingress.Hostname) - if err != nil { - return nil, err - } - ip = ipAddr.String() + _, err = rcsw.localAPIClient.Client.CoreV1().Services(updatedService.Namespace).Update(updatedService) + if err != nil { + rcsw.log.Error(err) + continue } - gatewayEndpoints = append(gatewayEndpoints, corev1.EndpointAddress{ - IP: ip, - }) - } - gatewayIdentity := gateway.Annotations[consts.GatewayIdentity] - probeConfig, err := extractProbeConfig(gateway) - if err != nil { - return nil, fmt.Errorf("could not parse probe config for gateway: %s/%s: %s", gateway.Namespace, gateway.Name, err) + _, err = rcsw.localAPIClient.Client.CoreV1().Endpoints(updatedService.Namespace).Update(updatedEndpoints) + if err != nil { + rcsw.log.Error(err) + } } - - return &GatewaySpec{ - clusterName: rcsw.clusterName, - gatewayName: gateway.Name, - gatewayNamespace: gateway.Namespace, - addresses: gatewayEndpoints, - incomingPort: incomingPort, - resourceVersion: gateway.ResourceVersion, - identity: gatewayIdentity, - ProbeConfig: probeConfig, - }, nil } -// repairEndpoints will look up all remote gateways and update the endpoints -// of all local mirror services for those gateways. Note that we ignore resource -// version and update ALL affected endpoints objects. This is because the -// remote gateway may be exposed as a DNS hostname and we want to re-resolve -// this DNS name in case its IP address has changed. By invoking repairEndpoints -// frequently, we can pick up any DNS changes fairly quickly. -// TODO: Replace this with a more robust solution that does not rely on -// frequently repairing endpoints to pick up DNS updates. -func (rcsw *RemoteClusterServiceWatcher) repairEndpoints() { - svcs, err := rcsw.remoteAPIClient.Svc().Lister().Services(metav1.NamespaceAll).List(labels.Everything()) +func (rcsw *RemoteClusterServiceWatcher) createOrUpdateEndpoints(ep *corev1.Endpoints) error { + _, err := rcsw.localAPIClient.Client.CoreV1().Endpoints(ep.Namespace).Get(ep.Name, metav1.GetOptions{}) if err != nil { - rcsw.log.Errorf("failed to list remote gateways: %s", err) - return - } - rcsw.log.Errorf("During repair, found %d remote services", len(svcs)) - for _, svc := range svcs { - if isGateway(svc.Annotations) { - - // We omit a resource version here because we want to get ALL mirror - // services for this gateway. - affectedServices, err := rcsw.affectedMirroredServicesForGatewayUpdate(&gatewayMetadata{ - Name: svc.Name, - Namespace: svc.Namespace, - }, "") - if err != nil { - rcsw.log.Errorf("failed to determine mirror services for gateway %s.%s: %s", svc.Name, svc.Namespace, err) - continue - } - - spec, err := rcsw.extractGatewaySpec(svc) + if kerrors.IsNotFound(err) { + // Does not exist so we should create it. + _, err = rcsw.localAPIClient.Client.CoreV1().Endpoints(ep.Namespace).Create(ep) if err != nil { - rcsw.log.Errorf("failed to extract spec for gateway %s.%s: %s", svc.Name, svc.Namespace, err) - continue + return err } - - endpointRepairCounter.With(prometheus.Labels{ - gatewayNameLabel: svc.Name, - gatewayNamespaceLabel: svc.Namespace, - gatewayClusterName: rcsw.clusterName, - }).Inc() - - rcsw.log.Errorf("adding gateway update event %s with %d mirrro services", svc.Name, len(affectedServices)) - rcsw.eventsQueue.Add(&RemoteGatewayUpdated{ - gatewaySpec: *spec, - affectedServices: affectedServices, - }) + } else { + return err + } + } else { + // Exists so we should update it. + _, err = rcsw.localAPIClient.Client.CoreV1().Endpoints(ep.Namespace).Update(ep) + if err != nil { + return err } } + return nil } diff --git a/controller/cmd/service-mirror/cluster_watcher_mirroring_test.go b/controller/cmd/service-mirror/cluster_watcher_mirroring_test.go index ce434f8e29fe5..f2b55e5e526e4 100644 --- a/controller/cmd/service-mirror/cluster_watcher_mirroring_test.go +++ b/controller/cmd/service-mirror/cluster_watcher_mirroring_test.go @@ -2,12 +2,10 @@ package servicemirror import ( "fmt" - "net" "reflect" "testing" corev1 "k8s.io/api/core/v1" - v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/util/workqueue" ) @@ -94,48 +92,25 @@ func (tc *mirroringTestCase) run(t *testing.T) { func TestRemoteServiceCreatedMirroring(t *testing.T) { for _, tt := range []mirroringTestCase{ { - description: "create service and endpoints when gateway cannot be resolved", - environment: serviceCreateWithMissingGateway, - expectedLocalServices: []*corev1.Service{ - mirroredService("service-one-remote", "ns1", "missing-gateway", "missing-namespace", "111", "", nil), - }, - expectedLocalEndpoints: []*corev1.Endpoints{ - endpoints("service-one-remote", "ns1", "missing-gateway", "missing-namespace", "", "", nil), - }, + description: "does not create service and endpoints when gateway address is missing", + environment: serviceCreateWithMissingGateway, + expectedLocalServices: []*corev1.Service{}, + expectedLocalEndpoints: []*corev1.Endpoints{}, }, { - description: "create service and endpoints without subsets when gateway spec is wrong", - environment: createServiceWrongGatewaySpec, - expectedLocalServices: []*corev1.Service{ - mirroredService("service-one-remote", "ns1", "existing-gateway", "existing-namespace", "111", "", - []corev1.ServicePort{ - { - Name: "port1", - Protocol: "TCP", - Port: 555, - }, - { - Name: "port2", - Protocol: "TCP", - Port: 666, - }, - }), - }, - expectedLocalEndpoints: []*corev1.Endpoints{ - endpoints("service-one-remote", "ns1", "existing-gateway", "existing-namespace", "", "", nil), - }, + description: "does not create service and endpoints when gateway spec is wrong", + environment: createServiceWrongGatewaySpec, + expectedLocalServices: []*corev1.Service{}, + expectedLocalEndpoints: []*corev1.Endpoints{}, }, { description: "create service and endpoints when gateway can be resolved", environment: createServiceOkeGatewaySpec, expectedLocalServices: []*corev1.Service{ - mirroredService( + mirrorService( "service-one-remote", "ns1", - "existing-gateway", - "existing-namespace", "111", - "222", []corev1.ServicePort{ { Name: "port1", @@ -150,7 +125,7 @@ func TestRemoteServiceCreatedMirroring(t *testing.T) { }), }, expectedLocalEndpoints: []*corev1.Endpoints{ - endpoints("service-one-remote", "ns1", "existing-gateway", "existing-namespace", "192.0.2.127", "gateway-identity", []corev1.EndpointPort{ + endpoints("service-one-remote", "ns1", "192.0.2.127", "gateway-identity", []corev1.EndpointPort{ { Name: "port1", Port: 888, @@ -184,50 +159,11 @@ func TestRemoteServiceDeletedMirroring(t *testing.T) { func TestRemoteServiceUpdatedMirroring(t *testing.T) { for _, tt := range []mirroringTestCase{ - { - description: "update to new gateway", - environment: updateServiceToNewGateway, - expectedLocalServices: []*corev1.Service{ - mirroredService( - "test-service-remote", - "test-namespace", - "gateway-new", - "gateway-ns", - "currentServiceResVersion", - "currentGatewayResVersion", - []corev1.ServicePort{ - { - Name: "port1", - Protocol: "TCP", - Port: 111, - }, - { - Name: "port3", - Protocol: "TCP", - Port: 333, - }, - }), - }, - expectedLocalEndpoints: []*corev1.Endpoints{ - endpoints("test-service-remote", "test-namespace", "gateway-new", "gateway-ns", "0.0.0.0", "", []corev1.EndpointPort{ - { - Name: "port1", - Port: 999, - Protocol: "TCP", - }, - { - Name: "port2", - Port: 999, - Protocol: "TCP", - }, - }), - }, - }, { description: "updates service ports on both service and endpoints", environment: updateServiceWithChangedPorts, expectedLocalServices: []*corev1.Service{ - mirroredService("test-service-remote", "test-namespace", "gateway", "gateway-ns", "currentServiceResVersion", "currentGatewayResVersion", + mirrorService("test-service-remote", "test-namespace", "currentServiceResVersion", []corev1.ServicePort{ { Name: "port1", @@ -243,7 +179,7 @@ func TestRemoteServiceUpdatedMirroring(t *testing.T) { }, expectedLocalEndpoints: []*corev1.Endpoints{ - endpoints("test-service-remote", "test-namespace", "gateway", "gateway-ns", "192.0.2.127", "", []corev1.EndpointPort{ + endpoints("test-service-remote", "test-namespace", "192.0.2.127", "gateway-identity", []corev1.EndpointPort{ { Name: "port1", Port: 888, @@ -263,189 +199,6 @@ func TestRemoteServiceUpdatedMirroring(t *testing.T) { } } -func TestRemoteGatewayUpdatedMirroring(t *testing.T) { - - localhostIP, err := net.ResolveIPAddr("ip", "localhost") - if err != nil { - t.Fatal(err) - } - - for _, tt := range []mirroringTestCase{ - { - description: "endpoints ports are updated on gateway change", - environment: remoteGatewayUpdated, - expectedLocalServices: []*corev1.Service{ - mirroredService("test-service-1-remote", "test-namespace", "gateway", "gateway-ns", "", "currentGatewayResVersion", - []corev1.ServicePort{ - { - Name: "svc-1-port", - Protocol: "TCP", - Port: 8081, - }, - }), - - mirroredService("test-service-2-remote", "test-namespace", "gateway", "gateway-ns", "", "currentGatewayResVersion", []corev1.ServicePort{ - { - Name: "svc-2-port", - Protocol: "TCP", - Port: 8082, - }, - }), - }, - expectedLocalEndpoints: []*corev1.Endpoints{ - endpoints("test-service-1-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0", "", - []corev1.EndpointPort{ - { - Name: "svc-1-port", - Port: 999, - Protocol: "TCP", - }}), - endpoints("test-service-2-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0", "", - []corev1.EndpointPort{ - { - Name: "svc-2-port", - Port: 999, - Protocol: "TCP", - }}), - }, - }, - - { - description: "endpoints addresses are updated on gateway change", - environment: gatewayAddressChanged, - expectedLocalServices: []*corev1.Service{ - mirroredService("test-service-1-remote", "test-namespace", "gateway", "gateway-ns", "", "currentGatewayResVersion", - []corev1.ServicePort{ - { - Name: "svc-1-port", - Protocol: "TCP", - Port: 8081, - }, - }), - mirroredService("test-service-2-remote", "test-namespace", "gateway", "gateway-ns", "", "currentGatewayResVersion", []corev1.ServicePort{ - { - Name: "svc-2-port", - Protocol: "TCP", - Port: 8082, - }, - }), - }, - expectedLocalEndpoints: []*corev1.Endpoints{ - endpoints("test-service-1-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.1", "", - []corev1.EndpointPort{ - { - Name: "svc-1-port", - Port: 888, - Protocol: "TCP", - }}), - endpoints("test-service-2-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.1", "", - []corev1.EndpointPort{ - { - Name: "svc-2-port", - Port: 888, - Protocol: "TCP", - }}), - }, - }, - - { - description: "identity is updated on gateway change", - environment: gatewayIdentityChanged, - expectedLocalServices: []*corev1.Service{ - mirroredService("test-service-1-remote", "test-namespace", "gateway", "gateway-ns", "", "currentGatewayResVersion", - []corev1.ServicePort{ - { - Name: "svc-1-port", - Protocol: "TCP", - Port: 8081, - }, - }), - mirroredService("test-service-2-remote", "test-namespace", "gateway", "gateway-ns", "", "currentGatewayResVersion", []corev1.ServicePort{ - { - Name: "svc-2-port", - Protocol: "TCP", - Port: 8082, - }, - }), - }, - expectedLocalEndpoints: []*corev1.Endpoints{ - endpoints("test-service-1-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0", "new-identity", - []corev1.EndpointPort{ - { - Name: "svc-1-port", - Port: 888, - Protocol: "TCP", - }}), - endpoints("test-service-2-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0", "new-identity", - []corev1.EndpointPort{ - { - Name: "svc-2-port", - Port: 888, - Protocol: "TCP", - }}), - }, - }, - { - description: "gateway uses hostname address", - environment: remoteGatewayUpdatedWithHostnameAddress, - expectedEventsInQueue: []interface{}{ - &RemoteGatewayUpdated{ - gatewaySpec: GatewaySpec{ - gatewayName: "gateway", - gatewayNamespace: "gateway-ns", - clusterName: "remote", - addresses: []corev1.EndpointAddress{{IP: localhostIP.String()}}, - incomingPort: 999, - resourceVersion: "currentGatewayResVersion", - ProbeConfig: &ProbeConfig{ - path: defaultProbePath, - port: defaultProbePort, - periodInSeconds: defaultProbePeriod, - }, - }, - affectedServices: []*v1.Service{}, - }, - }, - }, - } { - tc := tt // pin - tc.run(t) - } -} -func TestRemoteGatewayDeletedMirroring(t *testing.T) { - for _, tt := range []mirroringTestCase{ - { - description: "removes endpoint subsets when gateway is deleted", - environment: gatewayDeleted, - expectedLocalServices: []*corev1.Service{ - mirroredService("test-service-1-remote", "test-namespace", "gateway", "gateway-ns", "", "pastGatewayResVersion", - []corev1.ServicePort{ - { - Name: "svc-1-port", - Protocol: "TCP", - Port: 8081, - }, - }), - - mirroredService("test-service-2-remote", "test-namespace", "gateway", "gateway-ns", "", "pastGatewayResVersion", []corev1.ServicePort{ - { - Name: "svc-2-port", - Protocol: "TCP", - Port: 8082, - }, - }), - }, - expectedLocalEndpoints: []*corev1.Endpoints{ - endpoints("test-service-1-remote", "test-namespace", "gateway", "gateway-ns", "", "", nil), - endpoints("test-service-2-remote", "test-namespace", "gateway", "gateway-ns", "", "", nil), - }, - }, - } { - tc := tt // pin - tc.run(t) - } -} - func TestClusterUnregisteredMirroring(t *testing.T) { for _, tt := range []mirroringTestCase{ { @@ -464,11 +217,11 @@ func TestGcOrphanedServicesMirroring(t *testing.T) { description: "deletes mirrored resources that are no longer present on the remote cluster", environment: gcTriggered, expectedLocalServices: []*corev1.Service{ - mirroredService("test-service-1-remote", "test-namespace", "gateway", "gateway-ns", "", "", nil), + mirrorService("test-service-1-remote", "test-namespace", "", nil), }, expectedLocalEndpoints: []*corev1.Endpoints{ - endpoints("test-service-1-remote", "test-namespace", "", "", "", "", nil), + endpoints("test-service-1-remote", "test-namespace", "", "", nil), }, }, } { @@ -490,39 +243,31 @@ func onAddOrUpdateTestCases(isAdd bool) []mirroringTestCase { environment: onAddOrUpdateExportedSvc(isAdd), expectedEventsInQueue: []interface{}{&RemoteServiceCreated{ service: remoteService("test-service", "test-namespace", "gateway", "gateway-ns", "resVersion", nil), - gatewayData: gatewayMetadata{ - Name: "gateway", - Namespace: "gateway-ns", - }, }}, }, { description: fmt.Sprintf("enqueue a RemoteServiceUpdated event if this is a service that we have already mirrored and its res version is different (%s)", testType), environment: onAddOrUpdateRemoteServiceUpdated(isAdd), expectedEventsInQueue: []interface{}{&RemoteServiceUpdated{ - localService: mirroredService("test-service-remote", "test-namespace", "gateway", "gateway-ns", "pastResourceVersion", "gatewayResVersion", nil), - localEndpoints: endpoints("test-service-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0", "", nil), + localService: mirrorService("test-service-remote", "test-namespace", "pastResourceVersion", nil), + localEndpoints: endpoints("test-service-remote", "test-namespace", "0.0.0.0", "", nil), remoteUpdate: remoteService("test-service", "test-namespace", "gateway", "gateway-ns", "currentResVersion", nil), - gatewayData: gatewayMetadata{ - Name: "gateway", - Namespace: "gateway-ns", - }, }}, expectedLocalServices: []*corev1.Service{ - mirroredService("test-service-remote", "test-namespace", "gateway", "gateway-ns", "pastResourceVersion", "gatewayResVersion", nil), + mirrorService("test-service-remote", "test-namespace", "pastResourceVersion", nil), }, expectedLocalEndpoints: []*corev1.Endpoints{ - endpoints("test-service-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0", "", nil), + endpoints("test-service-remote", "test-namespace", "0.0.0.0", "", nil), }, }, { description: fmt.Sprintf("not enqueue any events as this update does not really tell us anything new (res version is the same...) (%s)", testType), environment: onAddOrUpdateSameResVersion(isAdd), expectedLocalServices: []*corev1.Service{ - mirroredService("test-service-remote", "test-namespace", "gateway", "gateway-ns", "currentResVersion", "gatewayResVersion", nil), + mirrorService("test-service-remote", "test-namespace", "currentResVersion", nil), }, expectedLocalEndpoints: []*corev1.Endpoints{ - endpoints("test-service-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0", "", nil), + endpoints("test-service-remote", "test-namespace", "0.0.0.0", "", nil), }, }, { @@ -534,10 +279,10 @@ func onAddOrUpdateTestCases(isAdd bool) []mirroringTestCase { }}, expectedLocalServices: []*corev1.Service{ - mirroredService("test-service-remote", "test-namespace", "gateway", "gateway-ns", "currentResVersion", "gatewayResVersion", nil), + mirrorService("test-service-remote", "test-namespace", "currentResVersion", nil), }, expectedLocalEndpoints: []*corev1.Endpoints{ - endpoints("test-service-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0", "", nil), + endpoints("test-service-remote", "test-namespace", "0.0.0.0", "", nil), }, }, } diff --git a/controller/cmd/service-mirror/cluster_watcher_test_util.go b/controller/cmd/service-mirror/cluster_watcher_test_util.go index b59dc0b61b2ed..a1f9ff24d630e 100644 --- a/controller/cmd/service-mirror/cluster_watcher_test_util.go +++ b/controller/cmd/service-mirror/cluster_watcher_test_util.go @@ -5,10 +5,12 @@ import ( "log" "reflect" "strings" + "time" "github.com/ghodss/yaml" "github.com/linkerd/linkerd2/controller/k8s" consts "github.com/linkerd/linkerd2/pkg/k8s" + "github.com/linkerd/linkerd2/pkg/multicluster" logging "github.com/sirupsen/logrus" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -23,10 +25,17 @@ const ( defaultProbePeriod = 60 ) +var defaultProbeSpec = multicluster.ProbeSpec{ + Path: defaultProbePath, + Port: defaultProbePort, + Period: time.Duration(defaultProbePeriod) * time.Second, +} + type testEnvironment struct { events []interface{} remoteResources []string localResources []string + link multicluster.Link } func (te *testEnvironment) runEnvironment(watcherQueue workqueue.RateLimitingInterface) (*k8s.API, error) { @@ -44,8 +53,7 @@ func (te *testEnvironment) runEnvironment(watcherQueue workqueue.RateLimitingInt localAPI.Sync(nil) watcher := RemoteClusterServiceWatcher{ - clusterName: clusterName, - clusterDomain: clusterDomain, + link: &te.link, remoteAPIClient: remoteAPI, localAPIClient: localAPI, stopper: nil, @@ -72,12 +80,12 @@ var serviceCreateWithMissingGateway = &testEnvironment{ events: []interface{}{ &RemoteServiceCreated{ service: remoteService("service-one", "ns1", "missing-gateway", "missing-namespace", "111", nil), - gatewayData: gatewayMetadata{ - Name: "missing-gateway", - Namespace: "missing-namespace", - }, }, }, + link: multicluster.Link{ + TargetClusterName: clusterName, + GatewayAddress: "", + }, } var createServiceWrongGatewaySpec = &testEnvironment{ @@ -96,15 +104,14 @@ var createServiceWrongGatewaySpec = &testEnvironment{ Port: 666, }, }), - - gatewayData: gatewayMetadata{ - Name: "existing-gateway", - Namespace: "existing-namespace", - }, }, }, remoteResources: []string{ - gatewayAsYaml("existing-gateway", "existing-namespace", "222", "192.0.2.127", "", "mc-wrong", 888, "", 111, "/path", 666), + gatewayAsYaml("existing-gateway", "existing-namespace", "222", "192.0.2.127", "mc-wrong", 888, "", 111, "/path", 666), + }, + link: multicluster.Link{ + TargetClusterName: clusterName, + GatewayAddress: "??????", }, } @@ -123,14 +130,18 @@ var createServiceOkeGatewaySpec = &testEnvironment{ Port: 666, }, }), - gatewayData: gatewayMetadata{ - Name: "existing-gateway", - Namespace: "existing-namespace", - }, }, }, remoteResources: []string{ - gatewayAsYaml("existing-gateway", "existing-namespace", "222", "192.0.2.127", "", "mc-gateway", 888, "gateway-identity", defaultProbePort, defaultProbePath, defaultProbePeriod), + gatewayAsYaml("existing-gateway", "existing-namespace", "222", "192.0.2.127", "mc-gateway", 888, "gateway-identity", defaultProbePort, defaultProbePath, defaultProbePeriod), + }, + link: multicluster.Link{ + TargetClusterName: clusterName, + TargetClusterDomain: clusterDomain, + GatewayIdentity: "gateway-identity", + GatewayAddress: "192.0.2.127", + GatewayPort: 888, + ProbeSpec: defaultProbeSpec, }, } @@ -142,84 +153,16 @@ var deleteMirroredService = &testEnvironment{ }, }, localResources: []string{ - mirroredServiceAsYaml("test-service-remote-to-delete-remote", "test-namespace-to-delete", "", "", "", "", nil), - endpointsAsYaml("test-service-remote-to-delete-remote", "test-namespace-to-delete", "", "", "", "gateway-identity", nil), - }, -} - -var updateServiceToNewGateway = &testEnvironment{ - events: []interface{}{ - &RemoteServiceUpdated{ - remoteUpdate: remoteService("test-service", "test-namespace", "gateway-new", "gateway-ns", "currentServiceResVersion", []corev1.ServicePort{ - { - Name: "port1", - Protocol: "TCP", - Port: 111, - }, - { - Name: "port2", - Protocol: "TCP", - Port: 222, - }, - }), - localService: mirroredService("test-service-remote", "test-namespace", "gateway", "gateway-ns", "pastServiceResVersion", "pastGatewayResVersion", []corev1.ServicePort{ - { - Name: "port1", - Protocol: "TCP", - Port: 111, - }, - { - Name: "port2", - Protocol: "TCP", - Port: 222, - }, - }), - localEndpoints: endpoints("test-service-remote", "test-namespace", "gateway", "gateway-ns", "192.0.2.127", "", []corev1.EndpointPort{ - { - Name: "port1", - Port: 888, - Protocol: "TCP", - }, - { - Name: "port2", - Port: 888, - Protocol: "TCP", - }, - }), - gatewayData: gatewayMetadata{ - Name: "gateway-new", - Namespace: "gateway-ns", - }, - }, + mirrorServiceAsYaml("test-service-remote-to-delete-remote", "test-namespace-to-delete", "", nil), + endpointsAsYaml("test-service-remote-to-delete-remote", "test-namespace-to-delete", "", "gateway-identity", nil), }, - remoteResources: []string{ - gatewayAsYaml("gateway-new", "gateway-ns", "currentGatewayResVersion", "0.0.0.0", "", "mc-gateway", 999, "", defaultProbePort, defaultProbePath, defaultProbePeriod), - }, - localResources: []string{ - mirroredServiceAsYaml("test-service-remote", "test-namespace", "gateway", "gateway-ns", "past", "pastGatewayResVersion", []corev1.ServicePort{ - { - Name: "port1", - Protocol: "TCP", - Port: 111, - }, - { - Name: "port2", - Protocol: "TCP", - Port: 222, - }, - }), - endpointsAsYaml("test-service-remote", "test-namespace", "gateway", "gateway-ns", "192.0.2.127", "", []corev1.EndpointPort{ - { - Name: "port1", - Port: 888, - Protocol: "TCP", - }, - { - Name: "port2", - Port: 888, - Protocol: "TCP", - }, - }), + link: multicluster.Link{ + TargetClusterName: clusterName, + TargetClusterDomain: clusterDomain, + GatewayIdentity: "gateway-identity", + GatewayAddress: "192.0.2.127", + GatewayPort: 888, + ProbeSpec: defaultProbeSpec, }, } @@ -238,7 +181,7 @@ var updateServiceWithChangedPorts = &testEnvironment{ Port: 333, }, }), - localService: mirroredService("test-service-remote", "test-namespace", "gateway", "gateway-ns", "pastServiceResVersion", "pastGatewayResVersion", []corev1.ServicePort{ + localService: mirrorService("test-service-remote", "test-namespace", "pastServiceResVersion", []corev1.ServicePort{ { Name: "port1", Protocol: "TCP", @@ -250,7 +193,7 @@ var updateServiceWithChangedPorts = &testEnvironment{ Port: 222, }, }), - localEndpoints: endpoints("test-service-remote", "test-namespace", "gateway", "gateway-ns", "192.0.2.127", "", []corev1.EndpointPort{ + localEndpoints: endpoints("test-service-remote", "test-namespace", "192.0.2.127", "", []corev1.EndpointPort{ { Name: "port1", Port: 888, @@ -262,17 +205,13 @@ var updateServiceWithChangedPorts = &testEnvironment{ Protocol: "TCP", }, }), - gatewayData: gatewayMetadata{ - Name: "gateway", - Namespace: "gateway-ns", - }, }, }, remoteResources: []string{ - gatewayAsYaml("gateway", "gateway-ns", "currentGatewayResVersion", "192.0.2.127", "", "mc-gateway", 888, "", defaultProbePort, defaultProbePath, defaultProbePeriod), + gatewayAsYaml("gateway", "gateway-ns", "currentGatewayResVersion", "192.0.2.127", "mc-gateway", 888, "", defaultProbePort, defaultProbePath, defaultProbePeriod), }, localResources: []string{ - mirroredServiceAsYaml("test-service-remote", "test-namespace", "gateway", "gateway-ns", "past", "pastGatewayResVersion", []corev1.ServicePort{ + mirrorServiceAsYaml("test-service-remote", "test-namespace", "past", []corev1.ServicePort{ { Name: "port1", Protocol: "TCP", @@ -289,7 +228,7 @@ var updateServiceWithChangedPorts = &testEnvironment{ Port: 333, }, }), - endpointsAsYaml("test-service-remote", "test-namespace", "gateway", "gateway-ns", "192.0.2.127", "", []corev1.EndpointPort{ + endpointsAsYaml("test-service-remote", "test-namespace", "192.0.2.127", "", []corev1.EndpointPort{ { Name: "port1", Port: 888, @@ -307,262 +246,13 @@ var updateServiceWithChangedPorts = &testEnvironment{ }, }), }, -} - -var remoteGatewayUpdated = &testEnvironment{ - events: []interface{}{ - &RemoteGatewayUpdated{ - gatewaySpec: GatewaySpec{ - gatewayName: "gateway", - gatewayNamespace: "gateway-ns", - clusterName: "remote", - addresses: []corev1.EndpointAddress{{IP: "0.0.0.0"}}, - incomingPort: 999, - resourceVersion: "currentGatewayResVersion", - ProbeConfig: &ProbeConfig{ - path: defaultProbePath, - port: defaultProbePort, - periodInSeconds: defaultProbePeriod, - }, - }, - affectedServices: []*corev1.Service{ - mirroredService("test-service-1-remote", "test-namespace", "gateway", "gateway-ns", "", "pastGatewayResVersion", - []corev1.ServicePort{ - { - Name: "svc-1-port", - Protocol: "TCP", - Port: 8081, - }, - }), - - mirroredService("test-service-2-remote", "test-namespace", "gateway", "gateway-ns", "", "pastGatewayResVersion", []corev1.ServicePort{ - { - Name: "svc-2-port", - Protocol: "TCP", - Port: 8082, - }, - }), - }, - }, - }, - localResources: []string{ - mirroredServiceAsYaml("test-service-1-remote", "test-namespace", "gateway", "gateway-ns", "", "pastGatewayResVersion", - []corev1.ServicePort{ - { - Name: "svc-1-port", - Protocol: "TCP", - Port: 8081, - }, - }), - endpointsAsYaml("test-service-1-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0", "", - []corev1.EndpointPort{ - { - Name: "svc-1-port", - Port: 888, - Protocol: "TCP", - }}), - mirroredServiceAsYaml("test-service-2-remote", "test-namespace", "gateway", "gateway-ns", "", "pastGatewayResVersion", []corev1.ServicePort{ - { - Name: "svc-2-port", - Protocol: "TCP", - Port: 8082, - }, - }), - endpointsAsYaml("test-service-2-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0", "", - []corev1.EndpointPort{ - { - Name: "svc-2-port", - Port: 888, - Protocol: "TCP", - }}), - }, -} - -var remoteGatewayUpdatedWithHostnameAddress = &testEnvironment{ - events: []interface{}{ - &RepairEndpoints{}, - }, - remoteResources: []string{ - gatewayAsYaml("gateway", "gateway-ns", "currentGatewayResVersion", "", "localhost", "mc-gateway", 999, "", defaultProbePort, defaultProbePath, defaultProbePeriod), - }, -} - -var gatewayAddressChanged = &testEnvironment{ - events: []interface{}{ - &RemoteGatewayUpdated{ - gatewaySpec: GatewaySpec{ - gatewayName: "gateway", - gatewayNamespace: "gateway-ns", - clusterName: "some-cluster", - addresses: []corev1.EndpointAddress{{IP: "0.0.0.1"}}, - incomingPort: 888, - resourceVersion: "currentGatewayResVersion", - ProbeConfig: &ProbeConfig{ - path: "/p", - port: 1, - periodInSeconds: 222, - }, - }, - affectedServices: []*corev1.Service{ - mirroredService("test-service-1-remote", "test-namespace", "gateway", "gateway-ns", "", "pastGatewayResVersion", - []corev1.ServicePort{ - { - Name: "svc-1-port", - Protocol: "TCP", - Port: 8081, - }, - }), - mirroredService("test-service-2-remote", "test-namespace", "gateway", "gateway-ns", "", "pastGatewayResVersion", []corev1.ServicePort{ - { - Name: "svc-2-port", - Protocol: "TCP", - Port: 8082, - }, - }), - }, - }, - }, - localResources: []string{ - mirroredServiceAsYaml("test-service-1-remote", "test-namespace", "gateway", "gateway-ns", "", "pastGatewayResVersion", - []corev1.ServicePort{ - { - Name: "svc-1-port", - Protocol: "TCP", - Port: 8081, - }, - }), - endpointsAsYaml("test-service-1-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0", "", - []corev1.EndpointPort{ - { - Name: "svc-1-port", - Port: 888, - Protocol: "TCP", - }}), - mirroredServiceAsYaml("test-service-2-remote", "test-namespace", "gateway", "gateway-ns", "", "pastGatewayResVersion", []corev1.ServicePort{ - { - Name: "svc-2-port", - Protocol: "TCP", - Port: 8082, - }, - }), - endpointsAsYaml("test-service-2-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0", "", - []corev1.EndpointPort{ - { - Name: "svc-2-port", - Port: 888, - Protocol: "TCP", - }}), - }, -} - -var gatewayIdentityChanged = &testEnvironment{ - events: []interface{}{ - &RemoteGatewayUpdated{ - gatewaySpec: GatewaySpec{ - gatewayName: "gateway", - gatewayNamespace: "gateway-ns", - clusterName: clusterName, - addresses: []corev1.EndpointAddress{{IP: "0.0.0.0"}}, - incomingPort: 888, - resourceVersion: "currentGatewayResVersion", - identity: "new-identity", - ProbeConfig: &ProbeConfig{ - path: defaultProbePath, - port: defaultProbePort, - periodInSeconds: defaultProbePeriod, - }, - }, - affectedServices: []*corev1.Service{ - mirroredService("test-service-1-remote", "test-namespace", "gateway", "gateway-ns", "", "pastGatewayResVersion", - []corev1.ServicePort{ - { - Name: "svc-1-port", - Protocol: "TCP", - Port: 8081, - }, - }), - mirroredService("test-service-2-remote", "test-namespace", "gateway", "gateway-ns", "", "pastGatewayResVersion", []corev1.ServicePort{ - { - Name: "svc-2-port", - Protocol: "TCP", - Port: 8082, - }, - }), - }, - }, - }, - localResources: []string{ - mirroredServiceAsYaml("test-service-1-remote", "test-namespace", "gateway", "gateway-ns", "", "pastGatewayResVersion", - []corev1.ServicePort{ - { - Name: "svc-1-port", - Protocol: "TCP", - Port: 8081, - }, - }), - endpointsAsYaml("test-service-1-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0", "", - []corev1.EndpointPort{ - { - Name: "svc-1-port", - Port: 888, - Protocol: "TCP", - }}), - mirroredServiceAsYaml("test-service-2-remote", "test-namespace", "gateway", "gateway-ns", "", "pastGatewayResVersion", []corev1.ServicePort{ - { - Name: "svc-2-port", - Protocol: "TCP", - Port: 8082, - }, - }), - endpointsAsYaml("test-service-2-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0", "", - []corev1.EndpointPort{ - { - Name: "svc-2-port", - Port: 888, - Protocol: "TCP", - }}), - }, -} - -var gatewayDeleted = &testEnvironment{ - events: []interface{}{ - &RemoteGatewayDeleted{ - gatewayData: gatewayMetadata{ - Name: "gateway", - Namespace: "gateway-ns", - }, - }, - }, - localResources: []string{ - mirroredServiceAsYaml("test-service-1-remote", "test-namespace", "gateway", "gateway-ns", "", "pastGatewayResVersion", - []corev1.ServicePort{ - { - Name: "svc-1-port", - Protocol: "TCP", - Port: 8081, - }, - }), - endpointsAsYaml("test-service-1-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0", "", - []corev1.EndpointPort{ - { - Name: "svc-1-port", - Port: 888, - Protocol: "TCP", - }}), - mirroredServiceAsYaml("test-service-2-remote", "test-namespace", "gateway", "gateway-ns", "", "pastGatewayResVersion", []corev1.ServicePort{ - { - Name: "svc-2-port", - Protocol: "TCP", - Port: 8082, - }, - }), - endpointsAsYaml("test-service-2-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0", "", - []corev1.EndpointPort{ - { - Name: "svc-2-port", - Port: 888, - Protocol: "TCP", - }}), + link: multicluster.Link{ + TargetClusterName: clusterName, + TargetClusterDomain: clusterDomain, + GatewayIdentity: "gateway-identity", + GatewayAddress: "192.0.2.127", + GatewayPort: 888, + ProbeSpec: defaultProbeSpec, }, } @@ -571,10 +261,13 @@ var clusterUnregistered = &testEnvironment{ &ClusterUnregistered{}, }, localResources: []string{ - mirroredServiceAsYaml("test-service-1-remote", "test-namespace", "", "", "", "", nil), - endpointsAsYaml("test-service-1-remote", "test-namespace", "", "", "", "", nil), - mirroredServiceAsYaml("test-service-2-remote", "test-namespace", "", "", "", "", nil), - endpointsAsYaml("test-service-2-remote", "test-namespace", "", "", "", "", nil), + mirrorServiceAsYaml("test-service-1-remote", "test-namespace", "", nil), + endpointsAsYaml("test-service-1-remote", "test-namespace", "", "", nil), + mirrorServiceAsYaml("test-service-2-remote", "test-namespace", "", nil), + endpointsAsYaml("test-service-2-remote", "test-namespace", "", "", nil), + }, + link: multicluster.Link{ + TargetClusterName: clusterName, }, } @@ -583,14 +276,17 @@ var gcTriggered = &testEnvironment{ &OprhanedServicesGcTriggered{}, }, localResources: []string{ - mirroredServiceAsYaml("test-service-1-remote", "test-namespace", "gateway", "gateway-ns", "", "", nil), - endpointsAsYaml("test-service-1-remote", "test-namespace", "", "", "", "", nil), - mirroredServiceAsYaml("test-service-2-remote", "test-namespace", "", "", "", "", nil), - endpointsAsYaml("test-service-2-remote", "test-namespace", "", "", "", "", nil), + mirrorServiceAsYaml("test-service-1-remote", "test-namespace", "", nil), + endpointsAsYaml("test-service-1-remote", "test-namespace", "", "", nil), + mirrorServiceAsYaml("test-service-2-remote", "test-namespace", "", nil), + endpointsAsYaml("test-service-2-remote", "test-namespace", "", "", nil), }, remoteResources: []string{ remoteServiceAsYaml("test-service-1", "test-namespace", "gateway", "gateway-ns", "", nil), }, + link: multicluster.Link{ + TargetClusterName: clusterName, + }, } func onAddOrUpdateExportedSvc(isAdd bool) *testEnvironment { @@ -598,6 +294,14 @@ func onAddOrUpdateExportedSvc(isAdd bool) *testEnvironment { events: []interface{}{ onAddOrUpdateEvent(isAdd, remoteService("test-service", "test-namespace", "gateway", "gateway-ns", "resVersion", nil)), }, + link: multicluster.Link{ + TargetClusterName: clusterName, + TargetClusterDomain: clusterDomain, + GatewayIdentity: "gateway-identity", + GatewayAddress: "192.0.2.127", + GatewayPort: 888, + ProbeSpec: defaultProbeSpec, + }, } } @@ -608,8 +312,16 @@ func onAddOrUpdateRemoteServiceUpdated(isAdd bool) *testEnvironment { onAddOrUpdateEvent(isAdd, remoteService("test-service", "test-namespace", "gateway", "gateway-ns", "currentResVersion", nil)), }, localResources: []string{ - mirroredServiceAsYaml("test-service-remote", "test-namespace", "gateway", "gateway-ns", "pastResourceVersion", "gatewayResVersion", nil), - endpointsAsYaml("test-service-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0", "", nil), + mirrorServiceAsYaml("test-service-remote", "test-namespace", "pastResourceVersion", nil), + endpointsAsYaml("test-service-remote", "test-namespace", "0.0.0.0", "", nil), + }, + link: multicluster.Link{ + TargetClusterName: clusterName, + TargetClusterDomain: clusterDomain, + GatewayIdentity: "gateway-identity", + GatewayAddress: "192.0.2.127", + GatewayPort: 888, + ProbeSpec: defaultProbeSpec, }, } } @@ -620,8 +332,16 @@ func onAddOrUpdateSameResVersion(isAdd bool) *testEnvironment { onAddOrUpdateEvent(isAdd, remoteService("test-service", "test-namespace", "gateway", "gateway-ns", "currentResVersion", nil)), }, localResources: []string{ - mirroredServiceAsYaml("test-service-remote", "test-namespace", "gateway", "gateway-ns", "currentResVersion", "gatewayResVersion", nil), - endpointsAsYaml("test-service-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0", "", nil), + mirrorServiceAsYaml("test-service-remote", "test-namespace", "currentResVersion", nil), + endpointsAsYaml("test-service-remote", "test-namespace", "0.0.0.0", "", nil), + }, + link: multicluster.Link{ + TargetClusterName: clusterName, + TargetClusterDomain: clusterDomain, + GatewayIdentity: "gateway-identity", + GatewayAddress: "192.0.2.127", + GatewayPort: 888, + ProbeSpec: defaultProbeSpec, }, } } @@ -632,8 +352,16 @@ func serviceNotExportedAnymore(isAdd bool) *testEnvironment { onAddOrUpdateEvent(isAdd, remoteService("test-service", "test-namespace", "", "gateway-ns", "currentResVersion", nil)), }, localResources: []string{ - mirroredServiceAsYaml("test-service-remote", "test-namespace", "gateway", "gateway-ns", "currentResVersion", "gatewayResVersion", nil), - endpointsAsYaml("test-service-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0", "", nil), + mirrorServiceAsYaml("test-service-remote", "test-namespace", "currentResVersion", nil), + endpointsAsYaml("test-service-remote", "test-namespace", "0.0.0.0", "", nil), + }, + link: multicluster.Link{ + TargetClusterName: clusterName, + TargetClusterDomain: clusterDomain, + GatewayIdentity: "gateway-identity", + GatewayAddress: "192.0.2.127", + GatewayPort: 888, + ProbeSpec: defaultProbeSpec, }, } } @@ -644,6 +372,14 @@ var onDeleteWithGatewayMetadata = &testEnvironment{ svc: remoteService("test-service", "test-namespace", "gateway", "gateway-ns", "currentResVersion", nil), }, }, + link: multicluster.Link{ + TargetClusterName: clusterName, + TargetClusterDomain: clusterDomain, + GatewayIdentity: "gateway-identity", + GatewayAddress: "192.0.2.127", + GatewayPort: 888, + ProbeSpec: defaultProbeSpec, + }, } var onDeleteNoGatewayMetadata = &testEnvironment{ @@ -652,6 +388,14 @@ var onDeleteNoGatewayMetadata = &testEnvironment{ svc: remoteService("gateway", "test-namespace", "", "", "currentResVersion", nil), }, }, + link: multicluster.Link{ + TargetClusterName: clusterName, + TargetClusterDomain: clusterDomain, + GatewayIdentity: "gateway-identity", + GatewayAddress: "192.0.2.127", + GatewayPort: 888, + ProbeSpec: defaultProbeSpec, + }, } // the following tests ensure that onAdd, onUpdate and onDelete result in @@ -742,15 +486,11 @@ func remoteServiceAsYaml(name, namespace, gtwName, gtwNs, resourceVersion string return string(bytes) } -func mirroredService(name, namespace, gtwName, gtwNs, resourceVersion, gatewayResourceVersion string, ports []corev1.ServicePort) *corev1.Service { +func mirrorService(name, namespace, resourceVersion string, ports []corev1.ServicePort) *corev1.Service { annotations := make(map[string]string) annotations[consts.RemoteResourceVersionAnnotation] = resourceVersion annotations[consts.RemoteServiceFqName] = fmt.Sprintf("%s.%s.svc.cluster.local", strings.Replace(name, "-remote", "", 1), namespace) - if gatewayResourceVersion != "" { - annotations[consts.RemoteGatewayResourceVersionAnnotation] = gatewayResourceVersion - - } return &corev1.Service{ TypeMeta: metav1.TypeMeta{ Kind: "Service", @@ -760,10 +500,8 @@ func mirroredService(name, namespace, gtwName, gtwNs, resourceVersion, gatewayRe Name: name, Namespace: namespace, Labels: map[string]string{ - consts.RemoteClusterNameLabel: "remote", + consts.RemoteClusterNameLabel: clusterName, consts.MirroredResourceLabel: "true", - consts.RemoteGatewayNameLabel: gtwName, - consts.RemoteGatewayNsLabel: gtwNs, }, Annotations: annotations, }, @@ -773,8 +511,8 @@ func mirroredService(name, namespace, gtwName, gtwNs, resourceVersion, gatewayRe } } -func mirroredServiceAsYaml(name, namespace, gtwName, gtwNs, resourceVersion, gatewayResourceVersion string, ports []corev1.ServicePort) string { - svc := mirroredService(name, namespace, gtwName, gtwNs, resourceVersion, gatewayResourceVersion, ports) +func mirrorServiceAsYaml(name, namespace, resourceVersion string, ports []corev1.ServicePort) string { + svc := mirrorService(name, namespace, resourceVersion, ports) bytes, err := yaml.Marshal(svc) if err != nil { @@ -825,8 +563,8 @@ func gateway(name, namespace, resourceVersion, ip, hostname, portName string, po return &svc } -func gatewayAsYaml(name, namespace, resourceVersion, ip, hostname, portName string, port int32, identity string, probePort int32, probePath string, probePeriod int) string { - gtw := gateway(name, namespace, resourceVersion, ip, hostname, portName, port, identity, probePort, probePath, probePeriod) +func gatewayAsYaml(name, namespace, resourceVersion, ip, portName string, port int32, identity string, probePort int32, probePath string, probePeriod int) string { + gtw := gateway(name, namespace, resourceVersion, ip, "", portName, port, identity, probePort, probePath, probePeriod) bytes, err := yaml.Marshal(gtw) if err != nil { @@ -835,7 +573,7 @@ func gatewayAsYaml(name, namespace, resourceVersion, ip, hostname, portName stri return string(bytes) } -func endpoints(name, namespace, gtwName, gtwNs, gatewayIP string, gatewayIdentity string, ports []corev1.EndpointPort) *corev1.Endpoints { +func endpoints(name, namespace, gatewayIP string, gatewayIdentity string, ports []corev1.EndpointPort) *corev1.Endpoints { var subsets []corev1.EndpointSubset if gatewayIP != "" { subsets = []corev1.EndpointSubset{ @@ -859,10 +597,8 @@ func endpoints(name, namespace, gtwName, gtwNs, gatewayIP string, gatewayIdentit Name: name, Namespace: namespace, Labels: map[string]string{ - consts.RemoteClusterNameLabel: "remote", + consts.RemoteClusterNameLabel: clusterName, consts.MirroredResourceLabel: "true", - consts.RemoteGatewayNameLabel: gtwName, - consts.RemoteGatewayNsLabel: gtwNs, }, Annotations: map[string]string{ consts.RemoteServiceFqName: fmt.Sprintf("%s.%s.svc.cluster.local", strings.Replace(name, "-remote", "", 1), namespace), @@ -878,8 +614,8 @@ func endpoints(name, namespace, gtwName, gtwNs, gatewayIP string, gatewayIdentit return endpoints } -func endpointsAsYaml(name, namespace, gtwName, gtwNs, gatewayIP, gatewayIdentity string, ports []corev1.EndpointPort) string { - ep := endpoints(name, namespace, gtwName, gtwNs, gatewayIP, gatewayIdentity, ports) +func endpointsAsYaml(name, namespace, gatewayIP, gatewayIdentity string, ports []corev1.EndpointPort) string { + ep := endpoints(name, namespace, gatewayIP, gatewayIdentity, ports) bytes, err := yaml.Marshal(ep) if err != nil { diff --git a/controller/cmd/service-mirror/config_watcher.go b/controller/cmd/service-mirror/config_watcher.go deleted file mode 100644 index c71543acad976..0000000000000 --- a/controller/cmd/service-mirror/config_watcher.go +++ /dev/null @@ -1,161 +0,0 @@ -package servicemirror - -import ( - "fmt" - "sync" - "time" - - "github.com/linkerd/linkerd2/controller/k8s" - log "github.com/sirupsen/logrus" - corev1 "k8s.io/api/core/v1" - "k8s.io/client-go/tools/cache" - "k8s.io/client-go/tools/clientcmd" - - consts "github.com/linkerd/linkerd2/pkg/k8s" - sm "github.com/linkerd/linkerd2/pkg/servicemirror" -) - -// RemoteClusterConfigWatcher watches for secrets of type MirrorSecretType -// and upon the detection of such secret created starts a RemoteClusterServiceWatcher -type RemoteClusterConfigWatcher struct { - serviceMirrorNamespace string - k8sAPI *k8s.API - clusterWatchers map[string]*RemoteClusterServiceWatcher - requeueLimit int - repairPeriod time.Duration - sync.RWMutex -} - -// NewRemoteClusterConfigWatcher Creates a new config watcher -func NewRemoteClusterConfigWatcher(serviceMirrorNamespace string, secretsInformer cache.SharedIndexInformer, k8sAPI *k8s.API, requeueLimit int, repairPeriod time.Duration) *RemoteClusterConfigWatcher { - rcw := &RemoteClusterConfigWatcher{ - serviceMirrorNamespace: serviceMirrorNamespace, - k8sAPI: k8sAPI, - clusterWatchers: map[string]*RemoteClusterServiceWatcher{}, - requeueLimit: requeueLimit, - repairPeriod: repairPeriod, - } - secretsInformer.AddEventHandler( - cache.FilteringResourceEventHandler{ - FilterFunc: func(obj interface{}) bool { - switch object := obj.(type) { - case *corev1.Secret: - return object.Type == consts.MirrorSecretType - - case cache.DeletedFinalStateUnknown: - if secret, ok := object.Obj.(*corev1.Secret); ok { - return secret.Type == consts.MirrorSecretType - } - return false - default: - return false - } - }, - - Handler: cache.ResourceEventHandlerFuncs{ - AddFunc: func(obj interface{}) { - secret := obj.(*corev1.Secret) - if err := rcw.registerRemoteCluster(secret); err != nil { - log.Errorf("Cannot register target cluster: %s", err) - } - }, - DeleteFunc: func(obj interface{}) { - secret, ok := obj.(*corev1.Secret) - if !ok { - tombstone, ok := obj.(cache.DeletedFinalStateUnknown) - if !ok { - log.Errorf("couldn't get object from DeletedFinalStateUnknown %#v", obj) - return - } - secret, ok = tombstone.Obj.(*corev1.Secret) - if !ok { - log.Errorf("DeletedFinalStateUnknown contained object that is not a Secret %#v", obj) - return - } - } - if err := rcw.unregisterRemoteCluster(secret, true); err != nil { - log.Errorf("Cannot unregister target cluster: %s", err) - } - }, - UpdateFunc: func(old, new interface{}) { - oldSecret := old.(*corev1.Secret) - newSecret := new.(*corev1.Secret) - - if oldSecret.ResourceVersion != newSecret.ResourceVersion { - if err := rcw.unregisterRemoteCluster(oldSecret, false); err != nil { - log.Errorf("Cannot unregister target cluster: %s", err) - return - } - - if err := rcw.registerRemoteCluster(newSecret); err != nil { - log.Errorf("Cannot register target cluster: %s", err) - } - - } - - //TODO: Handle update (it might be that the credentials have changed...) - }, - }, - }, - ) - return rcw -} - -// Stop Shuts down all created config and cluster watchers -func (rcw *RemoteClusterConfigWatcher) Stop() { - rcw.Lock() - defer rcw.Unlock() - for _, watcher := range rcw.clusterWatchers { - watcher.Stop(false) - } -} - -func (rcw *RemoteClusterConfigWatcher) registerRemoteCluster(secret *corev1.Secret) error { - config, err := sm.ParseRemoteClusterSecret(secret) - - if err != nil { - return err - } - - clientConfig, err := clientcmd.RESTConfigFromKubeConfig(config.APIConfig) - if err != nil { - return fmt.Errorf("unable to parse kube config: %s", err) - } - - rcw.Lock() - defer rcw.Unlock() - - if _, ok := rcw.clusterWatchers[config.ClusterName]; ok { - return fmt.Errorf("there is already a cluster with name %s being watcher. Please delete its config before attempting to register a new one", config.ClusterName) - } - - watcher, err := NewRemoteClusterServiceWatcher(rcw.serviceMirrorNamespace, rcw.k8sAPI, clientConfig, config.ClusterName, rcw.requeueLimit, rcw.repairPeriod, config.ClusterDomain) - if err != nil { - return err - } - - rcw.clusterWatchers[config.ClusterName] = watcher - if err := watcher.Start(); err != nil { - return err - } - return nil - -} - -func (rcw *RemoteClusterConfigWatcher) unregisterRemoteCluster(secret *corev1.Secret, cleanState bool) error { - config, err := sm.ParseRemoteClusterSecret(secret) - - if err != nil { - return err - } - rcw.Lock() - defer rcw.Unlock() - if watcher, ok := rcw.clusterWatchers[config.ClusterName]; ok { - watcher.Stop(cleanState) - } else { - return fmt.Errorf("cannot find watcher for cluser: %s", config.ClusterName) - } - delete(rcw.clusterWatchers, config.ClusterName) - - return nil -} diff --git a/controller/cmd/service-mirror/events_formatting.go b/controller/cmd/service-mirror/events_formatting.go index 737e4b5fb8439..486b4e30b83e4 100644 --- a/controller/cmd/service-mirror/events_formatting.go +++ b/controller/cmd/service-mirror/events_formatting.go @@ -51,48 +51,19 @@ func formatEndpoints(endp *corev1.Endpoints) string { return fmt.Sprintf("Endpoints: {name: %s, namespace: %s, annotations: [%s], labels: [%s], subsets: [%s]}", endp.Name, endp.Namespace, formatMetadata(endp.Annotations), formatMetadata(endp.Labels), strings.Join(subsets, ",")) } -func (b ProbeConfig) String() string { - return fmt.Sprintf("ProbeConfig: {path: %s, port: %d, periodInSeconds: %d}", b.path, b.port, b.periodInSeconds) -} - -func (b GatewaySpec) String() string { - return fmt.Sprintf("GatewaySpec: {gatewayName: %s, gatewayNamespace: %s, clusterName: %s, addresses: [%s], incomingPort: %d, resourceVersion: %s, identity: %s, probeConfig: %s}", b.gatewayName, b.gatewayNamespace, b.clusterName, formatAddresses(b.addresses), b.incomingPort, b.resourceVersion, b.identity, b.ProbeConfig) -} - -func (gtm gatewayMetadata) String() string { - return fmt.Sprintf("gatewayMetadata: {name: %s, namespace: %s}", gtm.Name, gtm.Namespace) -} - // Events for cluster watcher func (rsc RemoteServiceCreated) String() string { - return fmt.Sprintf("RemoteServiceCreated: {service: %s, gatewayData: %s}", formatService(rsc.service), rsc.gatewayData) + return fmt.Sprintf("RemoteServiceCreated: {service: %s}", formatService(rsc.service)) } func (rsu RemoteServiceUpdated) String() string { - return fmt.Sprintf("RemoteServiceUpdated: {localService: %s, localEndpoints: %s, remoteUpdate: %s, gatewayData: %s}", formatService(rsu.localService), formatEndpoints(rsu.localEndpoints), formatService(rsu.remoteUpdate), rsu.gatewayData) + return fmt.Sprintf("RemoteServiceUpdated: {localService: %s, localEndpoints: %s, remoteUpdate: %s}", formatService(rsu.localService), formatEndpoints(rsu.localEndpoints), formatService(rsu.remoteUpdate)) } func (rsd RemoteServiceDeleted) String() string { return fmt.Sprintf("RemoteServiceDeleted: {name: %s, namespace: %s }", rsd.Name, rsd.Namespace) } -func (rgd RemoteGatewayDeleted) String() string { - return fmt.Sprintf("RemoteGatewayDeleted: {gatewayData: %s}", rgd.gatewayData) -} - -func (rgd *RemoteGatewayCreated) String() string { - return fmt.Sprintf("RemoteGatewayCreated: {gatewaySpec: %s}", rgd.gatewaySpec) -} - -func (rgu RemoteGatewayUpdated) String() string { - var services []string - - for _, s := range rgu.affectedServices { - services = append(services, formatService(s)) - } - return fmt.Sprintf("RemoteGatewayUpdated: {gatewaySpec: %s, affectedServices: [%s]}", rgu.gatewaySpec, strings.Join(services, ",")) -} - func (cgu ClusterUnregistered) String() string { return "ClusterUnregistered: {}" } @@ -116,15 +87,3 @@ func (od OnDeleteCalled) String() string { func (re RepairEndpoints) String() string { return "RepairEndpoints" } - -func (gmc GatewayMirrorCreated) String() string { - return fmt.Sprintf("GatewayMirrorCreated: {gatewayName: %s, gatewayNamespace: %s, clusterName: %s, probeSpec: %s}", gmc.gatewayName, gmc.gatewayNamespace, gmc.clusterName, gmc.ProbeSpec) -} - -func (gmd GatewayMirrorDeleted) String() string { - return fmt.Sprintf("GatewayMirrorDeleted: {gatewayName: %s, gatewayNamespace: %s, clusterName: %s}", gmd.gatewayName, gmd.gatewayNamespace, gmd.clusterName) -} - -func (gmu GatewayMirrorUpdated) String() string { - return fmt.Sprintf("GatewayMirrorUpdated: {gatewayName: %s, gatewayNamespace: %s, clusterName: %s, probeSpec: %s}", gmu.gatewayName, gmu.gatewayNamespace, gmu.clusterName, gmu.ProbeSpec) -} diff --git a/controller/cmd/service-mirror/main.go b/controller/cmd/service-mirror/main.go index 228963bb03029..d508f7aab7160 100644 --- a/controller/cmd/service-mirror/main.go +++ b/controller/cmd/service-mirror/main.go @@ -23,7 +23,10 @@ import ( log "github.com/sirupsen/logrus" ) -var clusterWatcher *RemoteClusterServiceWatcher +var ( + clusterWatcher *RemoteClusterServiceWatcher + probeWorker *ProbeWorker +) // Main executes the service-mirror controller func Main(args []string) { @@ -69,6 +72,7 @@ func Main(args []string) { } linkClient := k8sAPI.DynamicClient.Resource(gvr).Namespace(*namespace) + metrics := newProbeMetricVecs() go admin.StartServer(*metricsAddr) controllerK8sAPI.Sync(nil) @@ -98,7 +102,7 @@ func Main(args []string) { if err != nil { log.Errorf("Failed to load remote cluster credentials: %s", err) } - restartClusterWatcher(link, *namespace, creds, controllerK8sAPI, *requeueLimit, *repairPeriod) + restartClusterWatcher(link, *namespace, creds, controllerK8sAPI, *requeueLimit, *repairPeriod, metrics) case watch.Deleted: log.Infof("Link %s deleted", linkName) // TODO: should we delete all mirror resources? @@ -128,10 +132,14 @@ func restartClusterWatcher( controllerK8sAPI *controllerK8s.API, requeueLimit int, repairPeriod time.Duration, + metrics probeMetricVecs, ) { if clusterWatcher != nil { clusterWatcher.Stop(false) } + if probeWorker != nil { + probeWorker.Stop() + } cfg, err := clientcmd.RESTConfigFromKubeConfig(creds.APIConfig) if err != nil { @@ -143,10 +151,9 @@ func restartClusterWatcher( namespace, controllerK8sAPI, cfg, - link.TargetClusterName, + &link, requeueLimit, repairPeriod, - link.TargetClusterDomain, ) if err != nil { log.Errorf("Unable to create cluster watcher: %s", err) @@ -156,5 +163,13 @@ func restartClusterWatcher( err = clusterWatcher.Start() if err != nil { log.Errorf("Failed to start cluster watcher: %s", err) + return + } + + workerMetrics, err := metrics.newWorkerMetrics(link.TargetClusterName) + if err != nil { + log.Errorf("Failed to create metrics for cluster watcher: %s", err) } + probeWorker = NewProbeWorker(fmt.Sprintf("probe-gateway-%s", link.TargetClusterName), &link.ProbeSpec, workerMetrics, link.TargetClusterName) + go probeWorker.run() } diff --git a/controller/cmd/service-mirror/metrics.go b/controller/cmd/service-mirror/metrics.go index 97f027b5acce6..6f6f087aa6083 100644 --- a/controller/cmd/service-mirror/metrics.go +++ b/controller/cmd/service-mirror/metrics.go @@ -7,11 +7,9 @@ import ( ) const ( - gatewayNameLabel = "gateway_name" - gatewayNamespaceLabel = "gateway_namespace" - gatewayClusterName = "target_cluster_name" - eventTypeLabelName = "event_type" - probeSuccessfulLabel = "probe_successful" + gatewayClusterName = "target_cluster_name" + eventTypeLabelName = "event_type" + probeSuccessfulLabel = "probe_successful" ) type probeMetricVecs struct { @@ -37,19 +35,19 @@ func init() { Name: "service_mirror_endpoint_repairs", Help: "Increments when the service mirror controller attempts to repair mirror endpoints", }, - []string{gatewayNameLabel, gatewayNamespaceLabel, gatewayClusterName}, + []string{gatewayClusterName}, ) } func newProbeMetricVecs() probeMetricVecs { - labelNames := []string{gatewayNameLabel, gatewayNamespaceLabel, gatewayClusterName} + labelNames := []string{gatewayClusterName} probes := promauto.NewCounterVec( prometheus.CounterOpts{ Name: "gateway_probes", Help: "A counter for the number of actual performed probes to a gateway", }, - []string{gatewayNameLabel, gatewayNamespaceLabel, gatewayClusterName, probeSuccessfulLabel}, + []string{gatewayClusterName, probeSuccessfulLabel}, ) enqueues := promauto.NewCounterVec( @@ -98,12 +96,10 @@ func newProbeMetricVecs() probeMetricVecs { probes: probes, } } -func (mv probeMetricVecs) newWorkerMetrics(gatewayNamespace, gatewayName, remoteClusterName string) (*probeMetrics, error) { +func (mv probeMetricVecs) newWorkerMetrics(remoteClusterName string) (*probeMetrics, error) { labels := prometheus.Labels{ - gatewayNameLabel: gatewayName, - gatewayNamespaceLabel: gatewayNamespace, - gatewayClusterName: remoteClusterName, + gatewayClusterName: remoteClusterName, } curriedProbes, err := mv.probes.CurryWith(labels) @@ -115,16 +111,14 @@ func (mv probeMetricVecs) newWorkerMetrics(gatewayNamespace, gatewayName, remote latencies: mv.latencies.With(labels), probes: curriedProbes, unregister: func() { - mv.unregister(gatewayNamespace, gatewayName, remoteClusterName) + mv.unregister(remoteClusterName) }, }, nil } -func (mv probeMetricVecs) unregister(gatewayNamespace, gatewayName, remoteClusterName string) { +func (mv probeMetricVecs) unregister(remoteClusterName string) { labels := prometheus.Labels{ - gatewayNameLabel: gatewayName, - gatewayNamespaceLabel: gatewayNamespace, - gatewayClusterName: remoteClusterName, + gatewayClusterName: remoteClusterName, } if !mv.alive.Delete(labels) { diff --git a/controller/cmd/service-mirror/probe_manager.go b/controller/cmd/service-mirror/probe_manager.go deleted file mode 100644 index 5a45da6288809..0000000000000 --- a/controller/cmd/service-mirror/probe_manager.go +++ /dev/null @@ -1,273 +0,0 @@ -package servicemirror - -import ( - "fmt" - "strconv" - "time" - - consts "github.com/linkerd/linkerd2/pkg/k8s" - "github.com/linkerd/linkerd2/pkg/multicluster" - "github.com/prometheus/client_golang/prometheus" - log "github.com/sirupsen/logrus" - corev1 "k8s.io/api/core/v1" - "k8s.io/client-go/tools/cache" -) - -const probeChanBufferSize = 500 - -// ProbeManager takes care of managing the lifecycle of probe workers -type ProbeManager struct { - probeWorkers map[string]*ProbeWorker - mirroredGatewayInformer cache.SharedIndexInformer - events chan interface{} - metricVecs *probeMetricVecs - done chan struct{} -} - -// GatewayMirrorCreated is observed when a mirror of a remote gateway is created locally -type GatewayMirrorCreated struct { - gatewayName string - gatewayNamespace string - clusterName string - multicluster.ProbeSpec -} - -// GatewayMirrorDeleted is emitted when a mirror of a remote gateway is deleted -type GatewayMirrorDeleted struct { - gatewayName string - gatewayNamespace string - clusterName string -} - -// GatewayMirrorUpdated is emitted when the mirror of a remote gateway has changed -type GatewayMirrorUpdated struct { - gatewayName string - gatewayNamespace string - clusterName string - multicluster.ProbeSpec -} - -// NewProbeManager creates a new probe manager -func NewProbeManager(mirroredGatewayInformer cache.SharedIndexInformer) *ProbeManager { - metricVecs := newProbeMetricVecs() - return &ProbeManager{ - mirroredGatewayInformer: mirroredGatewayInformer, - probeWorkers: make(map[string]*ProbeWorker), - events: make(chan interface{}, probeChanBufferSize), - metricVecs: &metricVecs, - done: make(chan struct{}), - } -} - -func eventTypeString(ev interface{}) string { - switch ev.(type) { - case *GatewayMirrorCreated: - return "GatewayMirrorCreated" - case *GatewayMirrorDeleted: - return "GatewayMirrorDeleted" - case *GatewayMirrorUpdated: - return "GatewayMirrorUpdated" - default: - return "Unknown" - } -} - -func (m *ProbeManager) enqueueEvent(event interface{}) { - m.metricVecs.enqueues.With(prometheus.Labels{eventTypeLabelName: eventTypeString(event)}).Inc() - m.events <- event -} - -func probeKey(gatewayNamespace string, gatewayName string, clusterName string) string { - return fmt.Sprintf("%s-%s-%s", gatewayNamespace, gatewayName, clusterName) -} - -func (m *ProbeManager) handleEvent(ev interface{}) { - switch ev := ev.(type) { - case *GatewayMirrorCreated: - m.handleGatewayMirrorCreated(ev) - case *GatewayMirrorUpdated: - m.handleGatewayMirrorUpdated(ev) - case *GatewayMirrorDeleted: - m.handleGatewayMirrorDeleted(ev) - default: - log.Errorf("Received unknown event: %v", ev) - } -} - -func (m *ProbeManager) handleGatewayMirrorDeleted(event *GatewayMirrorDeleted) { - probeKey := probeKey(event.gatewayNamespace, event.gatewayName, event.clusterName) - m.stopProbe(probeKey) -} - -func (m *ProbeManager) handleGatewayMirrorCreated(event *GatewayMirrorCreated) { - probeKey := probeKey(event.gatewayNamespace, event.gatewayName, event.clusterName) - worker, ok := m.probeWorkers[probeKey] - if ok { - log.Infof("There is already a probe worker for %s. Updating instead of creating", probeKey) - worker.UpdateProbeSpec(&event.ProbeSpec) - } else { - log.Infof("Creating probe worker %s", probeKey) - probeMetrics, err := m.metricVecs.newWorkerMetrics(event.gatewayNamespace, event.gatewayName, event.clusterName) - if err != nil { - log.Errorf("Could not crete probe metrics: %s", err) - } else { - localGatewayName := fmt.Sprintf("%s-%s", event.gatewayName, event.clusterName) - worker = NewProbeWorker(localGatewayName, &event.ProbeSpec, probeMetrics, probeKey) - m.probeWorkers[probeKey] = worker - worker.Start() - } - } -} - -func (m *ProbeManager) handleGatewayMirrorUpdated(event *GatewayMirrorUpdated) { - probeKey := probeKey(event.gatewayNamespace, event.gatewayName, event.clusterName) - worker, ok := m.probeWorkers[probeKey] - if ok { - if worker.probeSpec.Port != event.Port || worker.probeSpec.Period != event.Period || worker.probeSpec.Path != event.Path { - worker.UpdateProbeSpec(&event.ProbeSpec) - } - } else { - log.Infof("Could not find a worker for %s while handling GatewayMirrorUpdated event", probeKey) - } -} - -func (m *ProbeManager) stopProbe(key string) { - if worker, ok := m.probeWorkers[key]; ok { - worker.Stop() - delete(m.probeWorkers, key) - } else { - log.Infof("Could not find probe worker with key %s", key) - } -} - -func (m *ProbeManager) run() { - for { - select { - case event := <-m.events: - log.Infof("Probe Manager: received event: %s", event) - m.metricVecs.dequeues.With(prometheus.Labels{eventTypeLabelName: eventTypeString(event)}).Inc() - m.handleEvent(event) - case <-m.done: - log.Infof("Shutting down ProbeManager") - for key := range m.probeWorkers { - m.stopProbe(key) - } - return - } - } -} - -func extractProbeSpec(svc *corev1.Service) (*multicluster.ProbeSpec, error) { - path, hasPath := svc.Annotations[consts.MirroredGatewayProbePath] - if !hasPath { - return nil, fmt.Errorf("mirrored Gateway service is missing %s annotation", consts.MirroredGatewayProbePath) - } - - probePort, err := extractPort(svc.Spec.Ports, consts.ProbePortName) - if err != nil { - return nil, fmt.Errorf("%s: %s", svc.Name, err) - } - - period, hasPeriod := svc.Annotations[consts.MirroredGatewayProbePeriod] - if !hasPeriod { - return nil, fmt.Errorf("mirrored Gateway service is missing %s annotation", consts.MirroredGatewayProbePeriod) - } - - probePeriodSeconds, err := strconv.ParseUint(period, 10, 32) - if err != nil { - return nil, err - } - - return &multicluster.ProbeSpec{ - Path: path, - Port: probePort, - Period: time.Duration(probePeriodSeconds) * time.Second, - }, nil - -} - -// Start starts the probe manager -func (m *ProbeManager) Start() { - m.mirroredGatewayInformer.AddEventHandler( - cache.FilteringResourceEventHandler{ - FilterFunc: func(obj interface{}) bool { - switch object := obj.(type) { - case *corev1.Service: - _, isMirrorGateway := object.Labels[consts.MirroredGatewayLabel] - return isMirrorGateway - - case cache.DeletedFinalStateUnknown: - if svc, ok := object.Obj.(*corev1.Service); ok { - _, isMirrorGateway := svc.Labels[consts.MirroredGatewayLabel] - return isMirrorGateway - } - return false - default: - return false - } - }, - - Handler: cache.ResourceEventHandlerFuncs{ - AddFunc: func(obj interface{}) { - service := obj.(*corev1.Service) - spec, err := extractProbeSpec(service) - if err != nil { - log.Errorf("Could not parse probe spec %s", err) - } else { - m.enqueueEvent(&GatewayMirrorCreated{ - gatewayName: service.Annotations[consts.MirroredGatewayRemoteName], - gatewayNamespace: service.Annotations[consts.MirroredGatewayRemoteNameSpace], - clusterName: service.Labels[consts.RemoteClusterNameLabel], - ProbeSpec: *spec, - }) - } - }, - DeleteFunc: func(obj interface{}) { - service, ok := obj.(*corev1.Service) - if !ok { - tombstone, ok := obj.(cache.DeletedFinalStateUnknown) - if !ok { - log.Errorf("couldn't get object from DeletedFinalStateUnknown %#v", obj) - return - } - service, ok = tombstone.Obj.(*corev1.Service) - if !ok { - log.Errorf("DeletedFinalStateUnknown contained object that is not a Secret %#v", obj) - return - } - } - - m.enqueueEvent(&GatewayMirrorDeleted{ - gatewayName: service.Annotations[consts.MirroredGatewayRemoteName], - gatewayNamespace: service.Annotations[consts.MirroredGatewayRemoteNameSpace], - clusterName: service.Labels[consts.RemoteClusterNameLabel], - }) - }, - UpdateFunc: func(old, new interface{}) { - oldService := old.(*corev1.Service) - newService := new.(*corev1.Service) - - if oldService.ResourceVersion != newService.ResourceVersion { - spec, err := extractProbeSpec(newService) - if err != nil { - log.Errorf("Could not parse probe spec %s", err) - } else { - m.enqueueEvent(&GatewayMirrorUpdated{ - gatewayName: newService.Annotations[consts.MirroredGatewayRemoteName], - gatewayNamespace: newService.Annotations[consts.MirroredGatewayRemoteNameSpace], - clusterName: newService.Labels[consts.RemoteClusterNameLabel], - ProbeSpec: *spec, - }) - } - } - }, - }, - }, - ) - go m.run() -} - -// Stop stops the probe manager -func (m *ProbeManager) Stop() { - close(m.done) -} diff --git a/pkg/multicluster/link.go b/pkg/multicluster/link.go index d89529a740c08..cd24e854e87c2 100644 --- a/pkg/multicluster/link.go +++ b/pkg/multicluster/link.go @@ -31,6 +31,7 @@ type ( TargetClusterLinkerdNamespace string ClusterCredentialsSecret string GatewayAddress string + GatewayPort uint32 GatewayIdentity string ProbeSpec ProbeSpec } @@ -92,6 +93,15 @@ func NewLink(u unstructured.Unstructured) (Link, error) { return Link{}, err } + portStr, err := stringField(specObj, "gatewayPort") + if err != nil { + return Link{}, err + } + gatewayPort, err := strconv.ParseUint(portStr, 10, 32) + if err != nil { + return Link{}, err + } + gatewayIdentity, err := stringField(specObj, "gatewayIdentity") if err != nil { return Link{}, err @@ -103,6 +113,7 @@ func NewLink(u unstructured.Unstructured) (Link, error) { TargetClusterLinkerdNamespace: targetClusterLinkerdNamespace, ClusterCredentialsSecret: clusterCredentialsSecret, GatewayAddress: gatewayAddress, + GatewayPort: uint32(gatewayPort), GatewayIdentity: gatewayIdentity, ProbeSpec: probeSpec, }, nil @@ -126,6 +137,7 @@ func (l Link) ToUnstructured(name, namespace string) unstructured.Unstructured { "targetClusterLinkerdNamespace": l.TargetClusterLinkerdNamespace, "clusterCredentialsSecret": l.ClusterCredentialsSecret, "gatewayAddress": l.GatewayAddress, + "gatewayPort": fmt.Sprintf("%d", l.GatewayPort), "gatewayIdentity": l.GatewayIdentity, "probeSpec": map[string]interface{}{ "path": l.ProbeSpec.Path, From a7a8b8631cad34dc2139c0066701495e4193b053 Mon Sep 17 00:00:00 2001 From: Alex Leong Date: Fri, 10 Jul 2020 16:10:26 -0700 Subject: [PATCH 07/14] Update multicluster checks Signed-off-by: Alex Leong --- .../templates/gateway-mirror.yaml | 3 + .../templates/service-mirror.yaml | 11 +- cli/cmd/check.go | 5 +- cli/cmd/multicluster.go | 4 +- controller/cmd/service-mirror/main.go | 8 +- pkg/healthcheck/healthcheck.go | 36 +- pkg/healthcheck/healthcheck_multicluster.go | 827 +++++++----------- pkg/k8s/authz.go | 19 + pkg/k8s/k8s.go | 5 + pkg/multicluster/link.go | 57 +- 10 files changed, 429 insertions(+), 546 deletions(-) diff --git a/charts/linkerd2-multicluster/templates/gateway-mirror.yaml b/charts/linkerd2-multicluster/templates/gateway-mirror.yaml index f735e6366b229..88c5e22fee5b1 100644 --- a/charts/linkerd2-multicluster/templates/gateway-mirror.yaml +++ b/charts/linkerd2-multicluster/templates/gateway-mirror.yaml @@ -5,6 +5,9 @@ kind: Service metadata: name: probe-gateway-{{.Values.targetClusterName}} namespace: {{.Values.namespace}} + labels: + mirror.linkerd.io/mirrored-gateway: "true" + mirror.linkerd.io/cluster-name: {{.Values.targetClusterName}} spec: ports: - name: mc-probe diff --git a/charts/linkerd2-multicluster/templates/service-mirror.yaml b/charts/linkerd2-multicluster/templates/service-mirror.yaml index cfab1b2d12b6e..d6c7e07e35a3f 100644 --- a/charts/linkerd2-multicluster/templates/service-mirror.yaml +++ b/charts/linkerd2-multicluster/templates/service-mirror.yaml @@ -6,6 +6,7 @@ metadata: name: linkerd-service-mirror-access-local-resources-{{.Values.targetClusterName}} labels: {{.Values.controllerComponentLabel}}: linkerd-service-mirror + mirror.linkerd.io/cluster-name: {{.Values.targetClusterName}} rules: - apiGroups: [""] resources: ["endpoints", "services"] @@ -20,6 +21,7 @@ metadata: name: linkerd-service-mirror-access-local-resources-{{.Values.targetClusterName}} labels: {{.Values.controllerComponentLabel}}: linkerd-service-mirror + mirror.linkerd.io/cluster-name: {{.Values.targetClusterName}} roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole @@ -36,6 +38,7 @@ metadata: namespace: {{.Values.namespace}} labels: {{.Values.controllerComponentLabel}}: linkerd-service-mirror + mirror.linkerd.io/cluster-name: {{.Values.targetClusterName}} rules: - apiGroups: [""] resources: ["secrets"] @@ -52,6 +55,7 @@ metadata: namespace: {{.Values.namespace}} labels: {{.Values.controllerComponentLabel}}: linkerd-service-mirror + mirror.linkerd.io/cluster-name: {{.Values.targetClusterName}} roleRef: apiGroup: rbac.authorization.k8s.io kind: Role @@ -68,13 +72,14 @@ metadata: namespace: {{.Values.namespace}} labels: {{.Values.controllerComponentLabel}}: linkerd-service-mirror + mirror.linkerd.io/cluster-name: {{.Values.targetClusterName}} --- apiVersion: apps/v1 kind: Deployment metadata: labels: {{.Values.controllerComponentLabel}}: linkerd-service-mirror - app: linkerd-service-mirror-{{.Values.targetClusterName}} + mirror.linkerd.io/cluster-name: {{.Values.targetClusterName}} name: linkerd-service-mirror-{{.Values.targetClusterName}} namespace: {{.Values.namespace}} spec: @@ -82,14 +87,14 @@ spec: selector: matchLabels: {{.Values.controllerComponentLabel}}: linkerd-service-mirror - app: linkerd-service-mirror-{{.Values.targetClusterName}} + mirror.linkerd.io/cluster-name: {{.Values.targetClusterName}} template: metadata: annotations: linkerd.io/inject: enabled labels: {{.Values.controllerComponentLabel}}: linkerd-service-mirror - app: linkerd-service-mirror-{{.Values.targetClusterName}} + mirror.linkerd.io/cluster-name: {{.Values.targetClusterName}} spec: containers: - args: diff --git a/cli/cmd/check.go b/cli/cmd/check.go index 3c16eed02c315..807ac167a1054 100644 --- a/cli/cmd/check.go +++ b/cli/cmd/check.go @@ -188,8 +188,7 @@ func configureAndRunChecks(wout io.Writer, werr io.Writer, stage string, options } checks = append(checks, healthcheck.LinkerdCNIPluginChecks) checks = append(checks, healthcheck.LinkerdHAChecks) - checks = append(checks, healthcheck.LinkerdMulticlusterSourceChecks) - checks = append(checks, healthcheck.LinkerdMulticlusterTargetChecks) + checks = append(checks, healthcheck.LinkerdMulticlusterChecks) checks = append(checks, healthcheck.AddOnCategories...) } @@ -208,8 +207,6 @@ func configureAndRunChecks(wout io.Writer, werr io.Writer, stage string, options RetryDeadline: time.Now().Add(options.wait), CNIEnabled: options.cniEnabled, InstallManifest: installManifest, - SourceCluster: options.multicluster, - TargetCluster: options.multicluster, }) success := runChecks(wout, werr, hc, options.output) diff --git a/cli/cmd/multicluster.go b/cli/cmd/multicluster.go index 7a9c8372c23da..efdaacc3145ec 100644 --- a/cli/cmd/multicluster.go +++ b/cli/cmd/multicluster.go @@ -553,6 +553,8 @@ func newLinkCommand() *cobra.Command { } link := mc.Link{ + Name: opts.clusterName, + Namespace: opts.namespace, TargetClusterName: opts.clusterName, TargetClusterDomain: configMap.Global.ClusterDomain, TargetClusterLinkerdNamespace: controlPlaneNamespace, @@ -563,7 +565,7 @@ func newLinkCommand() *cobra.Command { ProbeSpec: probeSpec, } - linkOut, err := yaml.Marshal(link.ToUnstructured(opts.clusterName, opts.namespace).Object) + linkOut, err := yaml.Marshal(link.ToUnstructured().Object) if err != nil { return err } diff --git a/controller/cmd/service-mirror/main.go b/controller/cmd/service-mirror/main.go index d508f7aab7160..87869bf4c4f0d 100644 --- a/controller/cmd/service-mirror/main.go +++ b/controller/cmd/service-mirror/main.go @@ -10,7 +10,6 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" dynamic "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/watch" "k8s.io/client-go/tools/clientcmd" @@ -65,12 +64,7 @@ func Main(args []string) { log.Fatalf("Failed to initialize K8s API: %s", err) } - gvr := schema.GroupVersionResource{ - Group: "multicluster.linkerd.io", - Version: "v1alpha1", - Resource: "links", - } - linkClient := k8sAPI.DynamicClient.Resource(gvr).Namespace(*namespace) + linkClient := k8sAPI.DynamicClient.Resource(multicluster.LinkGVR).Namespace(*namespace) metrics := newProbeMetricVecs() go admin.StartServer(*metricsAddr) diff --git a/pkg/healthcheck/healthcheck.go b/pkg/healthcheck/healthcheck.go index 6165de7e29800..91af19fecfb2b 100644 --- a/pkg/healthcheck/healthcheck.go +++ b/pkg/healthcheck/healthcheck.go @@ -19,7 +19,7 @@ import ( "github.com/linkerd/linkerd2/pkg/identity" "github.com/linkerd/linkerd2/pkg/issuercerts" "github.com/linkerd/linkerd2/pkg/k8s" - sm "github.com/linkerd/linkerd2/pkg/servicemirror" + "github.com/linkerd/linkerd2/pkg/multicluster" "github.com/linkerd/linkerd2/pkg/tls" "github.com/linkerd/linkerd2/pkg/version" log "github.com/sirupsen/logrus" @@ -188,11 +188,6 @@ var ExpectedServiceAccountNames = []string{ "linkerd-tap", } -type expectedPolicy struct { - resources []string - verbs []string -} - var ( retryWindow = 5 * time.Second requestTimeout = 30 * time.Second @@ -344,8 +339,6 @@ type Options struct { RetryDeadline time.Time CNIEnabled bool InstallManifest string - SourceCluster bool - TargetCluster bool MultiCluster bool } @@ -356,20 +349,19 @@ type HealthChecker struct { *Options // these fields are set in the process of running checks - kubeAPI *k8s.KubernetesAPI - kubeVersion *k8sVersion.Info - controlPlanePods []corev1.Pod - apiClient public.APIClient - latestVersions version.Channels - serverVersion string - linkerdConfig *configPb.All - uuid string - issuerCert *tls.Cred - trustAnchors []*x509.Certificate - cniDaemonSet *appsv1.DaemonSet - serviceMirrorNs string - remoteClusterConfigs []*sm.WatchedClusterConfig - addOns map[string]interface{} + kubeAPI *k8s.KubernetesAPI + kubeVersion *k8sVersion.Info + controlPlanePods []corev1.Pod + apiClient public.APIClient + latestVersions version.Channels + serverVersion string + linkerdConfig *configPb.All + uuid string + issuerCert *tls.Cred + trustAnchors []*x509.Certificate + cniDaemonSet *appsv1.DaemonSet + links []multicluster.Link + addOns map[string]interface{} } // NewHealthChecker returns an initialized HealthChecker diff --git a/pkg/healthcheck/healthcheck_multicluster.go b/pkg/healthcheck/healthcheck_multicluster.go index 26e42e503211a..6f8f21944eaf9 100644 --- a/pkg/healthcheck/healthcheck_multicluster.go +++ b/pkg/healthcheck/healthcheck_multicluster.go @@ -8,50 +8,28 @@ import ( "sort" "strings" - pb "github.com/linkerd/linkerd2/controller/gen/public" - sm "github.com/linkerd/linkerd2/pkg/servicemirror" - tsclient "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/split/clientset/versioned" + "github.com/linkerd/linkerd2/controller/gen/public" + "github.com/linkerd/linkerd2/pkg/multicluster" + "github.com/linkerd/linkerd2/pkg/servicemirror" corev1 "k8s.io/api/core/v1" "github.com/linkerd/linkerd2/pkg/k8s" "github.com/linkerd/linkerd2/pkg/tls" - v1 "k8s.io/api/rbac/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/tools/clientcmd" ) const ( - // LinkerdMulticlusterSourceChecks adds a series of checks to validate - // the source side of a multicluster setup - LinkerdMulticlusterSourceChecks CategoryID = "linkerd-multicluster-source" - - // LinkerdMulticlusterTargetChecks add a series of checks to validate the - // targetside of a multicluster setup - LinkerdMulticlusterTargetChecks CategoryID = "linkerd-multicluster-target" - - linkerdServiceMirrorComponentName = "linkerd-service-mirror" - linkerdServiceMirrorClusterRoleName = "linkerd-service-mirror-access-local-resources" - linkerdServiceMirrorRoleName = "linkerd-service-mirror-read-remote-creds" + // LinkerdMulticlusterChecks adds a series of checks to validate a + // multicluster setup. + LinkerdMulticlusterChecks CategoryID = "linkerd-multicluster" + + linkerdServiceMirrorComponentName = "linkerd-service-mirror" + linkerdServiceMirrorSerivceAccountName = "linkerd-service-mirror-%s" + linkerdServiceMirrorClusterRoleName = "linkerd-service-mirror-access-local-resources-%s" + linkerdServiceMirrorRoleName = "linkerd-service-mirror-read-remote-creds-%s" ) -var expectedServiceMirrorClusterRolePolicies = []expectedPolicy{ - { - resources: []string{"endpoints", "services"}, - verbs: []string{"list", "get", "watch", "create", "delete", "update"}, - }, - { - resources: []string{"namespaces"}, - verbs: []string{"create", "list", "get", "watch"}, - }, -} - -var expectedServiceMirrorRolePolicies = []expectedPolicy{ - { - resources: []string{"secrets"}, - verbs: []string{"list", "get", "watch"}, - }, -} - var expectedServiceMirrorRemoteClusterPolicyVerbs = []string{ "get", "list", @@ -61,149 +39,104 @@ var expectedServiceMirrorRemoteClusterPolicyVerbs = []string{ func (hc *HealthChecker) multiClusterCategory() []category { return []category{ { - id: LinkerdMulticlusterSourceChecks, + id: LinkerdMulticlusterChecks, checkers: []checker{ + /* Link checks */ { - description: "service mirror controller is running", - hintAnchor: "l5d-multicluster-service-mirror-running", - retryDeadline: hc.RetryDeadline, - fatal: true, - check: func(context.Context) error { - return hc.checkServiceMirrorController() - }, - }, - { - description: "service mirror controller ClusterRoles exist", - hintAnchor: "l5d-multicluster-cluster-role-exist", + description: "Link CRD exists", + hintAnchor: "l5d-multicluster-link-crd-exists", + fatal: true, check: func(context.Context) error { - if hc.Options.SourceCluster { - return hc.checkClusterRoles(true, []string{linkerdServiceMirrorClusterRoleName}, hc.serviceMirrorComponentsSelector()) - } - return &SkipError{Reason: "not checking muticluster"} + return hc.checkLinkCRD() }, }, { - description: "service mirror controller ClusterRoleBindings exist", - hintAnchor: "l5d-multicluster-cluster-role-binding-exist", + description: "Link resources are valid", + hintAnchor: "l5d-multicluster-links-are-valid", + fatal: true, check: func(context.Context) error { - if hc.Options.SourceCluster { - return hc.checkClusterRoleBindings(true, []string{linkerdServiceMirrorClusterRoleName}, hc.serviceMirrorComponentsSelector()) + if hc.Options.MultiCluster { + return hc.checkLinks() } return &SkipError{Reason: "not checking muticluster"} }, }, + /* Serivce mirror controller checks */ { - description: "service mirror controller Roles exist", - hintAnchor: "l5d-multicluster-role-exist", + description: "service mirror controller has required permissions", + hintAnchor: "l5d-multicluster-source-rbac-correct", check: func(context.Context) error { - if hc.Options.SourceCluster { - return hc.checkRoles(true, hc.serviceMirrorNs, []string{linkerdServiceMirrorRoleName}, hc.serviceMirrorComponentsSelector()) + if hc.Options.MultiCluster { + return hc.checkServiceMirrorLocalRBAC() } return &SkipError{Reason: "not checking muticluster"} }, }, { - description: "service mirror controller RoleBindings exist", - hintAnchor: "l5d-multicluster-role-binding-exist", + description: "service mirror controllers are running", + hintAnchor: "l5d-multicluster-service-mirror-running", + retryDeadline: hc.RetryDeadline, + surfaceErrorOnRetry: true, check: func(context.Context) error { - if hc.Options.SourceCluster { - return hc.checkRoleBindings(true, hc.serviceMirrorNs, []string{linkerdServiceMirrorRoleName}, hc.serviceMirrorComponentsSelector()) + if hc.Options.MultiCluster { + return hc.checkServiceMirrorController() } return &SkipError{Reason: "not checking muticluster"} }, }, + /* Target cluster access checks */ { - description: "service mirror controller ServiceAccounts exist", - hintAnchor: "l5d-multicluster-service-account-exist", + description: "remote cluster access credentials are valid", + hintAnchor: "l5d-smc-target-clusters-access", check: func(context.Context) error { - if hc.Options.SourceCluster { - return hc.checkServiceAccounts([]string{linkerdServiceMirrorComponentName}, hc.serviceMirrorNs, hc.serviceMirrorComponentsSelector()) + if hc.Options.MultiCluster { + return hc.checkRemoteClusterConnectivity() } return &SkipError{Reason: "not checking muticluster"} }, }, - { - description: "service mirror controller has required permissions", - hintAnchor: "l5d-multicluster-source-rbac-correct", - check: func(context.Context) error { - return hc.checkServiceMirrorLocalRBAC() - }, - }, - { - description: "service mirror controller can access target clusters", - hintAnchor: "l5d-smc-target-clusters-access", - check: func(context.Context) error { - return hc.checkRemoteClusterConnectivity() - }, - }, - { - description: "all target cluster gateways are alive", - hintAnchor: "l5d-multicluster-target-gateways-alive", - check: func(ctx context.Context) error { - return hc.checkRemoteClusterGatewaysHealth(ctx) - }, - }, { description: "clusters share trust anchors", hintAnchor: "l5d-multicluster-clusters-share-anchors", check: func(ctx context.Context) error { - return hc.checkRemoteClusterAnchors() + if hc.Options.MultiCluster { + return hc.checkRemoteClusterAnchors() + } + return &SkipError{Reason: "not checking muticluster"} }, }, + /* Gateway mirror checks */ { - description: "multicluster daisy chaining is avoided", - hintAnchor: "l5d-multicluster-daisy-chaining", + description: "all gateway mirrors are healthy", + hintAnchor: "l5d-multicluster-gateways-endpoints", warning: true, check: func(ctx context.Context) error { - return hc.checkDaisyChains() + if hc.Options.MultiCluster { + return hc.checkIfGatewayMirrorsHaveEndpoints(ctx) + } + return &SkipError{Reason: "not checking muticluster"} }, }, + /* Mirror service checks */ { description: "all mirror services have endpoints", hintAnchor: "l5d-multicluster-services-endpoints", - warning: true, - check: func(ctx context.Context) error { - return hc.checkIfMirrorServicesHaveEndpoints() - }, - }, - { - description: "all gateway mirrors have endpoints", - hintAnchor: "l5d-multicluster-gateways-endpoints", - warning: true, - check: func(ctx context.Context) error { - return hc.checkIfGatewayMirrorsHaveEndpoints() - }, - }, - { - description: "remote: all referenced gateways are valid", - hintAnchor: "l5d-multicluster-gateways-exist", - warning: true, check: func(ctx context.Context) error { - return hc.checkRemoteGateways() + if hc.Options.MultiCluster { + return hc.checkIfMirrorServicesHaveEndpoints() + } + return &SkipError{Reason: "not checking muticluster"} }, }, - }, - }, - { - id: LinkerdMulticlusterTargetChecks, - checkers: []checker{ { - description: "all cluster gateways are valid", - hintAnchor: "l5d-multicluster-gateways-exist", + description: "all mirror services are part of a Link", + hintAnchor: "l5d-multicluster-orphaned-services", warning: true, check: func(ctx context.Context) error { - targetCluster, err := hc.isTargetCluster() - if err != nil { - return err + if hc.Options.MultiCluster { + return hc.checkForOrphanedServices() } - if targetCluster || hc.TargetCluster { - err := hc.checkLocalGateways() - if err != nil { - return err - } - return hc.checkIfGatewaysHaveEndpoints() - } - return &SkipError{Reason: "not checking target cluster"} + return &SkipError{Reason: "not checking muticluster"} }, }, }, @@ -211,148 +144,236 @@ func (hc *HealthChecker) multiClusterCategory() []category { } } -func (hc *HealthChecker) serviceMirrorComponentsSelector() string { - return fmt.Sprintf("%s=%s", k8s.ControllerComponentLabel, linkerdServiceMirrorComponentName) -} +/* Link checks */ -func (hc *HealthChecker) checkServiceMirrorController() error { - options := metav1.ListOptions{ - LabelSelector: hc.serviceMirrorComponentsSelector(), +func (hc *HealthChecker) checkLinkCRD() error { + err := k8s.LinkAccess(hc.kubeAPI.Interface) + if err == nil { + hc.Options.MultiCluster = true + return nil } - result, err := hc.kubeAPI.AppsV1().Deployments(corev1.NamespaceAll).List(options) + if !hc.Options.MultiCluster { + return &SkipError{Reason: "not checking muticluster"} + } + return fmt.Errorf("multicluster.linkerd.io/Link CRD is missing: %s", err) +} + +func (hc *HealthChecker) checkLinks() error { + links, err := multicluster.GetLinks(hc.kubeAPI.DynamicClient) if err != nil { return err } - - // if we have explicitly requested for multicluster to be checked, error out - if len(result.Items) == 0 && hc.Options.SourceCluster { - return errors.New("Service mirror controller is not present") + if len(links) == 0 { + return &SkipError{Reason: "no links detected"} } + linkNames := []string{} + for _, l := range links { + linkNames = append(linkNames, fmt.Sprintf("\t* %s", l.TargetClusterName)) + } + hc.links = links + return &VerboseSuccess{Message: strings.Join(linkNames, "\n")} +} - if len(result.Items) > 0 { - hc.Options.SourceCluster = true +/* Serivce mirror controller checks */ - if len(result.Items) > 1 { - var errors []error - for _, smc := range result.Items { - errors = append(errors, fmt.Errorf("%s/%s", smc.Namespace, smc.Name)) - } - return fmt.Errorf("There are more than one service mirror controllers:\n%s", joinErrors(errors, 1)) +func (hc *HealthChecker) checkServiceMirrorLocalRBAC() error { + links := []string{} + errors := []string{} + + for _, link := range hc.links { + + err := hc.checkServiceAccounts( + []string{fmt.Sprintf(linkerdServiceMirrorSerivceAccountName, link.TargetClusterName)}, + link.Namespace, + serviceMirrorComponentsSelector(link.TargetClusterName), + ) + if err != nil { + errors = append(errors, err.Error()) } - controller := result.Items[0] - if controller.Status.AvailableReplicas < 1 { - return fmt.Errorf("Service mirror controller is not available: %s/%s", controller.Namespace, controller.Name) + err = hc.checkClusterRoles( + true, + []string{fmt.Sprintf(linkerdServiceMirrorClusterRoleName, link.TargetClusterName)}, + serviceMirrorComponentsSelector(link.TargetClusterName), + ) + if err != nil { + errors = append(errors, err.Error()) } - hc.serviceMirrorNs = controller.Namespace - return nil - } - return &SkipError{Reason: "not checking muticluster"} -} + err = hc.checkClusterRoleBindings( + true, + []string{fmt.Sprintf(linkerdServiceMirrorClusterRoleName, link.TargetClusterName)}, + serviceMirrorComponentsSelector(link.TargetClusterName), + ) + if err != nil { + errors = append(errors, err.Error()) + } -func comparePermissions(expected, actual []string) error { - sort.Strings(expected) - sort.Strings(actual) + err = hc.checkRoles( + true, + link.Namespace, + []string{fmt.Sprintf(linkerdServiceMirrorRoleName, link.TargetClusterName)}, + serviceMirrorComponentsSelector(link.TargetClusterName), + ) + if err != nil { + errors = append(errors, err.Error()) + } - expectedStr := strings.Join(expected, ",") - actualStr := strings.Join(actual, ",") + err = hc.checkRoleBindings( + true, + link.Namespace, + []string{fmt.Sprintf(linkerdServiceMirrorRoleName, link.TargetClusterName)}, + serviceMirrorComponentsSelector(link.TargetClusterName), + ) + if err != nil { + errors = append(errors, err.Error()) + } - if expectedStr != actualStr { - return fmt.Errorf("expected %s, got %s", expectedStr, actualStr) + links = append(links, fmt.Sprintf("\t* %s", link.TargetClusterName)) + } + if len(errors) > 0 { + return fmt.Errorf(strings.Join(errors, "\n")) } - return nil + return &VerboseSuccess{Message: strings.Join(links, "\n")} } -func verifyRule(expected expectedPolicy, actual []v1.PolicyRule) error { - for _, rule := range actual { - if err := comparePermissions(expected.resources, rule.Resources); err == nil { - if err := comparePermissions(expected.verbs, rule.Verbs); err != nil { - return fmt.Errorf("unexpected verbs %s", err) - } - return nil +func (hc *HealthChecker) checkServiceMirrorController() error { + + errors := []error{} + clusterNames := []string{} + + for _, link := range hc.links { + options := metav1.ListOptions{ + LabelSelector: serviceMirrorComponentsSelector(link.TargetClusterName), + } + result, err := hc.kubeAPI.AppsV1().Deployments(corev1.NamespaceAll).List(options) + if err != nil { + return err + } + + if len(result.Items) > 1 { + errors = append(errors, fmt.Errorf("* too many service mirror controller deployments for Link %s", link.TargetClusterName)) + continue + } + if len(result.Items) == 0 { + errors = append(errors, fmt.Errorf("* no service mirror controller deployment for Link %s", link.TargetClusterName)) + continue } + + controller := result.Items[0] + if controller.Status.AvailableReplicas < 1 { + errors = append(errors, fmt.Errorf("* service mirror controller is not available: %s/%s", controller.Namespace, controller.Name)) + continue + } + clusterNames = append(clusterNames, fmt.Sprintf("\t* %s", link.TargetClusterName)) } - return fmt.Errorf("could not fine rule for %s", strings.Join(expected.resources, ",")) + if len(errors) > 0 { + return joinErrors(errors, 2) + } + return &VerboseSuccess{Message: strings.Join(clusterNames, "\n")} } -func (hc *HealthChecker) checkServiceMirrorLocalRBAC() error { - if hc.Options.SourceCluster { - var errors []string +/* Target cluster access checks */ - clusterRole, err := hc.kubeAPI.RbacV1().ClusterRoles().Get(linkerdServiceMirrorClusterRoleName, metav1.GetOptions{}) +func (hc *HealthChecker) checkRemoteClusterConnectivity() error { + errors := []error{} + links := []string{} + for _, link := range hc.links { + // Load the credentials secret + secret, err := hc.kubeAPI.Interface.CoreV1().Secrets(link.Namespace).Get(link.ClusterCredentialsSecret, metav1.GetOptions{}) if err != nil { - return fmt.Errorf("Could not obtain service mirror ClusterRole %s: %s", linkerdServiceMirrorClusterRoleName, err) + errors = append(errors, fmt.Errorf("* secret: [%s/%s]: %s", link.Namespace, link.ClusterCredentialsSecret, err)) + continue } - role, err := hc.kubeAPI.RbacV1().Roles(hc.serviceMirrorNs).Get(linkerdServiceMirrorRoleName, metav1.GetOptions{}) + config, err := servicemirror.ParseRemoteClusterSecret(secret) + if err != nil { - return fmt.Errorf("Could not obtain service mirror Role %s : %s", linkerdServiceMirrorRoleName, err) + errors = append(errors, fmt.Errorf("* secret: [%s/%s]: could not parse config secret: %s", secret.Namespace, secret.Name, err)) + continue } - if len(clusterRole.Rules) != len(expectedServiceMirrorClusterRolePolicies) { - return fmt.Errorf("Service mirror ClusterRole %s has %d policy rules, expected %d", clusterRole.Name, len(clusterRole.Rules), len(expectedServiceMirrorClusterRolePolicies)) + clientConfig, err := clientcmd.RESTConfigFromKubeConfig(config.APIConfig) + if err != nil { + errors = append(errors, fmt.Errorf("* secret: [%s/%s] cluster: [%s]: unable to parse api config: %s", secret.Namespace, secret.Name, config.ClusterName, err)) + continue } - for _, rule := range expectedServiceMirrorClusterRolePolicies { - if err := verifyRule(rule, clusterRole.Rules); err != nil { - errors = append(errors, fmt.Sprintf("Service mirror ClusterRole %s: %s", clusterRole.Name, err)) - } + remoteAPI, err := k8s.NewAPIForConfig(clientConfig, "", []string{}, requestTimeout) + if err != nil { + errors = append(errors, fmt.Errorf("* secret: [%s/%s] cluster: [%s]: could not instantiate api for target cluster: %s", secret.Namespace, secret.Name, config.ClusterName, err)) + continue } - if len(role.Rules) != len(expectedServiceMirrorRolePolicies) { - return fmt.Errorf("Service mirror Role %s has %d policy rules, expected %d", role.Name, len(role.Rules), len(expectedServiceMirrorRolePolicies)) + var verbs []string + if err := hc.checkCanPerformAction(remoteAPI, "get", corev1.NamespaceAll, "", "v1", "services"); err == nil { + verbs = append(verbs, "get") } - for _, rule := range expectedServiceMirrorRolePolicies { - if err := verifyRule(rule, role.Rules); err != nil { - errors = append(errors, fmt.Sprintf("Service mirror Role %s: %s", role.Name, err)) - } + if err := hc.checkCanPerformAction(remoteAPI, "list", corev1.NamespaceAll, "", "v1", "services"); err == nil { + verbs = append(verbs, "list") } - if len(errors) > 0 { - return fmt.Errorf(strings.Join(errors, "\n")) + if err := hc.checkCanPerformAction(remoteAPI, "watch", corev1.NamespaceAll, "", "v1", "services"); err == nil { + verbs = append(verbs, "watch") } - return nil + if err := comparePermissions(expectedServiceMirrorRemoteClusterPolicyVerbs, verbs); err != nil { + errors = append(errors, fmt.Errorf("* cluster: [%s]: Insufficient Service permissions: %s", config.ClusterName, err)) + } + + links = append(links, fmt.Sprintf("\t* %s", link.TargetClusterName)) } - return &SkipError{Reason: "not checking muticluster"} -} -func (hc *HealthChecker) checkRemoteClusterAnchors() error { - if len(hc.remoteClusterConfigs) == 0 { - return &SkipError{Reason: "no target cluster configs"} + if len(errors) > 0 { + return joinErrors(errors, 2) } + return &VerboseSuccess{Message: strings.Join(links, "\n")} +} +func (hc *HealthChecker) checkRemoteClusterAnchors() error { localAnchors, err := tls.DecodePEMCertificates(hc.linkerdConfig.Global.IdentityContext.TrustAnchorsPem) if err != nil { return fmt.Errorf("Cannot parse source trust anchors: %s", err) } + errors := []string{} + links := []string{} + for _, link := range hc.links { + // Load the credentials secret + secret, err := hc.kubeAPI.Interface.CoreV1().Secrets(link.Namespace).Get(link.ClusterCredentialsSecret, metav1.GetOptions{}) + if err != nil { + errors = append(errors, fmt.Sprintf("* secret: [%s/%s]: %s", link.Namespace, link.ClusterCredentialsSecret, err)) + continue + } - var offendingClusters []string - for _, cfg := range hc.remoteClusterConfigs { + config, err := servicemirror.ParseRemoteClusterSecret(secret) + if err != nil { + errors = append(errors, fmt.Sprintf("* secret: [%s/%s]: could not parse config secret: %s", secret.Namespace, secret.Name, err)) + continue + } - clientConfig, err := clientcmd.RESTConfigFromKubeConfig(cfg.APIConfig) + clientConfig, err := clientcmd.RESTConfigFromKubeConfig(config.APIConfig) if err != nil { - offendingClusters = append(offendingClusters, fmt.Sprintf("* %s: unable to parse api config", cfg.ClusterName)) + errors = append(errors, fmt.Sprintf("* secret: [%s/%s] cluster: [%s]: unable to parse api config: %s", secret.Namespace, secret.Name, config.ClusterName, err)) continue } remoteAPI, err := k8s.NewAPIForConfig(clientConfig, "", []string{}, requestTimeout) if err != nil { - offendingClusters = append(offendingClusters, fmt.Sprintf("* %s: unable to instantiate api", cfg.ClusterName)) + errors = append(errors, fmt.Sprintf("* secret: [%s/%s] cluster: [%s]: could not instantiate api for target cluster: %s", secret.Namespace, secret.Name, config.ClusterName, err)) continue } - _, cfMap, err := FetchLinkerdConfigMap(remoteAPI, cfg.LinkerdNamespace) + _, cfMap, err := FetchLinkerdConfigMap(remoteAPI, link.TargetClusterLinkerdNamespace) if err != nil { - offendingClusters = append(offendingClusters, fmt.Sprintf("* %s: unable to fetch anchors: %s", cfg.ClusterName, err)) + errors = append(errors, fmt.Sprintf("* %s: unable to fetch anchors: %s", link.TargetClusterName, err)) continue } + remoteAnchors, err := tls.DecodePEMCertificates(cfMap.Global.IdentityContext.TrustAnchorsPem) if err != nil { - offendingClusters = append(offendingClusters, fmt.Sprintf("* %s: cannot parse trust anchors", cfg.ClusterName)) + errors = append(errors, fmt.Sprintf("* %s: cannot parse trust anchors", link.TargetClusterName)) continue } @@ -360,7 +381,7 @@ func (hc *HealthChecker) checkRemoteClusterAnchors() error { // same, we can only compare certs one way and be sure we have // identical anchors if len(remoteAnchors) != len(localAnchors) { - offendingClusters = append(offendingClusters, fmt.Sprintf("* %s", cfg.ClusterName)) + errors = append(errors, fmt.Sprintf("* %s", link.TargetClusterName)) continue } @@ -372,363 +393,147 @@ func (hc *HealthChecker) checkRemoteClusterAnchors() error { for _, remote := range remoteAnchors { local, ok := localAnchorsMap[string(remote.Signature)] if !ok || !local.Equal(remote) { - offendingClusters = append(offendingClusters, fmt.Sprintf("* %s", cfg.ClusterName)) + errors = append(errors, fmt.Sprintf("* %s", link.TargetClusterName)) break } } + links = append(links, fmt.Sprintf("\t* %s", link.TargetClusterName)) } - if len(offendingClusters) > 0 { - return fmt.Errorf("Problematic clusters:\n %s", strings.Join(offendingClusters, "\n ")) + if len(errors) > 0 { + return fmt.Errorf("Problematic clusters:\n %s", strings.Join(errors, "\n ")) } - return nil + return &VerboseSuccess{Message: strings.Join(links, "\n")} } -func serviceExported(svc corev1.Service) bool { - _, hasGtwName := svc.Annotations[k8s.GatewayNameAnnotation] - _, hasGtwNs := svc.Annotations[k8s.GatewayNsAnnotation] - return hasGtwName && hasGtwNs -} +/* Gateway mirror checks */ -func (hc *HealthChecker) checkDaisyChains() error { - if hc.Options.SourceCluster { - errs := []error{} +func (hc *HealthChecker) checkIfGatewayMirrorsHaveEndpoints(ctx context.Context) error { + links := []string{} + errors := []error{} - svcs, err := hc.kubeAPI.CoreV1().Services(metav1.NamespaceAll).List(metav1.ListOptions{}) + for _, link := range hc.links { + selector := metav1.ListOptions{LabelSelector: fmt.Sprintf("%s,%s=%s", k8s.MirroredGatewayLabel, k8s.RemoteClusterNameLabel, link.TargetClusterName)} + gatewayMirrors, err := hc.kubeAPI.CoreV1().Services(metav1.NamespaceAll).List(selector) if err != nil { - return err - } - for _, svc := range svcs.Items { - _, isMirror := svc.Labels[k8s.MirroredResourceLabel] - if isMirror && serviceExported(svc) { - errs = append(errs, fmt.Errorf("mirror service %s.%s is exported", svc.Name, svc.Namespace)) - } + errors = append(errors, err) + continue } - ts, err := tsclient.NewForConfig(hc.kubeAPI.Config) - if err != nil { - return err - } - splits, err := ts.SplitV1alpha1().TrafficSplits(metav1.NamespaceAll).List(metav1.ListOptions{}) - if err != nil { - return err - } - for _, split := range splits.Items { - apex, err := hc.kubeAPI.CoreV1().Services(split.Namespace).Get(split.Spec.Service, metav1.GetOptions{}) - if err != nil { - return err - } - if serviceExported(*apex) { - for _, backend := range split.Spec.Backends { - if backend.Weight.IsZero() { - continue - } - leaf, err := hc.kubeAPI.CoreV1().Services(split.Namespace).Get(backend.Service, metav1.GetOptions{}) - if err != nil { - return err - } - _, isMirror := leaf.Labels[k8s.MirroredResourceLabel] - if isMirror { - errs = append(errs, fmt.Errorf("exported service %s.%s routes to mirror service %s.%s via traffic split %s.%s", - apex.Name, apex.Namespace, leaf.Name, leaf.Namespace, split.Name, split.Namespace, - )) - } - } - } - } - if len(errs) > 0 { - messages := []string{} - for _, err := range errs { - messages = append(messages, fmt.Sprintf("* %s", err.Error())) - } - return errors.New(strings.Join(messages, "\n")) + if len(gatewayMirrors.Items) != 1 { + errors = append(errors, fmt.Errorf("wrong number (%d) of probe gateways for target cluster %s", len(gatewayMirrors.Items), link.TargetClusterName)) + continue } - return nil - } - return &SkipError{Reason: "not checking muticluster"} -} -func (hc *HealthChecker) checkLocalGateways() error { + svc := gatewayMirrors.Items[0] - errs := checkGateways(hc.kubeAPI) - if len(errs) > 0 { - return joinErrors(errs, 1) - } - return nil -} - -func (hc *HealthChecker) checkRemoteGateways() error { - - if len(hc.remoteClusterConfigs) == 0 { - return &SkipError{Reason: "no target cluster configs"} - } - - var offendingClusters []error - for _, cfg := range hc.remoteClusterConfigs { - clientConfig, err := clientcmd.RESTConfigFromKubeConfig(cfg.APIConfig) - if err != nil { - offendingClusters = append(offendingClusters, fmt.Errorf("* %s: unable to parse api config", cfg.ClusterName)) + // Check if there is a relevant end-point + endpoints, err := hc.kubeAPI.CoreV1().Endpoints(svc.Namespace).Get(svc.Name, metav1.GetOptions{}) + if err != nil || len(endpoints.Subsets) == 0 { + errors = append(errors, fmt.Errorf("%s.%s mirrored from cluster [%s] has no endpoints", svc.Name, svc.Namespace, svc.Labels[k8s.RemoteClusterNameLabel])) continue } - remoteAPI, err := k8s.NewAPIForConfig(clientConfig, "", []string{}, requestTimeout) + // Check gateway liveness according to probes + req := public.GatewaysRequest{ + TimeWindow: "1m", + RemoteClusterName: link.TargetClusterName, + } + rsp, err := hc.apiClient.Gateways(ctx, &req) if err != nil { - offendingClusters = append(offendingClusters, fmt.Errorf("* %s: unable to instantiate api", cfg.ClusterName)) + errors = append(errors, fmt.Errorf("failed to fetch gateway metrics for %s.%s: %s", svc.Name, svc.Namespace, err)) continue } - - errs := checkGateways(remoteAPI) - if len(errs) > 0 { - offendingClusters = append(offendingClusters, fmt.Errorf("* %s: remote cluster has invalid gateways:\n%s", cfg.ClusterName, joinErrors(errs, 2).Error())) + table := rsp.GetOk().GetGatewaysTable() + if table == nil { + errors = append(errors, fmt.Errorf("failed to fetch gateway metrics for %s.%s: %s", svc.Name, svc.Namespace, rsp.GetError().GetError())) continue } - } - if len(offendingClusters) > 0 { - return joinErrors(offendingClusters, 1) - } - return nil -} - -func checkGateways(api *k8s.KubernetesAPI) []error { - errs := []error{} - services, err := api.CoreV1().Services(metav1.NamespaceAll).List(metav1.ListOptions{}) - if err != nil { - return []error{err} - } - - for _, svc := range services.Items { - if serviceExported(svc) { - // Check if there is a relevant gateway - gatewayName := svc.Annotations[k8s.GatewayNameAnnotation] - gatewayNamespace := svc.Annotations[k8s.GatewayNsAnnotation] - gateway, err := api.CoreV1().Services(gatewayNamespace).Get(gatewayName, metav1.GetOptions{}) - if err != nil { - errs = append(errs, fmt.Errorf("Exported service %s.%s references a gateway that does not exist: %s.%s", svc.Name, svc.Namespace, gatewayName, gatewayNamespace)) - continue - } - - // check if there is an external IP for the gateway service - if len(gateway.Status.LoadBalancer.Ingress) <= 0 { - errs = append(errs, fmt.Errorf("Exported service %s.%s references a gateway with no external IP: %s.%s", svc.Name, svc.Namespace, gatewayName, gatewayNamespace)) - } - - // check if the gateway service has relevant ports - portNames := []string{k8s.GatewayPortName, k8s.ProbePortName} - for _, portName := range portNames { - if !ifPortExists(gateway.Spec.Ports, portName) { - errs = append(errs, fmt.Errorf("Exported service %s.%s references a gateway that is missing port %s: %s.%s", svc.Name, svc.Namespace, portName, gatewayName, gatewayNamespace)) - } - } - + if len(table.Rows) != 1 { + errors = append(errors, fmt.Errorf("wrong number of (%d) gateway metrics entries for %s.%s", len(table.Rows), svc.Name, svc.Namespace)) + continue } - } - return errs -} -func ifPortExists(ports []corev1.ServicePort, portName string) bool { - for _, port := range ports { - if port.Name == portName { - return true + row := table.Rows[0] + if !row.Alive { + errors = append(errors, fmt.Errorf("liveness checks failed for %s", link.TargetClusterName)) + continue } - } - return false -} -func (hc *HealthChecker) isTargetCluster() (bool, error) { - - services, err := hc.kubeAPI.CoreV1().Services(metav1.NamespaceAll).List(metav1.ListOptions{}) - if err != nil { - return false, err + links = append(links, fmt.Sprintf("\t* %s", link.TargetClusterName)) } - - for _, service := range services.Items { - if serviceExported(service) { - return true, nil - } + if len(errors) > 0 { + return joinErrors(errors, 1) } - - return false, nil + return &VerboseSuccess{Message: strings.Join(links, "\n")} } -func (hc *HealthChecker) checkRemoteClusterConnectivity() error { - if hc.Options.SourceCluster { - options := metav1.ListOptions{ - FieldSelector: fmt.Sprintf("%s=%s", "type", k8s.MirrorSecretType), - } - secrets, err := hc.kubeAPI.CoreV1().Secrets(corev1.NamespaceAll).List(options) - if err != nil { - return err - } - - if len(secrets.Items) == 0 { - return &SkipError{Reason: "no target cluster configs"} - } - - var errors []error - for _, s := range secrets.Items { - secret := s - config, err := sm.ParseRemoteClusterSecret(&secret) - if err != nil { - errors = append(errors, fmt.Errorf("* secret: [%s/%s]: could not parse config secret: %s", secret.Namespace, secret.Name, err)) - continue - } - - clientConfig, err := clientcmd.RESTConfigFromKubeConfig(config.APIConfig) - if err != nil { - errors = append(errors, fmt.Errorf("* secret: [%s/%s] cluster: [%s]: unable to parse api config: %s", secret.Namespace, secret.Name, config.ClusterName, err)) - continue - } - - remoteAPI, err := k8s.NewAPIForConfig(clientConfig, "", []string{}, requestTimeout) - if err != nil { - errors = append(errors, fmt.Errorf("* secret: [%s/%s] cluster: [%s]: could not instantiate api for target cluster: %s", secret.Namespace, secret.Name, config.ClusterName, err)) - continue - } - - var verbs []string - if err := hc.checkCanPerformAction(remoteAPI, "get", corev1.NamespaceAll, "", "v1", "services"); err == nil { - verbs = append(verbs, "get") - } +/* Mirror service checks */ - if err := hc.checkCanPerformAction(remoteAPI, "list", corev1.NamespaceAll, "", "v1", "services"); err == nil { - verbs = append(verbs, "list") - } - - if err := hc.checkCanPerformAction(remoteAPI, "watch", corev1.NamespaceAll, "", "v1", "services"); err == nil { - verbs = append(verbs, "watch") - } - - if err := comparePermissions(expectedServiceMirrorRemoteClusterPolicyVerbs, verbs); err != nil { - errors = append(errors, fmt.Errorf("* cluster: [%s]: Insufficient Service permissions: %s", config.ClusterName, err)) - } - - hc.remoteClusterConfigs = append(hc.remoteClusterConfigs, config) - - } +func (hc *HealthChecker) checkIfMirrorServicesHaveEndpoints() error { - if len(errors) > 0 { - return joinErrors(errors, 2) - } - return nil + var servicesWithNoEndpoints []string + selector := fmt.Sprintf("%s, !%s", k8s.MirroredResourceLabel, k8s.MirroredGatewayLabel) + mirrorServices, err := hc.kubeAPI.CoreV1().Services(metav1.NamespaceAll).List(metav1.ListOptions{LabelSelector: selector}) + if err != nil { + return err } - return &SkipError{Reason: "not checking muticluster"} -} -func (hc *HealthChecker) checkRemoteClusterGatewaysHealth(ctx context.Context) error { - if hc.Options.SourceCluster { - if hc.apiClient == nil { - return errors.New("public api client uninitialized") - } - req := &pb.GatewaysRequest{ - TimeWindow: "1m", - } - rsp, err := hc.apiClient.Gateways(ctx, req) - if err != nil { - return err + for _, svc := range mirrorServices.Items { + // Check if there is a relevant end-point + endpoint, err := hc.kubeAPI.CoreV1().Endpoints(svc.Namespace).Get(svc.Name, metav1.GetOptions{}) + if err != nil || len(endpoint.Subsets) == 0 { + servicesWithNoEndpoints = append(servicesWithNoEndpoints, fmt.Sprintf("%s.%s mirrored from cluster [%s] (gateway: [%s/%s])", svc.Name, svc.Namespace, svc.Labels[k8s.RemoteClusterNameLabel], svc.Labels[k8s.RemoteGatewayNsLabel], svc.Labels[k8s.RemoteGatewayNameLabel])) } - - var deadGateways []string - var aliveGateways []string - if len(rsp.GetOk().GatewaysTable.Rows) == 0 { - return &SkipError{Reason: "no target gateways"} - } - for _, gtw := range rsp.GetOk().GatewaysTable.Rows { - if gtw.Alive { - aliveGateways = append(aliveGateways, fmt.Sprintf(" * cluster: [%s], gateway: [%s/%s]", gtw.ClusterName, gtw.Namespace, gtw.Name)) - } else { - deadGateways = append(deadGateways, fmt.Sprintf("* cluster: [%s], gateway: [%s/%s]", gtw.ClusterName, gtw.Namespace, gtw.Name)) - } - } - - if len(deadGateways) > 0 { - return fmt.Errorf("Some gateways are not alive:\n %s", strings.Join(deadGateways, "\n ")) - } - return &VerboseSuccess{Message: strings.Join(aliveGateways, "\n")} } - return &SkipError{Reason: "not checking muticluster"} -} - -func (hc *HealthChecker) checkIfMirrorServicesHaveEndpoints() error { - if hc.Options.SourceCluster { - var servicesWithNoEndpoints []string - selector := fmt.Sprintf("%s, !%s", k8s.MirroredResourceLabel, k8s.MirroredGatewayLabel) - mirrorServices, err := hc.kubeAPI.CoreV1().Services(metav1.NamespaceAll).List(metav1.ListOptions{LabelSelector: selector}) - if err != nil { - return err - } - - for _, svc := range mirrorServices.Items { - // Check if there is a relevant end-point - endpoint, err := hc.kubeAPI.CoreV1().Endpoints(svc.Namespace).Get(svc.Name, metav1.GetOptions{}) - if err != nil || len(endpoint.Subsets) == 0 { - servicesWithNoEndpoints = append(servicesWithNoEndpoints, fmt.Sprintf("%s.%s mirrored from cluster [%s] (gateway: [%s/%s])", svc.Name, svc.Namespace, svc.Labels[k8s.RemoteClusterNameLabel], svc.Labels[k8s.RemoteGatewayNsLabel], svc.Labels[k8s.RemoteGatewayNameLabel])) - } - } - - if len(servicesWithNoEndpoints) > 0 { - return fmt.Errorf("Some mirror services do not have endpoints:\n %s", strings.Join(servicesWithNoEndpoints, "\n ")) - } - return nil + if len(servicesWithNoEndpoints) > 0 { + return fmt.Errorf("Some mirror services do not have endpoints:\n %s", strings.Join(servicesWithNoEndpoints, "\n ")) } - return &SkipError{Reason: "not checking muticluster"} + return nil } -func (hc *HealthChecker) checkIfGatewayMirrorsHaveEndpoints() error { - if hc.Options.SourceCluster { - - var gatewayMirrorsWithNoEndpoints []string - gatewayServices, err := hc.kubeAPI.CoreV1().Services(metav1.NamespaceAll).List(metav1.ListOptions{LabelSelector: k8s.MirroredGatewayLabel}) - if err != nil { - return err - } - - for _, svc := range gatewayServices.Items { - // Check if there is a relevant end-point - endpoints, err := hc.kubeAPI.CoreV1().Endpoints(svc.Namespace).Get(svc.Name, metav1.GetOptions{}) - if err != nil || len(endpoints.Subsets) == 0 { - gatewayMirrorsWithNoEndpoints = append(gatewayMirrorsWithNoEndpoints, fmt.Sprintf("%s.%s mirrored from cluster [%s]", svc.Name, svc.Namespace, svc.Labels[k8s.RemoteClusterNameLabel])) - } - } +func (hc *HealthChecker) checkForOrphanedServices() error { + errors := []error{} - if len(gatewayMirrorsWithNoEndpoints) > 0 { - return fmt.Errorf("Some gateway mirrors do not have endpoints:\n %s", strings.Join(gatewayMirrorsWithNoEndpoints, "\n ")) - } - return nil + selector := fmt.Sprintf("%s, !%s", k8s.MirroredResourceLabel, k8s.MirroredGatewayLabel) + mirrorServices, err := hc.kubeAPI.CoreV1().Services(metav1.NamespaceAll).List(metav1.ListOptions{LabelSelector: selector}) + if err != nil { + return err } - return &SkipError{Reason: "not checking muticluster"} -} - -func (hc *HealthChecker) checkIfGatewaysHaveEndpoints() error { - var gatewaysWithNoEndpoints []string - services, err := hc.kubeAPI.CoreV1().Services(corev1.NamespaceAll).List(metav1.ListOptions{}) + links, err := multicluster.GetLinks(hc.kubeAPI.DynamicClient) if err != nil { return err } - for _, service := range services.Items { - if gatewayService(service) { - // Check if there is a relevant end-point - endpoints, err := hc.kubeAPI.CoreV1().Endpoints(service.Namespace).Get(service.Name, metav1.GetOptions{}) - if err != nil || len(endpoints.Subsets) == 0 { - gatewaysWithNoEndpoints = append(gatewaysWithNoEndpoints, fmt.Sprintf("%s.%s", service.Name, service.Namespace)) + for _, svc := range mirrorServices.Items { + targetCluster := svc.Labels[k8s.RemoteClusterNameLabel] + hasLink := false + for _, link := range links { + if link.TargetClusterName == targetCluster { + hasLink = true + break } } - + if !hasLink { + errors = append(errors, fmt.Errorf("mirror service %s.%s is not part of any Link", svc.Name, svc.Namespace)) + } } - if len(gatewaysWithNoEndpoints) > 0 { - return fmt.Errorf("Some gateway services do not have endpoints:\n %s", strings.Join(gatewaysWithNoEndpoints, "\n ")) + if len(errors) > 0 { + return joinErrors(errors, 1) } return nil - } -func gatewayService(svc corev1.Service) bool { - _, isGtw := svc.Annotations[k8s.MulticlusterGatewayAnnotation] - return isGtw +/* util */ + +func serviceMirrorComponentsSelector(targetCluster string) string { + return fmt.Sprintf("%s=%s,%s=%s", + k8s.ControllerComponentLabel, linkerdServiceMirrorComponentName, + k8s.RemoteClusterNameLabel, targetCluster) } func joinErrors(errs []error, tabDepth int) error { @@ -739,3 +544,17 @@ func joinErrors(errs []error, tabDepth int) error { } return errors.New(strings.Join(errStrings, "\n")) } + +func comparePermissions(expected, actual []string) error { + sort.Strings(expected) + sort.Strings(actual) + + expectedStr := strings.Join(expected, ",") + actualStr := strings.Join(actual, ",") + + if expectedStr != actualStr { + return fmt.Errorf("expected %s, got %s", expectedStr, actualStr) + } + + return nil +} diff --git a/pkg/k8s/authz.go b/pkg/k8s/authz.go index 3f274e04bd983..17e443855c191 100644 --- a/pkg/k8s/authz.go +++ b/pkg/k8s/authz.go @@ -142,6 +142,25 @@ func EndpointSliceAccess(k8sClient kubernetes.Interface) bool { // return errors.New("no EndpointSlice resources exist in the cluster") //} +// LinkAccess checks whether the Link CRD is installed on the cluster and the +// client is authorized to access Links. +func LinkAccess(k8sClient kubernetes.Interface) error { + res, err := k8sClient.Discovery().ServerResourcesForGroupVersion(LinkAPIGroupVersion) + if err != nil { + return err + } + + if res.GroupVersion == LinkAPIGroupVersion { + for _, apiRes := range res.APIResources { + if apiRes.Kind == LinkKind { + return ResourceAuthz(k8sClient, "", "list", LinkAPIGroup, LinkAPIVersion, "links", "") + } + } + } + + return errors.New("Link CRD not found") +} + // ClusterAccess verifies whether k8sClient is authorized to access all pods in // all namespaces in the cluster. func ClusterAccess(k8sClient kubernetes.Interface) error { diff --git a/pkg/k8s/k8s.go b/pkg/k8s/k8s.go index 892a9e888f03e..e480d3375b8c1 100644 --- a/pkg/k8s/k8s.go +++ b/pkg/k8s/k8s.go @@ -28,6 +28,11 @@ const ( ServiceProfileAPIVersion = "linkerd.io/v1alpha2" ServiceProfileKind = "ServiceProfile" + LinkAPIGroup = "multicluster.linkerd.io" + LinkAPIVersion = "v1alpha1" + LinkAPIGroupVersion = "multicluster.linkerd.io/v1alpha1" + LinkKind = "Link" + // special case k8s job label, to not conflict with Prometheus' job label l5dJob = "k8s_job" ) diff --git a/pkg/multicluster/link.go b/pkg/multicluster/link.go index cd24e854e87c2..2503301a23880 100644 --- a/pkg/multicluster/link.go +++ b/pkg/multicluster/link.go @@ -4,11 +4,16 @@ import ( "errors" "fmt" "strconv" + "strings" "time" + "github.com/linkerd/linkerd2/pkg/k8s" consts "github.com/linkerd/linkerd2/pkg/k8s" corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/dynamic" ) type ( @@ -26,6 +31,8 @@ type ( // target cluster and is configures the behavior of a service mirror // controller. Link struct { + Name string + Namespace string TargetClusterName string TargetClusterDomain string TargetClusterLinkerdNamespace string @@ -37,6 +44,13 @@ type ( } ) +// LinkGVR is the Group Version and Resource of the Link custom resource. +var LinkGVR = schema.GroupVersionResource{ + Group: k8s.LinkAPIGroup, + Version: k8s.LinkAPIVersion, + Resource: "links", +} + func (ps ProbeSpec) String() string { return fmt.Sprintf("ProbeSpec: {path: %s, port: %d, period: %s}", ps.Path, ps.Port, ps.Period) } @@ -108,6 +122,8 @@ func NewLink(u unstructured.Unstructured) (Link, error) { } return Link{ + Name: u.GetName(), + Namespace: u.GetNamespace(), TargetClusterName: targetClusterName, TargetClusterDomain: targetClusterDomain, TargetClusterLinkerdNamespace: targetClusterLinkerdNamespace, @@ -121,15 +137,15 @@ func NewLink(u unstructured.Unstructured) (Link, error) { // ToUnstructured converts a Link struct into an unstructured resource that can // be used by a kubernetes dynamic client. -func (l Link) ToUnstructured(name, namespace string) unstructured.Unstructured { +func (l Link) ToUnstructured() unstructured.Unstructured { return unstructured.Unstructured{ Object: map[string]interface{}{ - "apiVersion": "multicluster.linkerd.io/v1alpha1", - "kind": "Link", + "apiVersion": k8s.LinkAPIGroupVersion, + "kind": k8s.LinkKind, "metadata": map[string]interface{}{ - "name": name, - "namespace": namespace, + "name": l.Name, + "namespace": l.Namespace, }, "spec": map[string]interface{}{ "targetClusterName": l.TargetClusterName, @@ -173,6 +189,37 @@ func ExtractProbeSpec(gateway *corev1.Service) (ProbeSpec, error) { }, nil } +// GetLinks fetchs a list of all Link objects in the cluster. +func GetLinks(client dynamic.Interface) ([]Link, error) { + list, err := client.Resource(LinkGVR).List(metav1.ListOptions{}) + if err != nil { + return nil, err + } + links := []Link{} + errs := []string{} + for _, u := range list.Items { + link, err := NewLink(u) + if err != nil { + errs = append(errs, fmt.Sprintf("failed to parse Link %s: %s", u.GetName(), err)) + } else { + links = append(links, link) + } + } + if len(errs) > 0 { + return nil, errors.New(strings.Join(errs, "\n")) + } + return links, nil +} + +// GetLink fetches a Link object from Kubernetes by name/namespace. +func GetLink(client dynamic.Interface, namespace, name string) (Link, error) { + unstructured, err := client.Resource(LinkGVR).Namespace(namespace).Get(name, metav1.GetOptions{}) + if err != nil { + return Link{}, err + } + return NewLink(*unstructured) +} + func extractPort(port []corev1.ServicePort, portName string) (uint32, error) { for _, p := range port { if p.Name == portName { From 687659522cd82175fc3116758ff0545de5858d05 Mon Sep 17 00:00:00 2001 From: Alex Leong Date: Mon, 13 Jul 2020 17:01:17 -0700 Subject: [PATCH 08/14] Update integration tests Signed-off-by: Alex Leong --- pkg/healthcheck/healthcheck_multicluster.go | 32 +++++++++++++++++++ .../testdata/check.multicluster.golden | 13 ++------ .../testdata/check.multicluster.proxy.golden | 13 ++------ testutil/test_helper.go | 3 +- 4 files changed, 37 insertions(+), 24 deletions(-) diff --git a/pkg/healthcheck/healthcheck_multicluster.go b/pkg/healthcheck/healthcheck_multicluster.go index 6f8f21944eaf9..5fb26eac2dbeb 100644 --- a/pkg/healthcheck/healthcheck_multicluster.go +++ b/pkg/healthcheck/healthcheck_multicluster.go @@ -235,6 +235,10 @@ func (hc *HealthChecker) checkServiceMirrorLocalRBAC() error { return fmt.Errorf(strings.Join(errors, "\n")) } + if len(links) == 0 { + return &SkipError{Reason: "no links"} + } + return &VerboseSuccess{Message: strings.Join(links, "\n")} } @@ -271,6 +275,11 @@ func (hc *HealthChecker) checkServiceMirrorController() error { if len(errors) > 0 { return joinErrors(errors, 2) } + + if len(clusterNames) == 0 { + return &SkipError{Reason: "no links"} + } + return &VerboseSuccess{Message: strings.Join(clusterNames, "\n")} } @@ -329,6 +338,11 @@ func (hc *HealthChecker) checkRemoteClusterConnectivity() error { if len(errors) > 0 { return joinErrors(errors, 2) } + + if len(links) == 0 { + return &SkipError{Reason: "no links"} + } + return &VerboseSuccess{Message: strings.Join(links, "\n")} } @@ -404,6 +418,10 @@ func (hc *HealthChecker) checkRemoteClusterAnchors() error { return fmt.Errorf("Problematic clusters:\n %s", strings.Join(errors, "\n ")) } + if len(links) == 0 { + return &SkipError{Reason: "no links"} + } + return &VerboseSuccess{Message: strings.Join(links, "\n")} } @@ -466,6 +484,11 @@ func (hc *HealthChecker) checkIfGatewayMirrorsHaveEndpoints(ctx context.Context) if len(errors) > 0 { return joinErrors(errors, 1) } + + if len(links) == 0 { + return &SkipError{Reason: "no links"} + } + return &VerboseSuccess{Message: strings.Join(links, "\n")} } @@ -491,6 +514,11 @@ func (hc *HealthChecker) checkIfMirrorServicesHaveEndpoints() error { if len(servicesWithNoEndpoints) > 0 { return fmt.Errorf("Some mirror services do not have endpoints:\n %s", strings.Join(servicesWithNoEndpoints, "\n ")) } + + if len(mirrorServices.Items) == 0 { + return &SkipError{Reason: "no mirror services"} + } + return nil } @@ -522,6 +550,10 @@ func (hc *HealthChecker) checkForOrphanedServices() error { } } + if len(mirrorServices.Items) == 0 { + return &SkipError{Reason: "no mirror services"} + } + if len(errors) > 0 { return joinErrors(errors, 1) } diff --git a/test/integration/testdata/check.multicluster.golden b/test/integration/testdata/check.multicluster.golden index 30dc2dfdb69f0..765723115c531 100644 --- a/test/integration/testdata/check.multicluster.golden +++ b/test/integration/testdata/check.multicluster.golden @@ -68,17 +68,8 @@ linkerd-grafana √ grafana add-on config map exists √ grafana pod is running -linkerd-multicluster-source +linkerd-multicluster --------------------------- -√ service mirror controller is running -√ service mirror controller ClusterRoles exist -√ service mirror controller ClusterRoleBindings exist -√ service mirror controller Roles exist -√ service mirror controller RoleBindings exist -√ service mirror controller ServiceAccounts exist -√ service mirror controller has required permissions -√ multicluster daisy chaining is avoided -√ all mirror services have endpoints -√ all gateway mirrors have endpoints +√ Link CRD exists Status check results are √ diff --git a/test/integration/testdata/check.multicluster.proxy.golden b/test/integration/testdata/check.multicluster.proxy.golden index 4e93d3031a467..782e58bf7e229 100644 --- a/test/integration/testdata/check.multicluster.proxy.golden +++ b/test/integration/testdata/check.multicluster.proxy.golden @@ -75,17 +75,8 @@ linkerd-grafana √ grafana add-on config map exists √ grafana pod is running -linkerd-multicluster-source +linkerd-multicluster --------------------------- -√ service mirror controller is running -√ service mirror controller ClusterRoles exist -√ service mirror controller ClusterRoleBindings exist -√ service mirror controller Roles exist -√ service mirror controller RoleBindings exist -√ service mirror controller ServiceAccounts exist -√ service mirror controller has required permissions -√ multicluster daisy chaining is avoided -√ all mirror services have endpoints -√ all gateway mirrors have endpoints +√ Link CRD exists Status check results are √ diff --git a/testutil/test_helper.go b/testutil/test_helper.go index 4c9501b76eb3c..3c9356947ba3b 100644 --- a/testutil/test_helper.go +++ b/testutil/test_helper.go @@ -113,8 +113,7 @@ func NewGenericTestHelper( // MulticlusterDeployReplicas is a map containing the number of replicas for each Deployment and the main // container name for multicluster components var MulticlusterDeployReplicas = map[string]DeploySpec{ - "linkerd-gateway": {1, []string{"nginx"}}, - "linkerd-service-mirror": {1, []string{"service-mirror"}}, + "linkerd-gateway": {1, []string{"nginx"}}, } // NewTestHelper creates a new instance of TestHelper for the current test run. From a913f8f2ec9b72c1f38fc91282101d76bd4efd7f Mon Sep 17 00:00:00 2001 From: Alex Leong Date: Tue, 14 Jul 2020 11:35:13 -0700 Subject: [PATCH 09/14] Integration tests pass Signed-off-by: Alex Leong --- charts/linkerd2-multicluster-link/.helmignore | 22 ++++++++++ charts/linkerd2-multicluster-link/Chart.yaml | 7 ++++ charts/linkerd2-multicluster-link/README.md | 40 +++++++++++++++++++ .../templates/gateway-mirror.yaml | 0 .../templates/service-mirror.yaml | 0 charts/linkerd2-multicluster-link/values.yaml | 9 +++++ charts/linkerd2-multicluster/Chart.yaml | 4 +- charts/linkerd2-multicluster/values.yaml | 9 ----- cli/cmd/multicluster.go | 15 +++---- test/integration/install_test.go | 1 - .../testdata/check.multicluster.golden | 2 +- .../testdata/check.multicluster.proxy.golden | 2 +- 12 files changed, 90 insertions(+), 21 deletions(-) create mode 100644 charts/linkerd2-multicluster-link/.helmignore create mode 100644 charts/linkerd2-multicluster-link/Chart.yaml create mode 100644 charts/linkerd2-multicluster-link/README.md rename charts/{linkerd2-multicluster => linkerd2-multicluster-link}/templates/gateway-mirror.yaml (100%) rename charts/{linkerd2-multicluster => linkerd2-multicluster-link}/templates/service-mirror.yaml (100%) create mode 100644 charts/linkerd2-multicluster-link/values.yaml diff --git a/charts/linkerd2-multicluster-link/.helmignore b/charts/linkerd2-multicluster-link/.helmignore new file mode 100644 index 0000000000000..79c90a8063116 --- /dev/null +++ b/charts/linkerd2-multicluster-link/.helmignore @@ -0,0 +1,22 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +OWNERS +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/charts/linkerd2-multicluster-link/Chart.yaml b/charts/linkerd2-multicluster-link/Chart.yaml new file mode 100644 index 0000000000000..c6ec380a9b727 --- /dev/null +++ b/charts/linkerd2-multicluster-link/Chart.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +appVersion: edge-XX.X.X +description: A helm chart containing the resources to enable mirroring of services from a remote cluster +kubeVersion: ">=1.13.0-0" +icon: https://linkerd.io/images/logo-only-200h.png +name: "linkerd2-multicluster-link" +version: 0.1.0 diff --git a/charts/linkerd2-multicluster-link/README.md b/charts/linkerd2-multicluster-link/README.md new file mode 100644 index 0000000000000..3500c5285444a --- /dev/null +++ b/charts/linkerd2-multicluster-link/README.md @@ -0,0 +1,40 @@ + +# Linkerd2-multicluster-link Helm Chart + +Linkerd is a *service mesh*, designed to give platform-wide observability, +reliability, and security without requiring configuration or code changes. This +chart provides the components needed to enable communication between clusters. + +## Configuration + +The following table lists the configurable parameters of the +linkerd2-multicluster chart and their default values. + +| Parameter | Description | Default | +|---------------------------------|---------------------------------------------------------------------------------------------|----------------------------------------------| +|`controllerComponentLabel` | Control plane label. Do not edit |`linkerd.io/control-plane-component` | +|`controllerImage` | Docker image for the Service mirror component (uses the Linkerd controller image) |`gcr.io/linkerd-io/controller` | +|`controllerImageVersion` | Tag for the Service Mirror container Docker image |`latest version` | +|`createdByAnnotation` | Annotation label for the proxy create. Do not edit. |`linkerd.io/created-by` | +|`gateway` | If the gateway component should be installed |`true` | +|`gatewayLocalProbePath` | The path that will be used by the local liveness checks to ensure the gateway is alive |`/health-local` | +|`gatewayLocalProbePort` | The port that will be used by the local liveness checks to ensure the gateway is alive |`8888` | +|`gatewayName` | The name of the gateway that will be installed |`linkerd-gateway` | +|`gatewayNginxImage` | The Nginx image |`nginx` | +|`gatewayNginxImageVersion` | The version of the Nginx image |`1.17` | +|`gatewayPort` | The port on which all the gateway will accept incoming traffic |`4143` | +|`gatewayProbePath` | The path that will be used by remote clusters for determining whether the gateway is alive |`/health` | +|`gatewayProbePort` | The port used for liveliness probing |`4181` | +|`gatewayProbeSeconds` | The interval (in seconds) between liveness probes |`3` | +|`identityTrustDomain` | Trust domain used for identity of the existing linkerd installation |`cluster.local` | +|`installNamespace` | If the namespace should be installed |`true` | +|`linkerdNamespace` | The namespace of the existing Linkerd installation |`linkerd` | +|`linkerdVersion` | Control plane version | latest version | +|`namespace` | Service Mirror component namespace |`linkerd-multicluster` | +|`proxyOutboundPort` | The port on which the proxy accepts outbound traffic |`4140` | +|`remoteMirrorServiceAccountName` | The name of the service account used to allow remote clusters to mirror local services |`linkerd-service-mirror-remote-access-default`| +|`remoteMirrorServiceAccount` | If the remote mirror service account should be installed |`true` | +|`serviceMirror` | If the service mirror component should be installed |`true` | +|`logLevel` | Log level for the Multicluster components |`info` | +|`serviceMirrorRetryLimit` | Number of times update from the remote cluster is allowed to be requeued (retried) |`3` | +|`serviceMirrorUID` | User id under which the Service Mirror shall be ran |`2103` | diff --git a/charts/linkerd2-multicluster/templates/gateway-mirror.yaml b/charts/linkerd2-multicluster-link/templates/gateway-mirror.yaml similarity index 100% rename from charts/linkerd2-multicluster/templates/gateway-mirror.yaml rename to charts/linkerd2-multicluster-link/templates/gateway-mirror.yaml diff --git a/charts/linkerd2-multicluster/templates/service-mirror.yaml b/charts/linkerd2-multicluster-link/templates/service-mirror.yaml similarity index 100% rename from charts/linkerd2-multicluster/templates/service-mirror.yaml rename to charts/linkerd2-multicluster-link/templates/service-mirror.yaml diff --git a/charts/linkerd2-multicluster-link/values.yaml b/charts/linkerd2-multicluster-link/values.yaml new file mode 100644 index 0000000000000..df34d0d83c42f --- /dev/null +++ b/charts/linkerd2-multicluster-link/values.yaml @@ -0,0 +1,9 @@ +controllerComponentLabel: linkerd.io/control-plane-component +controllerImage: gcr.io/linkerd-io/controller +controllerImageVersion: linkerdVersionValue +createdByAnnotation: linkerd.io/created-by +gatewayProbePort: 4181 +namespace: linkerd-multicluster +logLevel: info +serviceMirrorRetryLimit: 3 +serviceMirrorUID: 2103 diff --git a/charts/linkerd2-multicluster/Chart.yaml b/charts/linkerd2-multicluster/Chart.yaml index 377b564f958e4..0870b69269002 100644 --- a/charts/linkerd2-multicluster/Chart.yaml +++ b/charts/linkerd2-multicluster/Chart.yaml @@ -1,7 +1,7 @@ apiVersion: v1 appVersion: edge-XX.X.X -description: A helm chart containing the resources to enable mirroring of services on remote clusters +description: A helm chart containing the resources to support multicluster linking to remote clusters kubeVersion: ">=1.13.0-0" icon: https://linkerd.io/images/logo-only-200h.png name: "linkerd2-multicluster" -version: 0.1.0 \ No newline at end of file +version: 0.1.0 diff --git a/charts/linkerd2-multicluster/values.yaml b/charts/linkerd2-multicluster/values.yaml index 6d260c2416989..78d17be59e569 100644 --- a/charts/linkerd2-multicluster/values.yaml +++ b/charts/linkerd2-multicluster/values.yaml @@ -1,6 +1,3 @@ -controllerComponentLabel: linkerd.io/control-plane-component -controllerImage: gcr.io/linkerd-io/controller -controllerImageVersion: linkerdVersionValue createdByAnnotation: linkerd.io/created-by gateway: true gatewayLocalProbePath: /health-local @@ -12,15 +9,9 @@ gatewayPort: 4143 gatewayProbePath: /health gatewayProbePort: 4181 gatewayProbeSeconds: 3 -identityTrustDomain: cluster.local installNamespace: true -linkerdNamespace: linkerd linkerdVersion: linkerdVersionValue namespace: linkerd-multicluster proxyOutboundPort: 4140 -serviceMirror: true -logLevel: info -serviceMirrorRetryLimit: 3 -serviceMirrorUID: 2103 remoteMirrorServiceAccount: true remoteMirrorServiceAccountName: linkerd-service-mirror-remote-access-default diff --git a/cli/cmd/multicluster.go b/cli/cmd/multicluster.go index efdaacc3145ec..0d88ef1f0c867 100644 --- a/cli/cmd/multicluster.go +++ b/cli/cmd/multicluster.go @@ -34,11 +34,12 @@ import ( ) const ( - defaultMulticlusterNamespace = "linkerd-multicluster" - defaultGatewayName = "linkerd-gateway" - helmMulticlusterDefaultChartName = "linkerd2-multicluster" - tokenKey = "token" - defaultServiceAccountName = "linkerd-service-mirror-remote-access-default" + defaultMulticlusterNamespace = "linkerd-multicluster" + defaultGatewayName = "linkerd-gateway" + helmMulticlusterDefaultChartName = "linkerd2-multicluster" + helmMulticlusterLinkDefaultChartName = "linkerd2-multicluster-link" + tokenKey = "token" + defaultServiceAccountName = "linkerd-service-mirror-remote-access-default" ) type ( @@ -589,8 +590,8 @@ func newLinkCommand() *cobra.Command { } chart := &charts.Chart{ - Name: helmMulticlusterDefaultChartName, - Dir: helmMulticlusterDefaultChartName, + Name: helmMulticlusterLinkDefaultChartName, + Dir: helmMulticlusterLinkDefaultChartName, Namespace: controlPlaneNamespace, RawValues: rawValues, Files: files, diff --git a/test/integration/install_test.go b/test/integration/install_test.go index d36e10dc51eca..b2b8d2506db21 100644 --- a/test/integration/install_test.go +++ b/test/integration/install_test.go @@ -863,7 +863,6 @@ func TestUninstallMulticluster(t *testing.T) { } else { exec := append([]string{"multicluster"}, []string{ "install", - "--log-level", "debug", "--namespace", TestHelper.GetMulticlusterNamespace(), }...) out, stderr, err := TestHelper.LinkerdRun(exec...) diff --git a/test/integration/testdata/check.multicluster.golden b/test/integration/testdata/check.multicluster.golden index 765723115c531..2d02d8d1260a7 100644 --- a/test/integration/testdata/check.multicluster.golden +++ b/test/integration/testdata/check.multicluster.golden @@ -69,7 +69,7 @@ linkerd-grafana √ grafana pod is running linkerd-multicluster ---------------------------- +-------------------- √ Link CRD exists Status check results are √ diff --git a/test/integration/testdata/check.multicluster.proxy.golden b/test/integration/testdata/check.multicluster.proxy.golden index 782e58bf7e229..5849a56d319d8 100644 --- a/test/integration/testdata/check.multicluster.proxy.golden +++ b/test/integration/testdata/check.multicluster.proxy.golden @@ -76,7 +76,7 @@ linkerd-grafana √ grafana pod is running linkerd-multicluster ---------------------------- +-------------------- √ Link CRD exists Status check results are √ From 7a60e703c9460a414eb4606ed82bcc4f267221bc Mon Sep 17 00:00:00 2001 From: Alex Leong Date: Tue, 14 Jul 2020 14:48:11 -0700 Subject: [PATCH 10/14] Cherry-pick PR #4740 to pick up fix for clusters that don't support endpointslices. Fix some helm template issues Signed-off-by: Alex Leong --- bin/helm-build | 2 + .../templates/gateway-mirror.yaml | 2 - .../templates/service-mirror.yaml | 2 - charts/linkerd2/templates/_config.tpl | 3 +- .../linkerd2/templates/destination-rbac.yaml | 2 + charts/linkerd2/values.yaml | 5 + cli/cmd/install.go | 22 ++ cli/cmd/multicluster.go | 10 +- cli/cmd/testdata/install_addon_config.golden | 3 - .../install_addon_control-plane.golden | 2 +- cli/cmd/testdata/install_config.golden | 3 - cli/cmd/testdata/install_control-plane.golden | 2 +- ...install_controlplane_tracing_output.golden | 5 +- .../testdata/install_custom_registry.golden | 5 +- cli/cmd/testdata/install_default.golden | 5 +- ...stall_default_override_dst_get_nets.golden | 5 +- .../testdata/install_grafana_existing.golden | 5 +- cli/cmd/testdata/install_ha_output.golden | 5 +- .../install_ha_with_overrides_output.golden | 5 +- .../install_heartbeat_disabled_output.golden | 5 +- cli/cmd/testdata/install_helm_output.golden | 6 +- .../install_helm_output_addons.golden | 6 +- .../testdata/install_helm_output_ha.golden | 6 +- .../testdata/install_no_init_container.golden | 5 +- cli/cmd/testdata/install_output.golden | 3 - .../install_prometheus_overwrite.golden | 5 +- cli/cmd/testdata/install_proxy_ignores.golden | 5 +- .../install_restricted_dashboard.golden | 5 +- cli/cmd/testdata/install_tracing.golden | 5 +- .../testdata/install_tracing_overwrite.golden | 5 +- cli/cmd/testdata/upgrade_add-on_config.golden | 3 - .../upgrade_add-on_controlplane.golden | 2 +- .../testdata/upgrade_add-on_overwrite.golden | 5 +- cli/cmd/testdata/upgrade_add_add-on.golden | 5 +- cli/cmd/testdata/upgrade_default.golden | 5 +- .../testdata/upgrade_external_issuer.golden | 5 +- .../upgrade_grafana_addon_overwrite.yaml | 5 +- .../testdata/upgrade_grafana_disabled.yaml | 5 +- cli/cmd/testdata/upgrade_grafana_enabled.yaml | 5 +- .../upgrade_grafana_enabled_disabled.yaml | 5 +- .../testdata/upgrade_grafana_overwrite.yaml | 5 +- cli/cmd/testdata/upgrade_ha.golden | 5 +- cli/cmd/testdata/upgrade_ha_config.golden | 3 - .../upgrade_keep_webhook_cabundle.golden | 5 +- cli/cmd/testdata/upgrade_nothing_addon.yaml | 5 +- .../testdata/upgrade_overwrite_issuer.golden | 5 +- ...write_trust_anchors-external-issuer.golden | 5 +- .../upgrade_overwrite_trust_anchors.golden | 5 +- .../upgrade_two_level_webhook_cert.golden | 5 +- controller/api/destination/server.go | 3 +- controller/api/destination/server_test.go | 2 +- .../destination/watcher/endpoints_watcher.go | 128 ++++----- .../watcher/endpoints_watcher_test.go | 233 +++++++++++------ .../destination/watcher/ip_watcher_test.go | 8 +- controller/cmd/destination/main.go | 32 ++- controller/gen/config/config.pb.go | 247 +++++++++--------- controller/gen/public/public.pb.go | 10 +- pkg/charts/linkerd2/values.go | 1 + pkg/charts/multicluster/values.go | 21 +- pkg/k8s/authz.go | 4 +- proto/config/config.proto | 1 + testutil/logs_events.go | 2 + 62 files changed, 485 insertions(+), 444 deletions(-) diff --git a/bin/helm-build b/bin/helm-build index 4f4b9a477fbab..f4be94e7a26e4 100755 --- a/bin/helm-build +++ b/bin/helm-build @@ -20,6 +20,7 @@ bindir=$( cd "${BASH_SOURCE[0]%/*}" && pwd ) rootdir=$( cd "$bindir"/.. && pwd ) "$bindir"/helm lint "$rootdir"/charts/linkerd2-multicluster +"$bindir"/helm lint "$rootdir"/charts/linkerd2-multicluster-link "$bindir"/helm lint "$rootdir"/charts/partials "$bindir"/helm dep up "$rootdir"/charts/linkerd2-cni "$bindir"/helm lint "$rootdir"/charts/linkerd2-cni @@ -50,6 +51,7 @@ if [ "$1" = package ]; then "$bindir"/helm --version "$version" --app-version "$tag" -d "$rootdir"/target/helm package "$rootdir"/charts/linkerd2 "$bindir"/helm --version "$version" --app-version "$tag" -d "$rootdir"/target/helm package "$rootdir"/charts/linkerd2-cni "$bindir"/helm --version "$version" --app-version "$tag" -d "$rootdir"/target/helm package "$rootdir"/charts/linkerd2-multicluster + "$bindir"/helm --version "$version" --app-version "$tag" -d "$rootdir"/target/helm package "$rootdir"/charts/linkerd2-multicluster-link mv "$rootdir"/target/helm/index-pre.yaml "$rootdir"/target/helm/index-pre-"$version".yaml "$bindir"/helm repo index --url "https://helm.linkerd.io/$repo/" --merge "$rootdir"/target/helm/index-pre-"$version".yaml "$rootdir"/target/helm diff --git a/charts/linkerd2-multicluster-link/templates/gateway-mirror.yaml b/charts/linkerd2-multicluster-link/templates/gateway-mirror.yaml index 88c5e22fee5b1..7806d3e470760 100644 --- a/charts/linkerd2-multicluster-link/templates/gateway-mirror.yaml +++ b/charts/linkerd2-multicluster-link/templates/gateway-mirror.yaml @@ -1,4 +1,3 @@ -{{if .Values.serviceMirror -}} --- apiVersion: v1 kind: Service @@ -13,4 +12,3 @@ spec: - name: mc-probe port: {{.Values.gatewayProbePort}} protocol: TCP -{{end -}} diff --git a/charts/linkerd2-multicluster-link/templates/service-mirror.yaml b/charts/linkerd2-multicluster-link/templates/service-mirror.yaml index d6c7e07e35a3f..a337660d23881 100644 --- a/charts/linkerd2-multicluster-link/templates/service-mirror.yaml +++ b/charts/linkerd2-multicluster-link/templates/service-mirror.yaml @@ -1,4 +1,3 @@ -{{if .Values.serviceMirror -}} --- kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 @@ -111,4 +110,3 @@ spec: - containerPort: 9999 name: admin-http serviceAccountName: linkerd-service-mirror-{{.Values.targetClusterName}} -{{end -}} diff --git a/charts/linkerd2/templates/_config.tpl b/charts/linkerd2/templates/_config.tpl index fe365fb4b65d1..bdd7b39615513 100644 --- a/charts/linkerd2/templates/_config.tpl +++ b/charts/linkerd2/templates/_config.tpl @@ -12,7 +12,8 @@ }, "autoInjectContext": null, "omitWebhookSideEffects": {{.Values.omitWebhookSideEffects}}, - "clusterDomain": "{{.Values.global.clusterDomain}}" + "clusterDomain": "{{.Values.global.clusterDomain}}", + "enableEndpointSlices": "{{.Values.global.enableEndpointSlices}}" } {{- end -}} diff --git a/charts/linkerd2/templates/destination-rbac.yaml b/charts/linkerd2/templates/destination-rbac.yaml index 29d3960372583..3bab38e492419 100644 --- a/charts/linkerd2/templates/destination-rbac.yaml +++ b/charts/linkerd2/templates/destination-rbac.yaml @@ -26,9 +26,11 @@ rules: - apiGroups: ["split.smi-spec.io"] resources: ["trafficsplits"] verbs: ["list", "get", "watch"] + {{- if .Values.global.enableEndpointSlices }} - apiGroups: ["discovery.k8s.io"] resources: ["endpointslices"] verbs: ["list", "get", "watch"] + {{- end }} --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 diff --git a/charts/linkerd2/values.yaml b/charts/linkerd2/values.yaml index 96f5734ef5883..6ef2e74c7d7b9 100644 --- a/charts/linkerd2/values.yaml +++ b/charts/linkerd2/values.yaml @@ -16,6 +16,11 @@ global: namespace: linkerd + # enables the use of EndpointSlice informers for the destination service; + # enableEndpointSlices should be set to true only if EndpointSlice K8s feature gate is on; + # the feature is still experimental. + enableEndpointSlices: false + identityTrustAnchorsPEM: | identityTrustDomain: *cluster_domain diff --git a/cli/cmd/install.go b/cli/cmd/install.go index a104a90cc204a..dfac291e12405 100644 --- a/cli/cmd/install.go +++ b/cli/cmd/install.go @@ -48,6 +48,7 @@ type ( disableH2Upgrade bool disableHeartbeat bool cniEnabled bool + enableEndpointSlices bool skipChecks bool omitWebhookSideEffects bool restrictDashboardPrivileges bool @@ -184,6 +185,7 @@ func newInstallOptionsWithDefaults() (*installOptions, error) { disableH2Upgrade: !defaults.EnableH2Upgrade, disableHeartbeat: defaults.DisableHeartBeat, cniEnabled: defaults.Global.CNIEnabled, + enableEndpointSlices: defaults.Global.EnableEndpointSlices, omitWebhookSideEffects: defaults.OmitWebhookSideEffects, restrictDashboardPrivileges: defaults.RestrictDashboardPrivileges, controlPlaneTracing: defaults.Global.ControlPlaneTracing, @@ -434,6 +436,12 @@ func (options *installOptions) validateAndBuild(stage string, flags *pflag.FlagS return nil, nil, err } + if options.enableEndpointSlices { + if err = validateEndpointSlicesFeature(); err != nil { + return nil, nil, fmt.Errorf("--enableEndpointSlice=true not supported:%s", err) + } + } + return values, configs, nil } @@ -506,6 +514,9 @@ func (options *installOptions) recordableFlagSet() *pflag.FlagSet { "Enables installing the SMI-Metrics controller", ) + flags.BoolVar(&options.enableEndpointSlices, "enable-endpoint-slices", options.enableEndpointSlices, + "Enables the usage of EndpointSlice informers and resources for destination service") + flags.StringVarP(&options.controlPlaneVersion, "control-plane-version", "", options.controlPlaneVersion, "Tag to be used for the control plane component images") flags.StringVar(&options.smiMetricsImage, "smi-metrics-image", options.smiMetricsImage, "SMI Metrics image") @@ -690,6 +701,15 @@ func (options *installOptions) validate() error { return nil } +func validateEndpointSlicesFeature() error { + k8sAPI, err := k8s.NewAPI(kubeconfigPath, kubeContext, impersonate, impersonateGroup, 0) + if err != nil { + return err + } + + return k8s.EndpointSliceAccess(k8sAPI) +} + // buildValuesWithoutIdentity builds the values that will be used to render // the Helm templates. It overrides the defaults values with CLI options. func (options *installOptions) buildValuesWithoutIdentity(configs *pb.All) (*l5dcharts.Values, error) { @@ -764,6 +784,7 @@ func (options *installOptions) buildValuesWithoutIdentity(configs *pb.All) (*l5d installValues.Grafana["image"].(map[string]interface{})["name"] = fmt.Sprintf("%s/grafana", options.dockerRegistry) installValues.Global.Namespace = controlPlaneNamespace installValues.Global.CNIEnabled = options.cniEnabled + installValues.Global.EnableEndpointSlices = options.enableEndpointSlices installValues.OmitWebhookSideEffects = options.omitWebhookSideEffects installValues.HeartbeatSchedule = options.heartbeatSchedule() installValues.RestrictDashboardPrivileges = options.restrictDashboardPrivileges @@ -922,6 +943,7 @@ func (options *installOptions) globalConfig(identity *pb.IdentityContext) *pb.Gl return &pb.Global{ LinkerdNamespace: controlPlaneNamespace, CniEnabled: options.cniEnabled, + EndpointSliceEnabled: options.enableEndpointSlices, Version: options.controlPlaneVersion, IdentityContext: identity, OmitWebhookSideEffects: options.omitWebhookSideEffects, diff --git a/cli/cmd/multicluster.go b/cli/cmd/multicluster.go index 0d88ef1f0c867..0f050005ec72f 100644 --- a/cli/cmd/multicluster.go +++ b/cli/cmd/multicluster.go @@ -87,7 +87,7 @@ type ( ) func newMulticlusterInstallOptionsWithDefault() (*multiclusterInstallOptions, error) { - defaults, err := mccharts.NewValues() + defaults, err := mccharts.NewInstallValues() if err != nil { return nil, err } @@ -106,7 +106,7 @@ func newMulticlusterInstallOptionsWithDefault() (*multiclusterInstallOptions, er } func newLinkOptionsWithDefault() (*linkOptions, error) { - defaults, err := mccharts.NewValues() + defaults, err := mccharts.NewLinkValues() if err != nil { return nil, err } @@ -152,7 +152,7 @@ func buildServiceMirrorValues(opts *linkOptions) (*multicluster.Values, error) { return nil, fmt.Errorf("--log-level must be one of: panic, fatal, error, warn, info, debug") } - defaults, err := mccharts.NewValues() + defaults, err := mccharts.NewLinkValues() if err != nil { return nil, err } @@ -185,7 +185,7 @@ func buildMulticlusterInstallValues(opts *multiclusterInstallOptions) (*multiclu return nil, errors.New("you need to setup the multicluster addons in a namespace different than the Linkerd one") } - defaults, err := mccharts.NewValues() + defaults, err := mccharts.NewInstallValues() if err != nil { return nil, err } @@ -225,7 +225,7 @@ func buildMulticlusterAllowValues(opts *allowOptions) (*mccharts.Values, error) return nil, errors.New("you need to setup the multicluster addons in a namespace different than the Linkerd one") } - defaults, err := mccharts.NewValues() + defaults, err := mccharts.NewInstallValues() if err != nil { return nil, err } diff --git a/cli/cmd/testdata/install_addon_config.golden b/cli/cmd/testdata/install_addon_config.golden index 8cab005064070..b3ab9c3063dee 100644 --- a/cli/cmd/testdata/install_addon_config.golden +++ b/cli/cmd/testdata/install_addon_config.golden @@ -141,9 +141,6 @@ rules: - apiGroups: ["split.smi-spec.io"] resources: ["trafficsplits"] verbs: ["list", "get", "watch"] -- apiGroups: ["discovery.k8s.io"] - resources: ["endpointslices"] - verbs: ["list", "get", "watch"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 diff --git a/cli/cmd/testdata/install_addon_control-plane.golden b/cli/cmd/testdata/install_addon_control-plane.golden index b9d924389b492..8ba490eb0bfa4 100644 --- a/cli/cmd/testdata/install_addon_control-plane.golden +++ b/cli/cmd/testdata/install_addon_control-plane.golden @@ -11,7 +11,7 @@ metadata: linkerd.io/created-by: linkerd/cli dev-undefined data: global: | - {"linkerdNamespace":"linkerd","cniEnabled":false,"version":"install-control-plane-version","identityContext":{"trustDomain":"cluster.local","trustAnchorsPem":"-----BEGIN CERTIFICATE-----\nMIIBYDCCAQegAwIBAgIBATAKBggqhkjOPQQDAjAYMRYwFAYDVQQDEw1jbHVzdGVy\nLmxvY2FsMB4XDTE5MDMwMzAxNTk1MloXDTI5MDIyODAyMDM1MlowGDEWMBQGA1UE\nAxMNY2x1c3Rlci5sb2NhbDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAChpAt0\nxtgO9qbVtEtDK80N6iCL2Htyf2kIv2m5QkJ1y0TFQi5hTVe3wtspJ8YpZF0pl364\n6TiYeXB8tOOhIACjQjBAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHSUEFjAUBggrBgEF\nBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNHADBE\nAiBQ/AAwF8kG8VOmRSUTPakSSa/N4mqK2HsZuhQXCmiZHwIgZEzI5DCkpU7w3SIv\nOLO4Zsk1XrGZHGsmyiEyvYF9lpY=\n-----END CERTIFICATE-----\n","issuanceLifetime":"86400s","clockSkewAllowance":"20s","scheme":"linkerd.io/tls"},"autoInjectContext":null,"omitWebhookSideEffects":false,"clusterDomain":"cluster.local"} + {"linkerdNamespace":"linkerd","cniEnabled":false,"version":"install-control-plane-version","identityContext":{"trustDomain":"cluster.local","trustAnchorsPem":"-----BEGIN CERTIFICATE-----\nMIIBYDCCAQegAwIBAgIBATAKBggqhkjOPQQDAjAYMRYwFAYDVQQDEw1jbHVzdGVy\nLmxvY2FsMB4XDTE5MDMwMzAxNTk1MloXDTI5MDIyODAyMDM1MlowGDEWMBQGA1UE\nAxMNY2x1c3Rlci5sb2NhbDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAChpAt0\nxtgO9qbVtEtDK80N6iCL2Htyf2kIv2m5QkJ1y0TFQi5hTVe3wtspJ8YpZF0pl364\n6TiYeXB8tOOhIACjQjBAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHSUEFjAUBggrBgEF\nBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNHADBE\nAiBQ/AAwF8kG8VOmRSUTPakSSa/N4mqK2HsZuhQXCmiZHwIgZEzI5DCkpU7w3SIv\nOLO4Zsk1XrGZHGsmyiEyvYF9lpY=\n-----END CERTIFICATE-----\n","issuanceLifetime":"86400s","clockSkewAllowance":"20s","scheme":"linkerd.io/tls"},"autoInjectContext":null,"omitWebhookSideEffects":false,"clusterDomain":"cluster.local","endpointSliceEnabled":false} 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":"install-proxy-version","proxyInitImageVersion":"v1.3.3","debugImage":{"imageName":"gcr.io/linkerd-io/debug","pullPolicy":"IfNotPresent"},"debugImageVersion":"install-debug-version","destinationGetNetworks":"10.0.0.0/8,172.16.0.0/12,192.168.0.0/16","logFormat":"plain"} install: | diff --git a/cli/cmd/testdata/install_config.golden b/cli/cmd/testdata/install_config.golden index de8c4b1566372..47661e50d6050 100644 --- a/cli/cmd/testdata/install_config.golden +++ b/cli/cmd/testdata/install_config.golden @@ -141,9 +141,6 @@ rules: - apiGroups: ["split.smi-spec.io"] resources: ["trafficsplits"] verbs: ["list", "get", "watch"] -- apiGroups: ["discovery.k8s.io"] - resources: ["endpointslices"] - verbs: ["list", "get", "watch"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 diff --git a/cli/cmd/testdata/install_control-plane.golden b/cli/cmd/testdata/install_control-plane.golden index 9d1a58d1be4f6..9690e9c068c9c 100644 --- a/cli/cmd/testdata/install_control-plane.golden +++ b/cli/cmd/testdata/install_control-plane.golden @@ -11,7 +11,7 @@ metadata: linkerd.io/created-by: linkerd/cli dev-undefined data: global: | - {"linkerdNamespace":"linkerd","cniEnabled":false,"version":"install-control-plane-version","identityContext":{"trustDomain":"cluster.local","trustAnchorsPem":"-----BEGIN CERTIFICATE-----\nMIIBYDCCAQegAwIBAgIBATAKBggqhkjOPQQDAjAYMRYwFAYDVQQDEw1jbHVzdGVy\nLmxvY2FsMB4XDTE5MDMwMzAxNTk1MloXDTI5MDIyODAyMDM1MlowGDEWMBQGA1UE\nAxMNY2x1c3Rlci5sb2NhbDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAChpAt0\nxtgO9qbVtEtDK80N6iCL2Htyf2kIv2m5QkJ1y0TFQi5hTVe3wtspJ8YpZF0pl364\n6TiYeXB8tOOhIACjQjBAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHSUEFjAUBggrBgEF\nBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNHADBE\nAiBQ/AAwF8kG8VOmRSUTPakSSa/N4mqK2HsZuhQXCmiZHwIgZEzI5DCkpU7w3SIv\nOLO4Zsk1XrGZHGsmyiEyvYF9lpY=\n-----END CERTIFICATE-----\n","issuanceLifetime":"86400s","clockSkewAllowance":"20s","scheme":"linkerd.io/tls"},"autoInjectContext":null,"omitWebhookSideEffects":false,"clusterDomain":"cluster.local"} + {"linkerdNamespace":"linkerd","cniEnabled":false,"version":"install-control-plane-version","identityContext":{"trustDomain":"cluster.local","trustAnchorsPem":"-----BEGIN CERTIFICATE-----\nMIIBYDCCAQegAwIBAgIBATAKBggqhkjOPQQDAjAYMRYwFAYDVQQDEw1jbHVzdGVy\nLmxvY2FsMB4XDTE5MDMwMzAxNTk1MloXDTI5MDIyODAyMDM1MlowGDEWMBQGA1UE\nAxMNY2x1c3Rlci5sb2NhbDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAChpAt0\nxtgO9qbVtEtDK80N6iCL2Htyf2kIv2m5QkJ1y0TFQi5hTVe3wtspJ8YpZF0pl364\n6TiYeXB8tOOhIACjQjBAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHSUEFjAUBggrBgEF\nBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNHADBE\nAiBQ/AAwF8kG8VOmRSUTPakSSa/N4mqK2HsZuhQXCmiZHwIgZEzI5DCkpU7w3SIv\nOLO4Zsk1XrGZHGsmyiEyvYF9lpY=\n-----END CERTIFICATE-----\n","issuanceLifetime":"86400s","clockSkewAllowance":"20s","scheme":"linkerd.io/tls"},"autoInjectContext":null,"omitWebhookSideEffects":false,"clusterDomain":"cluster.local","endpointSliceEnabled":false} 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":"install-proxy-version","proxyInitImageVersion":"v1.3.3","debugImage":{"imageName":"gcr.io/linkerd-io/debug","pullPolicy":"IfNotPresent"},"debugImageVersion":"install-debug-version","destinationGetNetworks":"10.0.0.0/8,172.16.0.0/12,192.168.0.0/16","logFormat":"plain"} install: | diff --git a/cli/cmd/testdata/install_controlplane_tracing_output.golden b/cli/cmd/testdata/install_controlplane_tracing_output.golden index 71f5624ac4152..ca539a06b0fe0 100644 --- a/cli/cmd/testdata/install_controlplane_tracing_output.golden +++ b/cli/cmd/testdata/install_controlplane_tracing_output.golden @@ -141,9 +141,6 @@ rules: - apiGroups: ["split.smi-spec.io"] resources: ["trafficsplits"] verbs: ["list", "get", "watch"] -- apiGroups: ["discovery.k8s.io"] - resources: ["endpointslices"] - verbs: ["list", "get", "watch"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 @@ -803,7 +800,7 @@ metadata: linkerd.io/created-by: linkerd/cli dev-undefined data: global: | - {"linkerdNamespace":"linkerd","cniEnabled":false,"version":"install-control-plane-version","identityContext":{"trustDomain":"cluster.local","trustAnchorsPem":"-----BEGIN CERTIFICATE-----\nMIIBYDCCAQegAwIBAgIBATAKBggqhkjOPQQDAjAYMRYwFAYDVQQDEw1jbHVzdGVy\nLmxvY2FsMB4XDTE5MDMwMzAxNTk1MloXDTI5MDIyODAyMDM1MlowGDEWMBQGA1UE\nAxMNY2x1c3Rlci5sb2NhbDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAChpAt0\nxtgO9qbVtEtDK80N6iCL2Htyf2kIv2m5QkJ1y0TFQi5hTVe3wtspJ8YpZF0pl364\n6TiYeXB8tOOhIACjQjBAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHSUEFjAUBggrBgEF\nBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNHADBE\nAiBQ/AAwF8kG8VOmRSUTPakSSa/N4mqK2HsZuhQXCmiZHwIgZEzI5DCkpU7w3SIv\nOLO4Zsk1XrGZHGsmyiEyvYF9lpY=\n-----END CERTIFICATE-----\n","issuanceLifetime":"86400s","clockSkewAllowance":"20s","scheme":"linkerd.io/tls"},"autoInjectContext":null,"omitWebhookSideEffects":false,"clusterDomain":"cluster.local"} + {"linkerdNamespace":"linkerd","cniEnabled":false,"version":"install-control-plane-version","identityContext":{"trustDomain":"cluster.local","trustAnchorsPem":"-----BEGIN CERTIFICATE-----\nMIIBYDCCAQegAwIBAgIBATAKBggqhkjOPQQDAjAYMRYwFAYDVQQDEw1jbHVzdGVy\nLmxvY2FsMB4XDTE5MDMwMzAxNTk1MloXDTI5MDIyODAyMDM1MlowGDEWMBQGA1UE\nAxMNY2x1c3Rlci5sb2NhbDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAChpAt0\nxtgO9qbVtEtDK80N6iCL2Htyf2kIv2m5QkJ1y0TFQi5hTVe3wtspJ8YpZF0pl364\n6TiYeXB8tOOhIACjQjBAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHSUEFjAUBggrBgEF\nBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNHADBE\nAiBQ/AAwF8kG8VOmRSUTPakSSa/N4mqK2HsZuhQXCmiZHwIgZEzI5DCkpU7w3SIv\nOLO4Zsk1XrGZHGsmyiEyvYF9lpY=\n-----END CERTIFICATE-----\n","issuanceLifetime":"86400s","clockSkewAllowance":"20s","scheme":"linkerd.io/tls"},"autoInjectContext":null,"omitWebhookSideEffects":false,"clusterDomain":"cluster.local","endpointSliceEnabled":false} 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":"install-proxy-version","proxyInitImageVersion":"v1.3.3","debugImage":{"imageName":"gcr.io/linkerd-io/debug","pullPolicy":"IfNotPresent"},"debugImageVersion":"install-debug-version","destinationGetNetworks":"10.0.0.0/8,172.16.0.0/12,192.168.0.0/16","logFormat":"plain"} install: | diff --git a/cli/cmd/testdata/install_custom_registry.golden b/cli/cmd/testdata/install_custom_registry.golden index c30bd495089a8..14e29e71fcc79 100644 --- a/cli/cmd/testdata/install_custom_registry.golden +++ b/cli/cmd/testdata/install_custom_registry.golden @@ -141,9 +141,6 @@ rules: - apiGroups: ["split.smi-spec.io"] resources: ["trafficsplits"] verbs: ["list", "get", "watch"] -- apiGroups: ["discovery.k8s.io"] - resources: ["endpointslices"] - verbs: ["list", "get", "watch"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 @@ -803,7 +800,7 @@ metadata: linkerd.io/created-by: linkerd/cli dev-undefined data: global: | - {"linkerdNamespace":"linkerd","cniEnabled":false,"version":"install-control-plane-version","identityContext":{"trustDomain":"cluster.local","trustAnchorsPem":"-----BEGIN CERTIFICATE-----\nMIIBYDCCAQegAwIBAgIBATAKBggqhkjOPQQDAjAYMRYwFAYDVQQDEw1jbHVzdGVy\nLmxvY2FsMB4XDTE5MDMwMzAxNTk1MloXDTI5MDIyODAyMDM1MlowGDEWMBQGA1UE\nAxMNY2x1c3Rlci5sb2NhbDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAChpAt0\nxtgO9qbVtEtDK80N6iCL2Htyf2kIv2m5QkJ1y0TFQi5hTVe3wtspJ8YpZF0pl364\n6TiYeXB8tOOhIACjQjBAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHSUEFjAUBggrBgEF\nBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNHADBE\nAiBQ/AAwF8kG8VOmRSUTPakSSa/N4mqK2HsZuhQXCmiZHwIgZEzI5DCkpU7w3SIv\nOLO4Zsk1XrGZHGsmyiEyvYF9lpY=\n-----END CERTIFICATE-----\n","issuanceLifetime":"86400s","clockSkewAllowance":"20s","scheme":"linkerd.io/tls"},"autoInjectContext":null,"omitWebhookSideEffects":false,"clusterDomain":"cluster.local"} + {"linkerdNamespace":"linkerd","cniEnabled":false,"version":"install-control-plane-version","identityContext":{"trustDomain":"cluster.local","trustAnchorsPem":"-----BEGIN CERTIFICATE-----\nMIIBYDCCAQegAwIBAgIBATAKBggqhkjOPQQDAjAYMRYwFAYDVQQDEw1jbHVzdGVy\nLmxvY2FsMB4XDTE5MDMwMzAxNTk1MloXDTI5MDIyODAyMDM1MlowGDEWMBQGA1UE\nAxMNY2x1c3Rlci5sb2NhbDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAChpAt0\nxtgO9qbVtEtDK80N6iCL2Htyf2kIv2m5QkJ1y0TFQi5hTVe3wtspJ8YpZF0pl364\n6TiYeXB8tOOhIACjQjBAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHSUEFjAUBggrBgEF\nBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNHADBE\nAiBQ/AAwF8kG8VOmRSUTPakSSa/N4mqK2HsZuhQXCmiZHwIgZEzI5DCkpU7w3SIv\nOLO4Zsk1XrGZHGsmyiEyvYF9lpY=\n-----END CERTIFICATE-----\n","issuanceLifetime":"86400s","clockSkewAllowance":"20s","scheme":"linkerd.io/tls"},"autoInjectContext":null,"omitWebhookSideEffects":false,"clusterDomain":"cluster.local","endpointSliceEnabled":false} proxy: | {"proxyImage":{"imageName":"my.custom.registry/linkerd-io/proxy","pullPolicy":"IfNotPresent"},"proxyInitImage":{"imageName":"my.custom.registry/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":"install-proxy-version","proxyInitImageVersion":"v1.3.3","debugImage":{"imageName":"my.custom.registry/linkerd-io/debug","pullPolicy":"IfNotPresent"},"debugImageVersion":"install-debug-version","destinationGetNetworks":"10.0.0.0/8,172.16.0.0/12,192.168.0.0/16","logFormat":"plain"} install: | diff --git a/cli/cmd/testdata/install_default.golden b/cli/cmd/testdata/install_default.golden index ccc43399d846f..f47ae77a3bb6c 100644 --- a/cli/cmd/testdata/install_default.golden +++ b/cli/cmd/testdata/install_default.golden @@ -141,9 +141,6 @@ rules: - apiGroups: ["split.smi-spec.io"] resources: ["trafficsplits"] verbs: ["list", "get", "watch"] -- apiGroups: ["discovery.k8s.io"] - resources: ["endpointslices"] - verbs: ["list", "get", "watch"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 @@ -803,7 +800,7 @@ metadata: linkerd.io/created-by: linkerd/cli dev-undefined data: global: | - {"linkerdNamespace":"linkerd","cniEnabled":false,"version":"install-control-plane-version","identityContext":{"trustDomain":"cluster.local","trustAnchorsPem":"-----BEGIN CERTIFICATE-----\nMIIBYDCCAQegAwIBAgIBATAKBggqhkjOPQQDAjAYMRYwFAYDVQQDEw1jbHVzdGVy\nLmxvY2FsMB4XDTE5MDMwMzAxNTk1MloXDTI5MDIyODAyMDM1MlowGDEWMBQGA1UE\nAxMNY2x1c3Rlci5sb2NhbDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAChpAt0\nxtgO9qbVtEtDK80N6iCL2Htyf2kIv2m5QkJ1y0TFQi5hTVe3wtspJ8YpZF0pl364\n6TiYeXB8tOOhIACjQjBAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHSUEFjAUBggrBgEF\nBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNHADBE\nAiBQ/AAwF8kG8VOmRSUTPakSSa/N4mqK2HsZuhQXCmiZHwIgZEzI5DCkpU7w3SIv\nOLO4Zsk1XrGZHGsmyiEyvYF9lpY=\n-----END CERTIFICATE-----\n","issuanceLifetime":"86400s","clockSkewAllowance":"20s","scheme":"linkerd.io/tls"},"autoInjectContext":null,"omitWebhookSideEffects":false,"clusterDomain":"cluster.local"} + {"linkerdNamespace":"linkerd","cniEnabled":false,"version":"install-control-plane-version","identityContext":{"trustDomain":"cluster.local","trustAnchorsPem":"-----BEGIN CERTIFICATE-----\nMIIBYDCCAQegAwIBAgIBATAKBggqhkjOPQQDAjAYMRYwFAYDVQQDEw1jbHVzdGVy\nLmxvY2FsMB4XDTE5MDMwMzAxNTk1MloXDTI5MDIyODAyMDM1MlowGDEWMBQGA1UE\nAxMNY2x1c3Rlci5sb2NhbDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAChpAt0\nxtgO9qbVtEtDK80N6iCL2Htyf2kIv2m5QkJ1y0TFQi5hTVe3wtspJ8YpZF0pl364\n6TiYeXB8tOOhIACjQjBAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHSUEFjAUBggrBgEF\nBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNHADBE\nAiBQ/AAwF8kG8VOmRSUTPakSSa/N4mqK2HsZuhQXCmiZHwIgZEzI5DCkpU7w3SIv\nOLO4Zsk1XrGZHGsmyiEyvYF9lpY=\n-----END CERTIFICATE-----\n","issuanceLifetime":"86400s","clockSkewAllowance":"20s","scheme":"linkerd.io/tls"},"autoInjectContext":null,"omitWebhookSideEffects":false,"clusterDomain":"cluster.local","endpointSliceEnabled":false} 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":"install-proxy-version","proxyInitImageVersion":"v1.3.3","debugImage":{"imageName":"gcr.io/linkerd-io/debug","pullPolicy":"IfNotPresent"},"debugImageVersion":"install-debug-version","destinationGetNetworks":"10.0.0.0/8,172.16.0.0/12,192.168.0.0/16","logFormat":"plain"} install: | 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 c0b4b05636fc9..03ece3929ed45 100644 --- a/cli/cmd/testdata/install_default_override_dst_get_nets.golden +++ b/cli/cmd/testdata/install_default_override_dst_get_nets.golden @@ -141,9 +141,6 @@ rules: - apiGroups: ["split.smi-spec.io"] resources: ["trafficsplits"] verbs: ["list", "get", "watch"] -- apiGroups: ["discovery.k8s.io"] - resources: ["endpointslices"] - verbs: ["list", "get", "watch"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 @@ -803,7 +800,7 @@ metadata: linkerd.io/created-by: linkerd/cli dev-undefined data: global: | - {"linkerdNamespace":"linkerd","cniEnabled":false,"version":"install-control-plane-version","identityContext":{"trustDomain":"cluster.local","trustAnchorsPem":"-----BEGIN CERTIFICATE-----\nMIIBYDCCAQegAwIBAgIBATAKBggqhkjOPQQDAjAYMRYwFAYDVQQDEw1jbHVzdGVy\nLmxvY2FsMB4XDTE5MDMwMzAxNTk1MloXDTI5MDIyODAyMDM1MlowGDEWMBQGA1UE\nAxMNY2x1c3Rlci5sb2NhbDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAChpAt0\nxtgO9qbVtEtDK80N6iCL2Htyf2kIv2m5QkJ1y0TFQi5hTVe3wtspJ8YpZF0pl364\n6TiYeXB8tOOhIACjQjBAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHSUEFjAUBggrBgEF\nBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNHADBE\nAiBQ/AAwF8kG8VOmRSUTPakSSa/N4mqK2HsZuhQXCmiZHwIgZEzI5DCkpU7w3SIv\nOLO4Zsk1XrGZHGsmyiEyvYF9lpY=\n-----END CERTIFICATE-----\n","issuanceLifetime":"86400s","clockSkewAllowance":"20s","scheme":"linkerd.io/tls"},"autoInjectContext":null,"omitWebhookSideEffects":false,"clusterDomain":"cluster.local"} + {"linkerdNamespace":"linkerd","cniEnabled":false,"version":"install-control-plane-version","identityContext":{"trustDomain":"cluster.local","trustAnchorsPem":"-----BEGIN CERTIFICATE-----\nMIIBYDCCAQegAwIBAgIBATAKBggqhkjOPQQDAjAYMRYwFAYDVQQDEw1jbHVzdGVy\nLmxvY2FsMB4XDTE5MDMwMzAxNTk1MloXDTI5MDIyODAyMDM1MlowGDEWMBQGA1UE\nAxMNY2x1c3Rlci5sb2NhbDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAChpAt0\nxtgO9qbVtEtDK80N6iCL2Htyf2kIv2m5QkJ1y0TFQi5hTVe3wtspJ8YpZF0pl364\n6TiYeXB8tOOhIACjQjBAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHSUEFjAUBggrBgEF\nBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNHADBE\nAiBQ/AAwF8kG8VOmRSUTPakSSa/N4mqK2HsZuhQXCmiZHwIgZEzI5DCkpU7w3SIv\nOLO4Zsk1XrGZHGsmyiEyvYF9lpY=\n-----END CERTIFICATE-----\n","issuanceLifetime":"86400s","clockSkewAllowance":"20s","scheme":"linkerd.io/tls"},"autoInjectContext":null,"omitWebhookSideEffects":false,"clusterDomain":"cluster.local","endpointSliceEnabled":false} 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":"install-proxy-version","proxyInitImageVersion":"v1.3.3","debugImage":{"imageName":"gcr.io/linkerd-io/debug","pullPolicy":"IfNotPresent"},"debugImageVersion":"install-debug-version","destinationGetNetworks":"10.0.0.0/8,172.0.0.0/8","logFormat":"plain"} install: | diff --git a/cli/cmd/testdata/install_grafana_existing.golden b/cli/cmd/testdata/install_grafana_existing.golden index e670004a528c4..578ec6d8ad52f 100644 --- a/cli/cmd/testdata/install_grafana_existing.golden +++ b/cli/cmd/testdata/install_grafana_existing.golden @@ -141,9 +141,6 @@ rules: - apiGroups: ["split.smi-spec.io"] resources: ["trafficsplits"] verbs: ["list", "get", "watch"] -- apiGroups: ["discovery.k8s.io"] - resources: ["endpointslices"] - verbs: ["list", "get", "watch"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 @@ -800,7 +797,7 @@ metadata: linkerd.io/created-by: linkerd/cli dev-undefined data: global: | - {"linkerdNamespace":"linkerd","cniEnabled":false,"version":"install-control-plane-version","identityContext":{"trustDomain":"cluster.local","trustAnchorsPem":"-----BEGIN CERTIFICATE-----\nMIIBYDCCAQegAwIBAgIBATAKBggqhkjOPQQDAjAYMRYwFAYDVQQDEw1jbHVzdGVy\nLmxvY2FsMB4XDTE5MDMwMzAxNTk1MloXDTI5MDIyODAyMDM1MlowGDEWMBQGA1UE\nAxMNY2x1c3Rlci5sb2NhbDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAChpAt0\nxtgO9qbVtEtDK80N6iCL2Htyf2kIv2m5QkJ1y0TFQi5hTVe3wtspJ8YpZF0pl364\n6TiYeXB8tOOhIACjQjBAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHSUEFjAUBggrBgEF\nBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNHADBE\nAiBQ/AAwF8kG8VOmRSUTPakSSa/N4mqK2HsZuhQXCmiZHwIgZEzI5DCkpU7w3SIv\nOLO4Zsk1XrGZHGsmyiEyvYF9lpY=\n-----END CERTIFICATE-----\n","issuanceLifetime":"86400s","clockSkewAllowance":"20s","scheme":"linkerd.io/tls"},"autoInjectContext":null,"omitWebhookSideEffects":false,"clusterDomain":"cluster.local"} + {"linkerdNamespace":"linkerd","cniEnabled":false,"version":"install-control-plane-version","identityContext":{"trustDomain":"cluster.local","trustAnchorsPem":"-----BEGIN CERTIFICATE-----\nMIIBYDCCAQegAwIBAgIBATAKBggqhkjOPQQDAjAYMRYwFAYDVQQDEw1jbHVzdGVy\nLmxvY2FsMB4XDTE5MDMwMzAxNTk1MloXDTI5MDIyODAyMDM1MlowGDEWMBQGA1UE\nAxMNY2x1c3Rlci5sb2NhbDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAChpAt0\nxtgO9qbVtEtDK80N6iCL2Htyf2kIv2m5QkJ1y0TFQi5hTVe3wtspJ8YpZF0pl364\n6TiYeXB8tOOhIACjQjBAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHSUEFjAUBggrBgEF\nBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNHADBE\nAiBQ/AAwF8kG8VOmRSUTPakSSa/N4mqK2HsZuhQXCmiZHwIgZEzI5DCkpU7w3SIv\nOLO4Zsk1XrGZHGsmyiEyvYF9lpY=\n-----END CERTIFICATE-----\n","issuanceLifetime":"86400s","clockSkewAllowance":"20s","scheme":"linkerd.io/tls"},"autoInjectContext":null,"omitWebhookSideEffects":false,"clusterDomain":"cluster.local","endpointSliceEnabled":false} 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":"install-proxy-version","proxyInitImageVersion":"v1.3.3","debugImage":{"imageName":"gcr.io/linkerd-io/debug","pullPolicy":"IfNotPresent"},"debugImageVersion":"install-debug-version","destinationGetNetworks":"10.0.0.0/8,172.16.0.0/12,192.168.0.0/16","logFormat":"plain"} install: | diff --git a/cli/cmd/testdata/install_ha_output.golden b/cli/cmd/testdata/install_ha_output.golden index 47dbde63add54..3e3f3c96a2e66 100644 --- a/cli/cmd/testdata/install_ha_output.golden +++ b/cli/cmd/testdata/install_ha_output.golden @@ -141,9 +141,6 @@ rules: - apiGroups: ["split.smi-spec.io"] resources: ["trafficsplits"] verbs: ["list", "get", "watch"] -- apiGroups: ["discovery.k8s.io"] - resources: ["endpointslices"] - verbs: ["list", "get", "watch"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 @@ -803,7 +800,7 @@ metadata: linkerd.io/created-by: linkerd/cli dev-undefined data: global: | - {"linkerdNamespace":"linkerd","cniEnabled":false,"version":"install-control-plane-version","identityContext":{"trustDomain":"cluster.local","trustAnchorsPem":"-----BEGIN CERTIFICATE-----\nMIIBYDCCAQegAwIBAgIBATAKBggqhkjOPQQDAjAYMRYwFAYDVQQDEw1jbHVzdGVy\nLmxvY2FsMB4XDTE5MDMwMzAxNTk1MloXDTI5MDIyODAyMDM1MlowGDEWMBQGA1UE\nAxMNY2x1c3Rlci5sb2NhbDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAChpAt0\nxtgO9qbVtEtDK80N6iCL2Htyf2kIv2m5QkJ1y0TFQi5hTVe3wtspJ8YpZF0pl364\n6TiYeXB8tOOhIACjQjBAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHSUEFjAUBggrBgEF\nBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNHADBE\nAiBQ/AAwF8kG8VOmRSUTPakSSa/N4mqK2HsZuhQXCmiZHwIgZEzI5DCkpU7w3SIv\nOLO4Zsk1XrGZHGsmyiEyvYF9lpY=\n-----END CERTIFICATE-----\n","issuanceLifetime":"86400s","clockSkewAllowance":"20s","scheme":"linkerd.io/tls"},"autoInjectContext":null,"omitWebhookSideEffects":false,"clusterDomain":"cluster.local"} + {"linkerdNamespace":"linkerd","cniEnabled":false,"version":"install-control-plane-version","identityContext":{"trustDomain":"cluster.local","trustAnchorsPem":"-----BEGIN CERTIFICATE-----\nMIIBYDCCAQegAwIBAgIBATAKBggqhkjOPQQDAjAYMRYwFAYDVQQDEw1jbHVzdGVy\nLmxvY2FsMB4XDTE5MDMwMzAxNTk1MloXDTI5MDIyODAyMDM1MlowGDEWMBQGA1UE\nAxMNY2x1c3Rlci5sb2NhbDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAChpAt0\nxtgO9qbVtEtDK80N6iCL2Htyf2kIv2m5QkJ1y0TFQi5hTVe3wtspJ8YpZF0pl364\n6TiYeXB8tOOhIACjQjBAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHSUEFjAUBggrBgEF\nBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNHADBE\nAiBQ/AAwF8kG8VOmRSUTPakSSa/N4mqK2HsZuhQXCmiZHwIgZEzI5DCkpU7w3SIv\nOLO4Zsk1XrGZHGsmyiEyvYF9lpY=\n-----END CERTIFICATE-----\n","issuanceLifetime":"86400s","clockSkewAllowance":"20s","scheme":"linkerd.io/tls"},"autoInjectContext":null,"omitWebhookSideEffects":false,"clusterDomain":"cluster.local","endpointSliceEnabled":false} 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":"100m","requestMemory":"20Mi","limitCpu":"1","limitMemory":"250Mi"},"proxyUid":"2102","logLevel":{"level":"warn,linkerd=info"},"disableExternalProfiles":true,"proxyVersion":"install-proxy-version","proxyInitImageVersion":"v1.3.3","debugImage":{"imageName":"gcr.io/linkerd-io/debug","pullPolicy":"IfNotPresent"},"debugImageVersion":"install-debug-version","destinationGetNetworks":"10.0.0.0/8,172.16.0.0/12,192.168.0.0/16","logFormat":"plain"} install: | diff --git a/cli/cmd/testdata/install_ha_with_overrides_output.golden b/cli/cmd/testdata/install_ha_with_overrides_output.golden index 5e776a4aa27d3..5b9867d861e28 100644 --- a/cli/cmd/testdata/install_ha_with_overrides_output.golden +++ b/cli/cmd/testdata/install_ha_with_overrides_output.golden @@ -141,9 +141,6 @@ rules: - apiGroups: ["split.smi-spec.io"] resources: ["trafficsplits"] verbs: ["list", "get", "watch"] -- apiGroups: ["discovery.k8s.io"] - resources: ["endpointslices"] - verbs: ["list", "get", "watch"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 @@ -803,7 +800,7 @@ metadata: linkerd.io/created-by: linkerd/cli dev-undefined data: global: | - {"linkerdNamespace":"linkerd","cniEnabled":false,"version":"install-control-plane-version","identityContext":{"trustDomain":"cluster.local","trustAnchorsPem":"-----BEGIN CERTIFICATE-----\nMIIBYDCCAQegAwIBAgIBATAKBggqhkjOPQQDAjAYMRYwFAYDVQQDEw1jbHVzdGVy\nLmxvY2FsMB4XDTE5MDMwMzAxNTk1MloXDTI5MDIyODAyMDM1MlowGDEWMBQGA1UE\nAxMNY2x1c3Rlci5sb2NhbDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAChpAt0\nxtgO9qbVtEtDK80N6iCL2Htyf2kIv2m5QkJ1y0TFQi5hTVe3wtspJ8YpZF0pl364\n6TiYeXB8tOOhIACjQjBAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHSUEFjAUBggrBgEF\nBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNHADBE\nAiBQ/AAwF8kG8VOmRSUTPakSSa/N4mqK2HsZuhQXCmiZHwIgZEzI5DCkpU7w3SIv\nOLO4Zsk1XrGZHGsmyiEyvYF9lpY=\n-----END CERTIFICATE-----\n","issuanceLifetime":"86400s","clockSkewAllowance":"20s","scheme":"linkerd.io/tls"},"autoInjectContext":null,"omitWebhookSideEffects":false,"clusterDomain":"cluster.local"} + {"linkerdNamespace":"linkerd","cniEnabled":false,"version":"install-control-plane-version","identityContext":{"trustDomain":"cluster.local","trustAnchorsPem":"-----BEGIN CERTIFICATE-----\nMIIBYDCCAQegAwIBAgIBATAKBggqhkjOPQQDAjAYMRYwFAYDVQQDEw1jbHVzdGVy\nLmxvY2FsMB4XDTE5MDMwMzAxNTk1MloXDTI5MDIyODAyMDM1MlowGDEWMBQGA1UE\nAxMNY2x1c3Rlci5sb2NhbDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAChpAt0\nxtgO9qbVtEtDK80N6iCL2Htyf2kIv2m5QkJ1y0TFQi5hTVe3wtspJ8YpZF0pl364\n6TiYeXB8tOOhIACjQjBAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHSUEFjAUBggrBgEF\nBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNHADBE\nAiBQ/AAwF8kG8VOmRSUTPakSSa/N4mqK2HsZuhQXCmiZHwIgZEzI5DCkpU7w3SIv\nOLO4Zsk1XrGZHGsmyiEyvYF9lpY=\n-----END CERTIFICATE-----\n","issuanceLifetime":"86400s","clockSkewAllowance":"20s","scheme":"linkerd.io/tls"},"autoInjectContext":null,"omitWebhookSideEffects":false,"clusterDomain":"cluster.local","endpointSliceEnabled":false} 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":"400m","requestMemory":"300Mi","limitCpu":"1","limitMemory":"250Mi"},"proxyUid":"2102","logLevel":{"level":"warn,linkerd=info"},"disableExternalProfiles":true,"proxyVersion":"install-proxy-version","proxyInitImageVersion":"v1.3.3","debugImage":{"imageName":"gcr.io/linkerd-io/debug","pullPolicy":"IfNotPresent"},"debugImageVersion":"install-debug-version","destinationGetNetworks":"10.0.0.0/8,172.16.0.0/12,192.168.0.0/16","logFormat":"plain"} install: | diff --git a/cli/cmd/testdata/install_heartbeat_disabled_output.golden b/cli/cmd/testdata/install_heartbeat_disabled_output.golden index 52b8d33dd080d..04933fda82e59 100644 --- a/cli/cmd/testdata/install_heartbeat_disabled_output.golden +++ b/cli/cmd/testdata/install_heartbeat_disabled_output.golden @@ -141,9 +141,6 @@ rules: - apiGroups: ["split.smi-spec.io"] resources: ["trafficsplits"] verbs: ["list", "get", "watch"] -- apiGroups: ["discovery.k8s.io"] - resources: ["endpointslices"] - verbs: ["list", "get", "watch"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 @@ -759,7 +756,7 @@ metadata: linkerd.io/created-by: linkerd/cli dev-undefined data: global: | - {"linkerdNamespace":"linkerd","cniEnabled":false,"version":"install-control-plane-version","identityContext":{"trustDomain":"cluster.local","trustAnchorsPem":"-----BEGIN CERTIFICATE-----\nMIIBYDCCAQegAwIBAgIBATAKBggqhkjOPQQDAjAYMRYwFAYDVQQDEw1jbHVzdGVy\nLmxvY2FsMB4XDTE5MDMwMzAxNTk1MloXDTI5MDIyODAyMDM1MlowGDEWMBQGA1UE\nAxMNY2x1c3Rlci5sb2NhbDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAChpAt0\nxtgO9qbVtEtDK80N6iCL2Htyf2kIv2m5QkJ1y0TFQi5hTVe3wtspJ8YpZF0pl364\n6TiYeXB8tOOhIACjQjBAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHSUEFjAUBggrBgEF\nBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNHADBE\nAiBQ/AAwF8kG8VOmRSUTPakSSa/N4mqK2HsZuhQXCmiZHwIgZEzI5DCkpU7w3SIv\nOLO4Zsk1XrGZHGsmyiEyvYF9lpY=\n-----END CERTIFICATE-----\n","issuanceLifetime":"86400s","clockSkewAllowance":"20s","scheme":"linkerd.io/tls"},"autoInjectContext":null,"omitWebhookSideEffects":false,"clusterDomain":"cluster.local"} + {"linkerdNamespace":"linkerd","cniEnabled":false,"version":"install-control-plane-version","identityContext":{"trustDomain":"cluster.local","trustAnchorsPem":"-----BEGIN CERTIFICATE-----\nMIIBYDCCAQegAwIBAgIBATAKBggqhkjOPQQDAjAYMRYwFAYDVQQDEw1jbHVzdGVy\nLmxvY2FsMB4XDTE5MDMwMzAxNTk1MloXDTI5MDIyODAyMDM1MlowGDEWMBQGA1UE\nAxMNY2x1c3Rlci5sb2NhbDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAChpAt0\nxtgO9qbVtEtDK80N6iCL2Htyf2kIv2m5QkJ1y0TFQi5hTVe3wtspJ8YpZF0pl364\n6TiYeXB8tOOhIACjQjBAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHSUEFjAUBggrBgEF\nBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNHADBE\nAiBQ/AAwF8kG8VOmRSUTPakSSa/N4mqK2HsZuhQXCmiZHwIgZEzI5DCkpU7w3SIv\nOLO4Zsk1XrGZHGsmyiEyvYF9lpY=\n-----END CERTIFICATE-----\n","issuanceLifetime":"86400s","clockSkewAllowance":"20s","scheme":"linkerd.io/tls"},"autoInjectContext":null,"omitWebhookSideEffects":false,"clusterDomain":"cluster.local","endpointSliceEnabled":false} 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":"install-proxy-version","proxyInitImageVersion":"v1.3.3","debugImage":{"imageName":"gcr.io/linkerd-io/debug","pullPolicy":"IfNotPresent"},"debugImageVersion":"install-debug-version","destinationGetNetworks":"10.0.0.0/8,172.16.0.0/12,192.168.0.0/16","logFormat":"plain"} install: | diff --git a/cli/cmd/testdata/install_helm_output.golden b/cli/cmd/testdata/install_helm_output.golden index 0dd74f0ec393d..5b0d3ebff31a1 100644 --- a/cli/cmd/testdata/install_helm_output.golden +++ b/cli/cmd/testdata/install_helm_output.golden @@ -149,9 +149,6 @@ rules: - apiGroups: ["split.smi-spec.io"] resources: ["trafficsplits"] verbs: ["list", "get", "watch"] -- apiGroups: ["discovery.k8s.io"] - resources: ["endpointslices"] - verbs: ["list", "get", "watch"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 @@ -844,7 +841,8 @@ data: }, "autoInjectContext": null, "omitWebhookSideEffects": false, - "clusterDomain": "cluster.local" + "clusterDomain": "cluster.local", + "enableEndpointSlices": "false" } proxy: | { diff --git a/cli/cmd/testdata/install_helm_output_addons.golden b/cli/cmd/testdata/install_helm_output_addons.golden index 2aa4555e5c5d6..ddd423e68c818 100644 --- a/cli/cmd/testdata/install_helm_output_addons.golden +++ b/cli/cmd/testdata/install_helm_output_addons.golden @@ -149,9 +149,6 @@ rules: - apiGroups: ["split.smi-spec.io"] resources: ["trafficsplits"] verbs: ["list", "get", "watch"] -- apiGroups: ["discovery.k8s.io"] - resources: ["endpointslices"] - verbs: ["list", "get", "watch"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 @@ -844,7 +841,8 @@ data: }, "autoInjectContext": null, "omitWebhookSideEffects": false, - "clusterDomain": "cluster.local" + "clusterDomain": "cluster.local", + "enableEndpointSlices": "false" } proxy: | { diff --git a/cli/cmd/testdata/install_helm_output_ha.golden b/cli/cmd/testdata/install_helm_output_ha.golden index 5b6c31b715fba..87ea2011c2dd1 100644 --- a/cli/cmd/testdata/install_helm_output_ha.golden +++ b/cli/cmd/testdata/install_helm_output_ha.golden @@ -149,9 +149,6 @@ rules: - apiGroups: ["split.smi-spec.io"] resources: ["trafficsplits"] verbs: ["list", "get", "watch"] -- apiGroups: ["discovery.k8s.io"] - resources: ["endpointslices"] - verbs: ["list", "get", "watch"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 @@ -844,7 +841,8 @@ data: }, "autoInjectContext": null, "omitWebhookSideEffects": false, - "clusterDomain": "cluster.local" + "clusterDomain": "cluster.local", + "enableEndpointSlices": "false" } proxy: | { diff --git a/cli/cmd/testdata/install_no_init_container.golden b/cli/cmd/testdata/install_no_init_container.golden index dcad55129f6db..7b87994c2585f 100644 --- a/cli/cmd/testdata/install_no_init_container.golden +++ b/cli/cmd/testdata/install_no_init_container.golden @@ -141,9 +141,6 @@ rules: - apiGroups: ["split.smi-spec.io"] resources: ["trafficsplits"] verbs: ["list", "get", "watch"] -- apiGroups: ["discovery.k8s.io"] - resources: ["endpointslices"] - verbs: ["list", "get", "watch"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 @@ -800,7 +797,7 @@ metadata: linkerd.io/created-by: linkerd/cli dev-undefined data: global: | - {"linkerdNamespace":"linkerd","cniEnabled":true,"version":"install-control-plane-version","identityContext":{"trustDomain":"cluster.local","trustAnchorsPem":"-----BEGIN CERTIFICATE-----\nMIIBYDCCAQegAwIBAgIBATAKBggqhkjOPQQDAjAYMRYwFAYDVQQDEw1jbHVzdGVy\nLmxvY2FsMB4XDTE5MDMwMzAxNTk1MloXDTI5MDIyODAyMDM1MlowGDEWMBQGA1UE\nAxMNY2x1c3Rlci5sb2NhbDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAChpAt0\nxtgO9qbVtEtDK80N6iCL2Htyf2kIv2m5QkJ1y0TFQi5hTVe3wtspJ8YpZF0pl364\n6TiYeXB8tOOhIACjQjBAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHSUEFjAUBggrBgEF\nBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNHADBE\nAiBQ/AAwF8kG8VOmRSUTPakSSa/N4mqK2HsZuhQXCmiZHwIgZEzI5DCkpU7w3SIv\nOLO4Zsk1XrGZHGsmyiEyvYF9lpY=\n-----END CERTIFICATE-----\n","issuanceLifetime":"86400s","clockSkewAllowance":"20s","scheme":"linkerd.io/tls"},"autoInjectContext":null,"omitWebhookSideEffects":false,"clusterDomain":"cluster.local"} + {"linkerdNamespace":"linkerd","cniEnabled":true,"version":"install-control-plane-version","identityContext":{"trustDomain":"cluster.local","trustAnchorsPem":"-----BEGIN CERTIFICATE-----\nMIIBYDCCAQegAwIBAgIBATAKBggqhkjOPQQDAjAYMRYwFAYDVQQDEw1jbHVzdGVy\nLmxvY2FsMB4XDTE5MDMwMzAxNTk1MloXDTI5MDIyODAyMDM1MlowGDEWMBQGA1UE\nAxMNY2x1c3Rlci5sb2NhbDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAChpAt0\nxtgO9qbVtEtDK80N6iCL2Htyf2kIv2m5QkJ1y0TFQi5hTVe3wtspJ8YpZF0pl364\n6TiYeXB8tOOhIACjQjBAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHSUEFjAUBggrBgEF\nBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNHADBE\nAiBQ/AAwF8kG8VOmRSUTPakSSa/N4mqK2HsZuhQXCmiZHwIgZEzI5DCkpU7w3SIv\nOLO4Zsk1XrGZHGsmyiEyvYF9lpY=\n-----END CERTIFICATE-----\n","issuanceLifetime":"86400s","clockSkewAllowance":"20s","scheme":"linkerd.io/tls"},"autoInjectContext":null,"omitWebhookSideEffects":false,"clusterDomain":"cluster.local","endpointSliceEnabled":false} 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":"install-proxy-version","proxyInitImageVersion":"v1.3.3","debugImage":{"imageName":"gcr.io/linkerd-io/debug","pullPolicy":"IfNotPresent"},"debugImageVersion":"install-debug-version","destinationGetNetworks":"10.0.0.0/8,172.16.0.0/12,192.168.0.0/16","logFormat":"plain"} install: | diff --git a/cli/cmd/testdata/install_output.golden b/cli/cmd/testdata/install_output.golden index 9aea2f39040fd..032c6dad05a74 100644 --- a/cli/cmd/testdata/install_output.golden +++ b/cli/cmd/testdata/install_output.golden @@ -141,9 +141,6 @@ rules: - apiGroups: ["split.smi-spec.io"] resources: ["trafficsplits"] verbs: ["list", "get", "watch"] -- apiGroups: ["discovery.k8s.io"] - resources: ["endpointslices"] - verbs: ["list", "get", "watch"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 diff --git a/cli/cmd/testdata/install_prometheus_overwrite.golden b/cli/cmd/testdata/install_prometheus_overwrite.golden index 1bea2dc660776..9df65565dd218 100644 --- a/cli/cmd/testdata/install_prometheus_overwrite.golden +++ b/cli/cmd/testdata/install_prometheus_overwrite.golden @@ -141,9 +141,6 @@ rules: - apiGroups: ["split.smi-spec.io"] resources: ["trafficsplits"] verbs: ["list", "get", "watch"] -- apiGroups: ["discovery.k8s.io"] - resources: ["endpointslices"] - verbs: ["list", "get", "watch"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 @@ -803,7 +800,7 @@ metadata: linkerd.io/created-by: linkerd/cli dev-undefined data: global: | - {"linkerdNamespace":"linkerd","cniEnabled":false,"version":"install-control-plane-version","identityContext":{"trustDomain":"cluster.local","trustAnchorsPem":"-----BEGIN CERTIFICATE-----\nMIIBYDCCAQegAwIBAgIBATAKBggqhkjOPQQDAjAYMRYwFAYDVQQDEw1jbHVzdGVy\nLmxvY2FsMB4XDTE5MDMwMzAxNTk1MloXDTI5MDIyODAyMDM1MlowGDEWMBQGA1UE\nAxMNY2x1c3Rlci5sb2NhbDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAChpAt0\nxtgO9qbVtEtDK80N6iCL2Htyf2kIv2m5QkJ1y0TFQi5hTVe3wtspJ8YpZF0pl364\n6TiYeXB8tOOhIACjQjBAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHSUEFjAUBggrBgEF\nBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNHADBE\nAiBQ/AAwF8kG8VOmRSUTPakSSa/N4mqK2HsZuhQXCmiZHwIgZEzI5DCkpU7w3SIv\nOLO4Zsk1XrGZHGsmyiEyvYF9lpY=\n-----END CERTIFICATE-----\n","issuanceLifetime":"86400s","clockSkewAllowance":"20s","scheme":"linkerd.io/tls"},"autoInjectContext":null,"omitWebhookSideEffects":false,"clusterDomain":"cluster.local"} + {"linkerdNamespace":"linkerd","cniEnabled":false,"version":"install-control-plane-version","identityContext":{"trustDomain":"cluster.local","trustAnchorsPem":"-----BEGIN CERTIFICATE-----\nMIIBYDCCAQegAwIBAgIBATAKBggqhkjOPQQDAjAYMRYwFAYDVQQDEw1jbHVzdGVy\nLmxvY2FsMB4XDTE5MDMwMzAxNTk1MloXDTI5MDIyODAyMDM1MlowGDEWMBQGA1UE\nAxMNY2x1c3Rlci5sb2NhbDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAChpAt0\nxtgO9qbVtEtDK80N6iCL2Htyf2kIv2m5QkJ1y0TFQi5hTVe3wtspJ8YpZF0pl364\n6TiYeXB8tOOhIACjQjBAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHSUEFjAUBggrBgEF\nBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNHADBE\nAiBQ/AAwF8kG8VOmRSUTPakSSa/N4mqK2HsZuhQXCmiZHwIgZEzI5DCkpU7w3SIv\nOLO4Zsk1XrGZHGsmyiEyvYF9lpY=\n-----END CERTIFICATE-----\n","issuanceLifetime":"86400s","clockSkewAllowance":"20s","scheme":"linkerd.io/tls"},"autoInjectContext":null,"omitWebhookSideEffects":false,"clusterDomain":"cluster.local","endpointSliceEnabled":false} 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":"install-proxy-version","proxyInitImageVersion":"v1.3.3","debugImage":{"imageName":"gcr.io/linkerd-io/debug","pullPolicy":"IfNotPresent"},"debugImageVersion":"install-debug-version","destinationGetNetworks":"10.0.0.0/8,172.16.0.0/12,192.168.0.0/16","logFormat":"plain"} install: | diff --git a/cli/cmd/testdata/install_proxy_ignores.golden b/cli/cmd/testdata/install_proxy_ignores.golden index 9630c809fb31a..779ef902524dc 100644 --- a/cli/cmd/testdata/install_proxy_ignores.golden +++ b/cli/cmd/testdata/install_proxy_ignores.golden @@ -141,9 +141,6 @@ rules: - apiGroups: ["split.smi-spec.io"] resources: ["trafficsplits"] verbs: ["list", "get", "watch"] -- apiGroups: ["discovery.k8s.io"] - resources: ["endpointslices"] - verbs: ["list", "get", "watch"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 @@ -803,7 +800,7 @@ metadata: linkerd.io/created-by: linkerd/cli dev-undefined data: global: | - {"linkerdNamespace":"linkerd","cniEnabled":false,"version":"install-control-plane-version","identityContext":{"trustDomain":"cluster.local","trustAnchorsPem":"-----BEGIN CERTIFICATE-----\nMIIBYDCCAQegAwIBAgIBATAKBggqhkjOPQQDAjAYMRYwFAYDVQQDEw1jbHVzdGVy\nLmxvY2FsMB4XDTE5MDMwMzAxNTk1MloXDTI5MDIyODAyMDM1MlowGDEWMBQGA1UE\nAxMNY2x1c3Rlci5sb2NhbDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAChpAt0\nxtgO9qbVtEtDK80N6iCL2Htyf2kIv2m5QkJ1y0TFQi5hTVe3wtspJ8YpZF0pl364\n6TiYeXB8tOOhIACjQjBAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHSUEFjAUBggrBgEF\nBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNHADBE\nAiBQ/AAwF8kG8VOmRSUTPakSSa/N4mqK2HsZuhQXCmiZHwIgZEzI5DCkpU7w3SIv\nOLO4Zsk1XrGZHGsmyiEyvYF9lpY=\n-----END CERTIFICATE-----\n","issuanceLifetime":"86400s","clockSkewAllowance":"20s","scheme":"linkerd.io/tls"},"autoInjectContext":null,"omitWebhookSideEffects":false,"clusterDomain":"cluster.local"} + {"linkerdNamespace":"linkerd","cniEnabled":false,"version":"install-control-plane-version","identityContext":{"trustDomain":"cluster.local","trustAnchorsPem":"-----BEGIN CERTIFICATE-----\nMIIBYDCCAQegAwIBAgIBATAKBggqhkjOPQQDAjAYMRYwFAYDVQQDEw1jbHVzdGVy\nLmxvY2FsMB4XDTE5MDMwMzAxNTk1MloXDTI5MDIyODAyMDM1MlowGDEWMBQGA1UE\nAxMNY2x1c3Rlci5sb2NhbDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAChpAt0\nxtgO9qbVtEtDK80N6iCL2Htyf2kIv2m5QkJ1y0TFQi5hTVe3wtspJ8YpZF0pl364\n6TiYeXB8tOOhIACjQjBAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHSUEFjAUBggrBgEF\nBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNHADBE\nAiBQ/AAwF8kG8VOmRSUTPakSSa/N4mqK2HsZuhQXCmiZHwIgZEzI5DCkpU7w3SIv\nOLO4Zsk1XrGZHGsmyiEyvYF9lpY=\n-----END CERTIFICATE-----\n","issuanceLifetime":"86400s","clockSkewAllowance":"20s","scheme":"linkerd.io/tls"},"autoInjectContext":null,"omitWebhookSideEffects":false,"clusterDomain":"cluster.local","endpointSliceEnabled":false} proxy: | {"proxyImage":{"imageName":"gcr.io/linkerd-io/proxy","pullPolicy":"IfNotPresent"},"proxyInitImage":{"imageName":"gcr.io/linkerd-io/proxy-init","pullPolicy":"IfNotPresent"},"controlPort":{"port":4190},"ignoreInboundPorts":[{"portRange":"22"},{"portRange":"8100-8102"}],"ignoreOutboundPorts":[{"portRange":"5432"}],"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","proxyInitImageVersion":"v1.3.3","debugImage":{"imageName":"gcr.io/linkerd-io/debug","pullPolicy":"IfNotPresent"},"debugImageVersion":"install-debug-version","destinationGetNetworks":"10.0.0.0/8,172.16.0.0/12,192.168.0.0/16","logFormat":"plain"} install: | diff --git a/cli/cmd/testdata/install_restricted_dashboard.golden b/cli/cmd/testdata/install_restricted_dashboard.golden index 6bb6875b94aae..e749afdc7886b 100644 --- a/cli/cmd/testdata/install_restricted_dashboard.golden +++ b/cli/cmd/testdata/install_restricted_dashboard.golden @@ -141,9 +141,6 @@ rules: - apiGroups: ["split.smi-spec.io"] resources: ["trafficsplits"] verbs: ["list", "get", "watch"] -- apiGroups: ["discovery.k8s.io"] - resources: ["endpointslices"] - verbs: ["list", "get", "watch"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 @@ -735,7 +732,7 @@ metadata: linkerd.io/created-by: linkerd/cli dev-undefined data: global: | - {"linkerdNamespace":"linkerd","cniEnabled":false,"version":"install-control-plane-version","identityContext":{"trustDomain":"cluster.local","trustAnchorsPem":"-----BEGIN CERTIFICATE-----\nMIIBYDCCAQegAwIBAgIBATAKBggqhkjOPQQDAjAYMRYwFAYDVQQDEw1jbHVzdGVy\nLmxvY2FsMB4XDTE5MDMwMzAxNTk1MloXDTI5MDIyODAyMDM1MlowGDEWMBQGA1UE\nAxMNY2x1c3Rlci5sb2NhbDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAChpAt0\nxtgO9qbVtEtDK80N6iCL2Htyf2kIv2m5QkJ1y0TFQi5hTVe3wtspJ8YpZF0pl364\n6TiYeXB8tOOhIACjQjBAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHSUEFjAUBggrBgEF\nBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNHADBE\nAiBQ/AAwF8kG8VOmRSUTPakSSa/N4mqK2HsZuhQXCmiZHwIgZEzI5DCkpU7w3SIv\nOLO4Zsk1XrGZHGsmyiEyvYF9lpY=\n-----END CERTIFICATE-----\n","issuanceLifetime":"86400s","clockSkewAllowance":"20s","scheme":"linkerd.io/tls"},"autoInjectContext":null,"omitWebhookSideEffects":false,"clusterDomain":"cluster.local"} + {"linkerdNamespace":"linkerd","cniEnabled":false,"version":"install-control-plane-version","identityContext":{"trustDomain":"cluster.local","trustAnchorsPem":"-----BEGIN CERTIFICATE-----\nMIIBYDCCAQegAwIBAgIBATAKBggqhkjOPQQDAjAYMRYwFAYDVQQDEw1jbHVzdGVy\nLmxvY2FsMB4XDTE5MDMwMzAxNTk1MloXDTI5MDIyODAyMDM1MlowGDEWMBQGA1UE\nAxMNY2x1c3Rlci5sb2NhbDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAChpAt0\nxtgO9qbVtEtDK80N6iCL2Htyf2kIv2m5QkJ1y0TFQi5hTVe3wtspJ8YpZF0pl364\n6TiYeXB8tOOhIACjQjBAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHSUEFjAUBggrBgEF\nBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNHADBE\nAiBQ/AAwF8kG8VOmRSUTPakSSa/N4mqK2HsZuhQXCmiZHwIgZEzI5DCkpU7w3SIv\nOLO4Zsk1XrGZHGsmyiEyvYF9lpY=\n-----END CERTIFICATE-----\n","issuanceLifetime":"86400s","clockSkewAllowance":"20s","scheme":"linkerd.io/tls"},"autoInjectContext":null,"omitWebhookSideEffects":false,"clusterDomain":"cluster.local","endpointSliceEnabled":false} 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":"install-proxy-version","proxyInitImageVersion":"v1.3.3","debugImage":{"imageName":"gcr.io/linkerd-io/debug","pullPolicy":"IfNotPresent"},"debugImageVersion":"install-debug-version","destinationGetNetworks":"10.0.0.0/8,172.16.0.0/12,192.168.0.0/16","logFormat":"plain"} install: | diff --git a/cli/cmd/testdata/install_tracing.golden b/cli/cmd/testdata/install_tracing.golden index f37bd33c2b4fe..d7dc1e8fecd35 100644 --- a/cli/cmd/testdata/install_tracing.golden +++ b/cli/cmd/testdata/install_tracing.golden @@ -141,9 +141,6 @@ rules: - apiGroups: ["split.smi-spec.io"] resources: ["trafficsplits"] verbs: ["list", "get", "watch"] -- apiGroups: ["discovery.k8s.io"] - resources: ["endpointslices"] - verbs: ["list", "get", "watch"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 @@ -803,7 +800,7 @@ metadata: linkerd.io/created-by: linkerd/cli dev-undefined data: global: | - {"linkerdNamespace":"linkerd","cniEnabled":false,"version":"install-control-plane-version","identityContext":{"trustDomain":"cluster.local","trustAnchorsPem":"-----BEGIN CERTIFICATE-----\nMIIBYDCCAQegAwIBAgIBATAKBggqhkjOPQQDAjAYMRYwFAYDVQQDEw1jbHVzdGVy\nLmxvY2FsMB4XDTE5MDMwMzAxNTk1MloXDTI5MDIyODAyMDM1MlowGDEWMBQGA1UE\nAxMNY2x1c3Rlci5sb2NhbDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAChpAt0\nxtgO9qbVtEtDK80N6iCL2Htyf2kIv2m5QkJ1y0TFQi5hTVe3wtspJ8YpZF0pl364\n6TiYeXB8tOOhIACjQjBAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHSUEFjAUBggrBgEF\nBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNHADBE\nAiBQ/AAwF8kG8VOmRSUTPakSSa/N4mqK2HsZuhQXCmiZHwIgZEzI5DCkpU7w3SIv\nOLO4Zsk1XrGZHGsmyiEyvYF9lpY=\n-----END CERTIFICATE-----\n","issuanceLifetime":"86400s","clockSkewAllowance":"20s","scheme":"linkerd.io/tls"},"autoInjectContext":null,"omitWebhookSideEffects":false,"clusterDomain":"cluster.local"} + {"linkerdNamespace":"linkerd","cniEnabled":false,"version":"install-control-plane-version","identityContext":{"trustDomain":"cluster.local","trustAnchorsPem":"-----BEGIN CERTIFICATE-----\nMIIBYDCCAQegAwIBAgIBATAKBggqhkjOPQQDAjAYMRYwFAYDVQQDEw1jbHVzdGVy\nLmxvY2FsMB4XDTE5MDMwMzAxNTk1MloXDTI5MDIyODAyMDM1MlowGDEWMBQGA1UE\nAxMNY2x1c3Rlci5sb2NhbDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAChpAt0\nxtgO9qbVtEtDK80N6iCL2Htyf2kIv2m5QkJ1y0TFQi5hTVe3wtspJ8YpZF0pl364\n6TiYeXB8tOOhIACjQjBAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHSUEFjAUBggrBgEF\nBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNHADBE\nAiBQ/AAwF8kG8VOmRSUTPakSSa/N4mqK2HsZuhQXCmiZHwIgZEzI5DCkpU7w3SIv\nOLO4Zsk1XrGZHGsmyiEyvYF9lpY=\n-----END CERTIFICATE-----\n","issuanceLifetime":"86400s","clockSkewAllowance":"20s","scheme":"linkerd.io/tls"},"autoInjectContext":null,"omitWebhookSideEffects":false,"clusterDomain":"cluster.local","endpointSliceEnabled":false} 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":"install-proxy-version","proxyInitImageVersion":"v1.3.3","debugImage":{"imageName":"gcr.io/linkerd-io/debug","pullPolicy":"IfNotPresent"},"debugImageVersion":"install-debug-version","destinationGetNetworks":"10.0.0.0/8,172.16.0.0/12,192.168.0.0/16","logFormat":"plain"} install: | diff --git a/cli/cmd/testdata/install_tracing_overwrite.golden b/cli/cmd/testdata/install_tracing_overwrite.golden index e8117eae4c9ec..5e8faff899695 100644 --- a/cli/cmd/testdata/install_tracing_overwrite.golden +++ b/cli/cmd/testdata/install_tracing_overwrite.golden @@ -141,9 +141,6 @@ rules: - apiGroups: ["split.smi-spec.io"] resources: ["trafficsplits"] verbs: ["list", "get", "watch"] -- apiGroups: ["discovery.k8s.io"] - resources: ["endpointslices"] - verbs: ["list", "get", "watch"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 @@ -803,7 +800,7 @@ metadata: linkerd.io/created-by: linkerd/cli dev-undefined data: global: | - {"linkerdNamespace":"linkerd","cniEnabled":false,"version":"install-control-plane-version","identityContext":{"trustDomain":"cluster.local","trustAnchorsPem":"-----BEGIN CERTIFICATE-----\nMIIBYDCCAQegAwIBAgIBATAKBggqhkjOPQQDAjAYMRYwFAYDVQQDEw1jbHVzdGVy\nLmxvY2FsMB4XDTE5MDMwMzAxNTk1MloXDTI5MDIyODAyMDM1MlowGDEWMBQGA1UE\nAxMNY2x1c3Rlci5sb2NhbDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAChpAt0\nxtgO9qbVtEtDK80N6iCL2Htyf2kIv2m5QkJ1y0TFQi5hTVe3wtspJ8YpZF0pl364\n6TiYeXB8tOOhIACjQjBAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHSUEFjAUBggrBgEF\nBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNHADBE\nAiBQ/AAwF8kG8VOmRSUTPakSSa/N4mqK2HsZuhQXCmiZHwIgZEzI5DCkpU7w3SIv\nOLO4Zsk1XrGZHGsmyiEyvYF9lpY=\n-----END CERTIFICATE-----\n","issuanceLifetime":"86400s","clockSkewAllowance":"20s","scheme":"linkerd.io/tls"},"autoInjectContext":null,"omitWebhookSideEffects":false,"clusterDomain":"cluster.local"} + {"linkerdNamespace":"linkerd","cniEnabled":false,"version":"install-control-plane-version","identityContext":{"trustDomain":"cluster.local","trustAnchorsPem":"-----BEGIN CERTIFICATE-----\nMIIBYDCCAQegAwIBAgIBATAKBggqhkjOPQQDAjAYMRYwFAYDVQQDEw1jbHVzdGVy\nLmxvY2FsMB4XDTE5MDMwMzAxNTk1MloXDTI5MDIyODAyMDM1MlowGDEWMBQGA1UE\nAxMNY2x1c3Rlci5sb2NhbDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAChpAt0\nxtgO9qbVtEtDK80N6iCL2Htyf2kIv2m5QkJ1y0TFQi5hTVe3wtspJ8YpZF0pl364\n6TiYeXB8tOOhIACjQjBAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHSUEFjAUBggrBgEF\nBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNHADBE\nAiBQ/AAwF8kG8VOmRSUTPakSSa/N4mqK2HsZuhQXCmiZHwIgZEzI5DCkpU7w3SIv\nOLO4Zsk1XrGZHGsmyiEyvYF9lpY=\n-----END CERTIFICATE-----\n","issuanceLifetime":"86400s","clockSkewAllowance":"20s","scheme":"linkerd.io/tls"},"autoInjectContext":null,"omitWebhookSideEffects":false,"clusterDomain":"cluster.local","endpointSliceEnabled":false} 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":"install-proxy-version","proxyInitImageVersion":"v1.3.3","debugImage":{"imageName":"gcr.io/linkerd-io/debug","pullPolicy":"IfNotPresent"},"debugImageVersion":"install-debug-version","destinationGetNetworks":"10.0.0.0/8,172.16.0.0/12,192.168.0.0/16","logFormat":"plain"} install: | diff --git a/cli/cmd/testdata/upgrade_add-on_config.golden b/cli/cmd/testdata/upgrade_add-on_config.golden index 1347b8c5ffe24..83d2bed2f48f4 100644 --- a/cli/cmd/testdata/upgrade_add-on_config.golden +++ b/cli/cmd/testdata/upgrade_add-on_config.golden @@ -141,9 +141,6 @@ rules: - apiGroups: ["split.smi-spec.io"] resources: ["trafficsplits"] verbs: ["list", "get", "watch"] -- apiGroups: ["discovery.k8s.io"] - resources: ["endpointslices"] - verbs: ["list", "get", "watch"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 diff --git a/cli/cmd/testdata/upgrade_add-on_controlplane.golden b/cli/cmd/testdata/upgrade_add-on_controlplane.golden index 1f750fc78d177..ad3c2af498852 100644 --- a/cli/cmd/testdata/upgrade_add-on_controlplane.golden +++ b/cli/cmd/testdata/upgrade_add-on_controlplane.golden @@ -11,7 +11,7 @@ metadata: linkerd.io/created-by: linkerd/cli dev-undefined 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"} + {"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","endpointSliceEnabled":false} 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":"100m","requestMemory":"20Mi","limitCpu":"1","limitMemory":"250Mi"},"proxyUid":"2102","logLevel":{"level":"warn,linkerd=info"},"disableExternalProfiles":true,"proxyVersion":"UPGRADE-PROXY-VERSION","proxyInitImageVersion":"v1.3.3","debugImage":{"imageName":"gcr.io/linkerd-io/debug","pullPolicy":"IfNotPresent"},"debugImageVersion":"UPGRADE-DEBUG-VERSION","destinationGetNetworks":"DST-GET-NETWORKS","logFormat":"plain"} install: | diff --git a/cli/cmd/testdata/upgrade_add-on_overwrite.golden b/cli/cmd/testdata/upgrade_add-on_overwrite.golden index 14f6eb13f0d48..14b873dec1df6 100644 --- a/cli/cmd/testdata/upgrade_add-on_overwrite.golden +++ b/cli/cmd/testdata/upgrade_add-on_overwrite.golden @@ -141,9 +141,6 @@ rules: - apiGroups: ["split.smi-spec.io"] resources: ["trafficsplits"] verbs: ["list", "get", "watch"] -- apiGroups: ["discovery.k8s.io"] - resources: ["endpointslices"] - verbs: ["list", "get", "watch"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 @@ -803,7 +800,7 @@ metadata: linkerd.io/created-by: linkerd/cli dev-undefined 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"} + {"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","endpointSliceEnabled":false} 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":"100m","requestMemory":"20Mi","limitCpu":"1","limitMemory":"250Mi"},"proxyUid":"2102","logLevel":{"level":"warn,linkerd=info"},"disableExternalProfiles":true,"proxyVersion":"UPGRADE-PROXY-VERSION","proxyInitImageVersion":"v1.3.3","debugImage":{"imageName":"gcr.io/linkerd-io/debug","pullPolicy":"IfNotPresent"},"debugImageVersion":"UPGRADE-DEBUG-VERSION","destinationGetNetworks":"DST-GET-NETWORKS","logFormat":"plain"} install: | diff --git a/cli/cmd/testdata/upgrade_add_add-on.golden b/cli/cmd/testdata/upgrade_add_add-on.golden index 5924df7872173..3669c91d1c0f4 100644 --- a/cli/cmd/testdata/upgrade_add_add-on.golden +++ b/cli/cmd/testdata/upgrade_add_add-on.golden @@ -141,9 +141,6 @@ rules: - apiGroups: ["split.smi-spec.io"] resources: ["trafficsplits"] verbs: ["list", "get", "watch"] -- apiGroups: ["discovery.k8s.io"] - resources: ["endpointslices"] - verbs: ["list", "get", "watch"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 @@ -803,7 +800,7 @@ metadata: linkerd.io/created-by: linkerd/cli dev-undefined 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"} + {"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","endpointSliceEnabled":false} 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":"100m","requestMemory":"20Mi","limitCpu":"1","limitMemory":"250Mi"},"proxyUid":"2102","logLevel":{"level":"warn,linkerd=info"},"disableExternalProfiles":true,"proxyVersion":"UPGRADE-PROXY-VERSION","proxyInitImageVersion":"v1.3.3","debugImage":{"imageName":"gcr.io/linkerd-io/debug","pullPolicy":"IfNotPresent"},"debugImageVersion":"UPGRADE-DEBUG-VERSION","destinationGetNetworks":"DST-GET-NETWORKS","logFormat":"plain"} install: | diff --git a/cli/cmd/testdata/upgrade_default.golden b/cli/cmd/testdata/upgrade_default.golden index 8e534f9484f45..8a925e7fd0193 100644 --- a/cli/cmd/testdata/upgrade_default.golden +++ b/cli/cmd/testdata/upgrade_default.golden @@ -141,9 +141,6 @@ rules: - apiGroups: ["split.smi-spec.io"] resources: ["trafficsplits"] verbs: ["list", "get", "watch"] -- apiGroups: ["discovery.k8s.io"] - resources: ["endpointslices"] - verbs: ["list", "get", "watch"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 @@ -803,7 +800,7 @@ metadata: linkerd.io/created-by: linkerd/cli dev-undefined 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"} + {"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","endpointSliceEnabled":false} proxy: | {"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.3","debugImage":{"imageName":"gcr.io/linkerd-io/debug","pullPolicy":"IfNotPresent"},"debugImageVersion":"UPGRADE-DEBUG-VERSION","destinationGetNetworks":"DST-GET-NETWORKS","logFormat":"plain"} install: | diff --git a/cli/cmd/testdata/upgrade_external_issuer.golden b/cli/cmd/testdata/upgrade_external_issuer.golden index 1e91baaed0d4e..65fa0685f5244 100644 --- a/cli/cmd/testdata/upgrade_external_issuer.golden +++ b/cli/cmd/testdata/upgrade_external_issuer.golden @@ -141,9 +141,6 @@ rules: - apiGroups: ["split.smi-spec.io"] resources: ["trafficsplits"] verbs: ["list", "get", "watch"] -- apiGroups: ["discovery.k8s.io"] - resources: ["endpointslices"] - verbs: ["list", "get", "watch"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 @@ -803,7 +800,7 @@ metadata: linkerd.io/created-by: linkerd/cli dev-undefined 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":"kubernetes.io/tls"},"autoInjectContext":null,"omitWebhookSideEffects":false,"clusterDomain":"cluster.local"} + {"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":"kubernetes.io/tls"},"autoInjectContext":null,"omitWebhookSideEffects":false,"clusterDomain":"cluster.local","endpointSliceEnabled":false} 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.3","debugImage":{"imageName":"gcr.io/linkerd-io/debug","pullPolicy":"IfNotPresent"},"debugImageVersion":"UPGRADE-DEBUG-VERSION","destinationGetNetworks":"DST-GET-NETWORKS","logFormat":"plain"} install: | diff --git a/cli/cmd/testdata/upgrade_grafana_addon_overwrite.yaml b/cli/cmd/testdata/upgrade_grafana_addon_overwrite.yaml index 5200f730f178a..b0de46ee9bc46 100644 --- a/cli/cmd/testdata/upgrade_grafana_addon_overwrite.yaml +++ b/cli/cmd/testdata/upgrade_grafana_addon_overwrite.yaml @@ -141,9 +141,6 @@ rules: - apiGroups: ["split.smi-spec.io"] resources: ["trafficsplits"] verbs: ["list", "get", "watch"] -- apiGroups: ["discovery.k8s.io"] - resources: ["endpointslices"] - verbs: ["list", "get", "watch"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 @@ -803,7 +800,7 @@ metadata: linkerd.io/created-by: linkerd/cli dev-undefined 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"} + {"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","endpointSliceEnabled":false} 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":"100m","requestMemory":"20Mi","limitCpu":"1","limitMemory":"250Mi"},"proxyUid":"2102","logLevel":{"level":"warn,linkerd=info"},"disableExternalProfiles":true,"proxyVersion":"UPGRADE-PROXY-VERSION","proxyInitImageVersion":"v1.3.3","debugImage":{"imageName":"gcr.io/linkerd-io/debug","pullPolicy":"IfNotPresent"},"debugImageVersion":"UPGRADE-DEBUG-VERSION","destinationGetNetworks":"DST-GET-NETWORKS","logFormat":"plain"} install: | diff --git a/cli/cmd/testdata/upgrade_grafana_disabled.yaml b/cli/cmd/testdata/upgrade_grafana_disabled.yaml index 915a6b4d2fb91..a047448389873 100644 --- a/cli/cmd/testdata/upgrade_grafana_disabled.yaml +++ b/cli/cmd/testdata/upgrade_grafana_disabled.yaml @@ -141,9 +141,6 @@ rules: - apiGroups: ["split.smi-spec.io"] resources: ["trafficsplits"] verbs: ["list", "get", "watch"] -- apiGroups: ["discovery.k8s.io"] - resources: ["endpointslices"] - verbs: ["list", "get", "watch"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 @@ -800,7 +797,7 @@ metadata: linkerd.io/created-by: linkerd/cli dev-undefined 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"} + {"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","endpointSliceEnabled":false} 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":"100m","requestMemory":"20Mi","limitCpu":"1","limitMemory":"250Mi"},"proxyUid":"2102","logLevel":{"level":"warn,linkerd=info"},"disableExternalProfiles":true,"proxyVersion":"UPGRADE-PROXY-VERSION","proxyInitImageVersion":"v1.3.3","debugImage":{"imageName":"gcr.io/linkerd-io/debug","pullPolicy":"IfNotPresent"},"debugImageVersion":"UPGRADE-DEBUG-VERSION","destinationGetNetworks":"DST-GET-NETWORKS","logFormat":"plain"} install: | diff --git a/cli/cmd/testdata/upgrade_grafana_enabled.yaml b/cli/cmd/testdata/upgrade_grafana_enabled.yaml index 5200f730f178a..b0de46ee9bc46 100644 --- a/cli/cmd/testdata/upgrade_grafana_enabled.yaml +++ b/cli/cmd/testdata/upgrade_grafana_enabled.yaml @@ -141,9 +141,6 @@ rules: - apiGroups: ["split.smi-spec.io"] resources: ["trafficsplits"] verbs: ["list", "get", "watch"] -- apiGroups: ["discovery.k8s.io"] - resources: ["endpointslices"] - verbs: ["list", "get", "watch"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 @@ -803,7 +800,7 @@ metadata: linkerd.io/created-by: linkerd/cli dev-undefined 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"} + {"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","endpointSliceEnabled":false} 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":"100m","requestMemory":"20Mi","limitCpu":"1","limitMemory":"250Mi"},"proxyUid":"2102","logLevel":{"level":"warn,linkerd=info"},"disableExternalProfiles":true,"proxyVersion":"UPGRADE-PROXY-VERSION","proxyInitImageVersion":"v1.3.3","debugImage":{"imageName":"gcr.io/linkerd-io/debug","pullPolicy":"IfNotPresent"},"debugImageVersion":"UPGRADE-DEBUG-VERSION","destinationGetNetworks":"DST-GET-NETWORKS","logFormat":"plain"} install: | diff --git a/cli/cmd/testdata/upgrade_grafana_enabled_disabled.yaml b/cli/cmd/testdata/upgrade_grafana_enabled_disabled.yaml index 915a6b4d2fb91..a047448389873 100644 --- a/cli/cmd/testdata/upgrade_grafana_enabled_disabled.yaml +++ b/cli/cmd/testdata/upgrade_grafana_enabled_disabled.yaml @@ -141,9 +141,6 @@ rules: - apiGroups: ["split.smi-spec.io"] resources: ["trafficsplits"] verbs: ["list", "get", "watch"] -- apiGroups: ["discovery.k8s.io"] - resources: ["endpointslices"] - verbs: ["list", "get", "watch"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 @@ -800,7 +797,7 @@ metadata: linkerd.io/created-by: linkerd/cli dev-undefined 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"} + {"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","endpointSliceEnabled":false} 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":"100m","requestMemory":"20Mi","limitCpu":"1","limitMemory":"250Mi"},"proxyUid":"2102","logLevel":{"level":"warn,linkerd=info"},"disableExternalProfiles":true,"proxyVersion":"UPGRADE-PROXY-VERSION","proxyInitImageVersion":"v1.3.3","debugImage":{"imageName":"gcr.io/linkerd-io/debug","pullPolicy":"IfNotPresent"},"debugImageVersion":"UPGRADE-DEBUG-VERSION","destinationGetNetworks":"DST-GET-NETWORKS","logFormat":"plain"} install: | diff --git a/cli/cmd/testdata/upgrade_grafana_overwrite.yaml b/cli/cmd/testdata/upgrade_grafana_overwrite.yaml index 79fde0daebe41..8b1216ef3b65f 100644 --- a/cli/cmd/testdata/upgrade_grafana_overwrite.yaml +++ b/cli/cmd/testdata/upgrade_grafana_overwrite.yaml @@ -141,9 +141,6 @@ rules: - apiGroups: ["split.smi-spec.io"] resources: ["trafficsplits"] verbs: ["list", "get", "watch"] -- apiGroups: ["discovery.k8s.io"] - resources: ["endpointslices"] - verbs: ["list", "get", "watch"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 @@ -803,7 +800,7 @@ metadata: linkerd.io/created-by: linkerd/cli dev-undefined 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"} + {"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","endpointSliceEnabled":false} 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":"100m","requestMemory":"20Mi","limitCpu":"1","limitMemory":"250Mi"},"proxyUid":"2102","logLevel":{"level":"warn,linkerd=info"},"disableExternalProfiles":true,"proxyVersion":"UPGRADE-PROXY-VERSION","proxyInitImageVersion":"v1.3.3","debugImage":{"imageName":"gcr.io/linkerd-io/debug","pullPolicy":"IfNotPresent"},"debugImageVersion":"UPGRADE-DEBUG-VERSION","destinationGetNetworks":"DST-GET-NETWORKS","logFormat":"plain"} install: | diff --git a/cli/cmd/testdata/upgrade_ha.golden b/cli/cmd/testdata/upgrade_ha.golden index 8db5a3ce11686..29bafdcaed83a 100644 --- a/cli/cmd/testdata/upgrade_ha.golden +++ b/cli/cmd/testdata/upgrade_ha.golden @@ -141,9 +141,6 @@ rules: - apiGroups: ["split.smi-spec.io"] resources: ["trafficsplits"] verbs: ["list", "get", "watch"] -- apiGroups: ["discovery.k8s.io"] - resources: ["endpointslices"] - verbs: ["list", "get", "watch"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 @@ -803,7 +800,7 @@ metadata: linkerd.io/created-by: linkerd/cli dev-undefined 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"} + {"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","endpointSliceEnabled":false} 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":"100m","requestMemory":"20Mi","limitCpu":"1","limitMemory":"250Mi"},"proxyUid":"2102","logLevel":{"level":"warn,linkerd=info"},"disableExternalProfiles":true,"proxyVersion":"UPGRADE-PROXY-VERSION","proxyInitImageVersion":"v1.3.3","debugImage":{"imageName":"gcr.io/linkerd-io/debug","pullPolicy":"IfNotPresent"},"debugImageVersion":"UPGRADE-DEBUG-VERSION","destinationGetNetworks":"DST-GET-NETWORKS","logFormat":"plain"} install: | diff --git a/cli/cmd/testdata/upgrade_ha_config.golden b/cli/cmd/testdata/upgrade_ha_config.golden index 046f8a2dc47ed..8f1581a562f2b 100644 --- a/cli/cmd/testdata/upgrade_ha_config.golden +++ b/cli/cmd/testdata/upgrade_ha_config.golden @@ -141,9 +141,6 @@ rules: - apiGroups: ["split.smi-spec.io"] resources: ["trafficsplits"] verbs: ["list", "get", "watch"] -- apiGroups: ["discovery.k8s.io"] - resources: ["endpointslices"] - verbs: ["list", "get", "watch"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 diff --git a/cli/cmd/testdata/upgrade_keep_webhook_cabundle.golden b/cli/cmd/testdata/upgrade_keep_webhook_cabundle.golden index f9d8c2fe1be26..0089db55e0811 100644 --- a/cli/cmd/testdata/upgrade_keep_webhook_cabundle.golden +++ b/cli/cmd/testdata/upgrade_keep_webhook_cabundle.golden @@ -141,9 +141,6 @@ rules: - apiGroups: ["split.smi-spec.io"] resources: ["trafficsplits"] verbs: ["list", "get", "watch"] -- apiGroups: ["discovery.k8s.io"] - resources: ["endpointslices"] - verbs: ["list", "get", "watch"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 @@ -803,7 +800,7 @@ metadata: linkerd.io/created-by: linkerd/cli dev-undefined 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"} + {"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","endpointSliceEnabled":false} proxy: | {"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.3","debugImage":{"imageName":"gcr.io/linkerd-io/debug","pullPolicy":"IfNotPresent"},"debugImageVersion":"UPGRADE-DEBUG-VERSION","destinationGetNetworks":"DST-GET-NETWORKS","logFormat":"plain"} install: | diff --git a/cli/cmd/testdata/upgrade_nothing_addon.yaml b/cli/cmd/testdata/upgrade_nothing_addon.yaml index 5200f730f178a..b0de46ee9bc46 100644 --- a/cli/cmd/testdata/upgrade_nothing_addon.yaml +++ b/cli/cmd/testdata/upgrade_nothing_addon.yaml @@ -141,9 +141,6 @@ rules: - apiGroups: ["split.smi-spec.io"] resources: ["trafficsplits"] verbs: ["list", "get", "watch"] -- apiGroups: ["discovery.k8s.io"] - resources: ["endpointslices"] - verbs: ["list", "get", "watch"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 @@ -803,7 +800,7 @@ metadata: linkerd.io/created-by: linkerd/cli dev-undefined 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"} + {"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","endpointSliceEnabled":false} 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":"100m","requestMemory":"20Mi","limitCpu":"1","limitMemory":"250Mi"},"proxyUid":"2102","logLevel":{"level":"warn,linkerd=info"},"disableExternalProfiles":true,"proxyVersion":"UPGRADE-PROXY-VERSION","proxyInitImageVersion":"v1.3.3","debugImage":{"imageName":"gcr.io/linkerd-io/debug","pullPolicy":"IfNotPresent"},"debugImageVersion":"UPGRADE-DEBUG-VERSION","destinationGetNetworks":"DST-GET-NETWORKS","logFormat":"plain"} install: | diff --git a/cli/cmd/testdata/upgrade_overwrite_issuer.golden b/cli/cmd/testdata/upgrade_overwrite_issuer.golden index 0bbe6270b4efe..aca0849ab623a 100644 --- a/cli/cmd/testdata/upgrade_overwrite_issuer.golden +++ b/cli/cmd/testdata/upgrade_overwrite_issuer.golden @@ -141,9 +141,6 @@ rules: - apiGroups: ["split.smi-spec.io"] resources: ["trafficsplits"] verbs: ["list", "get", "watch"] -- apiGroups: ["discovery.k8s.io"] - resources: ["endpointslices"] - verbs: ["list", "get", "watch"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 @@ -803,7 +800,7 @@ metadata: linkerd.io/created-by: linkerd/cli dev-undefined data: global: | - {"linkerdNamespace":"linkerd","cniEnabled":false,"version":"UPGRADE-CONTROL-PLANE-VERSION","identityContext":{"trustDomain":"cluster.local","trustAnchorsPem":"-----BEGIN CERTIFICATE-----\nMIIBYDCCAQegAwIBAgIBATAKBggqhkjOPQQDAjAYMRYwFAYDVQQDEw1jbHVzdGVy\nLmxvY2FsMB4XDTE5MDMwMzAxNTk1MloXDTI5MDIyODAyMDM1MlowGDEWMBQGA1UE\nAxMNY2x1c3Rlci5sb2NhbDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAChpAt0\nxtgO9qbVtEtDK80N6iCL2Htyf2kIv2m5QkJ1y0TFQi5hTVe3wtspJ8YpZF0pl364\n6TiYeXB8tOOhIACjQjBAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHSUEFjAUBggrBgEF\nBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNHADBE\nAiBQ/AAwF8kG8VOmRSUTPakSSa/N4mqK2HsZuhQXCmiZHwIgZEzI5DCkpU7w3SIv\nOLO4Zsk1XrGZHGsmyiEyvYF9lpY=\n-----END CERTIFICATE-----\n","issuanceLifetime":"86400s","clockSkewAllowance":"20s","scheme":"linkerd.io/tls"},"autoInjectContext":null,"omitWebhookSideEffects":false,"clusterDomain":"cluster.local"} + {"linkerdNamespace":"linkerd","cniEnabled":false,"version":"UPGRADE-CONTROL-PLANE-VERSION","identityContext":{"trustDomain":"cluster.local","trustAnchorsPem":"-----BEGIN CERTIFICATE-----\nMIIBYDCCAQegAwIBAgIBATAKBggqhkjOPQQDAjAYMRYwFAYDVQQDEw1jbHVzdGVy\nLmxvY2FsMB4XDTE5MDMwMzAxNTk1MloXDTI5MDIyODAyMDM1MlowGDEWMBQGA1UE\nAxMNY2x1c3Rlci5sb2NhbDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAChpAt0\nxtgO9qbVtEtDK80N6iCL2Htyf2kIv2m5QkJ1y0TFQi5hTVe3wtspJ8YpZF0pl364\n6TiYeXB8tOOhIACjQjBAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHSUEFjAUBggrBgEF\nBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNHADBE\nAiBQ/AAwF8kG8VOmRSUTPakSSa/N4mqK2HsZuhQXCmiZHwIgZEzI5DCkpU7w3SIv\nOLO4Zsk1XrGZHGsmyiEyvYF9lpY=\n-----END CERTIFICATE-----\n","issuanceLifetime":"86400s","clockSkewAllowance":"20s","scheme":"linkerd.io/tls"},"autoInjectContext":null,"omitWebhookSideEffects":false,"clusterDomain":"cluster.local","endpointSliceEnabled":false} 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.3","debugImage":{"imageName":"gcr.io/linkerd-io/debug","pullPolicy":"IfNotPresent"},"debugImageVersion":"UPGRADE-DEBUG-VERSION","destinationGetNetworks":"DST-GET-NETWORKS","logFormat":"plain"} install: | diff --git a/cli/cmd/testdata/upgrade_overwrite_trust_anchors-external-issuer.golden b/cli/cmd/testdata/upgrade_overwrite_trust_anchors-external-issuer.golden index 2a39cad3afb1f..1f438b95452b7 100644 --- a/cli/cmd/testdata/upgrade_overwrite_trust_anchors-external-issuer.golden +++ b/cli/cmd/testdata/upgrade_overwrite_trust_anchors-external-issuer.golden @@ -141,9 +141,6 @@ rules: - apiGroups: ["split.smi-spec.io"] resources: ["trafficsplits"] verbs: ["list", "get", "watch"] -- apiGroups: ["discovery.k8s.io"] - resources: ["endpointslices"] - verbs: ["list", "get", "watch"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 @@ -803,7 +800,7 @@ metadata: linkerd.io/created-by: linkerd/cli dev-undefined data: global: | - {"linkerdNamespace":"linkerd","cniEnabled":false,"version":"UPGRADE-CONTROL-PLANE-VERSION","identityContext":{"trustDomain":"cluster.local","trustAnchorsPem":"-----BEGIN CERTIFICATE-----\nMIIBYDCCAQegAwIBAgIBATAKBggqhkjOPQQDAjAYMRYwFAYDVQQDEw1jbHVzdGVy\nLmxvY2FsMB4XDTE5MDMwMzAxNTk1MloXDTI5MDIyODAyMDM1MlowGDEWMBQGA1UE\nAxMNY2x1c3Rlci5sb2NhbDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAChpAt0\nxtgO9qbVtEtDK80N6iCL2Htyf2kIv2m5QkJ1y0TFQi5hTVe3wtspJ8YpZF0pl364\n6TiYeXB8tOOhIACjQjBAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHSUEFjAUBggrBgEF\nBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNHADBE\nAiBQ/AAwF8kG8VOmRSUTPakSSa/N4mqK2HsZuhQXCmiZHwIgZEzI5DCkpU7w3SIv\nOLO4Zsk1XrGZHGsmyiEyvYF9lpY=\n-----END CERTIFICATE-----\n","issuanceLifetime":"86400s","clockSkewAllowance":"20s","scheme":"kubernetes.io/tls"},"autoInjectContext":null,"omitWebhookSideEffects":false,"clusterDomain":"cluster.local"} + {"linkerdNamespace":"linkerd","cniEnabled":false,"version":"UPGRADE-CONTROL-PLANE-VERSION","identityContext":{"trustDomain":"cluster.local","trustAnchorsPem":"-----BEGIN CERTIFICATE-----\nMIIBYDCCAQegAwIBAgIBATAKBggqhkjOPQQDAjAYMRYwFAYDVQQDEw1jbHVzdGVy\nLmxvY2FsMB4XDTE5MDMwMzAxNTk1MloXDTI5MDIyODAyMDM1MlowGDEWMBQGA1UE\nAxMNY2x1c3Rlci5sb2NhbDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAChpAt0\nxtgO9qbVtEtDK80N6iCL2Htyf2kIv2m5QkJ1y0TFQi5hTVe3wtspJ8YpZF0pl364\n6TiYeXB8tOOhIACjQjBAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHSUEFjAUBggrBgEF\nBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNHADBE\nAiBQ/AAwF8kG8VOmRSUTPakSSa/N4mqK2HsZuhQXCmiZHwIgZEzI5DCkpU7w3SIv\nOLO4Zsk1XrGZHGsmyiEyvYF9lpY=\n-----END CERTIFICATE-----\n","issuanceLifetime":"86400s","clockSkewAllowance":"20s","scheme":"kubernetes.io/tls"},"autoInjectContext":null,"omitWebhookSideEffects":false,"clusterDomain":"cluster.local","endpointSliceEnabled":false} 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.3","debugImage":{"imageName":"gcr.io/linkerd-io/debug","pullPolicy":"IfNotPresent"},"debugImageVersion":"UPGRADE-DEBUG-VERSION","destinationGetNetworks":"DST-GET-NETWORKS","logFormat":"plain"} install: | diff --git a/cli/cmd/testdata/upgrade_overwrite_trust_anchors.golden b/cli/cmd/testdata/upgrade_overwrite_trust_anchors.golden index 0bbe6270b4efe..aca0849ab623a 100644 --- a/cli/cmd/testdata/upgrade_overwrite_trust_anchors.golden +++ b/cli/cmd/testdata/upgrade_overwrite_trust_anchors.golden @@ -141,9 +141,6 @@ rules: - apiGroups: ["split.smi-spec.io"] resources: ["trafficsplits"] verbs: ["list", "get", "watch"] -- apiGroups: ["discovery.k8s.io"] - resources: ["endpointslices"] - verbs: ["list", "get", "watch"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 @@ -803,7 +800,7 @@ metadata: linkerd.io/created-by: linkerd/cli dev-undefined data: global: | - {"linkerdNamespace":"linkerd","cniEnabled":false,"version":"UPGRADE-CONTROL-PLANE-VERSION","identityContext":{"trustDomain":"cluster.local","trustAnchorsPem":"-----BEGIN CERTIFICATE-----\nMIIBYDCCAQegAwIBAgIBATAKBggqhkjOPQQDAjAYMRYwFAYDVQQDEw1jbHVzdGVy\nLmxvY2FsMB4XDTE5MDMwMzAxNTk1MloXDTI5MDIyODAyMDM1MlowGDEWMBQGA1UE\nAxMNY2x1c3Rlci5sb2NhbDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAChpAt0\nxtgO9qbVtEtDK80N6iCL2Htyf2kIv2m5QkJ1y0TFQi5hTVe3wtspJ8YpZF0pl364\n6TiYeXB8tOOhIACjQjBAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHSUEFjAUBggrBgEF\nBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNHADBE\nAiBQ/AAwF8kG8VOmRSUTPakSSa/N4mqK2HsZuhQXCmiZHwIgZEzI5DCkpU7w3SIv\nOLO4Zsk1XrGZHGsmyiEyvYF9lpY=\n-----END CERTIFICATE-----\n","issuanceLifetime":"86400s","clockSkewAllowance":"20s","scheme":"linkerd.io/tls"},"autoInjectContext":null,"omitWebhookSideEffects":false,"clusterDomain":"cluster.local"} + {"linkerdNamespace":"linkerd","cniEnabled":false,"version":"UPGRADE-CONTROL-PLANE-VERSION","identityContext":{"trustDomain":"cluster.local","trustAnchorsPem":"-----BEGIN CERTIFICATE-----\nMIIBYDCCAQegAwIBAgIBATAKBggqhkjOPQQDAjAYMRYwFAYDVQQDEw1jbHVzdGVy\nLmxvY2FsMB4XDTE5MDMwMzAxNTk1MloXDTI5MDIyODAyMDM1MlowGDEWMBQGA1UE\nAxMNY2x1c3Rlci5sb2NhbDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAChpAt0\nxtgO9qbVtEtDK80N6iCL2Htyf2kIv2m5QkJ1y0TFQi5hTVe3wtspJ8YpZF0pl364\n6TiYeXB8tOOhIACjQjBAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHSUEFjAUBggrBgEF\nBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNHADBE\nAiBQ/AAwF8kG8VOmRSUTPakSSa/N4mqK2HsZuhQXCmiZHwIgZEzI5DCkpU7w3SIv\nOLO4Zsk1XrGZHGsmyiEyvYF9lpY=\n-----END CERTIFICATE-----\n","issuanceLifetime":"86400s","clockSkewAllowance":"20s","scheme":"linkerd.io/tls"},"autoInjectContext":null,"omitWebhookSideEffects":false,"clusterDomain":"cluster.local","endpointSliceEnabled":false} 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.3","debugImage":{"imageName":"gcr.io/linkerd-io/debug","pullPolicy":"IfNotPresent"},"debugImageVersion":"UPGRADE-DEBUG-VERSION","destinationGetNetworks":"DST-GET-NETWORKS","logFormat":"plain"} install: | diff --git a/cli/cmd/testdata/upgrade_two_level_webhook_cert.golden b/cli/cmd/testdata/upgrade_two_level_webhook_cert.golden index c3055f4b133ae..85662051f0ecd 100644 --- a/cli/cmd/testdata/upgrade_two_level_webhook_cert.golden +++ b/cli/cmd/testdata/upgrade_two_level_webhook_cert.golden @@ -141,9 +141,6 @@ rules: - apiGroups: ["split.smi-spec.io"] resources: ["trafficsplits"] verbs: ["list", "get", "watch"] -- apiGroups: ["discovery.k8s.io"] - resources: ["endpointslices"] - verbs: ["list", "get", "watch"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 @@ -803,7 +800,7 @@ metadata: linkerd.io/created-by: linkerd/cli dev-undefined 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"} + {"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","endpointSliceEnabled":false} proxy: | {"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.3","debugImage":{"imageName":"gcr.io/linkerd-io/debug","pullPolicy":"IfNotPresent"},"debugImageVersion":"UPGRADE-DEBUG-VERSION","destinationGetNetworks":"DST-GET-NETWORKS","logFormat":"plain"} install: | diff --git a/controller/api/destination/server.go b/controller/api/destination/server.go index 70d62c991bfc1..544401c3721a3 100644 --- a/controller/api/destination/server.go +++ b/controller/api/destination/server.go @@ -51,6 +51,7 @@ func NewServer( controllerNS string, identityTrustDomain string, enableH2Upgrade bool, + enableEndpointSlices bool, k8sAPI *k8s.API, clusterDomain string, shutdown <-chan struct{}, @@ -59,7 +60,7 @@ func NewServer( "addr": addr, "component": "server", }) - endpoints := watcher.NewEndpointsWatcher(k8sAPI, log) + endpoints := watcher.NewEndpointsWatcher(k8sAPI, log, enableEndpointSlices) profiles := watcher.NewProfileWatcher(k8sAPI, log) trafficSplits := watcher.NewTrafficSplitWatcher(k8sAPI, log) ips := watcher.NewIPWatcher(k8sAPI, endpoints, log) diff --git a/controller/api/destination/server_test.go b/controller/api/destination/server_test.go index 5fed1ac5b63e9..c8171401dfce1 100644 --- a/controller/api/destination/server_test.go +++ b/controller/api/destination/server_test.go @@ -101,7 +101,7 @@ spec: k8sAPI.Sync(nil) - endpoints := watcher.NewEndpointsWatcher(k8sAPI, log) + endpoints := watcher.NewEndpointsWatcher(k8sAPI, log, false) profiles := watcher.NewProfileWatcher(k8sAPI, log) trafficSplits := watcher.NewTrafficSplitWatcher(k8sAPI, log) ips := watcher.NewIPWatcher(k8sAPI, endpoints, log) diff --git a/controller/api/destination/watcher/endpoints_watcher.go b/controller/api/destination/watcher/endpoints_watcher.go index 32f71baa4c98d..5d2f92fd631d3 100644 --- a/controller/api/destination/watcher/endpoints_watcher.go +++ b/controller/api/destination/watcher/endpoints_watcher.go @@ -7,7 +7,7 @@ import ( "sync" "github.com/linkerd/linkerd2/controller/k8s" - pkgK8s "github.com/linkerd/linkerd2/pkg/k8s" + consts "github.com/linkerd/linkerd2/pkg/k8s" "github.com/prometheus/client_golang/prometheus" logging "github.com/sirupsen/logrus" corev1 "k8s.io/api/core/v1" @@ -70,8 +70,9 @@ type ( publishers map[ServiceID]*servicePublisher k8sAPI *k8s.API - log *logging.Entry - sync.RWMutex // This mutex protects modification of the map itself. + log *logging.Entry + enableEndpointSlices bool + sync.RWMutex // This mutex protects modification of the map itself. } // servicePublisher represents a service. It keeps a map of portPublishers @@ -84,9 +85,10 @@ type ( // requested, the address set will be filtered to only include addresses // with the requested hostname. servicePublisher struct { - id ServiceID - log *logging.Entry - k8sAPI *k8s.API + id ServiceID + log *logging.Entry + k8sAPI *k8s.API + enableEndpointSlices bool ports map[portAndHostname]*portPublisher // All access to the servicePublisher and its portPublishers is explicitly synchronized by @@ -100,12 +102,13 @@ type ( // publishes diffs to all listeners when updates come from either the // endpoints API or the service API. portPublisher struct { - id ServiceID - targetPort namedPort - srcPort Port - hostname string - log *logging.Entry - k8sAPI *k8s.API + id ServiceID + targetPort namedPort + srcPort Port + hostname string + log *logging.Entry + k8sAPI *k8s.API + enableEndpointSlices bool exists bool addresses AddressSet @@ -127,10 +130,11 @@ var endpointsVecs = newEndpointsMetricsVecs() // k8sAPI for pod, service, and endpoint changes. An EndpointsWatcher will // watch on Endpoints or EndpointSlice resources, depending on cluster configuration. //TODO: Allow EndpointSlice resources to be used once opt-in functionality is supported. -func NewEndpointsWatcher(k8sAPI *k8s.API, log *logging.Entry) *EndpointsWatcher { +func NewEndpointsWatcher(k8sAPI *k8s.API, log *logging.Entry, enableEndpointSlices bool) *EndpointsWatcher { ew := &EndpointsWatcher{ - publishers: make(map[ServiceID]*servicePublisher), - k8sAPI: k8sAPI, + publishers: make(map[ServiceID]*servicePublisher), + k8sAPI: k8sAPI, + enableEndpointSlices: enableEndpointSlices, log: log.WithFields(logging.Fields{ "component": "endpoints-watcher", }), @@ -149,7 +153,14 @@ func NewEndpointsWatcher(k8sAPI *k8s.API, log *logging.Entry) *EndpointsWatcher UpdateFunc: func(_, obj interface{}) { ew.addService(obj) }, }) - if !pkgK8s.EndpointSliceAccess(k8sAPI.Client) { + if ew.enableEndpointSlices { + ew.log.Debugf("Watching EndpointSlice resources") + k8sAPI.ES().Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ + AddFunc: ew.addEndpointSlice, + DeleteFunc: ew.deleteEndpointSlice, + UpdateFunc: ew.updateEndpointSlice, + }) + } else { // ew.log.Debugf("Cluster does not have EndpointSlice access:%v", err) ew.log.Debugf("Watching Endpoints resources") k8sAPI.Endpoint().Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ @@ -157,13 +168,6 @@ func NewEndpointsWatcher(k8sAPI *k8s.API, log *logging.Entry) *EndpointsWatcher DeleteFunc: ew.deleteEndpoints, UpdateFunc: func(_, obj interface{}) { ew.addEndpoints(obj) }, }) - } else { - ew.log.Debugf("Watching EndpointSlice resources") - k8sAPI.ES().Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ - AddFunc: ew.addEndpointSlice, - DeleteFunc: ew.deleteEndpointSlice, - UpdateFunc: ew.updateEndpointSlice, - }) } return ew } @@ -392,8 +396,9 @@ func (ew *EndpointsWatcher) getOrNewServicePublisher(id ServiceID) *servicePubli "ns": id.Namespace, "svc": id.Name, }), - k8sAPI: ew.k8sAPI, - ports: make(map[portAndHostname]*portPublisher), + k8sAPI: ew.k8sAPI, + ports: make(map[portAndHostname]*portPublisher), + enableEndpointSlices: ew.enableEndpointSlices, } ew.publishers[id] = sp } @@ -518,27 +523,18 @@ func (sp *servicePublisher) newPortPublisher(srcPort Port, hostname string) *por log := sp.log.WithField("port", srcPort) port := &portPublisher{ - listeners: []EndpointUpdateListener{}, - targetPort: targetPort, - srcPort: srcPort, - hostname: hostname, - exists: exists, - k8sAPI: sp.k8sAPI, - log: log, - metrics: endpointsVecs.newEndpointsMetrics(sp.metricsLabels(srcPort, hostname)), - } - - if !pkgK8s.EndpointSliceAccess(sp.k8sAPI.Client) { - // sp.log.Debugf("No EndpointSlice access, using endpoints:%v", err) - endpoints, err := sp.k8sAPI.Endpoint().Lister().Endpoints(sp.id.Namespace).Get(sp.id.Name) - if err != nil && !apierrors.IsNotFound(err) { - sp.log.Errorf("error getting endpoints: %s", err) - } - if err == nil { - port.updateEndpoints(endpoints) - } - } else { - sp.log.Debugf("Using EndpointSlice") + listeners: []EndpointUpdateListener{}, + targetPort: targetPort, + srcPort: srcPort, + hostname: hostname, + exists: exists, + k8sAPI: sp.k8sAPI, + log: log, + metrics: endpointsVecs.newEndpointsMetrics(sp.metricsLabels(srcPort, hostname)), + enableEndpointSlices: sp.enableEndpointSlices, + } + + if port.enableEndpointSlices { matchLabels := map[string]string{discovery.LabelServiceName: sp.id.Name} selector := k8slabels.Set(matchLabels).AsSelector() @@ -551,6 +547,14 @@ func (sp *servicePublisher) newPortPublisher(srcPort Port, hostname string) *por port.addEndpointSlice(slice) } } + } else { + endpoints, err := sp.k8sAPI.Endpoint().Lister().Endpoints(sp.id.Namespace).Get(sp.id.Name) + if err != nil && !apierrors.IsNotFound(err) { + sp.log.Errorf("error getting endpoints: %s", err) + } + if err == nil { + port.updateEndpoints(endpoints) + } } return port @@ -667,10 +671,10 @@ func metricLabels(resource interface{}) map[string]string { labels := map[string]string{service: serviceName, namespace: ns} - gateway, hasRemoteGateway := resLabels[pkgK8s.RemoteGatewayNameLabel] - gatewayNs, hasRemoteGatwayNs := resLabels[pkgK8s.RemoteGatewayNsLabel] - remoteClusterName, hasRemoteClusterName := resLabels[pkgK8s.RemoteClusterNameLabel] - serviceFqn, hasServiceFqn := resAnnotations[pkgK8s.RemoteServiceFqName] + gateway, hasRemoteGateway := resLabels[consts.RemoteGatewayNameLabel] + gatewayNs, hasRemoteGatwayNs := resLabels[consts.RemoteGatewayNsLabel] + remoteClusterName, hasRemoteClusterName := resLabels[consts.RemoteClusterNameLabel] + serviceFqn, hasServiceFqn := resAnnotations[consts.RemoteServiceFqName] if hasRemoteGateway && hasRemoteGatwayNs && hasRemoteClusterName && hasServiceFqn { // this means we are looking at Endpoints created for the purpose of mirroring @@ -712,11 +716,11 @@ func (pp *portPublisher) endpointSliceToAddresses(es *discovery.EndpointSlice) A if endpoint.TargetRef == nil { for _, IPAddr := range endpoint.Addresses { var authorityOverride string - if fqName, ok := es.Annotations[pkgK8s.RemoteServiceFqName]; ok { + if fqName, ok := es.Annotations[consts.RemoteServiceFqName]; ok { authorityOverride = fmt.Sprintf("%s:%d", fqName, pp.srcPort) } - identity := es.Annotations[pkgK8s.RemoteGatewayIdentity] + identity := es.Annotations[consts.RemoteGatewayIdentity] address, id := pp.newServiceRefAddress(resolvedPort, IPAddr, serviceID.Name, es.Namespace) address.Identity, address.AuthorityOverride = authorityOverride, identity addresses[id] = address @@ -754,11 +758,11 @@ func (pp *portPublisher) endpointsToAddresses(endpoints *corev1.Endpoints) Addre if endpoint.TargetRef == nil { var authorityOverride string - if fqName, ok := endpoints.Annotations[pkgK8s.RemoteServiceFqName]; ok { + if fqName, ok := endpoints.Annotations[consts.RemoteServiceFqName]; ok { authorityOverride = fmt.Sprintf("%s:%d", fqName, pp.srcPort) } - identity := endpoints.Annotations[pkgK8s.RemoteGatewayIdentity] + identity := endpoints.Annotations[consts.RemoteGatewayIdentity] address, id := pp.newServiceRefAddress(resolvedPort, endpoint.IP, endpoints.Name, endpoints.Namespace) address.Identity, address.AuthorityOverride = identity, authorityOverride @@ -851,14 +855,7 @@ func (pp *portPublisher) resolveTargetPort(subset corev1.EndpointSubset) Port { func (pp *portPublisher) updatePort(targetPort namedPort) { pp.targetPort = targetPort - if !pkgK8s.EndpointSliceAccess(pp.k8sAPI.Client) { - endpoints, err := pp.k8sAPI.Endpoint().Lister().Endpoints(pp.id.Namespace).Get(pp.id.Name) - if err == nil { - pp.updateEndpoints(endpoints) - } else { - pp.log.Errorf("Unable to get endpoints during port update: %s", err) - } - } else { + if pp.enableEndpointSlices { matchLabels := map[string]string{discovery.LabelServiceName: pp.id.Name} selector := k8slabels.Set(matchLabels).AsSelector() @@ -871,6 +868,13 @@ func (pp *portPublisher) updatePort(targetPort namedPort) { } else { pp.log.Errorf("Unable to get EndpointSlices during port update: %s", err) } + } else { + endpoints, err := pp.k8sAPI.Endpoint().Lister().Endpoints(pp.id.Namespace).Get(pp.id.Name) + if err == nil { + pp.updateEndpoints(endpoints) + } else { + pp.log.Errorf("Unable to get endpoints during port update: %s", err) + } } } diff --git a/controller/api/destination/watcher/endpoints_watcher_test.go b/controller/api/destination/watcher/endpoints_watcher_test.go index 2d06ca759bcc2..a5811c84382e6 100644 --- a/controller/api/destination/watcher/endpoints_watcher_test.go +++ b/controller/api/destination/watcher/endpoints_watcher_test.go @@ -140,8 +140,6 @@ func (bel *bufferingEndpointListenerWithResVersion) Remove(set AddressSet) { func (bel *bufferingEndpointListenerWithResVersion) NoEndpoints(exists bool) {} -//TODO: Uncomment EndpointSlice related test cases -// once EndpointSlices are opt-in and supported func TestEndpointsWatcher(t *testing.T) { for _, tt := range []struct { serviceType string @@ -557,6 +555,55 @@ status: expectedNoEndpoints: false, expectedNoEndpointsServiceExists: false, }, + } { + tt := tt // pin + t.Run("subscribes listener to "+tt.serviceType, func(t *testing.T) { + k8sAPI, err := k8s.NewFakeAPI(tt.k8sConfigs...) + if err != nil { + t.Fatalf("NewFakeAPI returned an error: %s", err) + } + + watcher := NewEndpointsWatcher(k8sAPI, logging.WithField("test", t.Name()), false) + + k8sAPI.Sync(nil) + + listener := newBufferingEndpointListener() + + err = watcher.Subscribe(tt.id, tt.port, tt.hostname, listener) + if tt.expectedError && err == nil { + t.Fatal("Expected error but was ok") + } + if !tt.expectedError && err != nil { + t.Fatalf("Expected no error, got [%s]", err) + } + + listener.ExpectAdded(tt.expectedAddresses, t) + + if listener.endpointsAreNotCalled() != tt.expectedNoEndpoints { + t.Fatalf("Expected noEndpointsCalled to be [%t], got [%t]", + tt.expectedNoEndpoints, listener.endpointsAreNotCalled()) + } + + if listener.endpointsDoNotExist() != tt.expectedNoEndpointsServiceExists { + t.Fatalf("Expected noEndpointsExist to be [%t], got [%t]", + tt.expectedNoEndpointsServiceExists, listener.endpointsDoNotExist()) + } + }) + } +} + +func TestEndpointsWatcherWithEndpointSlices(t *testing.T) { + for _, tt := range []struct { + serviceType string + k8sConfigs []string + id ServiceID + hostname string + port Port + expectedAddresses []string + expectedNoEndpoints bool + expectedNoEndpointsServiceExists bool + expectedError bool + }{ { serviceType: "local services with EndpointSlice", k8sConfigs: []string{` @@ -675,17 +722,14 @@ status: }, id: ServiceID{Name: "name-1", Namespace: "ns"}, port: 8989, - // expectedAddresses: []string{ - // "172.17.0.12:8989", - // "172.17.0.19:8989", - // "172.17.0.20:8989", - // "172.17.0.21:8989", - // }, - expectedAddresses: []string{}, - //expectedNoEndpoints: false, - expectedNoEndpoints: true, - //expectedNoEndpointsServiceExists: false, - expectedNoEndpointsServiceExists: true, + expectedAddresses: []string{ + "172.17.0.12:8989", + "172.17.0.19:8989", + "172.17.0.20:8989", + "172.17.0.21:8989", + }, + expectedNoEndpoints: false, + expectedNoEndpointsServiceExists: false, expectedError: false, }, { @@ -772,14 +816,11 @@ status: podIP: 172.17.0.25 phase: Running`, }, - id: ServiceID{Name: "name-1", Namespace: "ns"}, - port: 8989, - //expectedAddresses: []string{"172.17.0.25:8989"}, - expectedAddresses: []string{}, - //expectedNoEndpoints: false, - expectedNoEndpoints: true, - //expectedNoEndpointsServiceExists: false, - expectedNoEndpointsServiceExists: true, + id: ServiceID{Name: "name-1", Namespace: "ns"}, + port: 8989, + expectedAddresses: []string{"172.17.0.25:8989"}, + expectedNoEndpoints: false, + expectedNoEndpointsServiceExists: false, expectedError: false, }, { @@ -978,15 +1019,12 @@ status: phase: Running podIP: 172.17.0.20`, }, - id: ServiceID{Name: "name-1", Namespace: "ns"}, - hostname: "name-1-3", - port: 6000, - //expectedAddresses: []string{"172.17.0.20:6000"}, - expectedAddresses: []string{}, - //expectedNoEndpoints: false, - expectedNoEndpoints: true, - //expectedNoEndpointsServiceExists: false, - expectedNoEndpointsServiceExists: true, + id: ServiceID{Name: "name-1", Namespace: "ns"}, + hostname: "name-1-3", + port: 6000, + expectedAddresses: []string{"172.17.0.20:6000"}, + expectedNoEndpoints: false, + expectedNoEndpointsServiceExists: false, expectedError: false, }, { @@ -1133,8 +1171,7 @@ status: expectedNoEndpoints: true, expectedNoEndpointsServiceExists: true, expectedError: false, - }, - } { + }} { tt := tt // pin t.Run("subscribes listener to "+tt.serviceType, func(t *testing.T) { k8sAPI, err := k8s.NewFakeAPI(tt.k8sConfigs...) @@ -1142,7 +1179,7 @@ status: t.Fatalf("NewFakeAPI returned an error: %s", err) } - watcher := NewEndpointsWatcher(k8sAPI, logging.WithField("test", t.Name())) + watcher := NewEndpointsWatcher(k8sAPI, logging.WithField("test", t.Name()), true) k8sAPI.Sync(nil) @@ -1207,6 +1244,84 @@ status: phase: Running podIP: 172.17.0.12`} + for _, tt := range []struct { + serviceType string + k8sConfigs []string + id ServiceID + hostname string + port Port + objectToDelete interface{} + deletingServices bool + }{ + { + serviceType: "can delete endpoints", + k8sConfigs: k8sConfigs, + id: ServiceID{Name: "name1", Namespace: "ns"}, + port: 8989, + hostname: "name1-1", + objectToDelete: &corev1.Endpoints{ObjectMeta: metav1.ObjectMeta{Name: "name1", Namespace: "ns"}}, + }, + { + serviceType: "can delete endpoints when wrapped in a DeletedFinalStateUnknown", + k8sConfigs: k8sConfigs, + id: ServiceID{Name: "name1", Namespace: "ns"}, + port: 8989, + hostname: "name1-1", + objectToDelete: &corev1.Endpoints{ObjectMeta: metav1.ObjectMeta{Name: "name1", Namespace: "ns"}}, + }, + { + serviceType: "can delete services", + k8sConfigs: k8sConfigs, + id: ServiceID{Name: "name1", Namespace: "ns"}, + port: 8989, + hostname: "name1-1", + objectToDelete: &corev1.Service{ObjectMeta: metav1.ObjectMeta{Name: "name1", Namespace: "ns"}}, + deletingServices: true, + }, + { + serviceType: "can delete services when wrapped in a DeletedFinalStateUnknown", + k8sConfigs: k8sConfigs, + id: ServiceID{Name: "name1", Namespace: "ns"}, + port: 8989, + hostname: "name1-1", + objectToDelete: &corev1.Service{ObjectMeta: metav1.ObjectMeta{Name: "name1", Namespace: "ns"}}, + deletingServices: true, + }, + } { + + tt := tt // pin + t.Run("subscribes listener to "+tt.serviceType, func(t *testing.T) { + k8sAPI, err := k8s.NewFakeAPI(tt.k8sConfigs...) + if err != nil { + t.Fatalf("NewFakeAPI returned an error: %s", err) + } + + watcher := NewEndpointsWatcher(k8sAPI, logging.WithField("test", t.Name()), false) + + k8sAPI.Sync(nil) + + listener := newBufferingEndpointListener() + + err = watcher.Subscribe(tt.id, tt.port, tt.hostname, listener) + if err != nil { + t.Fatal(err) + } + + if tt.deletingServices { + watcher.deleteService(tt.objectToDelete) + } else { + watcher.deleteEndpoints(tt.objectToDelete) + } + + if !listener.endpointsAreNotCalled() { + t.Fatal("Expected NoEndpoints to be Called") + } + }) + + } +} + +func TestEndpointsWatcherDeletionWithEndpointSlices(t *testing.T) { k8sConfigsWithES := []string{` kind: APIResourceList apiVersion: v1 @@ -1276,40 +1391,6 @@ status: deletingServices bool hasSliceAccess bool }{ - { - serviceType: "can delete endpoints", - k8sConfigs: k8sConfigs, - id: ServiceID{Name: "name1", Namespace: "ns"}, - port: 8989, - hostname: "name1-1", - objectToDelete: &corev1.Endpoints{ObjectMeta: metav1.ObjectMeta{Name: "name1", Namespace: "ns"}}, - }, - { - serviceType: "can delete endpoints when wrapped in a DeletedFinalStateUnknown", - k8sConfigs: k8sConfigs, - id: ServiceID{Name: "name1", Namespace: "ns"}, - port: 8989, - hostname: "name1-1", - objectToDelete: &corev1.Endpoints{ObjectMeta: metav1.ObjectMeta{Name: "name1", Namespace: "ns"}}, - }, - { - serviceType: "can delete services", - k8sConfigs: k8sConfigs, - id: ServiceID{Name: "name1", Namespace: "ns"}, - port: 8989, - hostname: "name1-1", - objectToDelete: &corev1.Service{ObjectMeta: metav1.ObjectMeta{Name: "name1", Namespace: "ns"}}, - deletingServices: true, - }, - { - serviceType: "can delete services when wrapped in a DeletedFinalStateUnknown", - k8sConfigs: k8sConfigs, - id: ServiceID{Name: "name1", Namespace: "ns"}, - port: 8989, - hostname: "name1-1", - objectToDelete: &corev1.Service{ObjectMeta: metav1.ObjectMeta{Name: "name1", Namespace: "ns"}}, - deletingServices: true, - }, { serviceType: "can delete EndpointSlices", k8sConfigs: k8sConfigsWithES, @@ -1329,7 +1410,6 @@ status: hasSliceAccess: true, }, } { - tt := tt // pin t.Run("subscribes listener to "+tt.serviceType, func(t *testing.T) { k8sAPI, err := k8s.NewFakeAPI(tt.k8sConfigs...) @@ -1337,7 +1417,7 @@ status: t.Fatalf("NewFakeAPI returned an error: %s", err) } - watcher := NewEndpointsWatcher(k8sAPI, logging.WithField("test", t.Name())) + watcher := NewEndpointsWatcher(k8sAPI, logging.WithField("test", t.Name()), true) k8sAPI.Sync(nil) @@ -1348,19 +1428,12 @@ status: t.Fatal(err) } - if tt.deletingServices { - watcher.deleteService(tt.objectToDelete) - } else if tt.hasSliceAccess { - watcher.deleteEndpointSlice(tt.objectToDelete) - } else { - watcher.deleteEndpoints(tt.objectToDelete) - } + watcher.deleteEndpointSlice(tt.objectToDelete) if !listener.endpointsAreNotCalled() { t.Fatal("Expected NoEndpoints to be Called") } }) - } } @@ -1531,7 +1604,7 @@ subsets: t.Fatalf("NewFakeAPI returned an error: %s", err) } - watcher := NewEndpointsWatcher(k8sAPI, logging.WithField("test", t.Name())) + watcher := NewEndpointsWatcher(k8sAPI, logging.WithField("test", t.Name()), false) k8sAPI.Sync(nil) @@ -1691,7 +1764,7 @@ subsets: t.Fatalf("NewFakeAPI returned an error: %s", err) } - watcher := NewEndpointsWatcher(k8sAPI, logging.WithField("test", t.Name())) + watcher := NewEndpointsWatcher(k8sAPI, logging.WithField("test", t.Name()), false) k8sAPI.Sync(nil) @@ -1814,7 +1887,7 @@ status: t.Fatalf("NewFakeAPI returned an error: %s", err) } - watcher := NewEndpointsWatcher(k8sAPI, logging.WithField("test", t.Name())) + watcher := NewEndpointsWatcher(k8sAPI, logging.WithField("test", t.Name()), false) k8sAPI.Sync(nil) diff --git a/controller/api/destination/watcher/ip_watcher_test.go b/controller/api/destination/watcher/ip_watcher_test.go index 7e1bc9a17cd2a..3836632ca32a3 100644 --- a/controller/api/destination/watcher/ip_watcher_test.go +++ b/controller/api/destination/watcher/ip_watcher_test.go @@ -431,7 +431,7 @@ status: t.Fatalf("NewFakeAPI returned an error: %s", err) } - endpoints := NewEndpointsWatcher(k8sAPI, logging.WithField("test", t.Name())) + endpoints := NewEndpointsWatcher(k8sAPI, logging.WithField("test", t.Name()), false) watcher := NewIPWatcher(k8sAPI, endpoints, logging.WithField("test", t.Name())) k8sAPI.Sync(nil) @@ -565,7 +565,7 @@ status: t.Fatalf("NewFakeAPI returned an error: %s", err) } - endpoints := NewEndpointsWatcher(k8sAPI, logging.WithField("test", t.Name())) + endpoints := NewEndpointsWatcher(k8sAPI, logging.WithField("test", t.Name()), false) watcher := NewIPWatcher(k8sAPI, endpoints, logging.WithField("test", t.Name())) k8sAPI.Sync(nil) @@ -656,7 +656,7 @@ status: t.Fatalf("NewFakeAPI returned an error: %s", err) } - endpoints := NewEndpointsWatcher(k8sAPI, logging.WithField("test", t.Name())) + endpoints := NewEndpointsWatcher(k8sAPI, logging.WithField("test", t.Name()), false) watcher := NewIPWatcher(k8sAPI, endpoints, logging.WithField("test", t.Name())) k8sAPI.Sync(nil) @@ -700,7 +700,7 @@ spec: t.Fatalf("NewFakeAPI returned an error: %s", err) } - endpoints := NewEndpointsWatcher(k8sAPI, logging.WithField("test", t.Name())) + endpoints := NewEndpointsWatcher(k8sAPI, logging.WithField("test", t.Name()), false) watcher := NewIPWatcher(k8sAPI, endpoints, logging.WithField("test", t.Name())) k8sAPI.Sync(nil) diff --git a/controller/cmd/destination/main.go b/controller/cmd/destination/main.go index cb7d0db4fd3ec..e9db611d38023 100644 --- a/controller/cmd/destination/main.go +++ b/controller/cmd/destination/main.go @@ -35,14 +35,6 @@ func Main(args []string) { stop := make(chan os.Signal, 1) signal.Notify(stop, os.Interrupt, syscall.SIGTERM) - k8sAPI, err := k8s.InitializeAPI( - *kubeConfigPath, true, - k8s.Endpoint, k8s.ES, k8s.Pod, k8s.RS, k8s.Svc, k8s.SP, k8s.TS, k8s.Job, - ) - if err != nil { - log.Fatalf("Failed to initialize K8s API: %s", err) - } - done := make(chan struct{}) lis, err := net.Listen("tcp", *addr) @@ -75,11 +67,35 @@ func Main(args []string) { } } + enableEndpointSlices := global.GetEndpointSliceEnabled() + + var k8sAPI *k8s.API + if enableEndpointSlices { + k8sAPI, err = k8s.InitializeAPI( + *kubeConfigPath, true, + k8s.Endpoint, k8s.ES, k8s.Pod, k8s.RS, k8s.Svc, k8s.SP, k8s.TS, k8s.Job, + ) + } else { + k8sAPI, err = k8s.InitializeAPI( + *kubeConfigPath, true, + k8s.Endpoint, k8s.Pod, k8s.RS, k8s.Svc, k8s.SP, k8s.TS, k8s.Job, + ) + } + if err != nil { + log.Fatalf("Failed to initialize K8s API: %s", err) + } + + err = consts.EndpointSliceAccess(k8sAPI.Client) + if enableEndpointSlices && err != nil { + log.Fatalf("Failed to start with EndpointSlices enabled: %s", err) + } + server := destination.NewServer( *addr, *controllerNamespace, trustDomain, *enableH2Upgrade, + enableEndpointSlices, k8sAPI, clusterDomain, done, diff --git a/controller/gen/config/config.pb.go b/controller/gen/config/config.pb.go index 8373414073de8..fb9986801039d 100644 --- a/controller/gen/config/config.pb.go +++ b/controller/gen/config/config.pb.go @@ -104,7 +104,8 @@ type Global struct { AutoInjectContext *AutoInjectContext `protobuf:"bytes,6,opt,name=auto_inject_context,json=autoInjectContext,proto3" json:"auto_inject_context,omitempty"` OmitWebhookSideEffects bool `protobuf:"varint,7,opt,name=omitWebhookSideEffects,proto3" json:"omitWebhookSideEffects,omitempty"` // Override default `cluster.local` - ClusterDomain string `protobuf:"bytes,8,opt,name=cluster_domain,json=clusterDomain,proto3" json:"cluster_domain,omitempty"` + ClusterDomain string `protobuf:"bytes,8,opt,name=cluster_domain,json=clusterDomain,proto3" json:"cluster_domain,omitempty"` + EndpointSliceEnabled bool `protobuf:"varint,9,opt,name=endpoint_slice_enabled,json=endpointSliceEnabled,proto3" json:"endpoint_slice_enabled,omitempty"` } func (x *Global) Reset() { @@ -189,6 +190,13 @@ func (x *Global) GetClusterDomain() string { return "" } +func (x *Global) GetEndpointSliceEnabled() bool { + if x != nil { + return x.EndpointSliceEnabled + } + return false +} + type Proxy struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -890,7 +898,7 @@ var file_config_config_proto_rawDesc = []byte{ 0x07, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x6c, 0x69, 0x6e, 0x6b, 0x65, 0x72, 0x64, 0x32, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x52, 0x07, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, - 0x6c, 0x22, 0xf4, 0x02, 0x0a, 0x06, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x12, 0x2b, 0x0a, 0x11, + 0x6c, 0x22, 0xaa, 0x03, 0x0a, 0x06, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x12, 0x2b, 0x0a, 0x11, 0x6c, 0x69, 0x6e, 0x6b, 0x65, 0x72, 0x64, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x6c, 0x69, 0x6e, 0x6b, 0x65, 0x72, 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6e, 0x69, @@ -913,124 +921,127 @@ var file_config_config_proto_rawDesc = []byte{ 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x53, 0x69, 0x64, 0x65, 0x45, 0x66, 0x66, 0x65, 0x63, 0x74, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6c, 0x75, 0x73, 0x74, - 0x65, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x22, 0xfa, 0x07, 0x0a, 0x05, 0x50, 0x72, 0x6f, - 0x78, 0x79, 0x12, 0x37, 0x0a, 0x0b, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x69, 0x6d, 0x61, 0x67, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6c, 0x69, 0x6e, 0x6b, 0x65, 0x72, - 0x64, 0x32, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, - 0x0a, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x40, 0x0a, 0x10, 0x70, - 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x5f, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6c, 0x69, 0x6e, 0x6b, 0x65, 0x72, 0x64, 0x32, - 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x0e, 0x70, - 0x72, 0x6f, 0x78, 0x79, 0x49, 0x6e, 0x69, 0x74, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x38, 0x0a, - 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6c, 0x69, 0x6e, 0x6b, 0x65, 0x72, 0x64, 0x32, 0x2e, 0x63, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, - 0x72, 0x6f, 0x6c, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x4c, 0x0a, 0x14, 0x69, 0x67, 0x6e, 0x6f, 0x72, - 0x65, 0x5f, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x18, - 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6c, 0x69, 0x6e, 0x6b, 0x65, 0x72, 0x64, 0x32, - 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x52, 0x61, 0x6e, 0x67, - 0x65, 0x52, 0x12, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, - 0x50, 0x6f, 0x72, 0x74, 0x73, 0x12, 0x4e, 0x0a, 0x15, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x5f, - 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x18, 0x05, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6c, 0x69, 0x6e, 0x6b, 0x65, 0x72, 0x64, 0x32, 0x2e, - 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x52, 0x61, 0x6e, 0x67, 0x65, - 0x52, 0x13, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, - 0x50, 0x6f, 0x72, 0x74, 0x73, 0x12, 0x38, 0x0a, 0x0c, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, - 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6c, 0x69, + 0x65, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x34, 0x0a, 0x16, 0x65, 0x6e, 0x64, 0x70, + 0x6f, 0x69, 0x6e, 0x74, 0x5f, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, + 0x65, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, + 0x6e, 0x74, 0x53, 0x6c, 0x69, 0x63, 0x65, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x22, 0xfa, + 0x07, 0x0a, 0x05, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x12, 0x37, 0x0a, 0x0b, 0x70, 0x72, 0x6f, 0x78, + 0x79, 0x5f, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, + 0x6c, 0x69, 0x6e, 0x6b, 0x65, 0x72, 0x64, 0x32, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, + 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x49, 0x6d, 0x61, 0x67, + 0x65, 0x12, 0x40, 0x0a, 0x10, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x5f, + 0x69, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6c, 0x69, + 0x6e, 0x6b, 0x65, 0x72, 0x64, 0x32, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x49, 0x6d, + 0x61, 0x67, 0x65, 0x52, 0x0e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x49, 0x6e, 0x69, 0x74, 0x49, 0x6d, + 0x61, 0x67, 0x65, 0x12, 0x38, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x5f, 0x70, + 0x6f, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6c, 0x69, 0x6e, 0x6b, + 0x65, 0x72, 0x64, 0x32, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x50, 0x6f, 0x72, 0x74, + 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x4c, 0x0a, + 0x14, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x5f, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, + 0x70, 0x6f, 0x72, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6c, 0x69, 0x6e, 0x6b, 0x65, 0x72, 0x64, 0x32, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x50, 0x6f, - 0x72, 0x74, 0x52, 0x0b, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x50, 0x6f, 0x72, 0x74, 0x12, - 0x34, 0x0a, 0x0a, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x07, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6c, 0x69, 0x6e, 0x6b, 0x65, 0x72, 0x64, 0x32, 0x2e, 0x63, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x52, 0x09, 0x61, 0x64, 0x6d, 0x69, - 0x6e, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x3a, 0x0a, 0x0d, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, - 0x64, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6c, - 0x69, 0x6e, 0x6b, 0x65, 0x72, 0x64, 0x32, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x50, - 0x6f, 0x72, 0x74, 0x52, 0x0c, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x50, 0x6f, 0x72, - 0x74, 0x12, 0x41, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x09, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x6c, 0x69, 0x6e, 0x6b, 0x65, 0x72, 0x64, 0x32, 0x2e, 0x63, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x75, 0x69, - 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x55, 0x69, - 0x64, 0x12, 0x36, 0x0a, 0x09, 0x6c, 0x6f, 0x67, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x0b, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x6c, 0x69, 0x6e, 0x6b, 0x65, 0x72, 0x64, 0x32, 0x2e, - 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, - 0x08, 0x6c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x3a, 0x0a, 0x19, 0x64, 0x69, 0x73, - 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x70, 0x72, - 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x17, 0x64, 0x69, - 0x73, 0x61, 0x62, 0x6c, 0x65, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x50, 0x72, 0x6f, - 0x66, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x76, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x70, 0x72, - 0x6f, 0x78, 0x79, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x37, 0x0a, 0x18, 0x70, 0x72, - 0x6f, 0x78, 0x79, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x5f, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x5f, 0x76, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x15, 0x70, 0x72, - 0x6f, 0x78, 0x79, 0x49, 0x6e, 0x69, 0x74, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x56, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x12, 0x37, 0x0a, 0x0b, 0x64, 0x65, 0x62, 0x75, 0x67, 0x5f, 0x69, 0x6d, 0x61, - 0x67, 0x65, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6c, 0x69, 0x6e, 0x6b, 0x65, - 0x72, 0x64, 0x32, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x49, 0x6d, 0x61, 0x67, 0x65, - 0x52, 0x0a, 0x64, 0x65, 0x62, 0x75, 0x67, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x2e, 0x0a, 0x13, - 0x64, 0x65, 0x62, 0x75, 0x67, 0x5f, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x18, 0x10, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x64, 0x65, 0x62, 0x75, 0x67, - 0x49, 0x6d, 0x61, 0x67, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x38, 0x0a, 0x18, - 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x67, 0x65, 0x74, 0x5f, - 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x52, 0x16, - 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x47, 0x65, 0x74, 0x4e, 0x65, - 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x6f, 0x67, 0x5f, 0x66, 0x6f, - 0x72, 0x6d, 0x61, 0x74, 0x18, 0x12, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6c, 0x6f, 0x67, 0x46, - 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x22, 0x47, 0x0a, 0x05, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x1d, - 0x0a, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x09, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, - 0x0b, 0x70, 0x75, 0x6c, 0x6c, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0a, 0x70, 0x75, 0x6c, 0x6c, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x22, 0x1a, - 0x0a, 0x04, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x22, 0x2a, 0x0a, 0x09, 0x50, 0x6f, - 0x72, 0x74, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x6f, 0x72, 0x74, 0x5f, - 0x72, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x6f, 0x72, - 0x74, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x22, 0x9e, 0x01, 0x0a, 0x14, 0x52, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, - 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x63, 0x70, 0x75, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x43, 0x70, 0x75, - 0x12, 0x25, 0x0a, 0x0e, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x6d, 0x65, 0x6d, 0x6f, - 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x12, 0x1b, 0x0a, 0x09, 0x6c, 0x69, 0x6d, 0x69, 0x74, - 0x5f, 0x63, 0x70, 0x75, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x69, 0x6d, 0x69, - 0x74, 0x43, 0x70, 0x75, 0x12, 0x21, 0x0a, 0x0c, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x5f, 0x6d, 0x65, - 0x6d, 0x6f, 0x72, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6c, 0x69, 0x6d, 0x69, - 0x74, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x22, 0x17, 0x0a, 0x11, 0x41, 0x75, 0x74, 0x6f, 0x49, - 0x6e, 0x6a, 0x65, 0x63, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x3a, 0x02, 0x18, 0x01, - 0x22, 0x8d, 0x02, 0x0a, 0x0f, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, - 0x74, 0x65, 0x78, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x74, 0x72, 0x75, 0x73, 0x74, 0x5f, 0x64, 0x6f, - 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x74, 0x72, 0x75, 0x73, - 0x74, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x2a, 0x0a, 0x11, 0x74, 0x72, 0x75, 0x73, 0x74, - 0x5f, 0x61, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x73, 0x5f, 0x70, 0x65, 0x6d, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0f, 0x74, 0x72, 0x75, 0x73, 0x74, 0x41, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x73, - 0x50, 0x65, 0x6d, 0x12, 0x46, 0x0a, 0x11, 0x69, 0x73, 0x73, 0x75, 0x61, 0x6e, 0x63, 0x65, 0x5f, - 0x6c, 0x69, 0x66, 0x65, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, - 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x10, 0x69, 0x73, 0x73, 0x75, 0x61, - 0x6e, 0x63, 0x65, 0x4c, 0x69, 0x66, 0x65, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x4b, 0x0a, 0x14, 0x63, - 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x73, 0x6b, 0x65, 0x77, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x61, - 0x6e, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x12, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x6b, 0x65, 0x77, 0x41, - 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x63, 0x68, 0x65, - 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x65, - 0x22, 0x20, 0x0a, 0x08, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x14, 0x0a, 0x05, - 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, 0x65, 0x76, - 0x65, 0x6c, 0x22, 0x97, 0x01, 0x0a, 0x07, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x12, 0x1f, - 0x0a, 0x0b, 0x63, 0x6c, 0x69, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6c, 0x69, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, - 0x33, 0x0a, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, + 0x72, 0x74, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x12, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x49, + 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x50, 0x6f, 0x72, 0x74, 0x73, 0x12, 0x4e, 0x0a, 0x15, 0x69, + 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x5f, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x70, + 0x6f, 0x72, 0x74, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6c, 0x69, 0x6e, + 0x6b, 0x65, 0x72, 0x64, 0x32, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x50, 0x6f, 0x72, + 0x74, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x13, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x4f, 0x75, + 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x50, 0x6f, 0x72, 0x74, 0x73, 0x12, 0x38, 0x0a, 0x0c, 0x69, + 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x15, 0x2e, 0x6c, 0x69, 0x6e, 0x6b, 0x65, 0x72, 0x64, 0x32, 0x2e, 0x63, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x52, 0x0b, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, + 0x64, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x34, 0x0a, 0x0a, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x5f, 0x70, + 0x6f, 0x72, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6c, 0x69, 0x6e, 0x6b, + 0x65, 0x72, 0x64, 0x32, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x50, 0x6f, 0x72, 0x74, + 0x52, 0x09, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x3a, 0x0a, 0x0d, 0x6f, + 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x08, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6c, 0x69, 0x6e, 0x6b, 0x65, 0x72, 0x64, 0x32, 0x2e, 0x63, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x52, 0x0c, 0x6f, 0x75, 0x74, 0x62, 0x6f, + 0x75, 0x6e, 0x64, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x41, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x6c, 0x69, 0x6e, 0x6b, + 0x65, 0x72, 0x64, 0x32, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x52, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, + 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x72, + 0x6f, 0x78, 0x79, 0x5f, 0x75, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x70, + 0x72, 0x6f, 0x78, 0x79, 0x55, 0x69, 0x64, 0x12, 0x36, 0x0a, 0x09, 0x6c, 0x6f, 0x67, 0x5f, 0x6c, + 0x65, 0x76, 0x65, 0x6c, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x6c, 0x69, 0x6e, + 0x6b, 0x65, 0x72, 0x64, 0x32, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x4c, 0x6f, 0x67, + 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, 0x08, 0x6c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, + 0x3a, 0x0a, 0x19, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x65, 0x78, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x6c, 0x5f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x0c, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x17, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x45, 0x78, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x6c, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x70, + 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0d, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0c, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x12, 0x37, 0x0a, 0x18, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x5f, 0x69, + 0x6d, 0x61, 0x67, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0e, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x15, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x49, 0x6e, 0x69, 0x74, 0x49, 0x6d, 0x61, + 0x67, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x37, 0x0a, 0x0b, 0x64, 0x65, 0x62, + 0x75, 0x67, 0x5f, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6c, 0x69, 0x6e, 0x6b, 0x65, 0x72, 0x64, 0x32, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x2e, 0x46, 0x6c, 0x61, 0x67, 0x52, 0x05, 0x66, - 0x6c, 0x61, 0x67, 0x73, 0x1a, 0x30, 0x0a, 0x04, 0x46, 0x6c, 0x61, 0x67, 0x12, 0x12, 0x0a, 0x04, - 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, - 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x42, 0x33, 0x5a, 0x31, - 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x69, 0x6e, 0x6b, 0x65, - 0x72, 0x64, 0x2f, 0x6c, 0x69, 0x6e, 0x6b, 0x65, 0x72, 0x64, 0x32, 0x2f, 0x63, 0x6f, 0x6e, 0x74, - 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x2e, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x0a, 0x64, 0x65, 0x62, 0x75, 0x67, 0x49, 0x6d, 0x61, + 0x67, 0x65, 0x12, 0x2e, 0x0a, 0x13, 0x64, 0x65, 0x62, 0x75, 0x67, 0x5f, 0x69, 0x6d, 0x61, 0x67, + 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x10, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x11, 0x64, 0x65, 0x62, 0x75, 0x67, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x12, 0x38, 0x0a, 0x18, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x67, 0x65, 0x74, 0x5f, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x18, 0x11, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x16, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x47, 0x65, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x12, 0x1d, 0x0a, 0x0a, + 0x6c, 0x6f, 0x67, 0x5f, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x18, 0x12, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x09, 0x6c, 0x6f, 0x67, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x22, 0x47, 0x0a, 0x05, 0x49, + 0x6d, 0x61, 0x67, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x5f, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x4e, + 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x75, 0x6c, 0x6c, 0x5f, 0x70, 0x6f, 0x6c, 0x69, + 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x75, 0x6c, 0x6c, 0x50, 0x6f, + 0x6c, 0x69, 0x63, 0x79, 0x22, 0x1a, 0x0a, 0x04, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x12, 0x0a, 0x04, + 0x70, 0x6f, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, + 0x22, 0x2a, 0x0a, 0x09, 0x50, 0x6f, 0x72, 0x74, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x1d, 0x0a, + 0x0a, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x09, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x22, 0x9e, 0x01, 0x0a, + 0x14, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, + 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x5f, 0x63, 0x70, 0x75, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x43, 0x70, 0x75, 0x12, 0x25, 0x0a, 0x0e, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x5f, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x12, 0x1b, 0x0a, + 0x09, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x5f, 0x63, 0x70, 0x75, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x43, 0x70, 0x75, 0x12, 0x21, 0x0a, 0x0c, 0x6c, 0x69, + 0x6d, 0x69, 0x74, 0x5f, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0b, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x22, 0x17, 0x0a, + 0x11, 0x41, 0x75, 0x74, 0x6f, 0x49, 0x6e, 0x6a, 0x65, 0x63, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, + 0x78, 0x74, 0x3a, 0x02, 0x18, 0x01, 0x22, 0x8d, 0x02, 0x0a, 0x0f, 0x49, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x74, 0x72, + 0x75, 0x73, 0x74, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0b, 0x74, 0x72, 0x75, 0x73, 0x74, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x2a, 0x0a, + 0x11, 0x74, 0x72, 0x75, 0x73, 0x74, 0x5f, 0x61, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x73, 0x5f, 0x70, + 0x65, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x74, 0x72, 0x75, 0x73, 0x74, 0x41, + 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x73, 0x50, 0x65, 0x6d, 0x12, 0x46, 0x0a, 0x11, 0x69, 0x73, 0x73, + 0x75, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x6c, 0x69, 0x66, 0x65, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x10, 0x69, 0x73, 0x73, 0x75, 0x61, 0x6e, 0x63, 0x65, 0x4c, 0x69, 0x66, 0x65, 0x74, 0x69, 0x6d, + 0x65, 0x12, 0x4b, 0x0a, 0x14, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x73, 0x6b, 0x65, 0x77, 0x5f, + 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x12, 0x63, 0x6c, 0x6f, 0x63, + 0x6b, 0x53, 0x6b, 0x65, 0x77, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x16, + 0x0a, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x73, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x22, 0x20, 0x0a, 0x08, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, + 0x65, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x22, 0x97, 0x01, 0x0a, 0x07, 0x49, 0x6e, 0x73, + 0x74, 0x61, 0x6c, 0x6c, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6c, 0x69, 0x5f, 0x76, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6c, 0x69, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x0a, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, 0x03, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x6c, 0x69, 0x6e, 0x6b, 0x65, 0x72, 0x64, 0x32, 0x2e, + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x2e, 0x46, + 0x6c, 0x61, 0x67, 0x52, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x1a, 0x30, 0x0a, 0x04, 0x46, 0x6c, + 0x61, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x4a, 0x04, 0x08, 0x01, + 0x10, 0x02, 0x42, 0x33, 0x5a, 0x31, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x6c, 0x69, 0x6e, 0x6b, 0x65, 0x72, 0x64, 0x2f, 0x6c, 0x69, 0x6e, 0x6b, 0x65, 0x72, 0x64, + 0x32, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x67, 0x65, 0x6e, + 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/controller/gen/public/public.pb.go b/controller/gen/public/public.pb.go index 471d5c06c89a3..bacb232c4c696 100644 --- a/controller/gen/public/public.pb.go +++ b/controller/gen/public/public.pb.go @@ -1774,7 +1774,7 @@ type ResourceSelection struct { // A string-formatted Kubernetes label selector as passed to `kubectl get // --selector`. // - // XXX in the future this may be superceded by a data structure that more + // XXX in the future this may be superseded by a data structure that more // richly describes a parsed label selector. LabelSelector string `protobuf:"bytes,2,opt,name=label_selector,json=labelSelector,proto3" json:"label_selector,omitempty"` } @@ -6474,10 +6474,10 @@ type ApiClient interface { ListPods(ctx context.Context, in *ListPodsRequest, opts ...grpc.CallOption) (*ListPodsResponse, error) ListServices(ctx context.Context, in *ListServicesRequest, opts ...grpc.CallOption) (*ListServicesResponse, error) // Deprecated: Do not use. - // Superceded by `TapByResource`. + // Superseded by `TapByResource`. Tap(ctx context.Context, in *TapRequest, opts ...grpc.CallOption) (Api_TapClient, error) // Deprecated: Do not use. - // Superceded by tap APIServer. + // Superseded by tap APIServer. TapByResource(ctx context.Context, in *TapByResourceRequest, opts ...grpc.CallOption) (Api_TapByResourceClient, error) Version(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*VersionInfo, error) SelfCheck(ctx context.Context, in *healthcheck.SelfCheckRequest, opts ...grpc.CallOption) (*healthcheck.SelfCheckResponse, error) @@ -6648,10 +6648,10 @@ type ApiServer interface { ListPods(context.Context, *ListPodsRequest) (*ListPodsResponse, error) ListServices(context.Context, *ListServicesRequest) (*ListServicesResponse, error) // Deprecated: Do not use. - // Superceded by `TapByResource`. + // Superseded by `TapByResource`. Tap(*TapRequest, Api_TapServer) error // Deprecated: Do not use. - // Superceded by tap APIServer. + // Superseded by tap APIServer. TapByResource(*TapByResourceRequest, Api_TapByResourceServer) error Version(context.Context, *Empty) (*VersionInfo, error) SelfCheck(context.Context, *healthcheck.SelfCheckRequest) (*healthcheck.SelfCheckResponse, error) diff --git a/pkg/charts/linkerd2/values.go b/pkg/charts/linkerd2/values.go index 3b370139de865..237c8a2bbca0b 100644 --- a/pkg/charts/linkerd2/values.go +++ b/pkg/charts/linkerd2/values.go @@ -88,6 +88,7 @@ type ( ProxyContainerName string `json:"proxyContainerName"` HighAvailability bool `json:"highAvailability"` CNIEnabled bool `json:"cniEnabled"` + EnableEndpointSlices bool `json:"enableEndpointSlices"` ControlPlaneTracing bool `json:"controlPlaneTracing"` IdentityTrustAnchorsPEM string `json:"identityTrustAnchorsPEM"` IdentityTrustDomain string `json:"identityTrustDomain"` diff --git a/pkg/charts/multicluster/values.go b/pkg/charts/multicluster/values.go index 2eccf9091758c..d95aa5d6b431d 100644 --- a/pkg/charts/multicluster/values.go +++ b/pkg/charts/multicluster/values.go @@ -9,7 +9,10 @@ import ( "sigs.k8s.io/yaml" ) -const helmDefaultChartDir = "linkerd2-multicluster" +const ( + helmDefaultChartDir = "linkerd2-multicluster" + helmDefaultLinkChartDir = "linkerd2-multicluster-link" +) // Values contains the top-level elements in the Helm charts type Values struct { @@ -43,8 +46,8 @@ type Values struct { TargetClusterName string `json:"targetClusterName"` } -// NewValues returns a new instance of the Values type. -func NewValues() (*Values, error) { +// NewInstallValues returns a new instance of the Values type. +func NewInstallValues() (*Values, error) { chartDir := fmt.Sprintf("%s/", helmDefaultChartDir) v, err := readDefaults(chartDir) if err != nil { @@ -55,6 +58,18 @@ func NewValues() (*Values, error) { return v, nil } +// NewLinkValues returns a new instance of the Values type. +func NewLinkValues() (*Values, error) { + chartDir := fmt.Sprintf("%s/", helmDefaultLinkChartDir) + v, err := readDefaults(chartDir) + if err != nil { + return nil, err + } + + v.CliVersion = k8s.CreatedByAnnotationValue() + return v, nil +} + // readDefaults read all the default variables from the values.yaml file. // chartDir is the root directory of the Helm chart where values.yaml is. func readDefaults(chartDir string) (*Values, error) { diff --git a/pkg/k8s/authz.go b/pkg/k8s/authz.go index 17e443855c191..55df9ccea8d4d 100644 --- a/pkg/k8s/authz.go +++ b/pkg/k8s/authz.go @@ -109,7 +109,7 @@ func ServiceProfilesAccess(k8sClient kubernetes.Interface) error { // access to EndpointSlice resources. //TODO: Uncomment function and change return type once EndpointSlices // are supported and made opt-in through install flag -func EndpointSliceAccess(k8sClient kubernetes.Interface) bool { +func EndpointSliceAccess(k8sClient kubernetes.Interface) error { // gv := discovery.SchemeGroupVersion.String() // res, err := k8sClient.Discovery().ServerResourcesForGroupVersion(gv) // if err != nil { @@ -125,7 +125,7 @@ func EndpointSliceAccess(k8sClient kubernetes.Interface) bool { // } // return errors.New("EndpointSlice resource not found") - return false + return errors.New("EndpointSlice not supported") } //TODO: Uncomment function once EndpointSlices are supported and opt-in diff --git a/proto/config/config.proto b/proto/config/config.proto index 90b61ef120bed..042722cd663ba 100644 --- a/proto/config/config.proto +++ b/proto/config/config.proto @@ -28,6 +28,7 @@ message Global { // Override default `cluster.local` string cluster_domain = 8; + bool endpoint_slice_enabled = 9; } message Proxy { diff --git a/testutil/logs_events.go b/testutil/logs_events.go index 16ae3fd03c35b..184d6fccc9021 100644 --- a/testutil/logs_events.go +++ b/testutil/logs_events.go @@ -47,6 +47,8 @@ var ( `(Liveness|Readiness) probe failed: Get http://.*: read tcp .*: read: connection reset by peer`, `(Liveness|Readiness) probe failed: Get http://.*: net/http: request canceled .*\(Client\.Timeout exceeded while awaiting headers\)`, `Failed to update endpoint .*/linkerd-.*: Operation cannot be fulfilled on endpoints "linkerd-.*": the object has been modified; please apply your changes to the latest version and try again`, + `Error updating Endpoint Slices for Service .*/linkerd-.*: Error deleting linkerd-.* EndpointSlice for Service .*/linkerd-.*: endpointslices.discovery.k8s.io "linkerd-.*" not found`, + `Error updating Endpoint Slices for Service .*/linkerd-.*: Error updating linkerd-.* EndpointSlice for Service .*/linkerd-.*: Operation cannot be fulfilled on endpointslices.discovery.k8s.io "linkerd-.*": the object has been modified; please apply your changes to the latest version and try again`, `error killing pod: failed to "KillPodSandbox" for ".*" with KillPodSandboxError: "rpc error: code = Unknown desc`, `failed to create containerd task: failed to start io pipe copy: unable to copy pipes: containerd-shim: opening w/o fifo "/run/containerd/io.containerd.grpc.v1.cri/containers/linkerd-proxy/io/\d+/linkerd-proxy-stdout"`, }, "|")) From bf489b21835a7e5098b58adda64f5d430034e64d Mon Sep 17 00:00:00 2001 From: Alex Leong Date: Mon, 20 Jul 2020 17:10:41 -0700 Subject: [PATCH 11/14] Review feedback Signed-off-by: Alex Leong --- cli/cmd/multicluster.go | 10 ++++- .../cmd/service-mirror/cluster_watcher.go | 42 +++++++------------ .../cluster_watcher_mirroring_test.go | 11 +---- pkg/healthcheck/healthcheck_multicluster.go | 1 - 4 files changed, 26 insertions(+), 38 deletions(-) diff --git a/cli/cmd/multicluster.go b/cli/cmd/multicluster.go index 0f050005ec72f..602eea20a2f07 100644 --- a/cli/cmd/multicluster.go +++ b/cli/cmd/multicluster.go @@ -542,6 +542,14 @@ func newLinkCommand() *cobra.Command { for _, ingress := range gateway.Status.LoadBalancer.Ingress { gatewayAddresses = append(gatewayAddresses, ingress.IP) } + if len(gatewayAddresses) == 0 { + return fmt.Errorf("Gateway %s.%s has no ingress addresses", gateway.Name, gateway.Namespace) + } + + gatewayIdentity, ok := gateway.Annotations[k8s.GatewayIdentity] + if !ok || gatewayIdentity == "" { + return fmt.Errorf("Gatway %s.%s has no %s annotation", gateway.Name, gateway.Namespace, k8s.GatewayIdentity) + } probeSpec, err := mc.ExtractProbeSpec(gateway) if err != nil { @@ -562,7 +570,7 @@ func newLinkCommand() *cobra.Command { ClusterCredentialsSecret: fmt.Sprintf("cluster-credentials-%s", opts.clusterName), GatewayAddress: strings.Join(gatewayAddresses, ","), GatewayPort: gatewayPort, - GatewayIdentity: gateway.Annotations[k8s.GatewayIdentity], + GatewayIdentity: gatewayIdentity, ProbeSpec: probeSpec, } diff --git a/controller/cmd/service-mirror/cluster_watcher.go b/controller/cmd/service-mirror/cluster_watcher.go index f6b6e96fde02b..95d41d8fd2685 100644 --- a/controller/cmd/service-mirror/cluster_watcher.go +++ b/controller/cmd/service-mirror/cluster_watcher.go @@ -259,10 +259,7 @@ func (rcsw *RemoteClusterServiceWatcher) cleanupOrphanedServices() error { // created. This piece of code is responsible for doing just that. It takes care of // services, endpoints and namespaces (if needed) func (rcsw *RemoteClusterServiceWatcher) cleanupMirroredResources() error { - matchLabels := map[string]string{ - consts.MirroredResourceLabel: "true", - consts.RemoteClusterNameLabel: rcsw.link.TargetClusterName, - } + matchLabels := rcsw.getMirroredServiceLabels() services, err := rcsw.localAPIClient.Svc().Lister().List(labels.Set(matchLabels).AsSelector()) if err != nil { @@ -315,7 +312,7 @@ func (rcsw *RemoteClusterServiceWatcher) cleanupMirroredResources() error { // Deletes a locally mirrored service as it is not present on the remote cluster anymore func (rcsw *RemoteClusterServiceWatcher) handleRemoteServiceDeleted(ev *RemoteServiceDeleted) error { localServiceName := rcsw.mirroredResourceName(ev.Name) - rcsw.log.Infof("Deleting mirrored service %s/%s and its corresponding Endpoints", ev.Namespace, localServiceName) + rcsw.log.Infof("Deleting mirrored service %s/%s", ev.Namespace, localServiceName) var errors []error if err := rcsw.localAPIClient.Client.CoreV1().Services(ev.Namespace).Delete(localServiceName, &metav1.DeleteOptions{}); err != nil { if !kerrors.IsNotFound(err) { @@ -323,12 +320,6 @@ func (rcsw *RemoteClusterServiceWatcher) handleRemoteServiceDeleted(ev *RemoteSe } } - if err := rcsw.localAPIClient.Client.CoreV1().Endpoints(ev.Namespace).Delete(localServiceName, &metav1.DeleteOptions{}); err != nil { - if !kerrors.IsNotFound(err) { - errors = append(errors, fmt.Errorf("could not delete Endpoints: %s/%s: %s", ev.Namespace, localServiceName, err)) - } - } - if len(errors) > 0 { return RetryableError{errors} } @@ -350,11 +341,7 @@ func (rcsw *RemoteClusterServiceWatcher) handleRemoteServiceUpdated(ev *RemoteSe }, } - if rcsw.link.GatewayIdentity != "" { - copiedEndpoints.Annotations[consts.RemoteGatewayIdentity] = rcsw.link.GatewayIdentity - } else { - delete(copiedEndpoints.Annotations, consts.RemoteGatewayIdentity) - } + copiedEndpoints.Annotations[consts.RemoteGatewayIdentity] = rcsw.link.GatewayIdentity if _, err := rcsw.localAPIClient.Client.CoreV1().Endpoints(copiedEndpoints.Namespace).Update(copiedEndpoints); err != nil { return RetryableError{[]error{err}} @@ -646,6 +633,11 @@ func (rcsw *RemoteClusterServiceWatcher) Start() error { ) go rcsw.processEvents() + // We need to issue a RepairEndpoints immediately to populate the gateway + // mirror endpoints. + ev := RepairEndpoints{} + rcsw.eventsQueue.Add(&ev) + go func() { ticker := time.NewTicker(rcsw.repairPeriod) for { @@ -746,11 +738,7 @@ func (rcsw *RemoteClusterServiceWatcher) repairEndpoints() { }, } - if rcsw.link.GatewayIdentity != "" { - updatedEndpoints.Annotations[consts.RemoteGatewayIdentity] = rcsw.link.GatewayIdentity - } else { - delete(updatedEndpoints.Annotations, consts.RemoteGatewayIdentity) - } + updatedEndpoints.Annotations[consts.RemoteGatewayIdentity] = rcsw.link.GatewayIdentity _, err = rcsw.localAPIClient.Client.CoreV1().Services(updatedService.Namespace).Update(updatedService) if err != nil { @@ -777,12 +765,12 @@ func (rcsw *RemoteClusterServiceWatcher) createOrUpdateEndpoints(ep *corev1.Endp } else { return err } - } else { - // Exists so we should update it. - _, err = rcsw.localAPIClient.Client.CoreV1().Endpoints(ep.Namespace).Update(ep) - if err != nil { - return err - } } + // Exists so we should update it. + _, err = rcsw.localAPIClient.Client.CoreV1().Endpoints(ep.Namespace).Update(ep) + if err != nil { + return err + } + return nil } diff --git a/controller/cmd/service-mirror/cluster_watcher_mirroring_test.go b/controller/cmd/service-mirror/cluster_watcher_mirroring_test.go index f2b55e5e526e4..758b7b7bfb1e2 100644 --- a/controller/cmd/service-mirror/cluster_watcher_mirroring_test.go +++ b/controller/cmd/service-mirror/cluster_watcher_mirroring_test.go @@ -51,15 +51,8 @@ func (tc *mirroringTestCase) run(t *testing.T) { } if tc.expectedLocalEndpoints == nil { - // ensure the are no local endpoints - endpoints, err := localAPI.Client.CoreV1().Endpoints(corev1.NamespaceAll).List(metav1.ListOptions{}) - if err != nil { - t.Fatal(err) - } - if len(endpoints.Items) > 0 { - t.Fatalf("Was expecting no local endpoints but instead found %d", len(endpoints.Items)) - - } + // In a real Kubernetes cluster, deleting the service is sufficient + // to delete the endpoints. } else { for _, expected := range tc.expectedLocalEndpoints { actual, err := localAPI.Client.CoreV1().Endpoints(expected.Namespace).Get(expected.Name, metav1.GetOptions{}) diff --git a/pkg/healthcheck/healthcheck_multicluster.go b/pkg/healthcheck/healthcheck_multicluster.go index 5fb26eac2dbeb..fc91757a5b5c1 100644 --- a/pkg/healthcheck/healthcheck_multicluster.go +++ b/pkg/healthcheck/healthcheck_multicluster.go @@ -109,7 +109,6 @@ func (hc *HealthChecker) multiClusterCategory() []category { { description: "all gateway mirrors are healthy", hintAnchor: "l5d-multicluster-gateways-endpoints", - warning: true, check: func(ctx context.Context) error { if hc.Options.MultiCluster { return hc.checkIfGatewayMirrorsHaveEndpoints(ctx) From f4f62e79edd46040d6498da95125b24e0d56233a Mon Sep 17 00:00:00 2001 From: Alex Leong Date: Tue, 21 Jul 2020 13:57:24 -0700 Subject: [PATCH 12/14] Fix assignment to nil map Signed-off-by: Alex Leong --- controller/cmd/service-mirror/cluster_watcher.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/controller/cmd/service-mirror/cluster_watcher.go b/controller/cmd/service-mirror/cluster_watcher.go index 95d41d8fd2685..890b34cfea9e1 100644 --- a/controller/cmd/service-mirror/cluster_watcher.go +++ b/controller/cmd/service-mirror/cluster_watcher.go @@ -341,6 +341,9 @@ func (rcsw *RemoteClusterServiceWatcher) handleRemoteServiceUpdated(ev *RemoteSe }, } + if copiedEndpoints.Annotations == nil { + copiedEndpoints.Annotations = make(map[string]string) + } copiedEndpoints.Annotations[consts.RemoteGatewayIdentity] = rcsw.link.GatewayIdentity if _, err := rcsw.localAPIClient.Client.CoreV1().Endpoints(copiedEndpoints.Namespace).Update(copiedEndpoints); err != nil { @@ -738,6 +741,9 @@ func (rcsw *RemoteClusterServiceWatcher) repairEndpoints() { }, } + if updatedEndpoints.Annotations == nil { + updatedEndpoints.Annotations = make(map[string]string) + } updatedEndpoints.Annotations[consts.RemoteGatewayIdentity] = rcsw.link.GatewayIdentity _, err = rcsw.localAPIClient.Client.CoreV1().Services(updatedService.Namespace).Update(updatedService) From d4fc5ee55612c2df6d3e53e888ea148e2cdad2da Mon Sep 17 00:00:00 2001 From: Alex Leong Date: Wed, 22 Jul 2020 11:12:18 -0700 Subject: [PATCH 13/14] Add --registry flag to multicluster link command Signed-off-by: Alex Leong --- cli/cmd/multicluster.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cli/cmd/multicluster.go b/cli/cmd/multicluster.go index 602eea20a2f07..4062c876ce669 100644 --- a/cli/cmd/multicluster.go +++ b/cli/cmd/multicluster.go @@ -624,11 +624,12 @@ func newLinkCommand() *cobra.Command { cmd.Flags().StringVar(&opts.clusterName, "cluster-name", "", "Cluster name") cmd.Flags().StringVar(&opts.apiServerAddress, "api-server-address", "", "The api server address of the target cluster") cmd.Flags().StringVar(&opts.serviceAccountName, "service-account-name", defaultServiceAccountName, "The name of the service account associated with the credentials") - cmd.Flags().StringVar(&opts.controlPlaneVersion, "control-plane-version", opts.controlPlaneVersion, "(Development) Tag to be used for the control plane component images") + cmd.Flags().StringVar(&opts.controlPlaneVersion, "control-plane-version", opts.controlPlaneVersion, "(Development) Tag to be used for the service mirror controller image") cmd.Flags().StringVar(&opts.gatewayName, "gateway-name", defaultGatewayName, "The name of the gateway service") cmd.Flags().StringVar(&opts.gatewayNamespace, "gateway-namespace", defaultMulticlusterNamespace, "The namespace of the gateway service") cmd.Flags().Uint32Var(&opts.serviceMirrorRetryLimit, "service-mirror-retry-limit", opts.serviceMirrorRetryLimit, "The number of times a failed update from the target cluster is allowed to be retried") cmd.Flags().StringVar(&opts.logLevel, "log-level", opts.logLevel, "Log level for the Multicluster components") + cmd.Flags().StringVar(&opts.dockerRegistry, "registry", opts.dockerRegistry, "Docker registry to pull service mirror controller image from") return cmd } From cb24531cf0a59f1f21da1d2c3516bdf3deb7027b Mon Sep 17 00:00:00 2001 From: Alex Leong Date: Wed, 22 Jul 2020 12:32:47 -0700 Subject: [PATCH 14/14] Restart link watches Signed-off-by: Alex Leong --- controller/cmd/service-mirror/main.go | 68 ++++++++++++++------------- 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/controller/cmd/service-mirror/main.go b/controller/cmd/service-mirror/main.go index 87869bf4c4f0d..378b5918cb3ae 100644 --- a/controller/cmd/service-mirror/main.go +++ b/controller/cmd/service-mirror/main.go @@ -71,42 +71,46 @@ func Main(args []string) { controllerK8sAPI.Sync(nil) - // Start link watch - linkWatch, err := linkClient.Watch(metav1.ListOptions{}) - if err != nil { - log.Fatalf("Failed to watch Link %s: %s", linkName, err) - } - results := linkWatch.ResultChan() - - // Each time the link resource is updated, reload the config and restart the - // cluster watcher. - for event := range results { - switch obj := event.Object.(type) { - case *dynamic.Unstructured: - if obj.GetName() == linkName { - switch event.Type { - case watch.Added, watch.Modified: - link, err := multicluster.NewLink(*obj) - if err != nil { - log.Errorf("Failed to parse link %s: %s", linkName, err) - continue - } - log.Infof("Got updated link %s: %+v", linkName, link) - creds, err := loadCredentials(link, *namespace, k8sAPI) - if err != nil { - log.Errorf("Failed to load remote cluster credentials: %s", err) + for { + // Start link watch + linkWatch, err := linkClient.Watch(metav1.ListOptions{}) + if err != nil { + log.Fatalf("Failed to watch Link %s: %s", linkName, err) + } + results := linkWatch.ResultChan() + + // Each time the link resource is updated, reload the config and restart the + // cluster watcher. + for event := range results { + switch obj := event.Object.(type) { + case *dynamic.Unstructured: + if obj.GetName() == linkName { + switch event.Type { + case watch.Added, watch.Modified: + link, err := multicluster.NewLink(*obj) + if err != nil { + log.Errorf("Failed to parse link %s: %s", linkName, err) + continue + } + log.Infof("Got updated link %s: %+v", linkName, link) + creds, err := loadCredentials(link, *namespace, k8sAPI) + if err != nil { + log.Errorf("Failed to load remote cluster credentials: %s", err) + } + restartClusterWatcher(link, *namespace, creds, controllerK8sAPI, *requeueLimit, *repairPeriod, metrics) + case watch.Deleted: + log.Infof("Link %s deleted", linkName) + // TODO: should we delete all mirror resources? + default: + log.Infof("Ignoring event type %s", event.Type) } - restartClusterWatcher(link, *namespace, creds, controllerK8sAPI, *requeueLimit, *repairPeriod, metrics) - case watch.Deleted: - log.Infof("Link %s deleted", linkName) - // TODO: should we delete all mirror resources? - default: - log.Infof("Ignoring event type %s", event.Type) } + default: + log.Errorf("Unknown object type detected: %+v", obj) } - default: - log.Errorf("Unknown object type detected: %+v", obj) } + + log.Info("Link watch terminated; restarting watch") } }