...

Source file src/github.com/linkerd/linkerd2/viz/cmd/install.go

Documentation: github.com/linkerd/linkerd2/viz/cmd

     1  package cmd
     2  
     3  import (
     4  	"bytes"
     5  	"io"
     6  	"os"
     7  	"path"
     8  	"time"
     9  
    10  	"github.com/linkerd/linkerd2/pkg/charts"
    11  	partials "github.com/linkerd/linkerd2/pkg/charts/static"
    12  	"github.com/linkerd/linkerd2/pkg/flags"
    13  	"github.com/linkerd/linkerd2/pkg/healthcheck"
    14  	"github.com/linkerd/linkerd2/viz/static"
    15  	"github.com/spf13/cobra"
    16  	"helm.sh/helm/v3/pkg/chart/loader"
    17  	"helm.sh/helm/v3/pkg/chartutil"
    18  	"helm.sh/helm/v3/pkg/cli/values"
    19  	"helm.sh/helm/v3/pkg/engine"
    20  )
    21  
    22  var (
    23  	// this doesn't include the namespace-metadata.* templates, which are Helm-only
    24  	templatesViz = []string{
    25  		"templates/namespace.yaml",
    26  		"templates/metrics-api-rbac.yaml",
    27  		"templates/prometheus-rbac.yaml",
    28  		"templates/tap-rbac.yaml",
    29  		"templates/web-rbac.yaml",
    30  		"templates/psp.yaml",
    31  		"templates/metrics-api.yaml",
    32  		"templates/metrics-api-policy.yaml",
    33  		"templates/admin-policy.yaml",
    34  		"templates/prometheus.yaml",
    35  		"templates/prometheus-policy.yaml",
    36  		"templates/tap.yaml",
    37  		"templates/tap-policy.yaml",
    38  		"templates/tap-injector-rbac.yaml",
    39  		"templates/tap-injector.yaml",
    40  		"templates/tap-injector-policy.yaml",
    41  		"templates/web.yaml",
    42  		"templates/service-profiles.yaml",
    43  	}
    44  )
    45  
    46  func newCmdInstall() *cobra.Command {
    47  	var skipChecks bool
    48  	var ignoreCluster bool
    49  	var ha bool
    50  	var cniEnabled bool
    51  	var wait time.Duration
    52  	var options values.Options
    53  
    54  	cmd := &cobra.Command{
    55  		Use:   "install [flags]",
    56  		Args:  cobra.NoArgs,
    57  		Short: "Output Kubernetes resources to install linkerd-viz extension",
    58  		Long:  `Output Kubernetes resources to install linkerd-viz extension.`,
    59  		Example: `  # Default install.
    60    linkerd viz install | kubectl apply -f -
    61  
    62  The installation can be configured by using the --set, --values, --set-string and --set-file flags.
    63  A full list of configurable values can be found at https://www.github.com/linkerd/linkerd2/tree/main/viz/charts/linkerd-viz/README.md
    64    `,
    65  		RunE: func(_ *cobra.Command, _ []string) error {
    66  			if !skipChecks && !ignoreCluster {
    67  				// Wait for the core control-plane to be up and running
    68  				hc := healthcheck.NewWithCoreChecks(&healthcheck.Options{
    69  					ControlPlaneNamespace: controlPlaneNamespace,
    70  					KubeConfig:            kubeconfigPath,
    71  					KubeContext:           kubeContext,
    72  					Impersonate:           impersonate,
    73  					ImpersonateGroup:      impersonateGroup,
    74  					APIAddr:               apiAddr,
    75  					RetryDeadline:         time.Now().Add(wait),
    76  				})
    77  				hc.RunWithExitOnError()
    78  				cniEnabled = hc.CNIEnabled
    79  			}
    80  			return install(os.Stdout, options, ha, cniEnabled)
    81  		},
    82  	}
    83  
    84  	cmd.Flags().BoolVar(&skipChecks, "skip-checks", false, `Skip checks for linkerd core control-plane existence`)
    85  	cmd.Flags().BoolVar(&ignoreCluster, "ignore-cluster", false,
    86  		"Ignore the current Kubernetes cluster when checking for existing cluster configuration (default false)")
    87  	cmd.Flags().BoolVar(&ha, "ha", false, `Install Viz Extension in High Availability mode.`)
    88  	cmd.Flags().DurationVar(&wait, "wait", 300*time.Second, "Wait for core control-plane components to be available")
    89  
    90  	flags.AddValueOptionsFlags(cmd.Flags(), &options)
    91  
    92  	return cmd
    93  }
    94  
    95  func install(w io.Writer, options values.Options, ha, cniEnabled bool) error {
    96  
    97  	// Create values override
    98  	valuesOverrides, err := options.MergeValues(nil)
    99  	if err != nil {
   100  		return err
   101  	}
   102  
   103  	// sync values overrides with Helm values
   104  	if controlPlaneNamespace != defaultLinkerdNamespace {
   105  		valuesOverrides["linkerdNamespace"] = controlPlaneNamespace
   106  	}
   107  	if reg := os.Getenv(flags.EnvOverrideDockerRegistry); reg != "" {
   108  		valuesOverrides["defaultRegistry"] = reg
   109  	}
   110  
   111  	if ha {
   112  		valuesOverrides, err = charts.OverrideFromFile(valuesOverrides, static.Templates, vizChartName, "values-ha.yaml")
   113  		if err != nil {
   114  			return err
   115  		}
   116  	}
   117  
   118  	if cniEnabled {
   119  		valuesOverrides["cniEnabled"] = true
   120  	}
   121  
   122  	// TODO: Add any validation logic here
   123  
   124  	return render(w, valuesOverrides)
   125  }
   126  
   127  func render(w io.Writer, valuesOverrides map[string]interface{}) error {
   128  
   129  	files := []*loader.BufferedFile{
   130  		{Name: chartutil.ChartfileName},
   131  		{Name: chartutil.ValuesfileName},
   132  	}
   133  
   134  	for _, template := range templatesViz {
   135  		files = append(files,
   136  			&loader.BufferedFile{Name: template},
   137  		)
   138  	}
   139  
   140  	var partialFiles []*loader.BufferedFile
   141  	for _, template := range charts.L5dPartials {
   142  		partialFiles = append(partialFiles,
   143  			&loader.BufferedFile{Name: template},
   144  		)
   145  	}
   146  
   147  	// Load all Viz chart files into buffer
   148  	if err := charts.FilesReader(static.Templates, vizChartName+"/", files); err != nil {
   149  		return err
   150  	}
   151  
   152  	// Load all partial chart files into buffer
   153  	if err := charts.FilesReader(partials.Templates, "", partialFiles); err != nil {
   154  		return err
   155  	}
   156  
   157  	// Create a Chart obj from the files
   158  	chart, err := loader.LoadFiles(append(files, partialFiles...))
   159  	if err != nil {
   160  		return err
   161  	}
   162  
   163  	vals, err := chartutil.CoalesceValues(chart, valuesOverrides)
   164  	if err != nil {
   165  		return err
   166  	}
   167  
   168  	vals, err = charts.InsertVersionValues(vals)
   169  	if err != nil {
   170  		return err
   171  	}
   172  
   173  	fullValues := map[string]interface{}{
   174  		"Values": vals,
   175  		"Release": map[string]interface{}{
   176  			"Namespace": defaultNamespace,
   177  			"Service":   "CLI",
   178  		},
   179  	}
   180  
   181  	// Attach the final values into the `Values` field for rendering to work
   182  	renderedTemplates, err := engine.Render(chart, fullValues)
   183  	if err != nil {
   184  		return err
   185  	}
   186  
   187  	// Merge templates and inject
   188  	var buf bytes.Buffer
   189  	for _, tmpl := range chart.Templates {
   190  		t := path.Join(chart.Metadata.Name, tmpl.Name)
   191  		if _, err := buf.WriteString(renderedTemplates[t]); err != nil {
   192  			return err
   193  		}
   194  	}
   195  
   196  	_, err = w.Write(buf.Bytes())
   197  	return err
   198  }
   199  

View as plain text