From 3b755e5c1d2853c0c7613b7d88d1d2122f291b12 Mon Sep 17 00:00:00 2001 From: Tarun Pothulapati Date: Wed, 20 Jan 2021 11:29:42 +0530 Subject: [PATCH] multicluster: add helm customization flags for install (#5534) * multicluster: add helm customization flags This branch updates the multicluster install flow to use the helm engine directly instead of our own chart wrapper. This also adds the helm customization flags. ```bash tarun in dev in on k3d-deep (default) linkerd2 on tarun/mc-helm-flags [$+?] via v1.15.4 ./bin/go-run cli mc install --set namespace=l5d-mc | grep l5d-mc github.com/linkerd/linkerd2/multicluster/cmd github.com/linkerd/linkerd2/cli/cmd name: l5d-mc namespace: l5d-mc namespace: l5d-mc namespace: l5d-mc mirror.linkerd.io/gateway-identity: linkerd-gateway.l5d-mc.serviceaccount.identity.linkerd.cluster.local namespace: l5d-mc namespace: l5d-mc namespace: l5d-mc namespace: l5d-mc namespace: l5d-mc ``` * add customization flags even for link cmd Signed-off-by: Tarun Pothulapati --- multicluster/cmd/install.go | 61 ++++++++++++++++++++++++++++++++----- multicluster/cmd/link.go | 60 +++++++++++++++++++++++++++++++----- 2 files changed, 105 insertions(+), 16 deletions(-) diff --git a/multicluster/cmd/install.go b/multicluster/cmd/install.go index 636e122ae..33f8c73be 100644 --- a/multicluster/cmd/install.go +++ b/multicluster/cmd/install.go @@ -1,19 +1,25 @@ package cmd import ( + "bytes" "context" "errors" "fmt" "os" + "path" "github.com/linkerd/linkerd2/multicluster/static" multicluster "github.com/linkerd/linkerd2/multicluster/values" "github.com/linkerd/linkerd2/pkg/charts" + "github.com/linkerd/linkerd2/pkg/flags" "github.com/linkerd/linkerd2/pkg/version" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" + "helm.sh/helm/v3/pkg/chart/loader" chartloader "helm.sh/helm/v3/pkg/chart/loader" "helm.sh/helm/v3/pkg/chartutil" + valuespkg "helm.sh/helm/v3/pkg/cli/values" + "helm.sh/helm/v3/pkg/engine" kerrors "k8s.io/apimachinery/pkg/api/errors" "sigs.k8s.io/yaml" ) @@ -34,6 +40,8 @@ type ( func newMulticlusterInstallCommand() *cobra.Command { options, err := newMulticlusterInstallOptionsWithDefault() + var valuesOptions valuespkg.Options + if err != nil { fmt.Fprintf(os.Stderr, "%s", err) os.Exit(1) @@ -43,6 +51,12 @@ func newMulticlusterInstallCommand() *cobra.Command { Use: "install", Short: "Output Kubernetes configs to install the Linkerd multicluster add-on", Args: cobra.NoArgs, + Example: ` # Default install. + linkerd multicluster install | kubectl apply -f - + +The installation can be configured by using the --set, --values, --set-string and --set-file flags. +A full list of configurable values can be found at https://github.com/linkerd/linkerd2/blob/main/multicluster/charts/linkerd2-multicluster/README.md + `, RunE: func(cmd *cobra.Command, args []string) error { values, err := buildMulticlusterInstallValues(cmd.Context(), options) @@ -65,18 +79,48 @@ func newMulticlusterInstallCommand() *cobra.Command { {Name: "templates/link-crd.yaml"}, } - chart := &charts.Chart{ - Name: helmMulticlusterDefaultChartName, - Dir: helmMulticlusterDefaultChartName, - Namespace: controlPlaneNamespace, - RawValues: rawValues, - Files: files, - Fs: static.Templates, + // Load all multicluster install chart files into buffer + if err := charts.FilesReader(static.Templates, helmMulticlusterDefaultChartName+"/", files); err != nil { + return err } - buf, err := chart.RenderNoPartials() + + // Create a Chart obj from the files + chart, err := loader.LoadFiles(files) if err != nil { return err } + + // Store final Values generated from values.yaml and CLI flags + err = yaml.Unmarshal(rawValues, &chart.Values) + if err != nil { + return err + } + + // Create values override + valuesOverrides, err := valuesOptions.MergeValues(nil) + if err != nil { + return err + } + + vals, err := chartutil.CoalesceValues(chart, valuesOverrides) + if err != nil { + return err + } + + // Attach the final values into the `Values` field for rendering to work + renderedTemplates, err := engine.Render(chart, map[string]interface{}{"Values": vals}) + if err != nil { + return err + } + + // Merge templates and inject + var buf bytes.Buffer + for _, tmpl := range chart.Templates { + t := path.Join(chart.Metadata.Name, tmpl.Name) + if _, err := buf.WriteString(renderedTemplates[t]); err != nil { + return err + } + } stdout.Write(buf.Bytes()) stdout.Write([]byte("---\n")) @@ -84,6 +128,7 @@ func newMulticlusterInstallCommand() *cobra.Command { }, } + flags.AddValueOptionsFlags(cmd.Flags(), &valuesOptions) cmd.Flags().StringVar(&options.namespace, "namespace", options.namespace, "The namespace in which the multicluster add-on is to be installed. Must not be the control plane namespace. ") cmd.Flags().BoolVar(&options.gateway, "gateway", options.gateway, "If the gateway component should be installed") cmd.Flags().Uint32Var(&options.gatewayPort, "gateway-port", options.gatewayPort, "The port on the gateway used for all incoming traffic") diff --git a/multicluster/cmd/link.go b/multicluster/cmd/link.go index 2278229cf..4f7e96182 100644 --- a/multicluster/cmd/link.go +++ b/multicluster/cmd/link.go @@ -1,14 +1,17 @@ package cmd import ( + "bytes" "errors" "fmt" "os" + "path" "strings" "github.com/linkerd/linkerd2/multicluster/static" multicluster "github.com/linkerd/linkerd2/multicluster/values" "github.com/linkerd/linkerd2/pkg/charts" + "github.com/linkerd/linkerd2/pkg/flags" "github.com/linkerd/linkerd2/pkg/k8s" mc "github.com/linkerd/linkerd2/pkg/multicluster" "github.com/linkerd/linkerd2/pkg/version" @@ -16,6 +19,8 @@ import ( "github.com/spf13/cobra" chartloader "helm.sh/helm/v3/pkg/chart/loader" "helm.sh/helm/v3/pkg/chartutil" + valuespkg "helm.sh/helm/v3/pkg/cli/values" + "helm.sh/helm/v3/pkg/engine" corev1 "k8s.io/api/core/v1" kerrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -43,6 +48,8 @@ type ( func newLinkCommand() *cobra.Command { opts, err := newLinkOptionsWithDefault() + var valuesOptions valuespkg.Options + if err != nil { fmt.Fprintf(os.Stderr, "%s", err) os.Exit(1) @@ -52,6 +59,12 @@ func newLinkCommand() *cobra.Command { Use: "link", Short: "Outputs resources that allow another cluster to mirror services from this one", Args: cobra.NoArgs, + Example: ` # To link the west cluster to east + linkerd --context=east multicluster link --cluster-name east | kubectl --context=west apply -f - + +The command can be configured by using the --set, --values, --set-string and --set-file flags. +A full list of configurable values can be found at https://github.com/linkerd/linkerd2/blob/main/multicluster/charts/linkerd2-multicluster-link/README.md + `, RunE: func(cmd *cobra.Command, args []string) error { if opts.clusterName == "" { @@ -242,19 +255,49 @@ func newLinkCommand() *cobra.Command { {Name: "templates/gateway-mirror.yaml"}, } - chart := &charts.Chart{ - Name: helmMulticlusterLinkDefaultChartName, - Dir: helmMulticlusterLinkDefaultChartName, - Namespace: controlPlaneNamespace, - RawValues: rawValues, - Files: files, - Fs: static.Templates, + // Load all multicluster link chart files into buffer + if err := charts.FilesReader(static.Templates, helmMulticlusterLinkDefaultChartName+"/", files); err != nil { + return err } - serviceMirrorOut, err := chart.RenderNoPartials() + + // Create a Chart obj from the files + chart, err := chartloader.LoadFiles(files) if err != nil { return err } + // Store final Values generated from values.yaml and CLI flags + err = yaml.Unmarshal(rawValues, &chart.Values) + if err != nil { + return err + } + + // Create values override + valuesOverrides, err := valuesOptions.MergeValues(nil) + if err != nil { + return err + } + + vals, err := chartutil.CoalesceValues(chart, valuesOverrides) + if err != nil { + return err + } + + // Attach the final values into the `Values` field for rendering to work + renderedTemplates, err := engine.Render(chart, map[string]interface{}{"Values": vals}) + if err != nil { + return err + } + + // Merge templates and inject + var serviceMirrorOut bytes.Buffer + for _, tmpl := range chart.Templates { + t := path.Join(chart.Metadata.Name, tmpl.Name) + if _, err := serviceMirrorOut.WriteString(renderedTemplates[t]); err != nil { + return err + } + } + stdout.Write(credsOut) stdout.Write([]byte("---\n")) stdout.Write(linkOut) @@ -266,6 +309,7 @@ func newLinkCommand() *cobra.Command { }, } + flags.AddValueOptionsFlags(cmd.Flags(), &valuesOptions) cmd.Flags().StringVar(&opts.namespace, "namespace", defaultMulticlusterNamespace, "The namespace for the service account") 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")