Skip to content

Commit

Permalink
simplify configuration to a single boolean attr
Browse files Browse the repository at this point in the history
  • Loading branch information
n-oden committed Aug 8, 2024
1 parent c4460fa commit 6dd3fb3
Show file tree
Hide file tree
Showing 6 changed files with 28 additions and 96 deletions.
2 changes: 1 addition & 1 deletion .changelog/1247.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
```release-note:enhancement
resource/helm_release: add `upgrade` map attribute to enable idempotent release installation, addressing components of [GH-425](https://github.com/hashicorp/terraform-provider-helm/issues/425)
resource/helm_release: add `upgrade_install` boolean attribute to enable idempotent release installation, addressing components of [GH-425](https://github.com/hashicorp/terraform-provider-helm/issues/425)
```
8 changes: 4 additions & 4 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,10 +186,10 @@ The `kubernetes` block supports:
* `config_context` - (Optional) Context to choose from the config file. Can be sourced from `KUBE_CTX`.
* `proxy_url` - (Optional) URL to the proxy to be used for all API requests. URLs with "http", "https", and "socks5" schemes are supported. Can be sourced from `KUBE_PROXY_URL`.
* `exec` - (Optional) Configuration block to use an [exec-based credential plugin](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#client-go-credential-plugins), e.g. call an external command to receive user credentials.
* `api_version` - (Required) API version to use when decoding the ExecCredentials resource, e.g. `client.authentication.k8s.io/v1beta1`.
* `command` - (Required) Command to execute.
* `args` - (Optional) List of arguments to pass when executing the plugin.
* `env` - (Optional) Map of environment variables to set when executing the plugin.
* `api_version` - (Required) API version to use when decoding the ExecCredentials resource, e.g. `client.authentication.k8s.io/v1beta1`.
* `command` - (Required) Command to execute.
* `args` - (Optional) List of arguments to pass when executing the plugin.
* `env` - (Optional) Map of environment variables to set when executing the plugin.

The `registry` block has options:

Expand Down
22 changes: 4 additions & 18 deletions docs/resources/release.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ A Chart is a Helm package. It contains all of the resource definitions necessary
- `set_sensitive` (Block Set) Custom sensitive values to be merged with the values. (see [below for nested schema](#nestedblock--set_sensitive))
- `skip_crds` (Boolean) If set, no CRDs will be installed. By default, CRDs are installed if not already present. Defaults to `false`.
- `timeout` (Number) Time in seconds to wait for any individual kubernetes operation. Defaults to 300 seconds.
- `upgrade` (Block List, Max: 1) Configure 'upgrade' strategy for installing charts. WARNING: this may not be suitable for production use -- see the 'Upgrade Mode' section of the provider documentation, (see [below for nested schema](#nestedblock--upgrade))
- `upgrade_install` (Boolean) If true, the provider will install the release at the specified version even if a release not controlled by the provider is present: this is equivalent to running 'helm upgrade --install' with the Helm CLI. WARNING: this may not be suitable for production use -- see the 'Upgrade Mode' note in the provider documentation. Defaults to `false`.
- `values` (List of String) List of values in raw yaml format to pass to helm.
- `verify` (Boolean) Verify the package before installing it.Defaults to `false`.
- `version` (String) Specify the exact chart version to install. If this is not specified, the latest version is installed.
Expand Down Expand Up @@ -115,18 +115,6 @@ Optional:
- `type` (String)


<a id="nestedblock--upgrade"></a>
### Nested Schema for `upgrade`

Required:

- `enable` (Boolean) If true, the provider will install the release at the specified version even if a release not controlled by the provider is present: this is equivalent to using the 'helm upgrade' CLI tool rather than 'helm install'.

Optional:

- `install` (Boolean) When using the 'upgrade' strategy, install the release if it is not already present. This is equivalent to using the 'helm upgrade' CLI tool with the '--install' flag.


<a id="nestedatt--metadata"></a>
### Nested Schema for `metadata`

Expand Down Expand Up @@ -353,16 +341,14 @@ having to manually import the release into terraform state each time. But the me
different from the defaults and you can easily produce unexpected or undesirable results if you are not careful:
using this approach in production is not necessarily recommended!

If upgrade mode is enabled by setting `enable` to `true` in the `upgrade` block, the provider will first check to see
If upgrade mode is enabled by setting the `upgrade_install` attribute to `true`, the provider will first check to see
if a release with the given name already exists. If that release exists, it will attempt to upgrade the release to
the state defined in the resource, using the same strategy as the [helm upgrade](https://helm.sh/docs/helm/helm_upgrade)
command. In this case, the `generate_name`, `name_template` and `replace` attributes of the resource (if set) are
ignored, as those attributes are not supported by helm's "upgrade" behavior.

If the release does _not_ exist, the behavior is controlled by the setting of the `install` attribute. If `install`
is `false` or unset, the apply stage will fail: the provider cannot upgrade a non-existent release. If `install`
is set to `true`, the provider will perform a from-scratch installation of the chart. In this case, all resource
attributes are honored.
If the release does not already exist, the provider will perform a from-scratch installation of the chart. In this
case, all resource attributes are honored.

## Import

Expand Down
44 changes: 8 additions & 36 deletions helm/resource_release.go
Original file line number Diff line number Diff line change
Expand Up @@ -386,26 +386,11 @@ func resourceRelease() *schema.Resource {
Description: "The rendered manifest as JSON.",
Computed: true,
},
"upgrade": {
Type: schema.TypeList,
"upgrade_install": {
Type: schema.TypeBool,
Optional: true,
MaxItems: 1,
Description: "Configure 'upgrade' strategy for installing charts. WARNING: this may not be suitable for production use -- see the 'Upgrade Mode' section of the provider documentation,",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"enable": {
Type: schema.TypeBool,
Required: true,
Description: "If true, the provider will install the release at the specified version even if a release not controlled by the provider is present: this is equivalent to using the 'helm upgrade' CLI tool rather than 'helm install'.",
},
"install": {
Type: schema.TypeBool,
Optional: true,
Default: false,
Description: "When using the 'upgrade' strategy, install the release if it is not already present. This is equivalent to using the 'helm upgrade' CLI tool with the '--install' flag.",
},
},
},
Default: defaultAttributes["upgrade_install"],
Description: "If true, the provider will install the release at the specified version even if a release not controlled by the provider is present: this is equivalent to running 'helm upgrade --install' with the Helm CLI. WARNING: this may not be suitable for production use -- see the 'Upgrade Mode' note in the provider documentation. Defaults to `false`.",
},
"metadata": {
Type: schema.TypeList,
Expand Down Expand Up @@ -626,20 +611,11 @@ func resourceReleaseCreate(ctx context.Context, d *schema.ResourceData, meta int
}

var rel *release.Release
var installIfNoReleaseToUpgrade bool
var releaseAlreadyExists bool
var enableUpgradeStrategy bool

releaseName := d.Get("name").(string)
upgradeBlock := d.Get("upgrade").([]interface{})
if len(upgradeBlock) > 0 {
upgradeStrategyMap := upgradeBlock[0].(map[string]interface{})
var ok bool
enableUpgradeStrategy, ok = upgradeStrategyMap["enable"].(bool)
if ok && enableUpgradeStrategy {
installIfNoReleaseToUpgrade, _ = upgradeStrategyMap["install"].(bool)
}
}
enableUpgradeStrategy = d.Get("upgrade_install").(bool)

if enableUpgradeStrategy {
// Check to see if there is already a release installed.
Expand All @@ -656,7 +632,7 @@ func resourceReleaseCreate(ctx context.Context, d *schema.ResourceData, meta int
}

if enableUpgradeStrategy && releaseAlreadyExists {
debug("%s Upgrading chart", logID)
debug("%s Upgrade-installing chart installed out of band", logID)

upgradeClient := action.NewUpgrade(actionConfig)
upgradeClient.ChartPathOptions = *cpo
Expand All @@ -682,7 +658,7 @@ func resourceReleaseCreate(ctx context.Context, d *schema.ResourceData, meta int

debug("%s Upgrading chart", logID)
rel, err = upgradeClient.Run(releaseName, c, values)
} else if (enableUpgradeStrategy && installIfNoReleaseToUpgrade && !releaseAlreadyExists) || !enableUpgradeStrategy {
} else {
instClient := action.NewInstall(actionConfig)
instClient.Replace = d.Get("replace").(bool)

Expand Down Expand Up @@ -716,16 +692,12 @@ func resourceReleaseCreate(ctx context.Context, d *schema.ResourceData, meta int

debug("%s Installing chart", logID)
rel, err = instClient.Run(c, values)
} else if enableUpgradeStrategy && !installIfNoReleaseToUpgrade && !releaseAlreadyExists {
return diag.FromErr(fmt.Errorf(
"upgrade strategy enabled, but chart not already installed and install=false chartName=%v releaseName=%v enableUpgradeStrategy=%t installIfNoReleaseToUpgrade=%t releaseAlreadyExists=%t",
chartName, releaseName, enableUpgradeStrategy, installIfNoReleaseToUpgrade, releaseAlreadyExists))
}
if err != nil && rel == nil {
return diag.FromErr(err)
}

if err != nil && rel != nil {
if err != nil {
exists, existsErr := resourceReleaseExists(d, meta)

if existsErr != nil {
Expand Down
40 changes: 8 additions & 32 deletions helm/resource_release_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ func TestAccResourceRelease_emptyVersion(t *testing.T) {
})
}

// "upgrade" without a previously installed release with --install (effectively equivalent to TestAccResourceRelease_basic)
// "upgrade_install" without a previously installed release (effectively equivalent to TestAccResourceRelease_basic)
func TestAccResourceRelease_upgrade_with_install_coldstart(t *testing.T) {
name := randName("basic")
namespace := createRandomNamespace(t)
Expand All @@ -124,7 +124,7 @@ func TestAccResourceRelease_upgrade_with_install_coldstart(t *testing.T) {
CheckDestroy: testAccCheckHelmReleaseDestroy(namespace),

Steps: []resource.TestStep{{
Config: testAccHelmReleaseConfigWithUpgradeStrategy(testResourceName, namespace, name, "1.2.3", true, true),
Config: testAccHelmReleaseConfigWithUpgradeStrategy(testResourceName, namespace, name, "1.2.3", true),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr("helm_release.test", "metadata.0.name", name),
resource.TestCheckResourceAttr("helm_release.test", "metadata.0.namespace", namespace),
Expand All @@ -136,7 +136,7 @@ func TestAccResourceRelease_upgrade_with_install_coldstart(t *testing.T) {
resource.TestCheckResourceAttr("helm_release.test", "metadata.0.app_version", "1.19.5"),
),
}, {
Config: testAccHelmReleaseConfigWithUpgradeStrategy(testResourceName, namespace, name, "1.2.3", true, true),
Config: testAccHelmReleaseConfigWithUpgradeStrategy(testResourceName, namespace, name, "1.2.3", true),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr("helm_release.test", "metadata.0.revision", "1"),
resource.TestCheckResourceAttr("helm_release.test", "metadata.0.version", "1.2.3"),
Expand Down Expand Up @@ -177,25 +177,6 @@ func TestAccResourceRelease_upgrade_with_install_warmstart(t *testing.T) {
})
}

// "upgrade" without a previously installed release without --install (will fail because nothing to upgrade)
func TestAccResourceRelease_upgrade_without_install(t *testing.T) {
name := randName("basic")
namespace := createRandomNamespace(t)
// Delete namespace automatically created by helm after checks
defer deleteNamespace(t, namespace)

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckHelmReleaseDestroy(namespace),
Steps: []resource.TestStep{{
Config: testAccHelmReleaseConfigWithUpgradeStrategy(testResourceName, namespace, name, "1.2.3", true, false),
ExpectError: regexp.MustCompile("upgrade strategy enabled, but chart not already installed and install=false"),
ExpectNonEmptyPlan: true,
}},
})
}

func TestAccResourceRelease_import(t *testing.T) {
name := randName("import")
namespace := createRandomNamespace(t)
Expand Down Expand Up @@ -1010,7 +991,7 @@ func testAccHelmReleaseConfigEmptyVersion(resource, ns, name string) string {
`, resource, name, ns, testRepositoryURL)
}

func testAccHelmReleaseConfigWithUpgradeStrategy(resource, ns, name, version string, enabled, install bool) string {
func testAccHelmReleaseConfigWithUpgradeStrategy(resource, ns, name, version string, upgrade_install bool) string {
return fmt.Sprintf(`
resource "helm_release" "%s" {
name = %q
Expand All @@ -1020,10 +1001,7 @@ func testAccHelmReleaseConfigWithUpgradeStrategy(resource, ns, name, version str
chart = "test-chart"
version = %q
upgrade {
enable = %t
install = %t
}
upgrade_install = %t
set {
name = "foo"
Expand All @@ -1044,7 +1022,7 @@ func testAccHelmReleaseConfigWithUpgradeStrategy(resource, ns, name, version str
value = false
}
}
`, resource, name, ns, testRepositoryURL, version, enabled, install)
`, resource, name, ns, testRepositoryURL, version, upgrade_install)
}

func testAccHelmReleaseConfigWithUpgradeStrategyWarmstart(ns, name string) string {
Expand All @@ -1056,10 +1034,8 @@ func testAccHelmReleaseConfigWithUpgradeStrategyWarmstart(ns, name string) strin
chart = "./test-chart-1.2.3.tgz"
version = "0.1.0"
upgrade {
enable = true
install = false
}
upgrade_install = true
set {
name = "foo"
value = "bar"
Expand Down
8 changes: 3 additions & 5 deletions templates/resources/release.md.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -86,16 +86,14 @@ having to manually import the release into terraform state each time. But the me
different from the defaults and you can easily produce unexpected or undesirable results if you are not careful:
using this approach in production is not necessarily recommended!

If upgrade mode is enabled by setting `enable` to `true` in the `upgrade` block, the provider will first check to see
If upgrade mode is enabled by setting the `upgrade_install` attribute to `true`, the provider will first check to see
if a release with the given name already exists. If that release exists, it will attempt to upgrade the release to
the state defined in the resource, using the same strategy as the [helm upgrade](https://helm.sh/docs/helm/helm_upgrade)
command. In this case, the `generate_name`, `name_template` and `replace` attributes of the resource (if set) are
ignored, as those attributes are not supported by helm's "upgrade" behavior.

If the release does _not_ exist, the behavior is controlled by the setting of the `install` attribute. If `install`
is `false` or unset, the apply stage will fail: the provider cannot upgrade a non-existent release. If `install`
is set to `true`, the provider will perform a from-scratch installation of the chart. In this case, all resource
attributes are honored.
If the release does not already exist, the provider will perform a from-scratch installation of the chart. In this
case, all resource attributes are honored.

## Import

Expand Down

0 comments on commit 6dd3fb3

Please sign in to comment.