...

Source file src/github.com/linkerd/linkerd2/cli/cmd/install_helm_test.go

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

     1  package cmd
     2  
     3  import (
     4  	"bytes"
     5  	"path/filepath"
     6  	"testing"
     7  
     8  	"github.com/linkerd/linkerd2/pkg/charts"
     9  	l5dcharts "github.com/linkerd/linkerd2/pkg/charts/linkerd2"
    10  	"github.com/linkerd/linkerd2/pkg/charts/static"
    11  	"github.com/linkerd/linkerd2/pkg/k8s"
    12  	"github.com/linkerd/linkerd2/testutil"
    13  	"helm.sh/helm/v3/pkg/chart"
    14  	"helm.sh/helm/v3/pkg/chart/loader"
    15  	"helm.sh/helm/v3/pkg/chartutil"
    16  	"helm.sh/helm/v3/pkg/engine"
    17  	"sigs.k8s.io/yaml"
    18  )
    19  
    20  func TestRenderHelm(t *testing.T) {
    21  	// read the control plane chart and its defaults from the local folder.
    22  	// override certain defaults with pinned values.
    23  	// use the Helm lib to render the templates.
    24  	t.Run("Non-HA mode", func(t *testing.T) {
    25  		chartCrds := chartCrds(t)
    26  		chartControlPlane := chartControlPlane(t, false, "", "111", "222")
    27  		testRenderHelm(t, chartCrds, "install_helm_crds_output.golden")
    28  		testRenderHelm(t, chartControlPlane, "install_helm_control_plane_output.golden")
    29  	})
    30  
    31  	t.Run("HA mode", func(t *testing.T) {
    32  		chartCrds := chartCrds(t)
    33  		chartControlPlane := chartControlPlane(t, true, "", "111", "222")
    34  		testRenderHelm(t, chartCrds, "install_helm_crds_output_ha.golden")
    35  		testRenderHelm(t, chartControlPlane, "install_helm_control_plane_output_ha.golden")
    36  	})
    37  
    38  	t.Run("HA mode with GID", func(t *testing.T) {
    39  		additionalConfig := `
    40  controllerGID: 1324
    41  proxy:
    42    gid: 4231
    43  `
    44  		chartControlPlane := chartControlPlane(t, true, additionalConfig, "111", "222")
    45  		testRenderHelm(t, chartControlPlane, "install_helm_control_plane_output_ha_with_gid.golden")
    46  	})
    47  
    48  	t.Run("HA mode with podLabels and podAnnotations", func(t *testing.T) {
    49  		additionalConfig := `
    50  podLabels:
    51    foo: bar
    52    fiz: buz
    53  podAnnotations:
    54    bingo: bongo
    55    asda: fasda
    56  `
    57  		chartControlPlane := chartControlPlane(t, true, additionalConfig, "333", "444")
    58  		testRenderHelm(t, chartControlPlane, "install_helm_output_ha_labels.golden")
    59  	})
    60  
    61  	t.Run("HA mode with custom namespaceSelector", func(t *testing.T) {
    62  		additionalConfig := `
    63  proxyInjector:
    64    namespaceSelector:
    65      matchExpressions:
    66      - key: config.linkerd.io/admission-webhooks
    67        operator: In
    68        values:
    69        - enabled
    70  profileValidator:
    71    namespaceSelector:
    72      matchExpressions:
    73      - key: config.linkerd.io/admission-webhooks
    74        operator: In
    75        values:
    76        - enabled
    77  `
    78  		chartControlPlane := chartControlPlane(t, true, additionalConfig, "111", "222")
    79  		testRenderHelm(t, chartControlPlane, "install_helm_output_ha_namespace_selector.golden")
    80  	})
    81  }
    82  
    83  func testRenderHelm(t *testing.T, linkerd2Chart *chart.Chart, goldenFileName string) {
    84  	var (
    85  		chartName = "linkerd2"
    86  		namespace = "linkerd-dev"
    87  	)
    88  
    89  	// pin values that are changed by Helm functions on each test run
    90  	overrideJSON := `{
    91     "cliVersion":"",
    92     "linkerdVersion":"linkerd-version",
    93     "identityTrustAnchorsPEM":"test-trust-anchor",
    94     "identityTrustDomain":"test.trust.domain",
    95     "proxy":{
    96      "image":{
    97       "version":"test-proxy-version"
    98      }
    99     },
   100     "proxyInit":{
   101      "image":{
   102       "version":"test-proxy-init-version"
   103      }
   104     },
   105    "identity":{
   106      "issuer":{
   107        "tls":{
   108          "keyPEM":"test-key-pem",
   109          "crtPEM":"test-crt-pem"
   110        }
   111      }
   112    },
   113    "configs": null,
   114    "debugContainer":{
   115      "image":{
   116        "version":"test-debug-version"
   117      }
   118    },
   119    "proxyInjector":{
   120      "externalSecret": true,
   121      "caBundle":"test-proxy-injector-ca-bundle"
   122    },
   123    "profileValidator":{
   124      "externalSecret": true,
   125      "caBundle":"test-profile-validator-ca-bundle"
   126    },
   127    "policyValidator":{
   128      "externalSecret": true,
   129      "caBundle":"test-profile-validator-ca-bundle"
   130    },
   131    "tap":{
   132      "externalSecret": true,
   133      "caBundle":"test-tap-ca-bundle"
   134    }
   135  }`
   136  
   137  	var overrideConfig chartutil.Values
   138  	err := yaml.Unmarshal([]byte(overrideJSON), &overrideConfig)
   139  	if err != nil {
   140  		t.Fatal("Unexpected error", err)
   141  	}
   142  
   143  	releaseOptions := chartutil.ReleaseOptions{
   144  		Name:      chartName,
   145  		Namespace: namespace,
   146  		IsUpgrade: false,
   147  		IsInstall: true,
   148  	}
   149  
   150  	valuesToRender, err := chartutil.ToRenderValues(linkerd2Chart, overrideConfig, releaseOptions, nil)
   151  	if err != nil {
   152  		t.Fatal("Unexpected error", err)
   153  	}
   154  
   155  	rendered, err := engine.Render(linkerd2Chart, valuesToRender)
   156  	if err != nil {
   157  		t.Fatal("Unexpected error", err)
   158  	}
   159  
   160  	var buf bytes.Buffer
   161  	for _, template := range linkerd2Chart.Templates {
   162  		source := linkerd2Chart.Metadata.Name + "/" + template.Name
   163  		v, exists := rendered[source]
   164  		if !exists {
   165  			// skip partial templates
   166  			continue
   167  		}
   168  		buf.WriteString("---\n# Source: " + source + "\n")
   169  		buf.WriteString(v)
   170  	}
   171  
   172  	for _, dep := range linkerd2Chart.Dependencies() {
   173  		for _, template := range dep.Templates {
   174  			source := linkerd2Chart.Metadata.Name + "/charts" + "/" + dep.Metadata.Name + "/" + template.Name
   175  			v, exists := rendered[source]
   176  			if !exists {
   177  				// skip partial templates
   178  				continue
   179  			}
   180  			buf.WriteString("---\n# Source: " + source + "\n")
   181  			buf.WriteString(v)
   182  		}
   183  	}
   184  
   185  	if err := testDataDiffer.DiffTestYAML(goldenFileName, buf.String()); err != nil {
   186  		t.Error(err)
   187  	}
   188  }
   189  
   190  func chartCrds(t *testing.T) *chart.Chart {
   191  	partialPaths := []string{
   192  		"templates/_proxy.tpl",
   193  		"templates/_proxy-init.tpl",
   194  		"templates/_volumes.tpl",
   195  		"templates/_resources.tpl",
   196  		"templates/_metadata.tpl",
   197  		"templates/_debug.tpl",
   198  		"templates/_trace.tpl",
   199  		"templates/_capabilities.tpl",
   200  		"templates/_affinity.tpl",
   201  		"templates/_nodeselector.tpl",
   202  		"templates/_tolerations.tpl",
   203  		"templates/_validate.tpl",
   204  		"templates/_pull-secrets.tpl",
   205  	}
   206  
   207  	chartPartials := chartPartials(partialPaths)
   208  
   209  	// Load defaults from values.yaml
   210  	valuesFile := &loader.BufferedFile{Name: l5dcharts.HelmChartDirCrds + "/values.yaml"}
   211  	if err := charts.ReadFile(static.Templates, "/", valuesFile); err != nil {
   212  		t.Fatal(err)
   213  	}
   214  	defaultValues := make(map[string]interface{})
   215  	err := yaml.Unmarshal(valuesFile.Data, &defaultValues)
   216  	if err != nil {
   217  		t.Fatal(err)
   218  	}
   219  	defaultValues["cliVersion"] = k8s.CreatedByAnnotationValue()
   220  
   221  	linkerd2Chart := &chart.Chart{
   222  		Metadata: &chart.Metadata{
   223  			Name: helmDefaultChartNameCrds,
   224  			Sources: []string{
   225  				filepath.Join("..", "..", "..", "charts", "linkerd-crds"),
   226  			},
   227  		},
   228  		Values: defaultValues,
   229  	}
   230  
   231  	linkerd2Chart.AddDependency(chartPartials)
   232  
   233  	for _, filepath := range TemplatesCrdFiles {
   234  		linkerd2Chart.Templates = append(linkerd2Chart.Templates, &chart.File{
   235  			Name: filepath,
   236  		})
   237  	}
   238  
   239  	for _, template := range linkerd2Chart.Templates {
   240  		filepath := filepath.Join(linkerd2Chart.Metadata.Sources[0], template.Name)
   241  		template.Data = []byte(testutil.ReadTestdata(filepath))
   242  	}
   243  
   244  	return linkerd2Chart
   245  }
   246  
   247  func chartControlPlane(t *testing.T, ha bool, additionalConfig string, ignoreOutboundPorts string, ignoreInboundPorts string) *chart.Chart {
   248  	values, err := readTestValues(ha, ignoreOutboundPorts, ignoreInboundPorts)
   249  	if err != nil {
   250  		t.Fatal("Unexpected error", err)
   251  	}
   252  
   253  	if additionalConfig != "" {
   254  		err := yaml.Unmarshal([]byte(additionalConfig), values)
   255  		if err != nil {
   256  			t.Fatal("Unexpected error", err)
   257  		}
   258  	}
   259  
   260  	partialPaths := []string{
   261  		"templates/_proxy.tpl",
   262  		"templates/_proxy-init.tpl",
   263  		"templates/_volumes.tpl",
   264  		"templates/_resources.tpl",
   265  		"templates/_metadata.tpl",
   266  		"templates/_debug.tpl",
   267  		"templates/_trace.tpl",
   268  		"templates/_capabilities.tpl",
   269  		"templates/_affinity.tpl",
   270  		"templates/_nodeselector.tpl",
   271  		"templates/_tolerations.tpl",
   272  		"templates/_validate.tpl",
   273  		"templates/_pull-secrets.tpl",
   274  	}
   275  
   276  	chartPartials := chartPartials(partialPaths)
   277  
   278  	rawValues, err := yaml.Marshal(values)
   279  	if err != nil {
   280  		t.Fatal("Unexpected error", err)
   281  	}
   282  
   283  	var mapValues chartutil.Values
   284  	err = yaml.Unmarshal(rawValues, &mapValues)
   285  	if err != nil {
   286  		t.Fatal("Unexpected error", err)
   287  	}
   288  	linkerd2Chart := &chart.Chart{
   289  		Metadata: &chart.Metadata{
   290  			Name: helmDefaultChartNameCP,
   291  			Sources: []string{
   292  				filepath.Join("..", "..", "..", "charts", "linkerd-control-plane"),
   293  			},
   294  		},
   295  		Values: mapValues,
   296  	}
   297  
   298  	linkerd2Chart.AddDependency(chartPartials)
   299  
   300  	for _, filepath := range TemplatesControlPlane {
   301  		linkerd2Chart.Templates = append(linkerd2Chart.Templates, &chart.File{
   302  			Name: filepath,
   303  		})
   304  	}
   305  
   306  	for _, template := range linkerd2Chart.Templates {
   307  		filepath := filepath.Join(linkerd2Chart.Metadata.Sources[0], template.Name)
   308  		template.Data = []byte(testutil.ReadTestdata(filepath))
   309  	}
   310  
   311  	return linkerd2Chart
   312  }
   313  
   314  func chartPartials(paths []string) *chart.Chart {
   315  	var partialTemplates []*chart.File
   316  	for _, path := range paths {
   317  		partialTemplates = append(partialTemplates, &chart.File{Name: path})
   318  	}
   319  
   320  	chart := &chart.Chart{
   321  		Metadata: &chart.Metadata{
   322  			Name: "partials",
   323  			Sources: []string{
   324  				filepath.Join("..", "..", "..", "charts", "partials"),
   325  			},
   326  		},
   327  		Templates: partialTemplates,
   328  	}
   329  
   330  	for _, template := range chart.Templates {
   331  		template := template
   332  		filepath := filepath.Join(chart.Metadata.Sources[0], template.Name)
   333  		template.Data = []byte(testutil.ReadTestdata(filepath))
   334  	}
   335  
   336  	return chart
   337  }
   338  
   339  func readTestValues(ha bool, ignoreOutboundPorts string, ignoreInboundPorts string) (*l5dcharts.Values, error) {
   340  	values, err := l5dcharts.NewValues()
   341  	if err != nil {
   342  		return nil, err
   343  	}
   344  	if ha {
   345  		if err = l5dcharts.MergeHAValues(values); err != nil {
   346  			return nil, err
   347  		}
   348  	}
   349  	values.ProxyInit.IgnoreOutboundPorts = ignoreOutboundPorts
   350  	values.ProxyInit.IgnoreInboundPorts = ignoreInboundPorts
   351  	values.HeartbeatSchedule = "1 2 3 4 5"
   352  
   353  	return values, nil
   354  }
   355  

View as plain text