From b9acac33e276ab5d7ad0a54d3d12fe87d1a3c1ba Mon Sep 17 00:00:00 2001 From: Thomas Rijpstra Date: Thu, 25 Jun 2026 10:04:22 +0200 Subject: [PATCH] feat(shuttles): vendor terraform-provider-helm source --- .../.changelog/1012.txt | 7 + .../.changelog/1026.txt | 3 + .../.changelog/1027.txt | 3 + .../.changelog/1029.txt | 3 + .../.changelog/1030.txt | 3 + .../.changelog/1036.txt | 3 + .../.changelog/1037.txt | 7 + .../.changelog/1050.txt | 7 + .../.changelog/1051.txt | 3 + .../.changelog/1054.txt | 3 + .../.changelog/1055.txt | 3 + .../.changelog/1071.txt | 3 + .../.changelog/1097.txt | 3 + .../.changelog/1143.txt | 3 + .../.changelog/1153.txt | 3 + .../.changelog/1176.txt | 3 + .../.changelog/1228.txt | 3 + .../.changelog/1231.txt | 3 + .../.changelog/1246.txt | 4 + .../.changelog/1247.txt | 3 + .../.changelog/1300.txt | 39 + .../.changelog/1326.txt | 3 + .../.changelog/1329.txt | 3 + .../.changelog/1335.txt | 3 + .../.changelog/1377.txt | 3 + .../.changelog/1379.txt | 3 + .../.changelog/1380.txt | 3 + .../.changelog/1458.txt | 3 + .../.changelog/1487.txt | 3 + .../.changelog/1501.txt | 3 + .../.changelog/1534.txt | 3 + .../.changelog/1572.txt | 3 + .../.changelog/1583.txt | 4 + .../.changelog/1592.txt | 3 + .../.changelog/1608.txt | 3 + .../.changelog/1615.txt | 3 + .../.changelog/1625.txt | 3 + .../.changelog/1633.txt | 3 + .../.changelog/1638.txt | 3 + .../.changelog/1644.txt | 3 + .../.changelog/839.txt | 3 + .../.changelog/862.txt | 3 + .../.changelog/903.txt | 3 + .../.changelog/945.txt | 3 + .../.changelog/950.txt | 3 + .../.changelog/966.txt | 3 + .../.changelog/982.txt | 3 + .../.changelog/changelog.tmpl | 71 + .../.changelog/note.tmpl | 3 + .../terraform-provider-helm/.copywrite.hcl | 16 + .../.github/CODEOWNERS | 1 + .../.github/ISSUE_TEMPLATE/bug-report.md | 61 + .../.github/ISSUE_TEMPLATE/config.yml | 5 + .../.github/ISSUE_TEMPLATE/feature-request.md | 39 + .../.github/ISSUE_TEMPLATE/question.md | 34 + .../.github/dependabot.yml | 18 + .../.github/labeler-issue-triage.yml | 4 + .../.github/labeler-pull-request-triage.yml | 4 + .../.github/pull_request_template.md | 41 + .../terraform-provider-helm/.github/tf.png | Bin 0 -> 26289 bytes .../workflows/acceptance_test_dfa.yaml | 31 + .../.github/workflows/build.yml | 153 + .../.github/workflows/changelog-checker.yml | 36 + .../.github/workflows/codeql-analysis.yml | 68 + .../.github/workflows/hc-copywrite.yml | 25 + .../workflows/issue-comment-created.yml | 15 + .../.github/workflows/issue-opened.yml | 56 + .../.github/workflows/jira-issues.yml | 104 + .../.github/workflows/jira-pr.yml | 102 + .../.github/workflows/lock.yml | 23 + .../.github/workflows/prune_stale_issues.yml | 15 + .../.github/workflows/pull-request.yml | 25 + .../.github/workflows/tests.yaml | 63 + .../.github/workflows/website.yaml | 17 + .../terraform-provider-helm/.gitignore | 38 + .../.markdownlinkcheck.json | 29 + .../terraform-provider-helm/.markdownlint.yml | 19 + .../terraform-provider-helm/.release/ci.hcl | 81 + .../.release/release-metadata.hcl | 4 + .../.release/security-scan.hcl | 18 + ...erraform-provider-kubernetes-artifacts.hcl | 16 + .../terraform-provider-helm/CHANGELOG.md | 585 ++++ .../CHANGELOG_GUIDE.md | 111 + .../terraform-provider-helm/GNUmakefile | 130 + .../terraform/terraform-provider-helm/LICENSE | 375 +++ .../META.d/_summary.yaml | 15 + .../terraform-provider-helm/META.d/links.yaml | 10 + .../terraform-provider-helm/README.md | 60 + .../_about/CONTRIBUTING.md | 37 + .../terraform-provider-helm/_about/FAQ.md | 45 + .../terraform-provider-helm/_about/ISSUES.md | 56 + .../_about/PULL_REQUESTS.md | 46 + .../docs/data-sources/template.md | 232 ++ .../docs/guides/v2-upgrade-guide.md | 72 + .../docs/guides/v3-upgrade-guide.md | 246 ++ .../terraform-provider-helm/docs/index.md | 212 ++ .../docs/resources/release.md | 386 +++ .../data-sources/template/example_1.tf | 41 + .../data-sources/template/example_2.tf | 46 + .../examples/example_1.tf | 31 + .../examples/example_2.tf | 5 + .../examples/example_3.tf | 8 + .../examples/example_4.tf | 9 + .../examples/example_5.tf | 11 + .../examples/example_6.tf | 12 + .../examples/resources/release/example_1.tf | 29 + .../examples/resources/release/example_10.tf | 4 + .../examples/resources/release/example_11.tf | 6 + .../examples/resources/release/example_2.tf | 4 + .../examples/resources/release/example_3.tf | 4 + .../examples/resources/release/example_4.tf | 22 + .../examples/resources/release/example_5.tf | 25 + .../examples/resources/release/example_6.tf | 25 + .../examples/resources/release/example_7.tf | 7 + .../examples/resources/release/example_8.tf | 6 + .../examples/resources/release/example_9.tf | 6 + .../terraform/terraform-provider-helm/go.mod | 206 ++ .../terraform/terraform-provider-helm/go.sum | 658 +++++ .../helm/data_helm_template.go | 1072 +++++++ .../helm/data_helm_template_test.go | 379 +++ .../helm/kubeconfig.go | 237 ++ .../helm/manifest_json.go | 95 + .../helm/manifest_json_test.go | 29 + .../terraform-provider-helm/helm/provider.go | 701 +++++ .../helm/provider_test.go | 350 +++ .../helm/resource_helm_release.go | 2271 +++++++++++++++ .../resource_helm_release_stateupgrader.go | 325 +++ ...esource_helm_release_stateupgrader_test.go | 215 ++ .../helm/resource_helm_release_test.go | 2506 +++++++++++++++++ .../helm/test-infra/README.md | 25 + .../helm/test-infra/gke/README.md | 38 + .../test-infra/gke/kubeconfig-template.yaml | 26 + .../helm/test-infra/gke/main.tf | 89 + .../test-infra/install-helm-via-docker.sh | 65 + .../helm/testdata/.gitingore | 2 + .../testdata/charts/broken-chart/Chart.yaml | 6 + .../broken-chart/templates/service.yaml | 13 + .../testdata/charts/crds-chart/.helmignore | 23 + .../testdata/charts/crds-chart/Chart.yaml | 23 + .../charts/crds-chart/crds/apples.yaml | 41 + .../charts/crds-chart/crds/oranges.yaml | 41 + .../charts/crds-chart/templates/NOTES.txt | 21 + .../charts/crds-chart/templates/_helpers.tpl | 62 + .../crds-chart/templates/configmaps.yaml | 18 + .../crds-chart/templates/deployment.yaml | 61 + .../charts/crds-chart/templates/hpa.yaml | 28 + .../charts/crds-chart/templates/ingress.yaml | 41 + .../charts/crds-chart/templates/service.yaml | 15 + .../crds-chart/templates/serviceaccount.yaml | 12 + .../templates/tests/test-connection.yaml | 15 + .../testdata/charts/crds-chart/values.yaml | 79 + .../charts/dependency-bar/.helmignore | 23 + .../testdata/charts/dependency-bar/Chart.yaml | 23 + .../charts/dependency-bar/templates/NOTES.txt | 21 + .../dependency-bar/templates/_helpers.tpl | 62 + .../dependency-bar/templates/deployment.yaml | 61 + .../charts/dependency-bar/templates/hpa.yaml | 28 + .../dependency-bar/templates/ingress.yaml | 41 + .../dependency-bar/templates/service.yaml | 15 + .../templates/serviceaccount.yaml | 12 + .../templates/tests/test-connection.yaml | 15 + .../charts/dependency-bar/values.yaml | 79 + .../charts/dependency-foo/.helmignore | 23 + .../testdata/charts/dependency-foo/Chart.yaml | 23 + .../charts/dependency-foo/templates/NOTES.txt | 21 + .../dependency-foo/templates/_helpers.tpl | 62 + .../dependency-foo/templates/deployment.yaml | 61 + .../charts/dependency-foo/templates/hpa.yaml | 28 + .../dependency-foo/templates/ingress.yaml | 41 + .../dependency-foo/templates/service.yaml | 15 + .../templates/serviceaccount.yaml | 12 + .../templates/tests/test-connection.yaml | 15 + .../charts/dependency-foo/values.yaml | 79 + .../testdata/charts/failed-deploy/Chart.yaml | 6 + .../failed-deploy/templates/service.yaml | 12 + .../testdata/charts/kube-version/Chart.yaml | 7 + .../kube-version/templates/_helpers.tpl | 42 + .../kube-version/templates/deployment.yaml | 53 + .../testdata/charts/kube-version/values.yaml | 49 + .../testdata/charts/test-chart-v2/.helmignore | 23 + .../testdata/charts/test-chart-v2/Chart.yaml | 23 + .../charts/test-chart-v2/templates/NOTES.txt | 21 + .../test-chart-v2/templates/_helpers.tpl | 62 + .../test-chart-v2/templates/deployment.yaml | 61 + .../charts/test-chart-v2/templates/hpa.yaml | 28 + .../test-chart-v2/templates/ingress.yaml | 41 + .../test-chart-v2/templates/service.yaml | 15 + .../templates/serviceaccount.yaml | 12 + .../templates/tests/test-connection.yaml | 15 + .../testdata/charts/test-chart-v2/values.yaml | 81 + .../testdata/charts/test-chart/.helmignore | 23 + .../testdata/charts/test-chart/Chart.yaml | 23 + .../charts/test-chart/templates/NOTES.txt | 21 + .../charts/test-chart/templates/_helpers.tpl | 62 + .../test-chart/templates/configmaps.yaml | 18 + .../test-chart/templates/deployment.yaml | 61 + .../charts/test-chart/templates/hpa.yaml | 28 + .../charts/test-chart/templates/ingress.yaml | 41 + .../charts/test-chart/templates/secrets.yaml | 6 + .../charts/test-chart/templates/service.yaml | 15 + .../test-chart/templates/serviceaccount.yaml | 12 + .../templates/tests/test-connection.yaml | 15 + .../testdata/charts/test-chart/values.yaml | 82 + .../testdata/charts/umbrella-chart/.gitignore | 1 + .../charts/umbrella-chart/.helmignore | 23 + .../testdata/charts/umbrella-chart/Chart.lock | 9 + .../testdata/charts/umbrella-chart/Chart.yaml | 31 + .../charts/umbrella-chart/templates/NOTES.txt | 21 + .../umbrella-chart/templates/_helpers.tpl | 62 + .../umbrella-chart/templates/deployment.yaml | 61 + .../charts/umbrella-chart/templates/hpa.yaml | 28 + .../umbrella-chart/templates/ingress.yaml | 41 + .../umbrella-chart/templates/service.yaml | 18 + .../templates/serviceaccount.yaml | 12 + .../templates/tests/test-connection.yaml | 15 + .../charts/umbrella-chart/values.yaml | 79 + .../manifest_json/rendered_manifest.json | 63 + .../manifest_json/rendered_manifest.yaml | 48 + .../helm/testdata/oci_registry/auth.htpasswd | 1 + .../helm/testing/config-da-basic/test.tf | 29 + .../helm/testing/deferred_actions_test.go | 84 + .../terraform/terraform-provider-helm/main.go | 45 + .../scripts/changelog-links.sh | 34 + .../scripts/errcheck.sh | 27 + .../scripts/fix-vendoring.sh | 25 + .../scripts/get-version-matrix.sh | 12 + .../scripts/gofmtcheck.sh | 16 + .../scripts/gogetcookie.sh | 15 + .../scripts/markdown-link-check.sh | 77 + .../templates/data-sources/template.md.tmpl | 31 + .../templates/guides/v2-upgrade-guide.md | 72 + .../templates/index.md.tmpl | 126 + .../templates/resources/release.md.tmpl | 123 + .../terraform-registry-manifest.json | 6 + .../terraform-provider-helm/tools/tools.go | 11 + .../terraform-provider-helm/version/VERSION | 1 + 236 files changed, 17098 insertions(+) create mode 100644 shuttles/terraform/terraform-provider-helm/.changelog/1012.txt create mode 100644 shuttles/terraform/terraform-provider-helm/.changelog/1026.txt create mode 100644 shuttles/terraform/terraform-provider-helm/.changelog/1027.txt create mode 100644 shuttles/terraform/terraform-provider-helm/.changelog/1029.txt create mode 100644 shuttles/terraform/terraform-provider-helm/.changelog/1030.txt create mode 100644 shuttles/terraform/terraform-provider-helm/.changelog/1036.txt create mode 100644 shuttles/terraform/terraform-provider-helm/.changelog/1037.txt create mode 100644 shuttles/terraform/terraform-provider-helm/.changelog/1050.txt create mode 100644 shuttles/terraform/terraform-provider-helm/.changelog/1051.txt create mode 100644 shuttles/terraform/terraform-provider-helm/.changelog/1054.txt create mode 100644 shuttles/terraform/terraform-provider-helm/.changelog/1055.txt create mode 100644 shuttles/terraform/terraform-provider-helm/.changelog/1071.txt create mode 100644 shuttles/terraform/terraform-provider-helm/.changelog/1097.txt create mode 100644 shuttles/terraform/terraform-provider-helm/.changelog/1143.txt create mode 100644 shuttles/terraform/terraform-provider-helm/.changelog/1153.txt create mode 100644 shuttles/terraform/terraform-provider-helm/.changelog/1176.txt create mode 100644 shuttles/terraform/terraform-provider-helm/.changelog/1228.txt create mode 100644 shuttles/terraform/terraform-provider-helm/.changelog/1231.txt create mode 100644 shuttles/terraform/terraform-provider-helm/.changelog/1246.txt create mode 100644 shuttles/terraform/terraform-provider-helm/.changelog/1247.txt create mode 100644 shuttles/terraform/terraform-provider-helm/.changelog/1300.txt create mode 100644 shuttles/terraform/terraform-provider-helm/.changelog/1326.txt create mode 100644 shuttles/terraform/terraform-provider-helm/.changelog/1329.txt create mode 100644 shuttles/terraform/terraform-provider-helm/.changelog/1335.txt create mode 100644 shuttles/terraform/terraform-provider-helm/.changelog/1377.txt create mode 100644 shuttles/terraform/terraform-provider-helm/.changelog/1379.txt create mode 100644 shuttles/terraform/terraform-provider-helm/.changelog/1380.txt create mode 100644 shuttles/terraform/terraform-provider-helm/.changelog/1458.txt create mode 100644 shuttles/terraform/terraform-provider-helm/.changelog/1487.txt create mode 100644 shuttles/terraform/terraform-provider-helm/.changelog/1501.txt create mode 100644 shuttles/terraform/terraform-provider-helm/.changelog/1534.txt create mode 100644 shuttles/terraform/terraform-provider-helm/.changelog/1572.txt create mode 100644 shuttles/terraform/terraform-provider-helm/.changelog/1583.txt create mode 100644 shuttles/terraform/terraform-provider-helm/.changelog/1592.txt create mode 100644 shuttles/terraform/terraform-provider-helm/.changelog/1608.txt create mode 100644 shuttles/terraform/terraform-provider-helm/.changelog/1615.txt create mode 100644 shuttles/terraform/terraform-provider-helm/.changelog/1625.txt create mode 100644 shuttles/terraform/terraform-provider-helm/.changelog/1633.txt create mode 100644 shuttles/terraform/terraform-provider-helm/.changelog/1638.txt create mode 100644 shuttles/terraform/terraform-provider-helm/.changelog/1644.txt create mode 100644 shuttles/terraform/terraform-provider-helm/.changelog/839.txt create mode 100644 shuttles/terraform/terraform-provider-helm/.changelog/862.txt create mode 100644 shuttles/terraform/terraform-provider-helm/.changelog/903.txt create mode 100644 shuttles/terraform/terraform-provider-helm/.changelog/945.txt create mode 100644 shuttles/terraform/terraform-provider-helm/.changelog/950.txt create mode 100644 shuttles/terraform/terraform-provider-helm/.changelog/966.txt create mode 100644 shuttles/terraform/terraform-provider-helm/.changelog/982.txt create mode 100644 shuttles/terraform/terraform-provider-helm/.changelog/changelog.tmpl create mode 100644 shuttles/terraform/terraform-provider-helm/.changelog/note.tmpl create mode 100644 shuttles/terraform/terraform-provider-helm/.copywrite.hcl create mode 100644 shuttles/terraform/terraform-provider-helm/.github/CODEOWNERS create mode 100644 shuttles/terraform/terraform-provider-helm/.github/ISSUE_TEMPLATE/bug-report.md create mode 100644 shuttles/terraform/terraform-provider-helm/.github/ISSUE_TEMPLATE/config.yml create mode 100644 shuttles/terraform/terraform-provider-helm/.github/ISSUE_TEMPLATE/feature-request.md create mode 100644 shuttles/terraform/terraform-provider-helm/.github/ISSUE_TEMPLATE/question.md create mode 100644 shuttles/terraform/terraform-provider-helm/.github/dependabot.yml create mode 100644 shuttles/terraform/terraform-provider-helm/.github/labeler-issue-triage.yml create mode 100644 shuttles/terraform/terraform-provider-helm/.github/labeler-pull-request-triage.yml create mode 100644 shuttles/terraform/terraform-provider-helm/.github/pull_request_template.md create mode 100644 shuttles/terraform/terraform-provider-helm/.github/tf.png create mode 100644 shuttles/terraform/terraform-provider-helm/.github/workflows/acceptance_test_dfa.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/.github/workflows/build.yml create mode 100644 shuttles/terraform/terraform-provider-helm/.github/workflows/changelog-checker.yml create mode 100644 shuttles/terraform/terraform-provider-helm/.github/workflows/codeql-analysis.yml create mode 100644 shuttles/terraform/terraform-provider-helm/.github/workflows/hc-copywrite.yml create mode 100644 shuttles/terraform/terraform-provider-helm/.github/workflows/issue-comment-created.yml create mode 100644 shuttles/terraform/terraform-provider-helm/.github/workflows/issue-opened.yml create mode 100644 shuttles/terraform/terraform-provider-helm/.github/workflows/jira-issues.yml create mode 100644 shuttles/terraform/terraform-provider-helm/.github/workflows/jira-pr.yml create mode 100644 shuttles/terraform/terraform-provider-helm/.github/workflows/lock.yml create mode 100644 shuttles/terraform/terraform-provider-helm/.github/workflows/prune_stale_issues.yml create mode 100644 shuttles/terraform/terraform-provider-helm/.github/workflows/pull-request.yml create mode 100644 shuttles/terraform/terraform-provider-helm/.github/workflows/tests.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/.github/workflows/website.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/.gitignore create mode 100644 shuttles/terraform/terraform-provider-helm/.markdownlinkcheck.json create mode 100644 shuttles/terraform/terraform-provider-helm/.markdownlint.yml create mode 100644 shuttles/terraform/terraform-provider-helm/.release/ci.hcl create mode 100644 shuttles/terraform/terraform-provider-helm/.release/release-metadata.hcl create mode 100644 shuttles/terraform/terraform-provider-helm/.release/security-scan.hcl create mode 100644 shuttles/terraform/terraform-provider-helm/.release/terraform-provider-kubernetes-artifacts.hcl create mode 100644 shuttles/terraform/terraform-provider-helm/CHANGELOG.md create mode 100644 shuttles/terraform/terraform-provider-helm/CHANGELOG_GUIDE.md create mode 100644 shuttles/terraform/terraform-provider-helm/GNUmakefile create mode 100644 shuttles/terraform/terraform-provider-helm/LICENSE create mode 100644 shuttles/terraform/terraform-provider-helm/META.d/_summary.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/META.d/links.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/README.md create mode 100644 shuttles/terraform/terraform-provider-helm/_about/CONTRIBUTING.md create mode 100644 shuttles/terraform/terraform-provider-helm/_about/FAQ.md create mode 100644 shuttles/terraform/terraform-provider-helm/_about/ISSUES.md create mode 100644 shuttles/terraform/terraform-provider-helm/_about/PULL_REQUESTS.md create mode 100644 shuttles/terraform/terraform-provider-helm/docs/data-sources/template.md create mode 100644 shuttles/terraform/terraform-provider-helm/docs/guides/v2-upgrade-guide.md create mode 100644 shuttles/terraform/terraform-provider-helm/docs/guides/v3-upgrade-guide.md create mode 100644 shuttles/terraform/terraform-provider-helm/docs/index.md create mode 100644 shuttles/terraform/terraform-provider-helm/docs/resources/release.md create mode 100644 shuttles/terraform/terraform-provider-helm/examples/data-sources/template/example_1.tf create mode 100644 shuttles/terraform/terraform-provider-helm/examples/data-sources/template/example_2.tf create mode 100644 shuttles/terraform/terraform-provider-helm/examples/example_1.tf create mode 100644 shuttles/terraform/terraform-provider-helm/examples/example_2.tf create mode 100644 shuttles/terraform/terraform-provider-helm/examples/example_3.tf create mode 100644 shuttles/terraform/terraform-provider-helm/examples/example_4.tf create mode 100644 shuttles/terraform/terraform-provider-helm/examples/example_5.tf create mode 100644 shuttles/terraform/terraform-provider-helm/examples/example_6.tf create mode 100644 shuttles/terraform/terraform-provider-helm/examples/resources/release/example_1.tf create mode 100644 shuttles/terraform/terraform-provider-helm/examples/resources/release/example_10.tf create mode 100644 shuttles/terraform/terraform-provider-helm/examples/resources/release/example_11.tf create mode 100644 shuttles/terraform/terraform-provider-helm/examples/resources/release/example_2.tf create mode 100644 shuttles/terraform/terraform-provider-helm/examples/resources/release/example_3.tf create mode 100644 shuttles/terraform/terraform-provider-helm/examples/resources/release/example_4.tf create mode 100644 shuttles/terraform/terraform-provider-helm/examples/resources/release/example_5.tf create mode 100644 shuttles/terraform/terraform-provider-helm/examples/resources/release/example_6.tf create mode 100644 shuttles/terraform/terraform-provider-helm/examples/resources/release/example_7.tf create mode 100644 shuttles/terraform/terraform-provider-helm/examples/resources/release/example_8.tf create mode 100644 shuttles/terraform/terraform-provider-helm/examples/resources/release/example_9.tf create mode 100644 shuttles/terraform/terraform-provider-helm/go.mod create mode 100644 shuttles/terraform/terraform-provider-helm/go.sum create mode 100644 shuttles/terraform/terraform-provider-helm/helm/data_helm_template.go create mode 100644 shuttles/terraform/terraform-provider-helm/helm/data_helm_template_test.go create mode 100644 shuttles/terraform/terraform-provider-helm/helm/kubeconfig.go create mode 100644 shuttles/terraform/terraform-provider-helm/helm/manifest_json.go create mode 100644 shuttles/terraform/terraform-provider-helm/helm/manifest_json_test.go create mode 100644 shuttles/terraform/terraform-provider-helm/helm/provider.go create mode 100644 shuttles/terraform/terraform-provider-helm/helm/provider_test.go create mode 100644 shuttles/terraform/terraform-provider-helm/helm/resource_helm_release.go create mode 100644 shuttles/terraform/terraform-provider-helm/helm/resource_helm_release_stateupgrader.go create mode 100644 shuttles/terraform/terraform-provider-helm/helm/resource_helm_release_stateupgrader_test.go create mode 100644 shuttles/terraform/terraform-provider-helm/helm/resource_helm_release_test.go create mode 100644 shuttles/terraform/terraform-provider-helm/helm/test-infra/README.md create mode 100644 shuttles/terraform/terraform-provider-helm/helm/test-infra/gke/README.md create mode 100644 shuttles/terraform/terraform-provider-helm/helm/test-infra/gke/kubeconfig-template.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/test-infra/gke/main.tf create mode 100755 shuttles/terraform/terraform-provider-helm/helm/test-infra/install-helm-via-docker.sh create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/.gitingore create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/broken-chart/Chart.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/broken-chart/templates/service.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/.helmignore create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/Chart.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/crds/apples.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/crds/oranges.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/templates/NOTES.txt create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/templates/_helpers.tpl create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/templates/configmaps.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/templates/deployment.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/templates/hpa.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/templates/ingress.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/templates/service.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/templates/serviceaccount.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/templates/tests/test-connection.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/values.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-bar/.helmignore create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-bar/Chart.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-bar/templates/NOTES.txt create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-bar/templates/_helpers.tpl create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-bar/templates/deployment.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-bar/templates/hpa.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-bar/templates/ingress.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-bar/templates/service.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-bar/templates/serviceaccount.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-bar/templates/tests/test-connection.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-bar/values.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-foo/.helmignore create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-foo/Chart.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-foo/templates/NOTES.txt create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-foo/templates/_helpers.tpl create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-foo/templates/deployment.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-foo/templates/hpa.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-foo/templates/ingress.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-foo/templates/service.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-foo/templates/serviceaccount.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-foo/templates/tests/test-connection.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-foo/values.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/failed-deploy/Chart.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/failed-deploy/templates/service.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/kube-version/Chart.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/kube-version/templates/_helpers.tpl create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/kube-version/templates/deployment.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/kube-version/values.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart-v2/.helmignore create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart-v2/Chart.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart-v2/templates/NOTES.txt create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart-v2/templates/_helpers.tpl create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart-v2/templates/deployment.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart-v2/templates/hpa.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart-v2/templates/ingress.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart-v2/templates/service.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart-v2/templates/serviceaccount.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart-v2/templates/tests/test-connection.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart-v2/values.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart/.helmignore create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart/Chart.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart/templates/NOTES.txt create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart/templates/_helpers.tpl create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart/templates/configmaps.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart/templates/deployment.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart/templates/hpa.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart/templates/ingress.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart/templates/secrets.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart/templates/service.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart/templates/serviceaccount.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart/templates/tests/test-connection.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart/values.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/umbrella-chart/.gitignore create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/umbrella-chart/.helmignore create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/umbrella-chart/Chart.lock create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/umbrella-chart/Chart.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/umbrella-chart/templates/NOTES.txt create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/umbrella-chart/templates/_helpers.tpl create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/umbrella-chart/templates/deployment.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/umbrella-chart/templates/hpa.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/umbrella-chart/templates/ingress.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/umbrella-chart/templates/service.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/umbrella-chart/templates/serviceaccount.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/umbrella-chart/templates/tests/test-connection.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/charts/umbrella-chart/values.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/manifest_json/rendered_manifest.json create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/manifest_json/rendered_manifest.yaml create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testdata/oci_registry/auth.htpasswd create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testing/config-da-basic/test.tf create mode 100644 shuttles/terraform/terraform-provider-helm/helm/testing/deferred_actions_test.go create mode 100644 shuttles/terraform/terraform-provider-helm/main.go create mode 100755 shuttles/terraform/terraform-provider-helm/scripts/changelog-links.sh create mode 100755 shuttles/terraform/terraform-provider-helm/scripts/errcheck.sh create mode 100755 shuttles/terraform/terraform-provider-helm/scripts/fix-vendoring.sh create mode 100755 shuttles/terraform/terraform-provider-helm/scripts/get-version-matrix.sh create mode 100755 shuttles/terraform/terraform-provider-helm/scripts/gofmtcheck.sh create mode 100755 shuttles/terraform/terraform-provider-helm/scripts/gogetcookie.sh create mode 100755 shuttles/terraform/terraform-provider-helm/scripts/markdown-link-check.sh create mode 100644 shuttles/terraform/terraform-provider-helm/templates/data-sources/template.md.tmpl create mode 100644 shuttles/terraform/terraform-provider-helm/templates/guides/v2-upgrade-guide.md create mode 100644 shuttles/terraform/terraform-provider-helm/templates/index.md.tmpl create mode 100644 shuttles/terraform/terraform-provider-helm/templates/resources/release.md.tmpl create mode 100644 shuttles/terraform/terraform-provider-helm/terraform-registry-manifest.json create mode 100644 shuttles/terraform/terraform-provider-helm/tools/tools.go create mode 100644 shuttles/terraform/terraform-provider-helm/version/VERSION diff --git a/shuttles/terraform/terraform-provider-helm/.changelog/1012.txt b/shuttles/terraform/terraform-provider-helm/.changelog/1012.txt new file mode 100644 index 0000000..ad9704d --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.changelog/1012.txt @@ -0,0 +1,7 @@ +```release-note:feature +`provider`: Add a new attribute `burst_limit` for client-side throttling limit configuration. +``` + +```release-note:doc +`provider`: Add a new attribute `burst_limit`. +``` diff --git a/shuttles/terraform/terraform-provider-helm/.changelog/1026.txt b/shuttles/terraform/terraform-provider-helm/.changelog/1026.txt new file mode 100644 index 0000000..0c359e6 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.changelog/1026.txt @@ -0,0 +1,3 @@ +```release-note:doc +`resource/helm_release`: Add usage examples for `GCS` and `S3` plugins. +``` diff --git a/shuttles/terraform/terraform-provider-helm/.changelog/1027.txt b/shuttles/terraform/terraform-provider-helm/.changelog/1027.txt new file mode 100644 index 0000000..c013efd --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.changelog/1027.txt @@ -0,0 +1,3 @@ +```release-note:doc +`data_source/helm_template`: Correct some errors in examples. +``` diff --git a/shuttles/terraform/terraform-provider-helm/.changelog/1029.txt b/shuttles/terraform/terraform-provider-helm/.changelog/1029.txt new file mode 100644 index 0000000..27d07ec --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.changelog/1029.txt @@ -0,0 +1,3 @@ +```release-note:dependency +Bump `github.com/containerd/containerd` from `1.6.6` to `1.6.12` +``` diff --git a/shuttles/terraform/terraform-provider-helm/.changelog/1030.txt b/shuttles/terraform/terraform-provider-helm/.changelog/1030.txt new file mode 100644 index 0000000..01ac7c7 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.changelog/1030.txt @@ -0,0 +1,3 @@ +```release-note:doc +`resource/helm_release`: Add usage example for `OCI` repositories. +``` diff --git a/shuttles/terraform/terraform-provider-helm/.changelog/1036.txt b/shuttles/terraform/terraform-provider-helm/.changelog/1036.txt new file mode 100644 index 0000000..563b09a --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.changelog/1036.txt @@ -0,0 +1,3 @@ +```release-note:dependency +Bump `helm.sh/helm/v3` from `3.9.4` to `3.11.0` +``` diff --git a/shuttles/terraform/terraform-provider-helm/.changelog/1037.txt b/shuttles/terraform/terraform-provider-helm/.changelog/1037.txt new file mode 100644 index 0000000..ec351c7 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.changelog/1037.txt @@ -0,0 +1,7 @@ +```release-note:dependency +Bump `k8s.io/client-go` from `0.24.2` to `0.26.1` +``` + +```release-note:note +`provider`: `kubernetes.exec.api_version` no longer supports `client.authentication.k8s.io/v1alpha1`. Please, switch to `client.authentication.k8s.io/v1beta1` or `client.authentication.k8s.io/v1`. +``` diff --git a/shuttles/terraform/terraform-provider-helm/.changelog/1050.txt b/shuttles/terraform/terraform-provider-helm/.changelog/1050.txt new file mode 100644 index 0000000..86d3bf8 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.changelog/1050.txt @@ -0,0 +1,7 @@ +```release-note:enhancement +`data_source/helm_template`: Add a new attribute `crds` which when `include_crds` is set to `true` will be populated with a list of the manifests from the `crds/` folder of the chart. +``` + +```release-note:doc +`data_source/helm_template`: Add a new attribute `crds` +``` diff --git a/shuttles/terraform/terraform-provider-helm/.changelog/1051.txt b/shuttles/terraform/terraform-provider-helm/.changelog/1051.txt new file mode 100644 index 0000000..d21e790 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.changelog/1051.txt @@ -0,0 +1,3 @@ +```release-note:doc +`provider`: Add a note regarding the `KUBECONFIG` environment variable. +``` diff --git a/shuttles/terraform/terraform-provider-helm/.changelog/1054.txt b/shuttles/terraform/terraform-provider-helm/.changelog/1054.txt new file mode 100644 index 0000000..8b21b93 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.changelog/1054.txt @@ -0,0 +1,3 @@ +```release-note:dependency +Bump `helm.sh/helm/v3` from `3.11.0` to `3.11.1` +``` diff --git a/shuttles/terraform/terraform-provider-helm/.changelog/1055.txt b/shuttles/terraform/terraform-provider-helm/.changelog/1055.txt new file mode 100644 index 0000000..c2ce123 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.changelog/1055.txt @@ -0,0 +1,3 @@ +```release-note:dependency +Bump `golang.org/x/crypto` from `0.5.0` to `0.6.0` +``` diff --git a/shuttles/terraform/terraform-provider-helm/.changelog/1071.txt b/shuttles/terraform/terraform-provider-helm/.changelog/1071.txt new file mode 100644 index 0000000..525afcb --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.changelog/1071.txt @@ -0,0 +1,3 @@ +```release-note:feature +`helm/resource_release.go`: Add `set_list` attribute +``` diff --git a/shuttles/terraform/terraform-provider-helm/.changelog/1097.txt b/shuttles/terraform/terraform-provider-helm/.changelog/1097.txt new file mode 100644 index 0000000..d108cf6 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.changelog/1097.txt @@ -0,0 +1,3 @@ +```release-note:bug +`helm/resource_release.go`: Always recompute metadata when a release is updated +``` diff --git a/shuttles/terraform/terraform-provider-helm/.changelog/1143.txt b/shuttles/terraform/terraform-provider-helm/.changelog/1143.txt new file mode 100644 index 0000000..07cf16c --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.changelog/1143.txt @@ -0,0 +1,3 @@ +```release-note:dependency +Bump `helm.sh/helm/v3` from `3.11.2` to `3.12.0` +``` diff --git a/shuttles/terraform/terraform-provider-helm/.changelog/1153.txt b/shuttles/terraform/terraform-provider-helm/.changelog/1153.txt new file mode 100644 index 0000000..2ee6372 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.changelog/1153.txt @@ -0,0 +1,3 @@ +```release-note:bug +`helm/resource_release.go`: Fix: only recompute metadata if version actually changes +``` diff --git a/shuttles/terraform/terraform-provider-helm/.changelog/1176.txt b/shuttles/terraform/terraform-provider-helm/.changelog/1176.txt new file mode 100644 index 0000000..b64225d --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.changelog/1176.txt @@ -0,0 +1,3 @@ +```release-note:bug +`helm/resource_release.go`: Fix: version conflicts when using local chart +``` \ No newline at end of file diff --git a/shuttles/terraform/terraform-provider-helm/.changelog/1228.txt b/shuttles/terraform/terraform-provider-helm/.changelog/1228.txt new file mode 100644 index 0000000..85d0cda --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.changelog/1228.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +`resource/helm_release`: add `name` field validation to be limited to 53 characters. +``` diff --git a/shuttles/terraform/terraform-provider-helm/.changelog/1231.txt b/shuttles/terraform/terraform-provider-helm/.changelog/1231.txt new file mode 100644 index 0000000..b5c49e4 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.changelog/1231.txt @@ -0,0 +1,3 @@ +```release-note:bug +`resource/helm_release`: Add nil check for `set_list.value` to prevent provider ChartPathOptions +``` \ No newline at end of file diff --git a/shuttles/terraform/terraform-provider-helm/.changelog/1246.txt b/shuttles/terraform/terraform-provider-helm/.changelog/1246.txt new file mode 100644 index 0000000..b6dcc24 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.changelog/1246.txt @@ -0,0 +1,4 @@ +```release-note:bug +`helm_release`: Fix perpetual diff when version attribute is an empty string +``` + diff --git a/shuttles/terraform/terraform-provider-helm/.changelog/1247.txt b/shuttles/terraform/terraform-provider-helm/.changelog/1247.txt new file mode 100644 index 0000000..d86fda3 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.changelog/1247.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +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) +``` diff --git a/shuttles/terraform/terraform-provider-helm/.changelog/1300.txt b/shuttles/terraform/terraform-provider-helm/.changelog/1300.txt new file mode 100644 index 0000000..89645fe --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.changelog/1300.txt @@ -0,0 +1,39 @@ +```release-note:dependency +Bump Golang from `1.20` to `1.21`. +``` + +```release-note:dependency +Bump helm.sh/helm/v3 from `v3.13.1` to `v3.13.2`. +``` + +```release-note:dependency +Bump github.com/hashicorp/go-cty from `v1.4.1-0.20200414143053-d3edf31b6320` to `v1.4.1-0.20200723130312-85980079f637`. +``` + +```release-note:dependency +Bump github.com/hashicorp/terraform-plugin-docs from `v0.14.1` to `v0.16.0`. +``` + +```release-note:dependency +Bump github.com/hashicorp/terraform-plugin-sdk/v2 from `v2.26.1` to `v2.30.0`. +``` + +```release-note:dependency +Bump golang.org/x/crypto from `v0.14.0` to `v0.16.0`. +``` + +```release-note:dependency +Bump k8s.io/api from `v0.28.3` to `v0.28.4`. +``` + +```release-note:dependency +Bump k8s.io/apimachinery from `v0.28.3` to `v0.28.4`. +``` + +```release-note:dependency +Bump k8s.io/client-go from `v0.28.3` to `v0.28.4`. +``` + +```release-note:dependency +Bump sigs.k8s.io/yaml from `v1.3.0` to `v1.4.0`. +``` diff --git a/shuttles/terraform/terraform-provider-helm/.changelog/1326.txt b/shuttles/terraform/terraform-provider-helm/.changelog/1326.txt new file mode 100644 index 0000000..80adf26 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.changelog/1326.txt @@ -0,0 +1,3 @@ +```release-note:bug +`provider`: Fix manifest diff rendering for OCI charts. +``` diff --git a/shuttles/terraform/terraform-provider-helm/.changelog/1329.txt b/shuttles/terraform/terraform-provider-helm/.changelog/1329.txt new file mode 100644 index 0000000..62aa59e --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.changelog/1329.txt @@ -0,0 +1,3 @@ +```release-note:doc +`docs`: Use templatefile() instead of "template_file" provider in GKE example. +``` diff --git a/shuttles/terraform/terraform-provider-helm/.changelog/1335.txt b/shuttles/terraform/terraform-provider-helm/.changelog/1335.txt new file mode 100644 index 0000000..5e41e57 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.changelog/1335.txt @@ -0,0 +1,3 @@ +```release-note: enhancement +`resource/helm_release`: enable helm lockup function. +``` \ No newline at end of file diff --git a/shuttles/terraform/terraform-provider-helm/.changelog/1377.txt b/shuttles/terraform/terraform-provider-helm/.changelog/1377.txt new file mode 100644 index 0000000..2d81d5c --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.changelog/1377.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +Add support for Terraform's experimental deferred actions +``` \ No newline at end of file diff --git a/shuttles/terraform/terraform-provider-helm/.changelog/1379.txt b/shuttles/terraform/terraform-provider-helm/.changelog/1379.txt new file mode 100644 index 0000000..973a8ae --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.changelog/1379.txt @@ -0,0 +1,3 @@ +```release-note:dependency +Provider project ported from `terraform-plugin-sdk/v2` to `terraform-plugin-framework` +``` diff --git a/shuttles/terraform/terraform-provider-helm/.changelog/1380.txt b/shuttles/terraform/terraform-provider-helm/.changelog/1380.txt new file mode 100644 index 0000000..6d79a96 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.changelog/1380.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +`helm_release`: add new attributes metadata.last_deployed, metadata.first_deployed, metadata.notes +``` diff --git a/shuttles/terraform/terraform-provider-helm/.changelog/1458.txt b/shuttles/terraform/terraform-provider-helm/.changelog/1458.txt new file mode 100644 index 0000000..dcb4382 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.changelog/1458.txt @@ -0,0 +1,3 @@ +```release-note:bug +`resource/helm_release`: Fix: only recompute metadata when the version in the metadata changes +``` diff --git a/shuttles/terraform/terraform-provider-helm/.changelog/1487.txt b/shuttles/terraform/terraform-provider-helm/.changelog/1487.txt new file mode 100644 index 0000000..03f323e --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.changelog/1487.txt @@ -0,0 +1,3 @@ +```release-note:bug +`helm_release`: On destroy, do not error when release is not found +``` diff --git a/shuttles/terraform/terraform-provider-helm/.changelog/1501.txt b/shuttles/terraform/terraform-provider-helm/.changelog/1501.txt new file mode 100644 index 0000000..5456846 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.changelog/1501.txt @@ -0,0 +1,3 @@ +```release-note:bug +`helm_release`: Fix nil pointer deref panic on destroy when helm release is not found +``` diff --git a/shuttles/terraform/terraform-provider-helm/.changelog/1534.txt b/shuttles/terraform/terraform-provider-helm/.changelog/1534.txt new file mode 100644 index 0000000..9b29563 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.changelog/1534.txt @@ -0,0 +1,3 @@ +```release-note:bug +`resoure/helm_release`: fix an issue where `postrender.args` is not parsed correctly. +``` diff --git a/shuttles/terraform/terraform-provider-helm/.changelog/1572.txt b/shuttles/terraform/terraform-provider-helm/.changelog/1572.txt new file mode 100644 index 0000000..732570d --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.changelog/1572.txt @@ -0,0 +1,3 @@ +```release-note:bug +change `set.value` && `set_list.value` to optional instead of required +``` \ No newline at end of file diff --git a/shuttles/terraform/terraform-provider-helm/.changelog/1583.txt b/shuttles/terraform/terraform-provider-helm/.changelog/1583.txt new file mode 100644 index 0000000..00c538d --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.changelog/1583.txt @@ -0,0 +1,4 @@ +```release-note:bug +`helm_release`: Fix namespace behaviour for dependency charts in non-default namespaces +``` + diff --git a/shuttles/terraform/terraform-provider-helm/.changelog/1592.txt b/shuttles/terraform/terraform-provider-helm/.changelog/1592.txt new file mode 100644 index 0000000..f433883 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.changelog/1592.txt @@ -0,0 +1,3 @@ +```release-note:feature +`helm_release`: Add `set_wo` write-only attribute +``` diff --git a/shuttles/terraform/terraform-provider-helm/.changelog/1608.txt b/shuttles/terraform/terraform-provider-helm/.changelog/1608.txt new file mode 100644 index 0000000..e1f069a --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.changelog/1608.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +update helm dependency to v3.17.2 +``` diff --git a/shuttles/terraform/terraform-provider-helm/.changelog/1615.txt b/shuttles/terraform/terraform-provider-helm/.changelog/1615.txt new file mode 100644 index 0000000..2ed3353 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.changelog/1615.txt @@ -0,0 +1,3 @@ +```release-note:feature +Add `"literal"` as a supported `type` for the `set` block +``` \ No newline at end of file diff --git a/shuttles/terraform/terraform-provider-helm/.changelog/1625.txt b/shuttles/terraform/terraform-provider-helm/.changelog/1625.txt new file mode 100644 index 0000000..80fd857 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.changelog/1625.txt @@ -0,0 +1,3 @@ +```release-note:feature +`helm_release`: Add support for ResourceIdentity. +``` diff --git a/shuttles/terraform/terraform-provider-helm/.changelog/1633.txt b/shuttles/terraform/terraform-provider-helm/.changelog/1633.txt new file mode 100644 index 0000000..97baf5c --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.changelog/1633.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +`helm_release`: Add `UpgradeState` logic to support migration from SDKv2 to Plugin Framework +``` \ No newline at end of file diff --git a/shuttles/terraform/terraform-provider-helm/.changelog/1638.txt b/shuttles/terraform/terraform-provider-helm/.changelog/1638.txt new file mode 100644 index 0000000..5a6aee7 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.changelog/1638.txt @@ -0,0 +1,3 @@ +```release-note:bug +`helm_release`: Fix wrong type for "values" field in v3 state upgrader +``` diff --git a/shuttles/terraform/terraform-provider-helm/.changelog/1644.txt b/shuttles/terraform/terraform-provider-helm/.changelog/1644.txt new file mode 100644 index 0000000..aa4383b --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.changelog/1644.txt @@ -0,0 +1,3 @@ +```release-note:bug +`helm_release`: Fix shallow clone bug causing nested sensitive values to be redacted in the k8s API +``` diff --git a/shuttles/terraform/terraform-provider-helm/.changelog/839.txt b/shuttles/terraform/terraform-provider-helm/.changelog/839.txt new file mode 100644 index 0000000..af581c7 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.changelog/839.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +`kubernetes/provider.go`: Add `tls_server_name` kubernetes provider options. +``` \ No newline at end of file diff --git a/shuttles/terraform/terraform-provider-helm/.changelog/862.txt b/shuttles/terraform/terraform-provider-helm/.changelog/862.txt new file mode 100644 index 0000000..19ba167 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.changelog/862.txt @@ -0,0 +1,3 @@ +```release-note:feature +Add support for configuring OCI registries inside provider block +``` diff --git a/shuttles/terraform/terraform-provider-helm/.changelog/903.txt b/shuttles/terraform/terraform-provider-helm/.changelog/903.txt new file mode 100644 index 0000000..0c4ebd2 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.changelog/903.txt @@ -0,0 +1,3 @@ +```release-note:feature +Show Manifest when creating release +``` diff --git a/shuttles/terraform/terraform-provider-helm/.changelog/945.txt b/shuttles/terraform/terraform-provider-helm/.changelog/945.txt new file mode 100644 index 0000000..3f6176b --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.changelog/945.txt @@ -0,0 +1,3 @@ +```release-note:note +Upgrade Helm to v3.9.4 +``` diff --git a/shuttles/terraform/terraform-provider-helm/.changelog/950.txt b/shuttles/terraform/terraform-provider-helm/.changelog/950.txt new file mode 100644 index 0000000..307cd80 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.changelog/950.txt @@ -0,0 +1,3 @@ +```release-note:bug +Crash: Fix `show_only` crash when string is empty +``` diff --git a/shuttles/terraform/terraform-provider-helm/.changelog/966.txt b/shuttles/terraform/terraform-provider-helm/.changelog/966.txt new file mode 100644 index 0000000..f9ce93c --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.changelog/966.txt @@ -0,0 +1,3 @@ +```release-note:bug +Crash Fix: Fix Unknown Value in Manifest Diff +``` diff --git a/shuttles/terraform/terraform-provider-helm/.changelog/982.txt b/shuttles/terraform/terraform-provider-helm/.changelog/982.txt new file mode 100644 index 0000000..9a47a32 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.changelog/982.txt @@ -0,0 +1,3 @@ +```release-note:bug +`resource/helm_release`: Fix an issue when the provider crashes with the error message `Provider produced inconsistent final plan` after upgrading from `v2.5.1` to `v2.6.0` and higher. That happened due to changes in the provider schema and the introduction of a new attribute `pass_credentials` that was not properly handled. +``` diff --git a/shuttles/terraform/terraform-provider-helm/.changelog/changelog.tmpl b/shuttles/terraform/terraform-provider-helm/.changelog/changelog.tmpl new file mode 100644 index 0000000..cf77d8b --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.changelog/changelog.tmpl @@ -0,0 +1,71 @@ +{{- if index .NotesByType "breaking-change" -}} +BREAKING CHANGES: + +{{range index .NotesByType "breaking-change" -}} +* {{ template "note" . }} +{{ end -}} +{{- end -}} + +{{- if .NotesByType.security }} +SECURITY: + +{{range .NotesByType.security -}} +* {{ template "note" . }} +{{ end -}} +{{- end -}} + +{{- if .NotesByType.feature }} +FEATURES: + +{{range .NotesByType.feature -}} +* {{ template "note" . }} +{{ end -}} +{{- end -}} + +{{- if .NotesByType.enhancement }} +ENHANCEMENT: + +{{range .NotesByType.enhancement -}} +* {{ template "note" . }} +{{ end -}} +{{- end -}} + +{{- if .NotesByType.deprecation }} +DEPRECATIONS: + +{{range .NotesByType.deprecation -}} +* {{ template "note" . }} +{{ end -}} +{{- end -}} + +{{- if .NotesByType.bug }} +BUG FIXES: + +{{range .NotesByType.bug -}} +* {{ template "note" . }} +{{ end -}} +{{- end -}} + +{{- if .NotesByType.doc }} +DOCS: + +{{range .NotesByType.doc -}} +* {{ template "note" . }} +{{ end -}} +{{- end -}} + +{{- if .NotesByType.dependency }} +DEPENDENCIES: + +{{range .NotesByType.dependency -}} +* {{ template "note" . }} +{{ end -}} +{{- end -}} + +{{- if .NotesByType.note }} +NOTES: + +{{range .NotesByType.note -}} +* {{ template "note" . }} +{{ end -}} +{{- end -}} diff --git a/shuttles/terraform/terraform-provider-helm/.changelog/note.tmpl b/shuttles/terraform/terraform-provider-helm/.changelog/note.tmpl new file mode 100644 index 0000000..5f2aa03 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.changelog/note.tmpl @@ -0,0 +1,3 @@ +{{- define "note" -}} +{{.Body}}{{if not (stringHasPrefix .Issue "_")}} [[GH-{{- .Issue -}}](https://github.com/hashicorp/terraform-provider-helm/issues/{{- .Issue -}})]{{end}} +{{- end -}} diff --git a/shuttles/terraform/terraform-provider-helm/.copywrite.hcl b/shuttles/terraform/terraform-provider-helm/.copywrite.hcl new file mode 100644 index 0000000..8bc5bf2 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.copywrite.hcl @@ -0,0 +1,16 @@ +schema_version = 1 + +project { + license = "MPL-2.0" + copyright_year = 2017 + header_ignore = [ + ".changelog/**", + ".github/**", + ".goreleaser.yml", + ".markdownlint.yml", + ".release/**", + "helm/testdata/**", + "vendor/**", + "examples/**" + ] +} diff --git a/shuttles/terraform/terraform-provider-helm/.github/CODEOWNERS b/shuttles/terraform/terraform-provider-helm/.github/CODEOWNERS new file mode 100644 index 0000000..13c6134 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.github/CODEOWNERS @@ -0,0 +1 @@ +* @hashicorp/tf-eco-hybrid-cloud diff --git a/shuttles/terraform/terraform-provider-helm/.github/ISSUE_TEMPLATE/bug-report.md b/shuttles/terraform/terraform-provider-helm/.github/ISSUE_TEMPLATE/bug-report.md new file mode 100644 index 0000000..7a21cbd --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.github/ISSUE_TEMPLATE/bug-report.md @@ -0,0 +1,61 @@ +--- +name: "\U0001F41B Bug Report" +about: "If something isn't working as expected \U0001F914." +title: '' +labels: bug + +--- + +### Terraform, Provider, Kubernetes and Helm Versions + + +``` +Terraform version: +Provider version: +Kubernetes version: +``` + +### Affected Resource(s) + +- helm_release +- helm_repository + + + +### Terraform Configuration Files +```hcl +# Copy-paste your Terraform configurations here - for large Terraform configs, +# please use a service like Dropbox and share a link to the ZIP file. For +# security, you can also encrypt the files using our GPG public key. +``` + +### Debug Output + + +NOTE: In addition to Terraform debugging, please set HELM_DEBUG=1 to enable debugging info from helm. + +### Panic Output + + +### Steps to Reproduce + +1. `terraform apply` + +### Expected Behavior + + +### Actual Behavior + + +### Important Factoids + + +### References + +- GH-1234 + +### Community Note + +* Please vote on this issue by adding a 👍 [reaction](https://blog.github.com/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/) to the original issue to help the community and maintainers prioritize this request +* If you are interested in working on this issue or have submitted a pull request, please leave a comment diff --git a/shuttles/terraform/terraform-provider-helm/.github/ISSUE_TEMPLATE/config.yml b/shuttles/terraform/terraform-provider-helm/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..790ae60 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: Helm Provider for Terraform Roadmap + url: https://github.com/terraform-providers/terraform-provider-helm/blob/master/_about/ROADMAP.md + about: Each quarter the team highlights our areas of focus for our work and upcoming research. diff --git a/shuttles/terraform/terraform-provider-helm/.github/ISSUE_TEMPLATE/feature-request.md b/shuttles/terraform/terraform-provider-helm/.github/ISSUE_TEMPLATE/feature-request.md new file mode 100644 index 0000000..ba1c1f3 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.github/ISSUE_TEMPLATE/feature-request.md @@ -0,0 +1,39 @@ +--- +name: "\U0001F680 Feature Request" +about: "I have a suggestion (and might want to implement myself \U0001F642)!" +title: '' +labels: enhancement + +--- + + +### Description + + + +### Potential Terraform Configuration + + + +```hcl +# Copy-paste your Terraform configurations here - for large Terraform configs, +# please use a service like Dropbox and share a link to the ZIP file. For +# security, you can also encrypt the files using our GPG public key. +``` + +### References + + + + + +### Community Note + +* Please vote on this issue by adding a 👍 [reaction](https://blog.github.com/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/) to the original issue to help the community and maintainers prioritize this request +* If you are interested in working on this issue or have submitted a pull request, please leave a comment + + diff --git a/shuttles/terraform/terraform-provider-helm/.github/ISSUE_TEMPLATE/question.md b/shuttles/terraform/terraform-provider-helm/.github/ISSUE_TEMPLATE/question.md new file mode 100644 index 0000000..b6b3a3d --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.github/ISSUE_TEMPLATE/question.md @@ -0,0 +1,34 @@ +--- +name: "\U0001F914 Question" +about: "If you need help figuring something out" +title: '' +labels: question + +--- + + +If you prefer, you can also ask your question in the Kubernetes community Slack channel [#terraform-providers](https://kubernetes.slack.com/messages/CJY6ATQH4). ([Sign up here](http://slack.k8s.io/)) + +## Terraform version, Kubernetes provider version and Kubernetes version + +``` +Terraform version: +Helm Provider version: +Kubernetes version: +``` +## Terraform configuration + +```hcl +Enter your configuration here. +``` + +## Question + + diff --git a/shuttles/terraform/terraform-provider-helm/.github/dependabot.yml b/shuttles/terraform/terraform-provider-helm/.github/dependabot.yml new file mode 100644 index 0000000..4f78b5d --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.github/dependabot.yml @@ -0,0 +1,18 @@ +version: 2 +updates: + - package-ecosystem: "gomod" + directory: "/" + schedule: + interval: "weekly" + day: "sunday" + commit-message: + prefix: "🌱" + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + # DependaBot does not open a pull request to update the version of GH actions, only security updates. + # TSCCR is responsible for opening a pull request to update the version of GH actions. + open-pull-requests-limit: 0 + commit-message: + prefix: "🤖" diff --git a/shuttles/terraform/terraform-provider-helm/.github/labeler-issue-triage.yml b/shuttles/terraform/terraform-provider-helm/.github/labeler-issue-triage.yml new file mode 100644 index 0000000..d1a51fd --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.github/labeler-issue-triage.yml @@ -0,0 +1,4 @@ +bug: + - 'panic:' +crash: + - 'panic:' diff --git a/shuttles/terraform/terraform-provider-helm/.github/labeler-pull-request-triage.yml b/shuttles/terraform/terraform-provider-helm/.github/labeler-pull-request-triage.yml new file mode 100644 index 0000000..19f0cf1 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.github/labeler-pull-request-triage.yml @@ -0,0 +1,4 @@ +dependencies: + - vendor/**/* +documentation: + - website/**/* diff --git a/shuttles/terraform/terraform-provider-helm/.github/pull_request_template.md b/shuttles/terraform/terraform-provider-helm/.github/pull_request_template.md new file mode 100644 index 0000000..78cdb97 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.github/pull_request_template.md @@ -0,0 +1,41 @@ + + +## Rollback Plan + +If a change needs to be reverted, we will publish an updated version of the library. + +## Changes to Security Controls + +Are there any changes to security controls (access controls, encryption, logging) in this pull request? If so, explain. + +### Description + + + +### Acceptance tests +- [ ] Have you added an acceptance test for the functionality being added? + + +### Release Note +Release note for [CHANGELOG](https://github.com/hashicorp/terraform-provider-helm/blob/main/CHANGELOG.md): + + +```release-note +... +``` +### References + + + + + +### Community Note + +* Please vote on this issue by adding a 👍 [reaction](https://blog.github.com/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/) to the original issue to help the community and maintainers prioritize this request +* If you are interested in working on this issue or have submitted a pull request, please leave a comment + + diff --git a/shuttles/terraform/terraform-provider-helm/.github/tf.png b/shuttles/terraform/terraform-provider-helm/.github/tf.png new file mode 100644 index 0000000000000000000000000000000000000000..be817896f2b28a51d50ac2da99d22e36ec5b9618 GIT binary patch literal 26289 zcma&O1z48N)&>f%AdQriNF&lnHwZ|VG}2OnbV!#9NJ%5oNOwsor3eTLNOuTGcQ3HS>KPYj26@iQEpI{ck~e%6D( zf7J#C+B|>*-{Ee9FVg^XIE1VA9^hZ-j}-U@P!mh`IS*G6j_h--!j*XS=0p9~wK2|PrHa0#^Zaz*{xDRjq zPryegwo+OSaByh2&=)*hd?Fzn+>IP_RZT}tc{x5K8!Ki*W1FWY%q~{8&`59sE_~oe zD-%aUau+L0YX?3TLCT93eBfv3*DRFe7fl?W3sP#zE0K%Y*qe}ZF|#tWQVOAxlamYB z8=LYei%VQ}2mceKeCFtA%g4gv?Ci|!%+73MZ^rU~mzS4?m5qgsjR~}1a&WbFG<0FI zcA&Z(M|0DEpJeTDwJfke7U&a} z2h6N2|Ersci~0Z24f^E&>;`1?&$9mGVJ?QYmz^$zaXCi;Xa;;*$|eprmQK)Ggt*yQ z!5@|f(07503I4~&|1R&ctLFcA*S|mh@2>y$RI@gB6k@x2+JF7}zk4a#o11_gxtQyN zt1f^4?yvTcnD{P~Sxem9%Ea0MS|1l1Sl0jiM7F-EHhuZEP%s z{+BghPT->dRjaE31Xv(l{!6zn4d>#wz;c98LC01Kba|c9To4ikm&kS+%t15HZDu?B2@@u8&&`t7(KF$iR8x!S~ zFul(Bnc#d(|5DU=;+Vf-az1AxEMY&H3PB&4+y@T!|Nk3nfrypsx=~a8m*DG8K8gtF z*@NcsOXr2?Eqi^@x+f964m83DSR!!n;9Daqd@HwQ;D=1C%q$WCy}L`pXQFKcQH4I_ z_pYBir3$aXVL7rDLEwB)G_e6SF)cngxyBD=%y1WJF5bHIvy(9Q$%XaPVDV zvf0Y=4>D^`eq@*epWO?ef@$KL5_#Djz<%|BqHE+}?QJ^ukDJEmG9# z)3dpx9QtJ~*O^CNlGoEnq@LOb)6fy1&ai|Opa4ZL&iy|ckc%|E=w)1Jm6Qz-KXGx& zF*`=1(U+@VWU7C3J%}Z4s^KwdUAwAGQO9@G!~wMR0ly~tjXE(G_$z^6Nu|SKj53wT z)2)F|t=o={P6FeV7+r#!T!^lll<4^QufF)E-0>jhSux69rFyK_Zqw-9&g1L770E+< zHY7o3fm)$_^GH!WcGvPWVZLkfL3=L``t=}EPkj8XEMIFWx4%0+?oi=0nIDv(L~STN zwBxu^qYyD4eu%5^J;p<0(JhL=e~j|v5m*xoew)|3 z^k^5F)sOi57pWzp6wi-JivFgLVIR?OmqY{3P91 zvuzB9aabtkTOijJ9`f?)0eaY}hO#qqG8Clv%9ZLjjob$iSboaS z{6hD;YQPN5z;MfPMxBp(x)pa+r|v)_Wz0kj6+Q5}1rBIoRiWCegv|_xLAU zO+-ssKi}&~bc0E7DTdKCkAn}HwDePiAL9lgS}6qlzHZ?QS}457%bkmp`8bH+uKm2d z-mQ_&JOb%zYlc`vnoQ40JQ!}&ZLGlFq(Q0z>kExR;7awZrD%-oQ4pIk-W+*)|sbfs{qZ0M_<EWq7-(6F z^t}4gcH+YFpVBLLrahUZ-s4?OmD~?ZmG0X|p6EWsDE}GXFHzSxpeaE5&w408Bh2@2 z9%MxPwf+45+dOzz`l>@O(lpl-*sB<&paF2e!gbwu$zY|Gnd#NXs|Ok2ficoW>~|>q z=^u;MY7i}1=g=+F**X?c2V9AM28jL+LBfmz8vp`1Iz^3}?%c1N$V_>e#c;0h#@7z0 zNN7T51nmTk-$?W@_o28`iMt;aJ2l%=rb)At~hn z5#^;mH%fu2P%T!U2##0BUky-~xjtB1Krb8=jb}OR=t9&e9>KpL;P; z&!vi)L><2Cot*Eb6}!m!_;(oL@`>{9FZelE8Sn4bt7r{;c6mMHf_5bnl6ycVB`BqQ zck2+o8!6|#;`}l(5MNeITH+=!efb<8ku5NlwmYBLUh26xXVM)B_XV$6A3yBA4RlJ!_@OAL?RwK~W> zrM@&~pIczE9;|J2jNRewIS(=gbct5Ru`s>kV!jT&zSah92y|fn?mT`Ekt1i(>_r|$0eW9TwHc=K&~cbm z9zh5chCS=nRbzLV_hh^KE|JA22JE!@(h*PPgzDJ?y8efCUfR#)hc#{;#J%jfw2`a1 z!a}H12W_;?gU)W{zbcjY-aa|xm*9)tzw$5)T)=F8>$-5pz?9|sG{(4g_7k$}hv#H$ z9&{00pAFFI(Wgoh2lLGhv?|JbSz2WQbRmPBl;U!f4L^VjELp?mkJ@Qxh^BME$i)1=64C@!i7UD#~n5ZI)ax#sR% zg6~(#u-$QLl}qOH=5ml~T`}*Sq1fN>w~X9F|5eGinx?+i3XU8p0@;9QX``Z(P#QsrGjdI z2uO*>=}0b52Onp!m|FIC$;IL}VM_Er4~iLnxK;W$&9Cive8GEjxnL)t{9brE_fpw1 zqgl*$<@vG+CJNC4)EZ3?!L;A(f4C9wQ`7cbF1Zm0 zj3TRv63+}@mwN(1gWGB41vE$vR)<`kmLhyWFMD!3G-FW~c1P9YKb$u$8CdpC3V5Gk z{QV$;M+l~J6?hrWa;L?y0&ThO?hBY7Z@f#FW2ikQZ7Yfn*g+7)HKASm7F{!#OzHv&>20(MJD2=K$6Ri_DKh_A>q7B zZRG3Yb?-|K(NA?Ujew^S1hPW!4ZaY*zJefSXkD%-YvjH=i+iK-|w}kw=F=<2fBT6feS^6cIE_7z%cBO|lM-h!o)g2^&>Ge&2dN4VCcp5SpL_NDRhXbH@WBP!l*q#{I|~PYjSe+S1~w2n zU`hqyU98&!IvslhvsWIYjitYX4M+A59#>kA;fEeEVqQw_>KLYu&PF613>{62H?Ua_ zPFp(`)TL{_fL$I1puKh~qM{1;tbR{;pAnO(AsHon{XHSA&>1s!@swIB@RX#Qj7UdF z8Bj_o%302yeDXIYxqw1%U_yuPXSqTs@M4HVQbH)g3KwD^tOHxJP{@OGb!uUi09UUA z|HaK~rwl;?I4fLk3~w)I3eFl!;ANHjB|W@4+2MS%Jz}N=|H87x z+R+C?he3~s!gB;twwTg%NI6wrY)YOnqyzym`x+xe>y#OoRj+^8j8JZ2;Olv9{9)LY z86zR-C?vG;KH`orqO3fxOD$ht`Kezd%e}BI4ooqyVh@IrkJU4Q&0T9kjOaCDR6lL` z5rFNRg`b>Kho?pBBt+ci(Y?EJ0cncODhxo!S&4lgDV}(%;IoX?30h;;6`q$KuRQCt zYkI(8X&pynFFth-UM1*rjFNU)y-@MGjnQdk!m|S)4-ZBx%=Pb2bjF_0meVFiDi`)E zdb{PdZmK>II^)fB6h@Wel$;b8)x%w}Dr7ue3h<&%H3eHtPEnHKvY$6JUqidAvZw8s z9y|Z&_JHB`bb)eIF@jv0db^0XmWfuEcM>bbM#FiPciVY-G2DIVfecDzsYaD-{%65@ zQcTgBiXA`nbqu$+R+JM`5XwL(y$_B`i}udqP;tET$-Ukcus$JNf;4T zzcK?(l!Ux8r^rX>!n-P+HY<6 zdPik!;b0TE;h?>(0IOzNRn3twdy($&&UO(}k!!IWJ@9o{(4rX+=8;Uuw}szlEiUWo zSAU)RlVWcnHg(5$3^=cwD`V{ae@dSyLHfjv93A5{duGm0M>TV!PWp3kLd7?a?vk3{ z*|8+pQUJc=9Y3)(KX)SvKdnd`N~c4XMg~G}gu&Ci!(T62Z4lVm++EEmV6`7hg^-fi$Xy8mt+S;5C-Fancc@B5Yo5WCXC}v1Z)jV2NZ0;D>-X)Ie%DDHz z`Gc)r2fu?f4RXk%#$RZ1198g9dFXrA$N|DXiGQ?_1Vg=)r)m%j_nDa{`mwlYY?i7y zo;OYPlwiF2DvSIVVi%)0X0)9*bwCHN!^3;X zL(Hk?=GxF%zssd@&fzlury)$j%*)DMnHqSr$vB#|2Kz=mtW`^^8ThVwtii#*Q4^XQ zUrRQ6!syw-S*kvnaUCI!Y1|+J8{LZ#%XFNw4;~un?njZiczNi@6;sD@OO;i%{jO z6c&O9C3&+r%{Tvo;{IHl%9-TO^c17%u~rdU2% zN{T5mc)GRIUM>xjIve$vy^`;l-loYi*wua_-=r*QO)!m<)RnD%?dO#e?lWby9J7%H zzSVfUjU^%yrz}7N+j{mifr0bc$@uays!<65-iB-7UBDReF1W*4&xkXHn((OP^`k~f znD@wB`**DQJm8AT{xKWQ8J3Jv%ssoUc`{p^MOzuw(=h^HxM6fIlaXytT)D%;jtcX_ z`rgk?*Z^SnSj5KR_MX_6zBfK(i0XwF9dvZoq2CLBvJX~8ZBdDhJkK(e<>$RYIpyk$ z1k`~)Pqeg-(}ci#_RxY33w{#$evR>$&W%BWkSH0V;)OEWgDgiRJej6BA8B$#1Od9# zZ)_@eCTE^ z$Ez!7Dr@pC@HQ{$3ASx;W90OB{?nBCWI0RP%sUkVRkN$R0*5YNm)Ye!k$IHJOFLrF zciySR?w)86eLuO?VYR=*%POxd+Nc4eLE|%JFj{C>5EK?G$eydsokvaBo_igFwGk{5 z8@**>*rM1Uouq#!@cx<5){mbm+35%`zwCV`U>U1W<9<%-_;jpnDrfjmmhA-bkN~Y7 z98lT_eRwMIqg}N`?)et3D_Yvh21*DX_m!0G$&Ji6J1Yj6n-!NCELfhygq$2Uy5KPq zUeN~hVS%-Q99MneVTsp$Ly+To6pOLZJFD`11n~lPZx)kq$BY#rnGGj>>}niB%19vn zOk@Uh%?YL~9F6rB>81v7RL>k*Di{*HCUzS+m;I^OU}rd*CyvWvzCRm<T7^RZS;`#YZB3xwV3hJfjcfNjx^79As zK5nNpC6>eIwX~&4(ZIy4JRgOcb|67ZdnKJE4lOMVq*r8L=&$p~nA8P(s&Z!@iBAR6 zR+=$0TNmD0O0iu#dZBzW^NrR4^oa`0l0!J5PJIXGDktMqa&Kt#=xNTemvFyA;l%Cx zbQ430X|!?Z_XD_3_6E!6r*K15@sxU$PG#?(Xd>3@!b9l}Ss7OwFZ6 z_wtptprByqvsB~XYw~s`^~LMm1slc@c$^j>1MpbIjvR(u{X`_l9pFHJ^lrV@XU59L z{)+J0R>b;Yg?83IbTs`pJ&TEh#oawxBvnWO>`DY0fuo)smW8Jnh;FB9NYsKDs78PyP*Zyv_?K+?YKD%=JMVs}LQ7@T4qj%}eF6sLey zdB5({`%3Bq5!%4#jnH~;1`fPGk~b|#K~7@yemD;TJc0nrMrv-zMQoTClp}8g#ny-2J#peg>Qe{`_qzFg|+*VQYN~I zI#^&dU2E|TE{4b0hTrcV2~`}QD04gAgU+r*GBa>s?<277xM@5OxJR6gbBV#7TN5Os z%H3Ok&IOz{zmAXYN~YLIn=^l;LAmJ!0@#G-*>AsLi!{o>pK>gYgHSoktW`lZW;a%w z7r(TQ3G#VmENMAyX=b9mMobFp^IE*!>jeMAsTs~8i(bLt!K z&(msFlk1~ziHdX~GkTfMlhjR2dUv~f-PBU-VDGhfPN8F19+UC~Oj8#|uVRC}Q^q=T z?fQBLe0mOJ>f$1_Y;fQFs;g}xk{m8`lZh-G-h--9pR4}81?nR>-#(NaI;gVXp1!}D z_oviMh2Wi(^=+5wz}5Fx&ac-K{m1TFgV?sunPykzKtN~KiKa#2*N@wniPqxSG|bv=b7?4&wSgUcg4kEcj^ zuS&_nP8~aKi$uO@KB@hzjxp!u;mMzCIX@?3s)sv8^|-j>{w~meDun20Sx3rsHUCcu zH?mGfTRK1JNm5JT%;11-%Zt^K5Ey5--u8*Yl2Z0zu#|?`^Fi^`O901mg;#LAp?s)S z^gYDq&$lX>e^wkE+ zdpgAl-5p{1>J@X0%o8;aP2y;s%GJ}mrjx&QciTlj0s%Ju7aS-GJt*=yV>xRQZ69bi zu91=5%+Ufb44F`Y{GQ7{Y#e{1Vjvoa%np%8K)PJTvit9ePDAQc`nJ&x~;vE z*;UyQlz$*hPs4Dc&cFLf8?0(AS-1?K77OZCN^R068PtOMce(q;x zXvv1sKklIeIHF+H0wttd?y++Im0l}NYVV#z_9#zM6>000$-_9B>0&g-vQ3903;bj^ z@Ew#3J?>p*+dvvDtKhk>_xX0wOVSkhko++KSvq;I$39d=xjE{<^Ps>Zp@7rEvAn!<=KZi)||GL4i53{g>XrHz28Z}8<Q3qkFl#Fenc*RT+Bx2+%1pX#LjQ%+HOk)5epT@>Mhc-J>_UQ(axLHj;V3JDyWlz-})eW!^waRwNr8P1_o0fYG}OU|2P?z zKFjXtCoP`RUx%`h;AEg^Zr^#^`3$*QvXLEQ6k`j3`VaY4KkQSMk7Uvm>D+qr7fc3U zZPW{f1O36DJDj%#6(_fHqU*6A#DbKG+AFQ>Xw^H83oFt7w1hBH+zlN-Rq%@ELlqim zP)AdVS@PycuHNKpxTyJ!$uxS5g#0i9nG}D5*k)84C)KiI7Tu5TZINd44bSO!V>tBSOfO)gCI!Vwe*eGL%>CQE4Y)|Mj0LX!@6PhD@67uz^ApJg_#DYjF-^d`%v$7mI{(r`FI*;vbjsU zvUarcST+AJMCxsZtWS_RoW>@{`}964m=G#1e>MyoyH+gdSrACov)^F)yfxXcF@}Gq zN2f5w=xE$|VlM3ZVc-yaHsnw9F0a&6hJ%~^>|2Q3vKK%~L8qD&}&+EPSzAw9|R~#4gMa zeDjS4F;u8;nVoaD_AREkS|#GAp+Zbt{wlox=ESRjLrl0xiEYkRahnT$whbv0uXu@8 z=D3ycWz&VZK;t}s#tB?zL6S^Id>220MwLZ3zv$a1b*fJ3BFP@CcHRkiA12dsBd>Wsnv9@2_Q1C6cY60rSzyv~DxJM(>k?6+t%p}C zJS7C2^>;tDek8vv2i5BSud10}mB^~8t$MC%Jid6Ku9yk;Ac-P=A8+;e#NxM+Kij~f zU4z{GP{_5C??JW4ndH74U0wT}QuYQfavOtKWs3w%d_{V4+AD&CPdYFt52PBqSh#gkO~RJ-80Vp}gQQ`NVa~jtYD3*$AK+xvAZ>D@Iqz~_a^I!R2Kd4ouCll*T8 zuGF|u4Lq(WzNnjaw9n4lS;f7ZFUC-SCWD9Xh@JPk43-FyH$DK!PW9w@5T5`F3SMsuP>gLsPo^@w*HGC48F8t)FrQ z`_ZMixsPUfeZn?z#4b5|pPo{=AYLjeLLxPoQO2;819PbR)-9orsZ%IGJ=_*F;{(ii zuGE7NP=-eDr`5V?Qd4$hRetsV8K_|@OTo3Qf2vm)^XXCmw)sGZw9S~CUC&Q6Zh7?g zJ+AKN_#*%)4IItCQLf22(qL^gzVpp0+Ix73{b=h&n8>9%giAMA2BhS#q%9AmZN(m& z<#C4(b$?Fbe8mnx#!k3?mbs=s$h<>y@-+mNK>vroGi?x-mgjGAy_g%kHH-06S;nfj zxTW;E(GGx>%*in)Dv9)77RVVRBJy>0`(24Scw6M_)x!X(uHz4GT<6XmXL+IFp2vi2 z=)1MyOI3>`30K_94Z!?KNHOzHtl<6|H88umJ6RL`udF#8gcEmY@B%!w$%&KrQvnBt znEQBM3Y;gO=c>Y{6t65KoF0I@s`L>@C(GX0{v$|7>N@&+MT63XOj0c`rOgNm)#cHH z!e5}$!N{0i$@lO%3*FuIQx)ErOX7$DsI4aKwg?eF%xl@B>mDnpK8sVW%|mOLOP{8@ zeYvkcfPfg&cWtJQ268nZ__pKRDTy>qkNuVJ3s@SL7&HSOb*GqQeq4QuAZg!gq(>-I zU1potbHm2k9fov;AB`nIubav?p3)=6k7PRv0u8YP8p3C7LvMt8MM@F|yLxCCdsoTm zF9nglP>_Go$`&GrFl4pyOP~FtAjpJa#G-3E3MQ&o^c*Mfuz_J5R|H@G@k29WepGeD z*P2BsQU|uL#ayqRHVO9i@JzB%&&U7m*SaWEkE5YotD^cc?mH5fyurrzV3f{80(}!T zePM6b(vE(SiAK51J}zC4F%3ApO9*bX0wS`$@ojVw_YLqpEEgH`*x6v)JFOXa7w^1} zxKip$Fz535)_234Yw;dsndz*?giEdz{WhL~BHfppItC2r1@6sBKH1dL!W^fmw`dMU zlaqUrW+swcmn||B!I9!Q5W<1!`^<4o1W*gAhlRCe)QZL8W{{ict~3#FYk(@ur_6en z&eyZVj|2}8Wo>>eI*RkA&sM%vjn}D$GuZ%VfTf;S)TE~l0nJD{Sl5jaXuH%5Rt2D6 zc3T<&84PH99nu^YgS z?lNCwkWmKH@#z5agQ9R+mW|*}cVR1VurOrSs7fBoZ((1tH+{;1_!2qEjH6zQs2oQZ z1>oZeFk_TT1T4x^;$>e>XX-w9l%zaT8#Mz~pj3HoVF`u9bc~krn-0DSk+KK8WS6=M zIZ!Lf@GVv1Q}YdOQ~4m^3H9}P(1m56P4f!t(r@wQ0RBiOO1$9;_OqcR@2t{v12vI1 zf84x#ZmqVxe0&M{Qh?3C#4FtSB2Yw35^xyUg*;ahtcqp_nWYmrE}I-g!C~AHMy|)s zDNYfN1HnKzJF5y^g**Z2zWgTM1uJC=5)hOF3X@Fz{jQh!BS4N^pG1}zKAvR4#Q&nv zyv2Doth=$C)%gLZNvUi3n~b`S(ZR;G)czBQ-ihEdB*v86pv8C%k$WRHd zu@Ld%SmBIz6PMY{6IvT74EuBUQojlS!>+tD_B$!|vlYfqV|{vrf%$0xF&uXUmGMn3 z;Gi0KM;(u%9_8(!o_yGzP}CmD?xQyp%4RA(o#M?DL^q!I7a*8aeQOn(jnd4 zLQQ6s+w{($CVzNoRMnv(EmjlrRv=v_K~5YKXjS+YeH)+Uk_Q-W4_{Q0nHcSJX%^%@ zA{Jog%FEImmvg*GSpsGkEe-i4h#`}QKLJ|b=Y|84wU-Z&ssXIIc4?GLaurbN40WIw z70Ke)?iqqIp!&qxE5k1J6u4u#019ObX}d26fc$9a@c5t8XkoB5ucfsog&r?r5A&zM z`8>#T6zt#8-79AAg{?$1m>el;Ik1a)kZHOEc|I!yO7Ai_^pjj98#mp>%HQRj3Nsn| z_&gitoVgWmXymkT;!TisBuS%&$at~n0p$BMKYb|TLst$aS4a1I<2chZxacvoEd&Go zMU-LktB2W6KDR5rXy(=nHK=)?ODV(iUeLs+v|%#et6=_l{IbKfMa z5qeO^TidmW8HB(v8WLYTOi|XjD{vlPzxp)z%&VJF%ofteDM|Ru;+)f4xqXwX!evX& z)<_^7cZ?p{V1p3Pw>8<@%v?mbu63LH57(*c;%PlyvM4ZL-%^y?=Y(ZzjlYA^jrcoi zB)21S9OnIhViBreKrgG!6t?Hgii9WJaur7YH*kkzN)dk8N~&UQs@pkvOSwEYPL`O< z`%GM=;s@e~?nMo4K2$EGn@FY%Ack=iAhVtnL@G#~xKQtxvNK5bua1A- zs^T&=Jp9FB8H>vf2OB{9=qTr^t#7QYsXL*a{!@50PRaN*Cj|6C9=cE7EGFF*55m5fsnh8yd~;1zRi5ufAPIW{nxQ-Y^{EEM+vshNZ>b^S5>4gY7I zKNrtOJ3GAxm%me6$pra#+;j1N)TrQ_wRh6%b^=+BxlWta(OD($i@ByD2(u=l>lh3c zj{Dxe_IlN_k9Z)pb9}G%rH>5)G30|zoF9|PQVcGCIQCHC@dHWpCO_=9Z_z<|$)%(CY7^z06#Lbe$nzN{H1 z3JH+~@_G7yzXeXV+6hk1(xS(@P8%oBkGLY4j*cIh6UPIZS))EoM*s0KnJ>y_!}w?C z{`FI}ql5fEsG|p~Jh&j#SADm8CJT`+qY>pOl~g3p+(FnIj3Fji>>PbwMJ;Ma4>oQ? z*Vh>auU1f;Q<$Z7%-r$aJInCSaDX$mRIrcNlkGMaf1W3RC+$+2F^GNa1BJ#4?Ll2? zqSk%L?|NWg0BLbb8a{KDz+ZJ4lhkwm{b_(Y>9%nMKEWdp53>HoCVb@+-ToicO;&#g zCf<+rPD?SdZ(nx!e(@c4Td$W8d{e*B00 zxl!Nzg$&E~wMda(@IuU&l|)?5G;7I~8zUv&NApapDi*tSR$U9RtMZcfBS65;qb(Ac zWWg#_wXE6Pk}m0eBxy#we6j-k5@AW>1$|#6d6ShK^ya;OzzpW|P0KWDAMHp&M9ZWY zSnzO549DdKJ3oW)776yW?TZnE`dzoJoAfO>f+O;AXWuw)L zcU}0NSJ=H^F<}4EfF8K>A~e)6eAE*WKuOQH**ZQt;{u||BN#u`JbzMHT+M_llU!2r zLKKuvwh{JB32zAVI$Ay&pQy`kc%kPu(e}pwf<1MH6PLMeGpa@uvYM;4nMt(=53*K! z-a_H$)oCG4M@Bu{XYrVMj~bm}*%*ceJT8vSTb=>uOH`9;Hez3ZTbRmD4a>#(75X@r z*Z3@}tibF!kH=c4YV%#2#3E+izM=Q}Hl{iWPM!(*X`3z60ti^P8I5E+pCaz;dRl~$ z@;s>@jUaO4pd;oAQ(!bXlom0Oq0{eNN^mUV8`37g%=a1ZuUd)U47g74=!~p%25bUm z5-+@GSiHGZch0%lKpGVT_wsSy&B);I!$wdLlTX-6HKpV09u3%nM{bh?p$TAJo^=je zbbxm72!zL{248vSdm;dnzgLYFJxKOd6lobBW=Kd_9=;YGRjpv5mqX(ocx_q zzut)88H0n7P@I+U^px5FwZi@vhfp473zuJ0UDQfZ-Cv2uWx?tle9o7W=c~zhEs`La z|3f*xxc%ptE7GK9Tclvqoy=1;;>wRv?BpmlZ4mQPR7&>q zb7#)hvi2xXsdG1@73SVtx?f||sW|(&ZE~9igAr;GMMar|)^1@oR?zh%R~R9w??+@Q zyJA4oifI}Vt2hM&K3Z0j8LX+zqcmzf~z?Z0Fir%yYhkQ}dZA*T$ zv|Sgm-jYy=Wo4V@L)WZANgf8OmUkdhx4kF|NDA4r&xGBl;9l}z=B1#u7Xi$wlsn2r zyp9Fa?_agHPi{OOFJg%C@3>_DF{Rp2uv^?L?{9@J2SHc!q$TCpE}{~qyNC&X4|pWk z9}VR+Eh^eW#auMRA{iR)A3uMTU$`6EKR3^L(MnaYhNnFa3gQ?Qn`JX0E zmc6${r0eN@{W~;za`;|3 zNMjc_^K_Bu{bQ_+#Kw0=>aTYF_VwJBrn-L_cB#!ry#)R`TX%FIVBNCqG<+SzoF&Y@ zU~}b!JWe(nHUxuQR1`eJI>JE3vjD~9J%?`{Ed(F8M(wv|e~L+}TlJ4hm+qwn)4uob zXpWLxLe{*$@d^}<_D%P_l+*^at$*{RV-{W^h=v|Z|BtpL!red;h{?9&X#w9aEV-_% zG&rFCWsQ>bfCwy9HKuSM*ZiW5BGx%yJarcv}Vt0KP(iRzabg4qh&Yv8`SrLR2 z3R@Zd&?2d^?8@^Y{c`W(fVo8f4zVa{I%G|n@S!=2@6oi-WeD{c{qN-#iQO%$S9OFN zppFo&Ji6m5mM-{i25aMk&)LHE(`g~j_wU))r@DiMDXW+ z)qoHRRIoyhRD&@?u7i3t@=ZsE^N6zV?@Qj|6ZY&U4dnYICRHoSLxe~@5<%S=#kc-e zCod8MLCN_Z?V8PxrDacTZtLJgpN*?b@@-H@*m;HGfj;|MngZzu;!gh`Pq!a6t-H*K z%a~+EJT`|u=mt>!tMCN1NEPA>dikk*p;dJI_J>IJobkomtJNz5Ye5 zc-xTf#%Ef;O%>`?W@+>Kc!%sn=Z(-9M!P6VwW`-?h7LdEB4}Zq_}{zlU|WAbdXkg} zcnnL0BD;K5dtRJ>C9ju_-wq{Uq*Jka!Jmrw0*sA&Kyd~k2zH$uQm|B5N^gZ(Pf5*- zB`FekBvgPP_1SY3@nsX-`7-XwcB1}&l|Gm<4w7)~DUm>eGWE3wgTWg=q_+h*<5la~ zmc3k0cy5tOHqCvJ&ZI_I!Dr2MkwKX41|<2WV4Au|FXqz+GnGSERX)_b-;~_(h65-v zv@vofP4OxMA>-(0xP3=j`X4kvF&mHy*h&_LqRa!sI+FA*&jP-T;lqwY;+0b_PE3|>YF$-Sma3_-<%ie3blV2?QvJpy~a6jJ=gduCv zT`-N*(uO7g)99OMRi!uQ8nfGS8e$ZIj95W;o2_^FD*N;(!UQLJjg+Y+$uV@wNM*a@VV1^Z!-1afR6wyde=*fFCYgzoY5AvB0l* zmq*9WG4UZ!2Q8S9(EDeAMra5la^p{`5W@{s0qQ6t6MaVgeWDnUca>G#4ZmF^YMGzw z4D;VjCe@v!WKH$9`q739kX9>q5H%z&nK^D+85EylaU@;>s(=f^PH%=YZDmb-@?HMN z07!(A33G+AO%%Uq)uDg4sEa&mq*sH3qxc5B3%~;^3gy046i7k4h>SWQwisE-kR>=s7*s#3RX3A>0~vO2L@fi_%D2s?JcPy$;y|-wBablx5cZ7Um5AkC{uQC7o!;HQV(!jSZI z4Bcp4#8y&~Gq>&nQ1iL+V-=5}(OZG`<)kP@PG`K>JN|BZ-mibOKB00rJRAp67b(AE z!Bbt0L3$yD{cS~2)aTiTvK05yfZvI8Q6lF7cX|If=>IG+e*NI46)5%Jt)BTx0(fL@ zp7h*r!@9fj1D3-&x)w4G)$a;?dV1)ao_4G539ZvGxZ7hI#-C2<(@2O2PX9LO!v2?` zEZb`59zsRM!`~n+1<}#e>54jIl@~LK5MlvLCfFRn`i z$_ROjlv)TLEaBSN*k*$V3KS}k_fQ{9rZ-5cWh*4C{pSe|6Fg=D|RWAw6Ecg%2d zyn>sg(c*O#?HVnX-Y*}1m?yz|V@Nd36(43jL8zr0!g234_mCKCG$IRlO??jL=AdBt#RRK;%sg3TsL)F=|&+qE*c{awjr8JHDjfmc2!Sa(b`-OJG1_Ay5Eo znx8~ z*0TJ_9UVQi#m`D0Z{`;z(GH@Yf<|gj#cl?Ij#?1itZkG?W*j#EQ_+<($|XG-G$&2| ztxT1=bGzc%ocMM`5mi2=uC8ox<~_#8ScKqK-RMv)4+wY@SvJA}pAkZt__APOd(lsS z*Kqh!;s6o{JVvR-Mb3HZ`N(P)gaTf|dF(vM@WEhNj4x>zLBPTIUj%b5GpfHJ2D)3> zs_pvW*P3)q^MPByOO~Dam4D;F&&`IlAtFyehOVc*!vI)`sW18|*<=NgmTzzWmx)i2 zI581(n+@DL98YZNKuOWO9TZ^37xpoy5cx0Mxz;~ZD>o$7mnwEC3kuEVEm`;e2?IsI zwfxH$V#r<5(NQ=nSLk^12_|$4xn*>j(RY1u?YEpTWmZ&QZPw_v(sPjt9`yN@GFq0Nm;HI#?SNW+mfN2$Z>&n40R>R_4uAWbFkT|*VP`;UP16{(T!5%x6J%Y7a`Ab5Da?NE^kMq|BH4^^aA$w?E<%{wIc;{vkOL$SoW1@DKoA9pyi_`kK&wJoVcnU{W(Wj(%osdJ+L3fRBuenqbMu zFt7i}_oc}(=J}52@%$TfEGfY4y-3}H`&hSsjmi>pO86fDz#hFo5ax<21o=wnAyrH_ zkhA^x#k_IT!6ksyY-84!Mi$mv#=-f^g@JM05{W?Jww8(&7}Mw@_H}Xj9R8KpW$~j~ zo&%tIH^3U2$(N$fPm#?r`(J^ej)~k2KCvM{P&Q2wqyjmD&xjW{0O|2YwV@k;3imVZ z6wkguWgH4n#+k=;5LHm0O}#T$<;RvRKbAevU-6+e=)s#na1{w8Sh%QWL6u_-N9pN% zI;1d-0Jq8prLAV;&rxCG8N+?*L*cxe?Utv{mQ7FdC)W~{dCunjqn~5m&3BobD&68% zCVZ!a%meCo9h)lRFM$@re9<#!M?wl3&7mvs(t+(I{PQX2OTNW`?!+CRl?bjwJMGr# z9tDlu&Yd-V@9MheOLZGV)aKlvie-i>+!}0>V=y~N$-AgGMo(Kq_oEkwOL0Hhq4B2u ziWNjO+x_}E|Ar{zpl)Y?!gq5y-utD!tVnY&?&c2-^;aDA#C85LKoEdR;c0Cdcpzut ze|4#)AG~IRLAK#24Y$k!ULJ)5f!f5|v2GTfk8U!MpoSLQpKLWe%sw^tg6GE`Y=NZ{Rq6U>?AJPXu$xy}$C$ zY}@;Qw*@14RZ;d&*%#62%QiB7R=w>Gl#@Py6n6m3B8aYIb$(*O^D}fIh8B+FuL7qh z*}09?59!Hle5F%|9cDx)E34a{m4Ci8BJ*g1P5TlhW&t)$5MJdC?Q06m#t@$SC@z~>Sa^sou=W{>Rw4`uKQq-t4mNp6;6 z<14oIb(C{@T`}t&)e&UM;EA8M^xx@C*`+5pqg_+!9hJt&!|S3R`xT4u zm53VaK;bPG;wCzhrHAmjeGl22G$+eGH&Pt?(jSTr`)L(BD-4k7-aD^2c%S5eSy!`V zycO}r$LAc_#R>Pk>WTNCd=`x4GHn#2ifJmq-}`-AVFPt zG5YkD?^t9Y>U7UNv8;5K&13^*G3Y+~vrHaLC}CgRm;oZmD{sNpEx;5M!ffL~tl4Y& z+5?oUd~MJKjOmReO;{_lvsR|V>QC{#LAIm;D#@E<<>JC4=zv5E4>RYVUl&&xSfV{1 z4EHyO3jnzO*B=Fm$5gi6GQx{jQ~_gwuD}e%pv+MEh`2$g`*O!KsNB^9oyg13n@K!9 z^(H6r(eB+1hXV@%FOT4ARm4Vt3LsTj;TCUm#oZw~b=gin*~IjHJy3eSV%pGwcOIQE z{g+M5+hF8LHYNbXo=DWl1G7IzF_xy&2N8W+eA)JMD(vRT^|NE5)Tg)5HoTwRQe@5q z_W@WCv*LTkyyiNFwAFqXbsZ`De8ApF1%g4MjfsTnc)7D4hHshxU+3b+tQfceGR6cf zeC?15T#XSipoWLuQPq0m6)i}s)M;+Dy^g?~69mF70%Kg%m4I+nQJ@=H#Q*)0DsE7X zt}(Ct4zVqy6b#})O0D0d^ak*q!=lidhk+vmRpK2j*dg}R6dXLw9~_!*?$_kZyWu!= zAd0#sAV38ONyN*`--*zTRu@PWB$qQ75dx9GwRb2vasZ1(UQAJ)iZANdFuL|UYK#I~lbom?1eK&C34SR?&Y@A% z6f?QXP?Cp#1m{xEYXs2sviw>A5m*M^EnL(xFO`PFQW_WM`g5!jP>t<)qW|HF%LOj6 z0Z*MqUJCBAKZt5TL6_^f=l|2*mH$J%z42xmk;I5XacyO3knRLTGG7w)>ntnniF7RCs z<&aa9K~R90fk6D!L^6jiZ759Sy%PScox;xX_{J5Q%(JSzDJ`S&;k! zckrqB+lFC&m>FD3e%iHFQ7Fpk8a&m~cA5YAf>MLgM&%T@d{Dc>L|&(%&WBA8 z9+`uj4bhvfL+w|KR;B7+67CrHqdJ<=eUz0n`R&rcD=*Qxvs~6^NX_v8utr0=Rh8wd zp{@^O`e4kq1f4F0*GgXlW78nHM9rUyWM_t`g7w%vO%3i_h@a{Oq7YeW*+hB>hZG-d zqlDdyqRgS7Z0K?2B#5Y2e%LW*2<6N;=8bqspNVuotRIyu>fV%?p&(AUqFL9rWipBV z;e;zlbeg&bJRhU{g3pEpA(jF$cQ558)G^Lb#Vmm`deSNH807)xa5r#6D3Baz&+ySn zrU{(SY-0ZSRBNT|NeOJf{I{7C^ZjQ~K;cjwh=F?SusH*tQFC;)V@e_pr_cp$p$WTx zU~zP2w!oR}u+sn;7cqpF-+W{O>FN2iI`D~%sKa^VO$F7LY31P}EW}Pl5|~4aNk-!Q z9Lm#dnJ~A0wKlc1;dC3{!Y|GDEFhFP^lL&g~*|zNc;LaHEtO`bcLJu z)oH73L4W4KH~NS31oF`UJy?>r1s`0p(c)`NL^#oR`lceL_CK2rl8WW?fujE0P|fqQ zp?5*ikBh1cy7?Ll@AVqdfl-8cb5hV&Po>jBBt|YmWBx!B3dxfQ7oV1Mn z^2(^{s>Gak9EEUcKKsTh1@lCZ$z*>jNiW@gq-P8bAz>sv~FgR2=Zg{0%mnZ zMuP)d!-BN}E?SY&=Ema~Y%s=t9G>&=VcG^lutZgl3ddKk&(Xv7V4L)4 z%2>xpH6s*;Y=m&JIOK_5lN6!1OD31P}cJ21G}QZ1+$bHziT~gUy0)s@;NZ^9`r7#&K2sqMVl{sv z%g2IQx8NVOLi{KXWCpWJ?@yI?)pmO~xF4UX`1J7@N_@vG!DJ-67{F7FaJTQp?Zq5F zEob-WoRG4t9?v`-ke=*;&tyt3G=;*dur z=utb)LHf8;`A2Et#o%5bX*RxlPiQJOWgFeWFKYs&(Ro;k+%b;u?b&y_X&{RFDSevn{gP*&0sQZQWeT}3H;CN?Jctpx%>(4C zx{@7_7$`q=d^LW}#U7BZ1^#ow-$utx?rvOhXF*Y;g}m4=+H2-ioZ9=3Z~@V60Hk8_ z!A%fY&I$DUm)fVN(T8IS!(XtA?emKq5e9Lv;6;R5ceF>w@o9$-*0w%%tWfd)#W^Q4 zEcPurhe4pF!{_Z8%ss|gm7ixnb6v+LjXlZ<|P@q@OV$>74h=T_SH}1(nzBD<|LtGniSe- z;Is}9ptXeOqkwvdP3W=0fdjE)rx-r4`8rgr%D{TjUt)mGtx0>CkY-M$yChB!enM0< zo{je4IKE=vnNTN>)L224#0y~;wQ?}W#fjkX4nOit;*m*h@#7`VnvD&`@ukrb`7YUe z?ru^rfSwln;5#8bykB8VIZfb6PkmU+XZNqo5Ghz$1KT%An8@7}f4~5C1gvJV<$h3w zT2OZBv-q||e%^KcZD0@ zqAP^P{6TPKkB`b7U48W&7rO}7NybN5@Ov_T0opcmOHS1@%O3RCv0jP?BLqB}7x}>? zJa8#xGlwSczOUVqlwa~o> "$GITHUB_OUTPUT" + + set-product-version: + name: "Parse version file" + runs-on: ubuntu-latest + outputs: + product-version: ${{ steps.set-product-version.outputs.product-version }} + product-base-version: ${{ steps.set-product-version.outputs.base-product-version }} + product-prerelease-version: ${{ steps.set-product-version.outputs.prerelease-product-version }} + product-minor-version: ${{ steps.set-product-version.outputs.minor-product-version }} + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - name: Set variables + id: set-product-version + uses: hashicorp/actions-set-product-version@v2 + + generate-metadata-file: + needs: set-product-version + runs-on: ubuntu-latest + outputs: + filepath: ${{ steps.generate-metadata-file.outputs.filepath }} + steps: + - name: "Checkout directory" + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - name: Generate metadata file + id: generate-metadata-file + uses: hashicorp/actions-generate-metadata@v1 + with: + version: ${{ needs.set-product-version.outputs.product-version }} + product: ${{ env.PKG_NAME }} + repositoryOwner: "hashicorp" + - uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1 + with: + name: metadata.json + path: ${{ steps.generate-metadata-file.outputs.filepath }} + + upload-terraform-registry-manifest-artifact: + needs: set-product-version + runs-on: ubuntu-latest + steps: + - name: "Checkout directory" + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + path: ${{ env.PKG_NAME }} + - name: "Copy manifest from checkout directory to a file with the desired name" + id: terraform-registry-manifest + run: | + name="${{ env.PKG_NAME }}" + version="${{ needs.set-product-version.outputs.product-version }}" + + source="${name}/terraform-registry-manifest.json" + destination="${name}_${version}_manifest.json" + + cp "$source" "$destination" + echo "filename=$destination" >> "$GITHUB_OUTPUT" + - uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1 + with: + name: terraform-registry-manifest.json + path: ${{ steps.terraform-registry-manifest.outputs.filename }} + if-no-files-found: error + + build: + needs: + - get-go-version + - set-product-version + runs-on: ubuntu-latest + strategy: + fail-fast: true + matrix: + goos: [freebsd, windows, linux, darwin] + goarch: ["386", "amd64", "arm", "arm64"] + exclude: + - goos: freebsd + goarch: arm64 + - goos: windows + goarch: arm64 + - goos: windows + goarch: arm + - goos: darwin + goarch: 386 + - goos: darwin + goarch: arm + + name: Go ${{ needs.get-go-version.outputs.go-version }} ${{ matrix.goos }} ${{ matrix.goarch }} build + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: hashicorp/actions-go-build@v1 + env: + CGO_ENABLED: 0 + BASE_VERSION: ${{ needs.set-product-version.outputs.product-base-version }} + PRERELEASE_VERSION: ${{ needs.set-product-version.outputs.product-prerelease-version}} + METADATA_VERSION: ${{ env.METADATA }} + with: + bin_name: "${{ env.PKG_NAME }}_v${{ needs.set-product-version.outputs.product-version }}_x5" + product_name: ${{ env.PKG_NAME }} + product_version: ${{ needs.set-product-version.outputs.product-version }} + go_version: ${{ needs.get-go-version.outputs.go-version }} + os: ${{ matrix.goos }} + arch: ${{ matrix.goarch }} + reproducible: report + instructions: | + go build \ + -o "$BIN_PATH" \ + -trimpath \ + -buildvcs=false \ + -ldflags "-s -w -X 'main.Version=${{ needs.set-product-version.outputs.product-version }}'" + cp LICENSE "$TARGET_DIR/LICENSE.txt" + + whats-next: + needs: + - build + - generate-metadata-file + - upload-terraform-registry-manifest-artifact + runs-on: ubuntu-latest + name: "What's next?" + steps: + - name: "Write a helpful summary" + run: | + github_dot_com="${{ github.server_url }}" + owner_with_name="${{ github.repository }}" + ref="${{ github.ref }}" + + echo "### What's next?" >> "$GITHUB_STEP_SUMMARY" + echo "#### For a release branch (see \`.release/ci.hcl\`)" >> $GITHUB_STEP_SUMMARY + echo "After this \`build\` workflow run completes succesfully, you can expect the CRT \`prepare\` workflow to begin momentarily." >> "$GITHUB_STEP_SUMMARY" + echo "To find the \`prepare\` workflow run, [view the checks for this commit]($github_dot_com/$owner_with_name/commits/$ref)" >> "$GITHUB_STEP_SUMMARY" diff --git a/shuttles/terraform/terraform-provider-helm/.github/workflows/changelog-checker.yml b/shuttles/terraform/terraform-provider-helm/.github/workflows/changelog-checker.yml new file mode 100644 index 0000000..0e7ca63 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.github/workflows/changelog-checker.yml @@ -0,0 +1,36 @@ +# This workflow checks that there is either a 'pr/no-changelog' label applied to a PR +# or there is a .changelog/.txt file associated with a PR for a changelog entry +name: Changelog Entry + +on: + pull_request: + types: [opened, synchronize, labeled] + # Runs on PRs to main and all release branches + branches: + - main + +jobs: + # checks that a .changelog entry is present for a PR + changelog-check: + # If there a `pr/no-changelog` label we ignore this check + if: "!contains(github.event.pull_request.labels.*.name, 'pr/no-changelog') || github.event.pull_request.user.login == 'dependabot'" + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 + with: + ref: ${{ github.event.pull_request.head.sha }} + fetch-depth: 0 # by default the checkout action doesn't checkout all branches + - name: Check for changelog entry in diff + run: | + # check if there is a diff in the .changelog directory + changelog_files=$(git --no-pager diff --name-only HEAD "$(git merge-base HEAD "origin/${{ github.event.pull_request.base.ref }}")" -- .changelog/${{ github.event.pull_request.number }}.txt) + + # If we do not find a file in .changelog/, we fail the check + if [ -z "$changelog_files" ]; then + # Fail status check when no .changelog entry was found on the PR + echo "Did not find a .changelog entry and the 'pr/no-changelog' label was not applied. Reference - https://github.com/hashicorp/terraform-provider-helm/tree/main/.github/workflows/CHANGELOG_GUIDE.md" + exit 1 + else + echo "Found .changelog entry in PR!" + fi diff --git a/shuttles/terraform/terraform-provider-helm/.github/workflows/codeql-analysis.yml b/shuttles/terraform/terraform-provider-helm/.github/workflows/codeql-analysis.yml new file mode 100644 index 0000000..c0f86d8 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.github/workflows/codeql-analysis.yml @@ -0,0 +1,68 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +name: "CodeQL" + +on: + push: + branches: [main] + pull_request: + # The branches below must be a subset of the branches above + branches: [main] + schedule: + - cron: '0 13 * * 0' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + # Override automatic language detection by changing the below list + # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python'] + language: ['go'] + # Learn more... + # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection + + steps: + - name: Checkout repository + uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 + with: + # We must fetch at least the immediate parents so that if this is + # a pull request then we can checkout the head. + fetch-depth: 2 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@c4fb451437765abf5018c6fbf22cce1a7da1e5cc # codeql-bundle-v2.17.1 + + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@c4fb451437765abf5018c6fbf22cce1a7da1e5cc # codeql-bundle-v2.17.1 + + + # ℹ️ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl + + # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + + #- run: | + # make bootstrap + # make release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@c4fb451437765abf5018c6fbf22cce1a7da1e5cc # codeql-bundle-v2.17.1 diff --git a/shuttles/terraform/terraform-provider-helm/.github/workflows/hc-copywrite.yml b/shuttles/terraform/terraform-provider-helm/.github/workflows/hc-copywrite.yml new file mode 100644 index 0000000..86b8a7b --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.github/workflows/hc-copywrite.yml @@ -0,0 +1,25 @@ +name: HashiCorp Copywrite + +on: + schedule: + - cron: '30 2 * * *' + pull_request: + branches: + - main + push: + branches: + - main + workflow_dispatch: + +jobs: + copywrite: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 + + - name: Install copywrite + uses: hashicorp/setup-copywrite@32638da2d4e81d56a0764aa1547882fc4d209636 # v1.1.3 + + - name: Validate Header Compliance + run: copywrite headers --plan diff --git a/shuttles/terraform/terraform-provider-helm/.github/workflows/issue-comment-created.yml b/shuttles/terraform/terraform-provider-helm/.github/workflows/issue-comment-created.yml new file mode 100644 index 0000000..0c4f898 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.github/workflows/issue-comment-created.yml @@ -0,0 +1,15 @@ +name: Issue Comment Created Triage + +on: + issue_comment: + types: [created] + +jobs: + issue_comment_triage: + runs-on: ubuntu-latest + steps: + - uses: actions-ecosystem/action-remove-labels@2ce5d41b4b6aa8503e285553f75ed56e0a40bae0 # v1.3.0 + with: + labels: | + stale + waiting-response diff --git a/shuttles/terraform/terraform-provider-helm/.github/workflows/issue-opened.yml b/shuttles/terraform/terraform-provider-helm/.github/workflows/issue-opened.yml new file mode 100644 index 0000000..b0e8f52 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.github/workflows/issue-opened.yml @@ -0,0 +1,56 @@ +name: Issue Opened Triage + +on: + issues: + types: [opened] + +jobs: + issue_triage: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 + - uses: github/issue-labeler@c1b0f9f52a63158c4adc09425e858e87b32e9685 # v3.4 + with: + repo-token: "${{ secrets.GITHUB_TOKEN }}" + configuration-path: .github/labeler-issue-triage.yml + enable-versioned-regex: 0 + oncall_review_assigner: + runs-on: ubuntu-latest + steps: + - uses: actions/setup-node@v4 + - run: npm install @pagerduty/pdjs + - uses: actions/github-script@e69ef5462fd455e02edcaf4dd7708eda96b9eda0 # v7.0.0 + env: + PAGERDUTY_TOKEN: ${{ secrets.PAGERDUTY_TOKEN }} + with: + script: | + const { PAGERDUTY_TOKEN } = process.env + const { api } = require('@pagerduty/pdjs'); + const pd = api({token: PAGERDUTY_TOKEN}); + const reviewerList = new Map([ + ["Sheneska Williams", "sheneska"], + ["Mauricio Alvarez Leon", "BBBmau"], + ["Alex Somesan", "alexsomesan"], + ["Alex Pilon", "appilon"], + ["John Houston", "jrhouston"], + ["Sacha Rybolovlev", "arybolovlev"], + ]); + + + let resp = await pd.get('oncalls?escalation_policy_ids%5B%5D=PH8IF3M') + if (resp.status != 200){ + core.setFailed("PagerDuty Error: " + resp.statusText) + } + const reviewer = resp.data.oncalls[0].user.summary + const reviewerGH = reviewerList.get(reviewer) + console.log("Assigning issue to " + reviewerGH); + + resp = await github.rest.issues.addAssignees({ + owner: context.repo.owner, + repo: context.repo.repo, + assignees: reviewerGH, + issue_number: context.issue.number, + }) + if (resp.status != 201){ + core.setFailed("error assigning reviewer: user doesn't have the appropriate permissions to be assigned an issue.") + } diff --git a/shuttles/terraform/terraform-provider-helm/.github/workflows/jira-issues.yml b/shuttles/terraform/terraform-provider-helm/.github/workflows/jira-issues.yml new file mode 100644 index 0000000..911a0db --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.github/workflows/jira-issues.yml @@ -0,0 +1,104 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +on: + issues: + types: [opened, closed, deleted, reopened, edited] + issue_comment: + types: [created] + workflow_dispatch: + +name: Jira Community Issue Sync + +jobs: + sync: + runs-on: ubuntu-latest + name: Jira Community Issue sync + steps: + - name: Login + uses: atlassian/gajira-login@ca13f8850ea309cf44a6e4e0c49d9aa48ac3ca4c # v3 + env: + JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }} + JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }} + JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }} + + - name: Set ticket type + id: set-ticket-type + run: | + echo "TYPE=GH Issue" >> $GITHUB_OUTPUT + + - name: Set ticket labels + if: github.event.action == 'opened' + id: set-ticket-labels + run: | + LABELS="[\"${{github.event.repository.name}}\", " + if [[ "${{ contains(github.event.issue.labels.*.name, 'bug') }}" == "true" ]]; then LABELS+="\"bug\", "; fi + if [[ "${{ contains(github.event.issue.labels.*.name, 'enhancement') }}" == "true" ]]; then LABELS+="\"enhancement\", "; fi + if [[ "${{ contains(github.event.issue.labels.*.name, 'documentation') }}" == "true" ]]; then LABELS+="\"documentation\", "; fi + if [[ "${{ contains(github.event.issue.labels.*.name, 'needs-investigation') }}" == "true" ]]; then LABELS+="\"needs-investigation\", "; fi + if [[ "${{ contains(github.event.issue.labels.*.name, 'question') }}" == "true" ]]; then LABELS+="\"question\", "; fi + if [[ "${{ contains(github.event.issue.labels.*.name, 'size/XS') }}" == "true" ]]; then LABELS+="\"size/XS\", "; fi + if [[ "${{ contains(github.event.issue.labels.*.name, 'size/S') }}" == "true" ]]; then LABELS+="\"size/S\", "; fi + if [[ "${{ contains(github.event.issue.labels.*.name, 'size/M') }}" == "true" ]]; then LABELS+="\"size/M\", "; fi + if [[ "${{ contains(github.event.issue.labels.*.name, 'size/L') }}" == "true" ]]; then LABELS+="\"size/L\", "; fi + if [[ "${{ contains(github.event.issue.labels.*.name, 'size/XL') }}" == "true" ]]; then LABELS+="\"size/XL\", "; fi + if [[ "${{ contains(github.event.issue.labels.*.name, 'size/XXL') }}" == "true" ]]; then LABELS+="\"size/XXL\", "; fi + if [[ "${{ contains(github.event.issue.labels.*.name, 'acknowledged') }}" == "true" ]]; then LABELS+="\"acknowledged\", "; fi + if [[ "${{ contains(github.event.issue.labels.*.name, 'help wanted') }}" == "true" ]]; then LABELS+="\"help wanted\", "; fi + if [[ "${{ contains(github.event.issue.labels.*.name, 'upstream-helm') }}" == "true" ]]; then LABELS+="\"upstream-helm\", "; fi + if [[ "${{ contains(github.event.issue.labels.*.name, 'upstream-terraform') }}" == "true" ]]; then LABELS+="\"upstream-terraform\", "; fi + if [[ "${{ contains(github.event.issue.labels.*.name, 'progressive apply') }}" == "true" ]]; then LABELS+="\"progressive apply\", "; fi + if [[ "${{ contains(github.event.issue.labels.*.name, 'pr/changelog') }}" == "true" ]]; then LABELS+="\"pr/changelog\", "; fi + if [[ "${{ contains(github.event.issue.labels.*.name, 'crash') }}" == "true" ]]; then LABELS+="\"crash\", "; fi + if [[ "${{ contains(github.event.issue.labels.*.name, 'breaking-change') }}" == "true" ]]; then LABELS+="\"breaking-change\", "; fi + if [[ "${{ contains(github.event.issue.labels.*.name, 'provider') }}" == "true" ]]; then LABELS+="\"provider\", "; fi + if [[ "${{ contains(github.event.issue.labels.*.name, 'stale') }}" == "true" ]]; then LABELS+="\"stale\", "; fi + if [[ ${#LABELS} != 1 ]]; then LABELS=${LABELS::-2}"]"; else LABELS+="]"; fi + echo "LABELS=${LABELS}" >> $GITHUB_OUTPUT + + - name: Create ticket if an issue is filed, or if PR not by a team member is opened + if: github.event.action == 'opened' + uses: tomhjp/gh-action-jira-create@3ed1789cad3521292e591a7cfa703215ec1348bf # v0.2.1 + with: + project: TFECO + issuetype: "${{ steps.set-ticket-type.outputs.TYPE }}" + summary: "${{ github.event.issue.title }}:[Issue-${{ github.event.issue.number }}] (${{ github.event.repository.name }})" + description: "${{ github.event.issue.body || github.event.pull_request.body }}\n\n_Created in GitHub by ${{ github.actor }}._\n\n${{ github.event.issue.html_url || github.event.pull_request.html_url }}" + # customfield_10089 is "Issue Link", customfield_10371 is "Source" (use JIRA API to retrieve) + extraFields: '{ "customfield_10089": "${{ github.event.issue.html_url || github.event.pull_request.html_url }}", + "customfield_10371": { "value": "GitHub" }, + "customfield_10091": ["TF-HybridCloud"], + "labels": ${{ steps.set-ticket-labels.outputs.LABELS }} }' + env: + JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }} + JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }} + JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }} + + - name: Search + if: github.event.action != 'opened' + id: search + uses: tomhjp/gh-action-jira-search@04700b457f317c3e341ce90da5a3ff4ce058f2fa # v0.2.2 + with: + # cf[10089] is Issue Link (use JIRA API to retrieve) + jql: 'issuetype = "${{ steps.set-ticket-type.outputs.TYPE }}" and cf[10089] = "${{ github.event.issue.html_url || github.event.pull_request.html_url }}"' + + - name: Sync comment + if: github.event.action == 'created' && steps.search.outputs.issue + uses: tomhjp/gh-action-jira-comment@6eb6b9ead70221916b6badd118c24535ed220bd9 # v0.2.0 + with: + issue: ${{ steps.search.outputs.issue }} + comment: "${{ github.actor }} ${{ github.event.review.state || 'commented' }}:\n\n${{ github.event.comment.body || github.event.review.body }}\n\n${{ github.event.comment.html_url || github.event.review.html_url }}" + + - name: Close ticket + if: ( github.event.action == 'closed' || github.event.action == 'deleted' ) && steps.search.outputs.issue + uses: atlassian/gajira-transition@38fc9cd61b03d6a53dd35fcccda172fe04b36de3 # v3 + with: + issue: ${{ steps.search.outputs.issue }} + transition: "Closed" + + - name: Reopen ticket + if: github.event.action == 'reopened' && steps.search.outputs.issue + uses: atlassian/gajira-transition@38fc9cd61b03d6a53dd35fcccda172fe04b36de3 # v3 + with: + issue: ${{ steps.search.outputs.issue }} + transition: "To Do" \ No newline at end of file diff --git a/shuttles/terraform/terraform-provider-helm/.github/workflows/jira-pr.yml b/shuttles/terraform/terraform-provider-helm/.github/workflows/jira-pr.yml new file mode 100644 index 0000000..e15f756 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.github/workflows/jira-pr.yml @@ -0,0 +1,102 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +on: + pull_request_target: + types: [opened, closed, reopened, edited] + workflow_dispatch: + +name: Jira Community PR Sync + +jobs: + sync: + runs-on: ubuntu-latest + name: Jira sync + steps: + - name: Login + uses: atlassian/gajira-login@ca13f8850ea309cf44a6e4e0c49d9aa48ac3ca4c # v3 + env: + JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }} + JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }} + JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }} + + - name: Set ticket type + id: set-ticket-type + run: | + echo "TYPE=GH Issue" >> $GITHUB_OUTPUT + + - name: Set ticket labels + if: github.event.action == 'opened' + id: set-ticket-labels + run: | + LABELS="[\"${{github.event.repository.name}}\", " + if [[ "${{ contains(github.event.pull_request.labels.*.name, 'bug') }}" == "true" ]]; then LABELS+="\"bug\", "; fi + if [[ "${{ contains(github.event.pull_request.labels.*.name, 'enhancement') }}" == "true" ]]; then LABELS+="\"enhancement\", "; fi + if [[ "${{ contains(github.event.pull_request.labels.*.name, 'documentation') }}" == "true" ]]; then LABELS+="\"documentation\", "; fi + if [[ "${{ contains(github.event.pull_request.labels.*.name, 'needs-investigation') }}" == "true" ]]; then LABELS+="\"needs-investigation\", "; fi + if [[ "${{ contains(github.event.pull_request.labels.*.name, 'question') }}" == "true" ]]; then LABELS+="\"question\", "; fi + if [[ "${{ contains(github.event.pull_request.labels.*.name, 'size/XS') }}" == "true" ]]; then LABELS+="\"size/XS\", "; fi + if [[ "${{ contains(github.event.pull_request.labels.*.name, 'size/S') }}" == "true" ]]; then LABELS+="\"size/S\", "; fi + if [[ "${{ contains(github.event.pull_request.labels.*.name, 'size/M') }}" == "true" ]]; then LABELS+="\"size/M\", "; fi + if [[ "${{ contains(github.event.pull_request.labels.*.name, 'size/L') }}" == "true" ]]; then LABELS+="\"size/L\", "; fi + if [[ "${{ contains(github.event.pull_request.labels.*.name, 'size/XL') }}" == "true" ]]; then LABELS+="\"size/XL\", "; fi + if [[ "${{ contains(github.event.pull_request.labels.*.name, 'size/XXL') }}" == "true" ]]; then LABELS+="\"size/XXL\", "; fi + if [[ "${{ contains(github.event.pull_request.labels.*.name, 'acknowledged') }}" == "true" ]]; then LABELS+="\"acknowledged\", "; fi + if [[ "${{ contains(github.event.pull_request.labels.*.name, 'help wanted') }}" == "true" ]]; then LABELS+="\"help wanted\", "; fi + if [[ "${{ contains(github.event.pull_request.labels.*.name, 'upstream-helm') }}" == "true" ]]; then LABELS+="\"upstream-helm\", "; fi + if [[ "${{ contains(github.event.pull_request.labels.*.name, 'upstream-terraform') }}" == "true" ]]; then LABELS+="\"upstream-terraform\", "; fi + if [[ "${{ contains(github.event.pull_request.labels.*.name, 'progressive apply') }}" == "true" ]]; then LABELS+="\"progressive apply\", "; fi + if [[ "${{ contains(github.event.pull_request.labels.*.name, 'pr/changelog') }}" == "true" ]]; then LABELS+="\"pr/changelog\", "; fi + if [[ "${{ contains(github.event.pull_request.labels.*.name, 'crash') }}" == "true" ]]; then LABELS+="\"crash\", "; fi + if [[ "${{ contains(github.event.pull_request.labels.*.name, 'breaking-change') }}" == "true" ]]; then LABELS+="\"breaking-change\", "; fi + if [[ "${{ contains(github.event.pull_request.labels.*.name, 'provider') }}" == "true" ]]; then LABELS+="\"provider\", "; fi + if [[ "${{ contains(github.event.pull_request.labels.*.name, 'stale') }}" == "true" ]]; then LABELS+="\"stale\", "; fi + if [[ ${#LABELS} != 1 ]]; then LABELS=${LABELS::-2}"]"; else LABELS+="]"; fi + echo "LABELS=${LABELS}" >> $GITHUB_OUTPUT + + - name: Create ticket if a PR is opened + if: ( github.event.action == 'opened') + uses: tomhjp/gh-action-jira-create@3ed1789cad3521292e591a7cfa703215ec1348bf # v0.2.1 + with: + project: TFECO + issuetype: "${{ steps.set-ticket-type.outputs.TYPE }}" + summary: "${{ github.event.pull_request.title }}:[PR-${{ github.event.pull_request.number }}] (${{ github.event.repository.name }})" + description: "${{ github.event.issue.body || github.event.pull_request.body }}\n\n_Created in GitHub by ${{ github.actor }}._\n\n${{ github.event.pull_request.html_url }}" + # customfield_10089 is "Issue Link", customfield_10371 is "Source" (use JIRA API to retrieve) + extraFields: '{ "customfield_10089": "${{ github.event.pull_request.html_url }}", + "customfield_10371": { "value": "GitHub" }, + "customfield_10091": ["TF-HybridCloud"], + "labels": ${{ steps.set-ticket-labels.outputs.LABELS }} }' + env: + JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }} + JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }} + JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }} + + - name: Search + if: github.event.action != 'opened' + id: search + uses: tomhjp/gh-action-jira-search@04700b457f317c3e341ce90da5a3ff4ce058f2fa # v0.2.2 + with: + # cf[10089] is Issue Link (use JIRA API to retrieve) + jql: 'issuetype = "${{ steps.set-ticket-type.outputs.TYPE }}" and cf[10089] = "${{ github.event.issue.html_url || github.event.pull_request.html_url }}"' + + - name: Sync comment + if: github.event.action == 'created' && steps.search.outputs.issue + uses: tomhjp/gh-action-jira-comment@6eb6b9ead70221916b6badd118c24535ed220bd9 # v0.2.0 + with: + issue: ${{ steps.search.outputs.issue }} + comment: "${{ github.actor }} ${{ github.event.review.state || 'commented' }}:\n\n${{ github.event.comment.body || github.event.review.body }}\n\n${{ github.event.comment.html_url || github.event.review.html_url }}" + + - name: Close PR + if: ( github.event.action == 'closed' || github.event.action == 'deleted' || github.event.pull_request.merged == true) && steps.search.outputs.issue + uses: atlassian/gajira-transition@38fc9cd61b03d6a53dd35fcccda172fe04b36de3 # v3 + with: + issue: ${{ steps.search.outputs.issue }} + transition: "Closed" + + - name: Reopen PR + if: github.event.action == 'reopened' && steps.search.outputs.issue + uses: atlassian/gajira-transition@38fc9cd61b03d6a53dd35fcccda172fe04b36de3 # v3 + with: + issue: ${{ steps.search.outputs.issue }} + transition: "To Do" \ No newline at end of file diff --git a/shuttles/terraform/terraform-provider-helm/.github/workflows/lock.yml b/shuttles/terraform/terraform-provider-helm/.github/workflows/lock.yml new file mode 100644 index 0000000..697265b --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.github/workflows/lock.yml @@ -0,0 +1,23 @@ +name: 'Lock Threads' + +on: + schedule: + - cron: '49 1 * * *' + +jobs: + lock: + runs-on: ubuntu-latest + steps: + - uses: dessant/lock-threads@1bf7ec25051fe7c00bdd17e6a7cf3d7bfb7dc771 # v5.0.1 + with: + github-token: ${{ github.token }} + issue-lock-comment: > + I'm going to lock this issue because it has been closed for _30 days_ ⏳. This helps our maintainers find and focus on the active issues. + + If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further. + issue-lock-inactive-days: '30' + pr-lock-comment: > + I'm going to lock this pull request because it has been closed for _30 days_ ⏳. This helps our maintainers find and focus on the active issues. + + If you have found a problem that seems related to this change, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further. + pr-lock-inactive-days: '30' diff --git a/shuttles/terraform/terraform-provider-helm/.github/workflows/prune_stale_issues.yml b/shuttles/terraform/terraform-provider-helm/.github/workflows/prune_stale_issues.yml new file mode 100644 index 0000000..9dad5a4 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.github/workflows/prune_stale_issues.yml @@ -0,0 +1,15 @@ +name: "Close stale issues" +on: + schedule: + - cron: "0 0 * * *" + +jobs: + stale: + runs-on: ubuntu-latest + steps: + - uses: actions/stale@28ca1036281a5e5922ead5184a1bbf96e5fc984e # 9.0.0 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + stale-issue-message: 'Marking this issue as stale due to inactivity. If this issue receives no comments in the next 30 days it will automatically be closed. If this issue was automatically closed and you feel this issue should be reopened, we encourage creating a new issue linking back to this one for added context. This helps our maintainers find and focus on the active issues. Maintainers may also remove the stale label at their discretion. Thank you!' + days-before-stale: 365 + days-before-close: 30 \ No newline at end of file diff --git a/shuttles/terraform/terraform-provider-helm/.github/workflows/pull-request.yml b/shuttles/terraform/terraform-provider-helm/.github/workflows/pull-request.yml new file mode 100644 index 0000000..b77e9ff --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.github/workflows/pull-request.yml @@ -0,0 +1,25 @@ +name: "Pull Request Triage" + +on: [pull_request_target] + +jobs: + triage: + runs-on: ubuntu-latest + steps: + - uses: actions/labeler@ba790c862c380240c6d5e7427be5ace9a05c754b # v4.0.3 + with: + configuration-path: .github/labeler-pull-request-triage.yml + repo-token: "${{ secrets.GITHUB_TOKEN }}" + - uses: CodelyTV/pr-size-labeler@54ef36785e9f4cb5ecf1949cfc9b00dbb621d761 # v1.8.1 + with: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + xs_label: 'size/XS' + xs_max_size: '30' + s_label: 'size/S' + s_max_size: '60' + m_label: 'size/M' + m_max_size: '150' + l_label: 'size/L' + l_max_size: '300' + xl_label: 'size/XL' + message_if_xl: '' diff --git a/shuttles/terraform/terraform-provider-helm/.github/workflows/tests.yaml b/shuttles/terraform/terraform-provider-helm/.github/workflows/tests.yaml new file mode 100644 index 0000000..bea43c0 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.github/workflows/tests.yaml @@ -0,0 +1,63 @@ +name: "tests" +on: + push: + branches: + - main + pull_request: + branches: + - main + +env: + KUBECONFIG: ${{ github.workspace }}/.kube/config + +jobs: + get_version_matrix: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 + - id: get_version_matrix + shell: bash + run: scripts/get-version-matrix.sh + outputs: + version_matrix: ${{ steps.get_version_matrix.outputs.matrix }} + unit_test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 + - name: Set up Go + uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 + with: + go-version-file: go.mod + - name: Unit tests + env: + GOPATH: /home/runner/go + run: | + make test + make vet + acc_test: + needs: get_version_matrix + runs-on: ubuntu-latest + strategy: + # Don't cancel all in-progress and queued jobs in the matrix if any job in the matrix fails. + # That will be helpful to catch any issues related to a particular Terraform version. + fail-fast: false + matrix: + terraform_version: ${{ fromJson(needs.get_version_matrix.outputs.version_matrix) }} + steps: + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 + - name: Set up Go + uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 + with: + go-version-file: go.mod + - uses: helm/kind-action@0025e74a8c7512023d06dc019c617aa3cf561fde # v1.10.0 + id: kind + with: + wait: 2m + - name: Acceptance Tests + env: + KUBE_CONFIG_PATH: ${{ env.KUBECONFIG }} + TF_ACC_TERRAFORM_VERSION: ${{ matrix.terraform_version }} + TF_ACC_TEMP_DIR: ${{ runner.temp }} + TESTARGS: "-parallel 1" + run: | + make testacc diff --git a/shuttles/terraform/terraform-provider-helm/.github/workflows/website.yaml b/shuttles/terraform/terraform-provider-helm/.github/workflows/website.yaml new file mode 100644 index 0000000..ebc2863 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.github/workflows/website.yaml @@ -0,0 +1,17 @@ +name: website +on: + push: + paths: + - "docs/**" + pull_request: + branches: + - main + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 + - name: website-lint + run: | + make website-lint diff --git a/shuttles/terraform/terraform-provider-helm/.gitignore b/shuttles/terraform/terraform-provider-helm/.gitignore new file mode 100644 index 0000000..65a5620 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.gitignore @@ -0,0 +1,38 @@ +terraform-provider-helm +terraform-provider-helm_v* +*.tfstate* +/build +assets +.terraform +_output/ +.vscode +/results +*.dll +*.exe +.DS_Store +example.tf +terraform.tfvars +terraform.tfplan +bin/ +modules-dev/ +/pkg/ +website/.vagrant +website/.bundle +website/build +website/node_modules +.vagrant/ +*.backup +*.log +*.bak +*~ +.*.swp +.idea +*.iml +*.test +*.iml + +website/vendor + +# Test exclusions +!command/test-fixtures/**/*.tfstate +!command/test-fixtures/**/.terraform/ diff --git a/shuttles/terraform/terraform-provider-helm/.markdownlinkcheck.json b/shuttles/terraform/terraform-provider-helm/.markdownlinkcheck.json new file mode 100644 index 0000000..3707354 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.markdownlinkcheck.json @@ -0,0 +1,29 @@ +{ + "ignorePatterns": [ + { + "pattern": "^http(s)?:\/\/terraform.io/(.*)" + } + ], + "replacementPatterns": [ + { + "pattern": "^(/docs/(?!providers/helm/))", + "replacement": "https://terraform.io$1" + }, + { + "pattern": "^(?!http(s)?://)(.*)\\.html(#.*)?$", + "replacement": "$2.html.markdown$3" + }, + { + "pattern": "^/docs/providers/helm/", + "replacement": "file:///github/workspace/docs/" + }, + { + "pattern": "^(getting-started).html.markdown(#.*)?$", + "replacement": "file:///github/workspace/docs/guides/$1.html.md$2" + }, + { + "pattern": "^file:///github/workspace/docs/guides/(.*)\\.markdown(#.*)?$", + "replacement": "file:///github/workspace/docs/guides/$1.md$2" + } + ] +} diff --git a/shuttles/terraform/terraform-provider-helm/.markdownlint.yml b/shuttles/terraform/terraform-provider-helm/.markdownlint.yml new file mode 100644 index 0000000..6bfeb93 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.markdownlint.yml @@ -0,0 +1,19 @@ +# Configuration for markdownlint +# https://github.com/DavidAnson/markdownlint#configuration + +default: true +MD007: + indent: 2 + +# Disabled Rules +# https://github.com/DavidAnson/markdownlint/blob/master/doc/Rules.md + +MD001: false +MD004: false +MD006: false +MD012: false +MD013: false +MD014: false +MD022: false +MD024: false +MD033: false diff --git a/shuttles/terraform/terraform-provider-helm/.release/ci.hcl b/shuttles/terraform/terraform-provider-helm/.release/ci.hcl new file mode 100644 index 0000000..ce17ee1 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.release/ci.hcl @@ -0,0 +1,81 @@ +schema = "2" + +project "terraform-provider-helm" { + team = "terraform" + + slack { + notification_channel = "C051FAAHL8M" // #feed-terraform-ecosystem-kubernetes-releases + } + + github { + organization = "hashicorp" + repository = "terraform-provider-helm" + release_branches = ["main", "release/**"] + } +} + +event "merge" { +} + +event "build" { + action "build" { + depends = ["merge"] + + organization = "hashicorp" + repository = "terraform-provider-helm" + workflow = "build" + } +} + +event "prepare" { + depends = ["build"] + + action "prepare" { + organization = "hashicorp" + repository = "crt-workflows-common" + workflow = "prepare" + depends = ["build"] + } + + notification { + on = "fail" + } +} + +event "trigger-staging" { +} + +event "promote-staging" { + action "promote-staging" { + organization = "hashicorp" + repository = "crt-workflows-common" + workflow = "promote-staging" + depends = null + config = "release-metadata.hcl" + } + + depends = ["trigger-staging"] + + notification { + on = "always" + } +} + +event "trigger-production" { +} + +event "promote-production" { + action "promote-production" { + organization = "hashicorp" + repository = "crt-workflows-common" + workflow = "promote-production" + depends = null + config = "" + } + + depends = ["trigger-production"] + + notification { + on = "always" + } +} diff --git a/shuttles/terraform/terraform-provider-helm/.release/release-metadata.hcl b/shuttles/terraform/terraform-provider-helm/.release/release-metadata.hcl new file mode 100644 index 0000000..5c3afea --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.release/release-metadata.hcl @@ -0,0 +1,4 @@ +url_source_repository = "https://github.com/hashicorp/terraform-provider-helm" +url_project_website = "https://registry.terraform.io/providers/hashicorp/helm" +url_license = "https://github.com/hashicorp/terraform-provider-helm/blob/main/LICENSE" +url_release_notes = "https://github.com/hashicorp/terraform-provider-helm/blob/main/CHANGELOG.md" diff --git a/shuttles/terraform/terraform-provider-helm/.release/security-scan.hcl b/shuttles/terraform/terraform-provider-helm/.release/security-scan.hcl new file mode 100644 index 0000000..5a48bf8 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.release/security-scan.hcl @@ -0,0 +1,18 @@ +binary { + secrets { + all = true + } + go_modules = true + osv = true + oss_index = false + nvd = false + + triage { + suppress { + vulnerabilities = [ + "GO", + "GHSA" + ] + } + } +} diff --git a/shuttles/terraform/terraform-provider-helm/.release/terraform-provider-kubernetes-artifacts.hcl b/shuttles/terraform/terraform-provider-helm/.release/terraform-provider-kubernetes-artifacts.hcl new file mode 100644 index 0000000..cd7a53a --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/.release/terraform-provider-kubernetes-artifacts.hcl @@ -0,0 +1,16 @@ +schema = 1 +artifacts { + zip = [ + "terraform-provider-helm_${version}_darwin_amd64.zip", + "terraform-provider-helm_${version}_darwin_arm64.zip", + "terraform-provider-helm_${version}_freebsd_386.zip", + "terraform-provider-helm_${version}_freebsd_amd64.zip", + "terraform-provider-helm_${version}_freebsd_arm.zip", + "terraform-provider-helm_${version}_linux_386.zip", + "terraform-provider-helm_${version}_linux_amd64.zip", + "terraform-provider-helm_${version}_linux_arm.zip", + "terraform-provider-helm_${version}_linux_arm64.zip", + "terraform-provider-helm_${version}_windows_386.zip", + "terraform-provider-helm_${version}_windows_amd64.zip", + ] +} diff --git a/shuttles/terraform/terraform-provider-helm/CHANGELOG.md b/shuttles/terraform/terraform-provider-helm/CHANGELOG.md new file mode 100644 index 0000000..b6f50e7 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/CHANGELOG.md @@ -0,0 +1,585 @@ +## 3.0.1 (Jun 18, 2025) + +This is a hotfix release. + +HOTFIX: + +- `helm_release`: Fix state upgrader code to use correct type for "values" attribute. [[GH-1638](https://github.com/hashicorp/terraform-provider-helm/pull/1638)] + + +## 3.0.0 (Jun 18, 2025) + +This release migrates ports the provider project from `terraform-plugin-sdk/v2` to `terraform-plugin-framework` [[GH-1379](https://github.com/hashicorp/terraform-provider-helm/pull/1379)] + +Please refer to the [migration guide](./docs/guides/v3-upgrade-guide.md). + +BREAKING CHANGES: + +- **Blocks to Nested Objects**: Blocks like `kubernetes`, `registry`, and `experiments` are now represented as nested objects. +- **List Syntax for Nested Attributes**: Attributes like `set`, `set_list`, and `set_sensitive` in `helm_release` and `helm_template` are now lists of nested objects instead of blocks +- The new framework code uses [Terraform Plugin Protocol Version 6](https://developer.hashicorp.com/terraform/plugin/terraform-plugin-protocol#protocol-version-6) which is compatible with Terraform versions 1.0 and aboove. Users of earlier versions of Terraform can continue to use the Helm provider by pinning their configuration to the 2.x version. + +FEATURES: + +* Add `"literal"` as a supported `type` for the `set` block [[GH-1615](https://github.com/hashicorp/terraform-provider-helm/issues/1615)] + +* `helm_release`: Add support for ResourceIdentity. [[GH-1625](https://github.com/hashicorp/terraform-provider-helm/issues/1625)] + +* `helm_release`: Add `set_wo` write-only attribute [[GH-1592](https://github.com/hashicorp/terraform-provider-helm/issues/1592)] + +ENHANCEMENT: + +* `helm_release`: Add `UpgradeState` logic to support migration from SDKv2 to Plugin Framework [[GH-1633](https://github.com/hashicorp/terraform-provider-helm/issues/1633)] +* update helm dependency to v3.17.2 [[GH-1608](https://github.com/hashicorp/terraform-provider-helm/issues/1608)] + +BUG FIXES: + +* `helm_release`: Fix namespace behaviour for dependency charts in non-default namespaces [[GH-1583](https://github.com/hashicorp/terraform-provider-helm/issues/1583)] + +* change `set.value` && `set_list.value` to optional instead of required [[GH-1572](https://github.com/hashicorp/terraform-provider-helm/issues/1572)] + +## 3.0.0-pre2 (Feb 27, 2025) + +FEATURES: + +* `helm_release`: Add `set_wo` write-only attribute [[GH-1592](https://github.com/hashicorp/terraform-provider-helm/issues/1592)] + +BUG FIXES: + +* change `set.value` && `set_list.value` to optional instead of required [[GH-1572](https://github.com/hashicorp/terraform-provider-helm/issues/1572)] + + +## 3.0.0-pre1 (Jan 16, 2025) + +* This pre-release migrates ports the provider project from `terraform-plugin-sdk/v2` to `terraform-plugin-framework` [[GH-1379](https://github.com/hashicorp/terraform-provider-helm/pull/1379)] + +Please refer to the [migration guide](./docs/guides/v3-upgrade-guide.md). + +## 2.17.0 (Dec 19, 2024) + +ENHANCEMENT: + +* `resource/helm_release`: the dry-run option is now set to `server` to execute any chart lookups against the server during the plan stage. [[GH-1335](https://github.com/hashicorp/terraform-provider-helm/issues/1335)] + +BUG FIXES: + +* `resource/helm_release`: fix an issue where `postrender.args` is not parsed correctly. [[GH-1534](https://github.com/hashicorp/terraform-provider-helm/issues/1534)] + +## 2.16.1 (Oct 15, 2024) + +BUG FIXES: + +* `helm_release`: Fix nil pointer deref panic on destroy when helm release is not found [[GH-1501](https://github.com/hashicorp/terraform-provider-helm/issues/1501)] + +## 2.16.0 (Oct 10, 2024) + +BUG FIXES: + +* `helm_release`: On destroy, do not error when release is not found [[GH-1487](https://github.com/hashicorp/terraform-provider-helm/issues/1487)] +* `resource/helm_release`: Fix: only recompute metadata when the version in the metadata changes [[GH-1458](https://github.com/hashicorp/terraform-provider-helm/issues/1458)] + +## 2.15.0 (Aug 14, 2024) + +ENHANCEMENT: + +* 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) [[GH-1247](https://github.com/hashicorp/terraform-provider-helm/issues/1247)] + +## 2.14.1 (Aug 7, 2024) + +DEPENDENCIES: + +* Bump golang.org/x/crypto from v0.23.0 to v0.25.0 [[GH-1399](https://github.com/hashicorp/terraform-provider-helm/pull/1399)] +* Bump k8s.io/api from v0.30.0 to v0.30.3 [[GH-1436](https://github.com/hashicorp/terraform-provider-helm/pull/1436)] +* Bump k8s.io/apimachinery from v0.30.0 to v0.30.3 [[GH-1436](https://github.com/hashicorp/terraform-provider-helm/pull/1436)] +* Bump k8s.io/client-go from v0.30.0 to v0.30.3 [[GH-1436](https://github.com/hashicorp/terraform-provider-helm/pull/1436)] +* Bump helm.sh/helm/v3 from v3.13.2 to v3.15.3 [[GH-1422](https://github.com/hashicorp/terraform-provider-helm/pull/1422)] + +## 2.14.0 (June 13, 2024) + +ENHANCEMENT: + +* Add support for Terraform's experimental deferred actions [[GH-1377](https://github.com/hashicorp/terraform-provider-helm/issues/1377)] +* `helm_release`: add new attributes metadata.last_deployed, metadata.first_deployed, metadata.notes [[GH-1380](https://github.com/hashicorp/terraform-provider-helm/issues/1380)] + +## 2.13.2 (May 8, 2024) + +DEPENDENCIES: + +* Bump github.com/docker/docker from 24.0.7 to 24.0.9 +* Bump golang.org/x/net from 0.21.0 to 0.23.0 +* Bundle license file with TF provider release artifacts + +## 2.13.1 (Apr 15, 2024) + +HOTFIX: + +* `helm_release`: Fix regression causing errors at plan time. + +## 2.13.0 (Apr 4, 2024) + +BUG FIXES: + +* `provider`: Fix manifest diff rendering for OCI charts. [[GH-1326](https://github.com/hashicorp/terraform-provider-helm/issues/1326)] + +DOCS: + +* `docs`: Use templatefile() instead of "template_file" provider in GKE example. [[GH-1329](https://github.com/hashicorp/terraform-provider-helm/issues/1329)] + +## 2.12.1 (Nov 30, 2023) + +DEPENDENCIES: + +* Bump Golang from `1.20` to `1.21`. [[GH-1300](https://github.com/hashicorp/terraform-provider-helm/issues/1300)] +* Bump github.com/hashicorp/go-cty from `v1.4.1-0.20200414143053-d3edf31b6320` to `v1.4.1-0.20200723130312-85980079f637`. [[GH-1300](https://github.com/hashicorp/terraform-provider-helm/issues/1300)] +* Bump github.com/hashicorp/terraform-plugin-docs from `v0.14.1` to `v0.16.0`. [[GH-1300](https://github.com/hashicorp/terraform-provider-helm/issues/1300)] +* Bump github.com/hashicorp/terraform-plugin-sdk/v2 from `v2.26.1` to `v2.30.0`. [[GH-1300](https://github.com/hashicorp/terraform-provider-helm/issues/1300)] +* Bump golang.org/x/crypto from `v0.14.0` to `v0.16.0`. [[GH-1300](https://github.com/hashicorp/terraform-provider-helm/issues/1300)] +* Bump helm.sh/helm/v3 from `v3.13.1` to `v3.13.2`. [[GH-1300](https://github.com/hashicorp/terraform-provider-helm/issues/1300)] +* Bump k8s.io/api from `v0.28.3` to `v0.28.4`. [[GH-1300](https://github.com/hashicorp/terraform-provider-helm/issues/1300)] +* Bump k8s.io/apimachinery from `v0.28.3` to `v0.28.4`. [[GH-1300](https://github.com/hashicorp/terraform-provider-helm/issues/1300)] +* Bump k8s.io/client-go from `v0.28.3` to `v0.28.4`. [[GH-1300](https://github.com/hashicorp/terraform-provider-helm/issues/1300)] +* Bump sigs.k8s.io/yaml from `v1.3.0` to `v1.4.0`. [[GH-1300](https://github.com/hashicorp/terraform-provider-helm/issues/1300)] + +## 2.12.0 (Nov 27, 2023) + +BUG FIXES: + +* `helm_release`: Fix perpetual diff when version attribute is an empty string [[GH-1246](https://github.com/hashicorp/terraform-provider-helm/issues/1246)] + +DEPENDENCIES: + +* Bump `helm.sh/helm/v3` from `3.12.0` to `3.13.1` + +## 2.11.0 (Aug 24, 2023) + +ENHANCEMENT: + +* `kubernetes/provider.go`: Add `tls_server_name` kubernetes provider options. [[GH-839](https://github.com/hashicorp/terraform-provider-helm/issues/839)] +* `resource/helm_release`: add `name` field validation to be limited to 53 characters. [[GH-1228](https://github.com/hashicorp/terraform-provider-helm/issues/1228)] + +BUG FIXES: + +* `helm/resource_release.go`: Fix: version conflicts when using local chart [[GH-1176](https://github.com/hashicorp/terraform-provider-helm/issues/1176)] +* `resource/helm_release`: Add nil check for `set_list.value` to prevent provider ChartPathOptions [[GH-1231](https://github.com/hashicorp/terraform-provider-helm/issues/1231)] + +## 2.10.1 (Jun 5, 2023) + +HOTFIX: + +* `helm_release`: Fix: Only recompute metadata if version actually changes. [[GH-1150](https://github.com/hashicorp/terraform-provider-helm/issues/1150)] + +## 2.10.0 (May 30, 2023) + +FEATURES: + +* `helm_release`: Add `set_list` attribute [[GH-1071](https://github.com/hashicorp/terraform-provider-helm/issues/1071)] + +BUG FIXES: + +* `helm_release`: Always recompute metadata when a release is updated [[GH-1097](https://github.com/hashicorp/terraform-provider-helm/issues/1097)] + +DEPENDENCIES: + +* Bump `helm.sh/helm/v3` from `3.11.2` to `3.12.0` [[GH-1143](https://github.com/hashicorp/terraform-provider-helm/issues/1143)] + +## 2.9.0 (February 14, 2023) + +FEATURES: + +* `provider`: Add a new attribute `burst_limit` for client-side throttling limit configuration. [[GH-1012](https://github.com/hashicorp/terraform-provider-helm/issues/1012)] + +ENHANCEMENT: + +* `data_source/helm_template`: Add a new attribute `crds` which when `include_crds` is set to `true` will be populated with a list of the manifests from the `crds/` folder of the chart. [[GH-1050](https://github.com/hashicorp/terraform-provider-helm/issues/1050)] + +BUG FIXES: + +* `resource/helm_release`: Fix an issue when the provider crashes with the error message `Provider produced inconsistent final plan` after upgrading from `v2.5.1` to `v2.6.0` and higher. That happened due to changes in the provider schema and the introduction of a new attribute `pass_credentials` that was not properly handled. [[GH-982](https://github.com/hashicorp/terraform-provider-helm/issues/982)] + +DOCS: + +* `data_source/helm_template`: Add a new attribute `crds` [[GH-1050](https://github.com/hashicorp/terraform-provider-helm/issues/1050)] +* `data_source/helm_template`: Correct some errors in examples. [[GH-1027](https://github.com/hashicorp/terraform-provider-helm/issues/1027)] +* `provider`: Add a new attribute `burst_limit`. [[GH-1012](https://github.com/hashicorp/terraform-provider-helm/issues/1012)] +* `provider`: Add a note regarding the `KUBECONFIG` environment variable. [[GH-1051](https://github.com/hashicorp/terraform-provider-helm/issues/1051)] +* `resource/helm_release`: Add usage example for `OCI` repositories. [[GH-1030](https://github.com/hashicorp/terraform-provider-helm/issues/1030)] +* `resource/helm_release`: Add usage examples for `GCS` and `S3` plugins. [[GH-1026](https://github.com/hashicorp/terraform-provider-helm/issues/1026)] + +DEPENDENCIES: + +* Bump `github.com/containerd/containerd` from `1.6.6` to `1.6.12` [[GH-1029](https://github.com/hashicorp/terraform-provider-helm/issues/1029)] +* Bump `golang.org/x/crypto` from `0.5.0` to `0.6.0` [[GH-1055](https://github.com/hashicorp/terraform-provider-helm/issues/1055)] +* Bump `helm.sh/helm/v3` from `3.9.4` to `3.11.1` [[GH-1036](https://github.com/hashicorp/terraform-provider-helm/issues/1036)] [[GH-1054](https://github.com/hashicorp/terraform-provider-helm/issues/1054)] +* Bump `k8s.io/client-go` from `0.24.2` to `0.26.1` [[GH-1037](https://github.com/hashicorp/terraform-provider-helm/issues/1037)] + +NOTES: + +* `provider`: `kubernetes.exec.api_version` no longer supports `client.authentication.k8s.io/v1alpha1`. Please, switch to `client.authentication.k8s.io/v1beta1` or `client.authentication.k8s.io/v1`. [[GH-1037](https://github.com/hashicorp/terraform-provider-helm/issues/1037)] + +## Community Contributors :raised_hands: +- @loafoe made their contribution in https://github.com/hashicorp/terraform-provider-helm/pull/1012 + +## 2.8.0 (December 13, 2022) + +FEATURES: + +* Add support for configuring OCI registries inside provider block [[GH-862](https://github.com/hashicorp/terraform-provider-helm/issues/862)] +* Add support for setting kube version on helm_template data source [[GH-994](https://github.com/hashicorp/terraform-provider-helm/issues/994)] + +BUG FIXES: + +* Fix larger diff than expected when updating helm_release "set" block value [[GH-915](https://github.com/hashicorp/terraform-provider-helm/issues/915)] + +## 2.7.1 (October 12, 2022) + +BUG FIXES: + +* Crash Fix: Fix Unknown Value in Manifest Diff [[GH-966](https://github.com/hashicorp/terraform-provider-helm/issues/966)] + +## 2.7.0 (September 28, 2022) + +FEATURES: + +* Update helm package to 3.9.4 (#945) +* Show Manifest when creating release [[GH-903](https://github.com/hashicorp/terraform-provider-helm/issues/903)] + +BUG FIXES: + +* Do dependency update in resourceDiff #771 (#855) +* Crash: Fix `show_only` crash when string is empty [[GH-950](https://github.com/hashicorp/terraform-provider-helm/issues/950)] + +## 2.6.0 (June 17, 2022) + +IMPROVEMENTS: +* Upgrade helm dependency to 3.9.0 (#867) +* Add `args` attribute in `post_render` block in (#869) +* Add `pass_credentials` attribute (#841) +* Add `proxy_url` attribute to provider block (#843) + +BUG FIXES: +* Don't persist state when update causes an error (#857) + +## 2.5.1 (April 11, 2022) + +FIX: +* Only run OCI login on create and update (#846) +* OCI login concurrency issue (#848) + +## 2.5.0 (March 28, 2022) + +* Upgrade helm dependency to v3.8.1 +* Add support for OCI registries + +## 2.4.1 (November 09, 2021) + +HOTFIX: +* Fix exec plugin interactive mode regression (#798) + +## 2.4.0 (November 08, 2021) + +* Upgrade helm to 3.7.1 + +## 2.3.0 (August 27, 2021) + +* Support templates with multiple resources in helm_template data source (#772) +* Upgrade helm to 3.6.2 + +## 2.2.0 (June 10, 2021) + +* Add support for stand-alone debug mode (launch with -debug argument) (#748) +* Add helm_template data source to render chart templates locally (#483) +* Surface diagnostics when helm release creation fails (#727) + +## 2.1.2 (April 27, 2021) + +* Fix dependency download on resource update (#580) +* Add support for the --wait-for-jobs option (#720) + +## 2.1.1 (April 16, 2021) + +* Fix dry-run happening at plan when manifest is not enabled (#724) + +## 2.1.0 (April 01, 2021) + +IMPROVEMENTS: +* Add chart diff support by storing the rendered manifest (#702) +* Update to Helm 3.5.3 (#709) +* Docs: add link to Learn tutorial (#714) + +BUG FIXES: +* Remove kubeconfig file check (#708) + +## 2.0.3 (March 11, 2021) + +BUG FIXES: +* Fix documentation for KUBE_TOKEN env var name (#684) +* Fix destroy stage error for charts with "helm.sh/resource-policy:keep" annotation (#671) +* Fix read function to set resource id to null when not found (#674) + +IMPROVEMENTS: +* Update provider configuration docs (#673) + +## 2.0.2 (January 18, 2021) + +BUG FIXES: +* Remove check for empty kubernetes block + +## 2.0.1 (December 19, 2020) + +BUG FIXES: +* Move kubernetes config check out of providerConfigure (#648) + +## 2.0.0 (December 19, 2020) + +BREAKING CHANGES: +Please review our [upgrade guide](https://github.com/hashicorp/terraform-provider-helm/blob/master/website/docs/guides/v2-upgrade-guide.markdown). + +* Update Terraform SDK to v2 (#594). +* Remove deprecated helm_repository resource and data source (#600) +* Remove implicit support for KUBECONFIG (#604) +* Remove load_config_file attribute (#604) +* Remove set_string attribute from helm_release (#608) + +IMPROVEMENTS: +* Add support for multiple paths to kubeconfig files (#636) +* Remove remote dependencies from test-fixtures (#638) +* Set up matrix build to run acc tests against different tf versions (#637) + + +## 1.3.2 (October 07, 2020) + +BUG FIXES: +* Fix nil pointer crash when using Helm plugins (#598) + +## 1.3.1 (September 29, 2020) + +IMPROVEMENTS: +* Upgrade Helm to 3.3.4 (#572) + +## 1.3.0 (September 02, 2020) + +IMPROVEMENTS: +* Added app_version to metadata attribute block (#532) + +BUG FIXES: +* Fix nil path for `dependency_update` flag (#482) + +## 1.2.4 (July 22, 2020) + +BUG FIXES: + +* Update go-version for CVE-2020-14039 (#548) + +## 1.2.3 (June 16, 2020) + +BUG FIXES: + +* Fix concurrent read/write crash (#525) +* Fix for provider hang (#505) + +## 1.2.2 (June 01, 2020) + +BUG FIXES: + +* Add a lint attribute to helm_release (#514) + +## 1.2.1 (May 08, 2020) + +BUG FIXES: + +* Fix linter crash (#487) + +## 1.2.0 (May 06, 2020) + +IMPROVEMENTS: + +* Cloak sensitive values in metadata field (#480) +* Upgrade to Helm 3.2.0 +* Deprecate helm_repository data source +* Lint chart at plan time + +## 1.1.1 (March 26, 2020) + +BUG FIXES: + +* Fix chart path bug causing unwanted diff (#449) + +## 1.1.0 (March 19, 2020) + +IMPROVEMENTS: + +* Add import feature for helm_release (#394) +* Run acceptance tests in travis-ci using kind +* Upgrade helm to version v3.1.2 (#440) +* Add description attribute +* Add post-rendering support + +BUG FIXES: + +* Fix errors being swallowed when creating a helm_release (#406) +* Various documentation fixes + +## 1.0.0 (February 05, 2020) + +BREAKING CHANGES: + +* No longer supports helm v2 (#378) +* Provider no longer supports the following parameters + * host + * home + * namespace + * init_helm_home + * install_tiller + * tiller_image + * connection_timeout + * service_account + * automount_service_account_token + * override + * max_history (Moved to the release) + * plugins_disable + * insecure + * enable_tls + * client_key + * client_certificate + * ca_certificate +* Release no longer supports the following parameters + * disable_crd_hooks +* Release Parameters that were renamed + * reuse was renamed to replace to match the rename in helm v3 + +IMPROVEMENTS: + +* Upgrade Helm to v3.0 +* Adds the following parameters to the provider + * plugins_path - (Optional) The path to the plugins directory. Defaults to `HELM_PLUGINS` env if it is set, otherwise uses the default path set by helm. + * registry_config_path - (Optional) The path to the registry config file. Defaults to `HELM_REGISTRY_CONFIG` env if it is set, otherwise uses the default path set by helm. + * repository_config_path - (Optional) The path to the file containing repository names and URLs. Defaults to `HELM_REPOSITORY_CONFIG` env if it is set, otherwise uses the default path set by helm. + * repository_cache - (Optional) The path to the file containing cached repository indexes. Defaults to `HELM_REPOSITORY_CACHE` env if it is set, otherwise uses the default path set by helm. + * helm_driver - (Optional) "The backend storage driver. Valid values are: `configmap`, `secret`, `memory`. Defaults to `secret` +* Adds the following parameters to the release + * repository_key_file - (Optional) The repositories cert key file + * repository_cert_file - (Optional) The repositories cert file + * repository_ca_file - (Optional) The Repositories CA File. + * repository_username - (Optional) Username for HTTP basic authentication against the repository. + * repository_password - (Optional) Password for HTTP basic authentication against the reposotory. + * reset_values - (Optional) When upgrading, reset the values to the ones built into the chart. Defaults to `false`. + * cleanup_on_fail - (Optional) Allow deletion of new resources created in this upgrade when upgrade fails. Defaults to `false`. + * max_history - (Optional) Maximum number of release versions stored per release. Defaults to 0 (no limit). + * atomic - (Optional) If set, installation process purges chart on fail. The wait flag will be set automatically if atomic is used. Defaults to false. + * skip_crds - (Optional) If set, no CRDs will be installed. By default, CRDs are installed if not already present. Defaults to false. + * render_subchart_notes - (Optional) If set, render subchart notes along with the parent. Defaults to true. + * dependency_update - (Optional) Runs helm dependency update before installing the chart. Defaults to false + + +## 0.10.5 (Unreleased) +## 0.10.4 (October 28, 2019) + +BUG FIXES: + +* Tiller installed version should match helm client (#365) + +## 0.10.3 (October 27, 2019) + +IMPROVEMENTS: + +* Upgrade Helm to v2.15.1 and Kubernetes to v1.15.5 +* Migrate to terraform-plugin-sdk +* Allow for colon separated KUBECONFIG (#98) +* Modernise docs + +BUG FIXES: + +* Remove manual installation instructions +* Fix loading kubeconfig when disabled (#307) +* Don't enable TLS if `enable_tls` is false (#245) +* Remove ForceNew on repo and chart changes (#173) + +## 0.10.2 (August 07, 2019) + +BUG FIXES: + +* Revert "Escape commas in set_string" (#310) + +## 0.10.1 (July 30, 2019) + +IMPROVEMENTS: + +* Update helm and tiller to 2.14.1 (#294) +* Wait for tiller if it's not ready (#295) + +## 0.10.0 (June 18, 2019) + +FEATURES: + +* Automatically initialize the configured helm home directory (#185) + +IMPROVEMENTS: + +* Update helm and tiller to 2.14.0 (#277) +* Update terraform to 0.12.1 (#289 #290) + +BUG FIXES: + +* Fix concurrency issues reading multiple repos (#272) +* Documentation fixes (#262 #270 #276) +* helm/resource_release: typo fixes (#282) + +## 0.9.1 (April 24, 2019) + +FEATURES: + +IMPROVEMENTS: + +* Migrate to Terraform 0.12 SDK +* Move to Go modules for dep-management + +BUG FIXES: + +* Properly handle commas in attribute values +* Documentation fixes + +## 0.9.0 (March 07, 2019) +FEATURES: + +* `helm_repository` is now a data source. We retain backwards compatibility through `DataSourceResourceShim` (#221) +* Use configured helm home when reading default TLS settings (#210) +* Added `load_config_file` option to enable or disable the load of kubernetes config file (#231) + +IMPROVEMENTS: + +* CI and doc improvements + +## 0.8.0 (February 11, 2019) + +FEATURES: + +* Added the possibility to set sensitive values (#153) + +IMPROVEMENTS: + +* Multiple README, logs and docs improvements +* Go 1.11 and modules (#179, #200 and #201) +* Default tiller version v2.11.0 (#194) +* Suppress diff of "keyring" and "devel" attributes (#193) +* Add entries to .gitignore to roughly match the Google provider (#206) + +BUG FIXES: + +* Fix when Helm provider ignores FAILED release state (#161) +* Use `127.0.0.1` as default `localhost` (#207) + +## 0.7.0 (December 17, 2018) + +- Based on Helm 2.11 + +## 0.6.2 (October 26, 2018) + +- Bug fix: A recursion between the read and create methods as described in PR #137 + +## 0.6.1 (October 25, 2018) + +- Re-release after induction into 'terraform-providers'. This is to align to the de-facto repository version sequence. + +## 0.1.0 (October 10, 2018) + +- Initial Release by Hashicorp diff --git a/shuttles/terraform/terraform-provider-helm/CHANGELOG_GUIDE.md b/shuttles/terraform/terraform-provider-helm/CHANGELOG_GUIDE.md new file mode 100644 index 0000000..ba78bd8 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/CHANGELOG_GUIDE.md @@ -0,0 +1,111 @@ +# How To Use + +Helm Provider uses `go-changelog` to generate its changelog on release: + +* https://github.com/hashicorp/go-changelog + +To install, run the following commands: + +``` +go install github.com/hashicorp/go-changelog/cmd/changelog-build +go install github.com/hashicorp/go-changelog/cmd/changelog-entry +``` + +Either command can be ran with the following make command: + +``` +make changelog +make changelog-entry +``` + +## CHANGELOG entry examples + +CHANGELOG entries are expected to be txt files created inside this folder +`.changelog`. The file name is expected to be the same pull request number that will +be linked when the CHANGELOG is generated. So for example, if your pull request is +\#1234, your file name would be `.changelog/1234.txt`. + +While for git commit messages, we expect the leading subject to be more specific +as to the section it updates, for example a change with k8s might be: + +``` +builtin/k8s: Add support for feature Y + +This commit adds support for feature Y.... +``` + +The changelog entry should be more user facing friendly, so it would instead read: + +~~~ +```release-note:improvement +plugin/k8s: Add support for feature Y +``` +~~~ + +Below are some examples of how to generate a CHANGELOG entry with your pull +request. + +### Improvement + +~~~ +```release-note:improvement +server: Add new option for configs +``` +~~~ + +### Feature + +~~~ +```release-note:feature +plugin/nomad: New feature integration +``` +~~~ + +### Bug + +~~~ +```release-note:bug +plugin/docker: Fix broken code +``` +~~~ + +### Multiple Entries + +~~~ +```release-note:bug +plugin/docker: Fix broken code +``` + +```release-note:bug +plugin/nomad: Fix broken code +``` + +```release-note:bug +plugin/k8s: Fix broken code +``` +~~~ + +### Long Description with Markdown + +~~~ +```release-note:feature +cli: Lorem ipsum dolor `sit amet`, _consectetur_ adipiscing elit, **sed** do +eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim +veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo +consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse +cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non +proident, sunt in culpa qui officia deserunt mollit anim id est laborum. +``` +~~~ + +## How to generate CHANGELOG entries for release + +Below is an example for running `go-changelog` to generate a collection of +entries. It will generate output that can be inserted into CHANGELOG.md. + +For more information as to what each flag does, make sure to run `changelog-build -help`. + +``` +changelog-build -last-release v0.5.0 -entries-dir .changelog/ -changelog-template changelog.tmpl -note-template note.tmpl -this-release 86b6b38faa7c69f26f1d4c71e271cd4285daadf9 +``` + diff --git a/shuttles/terraform/terraform-provider-helm/GNUmakefile b/shuttles/terraform/terraform-provider-helm/GNUmakefile new file mode 100644 index 0000000..ec8cf76 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/GNUmakefile @@ -0,0 +1,130 @@ +TEST?="./helm" +GOFMT_FILES?=$$(find . -name '*.go' |grep -v vendor) +COVER_TEST?=$$(go list ./... |grep -v 'vendor') +WEBSITE_REPO=github.com/hashicorp/terraform-website +PKG_NAME=helm + +PKG_OS ?= darwin linux +PKG_ARCH ?= amd64 +BASE_PATH ?= $(shell pwd) +BUILD_PATH ?= $(BASE_PATH)/build +PROVIDER := $(shell basename $(BASE_PATH)) +BRANCH := $(shell git rev-parse --abbrev-ref HEAD) +VERSION ?= v0.0.0 +ifneq ($(origin TRAVIS_TAG), undefined) + BRANCH := $(TRAVIS_TAG) + VERSION := $(TRAVIS_TAG) +endif +# For changelog generation, default the last release to the last tag on +# any branch, and this release to just be the current branch we're on. +LAST_RELEASE?=$$(git describe --tags $$(git rev-list --tags --max-count=1)) +THIS_RELEASE?=$$(git rev-parse --abbrev-ref HEAD) + +default: build + +build: fmtcheck + go build -v . + +# expected to be invoked by make changelog LAST_RELEASE=gitref THIS_RELEASE=gitref +changelog: + @echo "Generating changelog for $(THIS_RELEASE) from $(LAST_RELEASE)..." + @echo + @changelog-build -last-release $(LAST_RELEASE) \ + -entries-dir .changelog/ \ + -changelog-template .changelog/changelog.tmpl \ + -note-template .changelog/note.tmpl \ + -this-release $(THIS_RELEASE) + +changelog-entry: + @changelog-entry -dir .changelog/ + + +test: fmtcheck + go test $(TEST) -v || exit 1 + echo $(TEST) | \ + xargs -t -n4 go test $(TESTARGS) -timeout=30s + +testacc: fmtcheck + TF_ACC=1 go test $(TEST) -v $(TESTARGS) -timeout 10m + +testrace: fmtcheck + TF_ACC= go test -race $(TEST) $(TESTARGS) + +cover: + @go tool cover 2>/dev/null; if [ $$? -eq 3 ]; then \ + go get -u golang.org/x/tools/cmd/cover; \ + fi + go test $(COVER_TEST) -coverprofile=coverage.out + go tool cover -html=coverage.out + rm coverage.out + +vet: + @echo "go vet ." + @go vet $$(go list ./... | grep -v vendor/) ; if [ $$? -eq 1 ]; then \ + echo ""; \ + echo "Vet found suspicious constructs. Please check the reported constructs"; \ + echo "and fix them if necessary before submitting the code for review."; \ + exit 1; \ + fi + +fmt: + gofmt -w $(GOFMT_FILES) + +fmtcheck: + @sh -c "'$(CURDIR)/scripts/gofmtcheck.sh'" + +errcheck: + @sh -c "'$(CURDIR)/scripts/errcheck.sh'" + +test-compile: fmtcheck + @if [ "$(TEST)" = "./..." ]; then \ + echo "ERROR: Set TEST to a specific package. For example,"; \ + echo " make test-compile TEST=./helm"; \ + exit 1; \ + fi + go test -c $(TEST) $(TESTARGS) + +packages: + @for os in $(PKG_OS); do \ + for arch in $(PKG_ARCH); do \ + mkdir -p $(BUILD_PATH)/$(PROVIDER)_$${os}_$${arch} && \ + cd $(BASE_PATH) && \ + CGO_ENABLED=0 GOOS=$${os} GOARCH=$${arch} go build -o $(BUILD_PATH)/$(PROVIDER)_$${os}_$${arch}/$(PROVIDER)_$(VERSION) . && \ + cd $(BUILD_PATH) && \ + tar -cvzf $(BUILD_PATH)/$(PROVIDER)_$(BRANCH)_$${os}_$${arch}.tar.gz $(PROVIDER)_$${os}_$${arch}/; \ + done; \ + done; + +clean: + @rm -rf $(BUILD_PATH) + +# The docker command and run options may be overridden using env variables DOCKER and DOCKER_RUN_OPTS. +# Example: +# DOCKER="podman --cgroup-manager=cgroupfs" make website-lint +# DOCKER_RUN_OPTS="--userns=keep-id" make website-lint +# This option is needed for systems using SELinux and rootless containers. +# DOCKER_VOLUME_OPTS="rw,Z" +# For more info, see https://docs.docker.com/storage/bind-mounts/#configure-the-selinux-label +DOCKER?=$(shell which docker) +ifeq ($(strip $(DOCKER)),) +$(error "Docker binary could not be found in PATH. Please install docker, or specify an alternative by setting DOCKER=/path/to/binary") +endif +DOCKER_VOLUME_OPTS?="rw" +DOCKER_SELINUX := $(shell which setenforce) +ifeq ($(.SHELLSTATUS),0) +DOCKER_VOLUME_OPTS="rw,Z" +endif +# PROVIDER_DIR_DOCKER is used instead of PWD since docker volume commands can be dangerous to run in $HOME. +# This ensures docker volumes are mounted from within provider directory instead. +PROVIDER_DIR_DOCKER := $(abspath $(lastword $(dir $(MAKEFILE_LIST)))) + +website-lint: + @echo "==> Checking website against linters..." + @echo "==> Running markdownlint-cli using DOCKER='$(DOCKER)', DOCKER_RUN_OPTS='$(DOCKER_RUN_OPTS)' and DOCKER_VOLUME_OPTS='$(DOCKER_VOLUME_OPTS)'" + @$(DOCKER) run --rm $(DOCKER_RUN_OPTS) -v $(PROVIDER_DIR_DOCKER):/workspace:$(DOCKER_VOLUME_OPTS) -w /workspace 06kellyjac/markdownlint-cli ./docs \ + && (echo; echo "PASS - website markdown files pass linting"; echo ) \ + || (echo; echo "FAIL - issues found in website markdown files"; echo ; exit 1) + @echo "==> Checking for broken links..." + @scripts/markdown-link-check.sh "$(DOCKER)" "$(DOCKER_RUN_OPTS)" "$(DOCKER_VOLUME_OPTS)" "$(PROVIDER_DIR_DOCKER)" + +.PHONY: build test testacc testrace cover vet fmt fmtcheck errcheck test-compile packages clean website-lint changelog changelog-entry diff --git a/shuttles/terraform/terraform-provider-helm/LICENSE b/shuttles/terraform/terraform-provider-helm/LICENSE new file mode 100644 index 0000000..b9ac071 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/LICENSE @@ -0,0 +1,375 @@ +Copyright (c) 2017 HashiCorp, Inc. + +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/shuttles/terraform/terraform-provider-helm/META.d/_summary.yaml b/shuttles/terraform/terraform-provider-helm/META.d/_summary.yaml new file mode 100644 index 0000000..080c718 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/META.d/_summary.yaml @@ -0,0 +1,15 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +--- + +schema: 1.1 + +partition: tf-ecosystem + +summary: + owner: team-tf-hybrid-cloud + description: | + This Helm provider for Terraform allows you to install and manage Helm Charts in your Kubernetes cluster using Terraform. + + visibility: external \ No newline at end of file diff --git a/shuttles/terraform/terraform-provider-helm/META.d/links.yaml b/shuttles/terraform/terraform-provider-helm/META.d/links.yaml new file mode 100644 index 0000000..efd49fc --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/META.d/links.yaml @@ -0,0 +1,10 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +runbooks: [] +#- name: +# link: + +other_links: [] +#- name: +# link: \ No newline at end of file diff --git a/shuttles/terraform/terraform-provider-helm/README.md b/shuttles/terraform/terraform-provider-helm/README.md new file mode 100644 index 0000000..a34fe6b --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/README.md @@ -0,0 +1,60 @@ + + Terraform logo + + +# Helm Provider for Terraform [![Actions Status](https://github.com/hashicorp/terraform-provider-helm/workflows/tests/badge.svg)](https://github.com/hashicorp/terraform-provider-helm/actions)[![GitHub tag (latest SemVer)](https://img.shields.io/github/v/tag/hashicorp/terraform-provider-helm?label=release)](https://github.com/hashicorp/terraform-provider-helm/releases)[![license](https://img.shields.io/github/license/hashicorp/terraform-provider-helm.svg)]()[![Go Report Card](https://goreportcard.com/badge/github.com/hashicorp/terraform-provider-helm)](https://goreportcard.com/report/github.com/hashicorp/terraform-provider-helm) + + +- [Documentation](https://www.terraform.io/docs/providers/helm/index.html) +- [#terraform-providers in Kubernetes Slack](https://kubernetes.slack.com/messages/CJY6ATQH4) ([Sign up here](http://slack.k8s.io/)) + +This is the [Helm](https://github.com/kubernetes/helm) provider for [Terraform](https://www.terraform.io/). + +This provider allows you to install and manage [Helm Charts](https://artifacthub.io/packages/search?kind=0&sort=relevance&page=1) in your Kubernetes cluster using Terraform. + + +## Contents + +* [Requirements](#requirements) +* [Getting Started](#getting-started) +* [Contributing to the provider](#contributing) + +## Requirements + +- [Terraform](https://www.terraform.io/downloads.html) v1.x.x +- [Go](https://golang.org/doc/install) v1.22.x (to build the provider plugin) + +## Getting Started + +This is a small example of how to install the nginx ingress controller chart. Please read the [documentation](https://www.terraform.io/docs/providers/helm/index.html) for more +information. + +```hcl +provider "helm" { + kubernetes = { + config_path = "~/.kube/config" + } +} + +resource "helm_release" "nginx_ingress" { + name = "nginx-ingress-controller" + + repository = "oci://registry-1.docker.io/bitnamicharts" + chart = "nginx-ingress-controller" + + set = [ + { + name = "service.type" + value = "ClusterIP" + } + ] +} +``` + +## Contributing + +The Helm Provider for Terraform is the work of many contributors. We appreciate your help! + +To contribute, please read the [contribution guidelines](_about/CONTRIBUTING.md). You may also [report an issue](https://github.com/hashicorp/terraform-provider-helm/issues/new/choose). Once you've filed an issue, it will follow the [issue lifecycle](_about/ISSUES.md). + +Also available are some answers to [Frequently Asked Questions](_about/FAQ.md). diff --git a/shuttles/terraform/terraform-provider-helm/_about/CONTRIBUTING.md b/shuttles/terraform/terraform-provider-helm/_about/CONTRIBUTING.md new file mode 100644 index 0000000..40d1dfe --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/_about/CONTRIBUTING.md @@ -0,0 +1,37 @@ +Developing the Provider +------------ + +Thank you for your interest in contributing to the Helm provider. We welcome your contributions. Here you'll find information to help you get started with provider development. + +## Documentation + +Our [provider development documentation](https://www.terraform.io/docs/extend/) provides a good start into developing an understanding of provider development. It's the best entry point if you are new to contributing to this provider. + +To learn more about how to create issues and pull requests in this repository, and what happens after they are created, you may refer to the resources below: +- [Issue creation and lifecycle](ISSUES.md) +- [Pull Request creation and lifecycle](PULL_REQUESTS.md) + +### Installation from sources + +If you wish to compile the provider from source code, you'll first need [Go](http://www.golang.org) installed on your machine (version >=1.14 is *required*). You'll also need to correctly setup a [GOPATH](http://golang.org/doc/code.html#GOPATH), as well as adding `$GOPATH/bin` to your `$PATH`. + +Clone repository to: `$GOPATH/src/github.com/hashicorp/terraform-provider-helm` + +```sh +> mkdir -p $GOPATH/src/github.com/terraform-providers +> git clone https://github.com/hashicorp/terraform-provider-helm.git $GOPATH/src/github.com/hashicorp/terraform-provider-helm +``` + +Enter the provider directory and build the provider + +```sh +> cd $GOPATH/src/github.com/hashicorp/terraform-provider-helm +> make build +``` + +Now copy the compiled binary to the Terraform plugins folder. If this is your first plugin it may not be present. + +```sh +> mkdir -p ~/.terraform.d/plugins/ +> mv terraform-provider-helm ~/.terraform.d/plugins/ +``` diff --git a/shuttles/terraform/terraform-provider-helm/_about/FAQ.md b/shuttles/terraform/terraform-provider-helm/_about/FAQ.md new file mode 100644 index 0000000..99c758b --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/_about/FAQ.md @@ -0,0 +1,45 @@ +# Frequently Asked Questions + +### Who are the maintainers? + +The HashiCorp Terraform Kubernetes provider team is : + +* Vishnu Ravindra, Product Manager - [@vravind1](https://github.com/vravind1) +* Alex Somesan, Engineer - [@alexsomesan](https://github.com/alexsomesan) +* John Houston, Engineer - [@jrhouston](https://github.com/jrhouston) +* Sacha Rybolovlev, Engineer - [@arybolovlev](https://github.com/arybolovlev) +* Mauricio Alvarez Leon, Engineer - [@BBBmau](https://github.com/BBBmau) +* Sheneska Williams, Engineer - [@sheneska](https://github.com/sheneska) +* Brandy Jackson, Engineering Manager - [@ibrandyjackson](https://github.com/ibrandyjackson) + +Our collaborators are: +* Maximo Cuadros - [@mcuadros](https://github.com/mcuadros) + +### Why isn’t my PR merged yet? + +Unfortunately, due to the volume of issues and new pull requests we receive, we are unable to give each one the full attention that we would like. We do our best to focus on the contributions that provide the greatest value to the most community members. + +### How do you decide what gets merged for each release? + +The number one factor we look at when deciding what issues to look at are your 👍 [reactions](https://blog.github.com/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/) to the original issue/PR description as these can be easily discovered. Comments that further explain desired use cases or poor user experience are also heavily factored. The items with the most support are always on our radar, and we do our best to keep the community updated on their status and potential timelines. + +We also are investing time to improve the contributing experience by improving documentation. + + +### Backward Compatibility Promise + +Our policy is described on the Terraform website [here](https://www.terraform.io/docs/extend/best-practices/versioning.html). While we do our best to prevent breaking changes until major version releases of the provider, it is generally recommended to [pin the provider version in your configuration](https://www.terraform.io/docs/configuration/providers.html#provider-versions). + +Due to the constant release pace of Kubernetes and the relatively infrequent major version releases of the provider, there can be cases where a minor version update may contain unexpected changes depending on your configuration or environment. + +### Where is the result of NOTES.txt? + +Helm charts often contain NOTES.txt output that provide helpful next steps and occasionally provide debug information on missing environment variables etc. At present, this provider will not output or log the result of NOTES.txt on any installed charts. Temporarily install the chart via helm directly to see the output of NOTES.txt + +### How can I help? + +Check out the [Contributing Guide](CONTRIBUTING.md) for additional information. + +### How can I become a maintainer? + +This is an area under active research. Stay tuned! diff --git a/shuttles/terraform/terraform-provider-helm/_about/ISSUES.md b/shuttles/terraform/terraform-provider-helm/_about/ISSUES.md new file mode 100644 index 0000000..f5ec444 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/_about/ISSUES.md @@ -0,0 +1,56 @@ +# Issue Reporting and Lifecycle + +## Issue Reporting Checklists + +We welcome your feature requests and bug reports. Below you'll find short checklists with guidelines for well-formed +issues of each type. + +### [Bug Reports](https://github.com/hashicorp/terraform-provider-helm/issues/new/choose) + + - [ ] __Test against the latest release__: Make sure you test against the latest + released version. It is possible we already fixed the bug you're experiencing. + + - [ ] __Search for possible duplicate reports__: It's helpful to keep bug + reports consolidated to one thread, so do a quick search on existing bug + reports to check if anybody else has reported the same thing. You can [scope + searches by the label "bug"](https://github.com/hashicorp/terraform-provider-helm/issues?q=is%3Aopen+is%3Aissue+label%3Abug) to help narrow things down. + + - [ ] __Include steps to reproduce__: Provide steps to reproduce the issue, + along with your `.tf` files, with secrets removed, so we can try to + reproduce it. Without this, it makes it much harder to fix the issue. + + - [ ] __For panics, include `crash.log`__: If you experienced a panic, please + create a [gist](https://gist.github.com) of the *entire* generated crash log + for us to look at. Double check no sensitive items were in the log. + +### [Feature Requests](https://github.com/hashicorp/terraform-provider-helm/issues/new/choose) + + - [ ] __Search for possible duplicate requests__: It's helpful to keep requests + consolidated to one thread, so do a quick search on existing requests to + check if anybody else has reported the same thing. You can [scope searches by + the label "enhancement"](https://github.com/hashicorp/terraform-provider-helm/issues?q=is%3Aopen+is%3Aissue+label%3Aenhancement) to help narrow things down. + + - [ ] __Include a use case description__: In addition to describing the + behavior of the feature you'd like to see added, it's helpful to also lay + out the reason why the feature would be important and how it would benefit + Terraform users. + + +## Issue Lifecycle + +1. The issue is reported on Github. + +2. The issue is verified and categorized by a Terraform collaborator. + Categorization is done via GitHub labels. We use + one of `bug`, `enhancement`, `documentation`, or `question` using some automated workflows. + +3. An initial triage process determines whether the issue is critical and must + be addressed immediately, or can be left open for community discussion. In this step, we typically assign a size estimate to the work involved for that issue for our reference. We'll label the issue `acknowledged` when we've run through this step. + +4. The issue queued in our backlog to be addressed in a pull request or commit. The issue number will be + referenced in the commit message so that the code that fixes it is clearly + linked. + +5. The issue is closed. Sometimes, valid issues will be closed because they are + tracked elsewhere or non-actionable. The issue is still indexed and + available for future viewers, or can be re-opened if necessary. diff --git a/shuttles/terraform/terraform-provider-helm/_about/PULL_REQUESTS.md b/shuttles/terraform/terraform-provider-helm/_about/PULL_REQUESTS.md new file mode 100644 index 0000000..94a3cb7 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/_about/PULL_REQUESTS.md @@ -0,0 +1,46 @@ +# Pull Request Submission and Lifecycle + +We appreciate direct contributions to the provider codebase. Here's what to +expect: + + * For pull requests that follow the guidelines, we will proceed to reviewing + and merging, following the provider team's review schedule. There may be some + internal or community discussion needed before we can complete this. + * Pull requests that don't follow the guidelines will be commented with what + they're missing. The person who submits the pull request or another community + member will need to address those requests before they move forward. + +## Pull Request Lifecycle + +1. [Fork the GitHub repository](https://help.github.com/en/articles/fork-a-repo), + modify the code, and [create a pull request](https://help.github.com/en/articles/creating-a-pull-request-from-a-fork). + You are welcome to submit your pull request for commentary or review before + it is fully completed by creating a [draft pull request](https://help.github.com/en/articles/about-pull-requests#draft-pull-requests). + Please include specific questions or items you'd like feedback on. + +1. Our documentation utilizes the [`tfplugindocs`](https://github.com/hashicorp/terraform-plugin-docs) tool. When making updates to documentation, please only edit the `.md.tmpl` files and execute the `tfplugindocs generate` command to ensure the changes are reflected in the `.md` files. + +1. Once you believe your pull request is ready to be reviewed, ensure the + pull request is not a draft pull request by [marking it ready for review](https://help.github.com/en/articles/changing-the-stage-of-a-pull-request) and a + maintainer will review it. + +1. One of Terraform's provider team members will look over your contribution and + either approve it or provide comments letting you know if there is anything + left to do. We do our best to keep up with the volume of PRs waiting for + review, but it will take some time for us to reach your PR based on the tasks we have in our backlog. Please do not leave LGTM comments or approvals on PRs unless you are a maintainer on the repository. + +1. Once all outstanding comments and checklist items have been addressed, your + contribution will be merged! Merged PRs will be included in the next + Terraform release. The provider team takes care of updating the CHANGELOG as + they merge. + +1. In some cases, we might decide that a PR should be closed without merging. + We'll make sure to provide clear reasoning when this happens. + + +### Go Coding Style + +The following Go language resources provide common coding preferences that may be referenced during review, if not automatically handled by the project's linting tools. + +- [Effective Go](https://golang.org/doc/effective_go.html) +- [Go Code Review Comments](https://github.com/golang/go/wiki/CodeReviewComments) diff --git a/shuttles/terraform/terraform-provider-helm/docs/data-sources/template.md b/shuttles/terraform/terraform-provider-helm/docs/data-sources/template.md new file mode 100644 index 0000000..8bdd71e --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/docs/data-sources/template.md @@ -0,0 +1,232 @@ +--- +page_title: "helm: helm_template" +sidebar_current: "docs-helm-template" +description: |- + +--- +# Data Source: helm_template + +Render chart templates locally. + +`helm_template` renders chart templates locally and exposes the rendered manifests in the data source attributes. `helm_template` mimics the functionality of the `helm template` command. + +The arguments aim to be identical to the `helm_release` resource. + +For further details on the `helm template` command, refer to the [Helm documentation](https://helm.sh/docs/helm/helm_template/). + + +## Schema + +### Required + +- `chart` (String) Chart name to be installed. A path may be used. +- `name` (String) Release name. + +### Optional + +- `api_versions` (List of String) Kubernetes api versions used for Capabilities.APIVersions +- `atomic` (Boolean) If set, installation process purges chart on fail. The wait flag will be set automatically if atomic is used. Defaults to `false`. +- `crds` (List of String) List of rendered CRDs from the chart. +- `create_namespace` (Boolean) Create the namespace if it does not exist. Defaults to `false`. +- `dependency_update` (Boolean) Run helm dependency update before installing the chart. Defaults to `false`. +- `description` (String) Add a custom description +- `devel` (Boolean) Use chart development versions, too. Equivalent to version '>0.0.0-0'. If `version` is set, this is ignored +- `disable_openapi_validation` (Boolean) If set, the installation process will not validate rendered templates against the Kubernetes OpenAPI Schema.Defaults to `false`. +- `disable_webhooks` (Boolean) Prevent hooks from running.Defaults to `300` seconds. +- `include_crds` (Boolean) Include CRDs in the templated output +- `is_upgrade` (Boolean) Set .Release.IsUpgrade instead of .Release.IsInstall +- `keyring` (String) Location of public keys used for verification. Used only if `verify` is true. Defaults to `/.gnupg/pubring.gpg` in the location set by `home`. +- `kube_version` (String) Kubernetes version used for Capabilities.KubeVersion +- `manifest` (String) Concatenated rendered chart templates. This corresponds to the output of the `helm template` command. +- `manifests` (Map of String) Map of rendered chart templates indexed by the template name. +- `namespace` (String) Namespace to install the release into. Defaults to `default`. +- `notes` (String) Rendered notes if the chart contains a `NOTES.txt`. +- `pass_credentials` (Boolean) Pass credentials to all domains. Defaults to `false`. +- `postrender` (Block List, Max: 1) Postrender command configuration. (see [below for nested schema](#nestedblock--postrender)) +- `render_subchart_notes` (Boolean) If set, render subchart notes along with the parent. Defaults to `true`. +- `replace` (Boolean) Re-use the given name, even if that name is already used. This is unsafe in production. Defaults to `false`. +- `repository` (String) Repository where to locate the requested chart. If is a URL the chart is installed without installing the repository. +- `repository_ca_file` (String) The Repositories CA File +- `repository_cert_file` (String) The repositories cert file +- `repository_key_file` (String) The repositories cert key file +- `repository_password` (String, Sensitive) Password for HTTP basic authentication +- `repository_username` (String) Username for HTTP basic authentication +- `reset_values` (Boolean) When upgrading, reset the values to the ones built into the chart.Defaults to `false`. +- `reuse_values` (Boolean) When upgrading, reuse the last release's values and merge in any overrides. If 'reset_values' is specified, this is ignored. Defaults to `false`. +- `set` (Block Set) Custom values to be merged with the values. (see [below for nested schema](#nestedblock--set)) +- `set_list` (Block List) Custom list values to be merged with the values. (see [below for nested schema](#nestedblock--set_list)) +- `set_sensitive` (Block Set) Custom sensitive values to be merged with the values. (see [below for nested schema](#nestedblock--set_sensitive)) +- `set_string` (Block Set, Deprecated) Custom string values to be merged with the values. (see [below for nested schema](#nestedblock--set_string)) +- `show_only` (List of String) Only show manifests rendered from the given templates +- `skip_crds` (Boolean) If set, no CRDs will be installed. By default, CRDs are installed if not already present. Defaults to `false`. +- `skip_tests` (Boolean) If set, tests will not be rendered. By default, tests are rendered. Defaults to `false`. +- `timeout` (Number) Time in seconds to wait for any individual kubernetes operation. Defaults to `300` seconds. +- `validate` (Boolean) Validate your manifests against the Kubernetes cluster you are currently pointing at. This is the same validation performed on an install +- `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. +- `wait` (Boolean) Will wait until all resources are in a ready state before marking the release as successful.Defaults to `true`. + +### Read-Only + +- `id` (String) The ID of this resource. + + +### Nested Schema for `postrender` + +Required: + +- `binary_path` (String) The command binary path. + + + +### Nested Schema for `set` + +Required: + +- `name` (String) + +Optional: + +- `type` (String) +- `value` (String) + + + +### Nested Schema for `set_list` + +Required: + +- `name` (String) +- `value` (List of String) + + + +### Nested Schema for `set_sensitive` + +Required: + +- `name` (String) +- `value` (String, Sensitive) + +Optional: + +- `type` (String) + + + +### Nested Schema for `set_string` + +Required: + +- `name` (String) +- `value` (String) + + + + +## Example Usage + +### Render all chart templates + +The following example renders all templates of the `mariadb` chart of the official Helm stable repository. Concatenated manifests are exposed as output variable `mariadb_instance_manifest`. + +```terraform +data "helm_template" "mariadb_instance" { + name = "mariadb-instance" + namespace = "default" + repository = "https://charts.helm.sh/stable" + + chart = "mariadb" + version = "7.1.0" + + set = [ + { + name = "service.port" + value = "13306" + } + ] + + set_sensitive = [ + { + name = "rootUser.password" + value = "s3cr3t!" + } + ] +} + + +resource "local_file" "mariadb_manifests" { + for_each = data.helm_template.mariadb_instance.manifests + + filename = "./${each.key}" + content = each.value +} + +output "mariadb_instance_manifest" { + value = data.helm_template.mariadb_instance.manifest +} + +output "mariadb_instance_manifests" { + value = data.helm_template.mariadb_instance.manifests +} + +output "mariadb_instance_notes" { + value = data.helm_template.mariadb_instance.notes +} +``` + +### Render selected chart templates + +The following example renders only the templates `master-statefulset.yaml` and `master-svc.yaml` of the `mariadb` chart of the official Helm stable repository. + +```terraform +data "helm_template" "mariadb_instance" { + name = "mariadb-instance" + namespace = "default" + repository = "https://charts.helm.sh/stable" + + chart = "mariadb" + version = "7.1.0" + + show_only = [ + "templates/master-statefulset.yaml", + "templates/master-svc.yaml", + ] + + set = [ + { + name = "service.port" + value = "13306" + } + ] + + set_sensitive = [ + { + name = "rootUser.password" + value = "s3cr3t!" + } + ] +} + + +resource "local_file" "mariadb_manifests" { + for_each = data.helm_template.mariadb_instance.manifests + + filename = "./${each.key}" + content = each.value +} + +output "mariadb_instance_manifest" { + value = data.helm_template.mariadb_instance.manifest +} + +output "mariadb_instance_manifests" { + value = data.helm_template.mariadb_instance.manifests +} + +output "mariadb_instance_notes" { + value = data.helm_template.mariadb_instance.notes +} +``` + diff --git a/shuttles/terraform/terraform-provider-helm/docs/guides/v2-upgrade-guide.md b/shuttles/terraform/terraform-provider-helm/docs/guides/v2-upgrade-guide.md new file mode 100644 index 0000000..2065c02 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/docs/guides/v2-upgrade-guide.md @@ -0,0 +1,72 @@ +--- +layout: "helm" +page_title: "Helm: Upgrade Guide for Helm Provider v2.0.0" +description: |- + This guide covers the changes introduced in v2.0.0 of the Helm provider and what you may need to do to upgrade your configuration. +--- + +# Upgrading to v2.0.0 of the Helm provider + +This guide covers the changes introduced in v2.0.0 of the Helm provider and what you may need to do to upgrade your configuration. + +## Changes in v2.0.0 + +### Changes to Kubernetes credentials supplied in the provider block + +We have made several changes to the way access to Kubernetes is configured in the provider block. + +1. The `load_config_file` attribute has been removed. +2. Support for the `KUBECONFIG` environment variable has been dropped and replaced with `KUBE_CONFIG_PATH`. +3. The `config_path` attribute will no longer default to `~/.kube/config` and must be set explicitly. + +The above changes have been made to encourage the best practise of configuring access to Kubernetes in the provider block explicitly, instead of relying upon default paths or `KUBECONFIG` being set. We have done this because allowing the provider to configure its access to Kubernetes implicitly caused confusion with a subset of our users. It also created risk for users who use Terraform to manage multiple clusters. Requiring explicit configuring for kubernetes in the provider block eliminates the possibility that the configuration will be applied to the wrong cluster. + +You will therefore need to explicity configure access to your Kubernetes cluster in the provider block going forward. For many users this will simply mean specifying the `config_path` attribute in the provider block. Users already explicitly configuring the provider should not be affected by this change, but will need to remove the `load_config_file` attribute if they are currently using it. + +When running Terraform inside a Kubernetes cluster no provider configuration is neccessary, as the provider will detect that is has access to a service account token. + +### Removal of the `helm_repository` data source + +This feature of the provider caused a fair bit of confusion and was a source of instability as data sources are not supposed to be stateful. This data source performed a stateful operation that modified the filesystem, mirroring similar functionality to the `helm repo add` command. It has been the recommendation for some time to configure repository information explicity at the `helm_resource` level and so the data source has been removed. See the example below. + +```hcl +resource "helm_release" "redis" { + name = "redis" + + repository = "https://charts.bitnami.com/bitnami" + chart = "redis" +} +``` + +The provider will continue to work with repositories that are configured with `helm repo add` before Terraform is run. + +### Removal of `set_string` in the `helm_release` resource + +The addition of a `type` attribute to the `set` block has rendered `set_string` superfluous so it has been removed. See the example below on how to set a string using the `set` block. This is used when the type of a value is an ambigious (e.g strings containing only numbers, true, false) and we want it to be explicitly parsed as a string. + +```hcl +resource "helm_release" "redis" { + name = "redis" + + repository = "https://charts.bitnami.com/bitnami" + chart = "redis" + + set { + name = "test.value" + value = "123456" + type = "string" + } +} +``` + +### Dropped support for Terraform 0.11 + +All builds of the Helm provider going forward will no longer work with Terraform 0.11. See [Upgrade Guides](https://www.terraform.io/upgrade-guides/index.html) for how to migrate your configurations to a newer version of Terraform. + +### Upgrade to v2 of the Terraform Plugin SDK + +Contributors to the provider will be interested to know this upgrade has brought the latest version of the [Terraform Plugin SDK](https://github.com/hashicorp/terraform-plugin-sdk) which introduced a number of enhancements to the developer experience. Details of the changes introduced can be found under [Extending Terraform](https://www.terraform.io/docs/extend/guides/v2-upgrade-guide.html). + +## Helm 2 + +We removed support in the provider for Helm 2 earlier this year. In accordance with the [Helm v2 deprecation timeline](https://helm.sh/blog/helm-v2-deprecation-timeline/) we will no longer be accepting PRs or handling issues that relate to Helm 2 going forward. diff --git a/shuttles/terraform/terraform-provider-helm/docs/guides/v3-upgrade-guide.md b/shuttles/terraform/terraform-provider-helm/docs/guides/v3-upgrade-guide.md new file mode 100644 index 0000000..0037051 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/docs/guides/v3-upgrade-guide.md @@ -0,0 +1,246 @@ +--- +layout: "helm" +page_title: "Helm: Upgrade Guide for Helm Provider v3.0.0" +description: |- + This guide covers the changes introduced in v3.0.0 of the Helm provider and what you may need to do to upgrade your configuration. +--- + +# Upgrading to v3.0.0 of the Helm provider + + +This guide covers the changes introduced in v3.0.0 of the Helm provider and what you may need to do to upgrade your configuration. + +## Changes in v3.0.0 + +### Adoption of the Terraform Plugin Framework + +The Helm provider has been migrated from the legacy [Terraform Plugin SDKv2](https://github.com/hashicorp/terraform-plugin-sdk) to the [Terraform Plugin Framework](https://github.com/hashicorp/terraform-plugin-framework). This migration introduces structural changes to the schema, affecting nested blocks, attribute names, and how configurations are represented. Users must update their configurations to align with the new framework. Key changes include: + +- **Blocks to Nested Objects**: Blocks like `kubernetes`, `registry`, and `experiments` are now represented as nested objects. +- **List Syntax for Nested Attributes**: Attributes like `set`, `set_list`, and `set_sensitive` in `helm_release` and `helm_template` are now lists of nested objects instead of blocks. + +### Terraform Version Compatability + +The new framework code uses [Terraform Plugin Protocol Version 6](https://developer.hashicorp.com/terraform/plugin/terraform-plugin-protocol#protocol-version-6) which is compatible with Terraform versions 1.0 and aboove. Users of earlier versions of Terraform can continue to use the Helm provider by pinning their configuration to the 2.x version. + +--- + +### Changes to Provider Attributes + +#### Kubernetes Configuration (`kubernetes`) + +The `kubernetes` block has been updated to a single nested object. + +**Old SDKv2 Configuration:** + +```hcl +provider "helm" { + kubernetes { + config_path = "~/.kube/config" + } + + registry { + url = "oci://localhost:5000" + username = "username" + password = "password" + } + + registry { + url = "oci://private.registry" + username = "username" + password = "password" + } +} +``` + +**New Plugin Framework Configuration:** + +```hcl +provider "helm" { + kubernetes = { + config_path = "~/.kube/config" + } + + registries = [ + { + url = "oci://localhost:5000" + username = "username" + password = "password" + }, + { + url = "oci://private.registry" + username = "username" + password = "password" + } + ] +} +``` + +**What Changed?** + +- `kubernetes` is now a single nested object attribute using `{ ... }`. +- `registry` blocks have been replaced by a `registries` list attribute. + +#### Experiments Configuration (experiments) + +The `experiments` block has been updated to a list of nested objects. + +**Old SDKv2 Configuration:** + +```hcl +provider "helm" { + experiments { + manifest = true + } +} +``` + +**New Plugin Framework Configuration:** + +```hcl +provider "helm" { + experiments = { + manifest = true + } +} +``` + +**What Changed?** + +- `experiments` is now a single nested object attribute using `{ ... }`. + +### Changes to helm_release Resource + +#### `set`, `set_list`, and `set_sensitive` Configuration + +Attributes `set`, `set_list`, and `set_sensitive` are now represented as lists of nested objects instead of individual blocks. + +**Old SDKv2 Configuration:** + +```hcl +resource "helm_release" "nginx_ingress" { + name = "nginx-ingress-controller" + + repository = "https://charts.bitnami.com/bitnami" + chart = "nginx-ingress-controller" + + set { + name = "service.type" + value = "ClusterIP" + } + + set_list { + name = "allowed.hosts" + value = ["host1", "host2"] + } + + set_sensitive { + name = "api.key" + value = "super-secret-key" + } +} +``` + +**New Plugin Framework Configuration:** + +```hcl +resource "helm_release" "nginx_ingress" { + name = "nginx-ingress-controller" + + repository = "https://charts.bitnami.com/bitnami" + chart = "nginx-ingress-controller" + + set = [ + { + name = "service.type" + value = "ClusterIP" + } + ] + + set_list = [ + { + name = "allowed.hosts" + value = ["host1", "host2"] + } + ] + + set_sensitive = [ + { + name = "api.key" + value = "super-secret-key" + } + ] +} +``` + +**What Changed?** + +- `set`, `set_list`, and `set_sensitive` is now a list of nested objects using `[ { ... } ]`. + +### Changes to helm_template Data Source + +#### `set`, `set_list`, and `set_sensitive` Configuration + +Attributes `set`, `set_list`, and `set_sensitive` are now represented as lists of nested objects instead of individual blocks. + +**Old SDKv2 Configuration:** + +```hcl +data "helm_template" "example" { + name = "my-release" + chart = "my-chart" + namespace = "my-namespace" + values = ["custom-values.yaml"] + + set { + name = "image.tag" + value = "1.2.3" + } + + set_list { + name = "allowed.hosts" + value = ["host1", "host2"] + } + + set_sensitive { + name = "api.key" + value = "super-secret-key" + } +} +``` + +**New Plugin Framework Configuration:** + +```hcl +data "helm_template" "example" { + name = "my-release" + chart = "my-chart" + namespace = "my-namespace" + values = ["custom-values.yaml"] + + set = [ + { + name = "image.tag" + value = "1.2.3" + } + ] + + set_list = [ + { + name = "allowed.hosts" + value = ["host1", "host2"] + } + ] + + set_sensitive = [ + { + name = "api.key" + value = "super-secret-key" + } + ] +} +``` + +**What Changed?** + +- `set`, `set_list`, and `set_sensitive` is now a list of nested objects using `[ { ... } ]`. diff --git a/shuttles/terraform/terraform-provider-helm/docs/index.md b/shuttles/terraform/terraform-provider-helm/docs/index.md new file mode 100644 index 0000000..8f094cb --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/docs/index.md @@ -0,0 +1,212 @@ +--- +page_title: "Provider: Helm" +sidebar_current: "docs-helm-index" +description: |- + The Helm provider is used to deploy software packages in Kubernetes. The provider needs to be configured with the proper credentials before it can be used. +--- + +# Helm Provider + +The Helm provider is used to deploy software packages in Kubernetes. The provider needs to be configured with the proper credentials before it can be used. + +Try the [hands-on tutorial](https://learn.hashicorp.com/tutorials/terraform/helm-provider?in=terraform/kubernetes) on the Helm provider on the HashiCorp Learn site. + +## Resources + +* [Resource: helm_release](r/release.md) + +## Data Sources + +* [Data Source: helm_template](d/template.html) + +## Example Usage + +```terraform +provider "helm" { + kubernetes = { + config_path = "~/.kube/config" + } + + registries = [ + { + url = "oci://localhost:5000" + username = "username" + password = "password" + }, + { + url = "oci://private.registry" + username = "username" + password = "password" + } + ] +} + +resource "helm_release" "nginx_ingress" { + name = "nginx-ingress-controller" + repository = "https://charts.bitnami.com/bitnami" + chart = "nginx-ingress-controller" + + set = [ + { + name = "service.type" + value = "ClusterIP" + } + ] +} +``` + +## Requirements + +~> NOTE: The provider does not use the `KUBECONFIG` environment variable by default. See the attribute reference below for the environment variables that map to provider block attributes. + +- You must have a Kubernetes cluster available. We support version 1.14.0 or higher. + +## Authentication + +The Helm provider can get its configuration in two ways: + +1. *Explicitly* by supplying attributes to the provider block. This includes: + * [Using a kubeconfig file](#file-config) + * [Supplying credentials](#credentials-config) + * [Exec plugins](#exec-plugins) +2. *Implicitly* through environment variables. This includes: + * [Using the in-cluster config](#in-cluster-config) + +For a full list of supported provider authentication arguments and their corresponding environment variables, see the [argument reference](#argument-reference) below. + +### File config + +The easiest way is to supply a path to your kubeconfig file using the `config_path` attribute or using the `KUBE_CONFIG_PATH` environment variable. A kubeconfig file may have multiple contexts. If `config_context` is not specified, the provider will use the `default` context. + +```terraform +provider "helm" { + kubernetes = { + config_path = "~/.kube/config" + } +} +``` + +The provider also supports multiple paths in the same way that kubectl does using the `config_paths` attribute or `KUBE_CONFIG_PATHS` environment variable. + +```terraform +provider "helm" { + kubernetes = { + config_paths = [ + "/path/to/config_a.yaml", + "/path/to/config_b.yaml" + ] + } +} +``` + +### Credentials config + +You can also configure the host, basic auth credentials, and client certificate authentication explicitly or through environment variables. + +```terraform +provider "helm" = { + kubernetes { + host = "https://cluster_endpoint:port" + + client_certificate = file("~/.kube/client-cert.pem") + client_key = file("~/.kube/client-key.pem") + cluster_ca_certificate = file("~/.kube/cluster-ca-cert.pem") + } +} +``` + +### In-cluster Config + +The provider uses the `KUBERNETES_SERVICE_HOST` and `KUBERNETES_SERVICE_PORT` environment variables to detect when it is running inside a cluster, so in this case you do not need to specify any attributes in the provider block if you want to connect to the local kubernetes cluster. + +If you want to connect to a different cluster than the one terraform is running inside, configure the provider as [above](#credentials-config). + +## Exec plugins + +Some cloud providers have short-lived authentication tokens that can expire relatively quickly. To ensure the Kubernetes provider is receiving valid credentials, an exec-based plugin can be used to fetch a new token before initializing the provider. For example, on EKS, the command `eks get-token` can be used: + +```terraform +provider "helm" { + kubernetes = { + host = var.cluster_endpoint + cluster_ca_certificate = base64decode(var.cluster_ca_cert) + exec = { + api_version = "client.authentication.k8s.io/v1beta1" + args = ["eks", "get-token", "--cluster-name", var.cluster_name] + command = "aws" + } + } +} +``` + +For example, to [authenticate with GKE](https://registry.terraform.io/providers/hashicorp/google/latest/docs/guides/using_gke_with_terraform#using-the-kubernetes-and-helm-providers), the `gke-cloud-auth-plugin` can be used: + +```terraform +provider "helm" { + kubernetes = { + host = "https://${data.google_container_cluster.my_cluster.endpoint}" + token = data.google_client_config.provider.access_token + cluster_ca_certificate = base64decode( + data.google_container_cluster.my_cluster.master_auth[0].cluster_ca_certificate,) + exec = { + api_version = "client.authentication.k8s.io/v1beta1" + command = "gke-gcloud-auth-plugin" + } + } +} +``` + +## Argument Reference + +The following arguments are supported: + +* `debug` - (Optional) - Debug indicates whether or not Helm is running in Debug mode. Defaults to `false`. +* `plugins_path` - (Optional) The path to the plugins directory. Defaults to `HELM_PLUGINS` env if it is set, otherwise uses the default path set by helm. +* `registry_config_path` - (Optional) The path to the registry config file. Defaults to `HELM_REGISTRY_CONFIG` env if it is set, otherwise uses the default path set by helm. +* `repository_config_path` - (Optional) The path to the file containing repository names and URLs. Defaults to `HELM_REPOSITORY_CONFIG` env if it is set, otherwise uses the default path set by helm. +* `repository_cache` - (Optional) The path to the file containing cached repository indexes. Defaults to `HELM_REPOSITORY_CACHE` env if it is set, otherwise uses the default path set by helm. +* `helm_driver` - (Optional) "The backend storage driver. Valid values are: `configmap`, `secret`, `memory`, `sql`. Defaults to `secret`. Note: Regarding the sql driver, as of helm v3.2.0 SQL support exists only for the postgres dialect. The connection string can be configured by setting the `HELM_DRIVER_SQL_CONNECTION_STRING` environment variable e.g. `HELM_DRIVER_SQL_CONNECTION_STRING=postgres://username:password@host/dbname` more info [here](https://pkg.go.dev/github.com/lib/pq). +* `burst_limit` - (Optional) The helm burst limit to use. Set this value higher if your cluster has many CRDs. Default: `100` +* `kubernetes` - Kubernetes configuration block. +* `registries` - Private OCI registry configuration block. Can be specified multiple times. + +The `kubernetes` block supports: + +* `config_path` - (Optional) Path to the kube config file. Can be sourced from `KUBE_CONFIG_PATH`. +* `config_paths` - (Optional) A list of paths to the kube config files. Can be sourced from `KUBE_CONFIG_PATHS`. +* `host` - (Optional) The hostname (in form of URI) of the Kubernetes API. Can be sourced from `KUBE_HOST`. +* `username` - (Optional) The username to use for HTTP basic authentication when accessing the Kubernetes API. Can be sourced from `KUBE_USER`. +* `password` - (Optional) The password to use for HTTP basic authentication when accessing the Kubernetes API. Can be sourced from `KUBE_PASSWORD`. +* `token` - (Optional) The bearer token to use for authentication when accessing the Kubernetes API. Can be sourced from `KUBE_TOKEN`. +* `insecure` - (Optional) Whether server should be accessed without verifying the TLS certificate. Can be sourced from `KUBE_INSECURE`. +* `tls_server_name` - (Optional) Server name passed to the server for SNI and is used in the client to check server certificates against. Can be sourced from `KUBE_TLS_SERVER_NAME`. +* `client_certificate` - (Optional) PEM-encoded client certificate for TLS authentication. Can be sourced from `KUBE_CLIENT_CERT_DATA`. +* `client_key` - (Optional) PEM-encoded client certificate key for TLS authentication. Can be sourced from `KUBE_CLIENT_KEY_DATA`. +* `cluster_ca_certificate` - (Optional) PEM-encoded root certificates bundle for TLS authentication. Can be sourced from `KUBE_CLUSTER_CA_CERT_DATA`. +* `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. + +The `registries` block has options: + +* `url` - (Required) url to the registry in format `oci://host:port` +* `username` - (Required) username to registry +* `password` - (Required) password to registry + +## Experiments + +The provider takes an `experiments` block that allows you enable experimental features by setting them to `true`. + +* `manifest` - Enable storing of the rendered manifest for `helm_release` so the full diff of what is changing can been seen in the plan. + +```terraform +provider "helm" { + experiments = { + manifest = true + } +} +``` diff --git a/shuttles/terraform/terraform-provider-helm/docs/resources/release.md b/shuttles/terraform/terraform-provider-helm/docs/resources/release.md new file mode 100644 index 0000000..1f7242e --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/docs/resources/release.md @@ -0,0 +1,386 @@ +--- +page_title: "helm: helm_release" +sidebar_current: "docs-helm-release" +description: |- + +--- +# Resource: helm_release + +A Release is an instance of a chart running in a Kubernetes cluster. + +A Chart is a Helm package. It contains all of the resource definitions necessary to run an application, tool, or service inside of a Kubernetes cluster. + +`helm_release` describes the desired status of a chart in a kubernetes cluster. + + +## Schema + +### Required + +- `chart` (String) Chart name to be installed. A path may be used. +- `name` (String) Release name. The length must not be longer than 53 characters. + +### Optional + +- `atomic` (Boolean) If set, installation process purges chart on fail. The wait flag will be set automatically if atomic is used. Defaults to `false`. +- `cleanup_on_fail` (Boolean) Allow deletion of new resources created in this upgrade when upgrade fails. Defaults to `false`. +- `create_namespace` (Boolean) Create the namespace if it does not exist. Defaults to `false`. +- `dependency_update` (Boolean) Run helm dependency update before installing the chart. Defaults to `false`. +- `description` (String) Add a custom description +- `devel` (Boolean) Use chart development versions, too. Equivalent to version '>0.0.0-0'. If `version` is set, this is ignored +- `disable_crd_hooks` (Boolean) Prevent CRD hooks from, running, but run other hooks. See helm install --no-crd-hook +- `disable_openapi_validation` (Boolean) If set, the installation process will not validate rendered templates against the Kubernetes OpenAPI Schema. Defaults to `false`. +- `disable_webhooks` (Boolean) Prevent hooks from running.Defaults to `false`. +- `force_update` (Boolean) Force resource update through delete/recreate if needed. Defaults to `false`. +- `keyring` (String) Location of public keys used for verification. Used only if `verify` is true. Defaults to `/.gnupg/pubring.gpg` in the location set by `home`. +- `lint` (Boolean) Run helm lint when planning. Defaults to `false`. +- `max_history` (Number) Limit the maximum number of revisions saved per release. Use 0 for no limit. Defaults to 0 (no limit). +- `namespace` (String) Namespace to install the release into. Defaults to `default`. +- `pass_credentials` (Boolean) Pass credentials to all domains. Defaults to `false`. +- `postrender` (Block List, Max: 1) Postrender command configuration. (see [below for nested schema](#nestedblock--postrender)) +- `recreate_pods` (Boolean) Perform pods restart during upgrade/rollback. Defaults to `false`. +- `render_subchart_notes` (Boolean) If set, render subchart notes along with the parent. Defaults to `true`. +- `replace` (Boolean) Re-use the given name, even if that name is already used. This is unsafe in production. Defaults to `false`. +- `repository` (String) Repository where to locate the requested chart. If is a URL the chart is installed without installing the repository. +- `repository_ca_file` (String) The Repositories CA File +- `repository_cert_file` (String) The repositories cert file +- `repository_key_file` (String) The repositories cert key file +- `repository_password` (String, Sensitive) Password for HTTP basic authentication +- `repository_username` (String) Username for HTTP basic authentication +- `reset_values` (Boolean) When upgrading, reset the values to the ones built into the chart. Defaults to `false`. +- `reuse_values` (Boolean) When upgrading, reuse the last release's values and merge in any overrides. If 'reset_values' is specified, this is ignored. Defaults to `false`. +- `set` (Block Set) Custom values to be merged with the values. (see [below for nested schema](#nestedblock--set)) +- `set_wo` (Attribute List) Custom values to be merged with the values. This is the same as "set" but write-only. (see [below for nested schema](#nestedblock--set)) +- `set_wo_revision` (Number) The current revision of the write-only "set_wo" attribute. Incrementing this integer value will cause Terraform to update the write-only value.` +- `set_list` (Block List) Custom list values to be merged with the values. (see [below for nested schema](#nestedblock--set_list)) +- `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_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. +- `wait` (Boolean) Will wait until all resources are in a ready state before marking the release as successful. Defaults to `true`. +- `wait_for_jobs` (Boolean) If wait is enabled, will wait until all Jobs have been completed before marking the release as successful. Defaults to `false``. + +### Read-Only + +- `id` (String) The ID of this resource. +- `manifest` (String) The rendered manifest as JSON. +- `metadata` (List of Object) Status of the deployed release. (see [below for nested schema](#nestedatt--metadata)) +- `status` (String) Status of the release. + + +### Nested Schema for `postrender` + +Required: + +- `binary_path` (String) The command binary path. + +Optional: + +- `args` (List of String) an argument to the post-renderer (can specify multiple) + + + +### Nested Schema for `set` + +Required: + +- `name` (String) + +Optional: + +- `type` (String) +- `value` (String) + + +### Nested Schema for `set_list` + +Required: + +- `name` (String) +- `value` (List of String) + + + +### Nested Schema for `set_sensitive` + +Required: + +- `name` (String) +- `value` (String, Sensitive) + +Optional: + +- `type` (String) + + + +### Nested Schema for `metadata` + +Read-Only: + +- `app_version` (String) +- `chart` (String) +- `first_deployed` (Number) +- `last_deployed` (Number) +- `name` (String) +- `namespace` (String) +- `notes` (String) +- `revision` (Number) +- `values` (String) +- `version` (String) + + + + + +## Example Usage - Chart Repository + +```terraform +resource "helm_release" "example" { + name = "my-redis-release" + repository = "https://charts.bitnami.com/bitnami" + chart = "redis" + version = "6.0.1" + + set = [ + { + name = "cluster.enabled" + value = "true" + }, + { + name = "metrics.enabled" + value = "true" + } + ] + + set = [ + { + name = "service.annotations.prometheus\\.io/port" + value = "9127" + type = "string" + } + ] +} +``` + +## Example Usage - Local Chart + +In case a Chart is not available from a repository, a path may be used: + +```terraform +resource "helm_release" "example" { + name = "my-local-chart" + chart = "./charts/example" +} +``` + +## Example Usage - Chart URL + +An absolute URL to the .tgz of the Chart may also be used: + +```terraform +resource "helm_release" "example" { + name = "redis" + chart = "https://charts.bitnami.com/bitnami/redis-10.7.16.tgz" +} +``` + +## Example Usage - Chart Repository configured from OCI Registry + +Provider supports grabbing charts from an OCI repository: + +```terraform +provider "helm" { + kubernetes = { + config_path = "~/.kube/config" + } + + registries = [ + { + url = "oci://localhost:5000" + username = "username" + password = "password" + } + ] +} + +resource "helm_release" "example" { + name = "testchart" + namespace = "helm_registry" + repository = "oci://localhost:5000/helm-charts" + version = "1.2.3" + chart = "test-chart" +} +``` + +## Example Usage - Chart Repository configured using GCS/S3 + +The provider also supports helm plugins such as GCS and S3 that add S3/GCS helm repositories by using `helm plugin install` + +```terraform +# Install GCS plugin +`helm plugin install https://github.com/hayorov/helm-gcs.git` + +# Run follow commands to setup GCS repository + +# Init a new repository: +# helm gcs init gs://bucket/path + +# Add your repository to Helm: +# helm repo add repo-name gs://bucket/path + +# Push a chart to your repository: +# helm gcs push chart.tar.gz repo-name + +# Update Helm cache: +# helm repo update + +# Get your chart: + +resource "helm_release" "GCS" { + name = "GCS" + repository = "gs://tf-test-helm-repo/charts" + chart = "chart" +} +``` + +```terraform +# Install AWS S3 plugin +`helm plugin install https://github.com/hypnoglow/helm-s3.git` + +# Run follow commands to setup S3 repository + +# Init a new repository: +# helm s3 init s3://my-helm-charts/stable/myapp + +# Add your repository to Helm: +# helm repo add stable-myapp s3://my-helm-charts/stable/myapp/ + +# Push a chart to your repository: +# helm s3 push chart.tar.gz repo-name + +# Update Helm cache: +# helm repo update + +# Get your chart: + +resource "helm_release" "S3" { + name = "S3" + repository = "s3://tf-test-helm-repo/charts" + chart = "chart" +} +``` + +## Example Usage - Chart Repository configured outside of Terraform + +The provider also supports repositories that are added to the local machine outside of Terraform by running `helm repo add` + +```terraform +# run this first: `helm repo add bitnami https://charts.bitnami.com/bitnami` + +resource "helm_release" "example" { + name = "redis" + chart = "bitnami/redis" +} +``` + +The `set`, `set_list`, and `set_sensitive` blocks support: + +* `name` - (Required) full name of the variable to be set. +* `value` - (Required; Optional for `set`) value of the variable to be set. +* `type` - (Optional) type of the variable to be set. Valid options are `auto` and `string`. + +Since Terraform Utilizes HCL as well as Helm using the Helm Template Language, it's necessary to escape the `{}`, `[]`, `.`, and `,` characters twice in order for it to be parsed. `name` should also be set to the `value path`, and `value` is the desired value that will be set. + +```terraform +set = [ + { + name = "grafana.ingress.annotations.alb\\.ingress\\.kubernetes\\.io/group\\.name" + value = "shared-ingress" + } +] +``` + +```terraform +set_list = [ + { + name = "hashicorp" + value = ["terraform", "nomad", "vault"] + } +] +``` + +```terraform +controller: + pod: + annotations: + status.kubernetes.io/restart-on-failure: {"timeout": "30s"} +``` + +```terraform +set = [ + { + name = "controller.pod.annotations.status\\.kubernetes\\.io/restart-on-failure" + value = "\\{\"timeout\": \"30s\"\\}" + } +] + +``` + +The `postrender` block supports two attributes: + +* `binary_path` - (Required) relative or full path to command binary. +* `args` - (Optional) a list of arguments to supply to the post-renderer. + +## Upgrade Mode Notes + +When using the Helm CLI directly, it is possible to use `helm upgrade --install` to +_idempotently_ install a release. For example, `helm upgrade --install mariadb charts/mariadb --verson 7.1.0` +will check to see if there is already a release called `mariadb`: if there is, ensure that it is set to version +7.1.0, and if there is not, install that version from scratch. (See the documentation for the +[helm upgrade](https://helm.sh/docs/helm/helm_upgrade) command for more details.) + + **NOTE:** The mechanics of this approach are subtly 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 the `upgrade_install` attribute to `true`, the provider will first check to see +if a release with the given name already exists. 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. + +However, if the release _does_ already exist, the provider 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. + +When using `upgrade_install`, the `version` attribute is used to determine the version of the chart to install or +upgrade to. If the `version` attribute is not set, the provider will attempt to determine the version of the chart +from the existing release and will use that version for the upgrade: this is to ensure that using `upgrade_install` +does not inadvertently change the version of the chart being used. + +**CRITICAL**: The user-supplied values passed to the chart in the new revision will be the ones specified in the +`helm_release` resource, not the values used in the original installation of the chart. This means that if +you are using `upgrade_install` to manage a release that was originally installed with a different set of values, +you must ensure that the values in the `helm_release` resource are correct, or you may inadvertently change the +configuration of the release. Additionally, since there is no existing terraform state to compare against, you +must manually inspect the installed release's values with the `helm get values` CLI command. + +**IMPORTANT**: Even if you are "upgrading" to the same version of the chart that is already present in the cluster, +the `helm_release` resource will still show as "changed" in the terraform plan output, because there is no existing +state for it to compare against. This also means that in the apply stage, the provider will in fact reinstall the +chart, which means that if there are any +[deployment](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/), +[daemonset](https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/) or +[statefulset](https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/) resources in the chart, they will +be replaced, which will cause a rolling update of the pods. + +## Import + +A Helm Release resource can be imported using its namespace and name e.g. + +```shell +$ terraform import helm_release.example default/example-name +``` + +~> **NOTE:** Since the `repository` attribute is not being persisted as metadata by helm, it will not be set to any value by default. All other provider specific attributes will be set to their default values and they can be overriden after running `apply` using the resource definition configuration. diff --git a/shuttles/terraform/terraform-provider-helm/examples/data-sources/template/example_1.tf b/shuttles/terraform/terraform-provider-helm/examples/data-sources/template/example_1.tf new file mode 100644 index 0000000..bf95762 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/examples/data-sources/template/example_1.tf @@ -0,0 +1,41 @@ +data "helm_template" "mariadb_instance" { + name = "mariadb-instance" + namespace = "default" + repository = "https://charts.helm.sh/stable" + + chart = "mariadb" + version = "7.1.0" + + set = [ + { + name = "service.port" + value = "13306" + } + ] + + set_sensitive = [ + { + name = "rootUser.password" + value = "s3cr3t!" + } + ] +} + +resource "local_file" "mariadb_manifests" { + for_each = data.helm_template.mariadb_instance.manifests + + filename = "./${each.key}" + content = each.value +} + +output "mariadb_instance_manifest" { + value = data.helm_template.mariadb_instance.manifest +} + +output "mariadb_instance_manifests" { + value = data.helm_template.mariadb_instance.manifests +} + +output "mariadb_instance_notes" { + value = data.helm_template.mariadb_instance.notes +} diff --git a/shuttles/terraform/terraform-provider-helm/examples/data-sources/template/example_2.tf b/shuttles/terraform/terraform-provider-helm/examples/data-sources/template/example_2.tf new file mode 100644 index 0000000..237a421 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/examples/data-sources/template/example_2.tf @@ -0,0 +1,46 @@ +data "helm_template" "mariadb_instance" { + name = "mariadb-instance" + namespace = "default" + repository = "https://charts.helm.sh/stable" + + chart = "mariadb" + version = "7.1.0" + + show_only = [ + "templates/master-statefulset.yaml", + "templates/master-svc.yaml", + ] + + set = [ + { + name = "service.port" + value = "13306" + } + ] + + set_sensitive = [ + { + name = "rootUser.password" + value = "s3cr3t!" + } + ] +} + +resource "local_file" "mariadb_manifests" { + for_each = data.helm_template.mariadb_instance.manifests + + filename = "./${each.key}" + content = each.value +} + +output "mariadb_instance_manifest" { + value = data.helm_template.mariadb_instance.manifest +} + +output "mariadb_instance_manifests" { + value = data.helm_template.mariadb_instance.manifests +} + +output "mariadb_instance_notes" { + value = data.helm_template.mariadb_instance.notes +} diff --git a/shuttles/terraform/terraform-provider-helm/examples/example_1.tf b/shuttles/terraform/terraform-provider-helm/examples/example_1.tf new file mode 100644 index 0000000..cb40620 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/examples/example_1.tf @@ -0,0 +1,31 @@ +provider "helm" { + kubernetes = { + config_path = "~/.kube/config" + } + + registries = [ + { + url = "oci://localhost:5000" + username = "username" + password = "password" + }, + { + url = "oci://private.registry" + username = "username" + password = "password" + } + ] +} + +resource "helm_release" "nginx_ingress" { + name = "nginx-ingress-controller" + repository = "https://charts.bitnami.com/bitnami" + chart = "nginx-ingress-controller" + + set = [ + { + name = "service.type" + value = "ClusterIP" + } + ] +} diff --git a/shuttles/terraform/terraform-provider-helm/examples/example_2.tf b/shuttles/terraform/terraform-provider-helm/examples/example_2.tf new file mode 100644 index 0000000..29cd45b --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/examples/example_2.tf @@ -0,0 +1,5 @@ +provider "helm" { + kubernetes = { + config_path = "~/.kube/config" + } +} diff --git a/shuttles/terraform/terraform-provider-helm/examples/example_3.tf b/shuttles/terraform/terraform-provider-helm/examples/example_3.tf new file mode 100644 index 0000000..59e1b5a --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/examples/example_3.tf @@ -0,0 +1,8 @@ +provider "helm" { + kubernetes = { + config_paths = [ + "/path/to/config_a.yaml", + "/path/to/config_b.yaml" + ] + } +} diff --git a/shuttles/terraform/terraform-provider-helm/examples/example_4.tf b/shuttles/terraform/terraform-provider-helm/examples/example_4.tf new file mode 100644 index 0000000..26cdf49 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/examples/example_4.tf @@ -0,0 +1,9 @@ +provider "helm" { + kubernetes = { + host = "https://cluster_endpoint:port" + + client_certificate = file("~/.kube/client-cert.pem") + client_key = file("~/.kube/client-key.pem") + cluster_ca_certificate = file("~/.kube/cluster-ca-cert.pem") + } +} diff --git a/shuttles/terraform/terraform-provider-helm/examples/example_5.tf b/shuttles/terraform/terraform-provider-helm/examples/example_5.tf new file mode 100644 index 0000000..bd4d57e --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/examples/example_5.tf @@ -0,0 +1,11 @@ +provider "helm" { + kubernetes = { + host = var.cluster_endpoint + cluster_ca_certificate = base64decode(var.cluster_ca_cert) + exec = { + api_version = "client.authentication.k8s.io/v1beta1" + args = ["eks", "get-token", "--cluster-name", var.cluster_name] + command = "aws" + } + } +} \ No newline at end of file diff --git a/shuttles/terraform/terraform-provider-helm/examples/example_6.tf b/shuttles/terraform/terraform-provider-helm/examples/example_6.tf new file mode 100644 index 0000000..02a4b33 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/examples/example_6.tf @@ -0,0 +1,12 @@ +provider "helm" { + kubernetes = { + host = "https://${data.google_container_cluster.my_cluster.endpoint}" + token = data.google_client_config.provider.access_token + cluster_ca_certificate = base64decode( + data.google_container_cluster.my_cluster.master_auth[0].cluster_ca_certificate,) + exec = { + api_version = "client.authentication.k8s.io/v1beta1" + command = "gke-gcloud-auth-plugin" + } + } +} diff --git a/shuttles/terraform/terraform-provider-helm/examples/resources/release/example_1.tf b/shuttles/terraform/terraform-provider-helm/examples/resources/release/example_1.tf new file mode 100644 index 0000000..16eaf45 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/examples/resources/release/example_1.tf @@ -0,0 +1,29 @@ +resource "helm_release" "example" { + name = "my-redis-release" + repository = "https://charts.bitnami.com/bitnami" + chart = "redis" + version = "6.0.1" + + values = [ + "${file("values.yaml")}" + ] + + set = [ + { + name = "cluster.enabled" + value = "true" + }, + { + name = "metrics.enabled" + value = "true" + } + ] + + set = [ + { + name = "service.annotations.prometheus\\.io/port" + value = "9127" + type = "string" + } + ] +} diff --git a/shuttles/terraform/terraform-provider-helm/examples/resources/release/example_10.tf b/shuttles/terraform/terraform-provider-helm/examples/resources/release/example_10.tf new file mode 100644 index 0000000..a4a122e --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/examples/resources/release/example_10.tf @@ -0,0 +1,4 @@ +controller: + pod: + annotations: + status.kubernetes.io/restart-on-failure: {"timeout": "30s"} diff --git a/shuttles/terraform/terraform-provider-helm/examples/resources/release/example_11.tf b/shuttles/terraform/terraform-provider-helm/examples/resources/release/example_11.tf new file mode 100644 index 0000000..01f38ee --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/examples/resources/release/example_11.tf @@ -0,0 +1,6 @@ +set = [ + { + name = "controller.pod.annotations.status\\.kubernetes\\.io/restart-on-failure" + value = "\\{\"timeout\": \"30s\"\\}" + } +] diff --git a/shuttles/terraform/terraform-provider-helm/examples/resources/release/example_2.tf b/shuttles/terraform/terraform-provider-helm/examples/resources/release/example_2.tf new file mode 100644 index 0000000..2158a87 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/examples/resources/release/example_2.tf @@ -0,0 +1,4 @@ +resource "helm_release" "example" { + name = "my-local-chart" + chart = "./charts/example" +} diff --git a/shuttles/terraform/terraform-provider-helm/examples/resources/release/example_3.tf b/shuttles/terraform/terraform-provider-helm/examples/resources/release/example_3.tf new file mode 100644 index 0000000..dcebc08 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/examples/resources/release/example_3.tf @@ -0,0 +1,4 @@ +resource "helm_release" "example" { + name = "redis" + chart = "https://charts.bitnami.com/bitnami/redis-10.7.16.tgz" +} diff --git a/shuttles/terraform/terraform-provider-helm/examples/resources/release/example_4.tf b/shuttles/terraform/terraform-provider-helm/examples/resources/release/example_4.tf new file mode 100644 index 0000000..0ce20e7 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/examples/resources/release/example_4.tf @@ -0,0 +1,22 @@ + +provider "helm" { + kubernetes = { + config_path = "~/.kube/config" + } + # localhost registry with password protection + registries = [ + { + url = "oci://localhost:5000" + username = "username" + password = "password" + } + ] +} + +resource "helm_release" "example" { + name = "testchart" + namespace = "helm_registry" + repository = "oci://localhost:5000/helm-charts" + version = "1.2.3" + chart = "test-chart" +} diff --git a/shuttles/terraform/terraform-provider-helm/examples/resources/release/example_5.tf b/shuttles/terraform/terraform-provider-helm/examples/resources/release/example_5.tf new file mode 100644 index 0000000..6f4d600 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/examples/resources/release/example_5.tf @@ -0,0 +1,25 @@ + +# Install GCS plugin +`helm plugin install https://github.com/hayorov/helm-gcs.git` + +# Run follow commands to setup GCS repository + +# Init a new repository: +# helm gcs init gs://bucket/path + +# Add your repository to Helm: +# helm repo add repo-name gs://bucket/path + +# Push a chart to your repository: +# helm gcs push chart.tar.gz repo-name + +# Update Helm cache: +# helm repo update + +# Get your chart: + +resource "helm_release" "GCS" { + name = "GCS" + repository = "gs://tf-test-helm-repo/charts" + chart = "chart" +} diff --git a/shuttles/terraform/terraform-provider-helm/examples/resources/release/example_6.tf b/shuttles/terraform/terraform-provider-helm/examples/resources/release/example_6.tf new file mode 100644 index 0000000..5364672 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/examples/resources/release/example_6.tf @@ -0,0 +1,25 @@ + +# Install AWS S3 plugin +`helm plugin install https://github.com/hypnoglow/helm-s3.git` + +# Run follow commands to setup S3 repository + +# Init a new repository: +# helm s3 init s3://my-helm-charts/stable/myapp + +# Add your repository to Helm: +# helm repo add stable-myapp s3://my-helm-charts/stable/myapp/ + +# Push a chart to your repository: +# helm s3 push chart.tar.gz repo-name + +# Update Helm cache: +# helm repo update + +# Get your chart: + +resource "helm_release" "S3" { + name = "S3" + repository = "s3://tf-test-helm-repo/charts" + chart = "chart" +} diff --git a/shuttles/terraform/terraform-provider-helm/examples/resources/release/example_7.tf b/shuttles/terraform/terraform-provider-helm/examples/resources/release/example_7.tf new file mode 100644 index 0000000..58a9400 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/examples/resources/release/example_7.tf @@ -0,0 +1,7 @@ + +# run this first: `helm repo add bitnami https://charts.bitnami.com/bitnami` + +resource "helm_release" "example" { + name = "redis" + chart = "bitnami/redis" +} diff --git a/shuttles/terraform/terraform-provider-helm/examples/resources/release/example_8.tf b/shuttles/terraform/terraform-provider-helm/examples/resources/release/example_8.tf new file mode 100644 index 0000000..04558c2 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/examples/resources/release/example_8.tf @@ -0,0 +1,6 @@ +set = [ + { + name = "grafana.ingress.annotations.alb\\.ingress\\.kubernetes\\.io/group\\.name" + value = "shared-ingress" + } +] diff --git a/shuttles/terraform/terraform-provider-helm/examples/resources/release/example_9.tf b/shuttles/terraform/terraform-provider-helm/examples/resources/release/example_9.tf new file mode 100644 index 0000000..ac56598 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/examples/resources/release/example_9.tf @@ -0,0 +1,6 @@ +set_list = [ + { + name = "hashicorp" + value = ["terraform", "nomad", "vault"] + } +] \ No newline at end of file diff --git a/shuttles/terraform/terraform-provider-helm/go.mod b/shuttles/terraform/terraform-provider-helm/go.mod new file mode 100644 index 0000000..d041f44 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/go.mod @@ -0,0 +1,206 @@ +module github.com/hashicorp/terraform-provider-helm + +go 1.23.0 + +toolchain go1.24.0 + +require ( + github.com/hashicorp/go-version v1.7.0 + github.com/hashicorp/terraform-plugin-docs v0.20.1 + github.com/hashicorp/terraform-plugin-framework v1.15.0 + github.com/hashicorp/terraform-plugin-framework-validators v0.13.0 + github.com/hashicorp/terraform-plugin-go v0.27.0 + github.com/hashicorp/terraform-plugin-log v0.9.0 + github.com/hashicorp/terraform-plugin-testing v1.13.0 + github.com/mitchellh/go-homedir v1.1.0 + github.com/pkg/errors v0.9.1 + github.com/stretchr/testify v1.10.0 + golang.org/x/crypto v0.38.0 + helm.sh/helm/v3 v3.17.2 + k8s.io/api v0.32.2 + k8s.io/apimachinery v0.32.2 + k8s.io/client-go v0.32.2 + k8s.io/helm v2.17.0+incompatible + k8s.io/klog v1.0.0 + sigs.k8s.io/yaml v1.4.0 +) + +require ( + github.com/Kunde21/markdownfmt/v3 v3.1.0 // indirect + github.com/bmatcuk/doublestar/v4 v4.7.1 // indirect + github.com/hashicorp/cli v1.1.7 // indirect + github.com/rivo/uniseg v0.2.0 // indirect +) + +require ( + dario.cat/mergo v1.0.1 // indirect + github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect + github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect + github.com/BurntSushi/toml v1.4.0 // indirect + github.com/MakeNowJust/heredoc v1.0.0 // indirect + github.com/Masterminds/goutils v1.1.1 // indirect + github.com/Masterminds/semver/v3 v3.3.0 // indirect + github.com/Masterminds/sprig/v3 v3.3.0 // indirect + github.com/Masterminds/squirrel v1.5.4 // indirect + github.com/ProtonMail/go-crypto v1.1.6 // indirect + github.com/agext/levenshtein v1.2.3 // indirect + github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/bgentry/speakeasy v0.1.0 // indirect + github.com/blang/semver/v4 v4.0.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/chai2010/gettext-go v1.0.2 // indirect + github.com/cloudflare/circl v1.6.0 // indirect + github.com/containerd/containerd v1.7.24 // indirect + github.com/containerd/errdefs v0.3.0 // indirect + github.com/containerd/log v0.1.0 // indirect + github.com/containerd/platforms v0.2.1 // indirect + github.com/cyphar/filepath-securejoin v0.4.1 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/distribution/reference v0.6.0 // indirect + github.com/docker/cli v25.0.1+incompatible // indirect + github.com/docker/distribution v2.8.3+incompatible // indirect + github.com/docker/docker v25.0.6+incompatible // indirect + github.com/docker/docker-credential-helpers v0.7.0 // indirect + github.com/docker/go-connections v0.5.0 // indirect + github.com/docker/go-metrics v0.0.1 // indirect + github.com/emicklei/go-restful/v3 v3.11.0 // indirect + github.com/evanphx/json-patch v5.9.0+incompatible // indirect + github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect + github.com/fatih/color v1.16.0 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/fxamacker/cbor/v2 v2.7.0 // indirect + github.com/ghodss/yaml v1.0.0 // indirect + github.com/go-errors/errors v1.4.2 // indirect + github.com/go-gorp/gorp/v3 v3.1.0 // indirect + github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-openapi/jsonpointer v0.21.0 // indirect + github.com/go-openapi/jsonreference v0.20.2 // indirect + github.com/go-openapi/swag v0.23.0 // indirect + github.com/gobwas/glob v0.2.3 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/google/btree v1.0.1 // indirect + github.com/google/gnostic-models v0.6.8 // indirect + github.com/google/go-cmp v0.7.0 // indirect + github.com/google/gofuzz v1.2.0 // indirect + github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/gorilla/mux v1.8.0 // indirect + github.com/gorilla/websocket v1.5.0 // indirect + github.com/gosuri/uitable v0.0.4 // indirect + github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-checkpoint v0.5.0 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-cty v1.5.0 // indirect + github.com/hashicorp/go-hclog v1.6.3 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.6.3 // indirect + github.com/hashicorp/go-retryablehttp v0.7.7 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/hc-install v0.9.2 // indirect + github.com/hashicorp/hcl/v2 v2.23.0 // indirect + github.com/hashicorp/logutils v1.0.0 // indirect + github.com/hashicorp/terraform-exec v0.23.0 // indirect + github.com/hashicorp/terraform-json v0.25.0 // indirect + github.com/hashicorp/terraform-plugin-sdk/v2 v2.37.0 // indirect + github.com/hashicorp/terraform-registry-address v0.2.5 // indirect + github.com/hashicorp/terraform-svchost v0.1.1 // indirect + github.com/hashicorp/yamux v0.1.1 // indirect + github.com/huandu/xstrings v1.5.0 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/jmoiron/sqlx v1.4.0 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/compress v1.16.7 // indirect + github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect + github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect + github.com/lib/pq v1.10.9 // indirect + github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-runewidth v0.0.13 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/go-wordwrap v1.0.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/moby/locker v1.0.1 // indirect + github.com/moby/spdystream v0.5.0 // indirect + github.com/moby/term v0.5.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect + github.com/oklog/run v1.0.0 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.1.0 // indirect + github.com/peterbourgon/diskv v2.0.1+incompatible // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/posener/complete v1.2.3 // indirect + github.com/prometheus/client_golang v1.19.1 // indirect + github.com/prometheus/client_model v0.6.1 // indirect + github.com/prometheus/common v0.55.0 // indirect + github.com/prometheus/procfs v0.15.1 // indirect + github.com/rubenv/sql-migrate v1.7.1 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/shopspring/decimal v1.4.0 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect + github.com/spf13/cast v1.7.0 // indirect + github.com/spf13/cobra v1.8.1 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect + github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect + github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect + github.com/x448/float16 v0.8.4 // indirect + github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect + github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect + github.com/xeipuuv/gojsonschema v1.2.0 // indirect + github.com/xlab/treeprint v1.2.0 // indirect + github.com/yuin/goldmark v1.7.7 // indirect + github.com/yuin/goldmark-meta v1.1.0 // indirect + github.com/zclconf/go-cty v1.16.2 // indirect + go.abhg.dev/goldmark/frontmatter v0.2.0 // indirect + go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect + go.opentelemetry.io/otel v1.34.0 // indirect + go.opentelemetry.io/otel/metric v1.34.0 // indirect + go.opentelemetry.io/otel/trace v1.34.0 // indirect + golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect + golang.org/x/mod v0.24.0 // indirect + golang.org/x/net v0.39.0 // indirect + golang.org/x/oauth2 v0.26.0 // indirect + golang.org/x/sync v0.14.0 // indirect + golang.org/x/sys v0.33.0 // indirect + golang.org/x/term v0.32.0 // indirect + golang.org/x/text v0.25.0 // indirect + golang.org/x/time v0.7.0 // indirect + golang.org/x/tools v0.26.0 // indirect + google.golang.org/appengine v1.6.8 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a // indirect + google.golang.org/grpc v1.72.1 // indirect + google.golang.org/protobuf v1.36.6 // indirect + gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/apiextensions-apiserver v0.32.2 // indirect + k8s.io/apiserver v0.32.2 // indirect + k8s.io/cli-runtime v0.32.2 // indirect + k8s.io/component-base v0.32.2 // indirect + k8s.io/klog/v2 v2.130.1 // indirect + k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f // indirect + k8s.io/kubectl v0.32.2 // indirect + k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect + oras.land/oras-go v1.2.5 // indirect + sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect + sigs.k8s.io/kustomize/api v0.18.0 // indirect + sigs.k8s.io/kustomize/kyaml v0.18.1 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.4.2 // indirect +) diff --git a/shuttles/terraform/terraform-provider-helm/go.sum b/shuttles/terraform/terraform-provider-helm/go.sum new file mode 100644 index 0000000..b99cba0 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/go.sum @@ -0,0 +1,658 @@ +dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= +dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= +github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= +github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU= +github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU= +github.com/Kunde21/markdownfmt/v3 v3.1.0 h1:KiZu9LKs+wFFBQKhrZJrFZwtLnCCWJahL+S+E/3VnM0= +github.com/Kunde21/markdownfmt/v3 v3.1.0/go.mod h1:tPXN1RTyOzJwhfHoon9wUr4HGYmWgVxSQN6VBJDkrVc= +github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= +github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE= +github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= +github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= +github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0= +github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= +github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe3tPhs= +github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0= +github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8afzqM= +github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= +github.com/Microsoft/hcsshim v0.11.7 h1:vl/nj3Bar/CvJSYo7gIQPyRWc9f3c6IeSNavBTSZNZQ= +github.com/Microsoft/hcsshim v0.11.7/go.mod h1:MV8xMfmECjl5HdO7U/3/hFVnkmSBjAjmA09d4bExKcU= +github.com/ProtonMail/go-crypto v1.1.6 h1:ZcV+Ropw6Qn0AX9brlQLAUXfqLBc7Bl+f/DmNxpLfdw= +github.com/ProtonMail/go-crypto v1.1.6/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= +github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs= +github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= +github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo= +github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec= +github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY= +github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= +github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= +github.com/bmatcuk/doublestar/v4 v4.7.1 h1:fdDeAqgT47acgwd9bd9HxJRDmc9UAmPpc+2m0CXv75Q= +github.com/bmatcuk/doublestar/v4 v4.7.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= +github.com/bshuster-repo/logrus-logstash-hook v1.0.0 h1:e+C0SB5R1pu//O4MQ3f9cFuPGoOVeF2fE4Og9otCc70= +github.com/bshuster-repo/logrus-logstash-hook v1.0.0/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= +github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA= +github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8= +github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd h1:rFt+Y/IK1aEZkEHchZRSq9OQbsSzIT/OrI8YFFmRIng= +github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= +github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b h1:otBG+dV+YK+Soembjv71DPz3uX/V/6MMlSyD9JBQ6kQ= +github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= +github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0 h1:nvj0OLI3YqYXer/kZD8Ri1aaunCxIEsOst1BVJswV0o= +github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk= +github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA= +github.com/cloudflare/circl v1.6.0 h1:cr5JKic4HI+LkINy2lg3W2jF8sHCVTBncJr5gIIq7qk= +github.com/cloudflare/circl v1.6.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= +github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= +github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= +github.com/containerd/containerd v1.7.24 h1:zxszGrGjrra1yYJW/6rhm9cJ1ZQ8rkKBR48brqsa7nA= +github.com/containerd/containerd v1.7.24/go.mod h1:7QUzfURqZWCZV7RLNEn1XjUCQLEf0bkaK4GjUaZehxw= +github.com/containerd/continuity v0.4.2 h1:v3y/4Yz5jwnvqPKJJ+7Wf93fyWoCB3F5EclWG023MDM= +github.com/containerd/continuity v0.4.2/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= +github.com/containerd/errdefs v0.3.0 h1:FSZgGOeK4yuT/+DnF07/Olde/q4KBoMsaamhXxIMDp4= +github.com/containerd/errdefs v0.3.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= +github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= +github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= +github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A= +github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= +github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= +github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s= +github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/distribution/distribution/v3 v3.0.0-20221208165359-362910506bc2 h1:aBfCb7iqHmDEIp6fBvC/hQUddQfg+3qdYjwzaiP9Hnc= +github.com/distribution/distribution/v3 v3.0.0-20221208165359-362910506bc2/go.mod h1:WHNsWjnIn2V1LYOrME7e8KxSeKunYHsxEm4am0BUtcI= +github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= +github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= +github.com/docker/cli v25.0.1+incompatible h1:mFpqnrS6Hsm3v1k7Wa/BO23oz0k121MTbTO1lpcGSkU= +github.com/docker/cli v25.0.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= +github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v25.0.6+incompatible h1:5cPwbwriIcsua2REJe8HqQV+6WlWc1byg2QSXzBxBGg= +github.com/docker/docker v25.0.6+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A= +github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0= +github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= +github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= +github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8= +github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= +github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8= +github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= +github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1 h1:ZClxb8laGDf5arXfYcAtECDFgAgHklGI8CxgjHnXKJ4= +github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= +github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= +github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= +github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= +github.com/evanphx/json-patch v5.9.0+incompatible h1:fBXyNpNMuTTDdquAq/uisOr2lShz4oaXpDTX2bLe7ls= +github.com/evanphx/json-patch v5.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f h1:Wl78ApPPB2Wvf/TIe2xdyJxTlb6obmF18d8QdkxNDu4= +github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f/go.mod h1:OSYXu++VVOHnXeitef/D8n/6y4QV8uLHSFXX4NeXMGc= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= +github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/foxcpp/go-mockdns v1.1.0 h1:jI0rD8M0wuYAxL7r/ynTrCQQq0BVqfB99Vgk7DlmewI= +github.com/foxcpp/go-mockdns v1.1.0/go.mod h1:IhLeSFGed3mJIAXPH2aiRQB+kqz7oqu8ld2qVbOu7Wk= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= +github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= +github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= +github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= +github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= +github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= +github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UNbRM= +github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU= +github.com/go-git/go-git/v5 v5.14.0 h1:/MD3lCrGjCen5WfEAzKg00MJJffKhC8gzS80ycmCi60= +github.com/go-git/go-git/v5 v5.14.0/go.mod h1:Z5Xhoia5PcWA3NF8vRLURn9E5FRhSl7dGj9ItW3Wk5k= +github.com/go-gorp/gorp/v3 v3.1.0 h1:ItKF/Vbuj31dmV4jxA1qblpSwkl9g1typ24xoe70IGs= +github.com/go-gorp/gorp/v3 v3.1.0/go.mod h1:dLEjIyyRNiXvNZ8PSmzpt1GsWAUK8kjVhEpjH8TixEw= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= +github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= +github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= +github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= +github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= +github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= +github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= +github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68= +github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= +github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= +github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ= +github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw= +github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/gomodule/redigo v1.8.2 h1:H5XSIre1MB5NbPYFp+i1NBbb5qN1W8Y8YAQoAYbkm8k= +github.com/gomodule/redigo v1.8.2/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0= +github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= +github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= +github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= +github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo= +github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= +github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= +github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gosuri/uitable v0.0.4 h1:IG2xLKRvErL3uhY6e1BylFzG+aJiwQviDDTfOKeKTpY= +github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo= +github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA= +github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/hashicorp/cli v1.1.7 h1:/fZJ+hNdwfTSfsxMBa9WWMlfjUZbX8/LnUxgAd7lCVU= +github.com/hashicorp/cli v1.1.7/go.mod h1:e6Mfpga9OCT1vqzFuoGZiiF/KaG9CbUfO5s3ghU3YgU= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-checkpoint v0.5.0 h1:MFYpPZCnQqQTE18jFwSII6eUQrD/oxMFp3mlgcqk5mU= +github.com/hashicorp/go-checkpoint v0.5.0/go.mod h1:7nfLNL10NsxqO4iWuW6tWW0HjZuDrwkBuEQsVcpCOgg= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-cty v1.5.0 h1:EkQ/v+dDNUqnuVpmS5fPqyY71NXVgT5gf32+57xY8g0= +github.com/hashicorp/go-cty v1.5.0/go.mod h1:lFUCG5kd8exDobgSfyj4ONE/dc822kiYMguVKdHGMLM= +github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= +github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.6.3 h1:xgHB+ZUSYeuJi96WtxEjzi23uh7YQpznjGh0U0UUrwg= +github.com/hashicorp/go-plugin v1.6.3/go.mod h1:MRobyh+Wc/nYy1V4KAXUiYfzxoYhs7V1mlH1Z7iY2h0= +github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU= +github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= +github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hc-install v0.9.2 h1:v80EtNX4fCVHqzL9Lg/2xkp62bbvQMnvPQ0G+OmtO24= +github.com/hashicorp/hc-install v0.9.2/go.mod h1:XUqBQNnuT4RsxoxiM9ZaUk0NX8hi2h+Lb6/c0OZnC/I= +github.com/hashicorp/hcl/v2 v2.23.0 h1:Fphj1/gCylPxHutVSEOf2fBOh1VE4AuLV7+kbJf3qos= +github.com/hashicorp/hcl/v2 v2.23.0/go.mod h1:62ZYHrXgPoX8xBnzl8QzbWq4dyDsDtfCRgIq1rbJEvA= +github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/terraform-exec v0.23.0 h1:MUiBM1s0CNlRFsCLJuM5wXZrzA3MnPYEsiXmzATMW/I= +github.com/hashicorp/terraform-exec v0.23.0/go.mod h1:mA+qnx1R8eePycfwKkCRk3Wy65mwInvlpAeOwmA7vlY= +github.com/hashicorp/terraform-json v0.25.0 h1:rmNqc/CIfcWawGiwXmRuiXJKEiJu1ntGoxseG1hLhoQ= +github.com/hashicorp/terraform-json v0.25.0/go.mod h1:sMKS8fiRDX4rVlR6EJUMudg1WcanxCMoWwTLkgZP/vc= +github.com/hashicorp/terraform-plugin-docs v0.20.1 h1:Fq7E/HrU8kuZu3hNliZGwloFWSYfWEOWnylFhYQIoys= +github.com/hashicorp/terraform-plugin-docs v0.20.1/go.mod h1:Yz6HoK7/EgzSrHPB9J/lWFzwl9/xep2OPnc5jaJDV90= +github.com/hashicorp/terraform-plugin-framework v1.15.0 h1:LQ2rsOfmDLxcn5EeIwdXFtr03FVsNktbbBci8cOKdb4= +github.com/hashicorp/terraform-plugin-framework v1.15.0/go.mod h1:hxrNI/GY32KPISpWqlCoTLM9JZsGH3CyYlir09bD/fI= +github.com/hashicorp/terraform-plugin-framework-validators v0.13.0 h1:bxZfGo9DIUoLLtHMElsu+zwqI4IsMZQBRRy4iLzZJ8E= +github.com/hashicorp/terraform-plugin-framework-validators v0.13.0/go.mod h1:wGeI02gEhj9nPANU62F2jCaHjXulejm/X+af4PdZaNo= +github.com/hashicorp/terraform-plugin-go v0.27.0 h1:ujykws/fWIdsi6oTUT5Or4ukvEan4aN9lY+LOxVP8EE= +github.com/hashicorp/terraform-plugin-go v0.27.0/go.mod h1:FDa2Bb3uumkTGSkTFpWSOwWJDwA7bf3vdP3ltLDTH6o= +github.com/hashicorp/terraform-plugin-log v0.9.0 h1:i7hOA+vdAItN1/7UrfBqBwvYPQ9TFvymaRGZED3FCV0= +github.com/hashicorp/terraform-plugin-log v0.9.0/go.mod h1:rKL8egZQ/eXSyDqzLUuwUYLVdlYeamldAHSxjUFADow= +github.com/hashicorp/terraform-plugin-sdk/v2 v2.37.0 h1:NFPMacTrY/IdcIcnUB+7hsore1ZaRWU9cnB6jFoBnIM= +github.com/hashicorp/terraform-plugin-sdk/v2 v2.37.0/go.mod h1:QYmYnLfsosrxjCnGY1p9c7Zj6n9thnEE+7RObeYs3fA= +github.com/hashicorp/terraform-plugin-testing v1.13.0 h1:vTELm6x3Z4H9VO3fbz71wbJhbs/5dr5DXfIwi3GMmPY= +github.com/hashicorp/terraform-plugin-testing v1.13.0/go.mod h1:b/hl6YZLm9fjeud/3goqh/gdqhZXbRfbHMkEiY9dZwc= +github.com/hashicorp/terraform-registry-address v0.2.5 h1:2GTftHqmUhVOeuu9CW3kwDkRe4pcBDq0uuK5VJngU1M= +github.com/hashicorp/terraform-registry-address v0.2.5/go.mod h1:PpzXWINwB5kuVS5CA7m1+eO2f1jKb5ZDIxrOPfpnGkg= +github.com/hashicorp/terraform-svchost v0.1.1 h1:EZZimZ1GxdqFRinZ1tpJwVxxt49xc/S52uzrw4x0jKQ= +github.com/hashicorp/terraform-svchost v0.1.1/go.mod h1:mNsjQfZyf/Jhz35v6/0LWcv26+X7JPS+buii2c9/ctc= +github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= +github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI= +github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= +github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c= +github.com/jhump/protoreflect v1.15.1/go.mod h1:jD/2GMKKE6OqX8qTjhADU1e6DShO+gavG9e0Q693nKo= +github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o= +github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= +github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= +github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw= +github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o= +github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk= +github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= +github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= +github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= +github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM= +github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= +github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg= +github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= +github.com/moby/spdystream v0.5.0 h1:7r0J1Si3QO/kjRitvSLVVFUjxMEb/YLj6S9FF62JBCU= +github.com/moby/spdystream v0.5.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI= +github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78= +github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI= +github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g= +github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28= +github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0= +github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= +github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM= +github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= +github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4= +github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= +github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= +github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= +github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= +github.com/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4= +github.com/pjbgf/sha1cd v0.3.2/go.mod h1:zQWigSxVmsHEZow5qaLtPYxpcKMMQpa09ixqBxuCS6A= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.2.3 h1:NP0eAhjcjImqslEwo/1hq7gpajME0fTLTezBKDqfXqo= +github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= +github.com/poy/onpar v1.1.2 h1:QaNrNiZx0+Nar5dLgTVp5mXkyoVFIbepjyEoGSnhbAY= +github.com/poy/onpar v1.1.2/go.mod h1:6X8FLNoxyr9kkmnlqpK6LSoiOtrO6MICtWwEuWkLjzg= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= +github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= +github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= +github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= +github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= +github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= +github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/rubenv/sql-migrate v1.7.1 h1:f/o0WgfO/GqNuVg+6801K/KW3WdDSupzSjDYODmiUq4= +github.com/rubenv/sql-migrate v1.7.1/go.mod h1:Ob2Psprc0/3ggbM6wCzyYVFFuc6FyZrb2AS+ezLDFb4= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= +github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= +github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= +github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8= +github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY= +github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w= +github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= +github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI= +github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= +github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8= +github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok= +github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= +github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= +github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= +github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ= +github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yuin/goldmark v1.7.7 h1:5m9rrB1sW3JUMToKFQfb+FGt1U7r57IHu5GrYrG2nqU= +github.com/yuin/goldmark v1.7.7/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= +github.com/yuin/goldmark-meta v1.1.0 h1:pWw+JLHGZe8Rk0EGsMVssiNb/AaPMHfSRszZeUeiOUc= +github.com/yuin/goldmark-meta v1.1.0/go.mod h1:U4spWENafuA7Zyg+Lj5RqK/MF+ovMYtBvXi1lBb2VP0= +github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43 h1:+lm10QQTNSBd8DVTNGHx7o/IKu9HYDvLMffDhbyLccI= +github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= +github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50 h1:hlE8//ciYMztlGpl/VA+Zm1AcTPHYkHJPbHqE6WJUXE= +github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= +github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f h1:ERexzlUfuTvpE74urLSbIQW0Z/6hF9t8U4NsJLaioAY= +github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= +github.com/zclconf/go-cty v1.16.2 h1:LAJSwc3v81IRBZyUVQDUdZ7hs3SYs9jv0eZJDWHD/70= +github.com/zclconf/go-cty v1.16.2/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE= +github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940 h1:4r45xpDWB6ZMSMNJFMOjqrGHynW3DIBuR2H9j0ug+Mo= +github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940/go.mod h1:CmBdvvj3nqzfzJ6nTCIwDTPZ56aVGvDrmztiO5g3qrM= +go.abhg.dev/goldmark/frontmatter v0.2.0 h1:P8kPG0YkL12+aYk2yU3xHv4tcXzeVnN+gU0tJ5JnxRw= +go.abhg.dev/goldmark/frontmatter v0.2.0/go.mod h1:XqrEkZuM57djk7zrlRUB02x8I5J0px76YjkOzhB4YlU= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg= +go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY= +go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI= +go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ= +go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE= +go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A= +go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU= +go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk= +go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w= +go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k= +go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8= +golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU= +golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY= +golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E= +golang.org/x/oauth2 v0.26.0 h1:afQXWNNaeC4nvZ0Ed9XvCCzXM6UHJG7iCg0W4fPqSBE= +golang.org/x/oauth2 v0.26.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ= +golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= +golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= +golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= +golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ= +golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ= +golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= +google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a h1:51aaUVRocpvUOSQKM6Q7VuoaktNIaMCLuhZB6DKksq4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a/go.mod h1:uRxBH1mhmO8PGhU89cMcHaXKZqO+OfakD8QQO0oYwlQ= +google.golang.org/grpc v1.72.1 h1:HR03wO6eyZ7lknl75XlxABNVLLFc2PAb6mHlYh756mA= +google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4= +gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o= +gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= +helm.sh/helm/v3 v3.17.2 h1:agYQ5ew2jq5vdx2K7q5W44KyKQrnSubUMCQsjkiv3/o= +helm.sh/helm/v3 v3.17.2/go.mod h1:+uJKMH/UiMzZQOALR3XUf3BLIoczI2RKKD6bMhPh4G8= +k8s.io/api v0.32.2 h1:bZrMLEkgizC24G9eViHGOPbW+aRo9duEISRIJKfdJuw= +k8s.io/api v0.32.2/go.mod h1:hKlhk4x1sJyYnHENsrdCWw31FEmCijNGPJO5WzHiJ6Y= +k8s.io/apiextensions-apiserver v0.32.2 h1:2YMk285jWMk2188V2AERy5yDwBYrjgWYggscghPCvV4= +k8s.io/apiextensions-apiserver v0.32.2/go.mod h1:GPwf8sph7YlJT3H6aKUWtd0E+oyShk/YHWQHf/OOgCA= +k8s.io/apimachinery v0.32.2 h1:yoQBR9ZGkA6Rgmhbp/yuT9/g+4lxtsGYwW6dR6BDPLQ= +k8s.io/apimachinery v0.32.2/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE= +k8s.io/apiserver v0.32.2 h1:WzyxAu4mvLkQxwD9hGa4ZfExo3yZZaYzoYvvVDlM6vw= +k8s.io/apiserver v0.32.2/go.mod h1:PEwREHiHNU2oFdte7BjzA1ZyjWjuckORLIK/wLV5goM= +k8s.io/cli-runtime v0.32.2 h1:aKQR4foh9qeyckKRkNXUccP9moxzffyndZAvr+IXMks= +k8s.io/cli-runtime v0.32.2/go.mod h1:a/JpeMztz3xDa7GCyyShcwe55p8pbcCVQxvqZnIwXN8= +k8s.io/client-go v0.32.2 h1:4dYCD4Nz+9RApM2b/3BtVvBHw54QjMFUl1OLcJG5yOA= +k8s.io/client-go v0.32.2/go.mod h1:fpZ4oJXclZ3r2nDOv+Ux3XcJutfrwjKTCHz2H3sww94= +k8s.io/component-base v0.32.2 h1:1aUL5Vdmu7qNo4ZsE+569PV5zFatM9hl+lb3dEea2zU= +k8s.io/component-base v0.32.2/go.mod h1:PXJ61Vx9Lg+P5mS8TLd7bCIr+eMJRQTyXe8KvkrvJq0= +k8s.io/helm v2.17.0+incompatible h1:Bpn6o1wKLYqKM3+Osh8e+1/K2g/GsQJ4F4yNF2+deao= +k8s.io/helm v2.17.0+incompatible/go.mod h1:LZzlS4LQBHfciFOurYBFkCMTaZ0D1l+p0teMg7TSULI= +k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= +k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= +k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= +k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f h1:GA7//TjRY9yWGy1poLzYYJJ4JRdzg3+O6e8I+e+8T5Y= +k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f/go.mod h1:R/HEjbvWI0qdfb8viZUeVZm0X6IZnxAydC7YU42CMw4= +k8s.io/kubectl v0.32.2 h1:TAkag6+XfSBgkqK9I7ZvwtF0WVtUAvK8ZqTt+5zi1Us= +k8s.io/kubectl v0.32.2/go.mod h1:+h/NQFSPxiDZYX/WZaWw9fwYezGLISP0ud8nQKg+3g8= +k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro= +k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +oras.land/oras-go v1.2.5 h1:XpYuAwAb0DfQsunIyMfeET92emK8km3W4yEzZvUbsTo= +oras.land/oras-go v1.2.5/go.mod h1:PuAwRShRZCsZb7g8Ar3jKKQR/2A/qN+pkYxIOd/FAoo= +sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8= +sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo= +sigs.k8s.io/kustomize/api v0.18.0 h1:hTzp67k+3NEVInwz5BHyzc9rGxIauoXferXyjv5lWPo= +sigs.k8s.io/kustomize/api v0.18.0/go.mod h1:f8isXnX+8b+SGLHQ6yO4JG1rdkZlvhaCf/uZbLVMb0U= +sigs.k8s.io/kustomize/kyaml v0.18.1 h1:WvBo56Wzw3fjS+7vBjN6TeivvpbW9GmRaWZ9CIVmt4E= +sigs.k8s.io/kustomize/kyaml v0.18.1/go.mod h1:C3L2BFVU1jgcddNBE1TxuVLgS46TjObMwW5FT9FcjYo= +sigs.k8s.io/structured-merge-diff/v4 v4.4.2 h1:MdmvkGuXi/8io6ixD5wud3vOLwc1rj0aNqRlpuvjmwA= +sigs.k8s.io/structured-merge-diff/v4 v4.4.2/go.mod h1:N8f93tFZh9U6vpxwRArLiikrE5/2tiu1w1AGfACIGE4= +sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/shuttles/terraform/terraform-provider-helm/helm/data_helm_template.go b/shuttles/terraform/terraform-provider-helm/helm/data_helm_template.go new file mode 100644 index 0000000..3e439d5 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/data_helm_template.go @@ -0,0 +1,1072 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package helm + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "net/url" + "os" + pathpkg "path" + "path/filepath" + "regexp" + "sort" + "strings" + "time" + + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-log/tflog" + "helm.sh/helm/v3/pkg/action" + "helm.sh/helm/v3/pkg/chart" + "helm.sh/helm/v3/pkg/chart/loader" + "helm.sh/helm/v3/pkg/chartutil" + "helm.sh/helm/v3/pkg/downloader" + "helm.sh/helm/v3/pkg/getter" + "helm.sh/helm/v3/pkg/registry" + "helm.sh/helm/v3/pkg/release" + "helm.sh/helm/v3/pkg/releaseutil" + "k8s.io/helm/pkg/strvals" + "sigs.k8s.io/yaml" +) + +var ( + _ datasource.DataSource = &HelmTemplate{} + _ datasource.DataSourceWithConfigure = &HelmTemplate{} +) + +func NewHelmTemplate() datasource.DataSource { + return &HelmTemplate{} +} + +// HelmTemplate represents the data source for rendering Helm chart templates +type HelmTemplate struct { + meta *Meta +} + +// HelmTemplateModel holds the attributes for configuring the Helm chart templates +type HelmTemplateModel struct { + APIVersions types.List `tfsdk:"api_versions"` + Atomic types.Bool `tfsdk:"atomic"` + Chart types.String `tfsdk:"chart"` + CreateNamespace types.Bool `tfsdk:"create_namespace"` + CRDs types.List `tfsdk:"crds"` + DependencyUpdate types.Bool `tfsdk:"dependency_update"` + Description types.String `tfsdk:"description"` + Devel types.Bool `tfsdk:"devel"` + DisableOpenAPIValidation types.Bool `tfsdk:"disable_openapi_validation"` + DisableWebhooks types.Bool `tfsdk:"disable_webhooks"` + ID types.String `tfsdk:"id"` + IncludeCRDs types.Bool `tfsdk:"include_crds"` + IsUpgrade types.Bool `tfsdk:"is_upgrade"` + Keyring types.String `tfsdk:"keyring"` + KubeVersion types.String `tfsdk:"kube_version"` + Manifest types.String `tfsdk:"manifest"` + Manifests types.Map `tfsdk:"manifests"` + Name types.String `tfsdk:"name"` + Namespace types.String `tfsdk:"namespace"` + Notes types.String `tfsdk:"notes"` + PassCredentials types.Bool `tfsdk:"pass_credentials"` + PostRender *PostRenderModel `tfsdk:"postrender"` + RenderSubchartNotes types.Bool `tfsdk:"render_subchart_notes"` + Replace types.Bool `tfsdk:"replace"` + Repository types.String `tfsdk:"repository"` + RepositoryCaFile types.String `tfsdk:"repository_ca_file"` + RepositoryCertFile types.String `tfsdk:"repository_cert_file"` + RepositoryKeyFile types.String `tfsdk:"repository_key_file"` + RepositoryPassword types.String `tfsdk:"repository_password"` + RepositoryUsername types.String `tfsdk:"repository_username"` + ResetValues types.Bool `tfsdk:"reset_values"` + ReuseValues types.Bool `tfsdk:"reuse_values"` + Set types.Set `tfsdk:"set"` + SetList types.List `tfsdk:"set_list"` + SetSensitive types.Set `tfsdk:"set_sensitive"` + ShowOnly types.List `tfsdk:"show_only"` + SkipCrds types.Bool `tfsdk:"skip_crds"` + SkipTests types.Bool `tfsdk:"skip_tests"` + Timeout types.Int64 `tfsdk:"timeout"` + Validate types.Bool `tfsdk:"validate"` + Values types.List `tfsdk:"values"` + Version types.String `tfsdk:"version"` + Verify types.Bool `tfsdk:"verify"` + Wait types.Bool `tfsdk:"wait"` +} + +// SetValue represents the custom value to be merged with the Helm chart values +type SetValue struct { + Name types.String `tfsdk:"name"` + Type types.String `tfsdk:"type"` + Value types.String `tfsdk:"value"` +} + +// SetListValue represents a custom list value to be merged with the Helm chart values. +// This type is used to specify lists of values that should be passed to the Helm chart during deployment. +type SetListValue struct { + Name types.String `tfsdk:"name"` + Value types.List `tfsdk:"value"` +} + +// SetSensitiveValue represents a custom sensitive value to be merged with the Helm chart values. +type SetSensitiveValue struct { + Name types.String `tfsdk:"name"` + Type types.String `tfsdk:"type"` + Value types.String `tfsdk:"value"` +} +type Postrender struct { + BinaryPath types.String `tfsdk:"binary_path"` +} + +func (d *HelmTemplate) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { + if req.ProviderData != nil { + d.meta = req.ProviderData.(*Meta) + } +} + +func (d *HelmTemplate) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_template" +} + +func (d *HelmTemplate) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = schema.Schema{ + Description: "Data source to render Helm chart templates.", + Attributes: map[string]schema.Attribute{ + "api_versions": schema.ListAttribute{ + Optional: true, + ElementType: types.StringType, + Description: "Kubernetes api versions used for Capabilities.APIVersions.", + }, + "atomic": schema.BoolAttribute{ + Optional: true, + Description: "If set, the installation process purges the chart on fail. The 'wait' flag will be set automatically if 'atomic' is used.", + }, + "chart": schema.StringAttribute{ + Required: true, + Description: "Chart name to be installed. A path may be used.", + }, + "crds": schema.ListAttribute{ + Optional: true, + Computed: true, + ElementType: types.StringType, + Description: "List of rendered CRDs from the chart.", + }, + "create_namespace": schema.BoolAttribute{ + Optional: true, + Description: "Create the namespace if it does not exist.", + }, + "dependency_update": schema.BoolAttribute{ + Optional: true, + Description: "Run helm dependency update before installing the chart.", + }, + "description": schema.StringAttribute{ + Optional: true, + Description: "Add a custom description.", + }, + "devel": schema.BoolAttribute{ + Optional: true, + Description: "Use chart development versions, too. Equivalent to version '>0.0.0-0'. If `version` is set, this is ignored.", + }, + "disable_openapi_validation": schema.BoolAttribute{ + Optional: true, + Description: "If set, the installation process will not validate rendered templates against the Kubernetes OpenAPI Schema.", + }, + "disable_webhooks": schema.BoolAttribute{ + Optional: true, + Description: "Prevent hooks from running.", + }, + "id": schema.StringAttribute{ + Computed: true, + }, + "include_crds": schema.BoolAttribute{ + Optional: true, + Description: "Include CRDs in the templated output.", + }, + "is_upgrade": schema.BoolAttribute{ + Optional: true, + Description: "Set .Release.IsUpgrade instead of .Release.IsInstall.", + }, + "keyring": schema.StringAttribute{ + Optional: true, + Description: "Location of public keys used for verification. Used only if `verify` is true.", + }, + "kube_version": schema.StringAttribute{ + Optional: true, + Description: "Kubernetes version used for Capabilities.KubeVersion.", + }, + "manifest": schema.StringAttribute{ + Optional: true, + Computed: true, + Description: "Concatenated rendered chart templates. This corresponds to the output of the `helm template` command.", + }, + "manifests": schema.MapAttribute{ + Optional: true, + Computed: true, + ElementType: types.StringType, + Description: "Map of rendered chart templates indexed by the template name.", + }, + "name": schema.StringAttribute{ + Required: true, + Description: "Release name", + }, + "namespace": schema.StringAttribute{ + Optional: true, + Description: "Namespace to install the release into.", + }, + "notes": schema.StringAttribute{ + Optional: true, + Computed: true, + Description: "Rendered notes if the chart contains a `NOTES.txt`.", + }, + "pass_credentials": schema.BoolAttribute{ + Optional: true, + Description: "Pass credentials to all domains", + }, + "postrender": schema.SingleNestedAttribute{ + Description: "Postrender command config", + Optional: true, + Attributes: map[string]schema.Attribute{ + "args": schema.ListAttribute{ + Optional: true, + Description: "An argument to the post-renderer (can specify multiple)", + ElementType: types.StringType, + }, + "binary_path": schema.StringAttribute{ + Required: true, + Description: "The common binary path", + }, + }, + }, + "render_subchart_notes": schema.BoolAttribute{ + Optional: true, + Description: "If set, render subchart notes along with the parent.", + }, + "replace": schema.BoolAttribute{ + Optional: true, + Description: "Re-use the given name, even if that name is already used. This is unsafe in production.", + }, + "repository": schema.StringAttribute{ + Optional: true, + Description: "Repository where to locate the requested chart. If it is a URL the chart is installed without installing the repository.", + }, + "repository_ca_file": schema.StringAttribute{ + Optional: true, + Description: "The repository's CA file", + }, + "repository_cert_file": schema.StringAttribute{ + Optional: true, + Description: "The repository's cert file", + }, + "repository_key_file": schema.StringAttribute{ + Optional: true, + Description: "The repository's cert key file", + }, + "repository_password": schema.StringAttribute{ + Optional: true, + Sensitive: true, + Description: "Password for HTTP basic authentication", + }, + "repository_username": schema.StringAttribute{ + Optional: true, + Description: "Username for HTTP basic authentication", + }, + "reset_values": schema.BoolAttribute{ + Optional: true, + Description: "When upgrading, reset the values to the ones built into the chart.", + }, + "reuse_values": schema.BoolAttribute{ + Optional: true, + Description: "When upgrading, reuse the last release's values and merge in any overrides. If 'reset_values' is specified, this is ignored.", + }, + "set": schema.SetNestedAttribute{ + Description: "Custom values to be merged with the values", + Optional: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "name": schema.StringAttribute{ + Required: true, + }, + "value": schema.StringAttribute{ + Optional: true, + }, + "type": schema.StringAttribute{ + Optional: true, + Computed: true, + Validators: []validator.String{ + stringvalidator.OneOf("auto", "string", "literal"), + }, + }, + }, + }, + }, + "set_list": schema.ListNestedAttribute{ + Description: "Custom sensitive values to be merged with the values", + Optional: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "name": schema.StringAttribute{ + Optional: true, + }, + "value": schema.ListAttribute{ + Required: true, + ElementType: types.StringType, + }, + }, + }, + }, + "set_sensitive": schema.SetNestedAttribute{ + Description: "Custom sensitive values to be merged with the values", + Optional: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "name": schema.StringAttribute{ + Required: true, + }, + "value": schema.StringAttribute{ + Required: true, + Sensitive: true, + }, + "type": schema.StringAttribute{ + Optional: true, + Validators: []validator.String{ + stringvalidator.OneOf("auto", "string", "literal"), + }, + }, + }, + }, + }, + "show_only": schema.ListAttribute{ + Optional: true, + ElementType: types.StringType, + Description: "Only show manifests rendered from the given templates.", + }, + "skip_crds": schema.BoolAttribute{ + Optional: true, + Description: "If set, no CRDs will be installed. By default, CRDs are installed if not already present.", + }, + "skip_tests": schema.BoolAttribute{ + Optional: true, + Description: "If set, tests will not be rendered. By default, tests are rendered.", + }, + "timeout": schema.Int64Attribute{ + Optional: true, + Description: "Time in seconds to wait for any individual Kubernetes operation.", + }, + "validate": schema.BoolAttribute{ + Optional: true, + Description: "Validate your manifests against the Kubernetes cluster you are currently pointing at. This is the same validation performed on an install.", + }, + "values": schema.ListAttribute{ + Optional: true, + ElementType: types.StringType, + Description: "List of values in raw yaml format to pass to helm.", + }, + "verify": schema.BoolAttribute{ + Optional: true, + Description: "Verify the package before installing it.", + }, + "version": schema.StringAttribute{ + Optional: true, + Computed: true, + Description: "Specify the exact chart version to install. If this is not specified, the latest version is installed.", + }, + "wait": schema.BoolAttribute{ + Optional: true, + Description: "Will wait until all resources are in a ready state before marking the release as successful.", + }, + }, + } +} + +// Reads the current state of the data template and will update the state with the data fetched +func (d *HelmTemplate) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var state HelmTemplateModel + resp.Diagnostics.Append(req.Config.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + // setting default values to false is attributes are not provided in the config + if state.Description.IsNull() || state.Description.ValueString() == "" { + state.Description = types.StringValue("") + } + if state.Devel.IsNull() || state.Devel.IsUnknown() { + if !state.Version.IsNull() && state.Version.ValueString() != "" { + // Version is set, suppress devel change + state.Devel = types.BoolValue(false) + } + } + if state.Keyring.IsNull() || state.Keyring.IsUnknown() { + if !state.Verify.IsNull() && state.Verify.ValueBool() { + state.Keyring = types.StringValue(os.ExpandEnv("$HOME/.gnupg/pubring.gpg")) + } else { + state.Keyring = types.StringValue("") + } + } + if state.IncludeCRDs.IsNull() || state.IncludeCRDs.IsUnknown() { + state.IncludeCRDs = types.BoolValue(false) + } + if state.IsUpgrade.IsNull() || state.IsUpgrade.IsUnknown() { + state.IsUpgrade = types.BoolValue(false) + } + if state.DisableWebhooks.IsNull() || state.DisableWebhooks.IsUnknown() { + state.DisableWebhooks = types.BoolValue(false) + } + if state.ReuseValues.IsNull() || state.ReuseValues.IsUnknown() { + state.ReuseValues = types.BoolValue(false) + } + if state.ResetValues.IsNull() || state.ResetValues.IsUnknown() { + state.ResetValues = types.BoolValue(false) + } + if state.Atomic.IsNull() || state.Atomic.IsUnknown() { + state.Atomic = types.BoolValue(false) + } + if state.SkipCrds.IsNull() || state.SkipCrds.IsUnknown() { + state.SkipCrds = types.BoolValue(false) + } + if state.SkipTests.IsNull() || state.SkipTests.IsUnknown() { + state.SkipTests = types.BoolValue(false) + } + if state.RenderSubchartNotes.IsNull() || state.RenderSubchartNotes.IsUnknown() { + state.RenderSubchartNotes = types.BoolValue(false) + } + if state.DisableOpenAPIValidation.IsNull() || state.DisableOpenAPIValidation.IsUnknown() { + state.DisableOpenAPIValidation = types.BoolValue(false) + } + if state.Wait.IsNull() || state.Wait.IsUnknown() { + state.Wait = types.BoolValue(false) + } + if state.DependencyUpdate.IsNull() || state.DependencyUpdate.IsUnknown() { + state.DependencyUpdate = types.BoolValue(false) + } + if state.Replace.IsNull() || state.Replace.IsUnknown() { + state.Replace = types.BoolValue(false) + } + if state.CreateNamespace.IsNull() || state.CreateNamespace.IsUnknown() { + state.CreateNamespace = types.BoolValue(false) + } + if state.Validate.IsNull() || state.Validate.IsUnknown() { + state.Validate = types.BoolValue(false) + } + if state.Verify.IsNull() || state.Verify.IsUnknown() { + state.Verify = types.BoolValue(false) + } + if state.Timeout.IsNull() || state.Timeout.IsUnknown() { + state.Timeout = types.Int64Value(300) + } + if state.Namespace.IsNull() || state.Namespace.IsUnknown() { + defaultNamespace := os.Getenv("HELM_NAMESPACE") + if defaultNamespace == "" { + defaultNamespace = "default" + } + state.Namespace = types.StringValue(defaultNamespace) + } + + meta := d.meta + + var apiVersions []string + if !state.APIVersions.IsNull() && !state.APIVersions.IsUnknown() { + var apiVersionElements []types.String + diags := state.APIVersions.ElementsAs(ctx, &apiVersionElements, false) + resp.Diagnostics.Append(diags...) + if diags.HasError() { + return + } + + for _, apiVersion := range apiVersionElements { + apiVersions = append(apiVersions, apiVersion.ValueString()) + } + } + + var showFiles []string + + if !state.ShowOnly.IsNull() && state.ShowOnly.Elements() != nil { + var showOnlyElements []types.String + diags := state.ShowOnly.ElementsAs(ctx, &showOnlyElements, false) + resp.Diagnostics.Append(diags...) + if diags.HasError() { + return + } + + for _, raw := range showOnlyElements { + if raw.IsNull() || raw.ValueString() == "" { + continue + } + showFiles = append(showFiles, raw.ValueString()) + } + } + + actionConfig, err := meta.GetHelmConfiguration(ctx, state.Namespace.ValueString()) + if err != nil { + resp.Diagnostics.AddError( + "Failed to get Helm configuration", + fmt.Sprintf("There was an error retrieving Helm configuration for namespace %q: %s", state.Namespace.ValueString(), err), + ) + return + } + diags := OCIRegistryLogin(ctx, meta, actionConfig, meta.RegistryClient, state.Repository.ValueString(), state.Chart.ValueString(), state.RepositoryUsername.ValueString(), state.RepositoryPassword.ValueString()) + if diags.HasError() { + resp.Diagnostics.Append(diags...) + return + } + client := action.NewInstall(actionConfig) + + cpo, chartName, cpoDiags := chartPathOptionsModel(&state, meta, &client.ChartPathOptions) + resp.Diagnostics.Append(cpoDiags...) + if resp.Diagnostics.HasError() { + return + } + + c, chartPath, chartDiags := getChartModel(ctx, &state, meta, chartName, cpo) + resp.Diagnostics.Append(chartDiags...) + if resp.Diagnostics.HasError() { + return + } + + updated, depDiags := checkChartDependenciesModel(ctx, &state, c, chartPath, meta) + resp.Diagnostics.Append(depDiags...) + if resp.Diagnostics.HasError() { + return + } else if updated { + c, err = loader.Load(chartPath) + if err != nil { + resp.Diagnostics.AddError("Error loading chart", fmt.Sprintf("Could not reload chart after updating dependencies: %s", err)) + return + } + } + + values, valuesDiags := getValuesModel(ctx, &state) + resp.Diagnostics.Append(valuesDiags...) + if resp.Diagnostics.HasError() { + return + } + + if err := isChartInstallable(c); err != nil { + resp.Diagnostics.AddError("Error checking if chart is installable", fmt.Sprintf("Chart is not installable: %s", err)) + return + } + client.ChartPathOptions = *cpo + client.ClientOnly = false + client.ReleaseName = state.Name.ValueString() + client.GenerateName = false + client.NameTemplate = "" + client.OutputDir = "" + client.Namespace = state.Namespace.ValueString() + client.Timeout = time.Duration(state.Timeout.ValueInt64()) * time.Second + client.Wait = state.Wait.ValueBool() + client.DependencyUpdate = state.DependencyUpdate.ValueBool() + client.DisableHooks = state.DisableWebhooks.ValueBool() + client.DisableOpenAPIValidation = state.DisableOpenAPIValidation.ValueBool() + client.Atomic = state.Atomic.ValueBool() + client.Replace = state.Replace.ValueBool() + client.SkipCRDs = state.SkipCrds.ValueBool() + client.SubNotes = state.RenderSubchartNotes.ValueBool() + client.Devel = state.Devel.ValueBool() + client.Description = state.Description.ValueString() + client.CreateNamespace = state.CreateNamespace.ValueBool() + + if state.KubeVersion.ValueString() != "" { + parsedVer, err := chartutil.ParseKubeVersion(state.KubeVersion.ValueString()) + if err != nil { + resp.Diagnostics.AddError( + "Failed to parse Kubernetes version", + fmt.Sprintf("couldn't parse string %q into kube-version: %s", state.KubeVersion.ValueString(), err), + ) + return + } + client.KubeVersion = parsedVer + } + + client.DryRun = true + client.Replace = true + client.ClientOnly = !state.Validate.ValueBool() + client.APIVersions = chartutil.VersionSet(apiVersions) + client.IncludeCRDs = state.IncludeCRDs.ValueBool() + + rel, err := client.Run(c, values) + if err != nil { + resp.Diagnostics.AddError( + "Error running Helm install", + fmt.Sprintf("Error running Helm install: %s", err), + ) + return + } + + var manifests bytes.Buffer + fmt.Fprintln(&manifests, strings.TrimSpace(rel.Manifest)) + if !client.DisableHooks { + for _, m := range rel.Hooks { + if state.SkipTests.ValueBool() && isTestHook(m) { + continue + } + fmt.Fprintf(&manifests, "---\n# Source: %s\n%s\n", m.Path, m.Manifest) + } + } + var manifestsToRender []string + + splitManifests := releaseutil.SplitManifests(manifests.String()) + manifestsKeys := make([]string, 0, len(splitManifests)) + for k := range splitManifests { + manifestsKeys = append(manifestsKeys, k) + } + sort.Sort(releaseutil.BySplitManifestsOrder(manifestsKeys)) + + var chartCRDs []string + for _, crd := range rel.Chart.CRDObjects() { + chartCRDs = append(chartCRDs, string(crd.File.Data)) + } + + // Mapping of manifest key to manifest template name + manifestNamesByKey := make(map[string]string, len(manifestsKeys)) + + manifestNameRegex := regexp.MustCompile("# Source: [^/]+/(.+)") + + for _, manifestKey := range manifestsKeys { + manifest := splitManifests[manifestKey] + submatch := manifestNameRegex.FindStringSubmatch(manifest) + if len(submatch) == 0 { + continue + } + manifestName := submatch[1] + manifestNamesByKey[manifestKey] = manifestName + } + + if len(showFiles) > 0 { + for _, f := range showFiles { + missing := true + f = filepath.ToSlash(f) + + for manifestKey, manifestName := range manifestNamesByKey { + manifestPathSplit := strings.Split(manifestName, "/") + manifestPath := strings.Join(manifestPathSplit, "/") + + if matched, _ := filepath.Match(f, manifestPath); !matched { + continue + } + + manifestsToRender = append(manifestsToRender, manifestKey) + missing = false + } + + if missing { + resp.Diagnostics.AddError( + "Template Not Found", + fmt.Sprintf("Could not find template %q in chart", f), + ) + } + } + } else { + manifestsToRender = manifestsKeys + } + + // We need to sort the manifests so the order stays stable when they are + // concatenated back together in the computedManifests map + sort.Strings(manifestsToRender) + + // Map from rendered manifests to data source output + computedManifests := make(map[string]string, 0) + computedManifest := &strings.Builder{} + + for _, manifestKey := range manifestsToRender { + manifest := splitManifests[manifestKey] + manifestName := manifestNamesByKey[manifestKey] + + // Manifests + computedManifests[manifestName] = fmt.Sprintf("%s---\n%s\n", computedManifests[manifestName], manifest) + + // Manifest bundle + fmt.Fprintf(computedManifest, "---\n%s\n", manifest) + } + + // Convert chartCRDs to types.List + listElements := make([]attr.Value, len(chartCRDs)) + for i, crd := range chartCRDs { + listElements[i] = types.StringValue(crd) + } + listValue, diags := types.ListValue(types.StringType, listElements) + if diags.HasError() { + resp.Diagnostics.Append(diags...) + return + } + state.CRDs = listValue + // Convert computedManifests to types.Map + elements := make(map[string]attr.Value, len(computedManifests)) + for k, v := range computedManifests { + elements[k] = types.StringValue(v) + } + mapValue, diags := types.MapValue(types.StringType, elements) + if diags.HasError() { + resp.Diagnostics.Append(diags...) + return + } + state.Manifests = mapValue + + state.Manifest = types.StringValue(computedManifest.String()) + state.Notes = types.StringValue(rel.Info.Notes) + state.ID = types.StringValue(state.Name.ValueString()) + + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) +} + +func getValuesModel(ctx context.Context, model *HelmTemplateModel) (map[string]interface{}, diag.Diagnostics) { + base := map[string]interface{}{} + var diags diag.Diagnostics + + // Process "values" attribute + for _, raw := range model.Values.Elements() { + if raw.IsNull() { + continue + } + + value, ok := raw.(types.String) + if !ok { + diags.AddError("Type Error", fmt.Sprintf("Expected types.String, got %T", raw)) + return nil, diags + } + + values := value.ValueString() + if values == "" { + continue + } + + currentMap := map[string]interface{}{} + if err := yaml.Unmarshal([]byte(values), ¤tMap); err != nil { + diags.AddError("Error unmarshaling values", fmt.Sprintf("---> %v %s", err, values)) + return nil, diags + } + + base = mergeMaps(base, currentMap) + } + + // Process "set" attribute + if !model.Set.IsNull() { + var setList []SetValue + setDiags := model.Set.ElementsAs(ctx, &setList, false) + diags.Append(setDiags...) + if diags.HasError() { + return nil, diags + } + + for _, set := range setList { + setDiags := applySetValue(base, set) + diags.Append(setDiags...) + if diags.HasError() { + return nil, diags + } + } + } + + // Process "set_list" attribute + if !model.SetList.IsUnknown() { + var setListSlice []SetListValue + setListDiags := model.SetList.ElementsAs(ctx, &setListSlice, false) + diags.Append(setListDiags...) + if diags.HasError() { + return nil, diags + } + + for _, setList := range setListSlice { + setListDiags := applySetListValue(ctx, base, setList) + diags.Append(setListDiags...) + if diags.HasError() { + return nil, diags + } + } + } + + // Process "set_sensitive" attribute + if !model.SetSensitive.IsNull() { + var setSensitiveList []SetSensitiveValue + setSensitiveDiags := model.SetSensitive.ElementsAs(ctx, &setSensitiveList, false) + diags.Append(setSensitiveDiags...) + if diags.HasError() { + return nil, diags + } + + for _, setSensitive := range setSensitiveList { + setSensitiveDiags := applySetSensitiveValue(base, setSensitive) + diags.Append(setSensitiveDiags...) + if diags.HasError() { + return nil, diags + } + } + } + + tflog.Debug(ctx, fmt.Sprintf("Final merged values: %v", base)) + logDiags := LogValuesModel(ctx, base, model) + diags.Append(logDiags...) + return base, diags +} + +func isTestHook(h *release.Hook) bool { + for _, e := range h.Events { + if e == release.HookTest { + return true + } + } + return false +} + +func chartPathOptionsModel(model *HelmTemplateModel, meta *Meta, cpo *action.ChartPathOptions) (*action.ChartPathOptions, string, diag.Diagnostics) { + var diags diag.Diagnostics + chartName := model.Chart.ValueString() + repository := model.Repository.ValueString() + + var repositoryURL string + if registry.IsOCI(repository) { + // LocateChart expects the chart name to contain the full OCI path + u, err := url.Parse(repository) + if err != nil { + diags.AddError("Invalid Repository URL", fmt.Sprintf("Failed to parse repository URL %s: %s", repository, err)) + return nil, "", diags + } + u.Path = pathpkg.Join(u.Path, chartName) + chartName = u.String() + } else { + var err error + repositoryURL, chartName, err = buildChartNameWithRepository(repository, strings.TrimSpace(chartName)) + if err != nil { + diags.AddError("Error building Chart Name With Repository", fmt.Sprintf("Could not build Chart Name With Repository %s and chart %s: %s", repository, chartName, err)) + return nil, "", diags + } + } + + version := getVersionModel(model) + + cpo.CaFile = model.RepositoryCaFile.ValueString() + cpo.CertFile = model.RepositoryCertFile.ValueString() + cpo.KeyFile = model.RepositoryKeyFile.ValueString() + cpo.Keyring = model.Keyring.ValueString() + cpo.RepoURL = repositoryURL + cpo.Verify = model.Verify.ValueBool() + if !useChartVersion(chartName, cpo.RepoURL) { + cpo.Version = version + } + cpo.Username = model.RepositoryUsername.ValueString() + cpo.Password = model.RepositoryPassword.ValueString() + cpo.PassCredentialsAll = model.PassCredentials.ValueBool() + + return cpo, chartName, diags +} + +func getVersionModel(model *HelmTemplateModel) string { + version := model.Version.ValueString() + if version == "" && model.Devel.ValueBool() { + return ">0.0.0-0" + } + return strings.TrimSpace(version) +} + +func getChartModel(ctx context.Context, model *HelmTemplateModel, meta *Meta, name string, cpo *action.ChartPathOptions) (*chart.Chart, string, diag.Diagnostics) { + var diags diag.Diagnostics + + tflog.Debug(ctx, fmt.Sprintf("Helm settings: %+v", meta.Settings)) + + path, err := cpo.LocateChart(name, meta.Settings) + if err != nil { + diags.AddError("Error locating chart", fmt.Sprintf("Unable to locate chart %s: %s", name, err)) + return nil, "", diags + } + + c, err := loader.Load(path) + if err != nil { + diags.AddError("Error loading chart", fmt.Sprintf("Unable to load chart %s: %s", path, err)) + return nil, "", diags + } + + return c, path, diags +} + +func checkChartDependenciesModel(ctx context.Context, model *HelmTemplateModel, c *chart.Chart, path string, meta *Meta) (bool, diag.Diagnostics) { + var diags diag.Diagnostics + p := getter.All(meta.Settings) + + if req := c.Metadata.Dependencies; req != nil { + err := action.CheckDependencies(c, req) + if err != nil { + if model.DependencyUpdate.ValueBool() { + man := &downloader.Manager{ + Out: os.Stdout, + ChartPath: path, + Keyring: model.Keyring.ValueString(), + SkipUpdate: false, + Getters: p, + RepositoryConfig: meta.Settings.RepositoryConfig, + RepositoryCache: meta.Settings.RepositoryCache, + Debug: meta.Settings.Debug, + } + tflog.Debug(ctx, "Downloading chart dependencies...") + if err := man.Update(); err != nil { + diags.AddError("Failed to update chart dependencies", fmt.Sprintf("Error: %s", err)) + return true, diags + } + return true, diags + } + diags.AddError("Missing chart dependencies", "Found in Chart.yaml, but missing in charts/ directory.") + return false, diags + } + } + tflog.Debug(ctx, "Chart dependencies are up to date.") + return false, diags +} + +func applySetValue(base map[string]interface{}, set SetValue) diag.Diagnostics { + var diags diag.Diagnostics + + name := set.Name.ValueString() + value := set.Value.ValueString() + valueType := set.Type.ValueString() + + switch valueType { + case "auto", "": + if err := strvals.ParseInto(fmt.Sprintf("%s=%s", name, value), base); err != nil { + diags.AddError("Failed parsing value", fmt.Sprintf("Key %q with value %s: %s", name, value, err)) + } + case "string": + if err := strvals.ParseIntoString(fmt.Sprintf("%s=%s", name, value), base); err != nil { + diags.AddError("Failed parsing string value", fmt.Sprintf("Key %q with value %s: %s", name, value, err)) + } + case "literal": + var literal interface{} + if err := yaml.Unmarshal([]byte(fmt.Sprintf("%s: %s", name, value)), &literal); err != nil { + diags.AddError("Failed parsing literal value", fmt.Sprintf("Key %q with literal value %s: %s", name, value, err)) + return diags + } + if m, ok := literal.(map[string]interface{}); ok { + base[name] = m[name] + } else { + base[name] = literal + } + default: + diags.AddError("Unexpected type", fmt.Sprintf("Unexpected type: %s", valueType)) + } + return diags +} + +func applySetListValue(ctx context.Context, base map[string]interface{}, setList SetListValue) diag.Diagnostics { + var diags diag.Diagnostics + + name := setList.Name.ValueString() + + if setList.Value.IsNull() { + diags.AddError("Null List Value", "The list value is null.") + return diags + } + + // Extract elements from the list value + elements := setList.Value.Elements() + + listStringArray := make([]string, 0, len(elements)) + for _, element := range elements { + if !element.IsNull() { + strValue := element.(types.String).ValueString() + listStringArray = append(listStringArray, strValue) + } + } + + listString := strings.Join(listStringArray, ",") + + // Parse the joined string into the base map + if err := strvals.ParseInto(fmt.Sprintf("%s={%s}", name, listString), base); err != nil { + diags.AddError("Error parsing list value", fmt.Sprintf("Failed parsing key %q with value %s: %s", name, listString, err)) + return diags + } + + return diags +} + +func applySetSensitiveValue(base map[string]interface{}, setSensitive SetSensitiveValue) diag.Diagnostics { + var diags diag.Diagnostics + + name := setSensitive.Name.ValueString() + value := setSensitive.Value.ValueString() + valueType := setSensitive.Type.ValueString() + + switch valueType { + case "auto", "": + if err := strvals.ParseInto(fmt.Sprintf("%s=%s", name, value), base); err != nil { + diags.AddError("Failed parsing sensitive value", fmt.Sprintf("Failed parsing key %q with value %s: %s", name, value, err)) + } + case "string": + if err := strvals.ParseIntoString(fmt.Sprintf("%s=%s", name, value), base); err != nil { + diags.AddError("Failed parsing sensitive string value", fmt.Sprintf("Failed parsing key %q with value %s: %s", name, value, err)) + } + default: + diags.AddError("Unexpected type", fmt.Sprintf("Unexpected type for sensitive value: %s", valueType)) + } + + return diags +} + +func LogValuesModel(ctx context.Context, values map[string]interface{}, state *HelmTemplateModel) diag.Diagnostics { + var diags diag.Diagnostics + + asJSON, err := json.Marshal(values) + if err != nil { + diags.AddError("Error marshaling values to JSON", fmt.Sprintf("Failed to marshal values to JSON: %s", err)) + return diags + } + + var clonedValues map[string]interface{} + err = json.Unmarshal(asJSON, &clonedValues) + if err != nil { + diags.AddError("Error unmarshaling JSON to map", fmt.Sprintf("Failed to unmarshal JSON to map: %s", err)) + return diags + } + + // Apply cloaking or masking for sensitive values + cloakSetValuesModel(clonedValues, state) + + // Convert the modified map to YAML for logging purposes + yamlData, err := yaml.Marshal(clonedValues) + if err != nil { + diags.AddError("Error marshaling map to YAML", fmt.Sprintf("Failed to marshal map to YAML: %s", err)) + return diags + } + + // Log the final YAML representation of the values + tflog.Debug(ctx, fmt.Sprintf("---[ values.yaml ]-----------------------------------\n%s\n", string(yamlData))) + + return diags +} + +func cloakSetValuesModel(config map[string]interface{}, state *HelmTemplateModel) { + if !state.SetSensitive.IsNull() { + var setSensitiveList []SetSensitiveValue + diags := state.SetSensitive.ElementsAs(context.Background(), &setSensitiveList, false) + if diags.HasError() { + tflog.Warn(context.Background(), "Error parsing SetSensitive elements", map[string]interface{}{ + "diagnostics": diags, + }) + return + } + + for _, set := range setSensitiveList { + cloakSetValueModel(config, set.Name.ValueString()) + } + } +} + +const sensitiveContentModelValue = "(sensitive value)" + +func cloakSetValueModel(values map[string]interface{}, valuePath string) { + pathKeys := strings.Split(valuePath, ".") + sensitiveKey := pathKeys[len(pathKeys)-1] + parentPathKeys := pathKeys[:len(pathKeys)-1] + + currentMap := values + for _, key := range parentPathKeys { + v, ok := currentMap[key].(map[string]interface{}) + if !ok { + return + } + currentMap = v + } + currentMap[sensitiveKey] = sensitiveContentModelValue +} diff --git a/shuttles/terraform/terraform-provider-helm/helm/data_helm_template_test.go b/shuttles/terraform/terraform-provider-helm/helm/data_helm_template_test.go new file mode 100644 index 0000000..c17d9f6 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/data_helm_template_test.go @@ -0,0 +1,379 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package helm + +import ( + "fmt" + "regexp" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +func TestAccDataTemplate_basic(t *testing.T) { + name := randName("basic") + namespace := randName(testNamespacePrefix) + + datasourceAddress := fmt.Sprintf("data.helm_template.%s", testResourceName) + + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: protoV6ProviderFactories(), + Steps: []resource.TestStep{{ + Config: testAccDataHelmTemplateConfigBasic(testResourceName, namespace, name, "1.2.3"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr(datasourceAddress, "manifests.%", "6"), + resource.TestCheckResourceAttrSet(datasourceAddress, "manifests.templates/deployment.yaml"), + resource.TestCheckResourceAttrSet(datasourceAddress, "manifests.templates/service.yaml"), + resource.TestCheckResourceAttrSet(datasourceAddress, "manifests.templates/serviceaccount.yaml"), + resource.TestCheckResourceAttrSet(datasourceAddress, "manifests.templates/configmaps.yaml"), + resource.TestCheckResourceAttrSet(datasourceAddress, "manifests.templates/secrets.yaml"), + resource.TestCheckResourceAttrSet(datasourceAddress, "manifests.templates/tests/test-connection.yaml"), + resource.TestCheckResourceAttrSet(datasourceAddress, "manifest"), + resource.TestCheckResourceAttrSet(datasourceAddress, "notes"), + ), + }}, + }) +} + +func TestAccDataTemplate_crds(t *testing.T) { + name := randName("basic") + namespace := randName(testNamespacePrefix) + + datasourceAddress := fmt.Sprintf("data.helm_template.%s", testResourceName) + + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: protoV6ProviderFactories(), + Steps: []resource.TestStep{{ + Config: testAccDataHelmTemplateCRDs(testResourceName, namespace, name, "1.2.3"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr(datasourceAddress, "manifests.%", "8"), + resource.TestCheckResourceAttrSet(datasourceAddress, "manifests.templates/deployment.yaml"), + resource.TestCheckResourceAttrSet(datasourceAddress, "manifests.templates/service.yaml"), + resource.TestCheckResourceAttrSet(datasourceAddress, "manifests.templates/serviceaccount.yaml"), + resource.TestCheckResourceAttrSet(datasourceAddress, "manifests.templates/configmaps.yaml"), + resource.TestCheckResourceAttrSet(datasourceAddress, "manifests.templates/tests/test-connection.yaml"), + resource.TestCheckResourceAttrSet(datasourceAddress, "manifest"), + resource.TestCheckResourceAttrSet(datasourceAddress, "notes"), + resource.TestCheckResourceAttr(datasourceAddress, "crds.0", `--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + # name must match the spec fields below, and be in the form: . + name: apples.stable.example.com +spec: + # group name to use for REST API: /apis// + group: stable.example.com + # list of versions supported by this CustomResourceDefinition + versions: + - name: v1 + # Each version can be enabled/disabled by Served flag. + served: true + # One and only one version must be marked as the storage version. + storage: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + cronSpec: + type: string + image: + type: string + replicas: + type: integer + # either Namespaced or Cluster + scope: Namespaced + names: + # plural name to be used in the URL: /apis/// + plural: apples + # singular name to be used as an alias on the CLI and for display + singular: apple + # kind is normally the CamelCased singular type. Your resource manifests use this. + kind: Apple + # shortNames allow shorter string to match your resource on the CLI + shortNames: + - ap +`), + resource.TestCheckResourceAttr(datasourceAddress, "crds.1", `--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + # name must match the spec fields below, and be in the form: . + name: oranges.stable.example.com +spec: + # group name to use for REST API: /apis// + group: stable.example.com + # list of versions supported by this CustomResourceDefinition + versions: + - name: v1 + # Each version can be enabled/disabled by Served flag. + served: true + # One and only one version must be marked as the storage version. + storage: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + cronSpec: + type: string + image: + type: string + replicas: + type: integer + # either Namespaced or Cluster + scope: Namespaced + names: + # plural name to be used in the URL: /apis/// + plural: oranges + # singular name to be used as an alias on the CLI and for display + singular: orange + # kind is normally the CamelCased singular type. Your resource manifests use this. + kind: Orange + # shortNames allow shorter string to match your resource on the CLI + shortNames: + - or +`), + ), + }}, + }) +} + +func TestAccDataTemplate_templates(t *testing.T) { + name := randName("basic") + namespace := randName(testNamespacePrefix) + + datasourceAddress := fmt.Sprintf("data.helm_template.%s", testResourceName) + expectedTemplate := fmt.Sprintf(`--- +# Source: test-chart/templates/configmaps.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: %[1]s-test-chart-one + labels: + helm.sh/chart: test-chart-1.2.3 + app.kubernetes.io/name: test-chart + app.kubernetes.io/instance: %[1]s + app.kubernetes.io/version: "1.19.5" + app.kubernetes.io/managed-by: Helm +data: + test: one +--- +# Source: test-chart/templates/configmaps.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: %[1]s-test-chart-two + labels: + helm.sh/chart: test-chart-1.2.3 + app.kubernetes.io/name: test-chart + app.kubernetes.io/instance: %[1]s + app.kubernetes.io/version: "1.19.5" + app.kubernetes.io/managed-by: Helm +data: + test: two +`, name) + + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: protoV6ProviderFactories(), + Steps: []resource.TestStep{{ + Config: testAccDataHelmTemplateConfigTemplates(testResourceName, namespace, name, "1.2.3"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr(datasourceAddress, "manifests.%", "1"), + resource.TestCheckResourceAttrSet(datasourceAddress, "manifest"), + resource.TestCheckResourceAttrSet(datasourceAddress, "notes"), + resource.TestCheckResourceAttr(datasourceAddress, "manifests.templates/configmaps.yaml", expectedTemplate), + ), + }}, + }) +} + +func TestAccDataTemplate_kubeVersion(t *testing.T) { + name := randName("kube-version") + namespace := randName(testNamespacePrefix) + + datasourceAddress := fmt.Sprintf("data.helm_template.%s", testResourceName) + + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: protoV6ProviderFactories(), + Steps: []resource.TestStep{{ + Config: testAccDataHelmTemplateKubeVersionNoVersionSet(testResourceName, namespace, name, "1.2.3"), + ExpectError: regexp.MustCompile("chart requires kubeVersion.*"), + }}, + }) + + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: protoV6ProviderFactories(), + Steps: []resource.TestStep{{ + Config: testAccDataHelmTemplateKubeVersion(testResourceName, namespace, name, "1.2.3", "1.18.0"), + ExpectError: regexp.MustCompile("chart requires kubeVersion.*"), + }}, + }) + + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: protoV6ProviderFactories(), + Steps: []resource.TestStep{{ + Config: testAccDataHelmTemplateKubeVersion(testResourceName, namespace, name, "1.2.3", "abcdef"), + ExpectError: regexp.MustCompile(`couldn't parse string "abcdef" into kube-version`), + }}, + }) + + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: protoV6ProviderFactories(), + Steps: []resource.TestStep{{ + Config: testAccDataHelmTemplateKubeVersion(testResourceName, namespace, name, "1.2.3", "1.22.0"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr(datasourceAddress, "manifests.%", "1"), + resource.TestCheckResourceAttrSet(datasourceAddress, "manifests.templates/deployment.yaml"), + resource.TestCheckResourceAttrSet(datasourceAddress, "manifest"), + ), + }}, + }) +} + +func TestAccDataTemplate_configSetNull(t *testing.T) { + name := randName("basic") + namespace := randName(testNamespacePrefix) + + datasourceAddress := fmt.Sprintf("data.helm_template.%s", testResourceName) + + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: protoV6ProviderFactories(), + Steps: []resource.TestStep{{ + Config: testAccDataHelmTemplateConfigNullSet(testResourceName, namespace, name, "1.2.3"), + Check: resource.ComposeAggregateTestCheckFunc( + checkResourceAttrNotSet(datasourceAddress, "set.0.value"), + checkResourceAttrNotSet(datasourceAddress, "set.1.value"), + ), + }}, + }) +} + +func testAccDataHelmTemplateConfigBasic(resource, ns, name, version string) string { + return fmt.Sprintf(` + data "helm_template" "%s" { + show_only = [""] + + name = %q + namespace = %q + description = "Test" + repository = %q + chart = "test-chart" + version = %q + + set = [ + { + name = "foo" + value = "bar" + }, + { + name = "fizz" + value = 1337 + } + ] + } + `, resource, name, ns, testRepositoryURL, version) +} + +func testAccDataHelmTemplateConfigTemplates(resource, ns, name, version string) string { + return fmt.Sprintf(` + data "helm_template" "%s" { + name = %q + namespace = %q + description = "Test" + repository = %q + chart = "test-chart" + version = %q + + set = [ + { + name = "foo" + value = "bar" + }, + { + name = "fizz" + value = 1337 + } + ] + + show_only = [ + "templates/configmaps.yaml", + "" + ] + } + `, resource, name, ns, testRepositoryURL, version) +} + +func testAccDataHelmTemplateConfigNullSet(resource, ns, name, version string) string { + return fmt.Sprintf(` + data "helm_template" "%s" { + name = %q + namespace = %q + description = "Test" + repository = %q + chart = "test-chart" + version = %q + + set = [ + { + name = "foo" + }, + { + name = "fizz" + value = null + } + ] + + show_only = [ + "templates/configmaps.yaml", + "" + ] + } + `, resource, name, ns, testRepositoryURL, version) +} + +func testAccDataHelmTemplateKubeVersion(resource, ns, name, version, kubeVersion string) string { + return fmt.Sprintf(` + data "helm_template" "%s" { + name = %q + namespace = %q + description = "Test" + repository = %q + chart = "kube-version" + version = %q + kube_version = %q + } + `, resource, name, ns, testRepositoryURL, version, kubeVersion) +} + +func testAccDataHelmTemplateKubeVersionNoVersionSet(resource, ns, name, version string) string { + return fmt.Sprintf(` + data "helm_template" "%s" { + name = %q + namespace = %q + description = "Test" + repository = %q + chart = "kube-version" + version = %q + } + `, resource, name, ns, testRepositoryURL, version) +} + +func testAccDataHelmTemplateCRDs(resource, ns, name, version string) string { + return fmt.Sprintf(` + data "helm_template" "%s" { + name = %q + namespace = %q + description = "Test" + repository = %q + chart = "crds-chart" + include_crds = true + version = %q + } + `, resource, name, ns, testRepositoryURL, version) +} diff --git a/shuttles/terraform/terraform-provider-helm/helm/kubeconfig.go b/shuttles/terraform/terraform-provider-helm/helm/kubeconfig.go new file mode 100644 index 0000000..8e17293 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/kubeconfig.go @@ -0,0 +1,237 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package helm + +import ( + "context" + "fmt" + "os" + "path/filepath" + "sync" + + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" + + "github.com/hashicorp/terraform-plugin-log/tflog" + "github.com/mitchellh/go-homedir" + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/discovery" + "k8s.io/client-go/discovery/cached/memory" + "k8s.io/client-go/rest" + "k8s.io/client-go/restmapper" + "k8s.io/client-go/tools/clientcmd" + clientcmdapi "k8s.io/client-go/tools/clientcmd/api" +) + +// Struct holding k8s client config, burst limit for api requests, and mutex for sync +type KubeConfig struct { + ClientConfig clientcmd.ClientConfig + Burst int + sync.Mutex +} + +// Converting KubeConfig to a REST config, which will be used to create k8s clients +func (k *KubeConfig) ToRESTConfig() (*rest.Config, error) { + config, err := k.ToRawKubeConfigLoader().ClientConfig() + return config, err +} + +// Converting KubeConfig to a discovery client, which will be used to find api resources +func (k *KubeConfig) ToDiscoveryClient() (discovery.CachedDiscoveryInterface, error) { + config, err := k.ToRESTConfig() + if err != nil { + return nil, err + } + + config.Burst = k.Burst + return memory.NewMemCacheClient(discovery.NewDiscoveryClientForConfigOrDie(config)), nil +} + +// Converting KubeConfig to a REST mapper, which will be used to map REST resources to their API obj +func (k *KubeConfig) ToRESTMapper() (meta.RESTMapper, error) { + discoveryClient, err := k.ToDiscoveryClient() + if err != nil { + return nil, err + } + + // Using the appropriate types for the arguments + mapper := restmapper.NewDeferredDiscoveryRESTMapper(discoveryClient) + + warningHandler := func(warning string) { + fmt.Printf("Warning: %s\n", warning) + } + + // Pass the warning handler to the NewShortcutExpander function + expander := restmapper.NewShortcutExpander(mapper, discoveryClient, warningHandler) + + return expander, nil +} + +// Function returning raw k8s client config +func (k *KubeConfig) ToRawKubeConfigLoader() clientcmd.ClientConfig { + return k.ClientConfig +} + +// Generates a k8s client config, based on providers settings and namespace, which this config will be used to interact with the k8s cluster +func (m *Meta) NewKubeConfig(ctx context.Context, namespace string) (*KubeConfig, error) { + overrides := &clientcmd.ConfigOverrides{} + loader := &clientcmd.ClientConfigLoadingRules{} + configPaths := []string{} + if m == nil || m.Data == nil || m.Data.Kubernetes.IsNull() || m.Data.Kubernetes.IsUnknown() { + return nil, fmt.Errorf("configuration error: missing required structural data") + } + + tflog.Debug(ctx, "Raw Kubernetes Data before conversion", map[string]interface{}{ + "KubernetesData": m.Data.Kubernetes, + }) + + // Needing to get the Kubernetes configuration as an obj + var kubernetesConfig KubernetesConfigModel + diags := m.Data.Kubernetes.As(ctx, &kubernetesConfig, basetypes.ObjectAsOptions{}) + if diags.HasError() { + for _, d := range diags { + tflog.Error(ctx, "Kubernetes config conversion error", map[string]interface{}{ + "summary": d.Summary(), + "detail": d.Detail(), + }) + } + return nil, fmt.Errorf("configuration error: unable to extract Kubernetes config") + } + // Check ConfigPath + if !kubernetesConfig.ConfigPath.IsNull() { + if v := kubernetesConfig.ConfigPath.ValueString(); v != "" { + configPaths = []string{v} + } + } + if !kubernetesConfig.ConfigPaths.IsNull() { + additionalPaths := expandStringSlice(kubernetesConfig.ConfigPaths.Elements()) + configPaths = append(configPaths, additionalPaths...) + } + if v := os.Getenv("KUBE_CONFIG_PATHS"); v != "" { + configPaths = filepath.SplitList(v) + } + tflog.Debug(ctx, "Initial configPaths", map[string]interface{}{"configPaths": configPaths}) + + if len(configPaths) > 0 { + expandedPaths := []string{} + for _, p := range configPaths { + path, err := homedir.Expand(p) + if err != nil { + tflog.Error(ctx, "Error expanding home directory", map[string]interface{}{ + "path": p, + "error": err, + }) + return nil, err + } + expandedPaths = append(expandedPaths, path) + } + if len(expandedPaths) == 1 { + loader.ExplicitPath = expandedPaths[0] + } else { + loader.Precedence = expandedPaths + } + + // Check ConfigContext + if !kubernetesConfig.ConfigContext.IsNull() { + overrides.CurrentContext = kubernetesConfig.ConfigContext.ValueString() + } + if !kubernetesConfig.ConfigContextAuthInfo.IsNull() { + overrides.Context.AuthInfo = kubernetesConfig.ConfigContextAuthInfo.ValueString() + } + if !kubernetesConfig.ConfigContextCluster.IsNull() { + overrides.Context.Cluster = kubernetesConfig.ConfigContextCluster.ValueString() + } + } + + // Check and assign remaining fields + if !kubernetesConfig.Insecure.IsNull() { + overrides.ClusterInfo.InsecureSkipTLSVerify = kubernetesConfig.Insecure.ValueBool() + } + if !kubernetesConfig.TLSServerName.IsNull() { + overrides.ClusterInfo.TLSServerName = kubernetesConfig.TLSServerName.ValueString() + } + if !kubernetesConfig.ClusterCACertificate.IsNull() { + overrides.ClusterInfo.CertificateAuthorityData = []byte(kubernetesConfig.ClusterCACertificate.ValueString()) + } + if !kubernetesConfig.ClientCertificate.IsNull() { + overrides.AuthInfo.ClientCertificateData = []byte(kubernetesConfig.ClientCertificate.ValueString()) + } + if !kubernetesConfig.Host.IsNull() && kubernetesConfig.Host.ValueString() != "" { + hasCA := len(overrides.ClusterInfo.CertificateAuthorityData) != 0 + hasCert := len(overrides.AuthInfo.ClientCertificateData) != 0 + defaultTLS := hasCA || hasCert || overrides.ClusterInfo.InsecureSkipTLSVerify + host, _, err := rest.DefaultServerURL(kubernetesConfig.Host.ValueString(), "", schema.GroupVersion{}, defaultTLS) + if err != nil { + return nil, err + } + overrides.ClusterInfo.Server = host.String() + } + + if !kubernetesConfig.Username.IsNull() { + overrides.AuthInfo.Username = kubernetesConfig.Username.ValueString() + } + if !kubernetesConfig.Password.IsNull() { + overrides.AuthInfo.Password = kubernetesConfig.Password.ValueString() + } + if !kubernetesConfig.ClientKey.IsNull() { + overrides.AuthInfo.ClientKeyData = []byte(kubernetesConfig.ClientKey.ValueString()) + } + if !kubernetesConfig.Token.IsNull() { + overrides.AuthInfo.Token = kubernetesConfig.Token.ValueString() + } + if !kubernetesConfig.ProxyURL.IsNull() { + overrides.ClusterDefaults.ProxyURL = kubernetesConfig.ProxyURL.ValueString() + } + + if kubernetesConfig.Exec != nil { + execConfig := kubernetesConfig.Exec + if !execConfig.APIVersion.IsNull() && !execConfig.Command.IsNull() { + args := []string{} + if !execConfig.Args.IsNull() && !execConfig.Args.IsUnknown() { + args = expandStringSlice(execConfig.Args.Elements()) + } + + env := []clientcmdapi.ExecEnvVar{} + if !execConfig.Env.IsNull() && !execConfig.Env.IsUnknown() { + for k, v := range execConfig.Env.Elements() { + env = append(env, clientcmdapi.ExecEnvVar{ + Name: k, + Value: v.(types.String).ValueString(), + }) + } + } + + overrides.AuthInfo.Exec = &clientcmdapi.ExecConfig{ + APIVersion: execConfig.APIVersion.ValueString(), + Command: execConfig.Command.ValueString(), + Args: args, + Env: env, + InteractiveMode: clientcmdapi.IfAvailableExecInteractiveMode, + } + } + } + + overrides.Context.Namespace = "default" + if namespace != "" { + overrides.Context.Namespace = namespace + } + + burstLimit := int(m.Data.BurstLimit.ValueInt64()) + client := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loader, overrides) + if client == nil { + return nil, fmt.Errorf("failed to initialize kubernetes config") + } + tflog.Info(ctx, "Successfully initialized kubernetes config") + return &KubeConfig{ClientConfig: client, Burst: burstLimit}, nil +} + +func expandStringSlice(input []attr.Value) []string { + result := make([]string, len(input)) + for i, v := range input { + result[i] = v.(types.String).ValueString() + } + return result +} diff --git a/shuttles/terraform/terraform-provider-helm/helm/manifest_json.go b/shuttles/terraform/terraform-provider-helm/helm/manifest_json.go new file mode 100644 index 0000000..99c046a --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/manifest_json.go @@ -0,0 +1,95 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package helm + +import ( + "encoding/json" + "fmt" + "strings" + + "golang.org/x/crypto/sha3" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/yaml" + + "helm.sh/helm/v3/pkg/releaseutil" +) + +type resourceMeta struct { + metav1.TypeMeta + Metadata metav1.ObjectMeta +} + +func convertYAMLManifestToJSON(manifest string) (string, error) { + m := map[string]json.RawMessage{} + + resources := releaseutil.SplitManifests(manifest) + for _, resource := range resources { + jsonbytes, err := yaml.YAMLToJSON([]byte(resource)) + if err != nil { + return "", fmt.Errorf("could not convert manifest to JSON: %v", err) + } + + resourceMeta := resourceMeta{} + err = yaml.Unmarshal([]byte(resource), &resourceMeta) + if err != nil { + return "", err + } + + gvk := resourceMeta.GetObjectKind().GroupVersionKind() + key := fmt.Sprintf("%s/%s/%s", strings.ToLower(gvk.GroupKind().String()), + resourceMeta.APIVersion, + resourceMeta.Metadata.Name) + + if namespace := resourceMeta.Metadata.Namespace; namespace != "" { + key = fmt.Sprintf("%s/%s", namespace, key) + } + + if gvk.Kind == "Secret" { + secret := corev1.Secret{} + err = yaml.Unmarshal([]byte(resource), &secret) + if err != nil { + return "", err + } + + for k, v := range secret.Data { + h := hashSensitiveValue(string(v)) + secret.Data[k] = []byte(h) + } + + jsonbytes, err = json.Marshal(secret) + if err != nil { + return "", err + } + } + + m[key] = jsonbytes + } + + b, err := json.Marshal(m) + if err != nil { + return "", err + } + + return string(b), nil +} + +func hashSensitiveValue(v string) string { + hash := make([]byte, 8) + sha3.ShakeSum256(hash, []byte(v)) + return fmt.Sprintf("(sensitive value %x)", hash) +} + +// redactSensitiveValues removes values that appear in `set_sensitive` blocks from the manifest JSON +func redactSensitiveValues(text string, sensitiveValues map[string]string) string { + masked := text + + for originalValue := range sensitiveValues { + hashedValue := hashSensitiveValue(originalValue) + masked = strings.ReplaceAll(masked, originalValue, hashedValue) + } + + return masked +} diff --git a/shuttles/terraform/terraform-provider-helm/helm/manifest_json_test.go b/shuttles/terraform/terraform-provider-helm/helm/manifest_json_test.go new file mode 100644 index 0000000..63e2130 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/manifest_json_test.go @@ -0,0 +1,29 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package helm + +import ( + "io/ioutil" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestConvertYAMLManifestToJSON(t *testing.T) { + yamlManifest := readTestFile(t, "testdata/manifest_json/rendered_manifest.yaml") + expectedJSON := readTestFile(t, "testdata/manifest_json/rendered_manifest.json") + + json, err := convertYAMLManifestToJSON(yamlManifest) + + assert.NoError(t, err) + assert.JSONEq(t, expectedJSON, json) +} + +func readTestFile(t *testing.T, path string) string { + b, err := ioutil.ReadFile(path) + if err != nil { + t.Fatalf(err.Error()) + } + return string(b) +} diff --git a/shuttles/terraform/terraform-provider-helm/helm/provider.go b/shuttles/terraform/terraform-provider-helm/helm/provider.go new file mode 100644 index 0000000..3bc02b0 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/provider.go @@ -0,0 +1,701 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package helm + +import ( + "context" + "fmt" + "net/url" + "os" + "path/filepath" + "strconv" + "strings" + "sync" + + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/provider" + "github.com/hashicorp/terraform-plugin-framework/provider/schema" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-log/tflog" + "helm.sh/helm/v3/pkg/action" + "helm.sh/helm/v3/pkg/cli" + "helm.sh/helm/v3/pkg/registry" + "helm.sh/helm/v3/pkg/storage/driver" +) + +var _ provider.Provider = &HelmProvider{} + +func New(version string) func() provider.Provider { + return func() provider.Provider { + return &HelmProvider{ + version: version, + } + } +} + +// Meta contains the client configuration for the provider +type Meta struct { + providerData *HelmProvider + Data *HelmProviderModel + Settings *cli.EnvSettings + RegistryClient *registry.Client + HelmDriver string + // Experimental feature toggles + Experiments map[string]bool + Mutex sync.Mutex +} + +// HelmProviderModel contains the configuration for the provider +type HelmProviderModel struct { + Debug types.Bool `tfsdk:"debug"` + PluginsPath types.String `tfsdk:"plugins_path"` + RegistryConfigPath types.String `tfsdk:"registry_config_path"` + RepositoryConfigPath types.String `tfsdk:"repository_config_path"` + RepositoryCache types.String `tfsdk:"repository_cache"` + HelmDriver types.String `tfsdk:"helm_driver"` + BurstLimit types.Int64 `tfsdk:"burst_limit"` + Kubernetes types.Object `tfsdk:"kubernetes"` + Registries types.List `tfsdk:"registries"` + Experiments *ExperimentsConfigModel `tfsdk:"experiments"` +} + +// ExperimentsConfigModel configures the experiments that are enabled or disabled +type ExperimentsConfigModel struct { + Manifest types.Bool `tfsdk:"manifest"` +} + +// RegistryConfigModel configures an OCI registry +type RegistryConfigModel struct { + URL types.String `tfsdk:"url"` + Username types.String `tfsdk:"username"` + Password types.String `tfsdk:"password"` +} + +// KubernetesConfigModel configures a Kubernetes client +type KubernetesConfigModel struct { + Host types.String `tfsdk:"host"` + Username types.String `tfsdk:"username"` + Password types.String `tfsdk:"password"` + Insecure types.Bool `tfsdk:"insecure"` + TLSServerName types.String `tfsdk:"tls_server_name"` + ClientCertificate types.String `tfsdk:"client_certificate"` + ClientKey types.String `tfsdk:"client_key"` + ClusterCACertificate types.String `tfsdk:"cluster_ca_certificate"` + ConfigPaths types.List `tfsdk:"config_paths"` + ConfigPath types.String `tfsdk:"config_path"` + ConfigContext types.String `tfsdk:"config_context"` + ConfigContextAuthInfo types.String `tfsdk:"config_context_auth_info"` + ConfigContextCluster types.String `tfsdk:"config_context_cluster"` + Token types.String `tfsdk:"token"` + ProxyURL types.String `tfsdk:"proxy_url"` + Exec *ExecConfigModel `tfsdk:"exec"` +} + +// ExecConfigModel configures an external command to configure the Kubernetes client +type ExecConfigModel struct { + APIVersion types.String `tfsdk:"api_version"` + Command types.String `tfsdk:"command"` + Env types.Map `tfsdk:"env"` + Args types.List `tfsdk:"args"` +} + +// HelmProvider is the top level provider struct +type HelmProvider struct { + meta *Meta + version string +} + +func (p *HelmProvider) Metadata(ctx context.Context, req provider.MetadataRequest, resp *provider.MetadataResponse) { + resp.TypeName = "helm" + resp.Version = p.version +} + +// /////////////////////// START OF SCHEMA CREATION /////////////////////////////// +// Defines attributes that are avaiable in the provider +func (p *HelmProvider) Schema(ctx context.Context, req provider.SchemaRequest, resp *provider.SchemaResponse) { + resp.Schema = schema.Schema{ + Description: "Schema to define attributes that are available in the provider", + Attributes: map[string]schema.Attribute{ + "debug": schema.BoolAttribute{ + Description: "Debug indicates whether or not Helm is running in Debug mode.", + Optional: true, + }, + "plugins_path": schema.StringAttribute{ + Description: "The path to the helm plugins directory", + Optional: true, + }, + "registry_config_path": schema.StringAttribute{ + Description: "The path to the registry config file", + Optional: true, + }, + "repository_config_path": schema.StringAttribute{ + Description: "The path to the file containing repository names and URLs", + Optional: true, + }, + "repository_cache": schema.StringAttribute{ + Description: "The path to the file containing cached repository indexes", + Optional: true, + }, + "helm_driver": schema.StringAttribute{ + Description: "The backend storage driver. Values are: configmap, secret, memory, sql", + Optional: true, + Validators: []validator.String{ + stringvalidator.OneOf(strings.ToLower(driver.MemoryDriverName), + strings.ToLower(driver.ConfigMapsDriverName), + strings.ToLower(driver.SecretsDriverName), + strings.ToLower(driver.SQLDriverName)), + }, + }, + + "burst_limit": schema.Int64Attribute{ + Optional: true, + Description: "Helm burst limit. Increase this if you have a cluster with many CRDs", + }, + "kubernetes": schema.SingleNestedAttribute{ + Optional: true, + Description: "Kubernetes Configuration", + Attributes: kubernetesResourceSchema(), + }, + "registries": schema.ListNestedAttribute{ + Optional: true, + Description: "RegistryClient configuration.", + NestedObject: schema.NestedAttributeObject{ + Attributes: registriesResourceSchema(), + }, + }, + "experiments": schema.SingleNestedAttribute{ + Optional: true, + Description: "Enable and disable experimental features.", + Attributes: experimentsSchema(), + }, + }, + } +} + +func experimentsSchema() map[string]schema.Attribute { + return map[string]schema.Attribute{ + "manifest": schema.BoolAttribute{ + Optional: true, + Description: "Enable full diff by storing the rendered manifest in the state.", + }, + } +} + +func registriesResourceSchema() map[string]schema.Attribute { + return map[string]schema.Attribute{ + "url": schema.StringAttribute{ + Required: true, + Description: "OCI URL in form of oci://host:port or oci://host", + }, + "username": schema.StringAttribute{ + Required: true, + Description: "The username to use for the OCI HTTP basic authentication when accessing the Kubernetes master endpoint.", + }, + "password": schema.StringAttribute{ + Required: true, + Description: "The password to use for the OCI HTTP basic authentication when accessing the Kubernetes master endpoint.", + }, + } +} + +func kubernetesResourceSchema() map[string]schema.Attribute { + return map[string]schema.Attribute{ + "host": schema.StringAttribute{ + Optional: true, + Description: "The hostname (in form of URI) of kubernetes master", + }, + "username": schema.StringAttribute{ + Optional: true, + Description: "The username to use for HTTP basic authentication when accessing the Kubernetes master endpoint", + }, + "password": schema.StringAttribute{ + Optional: true, + Description: "The password to use for HTTP basic authentication when accessing the Kubernetes master endpoint.", + }, + "insecure": schema.BoolAttribute{ + Optional: true, + Description: "Whether server should be accessed without verifying the TLS certificate.", + }, + "tls_server_name": schema.StringAttribute{ + Optional: true, + Description: "Server name passed to the server for SNI and is used in the client to check server certificates against.", + }, + "client_certificate": schema.StringAttribute{ + Optional: true, + Description: "PEM-encoded client certificate for TLS authentication.", + }, + "client_key": schema.StringAttribute{ + Optional: true, + Description: "PEM-encoded client certificate key for TLS authentication.", + }, + "cluster_ca_certificate": schema.StringAttribute{ + Optional: true, + Description: "PEM-encoded root certificates bundle for TLS authentication.", + }, + "config_paths": schema.ListAttribute{ + Optional: true, + ElementType: types.StringType, + Description: "A list of paths to kube config files. Can be set with KUBE_CONFIG_PATHS environment variable.", + }, + "config_path": schema.StringAttribute{ + Optional: true, + Description: "Path to the kube config file. Can be set with KUBE_CONFIG_PATH.", + Validators: []validator.String{ + stringvalidator.ConflictsWith( + path.Root("kubernetes").AtName("config_paths").Expression(), + ), + }, + }, + + "config_context": schema.StringAttribute{ + Optional: true, + Description: "Context to choose from the config file. Can be sourced from KUBE_CTX.", + }, + "config_context_auth_info": schema.StringAttribute{ + Optional: true, + Description: "Authentication info context of the kube config (name of the kubeconfig user, --user flag in kubectl). Can be sourced from KUBE_CTX_AUTH_INFO.", + }, + "config_context_cluster": schema.StringAttribute{ + Optional: true, + Description: "Cluster context of the kube config (name of the kubeconfig cluster, --cluster flag in kubectl). Can be sourced from KUBE_CTX_CLUSTER.", + }, + "token": schema.StringAttribute{ + Optional: true, + Description: "Token to authenticate a service account.", + }, + "proxy_url": schema.StringAttribute{ + Optional: true, + Description: "URL to the proxy to be used for all API requests.", + }, + "exec": schema.SingleNestedAttribute{ + Optional: true, + Description: "Exec configuration for Kubernetes authentication", + Attributes: execSchema(), + }, + } +} + +func execSchema() map[string]schema.Attribute { + return map[string]schema.Attribute{ + "api_version": schema.StringAttribute{ + Required: true, + Description: "API version for the exec plugin.", + }, + "command": schema.StringAttribute{ + Required: true, + Description: "Command to run for Kubernetes exec plugin", + }, + "env": schema.MapAttribute{ + Optional: true, + ElementType: types.StringType, + Description: "Environment variables for the exec plugin", + }, + "args": schema.ListAttribute{ + Optional: true, + ElementType: types.StringType, + Description: "Arguments for the exec plugin", + }, + } +} + +func execSchemaAttrTypes() map[string]attr.Type { + return map[string]attr.Type{ + "api_version": types.StringType, + "command": types.StringType, + "args": types.ListType{ElemType: types.StringType}, + "env": types.MapType{ElemType: types.StringType}, + } +} + +///////////////////// END OF SCHEMA CREATION /////////////////////////////// + +// Setting up the provider, anything we need to get the provider running, probbaly authentication. like the api +func (p *HelmProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) { + if req.ClientCapabilities.DeferralAllowed && !req.Config.Raw.IsFullyKnown() { + resp.Deferred = &provider.Deferred{ + Reason: provider.DeferredReasonProviderConfigUnknown, + } + } + + pluginsPath := os.Getenv("HELM_PLUGINS_PATH") + registryConfigPath := os.Getenv("HELM_REGISTRY_CONFIG_PATH") + repositoryConfigPath := os.Getenv("HELM_REPOSITORY_CONFIG_PATH") + repositoryCache := os.Getenv("HELM_REPOSITORY_CACHE") + helmDriver := os.Getenv("HELM_DRIVER") + burstLimitStr := os.Getenv("HELM_BURST_LIMIT") + kubeHost := os.Getenv("KUBE_HOST") + kubeUser := os.Getenv("KUBE_USER") + kubePassword := os.Getenv("KUBE_PASSWORD") + kubeInsecureStr := os.Getenv("KUBE_INSECURE") + kubeTLSServerName := os.Getenv("KUBE_TLS_SERVER_NAME") + kubeClientCert := os.Getenv("KUBE_CLIENT_CERT_DATA") + kubeClientKey := os.Getenv("KUBE_CLIENT_KEY_DATA") + kubeCaCert := os.Getenv("KUBE_CLUSTER_CA_CERT_DATA") + kubeConfigPaths := os.Getenv("KUBE_CONFIG_PATHS") + kubeConfigPath := os.Getenv("KUBE_CONFIG_PATH") + kubeConfigContext := os.Getenv("KUBE_CTX") + kubeConfigContextAuthInfo := os.Getenv("KUBE_CTX_AUTH_INFO") + kubeConfigContextCluster := os.Getenv("KUBE_CTX_CLUSTER") + kubeToken := os.Getenv("KUBE_TOKEN") + kubeProxy := os.Getenv("KUBE_PROXY") + + // Initialize the HelmProviderModel with values from the config + var config HelmProviderModel + diags := req.Config.Get(ctx, &config) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + if !config.PluginsPath.IsNull() { + pluginsPath = config.PluginsPath.ValueString() + } + if !config.RegistryConfigPath.IsNull() { + registryConfigPath = config.RegistryConfigPath.ValueString() + } + if !config.RepositoryConfigPath.IsNull() { + repositoryConfigPath = config.RepositoryConfigPath.ValueString() + } + if !config.RepositoryCache.IsNull() { + repositoryCache = config.RepositoryCache.ValueString() + } + if !config.HelmDriver.IsNull() { + helmDriver = config.HelmDriver.ValueString() + } + var burstLimit int64 + if burstLimitStr != "" { + var err error + burstLimit, err = strconv.ParseInt(burstLimitStr, 10, 64) + if err != nil { + resp.Diagnostics.AddError( + "Invalid burst limit", + fmt.Sprintf("Invalid burst limit value: %s", burstLimitStr), + ) + return + } + } + if !config.BurstLimit.IsNull() { + burstLimit = config.BurstLimit.ValueInt64() + } + var kubeInsecure bool + if kubeInsecureStr != "" { + var err error + kubeInsecure, err = strconv.ParseBool(kubeInsecureStr) + if err != nil { + resp.Diagnostics.AddError( + "Invalid insecure value", + fmt.Sprintf("Invalid insecure value: %s", kubeInsecureStr), + ) + return + } + } + + var kubernetesConfig KubernetesConfigModel + if !config.Kubernetes.IsNull() && !config.Kubernetes.IsUnknown() { + diags := req.Config.GetAttribute(ctx, path.Root("kubernetes"), &kubernetesConfig) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + } + + if !kubernetesConfig.Insecure.IsNull() { + kubeInsecure = kubernetesConfig.Insecure.ValueBool() + } + var kubeConfigPathsList []attr.Value + if !kubernetesConfig.Host.IsNull() { + kubeHost = kubernetesConfig.Host.ValueString() + } + if !kubernetesConfig.Username.IsNull() { + kubeUser = kubernetesConfig.Username.ValueString() + } + if !kubernetesConfig.Password.IsNull() { + kubePassword = kubernetesConfig.Password.ValueString() + } + if !kubernetesConfig.TLSServerName.IsNull() { + kubeTLSServerName = kubernetesConfig.TLSServerName.ValueString() + } + if !kubernetesConfig.ClientCertificate.IsNull() { + kubeClientCert = kubernetesConfig.ClientCertificate.ValueString() + } + if !kubernetesConfig.ClientKey.IsNull() { + kubeClientKey = kubernetesConfig.ClientKey.ValueString() + } + if !kubernetesConfig.ClusterCACertificate.IsNull() { + kubeCaCert = kubernetesConfig.ClusterCACertificate.ValueString() + } + if kubeConfigPaths != "" { + for _, path := range filepath.SplitList(kubeConfigPaths) { + kubeConfigPathsList = append(kubeConfigPathsList, types.StringValue(path)) + } + } + if !kubernetesConfig.ConfigPaths.IsNull() { + var paths []string + diags = kubernetesConfig.ConfigPaths.ElementsAs(ctx, &paths, false) + resp.Diagnostics.Append(diags...) + for _, path := range paths { + kubeConfigPathsList = append(kubeConfigPathsList, types.StringValue(path)) + } + } + if !kubernetesConfig.ConfigPath.IsNull() { + kubeConfigPath = kubernetesConfig.ConfigPath.ValueString() + } + if !kubernetesConfig.ConfigContext.IsNull() { + kubeConfigContext = kubernetesConfig.ConfigContext.ValueString() + } + if !kubernetesConfig.ConfigContextAuthInfo.IsNull() { + kubeConfigContextAuthInfo = kubernetesConfig.ConfigContextAuthInfo.ValueString() + } + if !kubernetesConfig.ConfigContextCluster.IsNull() { + kubeConfigContextCluster = kubernetesConfig.ConfigContextCluster.ValueString() + } + if !kubernetesConfig.Token.IsNull() { + kubeToken = kubernetesConfig.Token.ValueString() + } + if !kubernetesConfig.ProxyURL.IsNull() { + kubeProxy = kubernetesConfig.ProxyURL.ValueString() + } + tflog.Debug(ctx, "Config values after overrides", map[string]interface{}{ + "config": config, + }) + debug := os.Getenv("HELM_DEBUG") == "true" || config.Debug.ValueBool() + settings := cli.New() + settings.Debug = debug + if pluginsPath != "" { + settings.PluginsDirectory = pluginsPath + } + if registryConfigPath != "" { + settings.RegistryConfig = registryConfigPath + } + if repositoryConfigPath != "" { + settings.RepositoryConfig = repositoryConfigPath + } + if repositoryCache != "" { + settings.RepositoryCache = repositoryCache + } + tflog.Debug(ctx, "Helm settings initialized", map[string]interface{}{ + "settings": settings, + }) + kubeConfigPathsListValue, diags := types.ListValue(types.StringType, kubeConfigPathsList) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + manifestExperiment := false + if config.Experiments != nil { + manifestExperiment = config.Experiments.Manifest.ValueBool() + } + + var execAttrValue attr.Value = types.ObjectNull(execSchemaAttrTypes()) + + if kubernetesConfig.Exec != nil { + // Check if `api_version` and `command` are set (since they're required fields) + if !kubernetesConfig.Exec.APIVersion.IsNull() && !kubernetesConfig.Exec.Command.IsNull() { + execAttrValue = types.ObjectValueMust(execSchemaAttrTypes(), map[string]attr.Value{ + "api_version": types.StringValue(kubernetesConfig.Exec.APIVersion.ValueString()), + "command": types.StringValue(kubernetesConfig.Exec.Command.ValueString()), + "args": types.ListValueMust(types.StringType, kubernetesConfig.Exec.Args.Elements()), + "env": types.MapValueMust(types.StringType, kubernetesConfig.Exec.Env.Elements()), + }) + } + } + + kubernetesConfigObjectValue, diags := types.ObjectValue(map[string]attr.Type{ + "host": types.StringType, + "username": types.StringType, + "password": types.StringType, + "insecure": types.BoolType, + "tls_server_name": types.StringType, + "client_certificate": types.StringType, + "client_key": types.StringType, + "cluster_ca_certificate": types.StringType, + "config_paths": types.ListType{ElemType: types.StringType}, + "config_path": types.StringType, + "config_context": types.StringType, + "config_context_auth_info": types.StringType, + "config_context_cluster": types.StringType, + "token": types.StringType, + "proxy_url": types.StringType, + "exec": types.ObjectType{AttrTypes: execSchemaAttrTypes()}, + }, map[string]attr.Value{ + "host": types.StringValue(kubeHost), + "username": types.StringValue(kubeUser), + "password": types.StringValue(kubePassword), + "insecure": types.BoolValue(kubeInsecure), + "tls_server_name": types.StringValue(kubeTLSServerName), + "client_certificate": types.StringValue(kubeClientCert), + "client_key": types.StringValue(kubeClientKey), + "cluster_ca_certificate": types.StringValue(kubeCaCert), + "config_paths": kubeConfigPathsListValue, + "config_path": types.StringValue(kubeConfigPath), + "config_context": types.StringValue(kubeConfigContext), + "config_context_auth_info": types.StringValue(kubeConfigContextAuthInfo), + "config_context_cluster": types.StringValue(kubeConfigContextCluster), + "token": types.StringValue(kubeToken), + "proxy_url": types.StringValue(kubeProxy), + "exec": execAttrValue, + }) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + meta := &Meta{ + Data: &HelmProviderModel{ + Debug: types.BoolValue(debug), + PluginsPath: types.StringValue(pluginsPath), + RegistryConfigPath: types.StringValue(registryConfigPath), + RepositoryConfigPath: types.StringValue(repositoryConfigPath), + RepositoryCache: types.StringValue(repositoryCache), + HelmDriver: types.StringValue(helmDriver), + BurstLimit: types.Int64Value(burstLimit), + Kubernetes: kubernetesConfigObjectValue, + Experiments: &ExperimentsConfigModel{ + Manifest: types.BoolValue(manifestExperiment), + }, + }, + Settings: settings, + HelmDriver: helmDriver, + Experiments: map[string]bool{ + "manifest": manifestExperiment, + }, + } + registryClient, err := registry.NewClient() + if err != nil { + resp.Diagnostics.AddError( + "Registry client initialization failed", + fmt.Sprintf("Unable to create Helm registry client: %s", err), + ) + return + } + + meta.RegistryClient = registryClient + if !config.Registries.IsUnknown() { + var registryConfigs []RegistryConfigModel + diags := config.Registries.ElementsAs(ctx, ®istryConfigs, false) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + for _, r := range registryConfigs { + if r.URL.IsNull() || r.Username.IsNull() || r.Password.IsNull() { + resp.Diagnostics.AddError( + "OCI Registry login failed", + "Registry URL, Username, or Password is null", + ) + return + } + + err := OCIRegistryPerformLogin(ctx, meta, meta.RegistryClient, r.URL.ValueString(), r.Username.ValueString(), r.Password.ValueString()) + if err != nil { + resp.Diagnostics.AddError( + "OCI Registry login failed", + err.Error(), + ) + return + } + } + } else { + tflog.Debug(ctx, "No registry configurations found") + } + resp.DataSourceData = meta + resp.ResourceData = meta + + tflog.Debug(ctx, "Configure method completed successfully") +} + +func (p *HelmProvider) DataSources(ctx context.Context) []func() datasource.DataSource { + return []func() datasource.DataSource{ + NewHelmTemplate, + } +} + +func (p *HelmProvider) Resources(ctx context.Context) []func() resource.Resource { + return []func() resource.Resource{ + NewHelmRelease, + } +} + +func OCIRegistryLogin(ctx context.Context, meta *Meta, actionConfig *action.Configuration, registryClient *registry.Client, repository, chartName, username, password string) diag.Diagnostics { + var diags diag.Diagnostics + + actionConfig.RegistryClient = registryClient + + var ociURL string + if registry.IsOCI(repository) { + ociURL = repository + } else if registry.IsOCI(chartName) { + ociURL = chartName + } + + if ociURL == "" { + return diags + } + + if username != "" && password != "" { + err := OCIRegistryPerformLogin(ctx, meta, registryClient, ociURL, username, password) + if err != nil { + diags.AddError( + "OCI Registry Login Failed", + fmt.Sprintf("Failed to log in to OCI registry %q: %s", ociURL, err.Error()), + ) + } + } + + return diags +} + +// registryClient = client used to comm with the registry, oci urls, un, and pw used for authentication +func OCIRegistryPerformLogin(ctx context.Context, meta *Meta, registryClient *registry.Client, ociURL, username, password string) error { + loggedInOCIRegistries := make(map[string]string) + // getting the oci url, and extracting the host. + u, err := url.Parse(ociURL) + if err != nil { + return fmt.Errorf("could not parse OCI registry URL: %v", err) + } + meta.Mutex.Lock() + defer meta.Mutex.Unlock() + if _, ok := loggedInOCIRegistries[u.Host]; ok { + tflog.Info(ctx, fmt.Sprintf("Already logged into OCI registry %q", u.Host)) + return nil + } + // Now we perform the login, with the provided username and password by calling the login method + err = registryClient.Login(u.Host, registry.LoginOptBasicAuth(username, password)) + if err != nil { + return fmt.Errorf("could not login to OCI registry %q: %v", u.Host, err) + } + loggedInOCIRegistries[u.Host] = "" + tflog.Info(ctx, fmt.Sprintf("Logged into OCI registry %q", u.Host)) + return nil +} + +// GetHelmConfiguration retrieves the Helm configuration for a given namespace +func (m *Meta) GetHelmConfiguration(ctx context.Context, namespace string) (*action.Configuration, error) { + if m == nil { + tflog.Error(ctx, "Meta is nil") + return nil, fmt.Errorf("Meta is nil") + } + + tflog.Info(context.Background(), "[INFO] GetHelmConfiguration start") + actionConfig := new(action.Configuration) + kc, err := m.NewKubeConfig(ctx, namespace) + if err != nil { + return nil, err + } + if err := actionConfig.Init(kc, namespace, m.HelmDriver, func(format string, v ...interface{}) { + tflog.Info(context.Background(), fmt.Sprintf(format, v...)) + }); err != nil { + return nil, err + } + tflog.Info(context.Background(), "[INFO] GetHelmConfiguration success") + // returning the initializing action.Configuration object + return actionConfig, nil +} diff --git a/shuttles/terraform/terraform-provider-helm/helm/provider_test.go b/shuttles/terraform/terraform-provider-helm/helm/provider_test.go new file mode 100644 index 0000000..d9157f4 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/provider_test.go @@ -0,0 +1,350 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package helm + +import ( + "context" + "fmt" + "io/ioutil" + "log" + "net" + "net/http" + "os" + "os/exec" + "path/filepath" + "sync" + "testing" + + "github.com/hashicorp/terraform-plugin-framework/provider" + "github.com/hashicorp/terraform-plugin-framework/providerserver" + "github.com/hashicorp/terraform-plugin-go/tfprotov6" + "github.com/hashicorp/terraform-plugin-testing/helper/acctest" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" + _ "k8s.io/client-go/plugin/pkg/client/auth" + "k8s.io/client-go/tools/clientcmd" +) + +const ( + testNamespacePrefix = "terraform-acc-test" + testResourceName = "test" + testChartsPath = "./testdata/charts" + testRepositoryDir = "./testdata/repository" +) + +var ( + accTest bool + testRepositoryURL string + client kubernetes.Interface = nil + testMeta *Meta +) + +var providerFactory map[string]func() (tfprotov6.ProviderServer, error) + +func protoV6ProviderFactories() map[string]func() (tfprotov6.ProviderServer, error) { + if len(providerFactory) != 0 { + return providerFactory + } + + providerFactory = map[string]func() (tfprotov6.ProviderServer, error){ + "helm": providerserver.NewProtocol6WithError(New("test")()), + } + + return providerFactory +} + +func TestMain(m *testing.M) { + home, err := ioutil.TempDir(os.TempDir(), "helm") + if err != nil { + panic(err) + } + + defer os.RemoveAll(home) + + err = os.Setenv("HELM_REPOSITORY_CONFIG", filepath.Join(home, "config/repositories.yaml")) + if err != nil { + panic(err) + } + + err = os.Setenv("HELM_REPOSITORY_CACHE", filepath.Join(home, "cache/helm/repository")) + if err != nil { + panic(err) + } + + err = os.Setenv("HELM_REGISTRY_CONFIG", filepath.Join(home, "config/registry.json")) + if err != nil { + panic(err) + } + + err = os.Setenv("HELM_PLUGINS", filepath.Join(home, "plugins")) + if err != nil { + panic(err) + } + + err = os.Setenv("XDG_CACHE_HOME", filepath.Join(home, "cache")) + if err != nil { + panic(err) + } + + accTest = os.Getenv("TF_ACC") == "1" + + var stopRepositoryServer func() + if accTest { + _, err := exec.LookPath("helm") + if err != nil { + panic(`command "helm" needs to be available to run the test suite`) + } + + // create the Kubernetes client + c, err := createKubernetesClient() + if err != nil { + panic(err) + } + client = c + + // Build the test repository and start the server + buildChartRepository() + testRepositoryURL, stopRepositoryServer = startRepositoryServer() + } + + ec := m.Run() + + if accTest { + stopRepositoryServer() + cleanupChartRepository() + } + + os.Exit(ec) +} + +// todo +func TestProvider(t *testing.T) { + ctx := context.Background() + provider := New("test")() + + // Create the provider server + providerServer, err := createProviderServer(provider) + if err != nil { + t.Fatalf("Failed to create provider server: %s", err) + } + // Perform config validation + + validateResponse, err := providerServer.ValidateProviderConfig(ctx, &tfprotov6.ValidateProviderConfigRequest{}) + if err != nil { + t.Fatalf("Provider config validation failed, error: %v", err) + } + + if hasError(validateResponse.Diagnostics) { + t.Fatalf("Provider config validation failed, diagnostics: %v", validateResponse.Diagnostics) + } +} + +func createProviderServer(provider provider.Provider) (tfprotov6.ProviderServer, error) { + providerServerFunc := providerserver.NewProtocol6WithError(provider) + server, err := providerServerFunc() + if err != nil { + } else { + } + return server, err +} + +func buildChartRepository() { + if _, err := os.Stat(testRepositoryDir); os.IsNotExist(err) { + os.Mkdir(testRepositoryDir, os.ModePerm) + } + + charts, err := ioutil.ReadDir(testChartsPath) + if err != nil { + panic(err) + } + + // package all the charts + for _, c := range charts { + cmd := exec.Command("helm", "package", "-u", + filepath.Join(testChartsPath, c.Name()), + "-d", testRepositoryDir) + out, err := cmd.CombinedOutput() + if err != nil { + log.Println(string(out)) + panic(err) + } + + log.Printf("Created repository package for %q\n", c.Name()) + } + + // build the repository index + cmd := exec.Command("helm", "repo", "index", testRepositoryDir) + out, err := cmd.CombinedOutput() + if err != nil { + log.Println(string(out)) + panic(err) + } + + log.Println("Built chart repository index") +} + +func cleanupChartRepository() { + if _, err := os.Stat(testRepositoryDir); err == nil { + err := os.RemoveAll(testRepositoryDir) + if err != nil { + fmt.Println(err) + } + } +} + +func startRepositoryServer() (string, func()) { + wg := sync.WaitGroup{} + wg.Add(1) + + var shutdownFunc func() + go func() { + fileserver := http.Server{ + Handler: http.FileServer(http.Dir(testRepositoryDir)), + } + fileserver.SetKeepAlivesEnabled(false) + shutdownFunc = func() { fileserver.Shutdown(context.Background()) } + listener, err := net.Listen("tcp", ":0") + if err != nil { + panic(err) + } + port := listener.Addr().(*net.TCPAddr).Port + testRepositoryURL = fmt.Sprintf("http://localhost:%d", port) + wg.Done() + err = fileserver.Serve(listener) + if err != nil && err != http.ErrServerClosed { + panic(err) + } + }() + wg.Wait() + + return testRepositoryURL, shutdownFunc +} + +func createAndConfigureProviderServer(provider provider.Provider, ctx context.Context) (tfprotov6.ProviderServer, error) { + log.Println("Starting createAndConfigureProviderServer...") + + providerServerFunc := providerserver.NewProtocol6WithError(provider) + providerServer, err := providerServerFunc() + if err != nil { + return nil, fmt.Errorf("Failed to create protocol6 provider: %w", err) + } + log.Println("Provider server function created successfully.") + + configResponse, err := providerServer.ConfigureProvider(ctx, nil) + if err != nil { + return nil, fmt.Errorf("Error configuring provider: %w", err) + } + log.Println("Provider configured successfully.") + + if hasError(configResponse.Diagnostics) { + return nil, fmt.Errorf("Provider configuration failed, diagnostics: %#v", configResponse.Diagnostics[0]) + } + + if helmProvider, ok := provider.(*HelmProvider); ok { + testMeta = helmProvider.meta + if testMeta == nil { + log.Println("testMeta is nil after type assertion.") + } else { + log.Printf("testMeta initialized: %+v", testMeta) + } + } else { + return nil, fmt.Errorf("Failed to type assert provider to HelmProvider") + } + + return providerServer, nil +} + +func testAccPreCheck(t *testing.T) { + if testing.Short() { + t.Skip("skipping acceptance tests in short mode") + } + http.DefaultClient.CloseIdleConnections() + + ctx := context.TODO() + + provider := New("test")() + + // Create and configure the ProviderServer + _, err := createAndConfigureProviderServer(provider, ctx) + if err != nil { + t.Fatalf("Pre-check failed: %v", err) + } +} + +func createKubernetesClient() (kubernetes.Interface, error) { + rules := clientcmd.NewDefaultClientConfigLoadingRules() + + kubeconfig := os.Getenv("KUBE_CONFIG_PATH") + if kubeconfig == "" { + panic("Need to set KUBE_CONFIG_PATH") + } + rules.ExplicitPath = kubeconfig + + config, err := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(rules, &clientcmd.ConfigOverrides{}).ClientConfig() + if err != nil { + return nil, err + } + + c, err := kubernetes.NewForConfig(config) + if err != nil { + return nil, err + } + return c, nil +} + +func createRandomNamespace(t *testing.T) string { + if !accTest { + t.Skip("TF_ACC=1 not set") + return "" + } + + namespace := fmt.Sprintf("%s-%s", testNamespacePrefix, acctest.RandString(10)) + ns := &v1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: namespace, + }, + } + _, err := client.CoreV1().Namespaces().Create(context.TODO(), ns, metav1.CreateOptions{}) + if err != nil { + t.Fatalf("Could not create test namespace %q: %s", namespace, err) + } + return namespace +} + +func deleteNamespace(t *testing.T, namespace string) { + if !accTest { + t.Skip("TF_ACC=1 not set") + return + } + + gracePeriodSeconds := int64(0) + deleteOptions := metav1.DeleteOptions{ + GracePeriodSeconds: &gracePeriodSeconds, + } + err := client.CoreV1().Namespaces().Delete(context.TODO(), namespace, deleteOptions) + if err != nil { + t.Fatalf("An error occurred while deleting namespace %q: %q", namespace, err) + } +} + +func randName(prefix string) string { + return fmt.Sprintf("%s-%s", prefix, acctest.RandString(10)) +} + +func hasError(diagnostics []*tfprotov6.Diagnostic) bool { + for _, diagnostic := range diagnostics { + if diagnostic.Severity == tfprotov6.DiagnosticSeverityError { + return true + } + } + return false +} + +func DynamicValueEmpty() *tfprotov6.DynamicValue { + return &tfprotov6.DynamicValue{ + MsgPack: nil, + JSON: nil, + } +} diff --git a/shuttles/terraform/terraform-provider-helm/helm/resource_helm_release.go b/shuttles/terraform/terraform-provider-helm/helm/resource_helm_release.go new file mode 100644 index 0000000..de03048 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/resource_helm_release.go @@ -0,0 +1,2271 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package helm + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "os" + pathpkg "path" + "strings" + "time" + + "github.com/hashicorp/terraform-plugin-framework-validators/int64validator" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/identityschema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/defaults" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/tfsdk" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" + "github.com/hashicorp/terraform-plugin-log/tflog" + "github.com/pkg/errors" + "helm.sh/helm/v3/pkg/action" + "helm.sh/helm/v3/pkg/chart" + "helm.sh/helm/v3/pkg/chart/loader" + + "helm.sh/helm/v3/pkg/downloader" + "helm.sh/helm/v3/pkg/getter" + "helm.sh/helm/v3/pkg/postrender" + "helm.sh/helm/v3/pkg/registry" + "helm.sh/helm/v3/pkg/release" + "k8s.io/helm/pkg/strvals" + "sigs.k8s.io/yaml" +) + +var ( + _ resource.Resource = &HelmRelease{} + _ resource.ResourceWithModifyPlan = &HelmRelease{} + _ resource.ResourceWithImportState = &HelmRelease{} + _ resource.ResourceWithIdentity = &HelmRelease{} + _ resource.ResourceWithUpgradeState = &HelmRelease{} +) + +type HelmRelease struct { + meta *Meta +} + +func NewHelmRelease() resource.Resource { + return &HelmRelease{} +} + +type HelmReleaseIdentityModel struct { + Namespace types.String `tfsdk:"namespace"` + ReleaseName types.String `tfsdk:"release_name"` +} + +type HelmReleaseModel struct { + Atomic types.Bool `tfsdk:"atomic"` + Chart types.String `tfsdk:"chart"` + CleanupOnFail types.Bool `tfsdk:"cleanup_on_fail"` + CreateNamespace types.Bool `tfsdk:"create_namespace"` + DependencyUpdate types.Bool `tfsdk:"dependency_update"` + Description types.String `tfsdk:"description"` + Devel types.Bool `tfsdk:"devel"` + DisableCrdHooks types.Bool `tfsdk:"disable_crd_hooks"` + DisableOpenapiValidation types.Bool `tfsdk:"disable_openapi_validation"` + DisableWebhooks types.Bool `tfsdk:"disable_webhooks"` + ForceUpdate types.Bool `tfsdk:"force_update"` + ID types.String `tfsdk:"id"` + Keyring types.String `tfsdk:"keyring"` + Lint types.Bool `tfsdk:"lint"` + Manifest types.String `tfsdk:"manifest"` + MaxHistory types.Int64 `tfsdk:"max_history"` + Metadata types.Object `tfsdk:"metadata"` + Name types.String `tfsdk:"name"` + Namespace types.String `tfsdk:"namespace"` + PassCredentials types.Bool `tfsdk:"pass_credentials"` + PostRender *PostRenderModel `tfsdk:"postrender"` + RecreatePods types.Bool `tfsdk:"recreate_pods"` + Replace types.Bool `tfsdk:"replace"` + RenderSubchartNotes types.Bool `tfsdk:"render_subchart_notes"` + Repository types.String `tfsdk:"repository"` + RepositoryCaFile types.String `tfsdk:"repository_ca_file"` + RepositoryCertFile types.String `tfsdk:"repository_cert_file"` + RepositoryKeyFile types.String `tfsdk:"repository_key_file"` + RepositoryPassword types.String `tfsdk:"repository_password"` + RepositoryUsername types.String `tfsdk:"repository_username"` + ResetValues types.Bool `tfsdk:"reset_values"` + ReuseValues types.Bool `tfsdk:"reuse_values"` + SetWO types.List `tfsdk:"set_wo"` + SetWORevision types.Int64 `tfsdk:"set_wo_revision"` + Set types.List `tfsdk:"set"` + SetList types.List `tfsdk:"set_list"` + SetSensitive types.List `tfsdk:"set_sensitive"` + SkipCrds types.Bool `tfsdk:"skip_crds"` + Status types.String `tfsdk:"status"` + Timeout types.Int64 `tfsdk:"timeout"` + Values types.List `tfsdk:"values"` + Verify types.Bool `tfsdk:"verify"` + Version types.String `tfsdk:"version"` + Wait types.Bool `tfsdk:"wait"` + WaitForJobs types.Bool `tfsdk:"wait_for_jobs"` +} + +var defaultAttributes = map[string]interface{}{ + "atomic": false, + "cleanup_on_fail": false, + "create_namespace": false, + "dependency_update": false, + "disable_crd_hooks": false, + "disable_openapi_validation": false, + "disable_webhooks": false, + "force_update": false, + "lint": false, + "max_history": int64(0), + "pass_credentials": false, + "recreate_pods": false, + "render_subchart_notes": true, + "replace": false, + "reset_values": false, + "reuse_values": false, + "skip_crds": false, + "timeout": int64(300), + "verify": false, + "wait": true, + "wait_for_jobs": false, +} + +type releaseMetaData struct { + AppVersion types.String `tfsdk:"app_version"` + Chart types.String `tfsdk:"chart"` + Name types.String `tfsdk:"name"` + Namespace types.String `tfsdk:"namespace"` + Revision types.Int64 `tfsdk:"revision"` + Version types.String `tfsdk:"version"` + Values types.String `tfsdk:"values"` + FirstDeployed types.Int64 `tfsdk:"first_deployed"` + LastDeployed types.Int64 `tfsdk:"last_deployed"` + Notes types.String `tfsdk:"notes"` +} +type setResourceModel struct { + Name types.String `tfsdk:"name"` + Type types.String `tfsdk:"type"` + Value types.String `tfsdk:"value"` +} + +type set_listResourceModel struct { + Name types.String `tfsdk:"name"` + Value types.List `tfsdk:"value"` +} + +type PostRenderModel struct { + Args types.List `tfsdk:"args"` + BinaryPath types.String `tfsdk:"binary_path"` +} + +type suppressDescriptionPlanModifier struct{} + +func (m suppressDescriptionPlanModifier) Description(ctx context.Context) string { + return "Suppress changes if the new description is an empty string" +} + +func (m suppressDescriptionPlanModifier) MarkdownDescription(ctx context.Context) string { + return m.Description(ctx) +} + +func (m suppressDescriptionPlanModifier) PlanModifyString(ctx context.Context, req planmodifier.StringRequest, resp *planmodifier.StringResponse) { + if req.PlanValue.IsNull() || req.PlanValue.ValueString() == "" { + resp.PlanValue = req.StateValue + } +} + +func suppressDescription() planmodifier.String { + return suppressDescriptionPlanModifier{} +} + +type suppressDevelPlanModifier struct{} + +func (m suppressDevelPlanModifier) Description(ctx context.Context) string { + return "Suppress changes if the version is set" +} + +func (m suppressDevelPlanModifier) MarkdownDescription(ctx context.Context) string { + return m.Description(ctx) +} + +func (m suppressDevelPlanModifier) PlanModifyBool(ctx context.Context, req planmodifier.BoolRequest, resp *planmodifier.BoolResponse) { + var version types.String + req.Plan.GetAttribute(ctx, path.Root("version"), &version) + if !version.IsNull() && version.ValueString() != "" { + resp.PlanValue = req.StateValue + } +} + +func suppressDevel() planmodifier.Bool { + return suppressDevelPlanModifier{} +} + +// Supress Keyring +type suppressKeyringPlanModifier struct{} + +func (m suppressKeyringPlanModifier) Description(ctx context.Context) string { + return "Suppress changes if verify is false" +} + +func (m suppressKeyringPlanModifier) MarkdownDescription(ctx context.Context) string { + return m.Description(ctx) +} + +func (m suppressKeyringPlanModifier) PlanModifyString(ctx context.Context, req planmodifier.StringRequest, resp *planmodifier.StringResponse) { + var verify types.Bool + req.Plan.GetAttribute(ctx, path.Root("verify"), &verify) + if !verify.IsNull() && !verify.ValueBool() { + resp.PlanValue = req.StateValue + } +} + +func suppressKeyring() planmodifier.String { + return suppressKeyringPlanModifier{} +} + +func namespaceDefault() defaults.String { + return namespaceDefaultValue{} +} + +type namespaceDefaultValue struct{} + +func (d namespaceDefaultValue) Description(ctx context.Context) string { + return "If namespace is not provided, defaults to HELM_NAMESPACE environment variable or 'default'." +} + +func (d namespaceDefaultValue) MarkdownDescription(ctx context.Context) string { + return d.Description(ctx) +} + +func (d namespaceDefaultValue) DefaultString(ctx context.Context, req defaults.StringRequest, resp *defaults.StringResponse) { + envNamespace := os.Getenv("HELM_NAMESPACE") + if envNamespace == "" { + envNamespace = "default" + } + resp.PlanValue = types.StringValue(envNamespace) +} + +func (r *HelmRelease) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_release" +} + +func (r *HelmRelease) UpgradeState(ctx context.Context) map[int64]resource.StateUpgrader { + return r.buildUpgradeStateMap(ctx) +} +func (r *HelmRelease) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + Description: "Schema to define attributes that are available in the resource", + Attributes: map[string]schema.Attribute{ + "atomic": schema.BoolAttribute{ + Optional: true, + Computed: true, + Default: booldefault.StaticBool(defaultAttributes["atomic"].(bool)), + Description: "If set, installation process purges chart on fail. The wait flag will be set automatically if atomic is used", + }, + "chart": schema.StringAttribute{ + Required: true, + Description: "Chart name to be installed. A path may be used", + }, + "cleanup_on_fail": schema.BoolAttribute{ + Optional: true, + Computed: true, + Default: booldefault.StaticBool(defaultAttributes["cleanup_on_fail"].(bool)), + Description: "Allow deletion of new resources created in this upgrade when upgrade fails", + }, + "create_namespace": schema.BoolAttribute{ + Optional: true, + Computed: true, + Default: booldefault.StaticBool(defaultAttributes["create_namespace"].(bool)), + Description: "Create the namespace if it does not exist", + }, + "dependency_update": schema.BoolAttribute{ + Optional: true, + Computed: true, + Default: booldefault.StaticBool(defaultAttributes["dependency_update"].(bool)), + Description: "Run helm dependency update before installing the chart", + }, + "description": schema.StringAttribute{ + Optional: true, + Description: "Add a custom description", + PlanModifiers: []planmodifier.String{ + suppressDescription(), + }, + }, + "devel": schema.BoolAttribute{ + Optional: true, + Description: "Use chart development versions, too. Equivalent to version '>0.0.0-0'. If 'version' is set, this is ignored", + PlanModifiers: []planmodifier.Bool{ + suppressDevel(), + }, + }, + "disable_crd_hooks": schema.BoolAttribute{ + Optional: true, + Computed: true, + Default: booldefault.StaticBool(defaultAttributes["disable_crd_hooks"].(bool)), + Description: "Prevent CRD hooks from running, but run other hooks. See helm install --no-crd-hook", + }, + "disable_openapi_validation": schema.BoolAttribute{ + Optional: true, + Computed: true, + Default: booldefault.StaticBool(defaultAttributes["disable_openapi_validation"].(bool)), + Description: "If set, the installation process will not validate rendered templates against the Kubernetes OpenAPI Schema", + }, + "disable_webhooks": schema.BoolAttribute{ + Optional: true, + Computed: true, + Default: booldefault.StaticBool(defaultAttributes["disable_webhooks"].(bool)), + Description: "Prevent hooks from running", + }, + "force_update": schema.BoolAttribute{ + Optional: true, + Computed: true, + Default: booldefault.StaticBool(defaultAttributes["force_update"].(bool)), + Description: "Force resource update through delete/recreate if needed.", + }, + "id": schema.StringAttribute{ + Computed: true, + }, + "keyring": schema.StringAttribute{ + Optional: true, + Description: "Location of public keys used for verification, Used only if 'verify is true'", + PlanModifiers: []planmodifier.String{ + suppressKeyring(), + }, + }, + "lint": schema.BoolAttribute{ + Optional: true, + Computed: true, + Default: booldefault.StaticBool(defaultAttributes["lint"].(bool)), + Description: "Run helm lint when planning", + }, + "manifest": schema.StringAttribute{ + Description: "The rendered manifest as JSON.", + Computed: true, + }, + "max_history": schema.Int64Attribute{ + Optional: true, + Computed: true, + Default: int64default.StaticInt64(defaultAttributes["max_history"].(int64)), + Description: "Limit the maximum number of revisions saved per release. Use 0 for no limit", + }, + "metadata": schema.SingleNestedAttribute{ + Description: "Status of the deployed release.", + Computed: true, + Attributes: map[string]schema.Attribute{ + "app_version": schema.StringAttribute{ + Computed: true, + Description: "The version number of the application being deployed", + }, + "chart": schema.StringAttribute{ + Computed: true, + Description: "The name of the chart", + }, + "first_deployed": schema.Int64Attribute{ + Computed: true, + Description: "FirstDeployed is an int64 which represents timestamp when the release was first deployed.", + }, + "last_deployed": schema.Int64Attribute{ + Computed: true, + Description: "LastDeployed is an int64 which represents timestamp when the release was last deployed.", + }, + "name": schema.StringAttribute{ + Computed: true, + Description: "Name is the name of the release", + }, + "namespace": schema.StringAttribute{ + Computed: true, + Description: "Namespace is the kubernetes namespace of the release", + }, + "notes": schema.StringAttribute{ + Computed: true, + Description: "Notes is the description of the deployed release, rendered from templates.", + }, + "revision": schema.Int64Attribute{ + Computed: true, + Description: "Version is an int32 which represents the version of the release", + }, + "values": schema.StringAttribute{ + Computed: true, + Description: "Set of extra values. added to the chart. The sensitive data is cloaked. JSON encoded.", + }, + "version": schema.StringAttribute{ + Computed: true, + Description: "A SemVer 2 conformant version string of the chart", + }, + }, + }, + "name": schema.StringAttribute{ + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + Validators: []validator.String{ + stringvalidator.LengthBetween(1, 53), + }, + Description: "Release name. The length must not be longer than 53 characters", + }, + "namespace": schema.StringAttribute{ + Optional: true, + Computed: true, + Default: namespaceDefault(), + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + Description: "Namespace to install the release into", + }, + + "pass_credentials": schema.BoolAttribute{ + Optional: true, + Description: "Pass credentials to all domains", + Computed: true, + Default: booldefault.StaticBool(defaultAttributes["pass_credentials"].(bool)), + }, + "recreate_pods": schema.BoolAttribute{ + Optional: true, + Computed: true, + Default: booldefault.StaticBool(defaultAttributes["recreate_pods"].(bool)), + Description: "Perform pods restart during upgrade/rollback", + }, + "render_subchart_notes": schema.BoolAttribute{ + Optional: true, + Computed: true, + Default: booldefault.StaticBool(defaultAttributes["render_subchart_notes"].(bool)), + Description: "If set, render subchart notes along with the parent", + }, + "replace": schema.BoolAttribute{ + Optional: true, + Computed: true, + Default: booldefault.StaticBool(defaultAttributes["replace"].(bool)), + Description: "Re-use the given name, even if that name is already used. This is unsafe in production", + }, + "repository": schema.StringAttribute{ + Optional: true, + Description: "Repository where to locate the requested chart. If it is a URL, the chart is installed without installing the repository", + }, + "repository_ca_file": schema.StringAttribute{ + Optional: true, + Description: "The Repositories CA file", + }, + "repository_cert_file": schema.StringAttribute{ + Optional: true, + Description: "The repositories cert file", + }, + "repository_key_file": schema.StringAttribute{ + Optional: true, + Description: "The repositories cert key file", + }, + "repository_password": schema.StringAttribute{ + Optional: true, + Sensitive: true, + Description: "Password for HTTP basic authentication", + }, + "repository_username": schema.StringAttribute{ + Optional: true, + Description: "Username for HTTP basic authentication", + }, + "reset_values": schema.BoolAttribute{ + Optional: true, + Computed: true, + Description: "When upgrading, reset the values to the ones built into the chart", + Default: booldefault.StaticBool(defaultAttributes["reset_values"].(bool)), + }, + "reuse_values": schema.BoolAttribute{ + Optional: true, + Computed: true, + Description: "When upgrading, reuse the last release's values and merge in any overrides. If 'reset_values' is specified, this is ignored", + Default: booldefault.StaticBool(defaultAttributes["reuse_values"].(bool)), + }, + "skip_crds": schema.BoolAttribute{ + Optional: true, + Computed: true, + Default: booldefault.StaticBool(defaultAttributes["skip_crds"].(bool)), + Description: "If set, no CRDs will be installed. By default, CRDs are installed if not already present", + }, + "status": schema.StringAttribute{ + Computed: true, + Description: "Status of the release", + }, + "timeout": schema.Int64Attribute{ + Optional: true, + Computed: true, + Default: int64default.StaticInt64(defaultAttributes["timeout"].(int64)), + Description: "Time in seconds to wait for any individual kubernetes operation", + }, + "values": schema.ListAttribute{ + Optional: true, + Description: "List of values in raw YAML format to pass to helm", + ElementType: types.StringType, + }, + "verify": schema.BoolAttribute{ + Optional: true, + Computed: true, + Default: booldefault.StaticBool(defaultAttributes["verify"].(bool)), + Description: "Verify the package before installing it.", + }, + "version": schema.StringAttribute{ + Optional: true, + Computed: true, + Description: "Specify the exact chart version to install. If this is not specified, the latest version is installed", + }, + "wait": schema.BoolAttribute{ + Optional: true, + Computed: true, + Default: booldefault.StaticBool(defaultAttributes["wait"].(bool)), + Description: "Will wait until all resources are in a ready state before marking the release as successful.", + }, + "wait_for_jobs": schema.BoolAttribute{ + Optional: true, + Computed: true, + Default: booldefault.StaticBool(defaultAttributes["wait_for_jobs"].(bool)), + Description: "If wait is enabled, will wait until all Jobs have been completed before marking the release as successful.", + }, + "set": schema.ListNestedAttribute{ + Description: "Custom values to be merged with the values", + Optional: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "name": schema.StringAttribute{ + Required: true, + }, + "value": schema.StringAttribute{ + Optional: true, + }, + "type": schema.StringAttribute{ + Optional: true, + Computed: true, + Default: stringdefault.StaticString(""), + Validators: []validator.String{ + stringvalidator.OneOf("auto", "string", "literal"), + }, + }, + }, + }, + }, + "set_wo": schema.ListNestedAttribute{ + Description: "Custom values to be merged with the values", + Optional: true, + WriteOnly: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "name": schema.StringAttribute{ + Required: true, + WriteOnly: true, + }, + "value": schema.StringAttribute{ + Required: true, + WriteOnly: true, + }, + "type": schema.StringAttribute{ + Optional: true, + WriteOnly: true, + Validators: []validator.String{ + stringvalidator.OneOf("auto", "string"), + }, + }, + }, + }, + }, + "set_wo_revision": schema.Int64Attribute{ + Optional: true, + Description: `The current revision of the write-only "set_wo" attribute. Incrementing this integer value will cause Terraform to update the write-only value.`, + Validators: []validator.Int64{ + int64validator.AtLeast(1), + }, + }, + "set_list": schema.ListNestedAttribute{ + Description: "Custom sensitive values to be merged with the values", + Optional: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "name": schema.StringAttribute{ + Required: true, + }, + "value": schema.ListAttribute{ + Required: true, + ElementType: types.StringType, + }, + }, + }, + }, + "set_sensitive": schema.ListNestedAttribute{ + Description: "Custom sensitive values to be merged with the values", + Optional: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "name": schema.StringAttribute{ + Required: true, + }, + "value": schema.StringAttribute{ + Required: true, + Sensitive: true, + }, + "type": schema.StringAttribute{ + Optional: true, + Validators: []validator.String{ + stringvalidator.OneOf("auto", "string", "literal"), + }, + }, + }, + }, + }, + "postrender": schema.SingleNestedAttribute{ + Description: "Postrender command config", + Optional: true, + Attributes: map[string]schema.Attribute{ + "args": schema.ListAttribute{ + Optional: true, + Description: "An argument to the post-renderer (can specify multiple)", + ElementType: types.StringType, + }, + "binary_path": schema.StringAttribute{ + Required: true, + Description: "The common binary path", + }, + }, + }, + }, + Version: 2, + } +} + +func (r *HelmRelease) IdentitySchema(ctx context.Context, req resource.IdentitySchemaRequest, resp *resource.IdentitySchemaResponse) { + resp.IdentitySchema = identityschema.Schema{ + Version: 0, + Attributes: map[string]identityschema.Attribute{ + "namespace": identityschema.StringAttribute{ + // use "default" if not specified + OptionalForImport: true, + }, + "release_name": identityschema.StringAttribute{ + RequiredForImport: true, + }, + }, + } +} + +func (r *HelmRelease) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + // Ensure that the ProviderData is not nil + if req.ProviderData == nil { + return + } + + // Assert that the ProviderData is of type *Meta + meta, ok := req.ProviderData.(*Meta) + if !ok { + resp.Diagnostics.AddError( + "Provider Configuration Error", + fmt.Sprintf("Unexpected ProviderData type: %T", req.ProviderData), + ) + return + } + tflog.Debug(ctx, fmt.Sprintf("Configured meta: %+v", meta)) + r.meta = meta +} + +const sensitiveContentValue = "(sensitive value)" + +func cloakSetValue(values map[string]interface{}, valuePath string) { + pathKeys := strings.Split(valuePath, ".") + sensitiveKey := pathKeys[len(pathKeys)-1] + parentPathKeys := pathKeys[:len(pathKeys)-1] + m := values + for _, key := range parentPathKeys { + v, ok := m[key].(map[string]interface{}) + if !ok { + return + } + m = v + } + m[sensitiveKey] = sensitiveContentValue +} + +func mergeMaps(a, b map[string]interface{}) map[string]interface{} { + out := make(map[string]interface{}, len(a)) + for k, v := range a { + out[k] = v + } + for k, v := range b { + if vMap, ok := v.(map[string]interface{}); ok { + if bv, ok := out[k]; ok { + if bvMap, ok := bv.(map[string]interface{}); ok { + out[k] = mergeMaps(bvMap, vMap) + continue + } + } + } + out[k] = v + } + return out +} + +func (r *HelmRelease) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var state HelmReleaseModel + diags := req.Plan.Get(ctx, &state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + var config HelmReleaseModel + diags = req.Config.Get(ctx, &config) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + tflog.Debug(ctx, fmt.Sprintf("Plan state on Create: %+v", state)) + + meta := r.meta + if meta == nil { + resp.Diagnostics.AddError("Initialization Error", "Meta instance is not initialized") + return + } + namespace := state.Namespace.ValueString() + actionConfig, err := meta.GetHelmConfiguration(ctx, namespace) + if err != nil { + resp.Diagnostics.AddError("Error getting helm configuration", fmt.Sprintf("Unable to get Helm configuration for namespace %s: %s", namespace, err)) + return + } + ociDiags := OCIRegistryLogin(ctx, meta, actionConfig, meta.RegistryClient, state.Repository.ValueString(), state.Chart.ValueString(), state.RepositoryUsername.ValueString(), state.RepositoryPassword.ValueString()) + resp.Diagnostics.Append(ociDiags...) + if resp.Diagnostics.HasError() { + return + } + + client := action.NewInstall(actionConfig) + cpo, chartName, cpoDiags := chartPathOptions(&state, meta, &client.ChartPathOptions) + resp.Diagnostics.Append(cpoDiags...) + if resp.Diagnostics.HasError() { + return + } + + c, cpath, chartDiags := getChart(ctx, &state, meta, chartName, cpo) + resp.Diagnostics.Append(chartDiags...) + if resp.Diagnostics.HasError() { + return + } + + updated, depDiags := checkChartDependencies(ctx, &state, c, cpath, meta) + resp.Diagnostics.Append(depDiags...) + if resp.Diagnostics.HasError() { + return + } else if updated { + c, err = loader.Load(cpath) + if err != nil { + resp.Diagnostics.AddError("Error loading chart", fmt.Sprintf("Could not load chart: %s", err)) + return + } + } + + values, valuesDiags := getValues(ctx, &state) + resp.Diagnostics.Append(valuesDiags...) + if resp.Diagnostics.HasError() { + return + } + + if config.SetWORevision.ValueInt64() > 0 { + woValues, woDiags := getWriteOnlyValues(ctx, &config) + resp.Diagnostics.Append(woDiags...) + if resp.Diagnostics.HasError() { + return + } + if len(woValues) > 0 { + values = mergeMaps(values, woValues) + } + } + + err = isChartInstallable(c) + if err != nil { + resp.Diagnostics.AddError("Error checking if chart is installable", fmt.Sprintf("Chart is not installable: %s", err)) + return + } + + client.ClientOnly = false + client.DryRun = false + client.DisableHooks = state.DisableWebhooks.ValueBool() + client.Wait = state.Wait.ValueBool() + client.WaitForJobs = state.WaitForJobs.ValueBool() + client.Devel = state.Devel.ValueBool() + client.DependencyUpdate = state.DependencyUpdate.ValueBool() + client.Timeout = time.Duration(state.Timeout.ValueInt64()) * time.Second + client.Namespace = state.Namespace.ValueString() + client.ReleaseName = state.Name.ValueString() + client.Atomic = state.Atomic.ValueBool() + client.SkipCRDs = state.SkipCrds.ValueBool() + client.SubNotes = state.RenderSubchartNotes.ValueBool() + client.DisableOpenAPIValidation = state.DisableOpenapiValidation.ValueBool() + client.Replace = state.Replace.ValueBool() + client.Description = state.Description.ValueString() + client.CreateNamespace = state.CreateNamespace.ValueBool() + + if state.PostRender != nil { + binaryPath := state.PostRender.BinaryPath.ValueString() + argsList := state.PostRender.Args.Elements() + + var args []string + for _, arg := range argsList { + args = append(args, arg.(basetypes.StringValue).ValueString()) + } + tflog.Debug(ctx, fmt.Sprintf("Creating post-renderer with binary path: %s and args: %v", binaryPath, args)) + pr, err := postrender.NewExec(binaryPath, args...) + if err != nil { + resp.Diagnostics.AddError("Error creating post-renderer", fmt.Sprintf("Could not create post-renderer: %s", err)) + return + } + + client.PostRenderer = pr + } + + rel, err := client.Run(c, values) + if err != nil && rel == nil { + resp.Diagnostics.AddError("installation failed", err.Error()) + return + } + + if err != nil && rel != nil { + exists, existsDiags := resourceReleaseExists(ctx, state.Name.ValueString(), state.Namespace.ValueString(), meta) + resp.Diagnostics.Append(existsDiags...) + if resp.Diagnostics.HasError() { + return + } + if !exists { + resp.Diagnostics.AddError("installation failed", err.Error()) + return + } + + diags := setReleaseAttributes(ctx, &state, resp.Identity, rel, meta) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + resp.Diagnostics.Append(diag.NewWarningDiagnostic("Helm release created with warnings", fmt.Sprintf("Helm release %q was created but has a failed status. Use the `helm` command to investigate the error, correct it, then run Terraform again.", client.ReleaseName))) + resp.Diagnostics.Append(diag.NewErrorDiagnostic("Helm release error", err.Error())) + + return + } + + diags = setReleaseAttributes(ctx, &state, resp.Identity, rel, meta) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + diags = resp.State.Set(ctx, &state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } +} + +func (r *HelmRelease) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var state HelmReleaseModel + + diags := req.State.Get(ctx, &state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + tflog.Debug(ctx, fmt.Sprintf("Current state before changes: %+v", state)) + + meta := r.meta + if meta == nil { + resp.Diagnostics.AddError( + "Meta not set", + "The meta information is not set for the resource", + ) + return + } + + exists, diags := resourceReleaseExists(ctx, state.Name.ValueString(), state.Namespace.ValueString(), meta) + if !exists { + resp.State.RemoveResource(ctx) + return + } + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + logID := fmt.Sprintf("[resourceReleaseRead: %s]", state.Name.ValueString()) + tflog.Debug(ctx, fmt.Sprintf("%s Started", logID)) + + c, err := meta.GetHelmConfiguration(ctx, state.Namespace.ValueString()) + if err != nil { + resp.Diagnostics.AddError( + "Error getting helm configuration", + fmt.Sprintf("Unable to get Helm configuration for namespace %s: %s", state.Namespace.ValueString(), err), + ) + return + } + + release, err := getRelease(ctx, meta, c, state.Name.ValueString()) + if err != nil { + resp.Diagnostics.AddError( + "Error getting release", + fmt.Sprintf("Unable to get Helm release %s: %s", state.Name.ValueString(), err.Error()), + ) + return + } + + diags = setReleaseAttributes(ctx, &state, resp.Identity, release, meta) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + resp.Diagnostics.AddError( + "Error setting release attributes", + fmt.Sprintf("Unable to set attributes for helm release %s", state.Name.ValueString()), + ) + return + } + + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } +} + +func (r *HelmRelease) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var plan HelmReleaseModel + diags := req.Plan.Get(ctx, &plan) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + // Current state of the resource before update operation is applied + var state HelmReleaseModel + diags = req.State.Get(ctx, &state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + var config HelmReleaseModel + diags = req.Config.Get(ctx, &config) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + logID := fmt.Sprintf("[resourceReleaseUpdate: %s]", state.Name.ValueString()) + tflog.Debug(ctx, fmt.Sprintf("%s Started", logID)) + + meta := r.meta + namespace := state.Namespace.ValueString() + tflog.Debug(ctx, fmt.Sprintf("%s Getting helm configuration for namespace: %s", logID, namespace)) + actionConfig, err := meta.GetHelmConfiguration(ctx, namespace) + if err != nil { + tflog.Debug(ctx, fmt.Sprintf("%s Failed to get helm configuration: %v", logID, err)) + resp.Diagnostics.AddError("Error getting helm configuration", fmt.Sprintf("Unable to get Helm configuration for namespace %s: %s", namespace, err)) + return + } + ociDiags := OCIRegistryLogin(ctx, meta, actionConfig, meta.RegistryClient, state.Repository.ValueString(), state.Chart.ValueString(), state.RepositoryUsername.ValueString(), state.RepositoryPassword.ValueString()) + resp.Diagnostics.Append(ociDiags...) + if resp.Diagnostics.HasError() { + return + } + client := action.NewUpgrade(actionConfig) + + cpo, chartName, cpoDiags := chartPathOptions(&plan, meta, &client.ChartPathOptions) + resp.Diagnostics.Append(cpoDiags...) + if resp.Diagnostics.HasError() { + return + } + + c, path, chartDiags := getChart(ctx, &plan, meta, chartName, cpo) + resp.Diagnostics.Append(chartDiags...) + if resp.Diagnostics.HasError() { + return + } + + // Check and update the chart's depenedcies if it's needed + updated, depDiags := checkChartDependencies(ctx, &plan, c, path, meta) + resp.Diagnostics.Append(depDiags...) + if resp.Diagnostics.HasError() { + return + } else if updated { + c, err = loader.Load(path) + if err != nil { + resp.Diagnostics.AddError("Error loading chart", fmt.Sprintf("Could not load chart: %s", err)) + return + } + } + + client.Devel = plan.Devel.ValueBool() + client.Namespace = plan.Namespace.ValueString() + client.Timeout = time.Duration(plan.Timeout.ValueInt64()) * time.Second + client.Wait = plan.Wait.ValueBool() + client.WaitForJobs = plan.WaitForJobs.ValueBool() + client.DryRun = false + client.DisableHooks = plan.DisableWebhooks.ValueBool() + client.Atomic = plan.Atomic.ValueBool() + client.SkipCRDs = plan.SkipCrds.ValueBool() + client.SubNotes = plan.RenderSubchartNotes.ValueBool() + client.DisableOpenAPIValidation = plan.DisableOpenapiValidation.ValueBool() + client.Force = plan.ForceUpdate.ValueBool() + client.ResetValues = plan.ResetValues.ValueBool() + client.ReuseValues = plan.ReuseValues.ValueBool() + client.Recreate = plan.RecreatePods.ValueBool() + client.MaxHistory = int(plan.MaxHistory.ValueInt64()) + client.CleanupOnFail = plan.CleanupOnFail.ValueBool() + client.Description = plan.Description.ValueString() + + if plan.PostRender != nil { + binaryPath := plan.PostRender.BinaryPath.ValueString() + argsList := plan.PostRender.Args.Elements() + + var args []string + for _, arg := range argsList { + args = append(args, arg.(basetypes.StringValue).ValueString()) + } + tflog.Debug(ctx, fmt.Sprintf("Binary path update method: %s, Args: %v", binaryPath, args)) + pr, err := postrender.NewExec(binaryPath, args...) + if err != nil { + resp.Diagnostics.AddError("Error creating post-renderer", fmt.Sprintf("Could not create post-renderer: %s", err)) + return + } + client.PostRenderer = pr + } + values, valuesDiags := getValues(ctx, &plan) + resp.Diagnostics.Append(valuesDiags...) + if resp.Diagnostics.HasError() { + return + } + if plan.SetWORevision.ValueInt64() > state.SetWORevision.ValueInt64() { + woValues, woDiags := getWriteOnlyValues(ctx, &config) + resp.Diagnostics.Append(woDiags...) + if resp.Diagnostics.HasError() { + return + } + if len(woValues) > 0 { + values = mergeMaps(values, woValues) + } + } + + name := plan.Name.ValueString() + release, err := client.Run(name, c, values) + if err != nil { + resp.Diagnostics.AddError("Error upgrading chart", fmt.Sprintf("Upgrade failed: %s", err)) + return + } + + diags = setReleaseAttributes(ctx, &plan, resp.Identity, release, meta) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + diags = resp.State.Set(ctx, &plan) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } +} + +func (r *HelmRelease) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var state HelmReleaseModel + diags := req.State.Get(ctx, &state) + + for _, diag := range diags { + tflog.Debug(ctx, fmt.Sprintf("Diagnostics after state get: %s", diag.Detail())) + } + + // Append diagnostics to response + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + tflog.Error(ctx, fmt.Sprintf("Error retrieving state: %v", resp.Diagnostics)) + return + } + tflog.Debug(ctx, fmt.Sprintf("Retrieved state: %+v", state)) + + // Check if meta is set + meta := r.meta + if meta == nil { + resp.Diagnostics.AddError( + "Meta not set", + "The meta information is not set for the resource", + ) + tflog.Error(ctx, "Meta information is not set for the resource") + return + } + + name := state.Name.ValueString() + namespace := state.Namespace.ValueString() + + exists, diags := resourceReleaseExists(ctx, name, namespace, meta) + if !exists { + return + } + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + // Get Helm configuration + actionConfig, err := meta.GetHelmConfiguration(ctx, namespace) + if err != nil { + resp.Diagnostics.AddError( + "Error getting helm configuration", + fmt.Sprintf("Unable to get Helm configuration for namespace %s: %s", namespace, err), + ) + tflog.Error(ctx, fmt.Sprintf("Unable to get Helm configuration for namespace %s: %s", namespace, err)) + return + } + tflog.Debug(ctx, fmt.Sprintf("Retrieved Helm configuration for namespace: %s", namespace)) + + // Initialize uninstall action + uninstall := action.NewUninstall(actionConfig) + uninstall.Wait = state.Wait.ValueBool() + uninstall.DisableHooks = state.DisableWebhooks.ValueBool() + uninstall.Timeout = time.Duration(state.Timeout.ValueInt64()) * time.Second + + // Uninstall the release + tflog.Info(ctx, fmt.Sprintf("Uninstalling Helm release: %s", name)) + res, err := uninstall.Run(name) + if err != nil { + resp.Diagnostics.AddError( + "Error uninstalling release", + fmt.Sprintf("Unable to uninstall Helm release %s: %s", name, err), + ) + tflog.Error(ctx, fmt.Sprintf("Unable to uninstall Helm release %s: %s", name, err)) + return + } + + if res.Info != "" { + resp.Diagnostics.Append(diag.NewWarningDiagnostic( + "Helm uninstall returned an information message", + res.Info, + )) + } +} + +func chartPathOptions(model *HelmReleaseModel, meta *Meta, cpo *action.ChartPathOptions) (*action.ChartPathOptions, string, diag.Diagnostics) { + var diags diag.Diagnostics + chartName := model.Chart.ValueString() + repository := model.Repository.ValueString() + + var repositoryURL string + if registry.IsOCI(repository) { + // LocateChart expects the chart name to contain the full OCI path + u, err := url.Parse(repository) + if err != nil { + diags.AddError("Invalid Repository URL", fmt.Sprintf("Failed to parse repository URL %s: %s", repository, err)) + return nil, "", diags + } + u.Path = pathpkg.Join(u.Path, chartName) + chartName = u.String() + } else { + var err error + repositoryURL, chartName, err = buildChartNameWithRepository(repository, strings.TrimSpace(chartName)) + if err != nil { + diags.AddError("Error building Chart Name With Repository", fmt.Sprintf("Could not build Chart Name With Repository %s and chart %s: %s", repository, chartName, err)) + return nil, "", diags + } + } + + version := getVersion(model) + + cpo.CaFile = model.RepositoryCaFile.ValueString() + cpo.CertFile = model.RepositoryCertFile.ValueString() + cpo.KeyFile = model.RepositoryKeyFile.ValueString() + cpo.Keyring = model.Keyring.ValueString() + cpo.RepoURL = repositoryURL + cpo.Verify = model.Verify.ValueBool() + if !useChartVersion(chartName, cpo.RepoURL) { + cpo.Version = version + } + cpo.Username = model.RepositoryUsername.ValueString() + cpo.Password = model.RepositoryPassword.ValueString() + cpo.PassCredentialsAll = model.PassCredentials.ValueBool() + + return cpo, chartName, diags +} + +func useChartVersion(chart string, repo string) bool { + // checks if chart is a URL or OCI registry + + if _, err := url.ParseRequestURI(chart); err == nil && !registry.IsOCI(chart) { + return true + } + // checks if chart is a local chart + if _, err := os.Stat(chart); err == nil { + return true + } + // checks if repo is a local chart + if _, err := os.Stat(repo); err == nil { + return true + } + + return false +} + +func buildChartNameWithRepository(repository, name string) (string, string, error) { + _, err := url.ParseRequestURI(repository) + if err == nil { + return repository, name, nil + } + + if strings.Index(name, "/") == -1 && repository != "" { + name = fmt.Sprintf("%s/%s", repository, name) + } + + return "", name, nil +} + +func getVersion(model *HelmReleaseModel) string { + version := model.Version.ValueString() + if version == "" && model.Devel.ValueBool() { + return ">0.0.0-0" + } + return strings.TrimSpace(version) +} + +func isChartInstallable(ch *chart.Chart) error { + switch ch.Metadata.Type { + case "", "application": + return nil + } + return errors.Errorf("%s charts are not installable", ch.Metadata.Type) +} + +func getChart(ctx context.Context, model *HelmReleaseModel, m *Meta, name string, cpo *action.ChartPathOptions) (*chart.Chart, string, diag.Diagnostics) { + var diags diag.Diagnostics + + tflog.Debug(ctx, fmt.Sprintf("Helm settings: %+v", m.Settings)) + + path, err := cpo.LocateChart(name, m.Settings) + if err != nil { + diags.AddError("Error locating chart", fmt.Sprintf("Unable to locate chart %s: %s", name, err)) + return nil, "", diags + } + + c, err := loader.Load(path) + if err != nil { + diags.AddError("Error loading chart", fmt.Sprintf("Unable to load chart %s: %s", path, err)) + return nil, "", diags + } + + return c, path, diags +} + +func getWriteOnlyValues(ctx context.Context, model *HelmReleaseModel) (map[string]interface{}, diag.Diagnostics) { + base := map[string]interface{}{} + diags := diag.Diagnostics{} + + if !model.SetWO.IsUnknown() && !model.SetWO.IsNull() { + tflog.Debug(ctx, "Processing SetWO attribute") + var setvals []setResourceModel + setDiags := model.SetWO.ElementsAs(ctx, &setvals, false) + diags.Append(setDiags...) + if diags.HasError() { + return nil, diags + } + for _, set := range setvals { + setDiags := getValue(base, set) + diags.Append(setDiags...) + if diags.HasError() { + return nil, diags + } + } + } + + return base, diags +} + +func getValues(ctx context.Context, model *HelmReleaseModel) (map[string]interface{}, diag.Diagnostics) { + base := map[string]interface{}{} + var diags diag.Diagnostics + + // Processing "values" attribute + for _, raw := range model.Values.Elements() { + if raw.IsNull() { + continue + } + + value, ok := raw.(types.String) + if !ok { + diags.AddError("Type Error", fmt.Sprintf("Expected types.String, got %T", raw)) + return nil, diags + } + + values := value.ValueString() + if values == "" { + continue + } + + currentMap := map[string]interface{}{} + if err := yaml.Unmarshal([]byte(values), ¤tMap); err != nil { + diags.AddError("Error unmarshaling values", fmt.Sprintf("---> %v %s", err, values)) + return nil, diags + } + + base = mergeMaps(base, currentMap) + } + + // Processing "set" attribute + if !model.Set.IsNull() { + tflog.Debug(ctx, "Processing Set attribute") + var setList []setResourceModel + setDiags := model.Set.ElementsAs(ctx, &setList, false) + diags.Append(setDiags...) + if diags.HasError() { + return nil, diags + } + + for i, set := range setList { + tflog.Debug(ctx, fmt.Sprintf("Processing Set element at index %d: %v", i, set)) + setDiags := getValue(base, set) + diags.Append(setDiags...) + if diags.HasError() { + tflog.Debug(ctx, fmt.Sprintf("Error occurred while processing Set element at index %d", i)) + return nil, diags + } + } + } + + // Processing "set_list" attribute + if !model.SetList.IsUnknown() { + tflog.Debug(ctx, "Processing Set_list attribute") + var setListSlice []set_listResourceModel + setListDiags := model.SetList.ElementsAs(ctx, &setListSlice, false) + diags.Append(setListDiags...) + if diags.HasError() { + tflog.Debug(ctx, "Error occurred while processing Set_list attribute") + return nil, diags + } + + for i, setList := range setListSlice { + tflog.Debug(ctx, fmt.Sprintf("Processing Set_list element at index %d: %v", i, setList)) + setListDiags := getListValue(ctx, base, setList) + diags.Append(setListDiags...) + if diags.HasError() { + tflog.Debug(ctx, fmt.Sprintf("Error occurred while processing Set_list element at index %d", i)) + return nil, diags + } + } + } + + // Processing "set_sensitive" attribute + if !model.SetSensitive.IsNull() { + tflog.Debug(ctx, "Processing Set_Sensitive attribute") + var setSensitiveList []setResourceModel + setSensitiveDiags := model.SetSensitive.ElementsAs(ctx, &setSensitiveList, false) + diags.Append(setSensitiveDiags...) + if diags.HasError() { + tflog.Debug(ctx, "Error occurred while processing Set_Sensitive attribute") + return nil, diags + } + + for i, setSensitive := range setSensitiveList { + tflog.Debug(ctx, fmt.Sprintf("Processing Set_Sensitive element at index %d: %v", i, setSensitive)) + setSensitiveDiags := getValue(base, setSensitive) + diags.Append(setSensitiveDiags...) + if diags.HasError() { + tflog.Debug(ctx, fmt.Sprintf("Error occurred while processing Set_Sensitive element at index %d", i)) + return nil, diags + } + } + } + + tflog.Debug(ctx, fmt.Sprintf("Final merged values: %v", base)) + logDiags := logValues(ctx, base, model) + diags.Append(logDiags...) + if diags.HasError() { + tflog.Debug(ctx, "Error occurred while logging values") + return nil, diags + } + + return base, diags +} + +func getValue(base map[string]interface{}, set setResourceModel) diag.Diagnostics { + var diags diag.Diagnostics + + name := set.Name.ValueString() + value := set.Value.ValueString() + valueType := set.Type.ValueString() + + switch valueType { + case "auto", "": + if err := strvals.ParseInto(fmt.Sprintf("%s=%s", name, value), base); err != nil { + diags.AddError("Failed parsing value", fmt.Sprintf("Failed parsing key %q with value %s: %s", name, value, err)) + return diags + } + case "string": + if err := strvals.ParseIntoString(fmt.Sprintf("%s=%s", name, value), base); err != nil { + diags.AddError("Failed parsing string value", fmt.Sprintf("Failed parsing key %q with value %s: %s", name, value, err)) + return diags + } + case "literal": + var literal interface{} + if err := yaml.Unmarshal([]byte(fmt.Sprintf("%s: %s", name, value)), &literal); err != nil { + diags.AddError("Failed parsing literal value", fmt.Sprintf("Key %q with literal value %s: %s", name, value, err)) + return diags + } + + if m, ok := literal.(map[string]interface{}); ok { + base[name] = m[name] + } else { + base[name] = literal + } + default: + diags.AddError("Unexpected type", fmt.Sprintf("Unexpected type: %s", valueType)) + return diags + } + return diags +} + +// deepCloneMap creates a deep copy of a map[string]interface{} +func deepCloneMap(m map[string]interface{}) map[string]interface{} { + if m == nil { + return nil + } + + clone := make(map[string]interface{}, len(m)) + for k, v := range m { + switch val := v.(type) { + case map[string]interface{}: + clone[k] = deepCloneMap(val) + default: + clone[k] = v + } + } + return clone +} + +func logValues(ctx context.Context, values map[string]interface{}, state *HelmReleaseModel) diag.Diagnostics { + var diags diag.Diagnostics + // Deep cloning values map to avoid modifying the original + c := deepCloneMap(values) + + cloakSetValues(c, state) + + y, err := yaml.Marshal(c) + if err != nil { + diags.AddError("Error marshaling map to YAML", fmt.Sprintf("Failed to marshal map to YAML: %s", err)) + return diags + } + + tflog.Debug(ctx, fmt.Sprintf("---[ values.yaml ]-----------------------------------\n%s\n", string(y))) + + return diags +} + +func cloakSetValues(config map[string]interface{}, state *HelmReleaseModel) { + if !state.SetSensitive.IsNull() { + var setSensitiveList []setResourceModel + diags := state.SetSensitive.ElementsAs(context.Background(), &setSensitiveList, false) + if diags.HasError() { + // Handle diagnostics error + return + } + + for _, set := range setSensitiveList { + cloakSetValue(config, set.Name.ValueString()) + } + } +} + +func getListValue(ctx context.Context, base map[string]interface{}, set set_listResourceModel) diag.Diagnostics { + var diags diag.Diagnostics + + name := set.Name.ValueString() + + if set.Value.IsNull() { + diags.AddError("Null List Value", "The list value is null.") + return diags + } + + // Get the elements of the ListValue + elements := set.Value.Elements() + + // Convert elements to a list of strings + listStringArray := make([]string, 0, len(elements)) + for _, element := range elements { + if !element.IsNull() { + strValue := element.(types.String).ValueString() + listStringArray = append(listStringArray, strValue) + } + } + + // Join the list into a single string + listString := strings.Join(listStringArray, ",") + + if err := strvals.ParseInto(fmt.Sprintf("%s={%s}", name, listString), base); err != nil { + diags.AddError("Error parsing list value", fmt.Sprintf("Failed parsing key %q with value %s: %s", name, listString, err)) + return diags + } + + return diags +} + +func versionsEqual(a, b string) bool { + return strings.TrimPrefix(a, "v") == strings.TrimPrefix(b, "v") +} + +func setReleaseAttributes(ctx context.Context, state *HelmReleaseModel, identity *tfsdk.ResourceIdentity, r *release.Release, meta *Meta) diag.Diagnostics { + var diags diag.Diagnostics + + // Update state with attributes from the helm release + state.Name = types.StringValue(r.Name) + version := r.Chart.Metadata.Version + if !versionsEqual(version, state.Version.ValueString()) { + state.Version = types.StringValue(version) + } + + state.Namespace = types.StringValue(r.Namespace) + state.Status = types.StringValue(r.Info.Status.String()) + + state.ID = types.StringValue(r.Name) + + rid := HelmReleaseIdentityModel{ + Namespace: types.StringValue(r.Namespace), + ReleaseName: types.StringValue(r.Name), + } + diags = identity.Set(ctx, rid) + if diags.HasError() { + return diags + } + + // Cloak sensitive values in the release config + values := "{}" + if r.Config != nil { + // Deep clone the config to avoid modifying the original + configClone := deepCloneMap(r.Config) + cloakSetValues(configClone, state) + v, err := json.Marshal(configClone) + if err != nil { + diags.AddError( + "Error marshaling values", + fmt.Sprintf("unable to marshal values: %s", err), + ) + return diags + } + values = string(v) + } + + // Handling the helm release if manifest experiment is enabled + if meta.ExperimentEnabled("manifest") { + jsonManifest, err := convertYAMLManifestToJSON(r.Manifest) + if err != nil { + diags.AddError( + "Error converting manifest to JSON", + fmt.Sprintf("Unable to convert manifest to JSON: %s", err), + ) + return diags + } + sensitiveValues := extractSensitiveValues(state) + manifest := redactSensitiveValues(string(jsonManifest), sensitiveValues) + state.Manifest = types.StringValue(manifest) + } + + // NOTE Don't retrieve values if write-only is being used. + // It is not possible to pick out which values are write-only + // at read time because write-only values are ephemeral + valuesstr := types.StringValue("{}") + if state.SetWORevision.ValueInt64() <= 0 { + valuesstr = types.StringValue(values) + } + + // Create metadata as a slice of maps + metadata := map[string]attr.Value{ + "name": types.StringValue(r.Name), + "revision": types.Int64Value(int64(r.Version)), + "namespace": types.StringValue(r.Namespace), + "chart": types.StringValue(r.Chart.Metadata.Name), + "version": types.StringValue(r.Chart.Metadata.Version), + "app_version": types.StringValue(r.Chart.Metadata.AppVersion), + "values": valuesstr, + "first_deployed": types.Int64Value(r.Info.FirstDeployed.Unix()), + "last_deployed": types.Int64Value(r.Info.LastDeployed.Unix()), + "notes": types.StringValue(r.Info.Notes), + } + + // Convert the list of ObjectValues to a ListValue + metadataObject, diag := types.ObjectValue(metadataAttrTypes(), metadata) + diags.Append(diag...) + if diags.HasError() { + tflog.Error(ctx, "Error converting metadata to ListValue", map[string]interface{}{ + "metadata": metadata, + "error": diags, + }) + + return diags + } + + // Log metadata after conversion + tflog.Debug(ctx, fmt.Sprintf("Metadata after conversion: %+v", metadataObject)) + state.Metadata = metadataObject + return diags +} + +func metadataAttrTypes() map[string]attr.Type { + return map[string]attr.Type{ + "name": types.StringType, + "revision": types.Int64Type, + "namespace": types.StringType, + "chart": types.StringType, + "version": types.StringType, + "app_version": types.StringType, + "values": types.StringType, + "first_deployed": types.Int64Type, + "last_deployed": types.Int64Type, + "notes": types.StringType, + } +} + +func extractSensitiveValues(state *HelmReleaseModel) map[string]string { + sensitiveValues := make(map[string]string) + + if !state.SetSensitive.IsNull() { + var setSensitiveList []setResourceModel + diags := state.SetSensitive.ElementsAs(context.Background(), &setSensitiveList, false) + if diags.HasError() { + return sensitiveValues + } + + for _, set := range setSensitiveList { + sensitiveValues[set.Name.ValueString()] = "(sensitive value)" + } + } + + return sensitiveValues +} + +func (m *Meta) ExperimentEnabled(name string) bool { + if enabled, exists := m.Experiments[name]; exists { + return enabled + } + return false +} + +// c +func resourceReleaseExists(ctx context.Context, name, namespace string, meta *Meta) (bool, diag.Diagnostics) { + logID := fmt.Sprintf("[resourceReleaseExists: %s]", name) + tflog.Debug(ctx, fmt.Sprintf("%s Start", logID)) + + var diags diag.Diagnostics + + c, err := meta.GetHelmConfiguration(ctx, namespace) + if err != nil { + diags.AddError( + "Error getting helm configuration", + fmt.Sprintf("Unable to get Helm configuration for namespace %s: %s", namespace, err), + ) + return false, diags + } + + _, err = getRelease(ctx, meta, c, name) + + tflog.Debug(ctx, fmt.Sprintf("%s Done", logID)) + + if err == nil { + return true, diags + } + + if err == errReleaseNotFound { + return false, diags + } + + diags.AddError( + "Error checking release existence", + fmt.Sprintf("Error checking release %s in namespace %s: %s", name, namespace, err), + ) + return false, diags +} + +var errReleaseNotFound = fmt.Errorf("release: not found") + +// c +func getRelease(ctx context.Context, m *Meta, cfg *action.Configuration, name string) (*release.Release, error) { + get := action.NewGet(cfg) + tflog.Debug(ctx, fmt.Sprintf("%s getRelease post action created", name)) + + res, err := get.Run(name) + tflog.Debug(ctx, fmt.Sprintf("%s getRelease post run", name)) + + if err != nil { + tflog.Debug(ctx, fmt.Sprintf("getRelease for %s occurred", name)) + tflog.Debug(ctx, fmt.Sprintf("%v", err)) + if strings.Contains(err.Error(), "release: not found") { + tflog.Error(ctx, errReleaseNotFound.Error()) + return nil, errReleaseNotFound + } + tflog.Debug(ctx, fmt.Sprintf("Could not get release %s", err)) + tflog.Error(ctx, err.Error()) + return nil, err + } + + tflog.Debug(ctx, fmt.Sprintf("%s getRelease completed", name)) + return res, nil +} + +// c +func checkChartDependencies(ctx context.Context, model *HelmReleaseModel, c *chart.Chart, path string, m *Meta) (bool, diag.Diagnostics) { + var diags diag.Diagnostics + p := getter.All(m.Settings) + + if req := c.Metadata.Dependencies; req != nil { + err := action.CheckDependencies(c, req) + if err != nil { + if model.DependencyUpdate.ValueBool() { + man := &downloader.Manager{ + Out: os.Stdout, + ChartPath: path, + Keyring: model.Keyring.ValueString(), + SkipUpdate: false, + Getters: p, + RepositoryConfig: m.Settings.RepositoryConfig, + RepositoryCache: m.Settings.RepositoryCache, + Debug: m.Settings.Debug, + } + tflog.Debug(ctx, "Downloading chart dependencies...") + if err := man.Update(); err != nil { + diags.AddError("", fmt.Sprintf("Failed to update chart dependencies: %s", err)) + return true, diags + } + return true, diags + } + diags.AddError("", "Found in Chart.yaml, but missing in charts/ directory") + return false, diags + } + } + tflog.Debug(ctx, "Chart dependencies are up to date.") + return false, diags +} + +func (r *HelmRelease) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + if req.Plan.Raw.IsNull() { + // resource is being destroyed + return + } + var plan HelmReleaseModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + var state *HelmReleaseModel + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + var config HelmReleaseModel + resp.Diagnostics.Append(req.Config.Get(ctx, &config)...) + if resp.Diagnostics.HasError() { + return + } + + tflog.Debug(ctx, fmt.Sprintf("Plan state on ModifyPlan: %+v", plan)) + tflog.Debug(ctx, fmt.Sprintf("Actual state on ModifyPlan: %+v", state)) + + logID := fmt.Sprintf("[resourceDiff: %s]", plan.Name.ValueString()) + tflog.Debug(ctx, fmt.Sprintf("%s Start", logID)) + + meta := r.meta + name := plan.Name.ValueString() + namespace := plan.Namespace.ValueString() + + actionConfig, err := meta.GetHelmConfiguration(ctx, namespace) + if err != nil { + resp.Diagnostics.AddError("Error getting Helm configuration", err.Error()) + return + } + tflog.Debug(ctx, fmt.Sprintf("%s Initial Values: Name=%s, Namespace=%s, Repository=%s, Repository_Username=%s, Repository_Password=%s, Chart=%s", logID, + name, namespace, plan.Repository.ValueString(), plan.RepositoryUsername.ValueString(), plan.RepositoryPassword.ValueString(), plan.Chart.ValueString())) + + repositoryURL := plan.Repository.ValueString() + repositoryUsername := plan.RepositoryUsername.ValueString() + repositoryPassword := plan.RepositoryPassword.ValueString() + chartName := plan.Chart.ValueString() + ociDiags := OCIRegistryLogin(ctx, meta, actionConfig, meta.RegistryClient, repositoryURL, chartName, repositoryUsername, repositoryPassword) + resp.Diagnostics.Append(ociDiags...) + if resp.Diagnostics.HasError() { + return + } + + // Always set desired state to DEPLOYED + plan.Status = types.StringValue(release.StatusDeployed.String()) + + if recomputeMetadata(plan, state) { + tflog.Debug(ctx, fmt.Sprintf("%s Metadata has changes, setting to unknown", logID)) + plan.Metadata = types.ObjectUnknown(metadataAttrTypes()) + } + + if !useChartVersion(plan.Chart.ValueString(), plan.Repository.ValueString()) { + // Check if version has changed + if state != nil && !plan.Version.Equal(state.Version) { + + // Ensure trimming 'v' prefix correctly + oldVersionStr := strings.TrimPrefix(state.Version.String(), "v") + newVersionStr := strings.TrimPrefix(plan.Version.String(), "v") + + if oldVersionStr != newVersionStr && newVersionStr != "" { + // Setting Metadata to a computed value + plan.Metadata = types.ObjectUnknown(metadataAttrTypes()) + } + } + } + + client := action.NewInstall(actionConfig) + cpo, chartName, diags := chartPathOptions(&plan, meta, &client.ChartPathOptions) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + chart, path, diags := getChart(ctx, &plan, meta, chartName, cpo) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + tflog.Debug(ctx, fmt.Sprintf("%s Got chart", logID)) + + updated, diags := checkChartDependencies(ctx, &plan, chart, path, meta) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } else if updated { + chart, err = loader.Load(path) + if err != nil { + resp.Diagnostics.AddError("Error loading chart", err.Error()) + return + } + } + + if plan.Lint.ValueBool() { + diags := resourceReleaseValidate(ctx, &plan, meta, cpo) + if diags.HasError() { + resp.Diagnostics.Append(diags...) + return + } + } + tflog.Debug(ctx, fmt.Sprintf("%s Release validated", logID)) + + if meta.ExperimentEnabled("manifest") { + // Check if all necessary values are known + if valuesUnknown(plan) { + tflog.Debug(ctx, "not all values are known, skipping dry run to render manifest") + plan.Manifest = types.StringNull() + plan.Version = types.StringNull() + return + } + + if plan.PostRender != nil { + binaryPath := plan.PostRender.BinaryPath.ValueString() + argsList := plan.PostRender.Args.Elements() + + var args []string + for _, arg := range argsList { + args = append(args, arg.(basetypes.StringValue).ValueString()) + } + + pr, err := postrender.NewExec(binaryPath, args...) + if err != nil { + resp.Diagnostics.AddError("Error creating post-renderer", fmt.Sprintf("Could not create post-renderer: %s", err)) + return + } + + client.PostRenderer = pr + } + if state == nil { + install := action.NewInstall(actionConfig) + install.ChartPathOptions = *cpo + install.DryRun = true + install.DisableHooks = plan.DisableWebhooks.ValueBool() + install.Wait = plan.Wait.ValueBool() + install.WaitForJobs = plan.WaitForJobs.ValueBool() + install.Devel = plan.Devel.ValueBool() + install.DependencyUpdate = plan.DependencyUpdate.ValueBool() + install.Timeout = time.Duration(plan.Timeout.ValueInt64()) * time.Second + install.Namespace = plan.Namespace.ValueString() + install.ReleaseName = plan.Name.ValueString() + install.Atomic = plan.Atomic.ValueBool() + install.SkipCRDs = plan.SkipCrds.ValueBool() + install.SubNotes = plan.RenderSubchartNotes.ValueBool() + install.DisableOpenAPIValidation = plan.DisableOpenapiValidation.ValueBool() + install.Replace = plan.Replace.ValueBool() + install.Description = plan.Description.ValueString() + install.CreateNamespace = plan.CreateNamespace.ValueBool() + install.PostRenderer = client.PostRenderer + + values, diags := getValues(ctx, &plan) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + tflog.Debug(ctx, fmt.Sprintf("%s performing dry run install", logID)) + dry, err := install.Run(chart, values) + if err != nil { + // NOTE if the cluster is not reachable then we can't run the install + // this will happen if the user has their cluster creation in the + // same apply. We are catching this case here and marking manifest + // as computed to avoid breaking existing configs + + if strings.Contains(err.Error(), "Kubernetes cluster unreachable") { + resp.Diagnostics.AddError("cluster was unreachable at create time, marking manifest as computed", err.Error()) + plan.Manifest = types.StringNull() + return + } + resp.Diagnostics.AddError("Error performing dry run install", err.Error()) + return + } + + jsonManifest, err := convertYAMLManifestToJSON(dry.Manifest) + if err != nil { + resp.Diagnostics.AddError("Error converting YAML manifest to JSON", err.Error()) + return + } + valuesMap := make(map[string]string) + if !plan.SetSensitive.IsNull() { + var setSensitiveList []setResourceModel + setSensitiveDiags := plan.SetSensitive.ElementsAs(ctx, &setSensitiveList, false) + resp.Diagnostics.Append(setSensitiveDiags...) + if resp.Diagnostics.HasError() { + return + } + + for _, set := range setSensitiveList { + valuesMap[set.Name.ValueString()] = set.Value.ValueString() + } + } + manifest := redactSensitiveValues(string(jsonManifest), valuesMap) + plan.Manifest = types.StringValue(manifest) + return + } + + _, err = getRelease(ctx, meta, actionConfig, name) + if err == errReleaseNotFound { + if len(chart.Metadata.Version) > 0 { + plan.Version = types.StringValue(chart.Metadata.Version) + } + plan.Manifest = types.StringNull() + return + } else if err != nil { + resp.Diagnostics.AddError("Error retrieving old release for a diff", err.Error()) + return + } + + upgrade := action.NewUpgrade(actionConfig) + upgrade.ChartPathOptions = *cpo + upgrade.Devel = plan.Devel.ValueBool() + upgrade.Namespace = plan.Namespace.ValueString() + upgrade.Timeout = time.Duration(plan.Timeout.ValueInt64()) * time.Second + upgrade.Wait = plan.Wait.ValueBool() + upgrade.DryRun = true + upgrade.DisableHooks = plan.DisableWebhooks.ValueBool() + upgrade.Atomic = plan.Atomic.ValueBool() + upgrade.SubNotes = plan.RenderSubchartNotes.ValueBool() + upgrade.WaitForJobs = plan.WaitForJobs.ValueBool() + upgrade.Force = plan.ForceUpdate.ValueBool() + upgrade.ResetValues = plan.ResetValues.ValueBool() + upgrade.ReuseValues = plan.ReuseValues.ValueBool() + upgrade.Recreate = plan.RecreatePods.ValueBool() + upgrade.MaxHistory = int(plan.MaxHistory.ValueInt64()) + upgrade.CleanupOnFail = plan.CleanupOnFail.ValueBool() + upgrade.Description = plan.Description.ValueString() + upgrade.PostRenderer = client.PostRenderer + + values, diags := getValues(ctx, &plan) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + tflog.Debug(ctx, fmt.Sprintf("%s performing dry run upgrade", logID)) + dry, err := upgrade.Run(name, chart, values) + if err != nil && strings.Contains(err.Error(), "has no deployed releases") { + if len(chart.Metadata.Version) > 0 && cpo.Version != "" { + plan.Version = types.StringValue(chart.Metadata.Version) + } + plan.Version = types.StringNull() + plan.Manifest = types.StringNull() + return + } else if err != nil { + resp.Diagnostics.AddError("Error running dry run for a diff", err.Error()) + return + } + + jsonManifest, err := convertYAMLManifestToJSON(dry.Manifest) + if err != nil { + resp.Diagnostics.AddError("Error converting YAML manifest to JSON", err.Error()) + return + } + valuesMap := make(map[string]string) + if !plan.SetSensitive.IsNull() { + var setSensitiveList []setResourceModel + setSensitiveDiags := plan.SetSensitive.ElementsAs(ctx, &setSensitiveList, false) + resp.Diagnostics.Append(setSensitiveDiags...) + if resp.Diagnostics.HasError() { + return + } + + for _, set := range setSensitiveList { + valuesMap[set.Name.ValueString()] = set.Value.ValueString() + } + } + manifest := redactSensitiveValues(string(jsonManifest), valuesMap) + plan.Manifest = types.StringValue(manifest) + tflog.Debug(ctx, fmt.Sprintf("%s set manifest: %s", logID, jsonManifest)) + } else { + plan.Manifest = types.StringNull() + } + + tflog.Debug(ctx, fmt.Sprintf("%s Done", logID)) + + if len(chart.Metadata.Version) > 0 { + plan.Version = types.StringValue(chart.Metadata.Version) + } else { + plan.Version = types.StringNull() + } + + if !config.Version.IsNull() && !config.Version.Equal(plan.Version) { + if versionsEqual(config.Version.ValueString(), plan.Version.ValueString()) { + plan.Version = config.Version + } else { + resp.Diagnostics.AddError( + "Planned version is different from configured version", + fmt.Sprintf(`The version in the configuration is %q but the planned version is %q. +You should update the version in your configuration to %[2]q, or remove the version attribute from your configuration.`, config.Version.ValueString(), plan.Version.ValueString())) + return + } + } + + resp.Plan.Set(ctx, &plan) +} + +// TODO: write unit test, always returns true for recomputing the metadata +// returns true if any metadata fields have changed +func recomputeMetadata(plan HelmReleaseModel, state *HelmReleaseModel) bool { + if state == nil { + return true + } + + if !plan.Chart.Equal(state.Chart) { + return true + } + if !plan.Repository.Equal(state.Repository) { + return true + } + if !plan.Values.Equal(state.Values) { + return true + } + if !plan.Set.Equal(state.Set) { + return true + } + if !plan.SetSensitive.Equal(state.SetSensitive) { + return true + } + if !plan.SetList.Equal(state.SetList) { + return true + } + return false +} + +func resourceReleaseValidate(ctx context.Context, model *HelmReleaseModel, meta *Meta, cpo *action.ChartPathOptions) diag.Diagnostics { + var diags diag.Diagnostics + + cpo, name, chartDiags := chartPathOptions(model, meta, cpo) + diags.Append(chartDiags...) + if diags.HasError() { + diags.AddError("Malformed values", fmt.Sprintf("Chart path options error: %s", chartDiags)) + return diags + } + + values, valuesDiags := getValues(ctx, model) + diags.Append(valuesDiags...) + if diags.HasError() { + return diags + } + + lintDiags := lintChart(meta, name, cpo, values) + if lintDiags != nil { + diagnostic := diag.NewErrorDiagnostic("Lint Error", lintDiags.Error()) + diags = append(diags, diagnostic) + } + return diags +} + +func lintChart(m *Meta, name string, cpo *action.ChartPathOptions, values map[string]interface{}) error { + path, err := cpo.LocateChart(name, m.Settings) + if err != nil { + return err + } + + l := action.NewLint() + result := l.Run([]string{path}, values) + + return resultToError(result) +} + +func resultToError(r *action.LintResult) error { + if len(r.Errors) == 0 { + return nil + } + + messages := []string{} + for _, msg := range r.Messages { + for _, err := range r.Errors { + if err == msg.Err { + messages = append(messages, fmt.Sprintf("%s: %s", msg.Path, msg.Err)) + break + } + } + } + + return fmt.Errorf("malformed chart or values: \n\t%s", strings.Join(messages, "\n\t")) +} + +func (r *HelmRelease) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + var namespace, name string + if req.ID != "" { + tflog.Debug(ctx, "Using ID string for import") + var err error + namespace, name, err = parseImportIdentifier(req.ID) + if err != nil { + resp.Diagnostics.AddError( + "Unable to parse import identifier", + fmt.Sprintf("Unable to parse identifier %s: %s", req.ID, err), + ) + return + } + } else { + tflog.Debug(ctx, "Using Resource Identity for Import") + rid := HelmReleaseIdentityModel{ + Namespace: types.StringValue("default"), + } + diags := req.Identity.Get(ctx, &rid) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + namespace = rid.Namespace.ValueString() + name = rid.ReleaseName.ValueString() + } + + meta := r.meta + if meta == nil { + resp.Diagnostics.AddError( + "Meta not set", + "The meta information is not set for the resource", + ) + return + } + + actionConfig, err := meta.GetHelmConfiguration(ctx, namespace) + if err != nil { + resp.Diagnostics.AddError( + "Error getting helm configuration", + fmt.Sprintf("Unable to get Helm configuration for namespace %s: %s", namespace, err), + ) + return + } + + release, err := getRelease(ctx, meta, actionConfig, name) + if err != nil { + resp.Diagnostics.AddError( + "Error getting release", + fmt.Sprintf("Unable to get Helm release %s: %s", name, err.Error()), + ) + return + } + + var state HelmReleaseModel + state.Name = types.StringValue(release.Name) + state.Description = types.StringValue(release.Info.Description) + state.Chart = types.StringValue(release.Chart.Metadata.Name) + + // Set release-specific attributes using the helper function + diags := setReleaseAttributes(ctx, &state, resp.Identity, release, meta) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + state.Set = types.ListNull(types.ObjectType{ + AttrTypes: map[string]attr.Type{ + "name": types.StringType, + "type": types.StringType, + "value": types.StringType, + }, + }) + state.SetWO = types.ListNull(types.ObjectType{ + AttrTypes: map[string]attr.Type{ + "name": types.StringType, + "type": types.StringType, + "value": types.StringType, + }, + }) + state.SetSensitive = types.ListNull(types.ObjectType{ + AttrTypes: map[string]attr.Type{ + "name": types.StringType, + "type": types.StringType, + "value": types.StringType, + }, + }) + state.SetList = types.ListNull(types.ObjectType{ + AttrTypes: map[string]attr.Type{ + "name": types.StringType, + "value": types.ListType{ + ElemType: types.StringType, + }, + }, + }) + state.Values = types.ListNull(types.StringType) + + tflog.Debug(ctx, fmt.Sprintf("Setting final state: %+v", state)) + diags = resp.State.Set(ctx, &state) + resp.Diagnostics.Append(diags...) + if diags.HasError() { + fmt.Println("DOH") + tflog.Error(ctx, "Error setting final state", map[string]interface{}{ + "state": state, + "diagnostics": diags, + }) + return + } + + // Set default attributes + for key, value := range defaultAttributes { + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root(key), value)...) + if resp.Diagnostics.HasError() { + return + } + } +} + +func parseImportIdentifier(id string) (string, string, error) { + parts := strings.Split(id, "/") + if len(parts) != 2 { + err := errors.Errorf("Unexpected ID format (%q), expected namespace/name", id) + return "", "", err + } + + return parts[0], parts[1], nil +} + +// returns true if any values, set_list, set, set_sensitive are unknown +func valuesUnknown(plan HelmReleaseModel) bool { + if plan.Values.IsUnknown() { + return true + } + if plan.SetList.IsUnknown() { + return true + } + if plan.Set.IsUnknown() { + return true + } + if plan.SetSensitive.IsUnknown() { + return true + } + return false +} diff --git a/shuttles/terraform/terraform-provider-helm/helm/resource_helm_release_stateupgrader.go b/shuttles/terraform/terraform-provider-helm/helm/resource_helm_release_stateupgrader.go new file mode 100644 index 0000000..5195007 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/resource_helm_release_stateupgrader.go @@ -0,0 +1,325 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 +package helm + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-go/tfprotov6" + "github.com/hashicorp/terraform-plugin-go/tftypes" +) + +func (r *HelmRelease) buildUpgradeStateMap(_ context.Context) map[int64]resource.StateUpgrader { + return map[int64]resource.StateUpgrader{ + 1: { + StateUpgrader: func(ctx context.Context, req resource.UpgradeStateRequest, resp *resource.UpgradeStateResponse) { + oldType := tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "metadata": tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "name": tftypes.String, + "namespace": tftypes.String, + "revision": tftypes.Number, + "version": tftypes.String, + "chart": tftypes.String, + "app_version": tftypes.String, + "values": tftypes.String, + "first_deployed": tftypes.Number, + "last_deployed": tftypes.Number, + "notes": tftypes.String, + }, + }, + }, + "postrender": tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "binary_path": tftypes.String, + "args": tftypes.List{ElementType: tftypes.String}, + }, + }, + }, + + "set": tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "name": tftypes.String, + "value": tftypes.String, + "type": tftypes.String, + }, + }, + }, + "set_list": tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "name": tftypes.String, + "value": tftypes.List{ + ElementType: tftypes.String, + }, + }, + }, + }, + "set_sensitive": tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "name": tftypes.String, + "value": tftypes.String, + "type": tftypes.String, + }, + }, + }, + "atomic": tftypes.Bool, + "chart": tftypes.String, + "cleanup_on_fail": tftypes.Bool, + "create_namespace": tftypes.Bool, + "dependency_update": tftypes.Bool, + "description": tftypes.String, + "devel": tftypes.Bool, + "disable_crd_hooks": tftypes.Bool, + "disable_openapi_validation": tftypes.Bool, + "disable_webhooks": tftypes.Bool, + "force_update": tftypes.Bool, + "id": tftypes.String, + "keyring": tftypes.String, + "lint": tftypes.Bool, + "manifest": tftypes.String, + "max_history": tftypes.Number, + "name": tftypes.String, + "namespace": tftypes.String, + "pass_credentials": tftypes.Bool, + "recreate_pods": tftypes.Bool, + "render_subchart_notes": tftypes.Bool, + "replace": tftypes.Bool, + "repository": tftypes.String, + "repository_ca_file": tftypes.String, + "repository_cert_file": tftypes.String, + "repository_key_file": tftypes.String, + "repository_password": tftypes.String, + "repository_username": tftypes.String, + "reset_values": tftypes.Bool, + "reuse_values": tftypes.Bool, + "skip_crds": tftypes.Bool, + "status": tftypes.String, + "timeout": tftypes.Number, + "upgrade_install": tftypes.String, + "values": tftypes.List{ElementType: tftypes.String}, + "verify": tftypes.Bool, + "version": tftypes.String, + "wait": tftypes.Bool, + "wait_for_jobs": tftypes.Bool, + }, + } + + // Unmarshalling the old raw state as old type + oldRawValue, err := req.RawState.Unmarshal(oldType) + if err != nil { + resp.Diagnostics.AddError("Failed to unmarshal prior state", err.Error()) + return + } + + var oldState map[string]tftypes.Value + if err := oldRawValue.As(&oldState); err != nil { + resp.Diagnostics.AddError("Failed to convert old state", err.Error()) + return + } + + // Converting metadata into object + var metadataList []tftypes.Value + if err := oldState["metadata"].As(&metadataList); err != nil || len(metadataList) == 0 { + resp.Diagnostics.AddError("Invalid old metadata format", "Expected a non-empty list") + return + } + + var metadata map[string]tftypes.Value + if err := metadataList[0].As(&metadata); err != nil { + resp.Diagnostics.AddError("Failed to read metadata[0]", err.Error()) + return + } + var postrenderList []tftypes.Value + var prObj map[string]tftypes.Value + + if prVal, ok := oldState["postrender"]; ok && !prVal.IsNull() { + if err := prVal.As(&postrenderList); err == nil && len(postrenderList) > 0 { + if err := postrenderList[0].As(&prObj); err != nil { + resp.Diagnostics.AddError("Failed to read postrender[0]", err.Error()) + return + } + } + } + + if prObj == nil { + prObj = map[string]tftypes.Value{ + "binary_path": tftypes.NewValue(tftypes.String, ""), + "args": tftypes.NewValue(tftypes.List{ElementType: tftypes.String}, []tftypes.Value{}), + } + } + + // Creating new type in FW + newType := tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "metadata": tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "name": tftypes.String, + "namespace": tftypes.String, + "revision": tftypes.Number, + "version": tftypes.String, + "chart": tftypes.String, + "app_version": tftypes.String, + "values": tftypes.String, + "first_deployed": tftypes.Number, + "last_deployed": tftypes.Number, + "notes": tftypes.String, + }, + }, + "postrender": tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "binary_path": tftypes.String, + "args": tftypes.List{ElementType: tftypes.String}, + }, + }, + "set": tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "name": tftypes.String, + "value": tftypes.String, + "type": tftypes.String, + }, + }, + }, + "set_list": tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "name": tftypes.String, + "value": tftypes.List{ + ElementType: tftypes.String, + }, + }, + }, + }, + "set_sensitive": tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "name": tftypes.String, + "value": tftypes.String, + "type": tftypes.String, + }, + }, + }, + "set_wo": tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "name": tftypes.String, + "value": tftypes.String, + "type": tftypes.String, + }, + }, + }, + "atomic": tftypes.Bool, + "chart": tftypes.String, + "cleanup_on_fail": tftypes.Bool, + "create_namespace": tftypes.Bool, + "dependency_update": tftypes.Bool, + "description": tftypes.String, + "devel": tftypes.Bool, + "disable_crd_hooks": tftypes.Bool, + "disable_openapi_validation": tftypes.Bool, + "disable_webhooks": tftypes.Bool, + "force_update": tftypes.Bool, + "id": tftypes.String, + "keyring": tftypes.String, + "lint": tftypes.Bool, + "manifest": tftypes.String, + "max_history": tftypes.Number, + "name": tftypes.String, + "namespace": tftypes.String, + "pass_credentials": tftypes.Bool, + "recreate_pods": tftypes.Bool, + "render_subchart_notes": tftypes.Bool, + "replace": tftypes.Bool, + "repository": tftypes.String, + "repository_ca_file": tftypes.String, + "repository_cert_file": tftypes.String, + "repository_key_file": tftypes.String, + "repository_password": tftypes.String, + "repository_username": tftypes.String, + "reset_values": tftypes.Bool, + "reuse_values": tftypes.Bool, + "skip_crds": tftypes.Bool, + "set_wo_revision": tftypes.Number, + "status": tftypes.String, + "timeout": tftypes.Number, + "values": tftypes.List{ElementType: tftypes.String}, + "verify": tftypes.Bool, + "version": tftypes.String, + "wait": tftypes.Bool, + "wait_for_jobs": tftypes.Bool, + }, + } + newValue := tftypes.NewValue(newType, map[string]tftypes.Value{ + "metadata": tftypes.NewValue(newType.AttributeTypes["metadata"], metadata), + "postrender": tftypes.NewValue( + newType.AttributeTypes["postrender"], + prObj, + ), + "set_wo": tftypes.NewValue( + newType.AttributeTypes["set_wo"], + []tftypes.Value{}, + ), + "set_wo_revision": tftypes.NewValue(tftypes.Number, float64(1)), + "atomic": oldState["atomic"], + "chart": oldState["chart"], + "cleanup_on_fail": oldState["cleanup_on_fail"], + "create_namespace": oldState["create_namespace"], + "dependency_update": oldState["dependency_update"], + "description": oldState["description"], + "devel": oldState["devel"], + "disable_crd_hooks": oldState["disable_crd_hooks"], + "disable_openapi_validation": oldState["disable_openapi_validation"], + "disable_webhooks": oldState["disable_webhooks"], + "force_update": oldState["force_update"], + "id": oldState["id"], + "keyring": oldState["keyring"], + "lint": oldState["lint"], + "manifest": oldState["manifest"], + "max_history": oldState["max_history"], + "name": oldState["name"], + "namespace": oldState["namespace"], + "pass_credentials": oldState["pass_credentials"], + "recreate_pods": oldState["recreate_pods"], + "render_subchart_notes": oldState["render_subchart_notes"], + "replace": oldState["replace"], + "repository": oldState["repository"], + "repository_ca_file": oldState["repository_ca_file"], + "repository_cert_file": oldState["repository_cert_file"], + "repository_key_file": oldState["repository_key_file"], + "repository_password": oldState["repository_password"], + "repository_username": oldState["repository_username"], + "reset_values": oldState["reset_values"], + "reuse_values": oldState["reuse_values"], + "set": oldState["set"], + "set_list": oldState["set_list"], + "set_sensitive": oldState["set_sensitive"], + "skip_crds": oldState["skip_crds"], + "status": oldState["status"], + "timeout": oldState["timeout"], + "values": oldState["values"], + "verify": oldState["verify"], + "version": oldState["version"], + "wait": oldState["wait"], + "wait_for_jobs": oldState["wait_for_jobs"], + }) + + dv, err := tfprotov6.NewDynamicValue(newType, newValue) + if err != nil { + resp.Diagnostics.AddError("Failed to construct upgraded state", err.Error()) + return + } + // Providing a message to the user, informing there state has been migrated to the current framework strucuture + resp.Diagnostics.AddWarning("UpgradeState Triggered", "Successfully migrated state from SDKv2 to Plugin Framework") + + resp.DynamicValue = &dv + }, + }, + } +} diff --git a/shuttles/terraform/terraform-provider-helm/helm/resource_helm_release_stateupgrader_test.go b/shuttles/terraform/terraform-provider-helm/helm/resource_helm_release_stateupgrader_test.go new file mode 100644 index 0000000..654f6f4 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/resource_helm_release_stateupgrader_test.go @@ -0,0 +1,215 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package helm + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +func TestAccHelmRelease_Upgrade_MetadataStructure(t *testing.T) { + name := randName("upgrade") + namespace := "default" + resourceName := "helm_release.test" + + resource.ParallelTest(t, resource.TestCase{ + Steps: []resource.TestStep{ + // Step 1: Apply using SDKv2 (v2.17.0) + { + ExternalProviders: map[string]resource.ExternalProvider{ + "helm": { + Source: "hashicorp/helm", + VersionConstraint: "=2.17.0", + }, + }, + Config: fmt.Sprintf(` +resource "helm_release" "test" { + name = "%s" + namespace = "%s" + repository = "https://charts.bitnami.com/bitnami" + chart = "nginx" + version = "15.0.0" + wait = false +} +`, name, namespace), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "metadata.0.name", name), + resource.TestCheckResourceAttr(resourceName, "metadata.0.namespace", namespace), + resource.TestCheckResourceAttr(resourceName, "metadata.0.chart", "nginx"), + resource.TestCheckResourceAttr(resourceName, "metadata.0.version", "15.0.0"), + resource.TestCheckResourceAttr(resourceName, "metadata.0.app_version", "1.25.0"), + resource.TestCheckResourceAttr(resourceName, "status", "deployed"), + resource.TestCheckResourceAttrSet(resourceName, "metadata.0.notes"), + resource.TestCheckResourceAttrSet(resourceName, "metadata.0.first_deployed"), + resource.TestCheckResourceAttrSet(resourceName, "metadata.0.last_deployed"), + resource.TestCheckResourceAttr(resourceName, "metadata.0.revision", "1"), + resource.TestCheckResourceAttr(resourceName, "metadata.0.values", "{}"), + ), + }, + + // Step 2: Reapply using Plugin Framework + { + ProtoV6ProviderFactories: protoV6ProviderFactories(), + Config: fmt.Sprintf(` +resource "helm_release" "test" { + name = "%s" + namespace = "%s" + repository = "https://charts.bitnami.com/bitnami" + chart = "nginx" + version = "15.0.0" + wait = false +} +`, name, namespace), + // Checking if strucuture of metadata has been migrated to plugin framework strucuture + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "metadata.name", name), + resource.TestCheckResourceAttr(resourceName, "metadata.namespace", namespace), + resource.TestCheckResourceAttr(resourceName, "metadata.chart", "nginx"), + resource.TestCheckResourceAttr(resourceName, "metadata.version", "15.0.0"), + resource.TestCheckResourceAttr(resourceName, "metadata.app_version", "1.25.0"), + resource.TestCheckResourceAttr(resourceName, "status", "deployed"), + resource.TestCheckResourceAttrSet(resourceName, "metadata.notes"), + resource.TestCheckResourceAttrSet(resourceName, "metadata.first_deployed"), + resource.TestCheckResourceAttrSet(resourceName, "metadata.last_deployed"), + resource.TestCheckResourceAttr(resourceName, "metadata.revision", "2"), + ), + }, + }, + }) +} + +func TestAccHelmRelease_Upgrade_values(t *testing.T) { + // regression test, see: https://github.com/hashicorp/terraform-provider-helm/issues/1637 + + name := randName("upgrade") + namespace := "default" + resourceName := "helm_release.test" + + resource.ParallelTest(t, resource.TestCase{ + Steps: []resource.TestStep{ + { + ExternalProviders: map[string]resource.ExternalProvider{ + "helm": { + Source: "hashicorp/helm", + VersionConstraint: "=2.17.0", + }, + }, + Config: fmt.Sprintf(` +resource "helm_release" "test" { + name = "%s" + namespace = "%s" + repository = "https://charts.bitnami.com/bitnami" + chart = "nginx" + version = "15.0.0" + wait = false + values = [ +< ")[1], ":")[1]) + ociRegistryURL := fmt.Sprintf("oci://localhost:%s/helm-charts", ociRegistryPort) + + t.Log("OCI registry started at", ociRegistryURL) + + // package chart + t.Log("packaging test-chart") + cmd = exec.Command(helmPath, "package", "testdata/charts/test-chart") + out, err = cmd.CombinedOutput() + t.Log(string(out)) + if err != nil { + t.Errorf("Failed to package chart: %v", err) + return "", nil + } + + if usepassword { + // log into OCI registry + t.Log("logging in to test-chart to OCI registry") + cmd = exec.Command(helmPath, "registry", "login", + fmt.Sprintf("localhost:%s", ociRegistryPort), + "--username", "hashicorp", + "--password", "terraform") + out, err = cmd.CombinedOutput() + t.Log(string(out)) + if err != nil { + t.Errorf("Failed to login to OCI registry: %v", err) + return "", nil + } + } + + // push chart to OCI registry + t.Log("pushing test-chart to OCI registry") + cmd = exec.Command(helmPath, "push", + "test-chart-1.2.3.tgz", + ociRegistryURL) + out, err = cmd.CombinedOutput() + t.Log(string(out)) + if err != nil { + t.Errorf("Failed to push chart: %v", err) + return "", nil + } + + return ociRegistryURL, func() { + t.Log("stopping OCI registry") + cmd := exec.Command(dockerPath, "rm", + "--force", registryContainerName) + out, err := cmd.CombinedOutput() + t.Log(string(out)) + if err != nil { + t.Errorf("Failed to stop OCI registry: %v", err) + } + } +} + +func TestAccResourceRelease_OCI_repository(t *testing.T) { + name := randName("oci") + namespace := createRandomNamespace(t) + defer deleteNamespace(t, namespace) + + ociRegistryURL, shutdown := setupOCIRegistry(t, false) + defer shutdown() + + resource.Test(t, resource.TestCase{ + //PreCheck: func() { + // testAccPreCheck(t) + //}, + ProtoV6ProviderFactories: protoV6ProviderFactories(), + // CheckDestroy: testAccCheckHelmReleaseDestroy(namespace), + Steps: []resource.TestStep{ + { + Config: testAccHelmReleaseConfig_OCI(testResourceName, namespace, name, ociRegistryURL, "1.2.3"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("helm_release.test", "metadata.name", name), + resource.TestCheckResourceAttr("helm_release.test", "metadata.namespace", namespace), + resource.TestCheckResourceAttr("helm_release.test", "metadata.version", "1.2.3"), + resource.TestCheckResourceAttr("helm_release.test", "status", release.StatusDeployed.String()), + ), + }, + { + Config: testAccHelmReleaseConfig_OCI_updated(testResourceName, namespace, name, ociRegistryURL, "1.2.3"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("helm_release.test", "metadata.name", name), + resource.TestCheckResourceAttr("helm_release.test", "metadata.namespace", namespace), + resource.TestCheckResourceAttr("helm_release.test", "metadata.version", "1.2.3"), + resource.TestCheckResourceAttr("helm_release.test", "status", release.StatusDeployed.String()), + resource.TestCheckResourceAttr("helm_release.test", "set.0.name", "replicaCount"), + resource.TestCheckResourceAttr("helm_release.test", "set.0.value", "2"), + ), + }, + { + Config: testAccHelmReleaseConfig_OCI_chartName(testResourceName, namespace, name, fmt.Sprintf("%s/%s", ociRegistryURL, "test-chart"), "1.2.3"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("helm_release.test", "metadata.name", name), + resource.TestCheckResourceAttr("helm_release.test", "metadata.namespace", namespace), + resource.TestCheckResourceAttr("helm_release.test", "metadata.version", "1.2.3"), + resource.TestCheckResourceAttr("helm_release.test", "status", release.StatusDeployed.String()), + resource.TestCheckResourceAttr("helm_release.test", "chart", fmt.Sprintf("%s/%s", ociRegistryURL, "test-chart")), + ), + }, + }, + }) +} + +// passes but make sure to change attributes in the config to single instead of list nested attribute +func TestAccResourceRelease_OCI_registry_login(t *testing.T) { + name := randName("oci") + namespace := createRandomNamespace(t) + defer deleteNamespace(t, namespace) + + ociRegistryURL, shutdown := setupOCIRegistry(t, false) + defer shutdown() + + resource.Test(t, resource.TestCase{ + //PreCheck: func() { + // testAccPreCheck(t) + //}, + ProtoV6ProviderFactories: protoV6ProviderFactories(), + // CheckDestroy: testAccCheckHelmReleaseDestroy(namespace), + Steps: []resource.TestStep{ + { + Config: testAccHelmReleaseConfig_OCI_login_provider(os.Getenv("KUBE_CONFIG_PATH"), testResourceName, namespace, name, ociRegistryURL, "1.2.3", "hashicorp", "terraform", "test-chart"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("helm_release.test", "metadata.name", name), + resource.TestCheckResourceAttr("helm_release.test", "metadata.namespace", namespace), + resource.TestCheckResourceAttr("helm_release.test", "metadata.version", "1.2.3"), + resource.TestCheckResourceAttr("helm_release.test", "status", release.StatusDeployed.String()), + ), + }, + }, + }) +} + +func testAccHelmReleaseConfig_OCI_login_provider(kubeconfig, resource, ns, name, repo, version, username, password, chart string) string { + return fmt.Sprintf(` +provider "helm" { + kubernetes = { + config_path = "%s" + } + registries = [{ + url = "%s" + username = "%s" + password = "%s" + }] +} + +resource "helm_release" "%s" { + name = "%s" + namespace = "%s" + version = "%s" + repository = "%s" + chart = "%s" +}`, kubeconfig, repo, username, password, resource, name, ns, version, repo, chart) +} + +func TestAccResourceRelease_OCI_login(t *testing.T) { + name := randName("oci") + namespace := createRandomNamespace(t) + defer deleteNamespace(t, namespace) + + ociRegistryURL, shutdown := setupOCIRegistry(t, true) + defer shutdown() + + resource.Test(t, resource.TestCase{ + //PreCheck: func() { + //testAccPreCheck(t) + //}, + ProtoV6ProviderFactories: protoV6ProviderFactories(), + // CheckDestroy: testAccCheckHelmReleaseDestroy(namespace), + Steps: []resource.TestStep{ + { + Config: testAccHelmReleaseConfig_OCI_login_multiple(testResourceName, namespace, name, ociRegistryURL, "1.2.3", "hashicorp", "terraform"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("helm_release.test1", "metadata.name", name+"1"), + resource.TestCheckResourceAttr("helm_release.test1", "metadata.namespace", namespace), + resource.TestCheckResourceAttr("helm_release.test1", "metadata.version", "1.2.3"), + resource.TestCheckResourceAttr("helm_release.test1", "status", release.StatusDeployed.String()), + resource.TestCheckResourceAttr("helm_release.test2", "metadata.name", name+"2"), + resource.TestCheckResourceAttr("helm_release.test2", "metadata.namespace", namespace), + resource.TestCheckResourceAttr("helm_release.test2", "metadata.version", "1.2.3"), + resource.TestCheckResourceAttr("helm_release.test2", "status", release.StatusDeployed.String()), + ), + }, + }, + }) +} + +func TestAccResourceRelease_recomputeMetadata(t *testing.T) { + name := randName("basic") + namespace := createRandomNamespace(t) + defer deleteNamespace(t, namespace) + + resource.Test(t, resource.TestCase{ + // PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: protoV6ProviderFactories(), + ExternalProviders: map[string]resource.ExternalProvider{ + "local": { + Source: "hashicorp/local", + }, + }, + // CheckDestroy: testAccCheckHelmReleaseDestroy(namespace), + Steps: []resource.TestStep{ + { + Config: testAccHelmReleaseRecomputeMetadata(testResourceName, namespace, name), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("helm_release.test", "metadata.name", name), + resource.TestCheckResourceAttr("helm_release.test", "metadata.namespace", namespace), + resource.TestCheckResourceAttr("helm_release.test", "metadata.revision", "1"), + resource.TestCheckResourceAttr("helm_release.test", "status", release.StatusDeployed.String()), + resource.TestCheckResourceAttr("helm_release.test", "metadata.version", "2.0.0"), + resource.TestCheckResourceAttr("helm_release.test", "set.%", "0"), + ), + }, + { + Config: testAccHelmReleaseRecomputeMetadataSet(testResourceName, namespace, name), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("helm_release.test", "metadata.version", "2.0.0"), + resource.TestCheckResourceAttr("helm_release.test", "status", release.StatusDeployed.String()), + resource.TestCheckResourceAttr("helm_release.test", "set.0.name", "test"), + resource.TestCheckResourceAttr("helm_release.test", "set.0.value", "test"), + ), + }, + { + Config: testAccHelmReleaseRecomputeMetadataSet(testResourceName, namespace, name), + PlanOnly: true, + }, + }, + }) +} + +func testAccHelmReleaseConfig_OCI(resource, ns, name, repo, version string) string { + return fmt.Sprintf(` + resource "helm_release" "%s" { + name = %q + namespace = %q + repository = %q + version = %q + chart = "test-chart" + } + `, resource, name, ns, repo, version) +} + +func testAccHelmReleaseConfig_OCI_login_multiple(resource, ns, name, repo, version, username, password string) string { + return fmt.Sprintf(` + resource "helm_release" "%s1" { + name = "%s1" + namespace = %q + repository = %q + version = %q + chart = "test-chart" + + repository_username = %q + repository_password = %q + } + resource "helm_release" "%[1]s2" { + name = "%[2]s2" + namespace = %[3]q + repository = %[4]q + version = %[5]q + chart = "test-chart" + + repository_username = %[6]q + repository_password = %[7]q + } + `, resource, name, ns, repo, version, username, password) +} + +func testAccHelmReleaseConfig_OCI_chartName(resource, ns, name, chartName, version string) string { + return fmt.Sprintf(` + resource "helm_release" "%s" { + name = %q + namespace = %q + version = %q + chart = %q + } + `, resource, name, ns, version, chartName) +} + +func testAccHelmReleaseConfig_OCI_updated(resource, ns, name, repo, version string) string { + return fmt.Sprintf(` + resource "helm_release" "%s" { + name = %q + namespace = %q + repository = %q + version = %q + chart = "test-chart" + + set = [ + { + name = "replicaCount" + value = 2 + } + ] + } + `, resource, name, ns, repo, version) +} + +func testAccHelmReleaseConfigManifestExperimentEnabled(resource, ns, name, version string) string { + return fmt.Sprintf(` + provider "helm" { + experiments = { + manifest = true + } + } + + resource "helm_release" "%s" { + name = %q + namespace = %q + repository = %q + version = %q + chart = "test-chart" + } + `, resource, name, ns, testRepositoryURL, version) +} + +func testAccHelmReleaseConfigManifestUnknownValues(resource, ns, name, version string) string { + return fmt.Sprintf(` + provider helm { + experiments = { + manifest = true + } + } + + resource "random_string" "random_label" { + length = 16 + special = false + } + + resource "helm_release" "%s" { + name = %q + namespace = %q + repository = %q + version = %q + chart = "test-chart" + + set = [ + { + name = "podAnnotations.random" + value = random_string.random_label.result + } + ] + + set_sensitive = [ + { + name = "podAnnotations.sensitive" + value = random_string.random_label.result + } + ] + + values = [< /dev/null +if [ "$?" != "0" ]; then + echo "Error: Docker not found" + exit 1 +fi +if [ "$KUBE_DIR" == "" ]; then + echo "Error: Please specify KUBE_DIR" + exit 1 +fi +if [ "$HELM_VERSION" == "" ]; then + echo "Error: Please specify HELM_VERSION" + exit 1 +fi +if [ "$HELM_HOME" == "" ]; then + HELM_HOME=~/.helm +fi +if [ "$HYPERKUBE_VERSION" == "" ]; then + URL="https://console.cloud.google.com/gcr/images/google-containers/GLOBAL/hyperkube" + echo "Error: Please specify HYPERKUBE_VERSION" + echo " - Available versions: $URL" + exit 1 +fi + +echo "HELM_HOME=${HELM_HOME}" + +docker version + +DOCKER_KUBECTL="docker run -i --rm \ + -v ${KUBE_DIR}:/root/.kube \ + gcr.io/google-containers/hyperkube:${HYPERKUBE_VERSION} \ + kubectl" + +$DOCKER_KUBECTL version + +echo "Creating Tiller service account ..." +$DOCKER_KUBECTL --namespace kube-system create sa tiller + +echo "Creating ClusterRoleBinding for Tiller ..." +$DOCKER_KUBECTL create clusterrolebinding tiller \ + --clusterrole cluster-admin \ + --serviceaccount=kube-system:tiller + +mkdir -p $HELM_HOME +ls -la $HELM_HOME +DOCKER_HELM="docker run -i --rm \ + -v $(pwd):/apps \ + -v ${HELM_HOME}:/.helm \ + -v ${KUBE_DIR}:/.kube \ + --user $(id -u):$(id -g) \ + alpine/helm:${HELM_VERSION}" + +echo "Helm client version:" +$DOCKER_HELM version -c + +echo "Initializing Helm ..." +$DOCKER_HELM init --service-account tiller + +echo "Verifying Helm ..." +$DOCKER_KUBECTL get deploy,svc tiller-deploy -n kube-system diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/.gitingore b/shuttles/terraform/terraform-provider-helm/helm/testdata/.gitingore new file mode 100644 index 0000000..71febe4 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/.gitingore @@ -0,0 +1,2 @@ +# we build and delete the repository on every test run +repository/ \ No newline at end of file diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/broken-chart/Chart.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/broken-chart/Chart.yaml new file mode 100644 index 0000000..3220bfb --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/broken-chart/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +name: broken-chart +description: A broken chart for testing the Helm provider +type: application +version: 1.2.3 +appVersion: 1.2.3 diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/broken-chart/templates/service.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/broken-chart/templates/service.yaml new file mode 100644 index 0000000..7d3cc57 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/broken-chart/templates/service.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Service +metadata: + name: test +spec: + type: NodePort + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + {{- BAD_FUNCTION }} diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/.helmignore b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/Chart.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/Chart.yaml new file mode 100644 index 0000000..eb91b96 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/Chart.yaml @@ -0,0 +1,23 @@ +apiVersion: v2 +name: crds-chart +description: This is a simple chart to use as a test fixture + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 1.2.3 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +appVersion: 1.19.5 diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/crds/apples.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/crds/apples.yaml new file mode 100644 index 0000000..556e4a3 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/crds/apples.yaml @@ -0,0 +1,41 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + # name must match the spec fields below, and be in the form: . + name: apples.stable.example.com +spec: + # group name to use for REST API: /apis// + group: stable.example.com + # list of versions supported by this CustomResourceDefinition + versions: + - name: v1 + # Each version can be enabled/disabled by Served flag. + served: true + # One and only one version must be marked as the storage version. + storage: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + cronSpec: + type: string + image: + type: string + replicas: + type: integer + # either Namespaced or Cluster + scope: Namespaced + names: + # plural name to be used in the URL: /apis/// + plural: apples + # singular name to be used as an alias on the CLI and for display + singular: apple + # kind is normally the CamelCased singular type. Your resource manifests use this. + kind: Apple + # shortNames allow shorter string to match your resource on the CLI + shortNames: + - ap diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/crds/oranges.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/crds/oranges.yaml new file mode 100644 index 0000000..5c444bb --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/crds/oranges.yaml @@ -0,0 +1,41 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + # name must match the spec fields below, and be in the form: . + name: oranges.stable.example.com +spec: + # group name to use for REST API: /apis// + group: stable.example.com + # list of versions supported by this CustomResourceDefinition + versions: + - name: v1 + # Each version can be enabled/disabled by Served flag. + served: true + # One and only one version must be marked as the storage version. + storage: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + cronSpec: + type: string + image: + type: string + replicas: + type: integer + # either Namespaced or Cluster + scope: Namespaced + names: + # plural name to be used in the URL: /apis/// + plural: oranges + # singular name to be used as an alias on the CLI and for display + singular: orange + # kind is normally the CamelCased singular type. Your resource manifests use this. + kind: Orange + # shortNames allow shorter string to match your resource on the CLI + shortNames: + - or diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/templates/NOTES.txt b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/templates/NOTES.txt new file mode 100644 index 0000000..0b1a16d --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/templates/NOTES.txt @@ -0,0 +1,21 @@ +1. Get the application URL by running these commands: +{{- if .Values.ingress.enabled }} +{{- range $host := .Values.ingress.hosts }} + {{- range .paths }} + http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }} + {{- end }} +{{- end }} +{{- else if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "test-chart.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT +{{- else if contains "LoadBalancer" .Values.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "test-chart.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "test-chart.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + echo http://$SERVICE_IP:{{ .Values.service.port }} +{{- else if contains "ClusterIP" .Values.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "test-chart.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:80 +{{- end }} diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/templates/_helpers.tpl b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/templates/_helpers.tpl new file mode 100644 index 0000000..7b311a7 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "test-chart.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "test-chart.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "test-chart.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "test-chart.labels" -}} +helm.sh/chart: {{ include "test-chart.chart" . }} +{{ include "test-chart.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "test-chart.selectorLabels" -}} +app.kubernetes.io/name: {{ include "test-chart.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "test-chart.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "test-chart.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/templates/configmaps.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/templates/configmaps.yaml new file mode 100644 index 0000000..e4f612f --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/templates/configmaps.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "test-chart.fullname" . }}-one + labels: + {{- include "test-chart.labels" . | nindent 4 }} +data: + test: one + +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "test-chart.fullname" . }}-two + labels: + {{- include "test-chart.labels" . | nindent 4 }} +data: + test: two diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/templates/deployment.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/templates/deployment.yaml new file mode 100644 index 0000000..91e453b --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/templates/deployment.yaml @@ -0,0 +1,61 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "test-chart.fullname" . }} + labels: + {{- include "test-chart.labels" . | nindent 4 }} +spec: +{{- if not .Values.autoscaling.enabled }} + replicas: {{ .Values.replicaCount }} +{{- end }} + selector: + matchLabels: + {{- include "test-chart.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "test-chart.selectorLabels" . | nindent 8 }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "test-chart.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - name: http + containerPort: 80 + protocol: TCP + livenessProbe: + httpGet: + path: / + port: http + readinessProbe: + httpGet: + path: / + port: http + resources: + {{- toYaml .Values.resources | nindent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/templates/hpa.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/templates/hpa.yaml new file mode 100644 index 0000000..4642327 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/templates/hpa.yaml @@ -0,0 +1,28 @@ +{{- if .Values.autoscaling.enabled }} +apiVersion: autoscaling/v2beta1 +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "test-chart.fullname" . }} + labels: + {{- include "test-chart.labels" . | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "test-chart.fullname" . }} + minReplicas: {{ .Values.autoscaling.minReplicas }} + maxReplicas: {{ .Values.autoscaling.maxReplicas }} + metrics: + {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} + {{- end }} + {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} + {{- end }} +{{- end }} diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/templates/ingress.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/templates/ingress.yaml new file mode 100644 index 0000000..95c5936 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/templates/ingress.yaml @@ -0,0 +1,41 @@ +{{- if .Values.ingress.enabled -}} +{{- $fullName := include "test-chart.fullname" . -}} +{{- $svcPort := .Values.service.port -}} +{{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{- else -}} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + name: {{ $fullName }} + labels: + {{- include "test-chart.labels" . | nindent 4 }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ . }} + backend: + serviceName: {{ $fullName }} + servicePort: {{ $svcPort }} + {{- end }} + {{- end }} + {{- end }} diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/templates/service.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/templates/service.yaml new file mode 100644 index 0000000..b8d5d51 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "test-chart.fullname" . }} + labels: + {{- include "test-chart.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + {{- include "test-chart.selectorLabels" . | nindent 4 }} diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/templates/serviceaccount.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/templates/serviceaccount.yaml new file mode 100644 index 0000000..85ea1e1 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/templates/serviceaccount.yaml @@ -0,0 +1,12 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "test-chart.serviceAccountName" . }} + labels: + {{- include "test-chart.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/templates/tests/test-connection.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/templates/tests/test-connection.yaml new file mode 100644 index 0000000..772f913 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/templates/tests/test-connection.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Pod +metadata: + name: "{{ include "test-chart.fullname" . }}-test-connection" + labels: + {{- include "test-chart.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": test-success +spec: + containers: + - name: wget + image: busybox + command: ['wget'] + args: ['{{ include "test-chart.fullname" . }}:{{ .Values.service.port }}'] + restartPolicy: Never diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/values.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/values.yaml new file mode 100644 index 0000000..d009b4a --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/crds-chart/values.yaml @@ -0,0 +1,79 @@ +# Default values for test-chart. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +replicaCount: 1 + +image: + repository: nginx + pullPolicy: IfNotPresent + # Overrides the image tag whose default is the chart appVersion. + tag: "" + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +serviceAccount: + # Specifies whether a service account should be created + create: true + # Annotations to add to the service account + annotations: {} + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "" + +podAnnotations: {} + +podSecurityContext: {} + # fsGroup: 2000 + +securityContext: {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + +service: + type: ClusterIP + port: 80 + +ingress: + enabled: false + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + hosts: + - host: chart-example.local + paths: [] + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +autoscaling: + enabled: false + minReplicas: 1 + maxReplicas: 100 + targetCPUUtilizationPercentage: 80 + # targetMemoryUtilizationPercentage: 80 + +nodeSelector: {} + +tolerations: [] + +affinity: {} diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-bar/.helmignore b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-bar/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-bar/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-bar/Chart.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-bar/Chart.yaml new file mode 100644 index 0000000..a860d42 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-bar/Chart.yaml @@ -0,0 +1,23 @@ +apiVersion: v2 +name: dependency-bar +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +appVersion: 1.16.0 diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-bar/templates/NOTES.txt b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-bar/templates/NOTES.txt new file mode 100644 index 0000000..a809efd --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-bar/templates/NOTES.txt @@ -0,0 +1,21 @@ +1. Get the application URL by running these commands: +{{- if .Values.ingress.enabled }} +{{- range $host := .Values.ingress.hosts }} + {{- range .paths }} + http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }} + {{- end }} +{{- end }} +{{- else if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "dependency-bar.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT +{{- else if contains "LoadBalancer" .Values.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "dependency-bar.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "dependency-bar.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + echo http://$SERVICE_IP:{{ .Values.service.port }} +{{- else if contains "ClusterIP" .Values.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "dependency-bar.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:80 +{{- end }} diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-bar/templates/_helpers.tpl b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-bar/templates/_helpers.tpl new file mode 100644 index 0000000..ee45d87 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-bar/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "dependency-bar.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "dependency-bar.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "dependency-bar.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "dependency-bar.labels" -}} +helm.sh/chart: {{ include "dependency-bar.chart" . }} +{{ include "dependency-bar.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "dependency-bar.selectorLabels" -}} +app.kubernetes.io/name: {{ include "dependency-bar.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "dependency-bar.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "dependency-bar.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-bar/templates/deployment.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-bar/templates/deployment.yaml new file mode 100644 index 0000000..9d7b4b1 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-bar/templates/deployment.yaml @@ -0,0 +1,61 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "dependency-bar.fullname" . }} + labels: + {{- include "dependency-bar.labels" . | nindent 4 }} +spec: +{{- if not .Values.autoscaling.enabled }} + replicas: {{ .Values.replicaCount }} +{{- end }} + selector: + matchLabels: + {{- include "dependency-bar.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "dependency-bar.selectorLabels" . | nindent 8 }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "dependency-bar.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - name: http + containerPort: 80 + protocol: TCP + livenessProbe: + httpGet: + path: / + port: http + readinessProbe: + httpGet: + path: / + port: http + resources: + {{- toYaml .Values.resources | nindent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-bar/templates/hpa.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-bar/templates/hpa.yaml new file mode 100644 index 0000000..9e6b9c5 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-bar/templates/hpa.yaml @@ -0,0 +1,28 @@ +{{- if .Values.autoscaling.enabled }} +apiVersion: autoscaling/v2beta1 +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "dependency-bar.fullname" . }} + labels: + {{- include "dependency-bar.labels" . | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "dependency-bar.fullname" . }} + minReplicas: {{ .Values.autoscaling.minReplicas }} + maxReplicas: {{ .Values.autoscaling.maxReplicas }} + metrics: + {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} + {{- end }} + {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} + {{- end }} +{{- end }} diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-bar/templates/ingress.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-bar/templates/ingress.yaml new file mode 100644 index 0000000..0e80848 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-bar/templates/ingress.yaml @@ -0,0 +1,41 @@ +{{- if .Values.ingress.enabled -}} +{{- $fullName := include "dependency-bar.fullname" . -}} +{{- $svcPort := .Values.service.port -}} +{{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{- else -}} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + name: {{ $fullName }} + labels: + {{- include "dependency-bar.labels" . | nindent 4 }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ . }} + backend: + serviceName: {{ $fullName }} + servicePort: {{ $svcPort }} + {{- end }} + {{- end }} + {{- end }} diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-bar/templates/service.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-bar/templates/service.yaml new file mode 100644 index 0000000..7c22313 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-bar/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "dependency-bar.fullname" . }} + labels: + {{- include "dependency-bar.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + {{- include "dependency-bar.selectorLabels" . | nindent 4 }} diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-bar/templates/serviceaccount.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-bar/templates/serviceaccount.yaml new file mode 100644 index 0000000..9002046 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-bar/templates/serviceaccount.yaml @@ -0,0 +1,12 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "dependency-bar.serviceAccountName" . }} + labels: + {{- include "dependency-bar.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-bar/templates/tests/test-connection.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-bar/templates/tests/test-connection.yaml new file mode 100644 index 0000000..a599081 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-bar/templates/tests/test-connection.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Pod +metadata: + name: "{{ include "dependency-bar.fullname" . }}-test-connection" + labels: + {{- include "dependency-bar.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": test-success +spec: + containers: + - name: wget + image: busybox + command: ['wget'] + args: ['{{ include "dependency-bar.fullname" . }}:{{ .Values.service.port }}'] + restartPolicy: Never diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-bar/values.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-bar/values.yaml new file mode 100644 index 0000000..7c81bea --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-bar/values.yaml @@ -0,0 +1,79 @@ +# Default values for dependency-bar. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +replicaCount: 1 + +image: + repository: nginx + pullPolicy: IfNotPresent + # Overrides the image tag whose default is the chart appVersion. + tag: "" + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +serviceAccount: + # Specifies whether a service account should be created + create: true + # Annotations to add to the service account + annotations: {} + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "" + +podAnnotations: {} + +podSecurityContext: {} + # fsGroup: 2000 + +securityContext: {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + +service: + type: ClusterIP + port: 80 + +ingress: + enabled: false + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + hosts: + - host: chart-example.local + paths: [] + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +autoscaling: + enabled: false + minReplicas: 1 + maxReplicas: 100 + targetCPUUtilizationPercentage: 80 + # targetMemoryUtilizationPercentage: 80 + +nodeSelector: {} + +tolerations: [] + +affinity: {} diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-foo/.helmignore b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-foo/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-foo/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-foo/Chart.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-foo/Chart.yaml new file mode 100644 index 0000000..e21fd6e --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-foo/Chart.yaml @@ -0,0 +1,23 @@ +apiVersion: v2 +name: dependency-foo +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +appVersion: 1.16.0 diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-foo/templates/NOTES.txt b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-foo/templates/NOTES.txt new file mode 100644 index 0000000..49f6b83 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-foo/templates/NOTES.txt @@ -0,0 +1,21 @@ +1. Get the application URL by running these commands: +{{- if .Values.ingress.enabled }} +{{- range $host := .Values.ingress.hosts }} + {{- range .paths }} + http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }} + {{- end }} +{{- end }} +{{- else if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "dependency-foo.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT +{{- else if contains "LoadBalancer" .Values.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "dependency-foo.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "dependency-foo.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + echo http://$SERVICE_IP:{{ .Values.service.port }} +{{- else if contains "ClusterIP" .Values.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "dependency-foo.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:80 +{{- end }} diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-foo/templates/_helpers.tpl b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-foo/templates/_helpers.tpl new file mode 100644 index 0000000..ed077d4 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-foo/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "dependency-foo.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "dependency-foo.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "dependency-foo.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "dependency-foo.labels" -}} +helm.sh/chart: {{ include "dependency-foo.chart" . }} +{{ include "dependency-foo.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "dependency-foo.selectorLabels" -}} +app.kubernetes.io/name: {{ include "dependency-foo.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "dependency-foo.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "dependency-foo.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-foo/templates/deployment.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-foo/templates/deployment.yaml new file mode 100644 index 0000000..2327087 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-foo/templates/deployment.yaml @@ -0,0 +1,61 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "dependency-foo.fullname" . }} + labels: + {{- include "dependency-foo.labels" . | nindent 4 }} +spec: +{{- if not .Values.autoscaling.enabled }} + replicas: {{ .Values.replicaCount }} +{{- end }} + selector: + matchLabels: + {{- include "dependency-foo.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "dependency-foo.selectorLabels" . | nindent 8 }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "dependency-foo.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - name: http + containerPort: 80 + protocol: TCP + livenessProbe: + httpGet: + path: / + port: http + readinessProbe: + httpGet: + path: / + port: http + resources: + {{- toYaml .Values.resources | nindent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-foo/templates/hpa.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-foo/templates/hpa.yaml new file mode 100644 index 0000000..b03f5fc --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-foo/templates/hpa.yaml @@ -0,0 +1,28 @@ +{{- if .Values.autoscaling.enabled }} +apiVersion: autoscaling/v2beta1 +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "dependency-foo.fullname" . }} + labels: + {{- include "dependency-foo.labels" . | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "dependency-foo.fullname" . }} + minReplicas: {{ .Values.autoscaling.minReplicas }} + maxReplicas: {{ .Values.autoscaling.maxReplicas }} + metrics: + {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} + {{- end }} + {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} + {{- end }} +{{- end }} diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-foo/templates/ingress.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-foo/templates/ingress.yaml new file mode 100644 index 0000000..f21953f --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-foo/templates/ingress.yaml @@ -0,0 +1,41 @@ +{{- if .Values.ingress.enabled -}} +{{- $fullName := include "dependency-foo.fullname" . -}} +{{- $svcPort := .Values.service.port -}} +{{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{- else -}} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + name: {{ $fullName }} + labels: + {{- include "dependency-foo.labels" . | nindent 4 }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ . }} + backend: + serviceName: {{ $fullName }} + servicePort: {{ $svcPort }} + {{- end }} + {{- end }} + {{- end }} diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-foo/templates/service.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-foo/templates/service.yaml new file mode 100644 index 0000000..f959e6d --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-foo/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "dependency-foo.fullname" . }} + labels: + {{- include "dependency-foo.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + {{- include "dependency-foo.selectorLabels" . | nindent 4 }} diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-foo/templates/serviceaccount.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-foo/templates/serviceaccount.yaml new file mode 100644 index 0000000..36503d0 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-foo/templates/serviceaccount.yaml @@ -0,0 +1,12 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "dependency-foo.serviceAccountName" . }} + labels: + {{- include "dependency-foo.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-foo/templates/tests/test-connection.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-foo/templates/tests/test-connection.yaml new file mode 100644 index 0000000..2727580 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-foo/templates/tests/test-connection.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Pod +metadata: + name: "{{ include "dependency-foo.fullname" . }}-test-connection" + labels: + {{- include "dependency-foo.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": test-success +spec: + containers: + - name: wget + image: busybox + command: ['wget'] + args: ['{{ include "dependency-foo.fullname" . }}:{{ .Values.service.port }}'] + restartPolicy: Never diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-foo/values.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-foo/values.yaml new file mode 100644 index 0000000..82b7808 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/dependency-foo/values.yaml @@ -0,0 +1,79 @@ +# Default values for dependency-foo. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +replicaCount: 1 + +image: + repository: nginx + pullPolicy: IfNotPresent + # Overrides the image tag whose default is the chart appVersion. + tag: "" + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +serviceAccount: + # Specifies whether a service account should be created + create: true + # Annotations to add to the service account + annotations: {} + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "" + +podAnnotations: {} + +podSecurityContext: {} + # fsGroup: 2000 + +securityContext: {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + +service: + type: ClusterIP + port: 80 + +ingress: + enabled: false + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + hosts: + - host: chart-example.local + paths: [] + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +autoscaling: + enabled: false + minReplicas: 1 + maxReplicas: 100 + targetCPUUtilizationPercentage: 80 + # targetMemoryUtilizationPercentage: 80 + +nodeSelector: {} + +tolerations: [] + +affinity: {} diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/failed-deploy/Chart.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/failed-deploy/Chart.yaml new file mode 100644 index 0000000..6041503 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/failed-deploy/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +name: failed-deploy +description: A broken chart for testing the Helm provider +type: application +version: 1.2.3 +appVersion: 1.2.3 diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/failed-deploy/templates/service.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/failed-deploy/templates/service.yaml new file mode 100644 index 0000000..62f4204 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/failed-deploy/templates/service.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Service +metadata: + name: test + namespace: doesnt-exist +spec: + type: NodePort + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/kube-version/Chart.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/kube-version/Chart.yaml new file mode 100644 index 0000000..80ac73f --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/kube-version/Chart.yaml @@ -0,0 +1,7 @@ +apiVersion: v2 +name: kube-version +description: A chart requiring kube version 1.22 or above +type: application +version: 1.2.3 +appVersion: 1.2.3 +kubeVersion: ">=1.22.0-0" diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/kube-version/templates/_helpers.tpl b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/kube-version/templates/_helpers.tpl new file mode 100644 index 0000000..1100173 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/kube-version/templates/_helpers.tpl @@ -0,0 +1,42 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "kube-version.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "kube-version.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "kube-version.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "kube-version.labels" -}} +helm.sh/chart: {{ include "kube-version.chart" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/kube-version/templates/deployment.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/kube-version/templates/deployment.yaml new file mode 100644 index 0000000..c0d1351 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/kube-version/templates/deployment.yaml @@ -0,0 +1,53 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "kube-version.fullname" . }} + labels: + {{- include "kube-version.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicaCount }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - name: http + containerPort: 80 + protocol: TCP + livenessProbe: + httpGet: + path: / + port: http + readinessProbe: + httpGet: + path: / + port: http + resources: + {{- toYaml .Values.resources | nindent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/kube-version/values.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/kube-version/values.yaml new file mode 100644 index 0000000..e0ddc93 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/kube-version/values.yaml @@ -0,0 +1,49 @@ +# Default values for kube-version. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +replicaCount: 1 + +image: + repository: nginx + pullPolicy: IfNotPresent + # Overrides the image tag whose default is the chart appVersion. + tag: "" + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +podAnnotations: {} + +podSecurityContext: + {} + # fsGroup: 2000 + +securityContext: + {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + +resources: + {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +nodeSelector: {} + +tolerations: [] + +affinity: {} diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart-v2/.helmignore b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart-v2/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart-v2/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart-v2/Chart.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart-v2/Chart.yaml new file mode 100644 index 0000000..82b39a7 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart-v2/Chart.yaml @@ -0,0 +1,23 @@ +apiVersion: v2 +name: test-chart +description: This is a simple chart to use as a test fixture + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 2.0.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +appVersion: 1.19.5 diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart-v2/templates/NOTES.txt b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart-v2/templates/NOTES.txt new file mode 100644 index 0000000..0b1a16d --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart-v2/templates/NOTES.txt @@ -0,0 +1,21 @@ +1. Get the application URL by running these commands: +{{- if .Values.ingress.enabled }} +{{- range $host := .Values.ingress.hosts }} + {{- range .paths }} + http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }} + {{- end }} +{{- end }} +{{- else if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "test-chart.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT +{{- else if contains "LoadBalancer" .Values.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "test-chart.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "test-chart.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + echo http://$SERVICE_IP:{{ .Values.service.port }} +{{- else if contains "ClusterIP" .Values.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "test-chart.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:80 +{{- end }} diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart-v2/templates/_helpers.tpl b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart-v2/templates/_helpers.tpl new file mode 100644 index 0000000..7b311a7 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart-v2/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "test-chart.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "test-chart.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "test-chart.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "test-chart.labels" -}} +helm.sh/chart: {{ include "test-chart.chart" . }} +{{ include "test-chart.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "test-chart.selectorLabels" -}} +app.kubernetes.io/name: {{ include "test-chart.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "test-chart.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "test-chart.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart-v2/templates/deployment.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart-v2/templates/deployment.yaml new file mode 100644 index 0000000..91e453b --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart-v2/templates/deployment.yaml @@ -0,0 +1,61 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "test-chart.fullname" . }} + labels: + {{- include "test-chart.labels" . | nindent 4 }} +spec: +{{- if not .Values.autoscaling.enabled }} + replicas: {{ .Values.replicaCount }} +{{- end }} + selector: + matchLabels: + {{- include "test-chart.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "test-chart.selectorLabels" . | nindent 8 }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "test-chart.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - name: http + containerPort: 80 + protocol: TCP + livenessProbe: + httpGet: + path: / + port: http + readinessProbe: + httpGet: + path: / + port: http + resources: + {{- toYaml .Values.resources | nindent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart-v2/templates/hpa.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart-v2/templates/hpa.yaml new file mode 100644 index 0000000..4642327 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart-v2/templates/hpa.yaml @@ -0,0 +1,28 @@ +{{- if .Values.autoscaling.enabled }} +apiVersion: autoscaling/v2beta1 +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "test-chart.fullname" . }} + labels: + {{- include "test-chart.labels" . | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "test-chart.fullname" . }} + minReplicas: {{ .Values.autoscaling.minReplicas }} + maxReplicas: {{ .Values.autoscaling.maxReplicas }} + metrics: + {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} + {{- end }} + {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} + {{- end }} +{{- end }} diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart-v2/templates/ingress.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart-v2/templates/ingress.yaml new file mode 100644 index 0000000..95c5936 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart-v2/templates/ingress.yaml @@ -0,0 +1,41 @@ +{{- if .Values.ingress.enabled -}} +{{- $fullName := include "test-chart.fullname" . -}} +{{- $svcPort := .Values.service.port -}} +{{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{- else -}} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + name: {{ $fullName }} + labels: + {{- include "test-chart.labels" . | nindent 4 }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ . }} + backend: + serviceName: {{ $fullName }} + servicePort: {{ $svcPort }} + {{- end }} + {{- end }} + {{- end }} diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart-v2/templates/service.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart-v2/templates/service.yaml new file mode 100644 index 0000000..b8d5d51 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart-v2/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "test-chart.fullname" . }} + labels: + {{- include "test-chart.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + {{- include "test-chart.selectorLabels" . | nindent 4 }} diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart-v2/templates/serviceaccount.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart-v2/templates/serviceaccount.yaml new file mode 100644 index 0000000..85ea1e1 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart-v2/templates/serviceaccount.yaml @@ -0,0 +1,12 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "test-chart.serviceAccountName" . }} + labels: + {{- include "test-chart.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart-v2/templates/tests/test-connection.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart-v2/templates/tests/test-connection.yaml new file mode 100644 index 0000000..772f913 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart-v2/templates/tests/test-connection.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Pod +metadata: + name: "{{ include "test-chart.fullname" . }}-test-connection" + labels: + {{- include "test-chart.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": test-success +spec: + containers: + - name: wget + image: busybox + command: ['wget'] + args: ['{{ include "test-chart.fullname" . }}:{{ .Values.service.port }}'] + restartPolicy: Never diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart-v2/values.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart-v2/values.yaml new file mode 100644 index 0000000..f6b7112 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart-v2/values.yaml @@ -0,0 +1,81 @@ +# Default values for test-chart. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +replicaCount: 1 + +image: + repository: nginx + pullPolicy: IfNotPresent + # Overrides the image tag whose default is the chart appVersion. + tag: "" + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +serviceAccount: + # Specifies whether a service account should be created + create: true + # Annotations to add to the service account + annotations: {} + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "" + +podAnnotations: {} + +podSecurityContext: {} + # fsGroup: 2000 + +securityContext: {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + +service: + type: ClusterIP + port: 80 + +ingress: + enabled: false + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + hosts: + - host: chart-example.local + paths: [] + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +autoscaling: + enabled: false + minReplicas: 1 + maxReplicas: 100 + targetCPUUtilizationPercentage: 80 + # targetMemoryUtilizationPercentage: 80 + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +set_list_test: [] \ No newline at end of file diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart/.helmignore b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart/Chart.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart/Chart.yaml new file mode 100644 index 0000000..300519c --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart/Chart.yaml @@ -0,0 +1,23 @@ +apiVersion: v2 +name: test-chart +description: This is a simple chart to use as a test fixture + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 1.2.3 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +appVersion: 1.19.5 diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart/templates/NOTES.txt b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart/templates/NOTES.txt new file mode 100644 index 0000000..0b1a16d --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart/templates/NOTES.txt @@ -0,0 +1,21 @@ +1. Get the application URL by running these commands: +{{- if .Values.ingress.enabled }} +{{- range $host := .Values.ingress.hosts }} + {{- range .paths }} + http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }} + {{- end }} +{{- end }} +{{- else if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "test-chart.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT +{{- else if contains "LoadBalancer" .Values.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "test-chart.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "test-chart.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + echo http://$SERVICE_IP:{{ .Values.service.port }} +{{- else if contains "ClusterIP" .Values.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "test-chart.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:80 +{{- end }} diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart/templates/_helpers.tpl b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart/templates/_helpers.tpl new file mode 100644 index 0000000..7b311a7 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "test-chart.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "test-chart.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "test-chart.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "test-chart.labels" -}} +helm.sh/chart: {{ include "test-chart.chart" . }} +{{ include "test-chart.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "test-chart.selectorLabels" -}} +app.kubernetes.io/name: {{ include "test-chart.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "test-chart.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "test-chart.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart/templates/configmaps.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart/templates/configmaps.yaml new file mode 100644 index 0000000..e4f612f --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart/templates/configmaps.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "test-chart.fullname" . }}-one + labels: + {{- include "test-chart.labels" . | nindent 4 }} +data: + test: one + +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "test-chart.fullname" . }}-two + labels: + {{- include "test-chart.labels" . | nindent 4 }} +data: + test: two diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart/templates/deployment.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart/templates/deployment.yaml new file mode 100644 index 0000000..91e453b --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart/templates/deployment.yaml @@ -0,0 +1,61 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "test-chart.fullname" . }} + labels: + {{- include "test-chart.labels" . | nindent 4 }} +spec: +{{- if not .Values.autoscaling.enabled }} + replicas: {{ .Values.replicaCount }} +{{- end }} + selector: + matchLabels: + {{- include "test-chart.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "test-chart.selectorLabels" . | nindent 8 }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "test-chart.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - name: http + containerPort: 80 + protocol: TCP + livenessProbe: + httpGet: + path: / + port: http + readinessProbe: + httpGet: + path: / + port: http + resources: + {{- toYaml .Values.resources | nindent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart/templates/hpa.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart/templates/hpa.yaml new file mode 100644 index 0000000..4642327 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart/templates/hpa.yaml @@ -0,0 +1,28 @@ +{{- if .Values.autoscaling.enabled }} +apiVersion: autoscaling/v2beta1 +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "test-chart.fullname" . }} + labels: + {{- include "test-chart.labels" . | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "test-chart.fullname" . }} + minReplicas: {{ .Values.autoscaling.minReplicas }} + maxReplicas: {{ .Values.autoscaling.maxReplicas }} + metrics: + {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} + {{- end }} + {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} + {{- end }} +{{- end }} diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart/templates/ingress.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart/templates/ingress.yaml new file mode 100644 index 0000000..95c5936 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart/templates/ingress.yaml @@ -0,0 +1,41 @@ +{{- if .Values.ingress.enabled -}} +{{- $fullName := include "test-chart.fullname" . -}} +{{- $svcPort := .Values.service.port -}} +{{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{- else -}} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + name: {{ $fullName }} + labels: + {{- include "test-chart.labels" . | nindent 4 }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ . }} + backend: + serviceName: {{ $fullName }} + servicePort: {{ $svcPort }} + {{- end }} + {{- end }} + {{- end }} diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart/templates/secrets.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart/templates/secrets.yaml new file mode 100644 index 0000000..380a7a7 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart/templates/secrets.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "test-chart.fullname" . }} +data: + cloaked: {{ .Values.cloakedData.cloaked | b64enc }} diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart/templates/service.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart/templates/service.yaml new file mode 100644 index 0000000..b8d5d51 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "test-chart.fullname" . }} + labels: + {{- include "test-chart.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + {{- include "test-chart.selectorLabels" . | nindent 4 }} diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart/templates/serviceaccount.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart/templates/serviceaccount.yaml new file mode 100644 index 0000000..85ea1e1 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart/templates/serviceaccount.yaml @@ -0,0 +1,12 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "test-chart.serviceAccountName" . }} + labels: + {{- include "test-chart.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart/templates/tests/test-connection.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart/templates/tests/test-connection.yaml new file mode 100644 index 0000000..772f913 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart/templates/tests/test-connection.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Pod +metadata: + name: "{{ include "test-chart.fullname" . }}-test-connection" + labels: + {{- include "test-chart.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": test-success +spec: + containers: + - name: wget + image: busybox + command: ['wget'] + args: ['{{ include "test-chart.fullname" . }}:{{ .Values.service.port }}'] + restartPolicy: Never diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart/values.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart/values.yaml new file mode 100644 index 0000000..7dc53da --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/test-chart/values.yaml @@ -0,0 +1,82 @@ +# Default values for test-chart. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +replicaCount: 1 + +image: + repository: nginx + pullPolicy: IfNotPresent + # Overrides the image tag whose default is the chart appVersion. + tag: "" + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +serviceAccount: + # Specifies whether a service account should be created + create: true + # Annotations to add to the service account + annotations: {} + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "" + +podAnnotations: {} + +podSecurityContext: {} + # fsGroup: 2000 + +securityContext: {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + +service: + type: ClusterIP + port: 80 + +ingress: + enabled: false + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + hosts: + - host: chart-example.local + paths: [] + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +autoscaling: + enabled: false + minReplicas: 1 + maxReplicas: 100 + targetCPUUtilizationPercentage: 80 + # targetMemoryUtilizationPercentage: 80 + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +cloakedData: + cloaked: secret diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/umbrella-chart/.gitignore b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/umbrella-chart/.gitignore new file mode 100644 index 0000000..711a39c --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/umbrella-chart/.gitignore @@ -0,0 +1 @@ +charts/ \ No newline at end of file diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/umbrella-chart/.helmignore b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/umbrella-chart/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/umbrella-chart/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/umbrella-chart/Chart.lock b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/umbrella-chart/Chart.lock new file mode 100644 index 0000000..f54c148 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/umbrella-chart/Chart.lock @@ -0,0 +1,9 @@ +dependencies: +- name: dependency-foo + repository: file://../dependency-foo + version: 0.1.0 +- name: dependency-bar + repository: file://../dependency-bar + version: 0.1.0 +digest: sha256:eb95e992b458355d1cbc448c9694cadf982a1b82c6b3fe70617d7e39ee071d54 +generated: "2020-12-03T00:30:06.840959-05:00" diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/umbrella-chart/Chart.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/umbrella-chart/Chart.yaml new file mode 100644 index 0000000..391ee4f --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/umbrella-chart/Chart.yaml @@ -0,0 +1,31 @@ +apiVersion: v2 +name: umbrella-chart +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +appVersion: 1.16.0 + +dependencies: +- name: dependency-foo + version: 0.x.x + repository: "file://../dependency-foo" +- name: dependency-bar + version: 0.x.x + repository: "file://../dependency-bar" \ No newline at end of file diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/umbrella-chart/templates/NOTES.txt b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/umbrella-chart/templates/NOTES.txt new file mode 100644 index 0000000..02adeda --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/umbrella-chart/templates/NOTES.txt @@ -0,0 +1,21 @@ +1. Get the application URL by running these commands: +{{- if .Values.ingress.enabled }} +{{- range $host := .Values.ingress.hosts }} + {{- range .paths }} + http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }} + {{- end }} +{{- end }} +{{- else if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "umbrella-chart.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT +{{- else if contains "LoadBalancer" .Values.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "umbrella-chart.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "umbrella-chart.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + echo http://$SERVICE_IP:{{ .Values.service.port }} +{{- else if contains "ClusterIP" .Values.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "umbrella-chart.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:80 +{{- end }} diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/umbrella-chart/templates/_helpers.tpl b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/umbrella-chart/templates/_helpers.tpl new file mode 100644 index 0000000..d13e0cb --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/umbrella-chart/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "umbrella-chart.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "umbrella-chart.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "umbrella-chart.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "umbrella-chart.labels" -}} +helm.sh/chart: {{ include "umbrella-chart.chart" . }} +{{ include "umbrella-chart.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "umbrella-chart.selectorLabels" -}} +app.kubernetes.io/name: {{ include "umbrella-chart.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "umbrella-chart.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "umbrella-chart.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/umbrella-chart/templates/deployment.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/umbrella-chart/templates/deployment.yaml new file mode 100644 index 0000000..63d505e --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/umbrella-chart/templates/deployment.yaml @@ -0,0 +1,61 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "umbrella-chart.fullname" . }} + labels: + {{- include "umbrella-chart.labels" . | nindent 4 }} +spec: +{{- if not .Values.autoscaling.enabled }} + replicas: {{ .Values.replicaCount }} +{{- end }} + selector: + matchLabels: + {{- include "umbrella-chart.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "umbrella-chart.selectorLabels" . | nindent 8 }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "umbrella-chart.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - name: http + containerPort: 80 + protocol: TCP + livenessProbe: + httpGet: + path: / + port: http + readinessProbe: + httpGet: + path: / + port: http + resources: + {{- toYaml .Values.resources | nindent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/umbrella-chart/templates/hpa.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/umbrella-chart/templates/hpa.yaml new file mode 100644 index 0000000..ac604e1 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/umbrella-chart/templates/hpa.yaml @@ -0,0 +1,28 @@ +{{- if .Values.autoscaling.enabled }} +apiVersion: autoscaling/v2beta1 +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "umbrella-chart.fullname" . }} + labels: + {{- include "umbrella-chart.labels" . | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "umbrella-chart.fullname" . }} + minReplicas: {{ .Values.autoscaling.minReplicas }} + maxReplicas: {{ .Values.autoscaling.maxReplicas }} + metrics: + {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} + {{- end }} + {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} + {{- end }} +{{- end }} diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/umbrella-chart/templates/ingress.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/umbrella-chart/templates/ingress.yaml new file mode 100644 index 0000000..c846fe1 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/umbrella-chart/templates/ingress.yaml @@ -0,0 +1,41 @@ +{{- if .Values.ingress.enabled -}} +{{- $fullName := include "umbrella-chart.fullname" . -}} +{{- $svcPort := .Values.service.port -}} +{{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{- else -}} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + name: {{ $fullName }} + labels: + {{- include "umbrella-chart.labels" . | nindent 4 }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ . }} + backend: + serviceName: {{ $fullName }} + servicePort: {{ $svcPort }} + {{- end }} + {{- end }} + {{- end }} diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/umbrella-chart/templates/service.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/umbrella-chart/templates/service.yaml new file mode 100644 index 0000000..ad54087 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/umbrella-chart/templates/service.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "umbrella-chart.fullname" . }} + labels: + {{- include "umbrella-chart.labels" . | nindent 4 }} + {{- /* The dependency-bar label template is included here to + test dependency updating. */}} + {{- include "dependency-bar.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + {{- include "umbrella-chart.selectorLabels" . | nindent 4 }} diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/umbrella-chart/templates/serviceaccount.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/umbrella-chart/templates/serviceaccount.yaml new file mode 100644 index 0000000..51874ac --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/umbrella-chart/templates/serviceaccount.yaml @@ -0,0 +1,12 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "umbrella-chart.serviceAccountName" . }} + labels: + {{- include "umbrella-chart.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/umbrella-chart/templates/tests/test-connection.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/umbrella-chart/templates/tests/test-connection.yaml new file mode 100644 index 0000000..4808f3c --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/umbrella-chart/templates/tests/test-connection.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Pod +metadata: + name: "{{ include "umbrella-chart.fullname" . }}-test-connection" + labels: + {{- include "umbrella-chart.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": test-success +spec: + containers: + - name: wget + image: busybox + command: ['wget'] + args: ['{{ include "umbrella-chart.fullname" . }}:{{ .Values.service.port }}'] + restartPolicy: Never diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/umbrella-chart/values.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/umbrella-chart/values.yaml new file mode 100644 index 0000000..38bb968 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/charts/umbrella-chart/values.yaml @@ -0,0 +1,79 @@ +# Default values for umbrella-chart. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +replicaCount: 1 + +image: + repository: nginx + pullPolicy: IfNotPresent + # Overrides the image tag whose default is the chart appVersion. + tag: "" + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +serviceAccount: + # Specifies whether a service account should be created + create: true + # Annotations to add to the service account + annotations: {} + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "" + +podAnnotations: {} + +podSecurityContext: {} + # fsGroup: 2000 + +securityContext: {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + +service: + type: ClusterIP + port: 80 + +ingress: + enabled: false + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + hosts: + - host: chart-example.local + paths: [] + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +autoscaling: + enabled: false + minReplicas: 1 + maxReplicas: 100 + targetCPUUtilizationPercentage: 80 + # targetMemoryUtilizationPercentage: 80 + +nodeSelector: {} + +tolerations: [] + +affinity: {} diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/manifest_json/rendered_manifest.json b/shuttles/terraform/terraform-provider-helm/helm/testdata/manifest_json/rendered_manifest.json new file mode 100644 index 0000000..9be6666 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/manifest_json/rendered_manifest.json @@ -0,0 +1,63 @@ +{ + "secret/v1/diff-tester": { + "kind": "Secret", + "apiVersion": "v1", + "metadata": { + "name": "diff-tester", + "creationTimestamp": null, + "labels": { + "app.kubernetes.io/instance": "diff-tester", + "app.kubernetes.io/managed-by": "Helm", + "app.kubernetes.io/name": "test", + "app.kubernetes.io/version": "1.16.0", + "helm.sh/chart": "test-0.1.5" + } + }, + "data": { + "PASSWORD": "KHNlbnNpdGl2ZSB2YWx1ZSA5NTIwYWUyM2E3MTA4ZmUxKQ==" + } + }, + "service/v1/diff-tester": { + "apiVersion": "v1", + "kind": "Service", + "metadata": { + "labels": { + "app.kubernetes.io/instance": "diff-tester", + "app.kubernetes.io/managed-by": "Helm", + "app.kubernetes.io/name": "test", + "app.kubernetes.io/version": "1.16.0", + "helm.sh/chart": "test-0.1.5" + }, + "name": "diff-tester" + }, + "spec": { + "ports": [ + { + "name": "http", + "port": 80, + "protocol": "TCP", + "targetPort": "http" + } + ], + "selector": { + "app.kubernetes.io/instance": "diff-tester", + "app.kubernetes.io/name": "test" + }, + "type": "ClusterIP" + } + }, + "serviceaccount/v1/diff-tester": { + "apiVersion": "v1", + "kind": "ServiceAccount", + "metadata": { + "labels": { + "app.kubernetes.io/instance": "diff-tester", + "app.kubernetes.io/managed-by": "Helm", + "app.kubernetes.io/name": "test", + "app.kubernetes.io/version": "1.16.0", + "helm.sh/chart": "test-0.1.5" + }, + "name": "diff-tester" + } + } +} \ No newline at end of file diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/manifest_json/rendered_manifest.yaml b/shuttles/terraform/terraform-provider-helm/helm/testdata/manifest_json/rendered_manifest.yaml new file mode 100644 index 0000000..a111aec --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/manifest_json/rendered_manifest.yaml @@ -0,0 +1,48 @@ +--- +# Source: test/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: diff-tester + labels: + helm.sh/chart: test-0.1.5 + app.kubernetes.io/name: test + app.kubernetes.io/instance: diff-tester + app.kubernetes.io/version: "1.16.0" + app.kubernetes.io/managed-by: Helm +--- +# Source: test/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + name: diff-tester + labels: + helm.sh/chart: test-0.1.5 + app.kubernetes.io/name: test + app.kubernetes.io/instance: diff-tester + app.kubernetes.io/version: "1.16.0" + app.kubernetes.io/managed-by: Helm +spec: + type: ClusterIP + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app.kubernetes.io/name: test + app.kubernetes.io/instance: diff-tester +--- +# Source: test/templates/secret.yaml +apiVersion: v1 +kind: Secret +metadata: + name: diff-tester + labels: + helm.sh/chart: test-0.1.5 + app.kubernetes.io/name: test + app.kubernetes.io/instance: diff-tester + app.kubernetes.io/version: "1.16.0" + app.kubernetes.io/managed-by: Helm +data: + PASSWORD: cGFzc3dvcmQK \ No newline at end of file diff --git a/shuttles/terraform/terraform-provider-helm/helm/testdata/oci_registry/auth.htpasswd b/shuttles/terraform/terraform-provider-helm/helm/testdata/oci_registry/auth.htpasswd new file mode 100644 index 0000000..7619901 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testdata/oci_registry/auth.htpasswd @@ -0,0 +1 @@ +hashicorp:$2y$05$w2qcus7DpEEmnm7u4qeX5upuioXmnWRa8ICgXQZznN6xhxbsqBHK6 diff --git a/shuttles/terraform/terraform-provider-helm/helm/testing/config-da-basic/test.tf b/shuttles/terraform/terraform-provider-helm/helm/testing/config-da-basic/test.tf new file mode 100644 index 0000000..0b98c4f --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testing/config-da-basic/test.tf @@ -0,0 +1,29 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +terraform { + required_providers { + kind = { + source = "tehcyx/kind" + } + } +} + +resource "kind_cluster" "demo" { + name = "tfacc" +} + +provider "helm" { + kubernetes = { + host = kind_cluster.demo.endpoint + cluster_ca_certificate = kind_cluster.demo.cluster_ca_certificate + client_certificate = kind_cluster.demo.client_certificate + client_key = kind_cluster.demo.client_key + } +} + +resource "helm_release" "test-release" { + name = "test-hello" + repository = "https://cloudecho.github.io/charts/" + chart = "hello" +} diff --git a/shuttles/terraform/terraform-provider-helm/helm/testing/deferred_actions_test.go b/shuttles/terraform/terraform-provider-helm/helm/testing/deferred_actions_test.go new file mode 100644 index 0000000..b12a4a7 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/helm/testing/deferred_actions_test.go @@ -0,0 +1,84 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package testing + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-framework/providerserver" + "github.com/hashicorp/terraform-plugin-go/tfprotov6" + "github.com/hashicorp/terraform-plugin-testing/config" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/plancheck" + "github.com/hashicorp/terraform-plugin-testing/statecheck" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" + "github.com/hashicorp/terraform-plugin-testing/tfversion" + "github.com/hashicorp/terraform-provider-helm/helm" +) + +var providerFactory = map[string]func() (tfprotov6.ProviderServer, error){ + "helm": providerserver.NewProtocol6WithError(helm.New("version")()), +} + +func TestAccDeferredActions_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_9_0), + }, + AdditionalCLIOptions: &resource.AdditionalCLIOptions{ + Plan: resource.PlanOptions{AllowDeferral: true}, + Apply: resource.ApplyOptions{AllowDeferral: true}, + }, + Steps: []resource.TestStep{ + { + ProtoV6ProviderFactories: providerFactory, + ConfigDirectory: func(tscr config.TestStepConfigRequest) string { + return "config-da-basic" + }, + ExpectNonEmptyPlan: true, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction("kind_cluster.demo", plancheck.ResourceActionCreate), + plancheck.ExpectDeferredChange("helm_release.test-release", plancheck.DeferredReasonProviderConfigUnknown), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction("helm_release.test-release", plancheck.ResourceActionCreate), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue("kind_cluster.demo", tfjsonpath.New("endpoint"), knownvalue.NotNull()), + statecheck.ExpectKnownValue("kind_cluster.demo", tfjsonpath.New("cluster_ca_certificate"), knownvalue.NotNull()), + statecheck.ExpectKnownValue("kind_cluster.demo", tfjsonpath.New("client_certificate"), knownvalue.NotNull()), + statecheck.ExpectKnownValue("kind_cluster.demo", tfjsonpath.New("client_key"), knownvalue.NotNull()), + }, + }, + { + ProtoV6ProviderFactories: providerFactory, + ConfigDirectory: func(tscr config.TestStepConfigRequest) string { + return "config-da-basic" + }, + ExpectNonEmptyPlan: false, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction("helm_release.test-release", plancheck.ResourceActionCreate), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue("kind_cluster.demo", tfjsonpath.New("endpoint"), knownvalue.NotNull()), + statecheck.ExpectKnownValue("kind_cluster.demo", tfjsonpath.New("cluster_ca_certificate"), knownvalue.NotNull()), + statecheck.ExpectKnownValue("kind_cluster.demo", tfjsonpath.New("client_certificate"), knownvalue.NotNull()), + statecheck.ExpectKnownValue("kind_cluster.demo", tfjsonpath.New("client_key"), knownvalue.NotNull()), + statecheck.ExpectKnownValue("helm_release.test-release", tfjsonpath.New("name"), knownvalue.StringExact("test-hello")), + statecheck.ExpectKnownValue("helm_release.test-release", tfjsonpath.New("chart"), knownvalue.StringExact("hello")), + statecheck.ExpectKnownValue("helm_release.test-release", tfjsonpath.New("repository"), knownvalue.StringExact("https://cloudecho.github.io/charts/")), + statecheck.ExpectKnownValue("helm_release.test-release", tfjsonpath.New("status"), knownvalue.StringExact("deployed")), + }, + }, + }, + }) +} diff --git a/shuttles/terraform/terraform-provider-helm/main.go b/shuttles/terraform/terraform-provider-helm/main.go new file mode 100644 index 0000000..9304fb2 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/main.go @@ -0,0 +1,45 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package main + +import ( + "context" + "flag" + "log" + + "github.com/hashicorp/terraform-plugin-framework/providerserver" + "github.com/hashicorp/terraform-provider-helm/helm" + "k8s.io/klog" +) + +// Example version string that can be overwritten by a release process +var Version string = "dev" + +func main() { + var debug bool + debugFlag := flag.Bool("debug", false, "Start provider in stand-alone debug mode.") + flag.Parse() + + klogFlags := flag.NewFlagSet("klog", flag.ExitOnError) + klog.InitFlags(klogFlags) + err := klogFlags.Set("logtostderr", "false") + if err != nil { + panic(err) + } + + opts := providerserver.ServeOpts{ + Address: "registry.terraform.io/hashicorp/helm", + Debug: debug, + ProtocolVersion: 6, + } + + if *debugFlag { + opts.Debug = true + } + + serveErr := providerserver.Serve(context.Background(), helm.New(Version), opts) + if serveErr != nil { + log.Fatal(serveErr.Error()) + } +} diff --git a/shuttles/terraform/terraform-provider-helm/scripts/changelog-links.sh b/shuttles/terraform/terraform-provider-helm/scripts/changelog-links.sh new file mode 100755 index 0000000..4bf4b02 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/scripts/changelog-links.sh @@ -0,0 +1,34 @@ +#!/bin/bash +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + + +# This script rewrites [GH-nnnn]-style references in the CHANGELOG.md file to +# be Markdown links to the given github issues. +# +# This is run during releases so that the issue references in all of the +# released items are presented as clickable links, but we can just use the +# easy [GH-nnnn] shorthand for quickly adding items to the "Unrelease" section +# while merging things between releases. + +set -e + +if [[ ! -f CHANGELOG.md ]]; then + echo "ERROR: CHANGELOG.md not found in pwd." + echo "Please run this from the root of the terraform provider repository" + exit 1 +fi + +if [[ `uname` == "Darwin" ]]; then + echo "Using BSD sed" + SED="sed -i.bak -E -e" +else + echo "Using GNU sed" + SED="sed -i.bak -r -e" +fi + +PROVIDER_URL="https:\/\/github.com\/terraform-providers\/terraform-provider-ignition\/issues" + +$SED "s/GH-([0-9]+)/\[#\1\]\($PROVIDER_URL\/\1\)/g" -e 's/\[\[#(.+)([0-9])\)]$/(\[#\1\2))/g' CHANGELOG.md + +rm CHANGELOG.md.bak diff --git a/shuttles/terraform/terraform-provider-helm/scripts/errcheck.sh b/shuttles/terraform/terraform-provider-helm/scripts/errcheck.sh new file mode 100755 index 0000000..2589dc8 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/scripts/errcheck.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + + +# Check gofmt +echo "==> Checking for unchecked errors..." + +if ! which errcheck > /dev/null; then + echo "==> Installing errcheck..." + go get -u github.com/kisielk/errcheck +fi + +err_files=$(errcheck -ignoretests \ + -ignore 'github.com/hashicorp/terraform/helper/schema:Set' \ + -ignore 'bytes:.*' \ + -ignore 'io:Close|Write' \ + $(go list ./...| grep -v /vendor/)) + +if [[ -n ${err_files} ]]; then + echo 'Unchecked errors found in the following places:' + echo "${err_files}" + echo "Please handle returned errors. You can check directly with \`make errcheck\`" + exit 1 +fi + +exit 0 diff --git a/shuttles/terraform/terraform-provider-helm/scripts/fix-vendoring.sh b/shuttles/terraform/terraform-provider-helm/scripts/fix-vendoring.sh new file mode 100755 index 0000000..970f910 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/scripts/fix-vendoring.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash + +# Copyright 2016 The Kubernetes Authors All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Copies the current versions of apimachinery and client-go out of the +# main kubernetes repo. These repos are currently out of sync and not +# versioned. +set -euo pipefail + + +rm -rf ./vendor/k8s.io/{api,kube-aggregator,apiserver,apimachinery,client-go,metrics} + +cp -r ./vendor/k8s.io/kubernetes/staging/src/k8s.io/{api,kube-aggregator,apiserver,apimachinery,client-go,metrics} ./vendor/k8s.io diff --git a/shuttles/terraform/terraform-provider-helm/scripts/get-version-matrix.sh b/shuttles/terraform/terraform-provider-helm/scripts/get-version-matrix.sh new file mode 100755 index 0000000..57c6c6a --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/scripts/get-version-matrix.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + + +function get_latest_version() { + curl -s https://api.github.com/repos/hashicorp/terraform/git/refs/tags | \ + jq ".[] | .ref | split(\"/\") | .[2] | select(. | startswith(\"$1\"))" | \ + sort -V -r | head -1 +} + +echo "matrix=[$(get_latest_version v1.0), $(get_latest_version v1.3), $(get_latest_version v1.5), $(get_latest_version v1.7), $(get_latest_version v1.9), $(get_latest_version v1.10), $(get_latest_version v1.11), $(get_latest_version v1.12)]" >> "$GITHUB_OUTPUT" diff --git a/shuttles/terraform/terraform-provider-helm/scripts/gofmtcheck.sh b/shuttles/terraform/terraform-provider-helm/scripts/gofmtcheck.sh new file mode 100755 index 0000000..26b3ff6 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/scripts/gofmtcheck.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + + +# Check gofmt +echo "==> Checking that code complies with gofmt requirements..." +gofmt_files=$(gofmt -l `find . -name '*.go' | grep -v vendor`) +if [[ -n ${gofmt_files} ]]; then + echo 'gofmt needs running on the following files:' + echo "${gofmt_files}" + echo "You can use the command: \`make fmt\` to reformat code." + exit 1 +fi + +exit 0 diff --git a/shuttles/terraform/terraform-provider-helm/scripts/gogetcookie.sh b/shuttles/terraform/terraform-provider-helm/scripts/gogetcookie.sh new file mode 100755 index 0000000..b7bb88c --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/scripts/gogetcookie.sh @@ -0,0 +1,15 @@ +#!/bin/bash +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +eval 'set +o history' 2>/dev/null || setopt HIST_IGNORE_SPACE 2>/dev/null +touch ~/.gitcookies +chmod 0600 ~/.gitcookies + +git config --global http.cookiefile ~/.gitcookies + +tr , \\t <<\__END__ >>~/.gitcookies +go.googlesource.com,FALSE,/,TRUE,2147483647,o,git-alex.somesan.gmail.com=1/ezYFnzxl__DgpHATkUdNGxHHoEg54KtNQxYBhzCkyNw +go-review.googlesource.com,FALSE,/,TRUE,2147483647,o,git-alex.somesan.gmail.com=1/ezYFnzxl__DgpHATkUdNGxHHoEg54KtNQxYBhzCkyNw +__END__ +eval 'set -o history' 2>/dev/null || unsetopt HIST_IGNORE_SPACE 2>/dev/null diff --git a/shuttles/terraform/terraform-provider-helm/scripts/markdown-link-check.sh b/shuttles/terraform/terraform-provider-helm/scripts/markdown-link-check.sh new file mode 100755 index 0000000..1281fa3 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/scripts/markdown-link-check.sh @@ -0,0 +1,77 @@ +#!/usr/bin/env bash +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +# Local script runner for recursive markdown-link-check. +# Runs a dockerized version of this program: https://github.com/tcort/markdown-link-check +# Based on: https://github.com/gaurav-nelson/github-action-markdown-link-check/blob/master/entrypoint.sh +set -o errexit +set -o errtrace +set -o nounset +set -o pipefail +trap 'echo "ERROR at line ${LINENO}"' ERR + +# Allow users to optionally specify additional docker options, path, +# or docker alternative (such as podman). +DOCKER=${1:-`command -v docker`} +DOCKER_RUN_OPTS=${2:-} +DOCKER_VOLUME_OPTS=${3:-} +PROVIDER_DIR=${4:-} + +if [ -z "${PROVIDER_DIR}" ]; then + echo "Please specify the directory containing the helm provider" + exit 1 +fi + +echo "==> Checking Markdown links..." + +error_file="markdown-link-check-errors.txt" +output_file="markdown-link-check-output.txt" + +rm -f "./${error_file}" "./${output_file}" + +${DOCKER} run ${DOCKER_RUN_OPTS} --rm -t \ + -v ${PROVIDER_DIR}:/github/workspace:${DOCKER_VOLUME_OPTS} \ + -w /github/workspace \ + --entrypoint /usr/bin/find \ + docker.io/robertbeal/markdown-link-checker \ + docs/resources docs/data-sources \( -type f -name "*.md" -or -name "*.markdown" \) -exec markdown-link-check --config .markdownlinkcheck.json --quiet --verbose {} \; \ + | tee -a "${output_file}" + +touch "${error_file}" +PREVIOUS_LINE="" +while IFS= read -r LINE; do + if [[ $LINE = *"FILE"* ]]; then + PREVIOUS_LINE=$LINE + if [[ $(tail -1 "${error_file}") != *FILE* ]]; then + echo -e "\n" >> "${error_file}" + echo "$LINE" >> "${error_file}" + fi + elif [[ $LINE = *"✖"* ]] && [[ $PREVIOUS_LINE = *"FILE"* ]]; then + echo "$LINE" >> "${error_file}" + else + PREVIOUS_LINE="" + fi +done < "${output_file}" + +if grep -q "ERROR:" "${output_file}"; then + echo -e "==================> MARKDOWN LINK CHECK FAILED <==================" + if [[ $(tail -1 "${error_file}") = *FILE* ]]; then + sed '$d' "${error_file}" + else + cat "${error_file}" + fi + printf "\n" + echo -e "==================================================================" + exit 1 +else + echo -e "==================> MARKDOWN LINK CHECK SUCCESS <==================" + printf "\n" + echo -e "[✔] All links are good!" + printf "\n" + echo -e "===================================================================" +fi + +rm -f "./${error_file}" "./${output_file}" + +exit 0 diff --git a/shuttles/terraform/terraform-provider-helm/templates/data-sources/template.md.tmpl b/shuttles/terraform/terraform-provider-helm/templates/data-sources/template.md.tmpl new file mode 100644 index 0000000..9a6e2c3 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/templates/data-sources/template.md.tmpl @@ -0,0 +1,31 @@ +--- +page_title: "helm: helm_template" +sidebar_current: "docs-helm-template" +description: |- + +--- +# Data Source: {{ .Name }} + +Render chart templates locally. + +`helm_template` renders chart templates locally and exposes the rendered manifests in the data source attributes. `helm_template` mimics the functionality of the `helm template` command. + +The arguments aim to be identical to the `helm_release` resource. + +For further details on the `helm template` command, refer to the [Helm documentation](https://helm.sh/docs/helm/helm_template/). + +{{ .SchemaMarkdown }} + +## Example Usage + +### Render all chart templates + +The following example renders all templates of the `mariadb` chart of the official Helm stable repository. Concatenated manifests are exposed as output variable `mariadb_instance_manifest`. + +{{tffile "examples/data-sources/template/example_1.tf"}} + +### Render selected chart templates + +The following example renders only the templates `master-statefulset.yaml` and `master-svc.yaml` of the `mariadb` chart of the official Helm stable repository. + +{{tffile "examples/data-sources/template/example_2.tf"}} diff --git a/shuttles/terraform/terraform-provider-helm/templates/guides/v2-upgrade-guide.md b/shuttles/terraform/terraform-provider-helm/templates/guides/v2-upgrade-guide.md new file mode 100644 index 0000000..2065c02 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/templates/guides/v2-upgrade-guide.md @@ -0,0 +1,72 @@ +--- +layout: "helm" +page_title: "Helm: Upgrade Guide for Helm Provider v2.0.0" +description: |- + This guide covers the changes introduced in v2.0.0 of the Helm provider and what you may need to do to upgrade your configuration. +--- + +# Upgrading to v2.0.0 of the Helm provider + +This guide covers the changes introduced in v2.0.0 of the Helm provider and what you may need to do to upgrade your configuration. + +## Changes in v2.0.0 + +### Changes to Kubernetes credentials supplied in the provider block + +We have made several changes to the way access to Kubernetes is configured in the provider block. + +1. The `load_config_file` attribute has been removed. +2. Support for the `KUBECONFIG` environment variable has been dropped and replaced with `KUBE_CONFIG_PATH`. +3. The `config_path` attribute will no longer default to `~/.kube/config` and must be set explicitly. + +The above changes have been made to encourage the best practise of configuring access to Kubernetes in the provider block explicitly, instead of relying upon default paths or `KUBECONFIG` being set. We have done this because allowing the provider to configure its access to Kubernetes implicitly caused confusion with a subset of our users. It also created risk for users who use Terraform to manage multiple clusters. Requiring explicit configuring for kubernetes in the provider block eliminates the possibility that the configuration will be applied to the wrong cluster. + +You will therefore need to explicity configure access to your Kubernetes cluster in the provider block going forward. For many users this will simply mean specifying the `config_path` attribute in the provider block. Users already explicitly configuring the provider should not be affected by this change, but will need to remove the `load_config_file` attribute if they are currently using it. + +When running Terraform inside a Kubernetes cluster no provider configuration is neccessary, as the provider will detect that is has access to a service account token. + +### Removal of the `helm_repository` data source + +This feature of the provider caused a fair bit of confusion and was a source of instability as data sources are not supposed to be stateful. This data source performed a stateful operation that modified the filesystem, mirroring similar functionality to the `helm repo add` command. It has been the recommendation for some time to configure repository information explicity at the `helm_resource` level and so the data source has been removed. See the example below. + +```hcl +resource "helm_release" "redis" { + name = "redis" + + repository = "https://charts.bitnami.com/bitnami" + chart = "redis" +} +``` + +The provider will continue to work with repositories that are configured with `helm repo add` before Terraform is run. + +### Removal of `set_string` in the `helm_release` resource + +The addition of a `type` attribute to the `set` block has rendered `set_string` superfluous so it has been removed. See the example below on how to set a string using the `set` block. This is used when the type of a value is an ambigious (e.g strings containing only numbers, true, false) and we want it to be explicitly parsed as a string. + +```hcl +resource "helm_release" "redis" { + name = "redis" + + repository = "https://charts.bitnami.com/bitnami" + chart = "redis" + + set { + name = "test.value" + value = "123456" + type = "string" + } +} +``` + +### Dropped support for Terraform 0.11 + +All builds of the Helm provider going forward will no longer work with Terraform 0.11. See [Upgrade Guides](https://www.terraform.io/upgrade-guides/index.html) for how to migrate your configurations to a newer version of Terraform. + +### Upgrade to v2 of the Terraform Plugin SDK + +Contributors to the provider will be interested to know this upgrade has brought the latest version of the [Terraform Plugin SDK](https://github.com/hashicorp/terraform-plugin-sdk) which introduced a number of enhancements to the developer experience. Details of the changes introduced can be found under [Extending Terraform](https://www.terraform.io/docs/extend/guides/v2-upgrade-guide.html). + +## Helm 2 + +We removed support in the provider for Helm 2 earlier this year. In accordance with the [Helm v2 deprecation timeline](https://helm.sh/blog/helm-v2-deprecation-timeline/) we will no longer be accepting PRs or handling issues that relate to Helm 2 going forward. diff --git a/shuttles/terraform/terraform-provider-helm/templates/index.md.tmpl b/shuttles/terraform/terraform-provider-helm/templates/index.md.tmpl new file mode 100644 index 0000000..2bad79b --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/templates/index.md.tmpl @@ -0,0 +1,126 @@ +--- +page_title: "Provider: Helm" +sidebar_current: "docs-helm-index" +description: |- + The Helm provider is used to deploy software packages in Kubernetes. The provider needs to be configured with the proper credentials before it can be used. +--- + +{{/* This template serves as a starting point for documentation generation, and can be customized with hardcoded values and/or doc gen templates. + +For example, the {{ .SchemaMarkdown }} template can be used to replace manual schema documentation if descriptions of schema attributes are added in the provider source code. */ -}} + +# Helm Provider + +The Helm provider is used to deploy software packages in Kubernetes. The provider needs to be configured with the proper credentials before it can be used. + +Try the [hands-on tutorial](https://learn.hashicorp.com/tutorials/terraform/helm-provider?in=terraform/kubernetes) on the Helm provider on the HashiCorp Learn site. + +## Resources + +* [Resource: helm_release](r/release.md) + +## Data Sources + +* [Data Source: helm_template](d/template.html) + +## Example Usage + +{{tffile "examples/example_1.tf"}} + +## Requirements + +~> NOTE: The provider does not use the `KUBECONFIG` environment variable by default. See the attribute reference below for the environment variables that map to provider block attributes. + +- You must have a Kubernetes cluster available. We support version 1.14.0 or higher. + +## Authentication + +The Helm provider can get its configuration in two ways: + +1. *Explicitly* by supplying attributes to the provider block. This includes: + * [Using a kubeconfig file](#file-config) + * [Supplying credentials](#credentials-config) + * [Exec plugins](#exec-plugins) +2. *Implicitly* through environment variables. This includes: + * [Using the in-cluster config](#in-cluster-config) + +For a full list of supported provider authentication arguments and their corresponding environment variables, see the [argument reference](#argument-reference) below. + +### File config + +The easiest way is to supply a path to your kubeconfig file using the `config_path` attribute or using the `KUBE_CONFIG_PATH` environment variable. A kubeconfig file may have multiple contexts. If `config_context` is not specified, the provider will use the `default` context. + +{{tffile "examples/example_2.tf"}} + +The provider also supports multiple paths in the same way that kubectl does using the `config_paths` attribute or `KUBE_CONFIG_PATHS` environment variable. + +{{tffile "examples/example_3.tf"}} + +### Credentials config + +You can also configure the host, basic auth credentials, and client certificate authentication explicitly or through environment variables. + +{{tffile "examples/example_4.tf"}} + +### In-cluster Config + +The provider uses the `KUBERNETES_SERVICE_HOST` and `KUBERNETES_SERVICE_PORT` environment variables to detect when it is running inside a cluster, so in this case you do not need to specify any attributes in the provider block if you want to connect to the local kubernetes cluster. + +If you want to connect to a different cluster than the one terraform is running inside, configure the provider as [above](#credentials-config). + +## Exec plugins + +Some cloud providers have short-lived authentication tokens that can expire relatively quickly. To ensure the Kubernetes provider is receiving valid credentials, an exec-based plugin can be used to fetch a new token before initializing the provider. For example, on EKS, the command `eks get-token` can be used: + +{{tffile "examples/example_5.tf"}} + +For example, to [authenticate with GKE](https://registry.terraform.io/providers/hashicorp/google/latest/docs/guides/using_gke_with_terraform#using-the-kubernetes-and-helm-providers), the `gke-cloud-auth-plugin` can be used: + +{{tffile "examples/example_6.tf"}} + +## Argument Reference + +The following arguments are supported: + +* `debug` - (Optional) - Debug indicates whether or not Helm is running in Debug mode. Defaults to `false`. +* `plugins_path` - (Optional) The path to the plugins directory. Defaults to `HELM_PLUGINS` env if it is set, otherwise uses the default path set by helm. +* `registry_config_path` - (Optional) The path to the registry config file. Defaults to `HELM_REGISTRY_CONFIG` env if it is set, otherwise uses the default path set by helm. +* `repository_config_path` - (Optional) The path to the file containing repository names and URLs. Defaults to `HELM_REPOSITORY_CONFIG` env if it is set, otherwise uses the default path set by helm. +* `repository_cache` - (Optional) The path to the file containing cached repository indexes. Defaults to `HELM_REPOSITORY_CACHE` env if it is set, otherwise uses the default path set by helm. +* `helm_driver` - (Optional) "The backend storage driver. Valid values are: `configmap`, `secret`, `memory`, `sql`. Defaults to `secret`. Note: Regarding the sql driver, as of helm v3.2.0 SQL support exists only for the postgres dialect. The connection string can be configured by setting the `HELM_DRIVER_SQL_CONNECTION_STRING` environment variable e.g. `HELM_DRIVER_SQL_CONNECTION_STRING=postgres://username:password@host/dbname` more info [here](https://pkg.go.dev/github.com/lib/pq). +* `burst_limit` - (Optional) The helm burst limit to use. Set this value higher if your cluster has many CRDs. Default: `100` +* `kubernetes` - Kubernetes configuration block. +* `registry` - Private OCI registry configuration block. Can be specified multiple times. + +The `kubernetes` block supports: + +* `config_path` - (Optional) Path to the kube config file. Can be sourced from `KUBE_CONFIG_PATH`. +* `config_paths` - (Optional) A list of paths to the kube config files. Can be sourced from `KUBE_CONFIG_PATHS`. +* `host` - (Optional) The hostname (in form of URI) of the Kubernetes API. Can be sourced from `KUBE_HOST`. +* `username` - (Optional) The username to use for HTTP basic authentication when accessing the Kubernetes API. Can be sourced from `KUBE_USER`. +* `password` - (Optional) The password to use for HTTP basic authentication when accessing the Kubernetes API. Can be sourced from `KUBE_PASSWORD`. +* `token` - (Optional) The bearer token to use for authentication when accessing the Kubernetes API. Can be sourced from `KUBE_TOKEN`. +* `insecure` - (Optional) Whether server should be accessed without verifying the TLS certificate. Can be sourced from `KUBE_INSECURE`. +* `tls_server_name` - (Optional) Server name passed to the server for SNI and is used in the client to check server certificates against. Can be sourced from `KUBE_TLS_SERVER_NAME`. +* `client_certificate` - (Optional) PEM-encoded client certificate for TLS authentication. Can be sourced from `KUBE_CLIENT_CERT_DATA`. +* `client_key` - (Optional) PEM-encoded client certificate key for TLS authentication. Can be sourced from `KUBE_CLIENT_KEY_DATA`. +* `cluster_ca_certificate` - (Optional) PEM-encoded root certificates bundle for TLS authentication. Can be sourced from `KUBE_CLUSTER_CA_CERT_DATA`. +* `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. + +The `registry` block has options: + +* `url` - (Required) url to the registry in format `oci://host:port` +* `username` - (Required) username to registry +* `password` - (Required) password to registry + +## Experiments + +The provider takes an `experiments` block that allows you enable experimental features by setting them to `true`. + +* `manifest` - Enable storing of the rendered manifest for `helm_release` so the full diff of what is changing can been seen in the plan. diff --git a/shuttles/terraform/terraform-provider-helm/templates/resources/release.md.tmpl b/shuttles/terraform/terraform-provider-helm/templates/resources/release.md.tmpl new file mode 100644 index 0000000..f920590 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/templates/resources/release.md.tmpl @@ -0,0 +1,123 @@ +--- +page_title: "helm: helm_release" +sidebar_current: "docs-helm-release" +description: |- + +--- +# Resource: {{ .Name }} + +A Release is an instance of a chart running in a Kubernetes cluster. + +A Chart is a Helm package. It contains all of the resource definitions necessary to run an application, tool, or service inside of a Kubernetes cluster. + +`helm_release` describes the desired status of a chart in a kubernetes cluster. + +{{ .SchemaMarkdown }} + + +## Example Usage - Chart Repository + +{{tffile "examples/resources/release/example_1.tf"}} + +## Example Usage - Local Chart + +In case a Chart is not available from a repository, a path may be used: + +{{tffile "examples/resources/release/example_2.tf"}} + +## Example Usage - Chart URL + +An absolute URL to the .tgz of the Chart may also be used: + +{{tffile "examples/resources/release/example_3.tf"}} + +## Example Usage - Chart Repository configured from OCI Registry + +Provider supports grabbing charts from an OCI repository: + +{{tffile "examples/resources/release/example_4.tf"}} + +## Example Usage - Chart Repository configured using GCS/S3 + +The provider also supports helm plugins such as GCS and S3 that add S3/GCS helm repositories by using `helm plugin install` + +{{tffile "examples/resources/release/example_5.tf"}} + +{{tffile "examples/resources/release/example_6.tf"}} + +## Example Usage - Chart Repository configured outside of Terraform + +The provider also supports repositories that are added to the local machine outside of Terraform by running `helm repo add` + +{{tffile "examples/resources/release/example_7.tf"}} + +The `set`, and `set_sensitive` blocks support: + +* `name` - (Required) full name of the variable to be set. +* `value` - (Required) value of the variable to be set. +* `type` - (Optional) type of the variable to be set. Valid options are `auto`, `string`, and `literal`. + +Since Terraform Utilizes HCL as well as Helm using the Helm Template Language, it's necessary to escape the `{}`, `[]`, `.`, and `,` characters twice in order for it to be parsed. `name` should also be set to the `value path`, and `value` is the desired value that will be set. + +{{tffile "examples/resources/release/example_8.tf"}} + +{{tffile "examples/resources/release/example_9.tf"}} + +{{tffile "examples/resources/release/example_10.tf"}} + +{{tffile "examples/resources/release/example_11.tf"}} + +The `postrender` block supports two attributes: + +* `binary_path` - (Required) relative or full path to command binary. +* `args` - (Optional) a list of arguments to supply to the post-renderer. + +## Upgrade Mode Notes + +When using the Helm CLI directly, it is possible to use `helm upgrade --install` to +_idempotently_ install a release. For example, `helm upgrade --install mariadb charts/mariadb --verson 7.1.0` +will check to see if there is already a release called `mariadb`: if there is, ensure that it is set to version +7.1.0, and if there is not, install that version from scratch. (See the documentation for the +[helm upgrade](https://helm.sh/docs/helm/helm_upgrade) command for more details.) + + **NOTE:** The mechanics of this approach are subtly 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 the `upgrade_install` attribute to `true`, the provider will first check to see +if a release with the given name already exists. 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. + +However, if the release _does_ already exist, the provider 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. + +When using `upgrade_install`, the `version` attribute is used to determine the version of the chart to install or +upgrade to. If the `version` attribute is not set, the provider will attempt to determine the version of the chart +from the existing release and will use that version for the upgrade: this is to ensure that using `upgrade_install` +does not inadvertently change the version of the chart being used. + +**CRITICAL**: The user-supplied values passed to the chart in the new revision will be the ones specified in the +`helm_release` resource, not the values used in the original installation of the chart. This means that if +you are using `upgrade_install` to manage a release that was originally installed with a different set of values, +you must ensure that the values in the `helm_release` resource are correct, or you may inadvertently change the +configuration of the release. Additionally, since there is no existing terraform state to compare against, you +must manually inspect the installed release's values with the `helm get values` CLI command. + +**IMPORTANT**: Even if you are "upgrading" to the same version of the chart that is already present in the cluster, +the `helm_release` resource will still show as "changed" in the terraform plan output, because there is no existing +state for it to compare against. This also means that in the apply stage, the provider will in fact reinstall the +chart, which means that if there are any +[deployment](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/), +[daemonset](https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/) or +[statefulset](https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/) resources in the chart, they will +be replaced, which will cause a rolling update of the pods. + +## Import + +A Helm Release resource can be imported using its namespace and name e.g. + +```shell +$ terraform import helm_release.example default/example-name +``` + +~> **NOTE:** Since the `repository` attribute is not being persisted as metadata by helm, it will not be set to any value by default. All other provider specific attributes will be set to their default values and they can be overriden after running `apply` using the resource definition configuration. diff --git a/shuttles/terraform/terraform-provider-helm/terraform-registry-manifest.json b/shuttles/terraform/terraform-provider-helm/terraform-registry-manifest.json new file mode 100644 index 0000000..1931b0e --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/terraform-registry-manifest.json @@ -0,0 +1,6 @@ +{ + "version": 1, + "metadata": { + "protocol_versions": ["5.0"] + } +} diff --git a/shuttles/terraform/terraform-provider-helm/tools/tools.go b/shuttles/terraform/terraform-provider-helm/tools/tools.go new file mode 100644 index 0000000..307faf2 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/tools/tools.go @@ -0,0 +1,11 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +//go:build tools +// +build tools + +package tools + +import ( + _ "github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs" +) diff --git a/shuttles/terraform/terraform-provider-helm/version/VERSION b/shuttles/terraform/terraform-provider-helm/version/VERSION new file mode 100644 index 0000000..b502146 --- /dev/null +++ b/shuttles/terraform/terraform-provider-helm/version/VERSION @@ -0,0 +1 @@ +3.0.2