Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updated helm dependencies with field to build dependencies #1289

Merged
merged 9 commits into from May 23, 2023
6 changes: 6 additions & 0 deletions modules/helm/install.go
Expand Up @@ -28,6 +28,12 @@ func InstallE(t testing.TestingT, options *Options, chart string, releaseName st
chart = absChartDir
}

// build chart dependencies
if options.BuildDependencies {
if _, err := RunHelmCommandAndGetOutputE(t, options, "dependency", "build", chart); err != nil {
return errors.WithStackTrace(err)
}
}
// Now call out to helm install to install the charts with the provided options
// Declare err here so that we can update args later
var err error
Expand Down
51 changes: 51 additions & 0 deletions modules/helm/install_test.go
Expand Up @@ -11,10 +11,13 @@ package helm
import (
"crypto/tls"
"fmt"
"path/filepath"
"strings"
"testing"
"time"

"github.com/stretchr/testify/assert"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

http_helper "github.com/gruntwork-io/terratest/modules/http-helper"
Expand Down Expand Up @@ -99,6 +102,54 @@ func TestRemoteChartInstall(t *testing.T) {
)
}

// Test deployment of helm chart with dependencies.
func TestHelmDependencyInstall(t *testing.T) {
t.Parallel()

// Path to the helm chart with dependencies which we will test
helmChartPath, err := filepath.Abs("../../examples/helm-dependency-example")
require.NoError(t, err)

// Custom namespace name.
namespaceName := fmt.Sprintf("helm-dependency-example-%s", strings.ToLower(random.UniqueId()))

// Setup the kubectl config and context. Here we choose to use the defaults, which is:
// - HOME/.kube/config for the kubectl config file
// - Current context of the kubectl config file
kubectlOptions := k8s.NewKubectlOptions("", "", namespaceName)

k8s.CreateNamespace(t, kubectlOptions, namespaceName)
defer k8s.DeleteNamespace(t, kubectlOptions, namespaceName)

// Helm chart deployment options.
options := &Options{
KubectlOptions: kubectlOptions,
SetValues: map[string]string{
"containerImageRepo": "nginx",
"containerImageTag": "1.15.8",
"basic.containerImageRepo": "nginx",
"basic.containerImageTag": "1.15.8",
},
BuildDependencies: true,
}
// We generate a unique release name so that we can refer to after deployment.
// By doing so, we can schedule the delete call here so that at the end of the test, we run
// `helm delete RELEASE_NAME` to clean up any resources that were created.
releaseName := fmt.Sprintf(
"helm-dependency-example-%s",
strings.ToLower(random.UniqueId()),
)
defer Delete(t, options, releaseName, true)

// Deploy the chart using `helm install`.
err = InstallE(t, options, helmChartPath, releaseName)
assert.NoError(t, err)

// Verify that Kubernetes service is available after helm chart deployment.
_, err = k8s.GetServiceE(t, kubectlOptions, releaseName)
assert.NoError(t, err)
}

func waitForRemoteChartPods(t *testing.T, kubectlOptions *k8s.KubectlOptions, releaseName string, podCount int) {
// Get pod and wait for it to be avaialable
// To get the pod, we need to filter it using the labels that the helm chart creates
Expand Down
23 changes: 12 additions & 11 deletions modules/helm/options.go
Expand Up @@ -6,15 +6,16 @@ import (
)

type Options struct {
ValuesFiles []string // List of values files to render.
SetValues map[string]string // Values that should be set via the command line.
SetStrValues map[string]string // Values that should be set via the command line explicitly as `string` types.
SetJsonValues map[string]string // Values that should be set via the command line in JSON format.
SetFiles map[string]string // Values that should be set from a file. These should be file paths. Use to avoid logging secrets.
KubectlOptions *k8s.KubectlOptions // KubectlOptions to control how to authenticate to kubernetes cluster. `nil` => use defaults.
HomePath string // The path to the helm home to use when calling out to helm. Empty string means use default ($HOME/.helm).
EnvVars map[string]string // Environment variables to set when running helm
Version string // Version of chart
Logger *logger.Logger // Set a non-default logger that should be used. See the logger package for more info. Use logger.Discard to not print the output while executing the command.
ExtraArgs map[string][]string // Extra arguments to pass to the helm install/upgrade/rollback/delete and helm repo add commands. The key signals the command (e.g., install) while the values are the extra arguments to pass through.
ValuesFiles []string // List of values files to render.
SetValues map[string]string // Values that should be set via the command line.
SetStrValues map[string]string // Values that should be set via the command line explicitly as `string` types.
SetJsonValues map[string]string // Values that should be set via the command line in JSON format.
SetFiles map[string]string // Values that should be set from a file. These should be file paths. Use to avoid logging secrets.
KubectlOptions *k8s.KubectlOptions // KubectlOptions to control how to authenticate to kubernetes cluster. `nil` => use defaults.
HomePath string // The path to the helm home to use when calling out to helm. Empty string means use default ($HOME/.helm).
EnvVars map[string]string // Environment variables to set when running helm
Version string // Version of chart
Logger *logger.Logger // Set a non-default logger that should be used. See the logger package for more info. Use logger.Discard to not print the output while executing the command.
ExtraArgs map[string][]string // Extra arguments to pass to the helm install/upgrade/rollback/delete and helm repo add commands. The key signals the command (e.g., install) while the values are the extra arguments to pass through.
BuildDependencies bool // If true, helm dependencies will be built before rendering template, installing or upgrade the chart.
}
6 changes: 4 additions & 2 deletions modules/helm/template.go
Expand Up @@ -35,8 +35,10 @@ func RenderTemplateE(t testing.TestingT, options *Options, chartDir string, rele
}

// check chart dependencies
if _, err := RunHelmCommandAndGetOutputE(t, options, "dependency", "build", chartDir); err != nil {
return "", errors.WithStackTrace(err)
if options.BuildDependencies {
if _, err := RunHelmCommandAndGetOutputE(t, options, "dependency", "build", chartDir); err != nil {
return "", errors.WithStackTrace(err)
}
}

// Now construct the args
Expand Down
6 changes: 6 additions & 0 deletions modules/helm/upgrade.go
Expand Up @@ -27,6 +27,12 @@ func UpgradeE(t testing.TestingT, options *Options, chart string, releaseName st
chart = absChartDir
}

// build chart dependencies
if options.BuildDependencies {
if _, err := RunHelmCommandAndGetOutputE(t, options, "dependency", "build", chart); err != nil {
return errors.WithStackTrace(err)
}
}
var err error
args := []string{}
if options.ExtraArgs != nil {
Expand Down
52 changes: 52 additions & 0 deletions modules/helm/upgrade_test.go
Expand Up @@ -11,10 +11,14 @@ package helm
import (
"crypto/tls"
"fmt"
"path/filepath"
"strings"
"testing"
"time"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

http_helper "github.com/gruntwork-io/terratest/modules/http-helper"
"github.com/gruntwork-io/terratest/modules/k8s"
"github.com/gruntwork-io/terratest/modules/random"
Expand Down Expand Up @@ -95,3 +99,51 @@ func TestRemoteChartInstallUpgradeRollback(t *testing.T) {
Rollback(t, options, releaseName, "")
waitForRemoteChartPods(t, kubectlOptions, releaseName, 1)
}

// Test deployment of helm chart with dependencies.
func TestHelmDependencyUpgrade(t *testing.T) {
t.Parallel()

// Path to the helm chart with dependencies which we will test
helmChartPath, err := filepath.Abs("../../examples/helm-dependency-example")
require.NoError(t, err)

// Custom namespace name.
namespaceName := fmt.Sprintf("helm-dependency-example-%s", strings.ToLower(random.UniqueId()))

// Setup the kubectl config and context. Here we choose to use the defaults, which is:
// - HOME/.kube/config for the kubectl config file
// - Current context of the kubectl config file
kubectlOptions := k8s.NewKubectlOptions("", "", namespaceName)

k8s.CreateNamespace(t, kubectlOptions, namespaceName)
defer k8s.DeleteNamespace(t, kubectlOptions, namespaceName)

// Helm chart deployment options.
options := &Options{
KubectlOptions: kubectlOptions,
SetValues: map[string]string{
"containerImageRepo": "nginx",
"containerImageTag": "1.15.8",
"basic.containerImageRepo": "nginx",
"basic.containerImageTag": "1.15.8",
},
BuildDependencies: true,
}
// We generate a unique release name so that we can refer to after deployment.
// By doing so, we can schedule the delete call here so that at the end of the test, we run
// `helm delete RELEASE_NAME` to clean up any resources that were created.
releaseName := fmt.Sprintf(
"helm-dependency-example-%s",
strings.ToLower(random.UniqueId()),
)
defer Delete(t, options, releaseName, true)

// Deploy the chart using `helm install`.
err = InstallE(t, options, helmChartPath, releaseName)
assert.NoError(t, err)

// Verify that upgrade is working as expected.
err = UpgradeE(t, options, helmChartPath, releaseName)
assert.NoError(t, err)
}
3 changes: 2 additions & 1 deletion test/helm_dependency_example_template_test.go
Expand Up @@ -57,7 +57,8 @@ func TestHelmDependencyExampleTemplateRenderedDeployment(t *testing.T) {
"basic.containerImageRepo": "nginx",
"basic.containerImageTag": "1.15.8",
},
KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
BuildDependencies: true,
}

testCases := []struct {
Expand Down