Skip to content

Commit

Permalink
Merge pull request #1289 from gruntwork-io/feature/helm-optional-depe…
Browse files Browse the repository at this point in the history
…ndencies-building-1193

Updated helm dependencies with field to build dependencies
  • Loading branch information
denis256 committed May 23, 2023
2 parents b69cbc6 + 80cc3cd commit e2568de
Show file tree
Hide file tree
Showing 7 changed files with 133 additions and 14 deletions.
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

0 comments on commit e2568de

Please sign in to comment.