mirror of
https://github.com/hashicorp/terraform-provider-helm.git
synced 2025-12-18 23:26:08 -05:00
Migrate to terraform plugin framework (#1379)
Co-authored-by: Mauricio Alvarez Leon <65101411+BBBmau@users.noreply.github.com> Co-authored-by: John Houston <jhouston@hashicorp.com> Co-authored-by: Brandy Jackson <90709515+iBrandyJackson@users.noreply.github.com>
This commit is contained in:
parent
afc64eda21
commit
b328cfa7d1
27 changed files with 5151 additions and 4186 deletions
3
.changelog/1379.txt
Normal file
3
.changelog/1379.txt
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
```release-note:dependency
|
||||
Provider project ported from `terraform-plugin-sdk/v2` to `terraform-plugin-framework`
|
||||
```
|
||||
42
.github/workflows/documentation-check.yaml
vendored
42
.github/workflows/documentation-check.yaml
vendored
|
|
@ -1,42 +0,0 @@
|
|||
name: "Documentation Updates"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- 'docs/**'
|
||||
types: [opened, synchronize, labeled]
|
||||
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
check-docs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
if: ${{ !contains(github.event.pull_request.labels.*.name, 'no-documentation') }}
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
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: Install tfplugindocs command
|
||||
run: go install github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs@latest
|
||||
|
||||
- name: Run tfplugindocs command
|
||||
run: tfplugindocs generate
|
||||
|
||||
- name: Check for changes
|
||||
run: |
|
||||
git diff --exit-code
|
||||
|
||||
- name: Undocumented changes
|
||||
run: |
|
||||
echo 'Documentation is not up to date. Please refer to the `Making Changes` in the Contribution Guide on how to properly update documentation.'
|
||||
exit 1
|
||||
if: failure()
|
||||
3
.github/workflows/tests.yaml
vendored
3
.github/workflows/tests.yaml
vendored
|
|
@ -3,11 +3,9 @@ on:
|
|||
push:
|
||||
branches:
|
||||
- main
|
||||
- helm-framework
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
- helm-framework
|
||||
|
||||
env:
|
||||
KUBECONFIG: ${{ github.workspace }}/.kube/config
|
||||
|
|
@ -59,6 +57,7 @@ jobs:
|
|||
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
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ 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))
|
||||
|
|
|
|||
|
|
@ -140,17 +140,22 @@ data "helm_template" "mariadb_instance" {
|
|||
chart = "mariadb"
|
||||
version = "7.1.0"
|
||||
|
||||
set {
|
||||
name = "service.port"
|
||||
value = "13306"
|
||||
}
|
||||
set = [
|
||||
{
|
||||
name = "service.port"
|
||||
value = "13306"
|
||||
}
|
||||
]
|
||||
|
||||
set_sensitive {
|
||||
name = "rootUser.password"
|
||||
value = "s3cr3t!"
|
||||
}
|
||||
set_sensitive = [
|
||||
{
|
||||
name = "rootUser.password"
|
||||
value = "s3cr3t!"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
resource "local_file" "mariadb_manifests" {
|
||||
for_each = data.helm_template.mariadb_instance.manifests
|
||||
|
||||
|
|
@ -188,18 +193,23 @@ data "helm_template" "mariadb_instance" {
|
|||
"templates/master-statefulset.yaml",
|
||||
"templates/master-svc.yaml",
|
||||
]
|
||||
|
||||
set {
|
||||
name = "service.port"
|
||||
value = "13306"
|
||||
}
|
||||
|
||||
set_sensitive {
|
||||
name = "rootUser.password"
|
||||
value = "s3cr3t!"
|
||||
}
|
||||
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
|
||||
|
||||
|
|
@ -219,3 +229,4 @@ output "mariadb_instance_notes" {
|
|||
value = data.helm_template.mariadb_instance.notes
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
|||
246
docs/guides/v3-upgrade-guide.md
Normal file
246
docs/guides/v3-upgrade-guide.md
Normal file
|
|
@ -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 `[ { ... } ]`.
|
||||
|
|
@ -23,35 +23,35 @@ Try the [hands-on tutorial](https://learn.hashicorp.com/tutorials/terraform/helm
|
|||
|
||||
```terraform
|
||||
provider "helm" {
|
||||
kubernetes {
|
||||
kubernetes = {
|
||||
config_path = "~/.kube/config"
|
||||
}
|
||||
|
||||
# localhost registry with password protection
|
||||
registry {
|
||||
url = "oci://localhost:5000"
|
||||
username = "username"
|
||||
password = "password"
|
||||
}
|
||||
|
||||
# private registry
|
||||
registry {
|
||||
url = "oci://private.registry"
|
||||
username = "username"
|
||||
password = "password"
|
||||
}
|
||||
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"
|
||||
}
|
||||
set = [
|
||||
{
|
||||
name = "service.type"
|
||||
value = "ClusterIP"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
|
|
@ -80,7 +80,7 @@ The easiest way is to supply a path to your kubeconfig file using the `config_pa
|
|||
|
||||
```terraform
|
||||
provider "helm" {
|
||||
kubernetes {
|
||||
kubernetes = {
|
||||
config_path = "~/.kube/config"
|
||||
}
|
||||
}
|
||||
|
|
@ -90,7 +90,7 @@ The provider also supports multiple paths in the same way that kubectl does usin
|
|||
|
||||
```terraform
|
||||
provider "helm" {
|
||||
kubernetes {
|
||||
kubernetes = {
|
||||
config_paths = [
|
||||
"/path/to/config_a.yaml",
|
||||
"/path/to/config_b.yaml"
|
||||
|
|
@ -104,7 +104,7 @@ provider "helm" {
|
|||
You can also configure the host, basic auth credentials, and client certificate authentication explicitly or through environment variables.
|
||||
|
||||
```terraform
|
||||
provider "helm" {
|
||||
provider "helm" = {
|
||||
kubernetes {
|
||||
host = "https://cluster_endpoint:port"
|
||||
|
||||
|
|
@ -127,7 +127,7 @@ Some cloud providers have short-lived authentication tokens that can expire rela
|
|||
|
||||
```terraform
|
||||
provider "helm" {
|
||||
kubernetes {
|
||||
kubernetes = {
|
||||
host = var.cluster_endpoint
|
||||
cluster_ca_certificate = base64decode(var.cluster_ca_cert)
|
||||
exec {
|
||||
|
|
@ -143,7 +143,7 @@ For example, to [authenticate with GKE](https://registry.terraform.io/providers/
|
|||
|
||||
```terraform
|
||||
provider "helm" {
|
||||
kubernetes{
|
||||
kubernetes = {
|
||||
host = "https://${data.google_container_cluster.my_cluster.endpoint}"
|
||||
token = data.google_client_config.provider.access_token
|
||||
cluster_ca_certificate = base64decode(
|
||||
|
|
@ -168,7 +168,7 @@ The following arguments are supported:
|
|||
* `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.
|
||||
* `registries` - Private OCI registry configuration block. Can be specified multiple times.
|
||||
|
||||
The `kubernetes` block supports:
|
||||
|
||||
|
|
@ -191,7 +191,7 @@ The `kubernetes` block supports:
|
|||
* `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:
|
||||
The `registries` block has options:
|
||||
|
||||
* `url` - (Required) url to the registry in format `oci://host:port`
|
||||
* `username` - (Required) username to registry
|
||||
|
|
@ -202,3 +202,11 @@ The `registry` block has options:
|
|||
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
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
|
|||
|
|
@ -144,25 +144,24 @@ resource "helm_release" "example" {
|
|||
chart = "redis"
|
||||
version = "6.0.1"
|
||||
|
||||
values = [
|
||||
"${file("values.yaml")}"
|
||||
set = [
|
||||
{
|
||||
name = "cluster.enabled"
|
||||
value = "true"
|
||||
},
|
||||
{
|
||||
name = "metrics.enabled"
|
||||
value = "true"
|
||||
}
|
||||
]
|
||||
|
||||
set {
|
||||
name = "cluster.enabled"
|
||||
value = "true"
|
||||
}
|
||||
|
||||
set {
|
||||
name = "metrics.enabled"
|
||||
value = "true"
|
||||
}
|
||||
|
||||
set {
|
||||
name = "service.annotations.prometheus\\.io/port"
|
||||
value = "9127"
|
||||
type = "string"
|
||||
}
|
||||
set = [
|
||||
{
|
||||
name = "service.annotations.prometheus\\.io/port"
|
||||
value = "9127"
|
||||
type = "string"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
|
|
@ -194,16 +193,17 @@ Provider supports grabbing charts from an OCI repository:
|
|||
|
||||
```terraform
|
||||
provider "helm" {
|
||||
kubernetes {
|
||||
kubernetes = {
|
||||
config_path = "~/.kube/config"
|
||||
}
|
||||
|
||||
# localhost registry with password protection
|
||||
registry {
|
||||
url = "oci://localhost:5000"
|
||||
username = "username"
|
||||
password = "password"
|
||||
}
|
||||
registries = [
|
||||
{
|
||||
url = "oci://localhost:5000"
|
||||
username = "username"
|
||||
password = "password"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
resource "helm_release" "example" {
|
||||
|
|
@ -295,17 +295,21 @@ The `set`, `set_list`, and `set_sensitive` blocks support:
|
|||
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"
|
||||
}
|
||||
set = [
|
||||
{
|
||||
name = "grafana.ingress.annotations.alb\\.ingress\\.kubernetes\\.io/group\\.name"
|
||||
value = "shared-ingress"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
```terraform
|
||||
set_list {
|
||||
name = "hashicorp"
|
||||
value = ["terraform", "nomad", "vault"]
|
||||
}
|
||||
set_list = [
|
||||
{
|
||||
name = "hashicorp"
|
||||
value = ["terraform", "nomad", "vault"]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
```terraform
|
||||
|
|
@ -316,10 +320,13 @@ controller:
|
|||
```
|
||||
|
||||
```terraform
|
||||
set {
|
||||
set = [
|
||||
{
|
||||
name = "controller.pod.annotations.status\\.kubernetes\\.io/restart-on-failure"
|
||||
value = "\\{\"timeout\": \"30s\"\\}"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
```
|
||||
|
||||
The `postrender` block supports two attributes:
|
||||
|
|
|
|||
45
go.mod
45
go.mod
|
|
@ -2,14 +2,17 @@ module github.com/hashicorp/terraform-provider-helm
|
|||
|
||||
go 1.22.0
|
||||
|
||||
toolchain go1.22.5
|
||||
toolchain go1.22.3
|
||||
|
||||
require (
|
||||
github.com/hashicorp/go-cty v1.4.1-0.20200723130312-85980079f637
|
||||
github.com/hashicorp/terraform-plugin-docs v0.19.4
|
||||
github.com/hashicorp/terraform-plugin-framework v1.11.0
|
||||
github.com/hashicorp/terraform-plugin-framework-validators v0.13.0
|
||||
github.com/hashicorp/terraform-plugin-go v0.23.0
|
||||
github.com/hashicorp/terraform-plugin-log v0.9.0
|
||||
github.com/hashicorp/terraform-plugin-sdk/v2 v2.34.0
|
||||
github.com/hashicorp/terraform-plugin-testing v1.8.0
|
||||
github.com/hashicorp/terraform-plugin-testing v1.10.0
|
||||
github.com/mitchellh/go-homedir v1.1.0
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/stretchr/testify v1.8.4
|
||||
|
|
@ -18,15 +21,22 @@ require (
|
|||
k8s.io/api v0.30.3
|
||||
k8s.io/apimachinery v0.30.3
|
||||
k8s.io/client-go v0.30.3
|
||||
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.6.1 // indirect
|
||||
github.com/hashicorp/cli v1.1.6 // indirect
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
|
||||
github.com/BurntSushi/toml v1.3.2 // indirect
|
||||
github.com/Kunde21/markdownfmt/v3 v3.1.0 // indirect
|
||||
github.com/MakeNowJust/heredoc v1.0.0 // indirect
|
||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||
github.com/Masterminds/semver/v3 v3.2.1 // indirect
|
||||
|
|
@ -34,13 +44,12 @@ require (
|
|||
github.com/Masterminds/squirrel v1.5.4 // indirect
|
||||
github.com/Microsoft/hcsshim v0.11.4 // indirect
|
||||
github.com/ProtonMail/go-crypto v1.1.0-alpha.2 // indirect
|
||||
github.com/agext/levenshtein v1.2.2 // 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-20200428143746-21a406dcc535 // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bgentry/speakeasy v0.1.0 // indirect
|
||||
github.com/bmatcuk/doublestar/v4 v4.6.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/chai2010/gettext-go v1.0.2 // indirect
|
||||
github.com/cloudflare/circl v1.3.7 // indirect
|
||||
|
|
@ -60,6 +69,7 @@ require (
|
|||
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect
|
||||
github.com/fatih/color v1.16.0 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.3 // 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.1 // indirect
|
||||
|
|
@ -80,21 +90,20 @@ require (
|
|||
github.com/gorilla/websocket v1.5.0 // indirect
|
||||
github.com/gosuri/uitable v0.0.4 // indirect
|
||||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect
|
||||
github.com/hashicorp/cli v1.1.6 // 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-hclog v1.6.3 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/hashicorp/go-plugin v1.6.0 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
|
||||
github.com/hashicorp/go-uuid v1.0.3 // indirect
|
||||
github.com/hashicorp/go-version v1.7.0 // indirect
|
||||
github.com/hashicorp/hc-install v0.7.0 // indirect
|
||||
github.com/hashicorp/hcl/v2 v2.20.1 // indirect
|
||||
github.com/hashicorp/hc-install v0.8.0 // indirect
|
||||
github.com/hashicorp/hcl/v2 v2.21.0 // indirect
|
||||
github.com/hashicorp/logutils v1.0.0 // indirect
|
||||
github.com/hashicorp/terraform-exec v0.21.0 // indirect
|
||||
github.com/hashicorp/terraform-json v0.22.1 // indirect
|
||||
github.com/hashicorp/terraform-plugin-log v0.9.0 // indirect
|
||||
github.com/hashicorp/terraform-registry-address v0.2.3 // indirect
|
||||
github.com/hashicorp/terraform-svchost v0.1.1 // indirect
|
||||
github.com/hashicorp/yamux v0.1.1 // indirect
|
||||
|
|
@ -112,7 +121,7 @@ require (
|
|||
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.9 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.13 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
|
||||
|
|
@ -153,22 +162,22 @@ require (
|
|||
github.com/xlab/treeprint v1.2.0 // indirect
|
||||
github.com/yuin/goldmark v1.7.1 // indirect
|
||||
github.com/yuin/goldmark-meta v1.1.0 // indirect
|
||||
github.com/zclconf/go-cty v1.14.4 // indirect
|
||||
github.com/zclconf/go-cty v1.15.0 // indirect
|
||||
go.abhg.dev/goldmark/frontmatter v0.2.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 // indirect
|
||||
go.opentelemetry.io/otel v1.19.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.19.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.19.0 // indirect
|
||||
go.opentelemetry.io/otel v1.21.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.21.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.21.0 // indirect
|
||||
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect
|
||||
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df // indirect
|
||||
golang.org/x/mod v0.17.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
|
||||
golang.org/x/mod v0.19.0 // indirect
|
||||
golang.org/x/net v0.25.0 // indirect
|
||||
golang.org/x/oauth2 v0.17.0 // indirect
|
||||
golang.org/x/sync v0.10.0 // indirect
|
||||
golang.org/x/sys v0.28.0 // indirect
|
||||
golang.org/x/term v0.27.0 // indirect
|
||||
golang.org/x/text v0.21.0 // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
golang.org/x/time v0.5.0 // indirect
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
|
||||
google.golang.org/appengine v1.6.8 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect
|
||||
|
|
|
|||
68
go.sum
68
go.sum
|
|
@ -31,8 +31,8 @@ github.com/ProtonMail/go-crypto v1.1.0-alpha.2 h1:bkyFVUP+ROOARdgCiJzNQo2V2kiB97
|
|||
github.com/ProtonMail/go-crypto v1.1.0-alpha.2/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.2 h1:0S/Yg6LYmFJ5stwQeRp6EeOcCbj7xiqQSdNelsXvaqE=
|
||||
github.com/agext/levenshtein v1.2.2/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
|
||||
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=
|
||||
|
|
@ -42,8 +42,8 @@ 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-20200428143746-21a406dcc535 h1:4daAzAu0S6Vi7/lbWECcX0j45yZReDZ56BQsrVBOEEY=
|
||||
github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg=
|
||||
github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef h1:46PFijGLmAjMPwCCCo7Jf0W6f9slllCkkv7vyc1yOSg=
|
||||
github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/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=
|
||||
|
|
@ -129,6 +129,8 @@ github.com/foxcpp/go-mockdns v1.0.0 h1:7jBqxd3WDWwi/6WhDvacvH1XsN3rOLXyHM1uhvIx6
|
|||
github.com/foxcpp/go-mockdns v1.0.0/go.mod h1:lgRN6+KxQBawyIghpnl5CezHFGS9VLzvtVlwxvzXTQ4=
|
||||
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
|
||||
github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps=
|
||||
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=
|
||||
|
|
@ -246,6 +248,8 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l
|
|||
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
||||
github.com/hashicorp/go-plugin v1.6.0 h1:wgd4KxHJTVGGqWBq4QPB1i5BZNEx9BR8+OFmHDmTk8A=
|
||||
github.com/hashicorp/go-plugin v1.6.0/go.mod h1:lBS5MtSSBZk0SHc66KACcjjlU6WzEVP/8pwz68aMkCI=
|
||||
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=
|
||||
|
|
@ -253,10 +257,10 @@ github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKe
|
|||
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.7.0 h1:Uu9edVqjKQxxuD28mR5TikkKDd/p55S8vzPC1659aBk=
|
||||
github.com/hashicorp/hc-install v0.7.0/go.mod h1:ELmmzZlGnEcqoUMKUuykHaPCIR1sYLYX+KSggWSKZuA=
|
||||
github.com/hashicorp/hcl/v2 v2.20.1 h1:M6hgdyz7HYt1UN9e61j+qKJBqR3orTWbI1HKBJEdxtc=
|
||||
github.com/hashicorp/hcl/v2 v2.20.1/go.mod h1:TZDqQ4kNKCbh1iJp99FdPiUaVDDUPivbqxZulxDYqL4=
|
||||
github.com/hashicorp/hc-install v0.8.0 h1:LdpZeXkZYMQhoKPCecJHlKvUkQFixN/nvyR1CdfOLjI=
|
||||
github.com/hashicorp/hc-install v0.8.0/go.mod h1:+MwJYjDfCruSD/udvBmRB22Nlkwwkwf5sAB6uTIhSaU=
|
||||
github.com/hashicorp/hcl/v2 v2.21.0 h1:lve4q/o/2rqwYOgUg3y3V2YPyD1/zkCLGjIV74Jit14=
|
||||
github.com/hashicorp/hcl/v2 v2.21.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.21.0 h1:uNkLAe95ey5Uux6KJdua6+cv8asgILFVWkd/RG0D2XQ=
|
||||
|
|
@ -265,14 +269,18 @@ github.com/hashicorp/terraform-json v0.22.1 h1:xft84GZR0QzjPVWs4lRUwvTcPnegqlyS7
|
|||
github.com/hashicorp/terraform-json v0.22.1/go.mod h1:JbWSQCLFSXFFhg42T7l9iJwdGXBYV8fmmD6o/ML4p3A=
|
||||
github.com/hashicorp/terraform-plugin-docs v0.19.4 h1:G3Bgo7J22OMtegIgn8Cd/CaSeyEljqjH3G39w28JK4c=
|
||||
github.com/hashicorp/terraform-plugin-docs v0.19.4/go.mod h1:4pLASsatTmRynVzsjEhbXZ6s7xBlUw/2Kt0zfrq8HxA=
|
||||
github.com/hashicorp/terraform-plugin-framework v1.11.0 h1:M7+9zBArexHFXDx/pKTxjE6n/2UCXY6b8FIq9ZYhwfE=
|
||||
github.com/hashicorp/terraform-plugin-framework v1.11.0/go.mod h1:qBXLDn69kM97NNVi/MQ9qgd1uWWsVftGSnygYG1tImM=
|
||||
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.23.0 h1:AALVuU1gD1kPb48aPQUjug9Ir/125t+AAurhqphJ2Co=
|
||||
github.com/hashicorp/terraform-plugin-go v0.23.0/go.mod h1:1E3Cr9h2vMlahWMbsSEcNrOCxovCZhOOIXjFHbjc/lQ=
|
||||
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.34.0 h1:kJiWGx2kiQVo97Y5IOGR4EMcZ8DtMswHhUuFibsCQQE=
|
||||
github.com/hashicorp/terraform-plugin-sdk/v2 v2.34.0/go.mod h1:sl/UoabMc37HA6ICVMmGO+/0wofkVIRxf+BMb/dnoIg=
|
||||
github.com/hashicorp/terraform-plugin-testing v1.8.0 h1:wdYIgwDk4iO933gC4S8KbKdnMQShu6BXuZQPScmHvpk=
|
||||
github.com/hashicorp/terraform-plugin-testing v1.8.0/go.mod h1:o2kOgf18ADUaZGhtOl0YCkfIxg01MAiMATT2EtIHlZk=
|
||||
github.com/hashicorp/terraform-plugin-testing v1.10.0 h1:2+tmRNhvnfE4Bs8rB6v58S/VpqzGC6RCh9Y8ujdn+aw=
|
||||
github.com/hashicorp/terraform-plugin-testing v1.10.0/go.mod h1:iWRW3+loP33WMch2P/TEyCxxct/ZEcCGMquSLSCVsrc=
|
||||
github.com/hashicorp/terraform-registry-address v0.2.3 h1:2TAiKJ1A3MAkZlH1YI/aTVcLZRu7JseiXNRHbOAyoTI=
|
||||
github.com/hashicorp/terraform-registry-address v0.2.3/go.mod h1:lFHA76T8jfQteVfT7caREqguFrW3c4MFSPhZB7HHgUM=
|
||||
github.com/hashicorp/terraform-svchost v0.1.1 h1:EZZimZ1GxdqFRinZ1tpJwVxxt49xc/S52uzrw4x0jKQ=
|
||||
|
|
@ -344,8 +352,8 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k
|
|||
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.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
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.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI=
|
||||
github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||
|
|
@ -434,6 +442,8 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT
|
|||
github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
|
||||
github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg=
|
||||
github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM=
|
||||
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.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||
github.com/rubenv/sql-migrate v1.5.2 h1:bMDqOnrJVV/6JQgQ/MxOpU+AdO8uzYYA/TxFUBzFtS0=
|
||||
|
|
@ -504,22 +514,22 @@ github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50 h1:hlE8//ciYMzt
|
|||
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.14.4 h1:uXXczd9QDGsgu0i/QFR/hzI5NYCHLf6NQw/atrbnhq8=
|
||||
github.com/zclconf/go-cty v1.14.4/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
|
||||
github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b h1:FosyBZYxY34Wul7O/MSKey3txpPYyCqVO5ZyceuQJEI=
|
||||
github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b/go.mod h1:ZRKQfBXbGkpdV6QMzT3rU1kSTAnfu1dO8dPKjYprgj8=
|
||||
github.com/zclconf/go-cty v1.15.0 h1:tTCRWxsexYUmtt/wVxgDClUe+uQusuI443uL6e+5sXQ=
|
||||
github.com/zclconf/go-cty v1.15.0/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/contrib/instrumentation/net/http/otelhttp v0.45.0 h1:x8Z78aZx8cOF0+Kkazoc7lwUNMGy0LrzEMxTm4BbTxg=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0/go.mod h1:62CPTSry9QZtOaSsE3tOzhx6LzDhHnXJ6xHeMNNiM6Q=
|
||||
go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs=
|
||||
go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY=
|
||||
go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE=
|
||||
go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8=
|
||||
go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg=
|
||||
go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo=
|
||||
go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc=
|
||||
go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo=
|
||||
go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4=
|
||||
go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM=
|
||||
go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc=
|
||||
go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ=
|
||||
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca h1:VdD38733bfYv5tUZwEIskMM93VanwNIi5bIKnDrJdEY=
|
||||
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
|
|
@ -531,16 +541,16 @@ golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4
|
|||
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
|
||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df h1:UA2aFVmmsIlefxMk29Dp2juaUSth8Pyn3Tq5Y5mJGME=
|
||||
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
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.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8=
|
||||
golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
|
|
@ -605,8 +615,8 @@ golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
|||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
||||
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||
golang.org/x/time v0.5.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-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
|
|
@ -686,6 +696,8 @@ k8s.io/client-go v0.30.3 h1:bHrJu3xQZNXIi8/MoxYtZBBWQQXwy16zqJwloXXfD3k=
|
|||
k8s.io/client-go v0.30.3/go.mod h1:8d4pf8vYu665/kUbsxWAQ/JDBNWqfFeZnvFiVdmx89U=
|
||||
k8s.io/component-base v0.30.0 h1:cj6bp38g0ainlfYtaOQuRELh5KSYjhKxM+io7AUIk4o=
|
||||
k8s.io/component-base v0.30.0/go.mod h1:V9x/0ePFNaKeKYA3bOvIbrNoluTSG+fSJKjLdjOoeXQ=
|
||||
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.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw=
|
||||
|
|
|
|||
1061
helm/data_helm_template.go
Normal file
1061
helm/data_helm_template.go
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -8,7 +8,7 @@ import (
|
|||
"regexp"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
|
||||
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
|
||||
)
|
||||
|
||||
func TestAccDataTemplate_basic(t *testing.T) {
|
||||
|
|
@ -18,8 +18,7 @@ func TestAccDataTemplate_basic(t *testing.T) {
|
|||
datasourceAddress := fmt.Sprintf("data.helm_template.%s", testResourceName)
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
ProtoV6ProviderFactories: protoV6ProviderFactories(),
|
||||
Steps: []resource.TestStep{{
|
||||
Config: testAccDataHelmTemplateConfigBasic(testResourceName, namespace, name, "1.2.3"),
|
||||
Check: resource.ComposeAggregateTestCheckFunc(
|
||||
|
|
@ -43,8 +42,7 @@ func TestAccDataTemplate_crds(t *testing.T) {
|
|||
datasourceAddress := fmt.Sprintf("data.helm_template.%s", testResourceName)
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
ProtoV6ProviderFactories: protoV6ProviderFactories(),
|
||||
Steps: []resource.TestStep{{
|
||||
Config: testAccDataHelmTemplateCRDs(testResourceName, namespace, name, "1.2.3"),
|
||||
Check: resource.ComposeAggregateTestCheckFunc(
|
||||
|
|
@ -181,8 +179,7 @@ data:
|
|||
`, name)
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
ProtoV6ProviderFactories: protoV6ProviderFactories(),
|
||||
Steps: []resource.TestStep{{
|
||||
Config: testAccDataHelmTemplateConfigTemplates(testResourceName, namespace, name, "1.2.3"),
|
||||
Check: resource.ComposeAggregateTestCheckFunc(
|
||||
|
|
@ -201,40 +198,32 @@ func TestAccDataTemplate_kubeVersion(t *testing.T) {
|
|||
|
||||
datasourceAddress := fmt.Sprintf("data.helm_template.%s", testResourceName)
|
||||
|
||||
// No kube version set, will fail as v1.20.0.
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
ProtoV6ProviderFactories: protoV6ProviderFactories(),
|
||||
Steps: []resource.TestStep{{
|
||||
Config: testAccDataHelmTemplateKubeVersionNoVersionSet(testResourceName, namespace, name, "1.2.3"),
|
||||
ExpectError: regexp.MustCompile("chart requires kubeVersion.*"),
|
||||
}},
|
||||
})
|
||||
|
||||
// Kube Version set but for a to low version.
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
ProtoV6ProviderFactories: protoV6ProviderFactories(),
|
||||
Steps: []resource.TestStep{{
|
||||
Config: testAccDataHelmTemplateKubeVersion(testResourceName, namespace, name, "1.2.3", "1.18.0"),
|
||||
ExpectError: regexp.MustCompile("chart requires kubeVersion.*"),
|
||||
}},
|
||||
})
|
||||
|
||||
// Kube Version set but not parsable.
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
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`),
|
||||
}},
|
||||
})
|
||||
|
||||
// Kube Version set and above the min version.
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
ProtoV6ProviderFactories: protoV6ProviderFactories(),
|
||||
Steps: []resource.TestStep{{
|
||||
Config: testAccDataHelmTemplateKubeVersion(testResourceName, namespace, name, "1.2.3", "1.22.0"),
|
||||
Check: resource.ComposeAggregateTestCheckFunc(
|
||||
|
|
@ -249,7 +238,8 @@ func TestAccDataTemplate_kubeVersion(t *testing.T) {
|
|||
func testAccDataHelmTemplateConfigBasic(resource, ns, name, version string) string {
|
||||
return fmt.Sprintf(`
|
||||
data "helm_template" "%s" {
|
||||
show_only = [""]
|
||||
show_only = [""]
|
||||
|
||||
name = %q
|
||||
namespace = %q
|
||||
description = "Test"
|
||||
|
|
@ -257,15 +247,16 @@ func testAccDataHelmTemplateConfigBasic(resource, ns, name, version string) stri
|
|||
chart = "test-chart"
|
||||
version = %q
|
||||
|
||||
set {
|
||||
name = "foo"
|
||||
value = "bar"
|
||||
}
|
||||
|
||||
set {
|
||||
name = "fizz"
|
||||
value = 1337
|
||||
}
|
||||
set = [
|
||||
{
|
||||
name = "foo"
|
||||
value = "bar"
|
||||
},
|
||||
{
|
||||
name = "fizz"
|
||||
value = 1337
|
||||
}
|
||||
]
|
||||
}
|
||||
`, resource, name, ns, testRepositoryURL, version)
|
||||
}
|
||||
|
|
@ -280,15 +271,16 @@ func testAccDataHelmTemplateConfigTemplates(resource, ns, name, version string)
|
|||
chart = "test-chart"
|
||||
version = %q
|
||||
|
||||
set {
|
||||
name = "foo"
|
||||
value = "bar"
|
||||
}
|
||||
|
||||
set {
|
||||
name = "fizz"
|
||||
value = 1337
|
||||
}
|
||||
set = [
|
||||
{
|
||||
name = "foo"
|
||||
value = "bar"
|
||||
},
|
||||
{
|
||||
name = "fizz"
|
||||
value = 1337
|
||||
}
|
||||
]
|
||||
|
||||
show_only = [
|
||||
"templates/configmaps.yaml",
|
||||
|
|
@ -1,645 +0,0 @@
|
|||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package helm
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
|
||||
"helm.sh/helm/v3/pkg/action"
|
||||
"helm.sh/helm/v3/pkg/chart/loader"
|
||||
"helm.sh/helm/v3/pkg/chartutil"
|
||||
"helm.sh/helm/v3/pkg/release"
|
||||
"helm.sh/helm/v3/pkg/releaseutil"
|
||||
)
|
||||
|
||||
// defaultTemplateAttributes template attribute values
|
||||
var defaultTemplateAttributes = map[string]interface{}{
|
||||
"validate": false,
|
||||
"include_crds": false,
|
||||
"is_upgrade": false,
|
||||
"skip_tests": false,
|
||||
}
|
||||
|
||||
func dataTemplate() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
ReadContext: dataTemplateRead,
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
Description: "Release name.",
|
||||
},
|
||||
"repository": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Description: "Repository where to locate the requested chart. If is a URL the chart is installed without installing the repository.",
|
||||
},
|
||||
"repository_key_file": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Description: "The repositories cert key file",
|
||||
},
|
||||
"repository_cert_file": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Description: "The repositories cert file",
|
||||
},
|
||||
"repository_ca_file": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Description: "The Repositories CA File",
|
||||
},
|
||||
"repository_username": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Description: "Username for HTTP basic authentication",
|
||||
},
|
||||
"repository_password": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Sensitive: true,
|
||||
Description: "Password for HTTP basic authentication",
|
||||
},
|
||||
"pass_credentials": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Description: "Pass credentials to all domains. Defaults to `false`.",
|
||||
},
|
||||
"chart": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
Description: "Chart name to be installed. A path may be used.",
|
||||
},
|
||||
"version": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
Description: "Specify the exact chart version to install. If this is not specified, the latest version is installed.",
|
||||
},
|
||||
"devel": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Description: "Use chart development versions, too. Equivalent to version '>0.0.0-0'. If `version` is set, this is ignored",
|
||||
// Suppress changes of this attribute if `version` is set
|
||||
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
|
||||
return d.Get("version").(string) != ""
|
||||
},
|
||||
},
|
||||
"values": {
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
Description: "List of values in raw yaml format to pass to helm.",
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
},
|
||||
"set": {
|
||||
Type: schema.TypeSet,
|
||||
Optional: true,
|
||||
Description: "Custom values to be merged with the values.",
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
"value": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
"type": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
// TODO: use ValidateDiagFunc once an SDK v2 version of StringInSlice exists.
|
||||
// https://github.com/hashicorp/terraform-plugin-sdk/issues/534
|
||||
ValidateFunc: validation.StringInSlice([]string{
|
||||
"auto", "string",
|
||||
}, false),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"set_list": {
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
Description: "Custom list values to be merged with the values.",
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
"value": {
|
||||
Type: schema.TypeList,
|
||||
Required: true,
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"set_sensitive": {
|
||||
Type: schema.TypeSet,
|
||||
Optional: true,
|
||||
Description: "Custom sensitive values to be merged with the values.",
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
"value": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
Sensitive: true,
|
||||
},
|
||||
"type": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ValidateFunc: validation.StringInSlice([]string{
|
||||
"auto", "string",
|
||||
}, false),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"set_string": {
|
||||
Type: schema.TypeSet,
|
||||
Optional: true,
|
||||
Description: "Custom string values to be merged with the values.",
|
||||
Deprecated: "This argument is deprecated and will be removed in the next major" +
|
||||
" version. Use `set` argument with `type` equals to `string`",
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
"value": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"namespace": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
Description: "Namespace to install the release into. Defaults to `default`.",
|
||||
DefaultFunc: schema.EnvDefaultFunc("HELM_NAMESPACE", "default"),
|
||||
},
|
||||
"verify": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: defaultAttributes["verify"],
|
||||
Description: "Verify the package before installing it.Defaults to `false`.",
|
||||
},
|
||||
"keyring": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Default: os.ExpandEnv("$HOME/.gnupg/pubring.gpg"),
|
||||
Description: "Location of public keys used for verification. Used only if `verify` is true. Defaults to `/.gnupg/pubring.gpg` in the location set by `home`.",
|
||||
// Suppress changes of this attribute if `verify` is false
|
||||
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
|
||||
return !d.Get("verify").(bool)
|
||||
},
|
||||
},
|
||||
"timeout": {
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
Default: defaultAttributes["timeout"],
|
||||
Description: "Time in seconds to wait for any individual kubernetes operation. Defaults to `300` seconds.",
|
||||
},
|
||||
"disable_webhooks": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: defaultAttributes["disable_webhooks"],
|
||||
Description: "Prevent hooks from running.Defaults to `300` seconds.",
|
||||
},
|
||||
"reuse_values": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Description: "When upgrading, reuse the last release's values and merge in any overrides. If 'reset_values' is specified, this is ignored. Defaults to `false`. ",
|
||||
Default: defaultAttributes["reuse_values"],
|
||||
},
|
||||
"reset_values": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Description: "When upgrading, reset the values to the ones built into the chart.Defaults to `false`. ",
|
||||
Default: defaultAttributes["reset_values"],
|
||||
},
|
||||
"atomic": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: defaultAttributes["atomic"],
|
||||
Description: "If set, installation process purges chart on fail. The wait flag will be set automatically if atomic is used. Defaults to `false`.",
|
||||
},
|
||||
"skip_crds": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: defaultAttributes["skip_crds"],
|
||||
Description: "If set, no CRDs will be installed. By default, CRDs are installed if not already present. Defaults to `false`.",
|
||||
},
|
||||
"skip_tests": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: defaultAttributes["skip_tests"],
|
||||
Description: "If set, tests will not be rendered. By default, tests are rendered. Defaults to `false`.",
|
||||
},
|
||||
"render_subchart_notes": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: defaultAttributes["render_subchart_notes"],
|
||||
Description: "If set, render subchart notes along with the parent. Defaults to `true`.",
|
||||
},
|
||||
"disable_openapi_validation": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: defaultAttributes["disable_openapi_validation"],
|
||||
Description: "If set, the installation process will not validate rendered templates against the Kubernetes OpenAPI Schema.Defaults to `false`.",
|
||||
},
|
||||
"wait": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: defaultAttributes["wait"],
|
||||
Description: "Will wait until all resources are in a ready state before marking the release as successful.Defaults to `true`.",
|
||||
},
|
||||
"dependency_update": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: defaultAttributes["dependency_update"],
|
||||
Description: "Run helm dependency update before installing the chart. Defaults to `false`.",
|
||||
},
|
||||
"replace": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: defaultAttributes["replace"],
|
||||
Description: "Re-use the given name, even if that name is already used. This is unsafe in production. Defaults to `false`.",
|
||||
},
|
||||
"description": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Description: "Add a custom description",
|
||||
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
|
||||
return new == ""
|
||||
},
|
||||
},
|
||||
"create_namespace": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: defaultAttributes["create_namespace"],
|
||||
Description: "Create the namespace if it does not exist. Defaults to `false`.",
|
||||
},
|
||||
"postrender": {
|
||||
Type: schema.TypeList,
|
||||
MaxItems: 1,
|
||||
Optional: true,
|
||||
Description: "Postrender command configuration.",
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"binary_path": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
Description: "The command binary path.",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"api_versions": {
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
Description: "Kubernetes api versions used for Capabilities.APIVersions",
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
},
|
||||
"include_crds": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: defaultTemplateAttributes["include_crds"],
|
||||
Description: "Include CRDs in the templated output",
|
||||
},
|
||||
"is_upgrade": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: defaultTemplateAttributes["is_upgrade"],
|
||||
Description: "Set .Release.IsUpgrade instead of .Release.IsInstall",
|
||||
},
|
||||
"show_only": {
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
Description: "Only show manifests rendered from the given templates",
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
},
|
||||
"validate": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: defaultTemplateAttributes["validate"],
|
||||
Description: "Validate your manifests against the Kubernetes cluster you are currently pointing at. This is the same validation performed on an install",
|
||||
},
|
||||
"manifests": {
|
||||
Type: schema.TypeMap,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
Description: "Map of rendered chart templates indexed by the template name.",
|
||||
Elem: &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
},
|
||||
},
|
||||
"crds": {
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
Description: "List of rendered CRDs from the chart.",
|
||||
Elem: &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
},
|
||||
},
|
||||
"manifest": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
Description: "Concatenated rendered chart templates. This corresponds to the output of the `helm template` command.",
|
||||
},
|
||||
"notes": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
Description: "Rendered notes if the chart contains a `NOTES.txt`.",
|
||||
},
|
||||
"kube_version": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Description: "Kubernetes version used for Capabilities.KubeVersion",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func dataTemplateRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
||||
logID := fmt.Sprintf("[dataTemplateRead: %s]", d.Get("name").(string))
|
||||
debug("%s Started", logID)
|
||||
|
||||
m := meta.(*Meta)
|
||||
|
||||
name := d.Get("name").(string)
|
||||
n := d.Get("namespace").(string)
|
||||
|
||||
var apiVersions []string
|
||||
|
||||
if apiVersionsAttr, ok := d.GetOk("api_versions"); ok {
|
||||
apiVersionsValues := apiVersionsAttr.([]interface{})
|
||||
|
||||
for _, apiVersion := range apiVersionsValues {
|
||||
apiVersions = append(apiVersions, apiVersion.(string))
|
||||
}
|
||||
}
|
||||
|
||||
var showFiles []string
|
||||
|
||||
if showOnlyAttr, ok := d.GetOk("show_only"); ok {
|
||||
showOnlyAttrValue := showOnlyAttr.([]interface{})
|
||||
|
||||
for _, showFile := range showOnlyAttrValue {
|
||||
if s, ok := showFile.(string); ok && len(s) > 0 {
|
||||
showFiles = append(showFiles, s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
debug("%s Getting Config", logID)
|
||||
|
||||
actionConfig, err := m.GetHelmConfiguration(n)
|
||||
if err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
err = OCIRegistryLogin(actionConfig, d, m)
|
||||
if err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
client := action.NewInstall(actionConfig)
|
||||
|
||||
cpo, chartName, err := chartPathOptions(d, m, &client.ChartPathOptions)
|
||||
if err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
|
||||
debug("%s Getting chart", logID)
|
||||
c, path, err := getChart(d, m, chartName, cpo)
|
||||
if err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
|
||||
// check and update the chart's dependencies if needed
|
||||
updated, err := checkChartDependencies(d, c, path, m)
|
||||
if err != nil {
|
||||
return diag.FromErr(err)
|
||||
} else if updated {
|
||||
// load the chart again if its dependencies have been updated
|
||||
c, err = loader.Load(path)
|
||||
if err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
}
|
||||
|
||||
debug("%s Preparing for installation", logID)
|
||||
|
||||
values, err := getValues(d)
|
||||
if err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
|
||||
err = isChartInstallable(c)
|
||||
if err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
|
||||
client.ChartPathOptions = *cpo
|
||||
client.ClientOnly = false
|
||||
client.DryRun = true
|
||||
client.DisableHooks = d.Get("disable_webhooks").(bool)
|
||||
client.Wait = d.Get("wait").(bool)
|
||||
client.Devel = d.Get("devel").(bool)
|
||||
client.DependencyUpdate = d.Get("dependency_update").(bool)
|
||||
client.Timeout = time.Duration(d.Get("timeout").(int)) * time.Second
|
||||
client.Namespace = d.Get("namespace").(string)
|
||||
client.ReleaseName = d.Get("name").(string)
|
||||
client.GenerateName = false
|
||||
client.NameTemplate = ""
|
||||
client.OutputDir = ""
|
||||
client.Atomic = d.Get("atomic").(bool)
|
||||
client.SkipCRDs = d.Get("skip_crds").(bool)
|
||||
client.SubNotes = d.Get("render_subchart_notes").(bool)
|
||||
client.DisableOpenAPIValidation = d.Get("disable_openapi_validation").(bool)
|
||||
client.Replace = d.Get("replace").(bool)
|
||||
client.Description = d.Get("description").(string)
|
||||
client.CreateNamespace = d.Get("create_namespace").(bool)
|
||||
|
||||
if ver := d.Get("kube_version").(string); ver != "" {
|
||||
parsedVer, err := chartutil.ParseKubeVersion(ver)
|
||||
if err != nil {
|
||||
return diag.FromErr(fmt.Errorf("couldn't parse string %q into kube-version", ver))
|
||||
}
|
||||
client.KubeVersion = parsedVer
|
||||
}
|
||||
|
||||
// The following source has been adapted from the source of the helm template command
|
||||
// https://github.com/helm/helm/blob/v3.5.3/cmd/helm/template.go#L67
|
||||
client.DryRun = true
|
||||
// NOTE Do not set fixed release name as client.ReleaseName like in helm template command
|
||||
client.Replace = true // Skip the name check
|
||||
client.ClientOnly = !d.Get("validate").(bool)
|
||||
client.APIVersions = chartutil.VersionSet(apiVersions)
|
||||
client.IncludeCRDs = d.Get("include_crds").(bool)
|
||||
|
||||
skipTests := d.Get("skip_tests").(bool)
|
||||
|
||||
debug("%s Rendering Chart", logID)
|
||||
|
||||
rel, err := client.Run(c, values)
|
||||
|
||||
if err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
|
||||
var manifests bytes.Buffer
|
||||
|
||||
fmt.Fprintln(&manifests, strings.TrimSpace(rel.Manifest))
|
||||
|
||||
if !client.DisableHooks {
|
||||
for _, m := range rel.Hooks {
|
||||
if skipTests && isTestHook(m) {
|
||||
continue
|
||||
}
|
||||
|
||||
fmt.Fprintf(&manifests, "---\n# Source: %s\n%s\n", m.Path, m.Manifest)
|
||||
}
|
||||
}
|
||||
|
||||
// Difference to the implementation of helm template in newTemplateCmd:
|
||||
// Independent of templates, names of the charts templates are always resolved from the manifests
|
||||
// to be able to populate the keys in the manifests computed attribute.
|
||||
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 we have a list of files to render, then check that each of the
|
||||
// provided files exists in the chart.
|
||||
if len(showFiles) > 0 {
|
||||
for _, f := range showFiles {
|
||||
missing := true
|
||||
// Use linux-style filepath separators to unify user's input path
|
||||
f = filepath.ToSlash(f)
|
||||
for manifestKey, manifestName := range manifestNamesByKey {
|
||||
// manifest.Name is rendered using linux-style filepath separators on Windows as
|
||||
// well as macOS/linux.
|
||||
manifestPathSplit := strings.Split(manifestName, "/")
|
||||
// manifest.Path is connected using linux-style filepath separators on Windows as
|
||||
// well as macOS/linux
|
||||
manifestPath := strings.Join(manifestPathSplit, "/")
|
||||
|
||||
// if the filepath provided matches a manifest path in the
|
||||
// chart, render that manifest
|
||||
if matched, _ := filepath.Match(f, manifestPath); !matched {
|
||||
continue
|
||||
}
|
||||
manifestsToRender = append(manifestsToRender, manifestKey)
|
||||
missing = false
|
||||
}
|
||||
|
||||
if missing {
|
||||
return diag.Errorf("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)
|
||||
}
|
||||
|
||||
computedNotes := rel.Info.Notes
|
||||
|
||||
d.SetId(name)
|
||||
|
||||
err = d.Set("crds", chartCRDs)
|
||||
if err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
|
||||
err = d.Set("manifests", computedManifests)
|
||||
if err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
|
||||
err = d.Set("manifest", computedManifest.String())
|
||||
if err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
|
||||
err = d.Set("notes", computedNotes)
|
||||
if err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func isTestHook(h *release.Hook) bool {
|
||||
for _, e := range h.Events {
|
||||
if e == release.HookTest {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
232
helm/kubeconfig.go
Normal file
232
helm/kubeconfig.go
Normal file
|
|
@ -0,0 +1,232 @@
|
|||
// 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
|
@ -10,8 +10,6 @@ import (
|
|||
|
||||
"golang.org/x/crypto/sha3"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
|
@ -78,29 +76,19 @@ func convertYAMLManifestToJSON(manifest string) (string, error) {
|
|||
return string(b), nil
|
||||
}
|
||||
|
||||
// hashSensitiveValue creates a hash of a sensitive value and returns the string
|
||||
// "(sensitive value xxxxxxxx)". We have to do this because Terraform's sensitive
|
||||
// value feature can't reach inside a text string and would supress the entire
|
||||
// manifest if we marked it as sensitive. This allows us to redact the value while
|
||||
// still being able to surface that something has changed so it appears in the diff.
|
||||
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, d resourceGetter) string {
|
||||
// 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 _, v := range d.Get("set_sensitive").(*schema.Set).List() {
|
||||
vv := v.(map[string]interface{})
|
||||
|
||||
if sensitiveValue, ok := vv["value"].(string); ok {
|
||||
h := hashSensitiveValue(sensitiveValue)
|
||||
masked = strings.ReplaceAll(masked, sensitiveValue, h)
|
||||
}
|
||||
for originalValue := range sensitiveValues {
|
||||
hashedValue := hashSensitiveValue(originalValue)
|
||||
masked = strings.ReplaceAll(masked, originalValue, hashedValue)
|
||||
}
|
||||
|
||||
return masked
|
||||
|
|
|
|||
999
helm/provider.go
999
helm/provider.go
File diff suppressed because it is too large
Load diff
|
|
@ -16,10 +16,10 @@ import (
|
|||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
|
||||
|
||||
"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"
|
||||
|
|
@ -37,24 +37,32 @@ const (
|
|||
var (
|
||||
accTest bool
|
||||
testRepositoryURL string
|
||||
|
||||
testAccProviders map[string]*schema.Provider
|
||||
testAccProvider *schema.Provider
|
||||
client kubernetes.Interface = nil
|
||||
client kubernetes.Interface = nil
|
||||
testMeta *Meta
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
testAccProvider = Provider()
|
||||
testAccProviders = map[string]*schema.Provider{
|
||||
"helm": testAccProvider,
|
||||
var providerFactory map[string]func() (tfprotov6.ProviderServer, error)
|
||||
|
||||
func protoV6ProviderFactories() map[string]func() (tfprotov6.ProviderServer, error) {
|
||||
if len(providerFactory) != 0 {
|
||||
return providerFactory
|
||||
}
|
||||
|
||||
home, err := ioutil.TempDir(os.TempDir(), "helm")
|
||||
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)
|
||||
|
|
@ -99,16 +107,10 @@ func TestMain(m *testing.M) {
|
|||
// Build the test repository and start the server
|
||||
buildChartRepository()
|
||||
testRepositoryURL, stopRepositoryServer = startRepositoryServer()
|
||||
log.Println("Test repository is listening on", testRepositoryURL)
|
||||
}
|
||||
|
||||
ec := m.Run()
|
||||
|
||||
err = os.RemoveAll(home)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if accTest {
|
||||
stopRepositoryServer()
|
||||
cleanupChartRepository()
|
||||
|
|
@ -117,16 +119,38 @@ func TestMain(m *testing.M) {
|
|||
os.Exit(ec)
|
||||
}
|
||||
|
||||
// todo
|
||||
func TestProvider(t *testing.T) {
|
||||
if err := Provider().InternalValidate(); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
// buildChartRepository packages all the test charts and builds the repository index
|
||||
func buildChartRepository() {
|
||||
log.Println("Building chart repository...")
|
||||
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)
|
||||
}
|
||||
|
|
@ -138,7 +162,7 @@ func buildChartRepository() {
|
|||
|
||||
// package all the charts
|
||||
for _, c := range charts {
|
||||
cmd := exec.Command("helm", "--kubeconfig", os.Getenv("KUBE_CONFIG_PATH"), "package", "-u",
|
||||
cmd := exec.Command("helm", "package", "-u",
|
||||
filepath.Join(testChartsPath, c.Name()),
|
||||
"-d", testRepositoryDir)
|
||||
out, err := cmd.CombinedOutput()
|
||||
|
|
@ -151,7 +175,7 @@ func buildChartRepository() {
|
|||
}
|
||||
|
||||
// build the repository index
|
||||
cmd := exec.Command("helm", "--kubeconfig", os.Getenv("KUBE_CONFIG_PATH"), "repo", "index", testRepositoryDir)
|
||||
cmd := exec.Command("helm", "repo", "index", testRepositoryDir)
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
log.Println(string(out))
|
||||
|
|
@ -161,7 +185,6 @@ func buildChartRepository() {
|
|||
log.Println("Built chart repository index")
|
||||
}
|
||||
|
||||
// cleanupChartRepository cleans up the repository of test charts
|
||||
func cleanupChartRepository() {
|
||||
if _, err := os.Stat(testRepositoryDir); err == nil {
|
||||
err := os.RemoveAll(testRepositoryDir)
|
||||
|
|
@ -171,8 +194,6 @@ func cleanupChartRepository() {
|
|||
}
|
||||
}
|
||||
|
||||
// startRepositoryServer starts a helm repository in a goroutine using
|
||||
// a plain HTTP server on a random port and returns the URL
|
||||
func startRepositoryServer() (string, func()) {
|
||||
wg := sync.WaitGroup{}
|
||||
wg.Add(1)
|
||||
|
|
@ -182,8 +203,6 @@ func startRepositoryServer() (string, func()) {
|
|||
fileserver := http.Server{
|
||||
Handler: http.FileServer(http.Dir(testRepositoryDir)),
|
||||
}
|
||||
// NOTE we disable keep alive to prevent the server from chewing
|
||||
// up a lot of open connections as the test suite is run
|
||||
fileserver.SetKeepAlivesEnabled(false)
|
||||
shutdownFunc = func() { fileserver.Shutdown(context.Background()) }
|
||||
listener, err := net.Listen("tcp", ":0")
|
||||
|
|
@ -203,16 +222,54 @@ func startRepositoryServer() (string, func()) {
|
|||
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 !accTest {
|
||||
t.Skip("TF_ACC=1 not set")
|
||||
if testing.Short() {
|
||||
t.Skip("skipping acceptance tests in short mode")
|
||||
}
|
||||
http.DefaultClient.CloseIdleConnections()
|
||||
ctx := context.TODO()
|
||||
diags := testAccProvider.Configure(ctx, terraform.NewResourceConfigRaw(nil))
|
||||
|
||||
if diags.HasError() {
|
||||
t.Fatal(diags)
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -275,3 +332,19 @@ func deleteNamespace(t *testing.T, namespace string) {
|
|||
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,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
2070
helm/resource_helm_release.go
Normal file
2070
helm/resource_helm_release.go
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,207 +0,0 @@
|
|||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package helm
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||
"github.com/mitchellh/go-homedir"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/client-go/discovery"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/restmapper"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
|
||||
apimachineryschema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
memcached "k8s.io/client-go/discovery/cached/memory"
|
||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||
)
|
||||
|
||||
// KubeConfig is a RESTClientGetter interface implementation
|
||||
type KubeConfig struct {
|
||||
ClientConfig clientcmd.ClientConfig
|
||||
|
||||
Burst int
|
||||
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
// ToRESTConfig implemented interface method
|
||||
func (k *KubeConfig) ToRESTConfig() (*rest.Config, error) {
|
||||
config, err := k.ToRawKubeConfigLoader().ClientConfig()
|
||||
return config, err
|
||||
}
|
||||
|
||||
// ToDiscoveryClient implemented interface method
|
||||
func (k *KubeConfig) ToDiscoveryClient() (discovery.CachedDiscoveryInterface, error) {
|
||||
config, err := k.ToRESTConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// The more groups you have, the more discovery requests you need to make.
|
||||
// given 25 groups (our groups + a few custom resources) with one-ish version each, discovery needs to make 50 requests
|
||||
// double it just so we don't end up here again for a while. This config is only used for discovery.
|
||||
config.Burst = k.Burst
|
||||
|
||||
return memcached.NewMemCacheClient(discovery.NewDiscoveryClientForConfigOrDie(config)), nil
|
||||
}
|
||||
|
||||
// ToRESTMapper implemented interface method
|
||||
func (k *KubeConfig) ToRESTMapper() (meta.RESTMapper, error) {
|
||||
discoveryClient, err := k.ToDiscoveryClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mapper := restmapper.NewDeferredDiscoveryRESTMapper(discoveryClient)
|
||||
expander := restmapper.NewShortcutExpander(mapper, discoveryClient, nil)
|
||||
return expander, nil
|
||||
}
|
||||
|
||||
// ToRawKubeConfigLoader implemented interface method
|
||||
func (k *KubeConfig) ToRawKubeConfigLoader() clientcmd.ClientConfig {
|
||||
return k.ClientConfig
|
||||
}
|
||||
|
||||
func newKubeConfig(configData *schema.ResourceData, namespace *string) (*KubeConfig, error) {
|
||||
overrides := &clientcmd.ConfigOverrides{}
|
||||
loader := &clientcmd.ClientConfigLoadingRules{}
|
||||
|
||||
configPaths := []string{}
|
||||
|
||||
if v, ok := k8sGetOk(configData, "config_path"); ok && v != "" {
|
||||
configPaths = []string{v.(string)}
|
||||
} else if v, ok := k8sGetOk(configData, "config_paths"); ok {
|
||||
for _, p := range v.([]interface{}) {
|
||||
configPaths = append(configPaths, p.(string))
|
||||
}
|
||||
} else if v := os.Getenv("KUBE_CONFIG_PATHS"); v != "" {
|
||||
// NOTE we have to do this here because the schema
|
||||
// does not yet allow you to set a default for a TypeList
|
||||
configPaths = filepath.SplitList(v)
|
||||
}
|
||||
|
||||
if len(configPaths) > 0 {
|
||||
expandedPaths := []string{}
|
||||
for _, p := range configPaths {
|
||||
path, err := homedir.Expand(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] Using kubeconfig: %s", path)
|
||||
expandedPaths = append(expandedPaths, path)
|
||||
}
|
||||
|
||||
if len(expandedPaths) == 1 {
|
||||
loader.ExplicitPath = expandedPaths[0]
|
||||
} else {
|
||||
loader.Precedence = expandedPaths
|
||||
}
|
||||
|
||||
ctx, ctxOk := k8sGetOk(configData, "config_context")
|
||||
authInfo, authInfoOk := k8sGetOk(configData, "config_context_auth_info")
|
||||
cluster, clusterOk := k8sGetOk(configData, "config_context_cluster")
|
||||
if ctxOk || authInfoOk || clusterOk {
|
||||
if ctxOk {
|
||||
overrides.CurrentContext = ctx.(string)
|
||||
log.Printf("[DEBUG] Using custom current context: %q", overrides.CurrentContext)
|
||||
}
|
||||
|
||||
overrides.Context = clientcmdapi.Context{}
|
||||
if authInfoOk {
|
||||
overrides.Context.AuthInfo = authInfo.(string)
|
||||
}
|
||||
if clusterOk {
|
||||
overrides.Context.Cluster = cluster.(string)
|
||||
}
|
||||
log.Printf("[DEBUG] Using overidden context: %#v", overrides.Context)
|
||||
}
|
||||
}
|
||||
|
||||
// Overriding with static configuration
|
||||
if v, ok := k8sGetOk(configData, "insecure"); ok {
|
||||
overrides.ClusterInfo.InsecureSkipTLSVerify = v.(bool)
|
||||
}
|
||||
if v, ok := k8sGetOk(configData, "tls_server_name"); ok {
|
||||
overrides.ClusterInfo.TLSServerName = v.(string)
|
||||
}
|
||||
if v, ok := k8sGetOk(configData, "cluster_ca_certificate"); ok {
|
||||
overrides.ClusterInfo.CertificateAuthorityData = bytes.NewBufferString(v.(string)).Bytes()
|
||||
}
|
||||
if v, ok := k8sGetOk(configData, "client_certificate"); ok {
|
||||
overrides.AuthInfo.ClientCertificateData = bytes.NewBufferString(v.(string)).Bytes()
|
||||
}
|
||||
if v, ok := k8sGetOk(configData, "host"); ok {
|
||||
// Server has to be the complete address of the kubernetes cluster (scheme://hostname:port), not just the hostname,
|
||||
// because `overrides` are processed too late to be taken into account by `defaultServerUrlFor()`.
|
||||
// This basically replicates what defaultServerUrlFor() does with config but for overrides,
|
||||
// see https://github.com/kubernetes/client-go/blob/v12.0.0/rest/url_utils.go#L85-L87
|
||||
hasCA := len(overrides.ClusterInfo.CertificateAuthorityData) != 0
|
||||
hasCert := len(overrides.AuthInfo.ClientCertificateData) != 0
|
||||
defaultTLS := hasCA || hasCert || overrides.ClusterInfo.InsecureSkipTLSVerify
|
||||
host, _, err := rest.DefaultServerURL(v.(string), "", apimachineryschema.GroupVersion{}, defaultTLS)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
overrides.ClusterInfo.Server = host.String()
|
||||
}
|
||||
if v, ok := k8sGetOk(configData, "username"); ok {
|
||||
overrides.AuthInfo.Username = v.(string)
|
||||
}
|
||||
if v, ok := k8sGetOk(configData, "password"); ok {
|
||||
overrides.AuthInfo.Password = v.(string)
|
||||
}
|
||||
if v, ok := k8sGetOk(configData, "client_key"); ok {
|
||||
overrides.AuthInfo.ClientKeyData = bytes.NewBufferString(v.(string)).Bytes()
|
||||
}
|
||||
if v, ok := k8sGetOk(configData, "token"); ok {
|
||||
overrides.AuthInfo.Token = v.(string)
|
||||
}
|
||||
|
||||
if v, ok := k8sGetOk(configData, "proxy_url"); ok {
|
||||
overrides.ClusterDefaults.ProxyURL = v.(string)
|
||||
}
|
||||
|
||||
if v, ok := k8sGetOk(configData, "exec"); ok {
|
||||
exec := &clientcmdapi.ExecConfig{}
|
||||
if spec, ok := v.([]interface{})[0].(map[string]interface{}); ok {
|
||||
exec.InteractiveMode = clientcmdapi.IfAvailableExecInteractiveMode
|
||||
exec.APIVersion = spec["api_version"].(string)
|
||||
exec.Command = spec["command"].(string)
|
||||
exec.Args = expandStringSlice(spec["args"].([]interface{}))
|
||||
for kk, vv := range spec["env"].(map[string]interface{}) {
|
||||
exec.Env = append(exec.Env, clientcmdapi.ExecEnvVar{Name: kk, Value: vv.(string)})
|
||||
}
|
||||
} else {
|
||||
log.Printf("[ERROR] Failed to parse exec")
|
||||
return nil, fmt.Errorf("failed to parse exec")
|
||||
}
|
||||
overrides.AuthInfo.Exec = exec
|
||||
}
|
||||
|
||||
overrides.Context.Namespace = "default"
|
||||
|
||||
if namespace != nil {
|
||||
overrides.Context.Namespace = *namespace
|
||||
}
|
||||
burstLimit := configData.Get("burst_limit").(int)
|
||||
|
||||
client := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loader, overrides)
|
||||
if client == nil {
|
||||
log.Printf("[ERROR] Failed to initialize kubernetes config")
|
||||
return nil, nil
|
||||
}
|
||||
log.Printf("[INFO] Successfully initialized kubernetes config")
|
||||
|
||||
return &KubeConfig{ClientConfig: client, Burst: burstLimit}, nil
|
||||
}
|
||||
Binary file not shown.
8
helm/testdata/postrender.sh
vendored
8
helm/testdata/postrender.sh
vendored
|
|
@ -1,8 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
if [ $# -ne 2 ]
|
||||
then
|
||||
echo "Usage: $0 <arg1> <arg2>" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
|
@ -14,7 +14,7 @@ resource "kind_cluster" "demo" {
|
|||
}
|
||||
|
||||
provider "helm" {
|
||||
kubernetes {
|
||||
kubernetes = {
|
||||
host = kind_cluster.demo.endpoint
|
||||
cluster_ca_certificate = kind_cluster.demo.cluster_ca_certificate
|
||||
client_certificate = kind_cluster.demo.client_certificate
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@ package testing
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-go/tfprotov5"
|
||||
"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"
|
||||
|
|
@ -17,10 +18,8 @@ import (
|
|||
"github.com/hashicorp/terraform-provider-helm/helm"
|
||||
)
|
||||
|
||||
var providerFactory = map[string]func() (tfprotov5.ProviderServer, error){
|
||||
"helm": func() (tfprotov5.ProviderServer, error) {
|
||||
return helm.Provider().GRPCProvider(), nil
|
||||
},
|
||||
var providerFactory = map[string]func() (tfprotov6.ProviderServer, error){
|
||||
"helm": providerserver.NewProtocol6WithError(helm.New("version")()),
|
||||
}
|
||||
|
||||
func TestAccDeferredActions_basic(t *testing.T) {
|
||||
|
|
@ -34,7 +33,7 @@ func TestAccDeferredActions_basic(t *testing.T) {
|
|||
},
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
ProtoV5ProviderFactories: providerFactory,
|
||||
ProtoV6ProviderFactories: providerFactory,
|
||||
ConfigDirectory: func(tscr config.TestStepConfigRequest) string {
|
||||
return "config-da-basic"
|
||||
},
|
||||
|
|
@ -56,7 +55,7 @@ func TestAccDeferredActions_basic(t *testing.T) {
|
|||
},
|
||||
},
|
||||
{
|
||||
ProtoV5ProviderFactories: providerFactory,
|
||||
ProtoV6ProviderFactories: providerFactory,
|
||||
ConfigDirectory: func(tscr config.TestStepConfigRequest) string {
|
||||
return "config-da-basic"
|
||||
},
|
||||
|
|
|
|||
28
main.go
28
main.go
|
|
@ -6,30 +6,40 @@ package main
|
|||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"log"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/plugin"
|
||||
"github.com/hashicorp/terraform-plugin-framework/providerserver"
|
||||
"github.com/hashicorp/terraform-provider-helm/helm"
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
// Generate docs for website
|
||||
//go:generate go run github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs
|
||||
// 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)
|
||||
}
|
||||
serveOpts := &plugin.ServeOpts{
|
||||
ProviderFunc: helm.Provider,
|
||||
|
||||
opts := providerserver.ServeOpts{
|
||||
Address: "registry.terraform.io/hashicorp/helm",
|
||||
Debug: debug,
|
||||
ProtocolVersion: 6,
|
||||
}
|
||||
if debugFlag != nil && *debugFlag {
|
||||
plugin.Debug(context.Background(), "registry.terraform.io/hashicorp/helm", serveOpts)
|
||||
} else {
|
||||
plugin.Serve(serveOpts)
|
||||
|
||||
if *debugFlag {
|
||||
opts.Debug = true
|
||||
}
|
||||
|
||||
serveErr := providerserver.Serve(context.Background(), helm.New(Version), opts)
|
||||
if serveErr != nil {
|
||||
log.Fatal(serveErr.Error())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,4 +9,4 @@ function get_latest_version() {
|
|||
sort -V -r | head -1
|
||||
}
|
||||
|
||||
echo "matrix=[$(get_latest_version v0.12), $(get_latest_version v0.13), $(get_latest_version v0.14), $(get_latest_version v0.15), $(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)]" >> "$GITHUB_OUTPUT"
|
||||
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)]" >> "$GITHUB_OUTPUT"
|
||||
|
|
|
|||
Loading…
Reference in a new issue