diff --git a/.github/workflows/lint_clean.yaml b/.github/workflows/lint_clean.yaml new file mode 100644 index 0000000..a15b694 --- /dev/null +++ b/.github/workflows/lint_clean.yaml @@ -0,0 +1,18 @@ +name: 'Lint and Clean' + +on: + pull_request: + + push: + branches: + - main + +jobs: + fmt: + name: Terraform FMT + runs-on: ubuntu-latest + container: + image: hashicorp/terraform:latest + steps: + - uses: actions/checkout@v2 + - run: terraform fmt --recursive --diff -check=true \ No newline at end of file diff --git a/.github/workflows/terraform-docs.yaml b/.github/workflows/terraform-docs.yaml new file mode 100644 index 0000000..5c766b9 --- /dev/null +++ b/.github/workflows/terraform-docs.yaml @@ -0,0 +1,16 @@ +name: Generate terraform docs +on: + - pull_request + +jobs: + docs: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + ref: ${{ github.event.pull_request.head.ref }} + + - name: Render terraform docs and push changes back to PR + uses: terraform-docs/gh-actions@main + with: + git-push: "true" \ No newline at end of file diff --git a/.github/workflows/tflint.yaml b/.github/workflows/tflint.yaml new file mode 100644 index 0000000..42620cf --- /dev/null +++ b/.github/workflows/tflint.yaml @@ -0,0 +1,40 @@ +name: Lint +on: + pull_request: + branches: + - main + +jobs: + tflint: + runs-on: ${{ matrix.os }} + + strategy: + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + + steps: + - uses: actions/checkout@v3 + name: Checkout source code + + - uses: actions/cache@v3 + name: Cache plugin dir + with: + path: ~/.tflint.d/plugins + key: ${{ matrix.os }}-tflint-${{ hashFiles('.tflint.hcl') }} + + - uses: terraform-linters/setup-tflint@v3 + name: Setup TFLint + with: + tflint_version: v0.47.0 + + - name: Show version + run: tflint --version + + - name: Init TFLint + run: tflint --init + env: + # https://github.com/terraform-linters/tflint/blob/master/docs/user-guide/plugins.md#avoiding-rate-limiting + GITHUB_TOKEN: ${{ github.token }} + + - name: Run TFLint + run: tflint --minimum-failure-severity=error -f compact \ No newline at end of file diff --git a/README.md b/README.md index 1fd5a2f..1db1466 100644 --- a/README.md +++ b/README.md @@ -1 +1,99 @@ -# terraform-kubernetes-helm \ No newline at end of file +# Terraform Helm Chart Installation Module + +This Terraform module provides a flexible way to install Helm charts on a Kubernetes cluster. It uses a `null_resource` with a `local-exec` provisioner to run Helm commands, allowing for dynamic chart installation and updates. + +## Features + +- Installs or upgrades Helm charts +- Supports custom repositories +- Allows for namespace creation +- Configurable chart values +- Uses temporary files for secure kubeconfig and values handling + +## Requirements + +- Terraform >= 0.13 +- Helm (installed on the machine running Terraform) +- Access to a Kubernetes cluster + +## Input Variables + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| `chart_name` | Name of the Helm chart to install | `string` | n/a | yes | +| `chart_version` | Version of the Helm chart to install | `string` | n/a | yes | +| `release_name` | Name for the Helm release | `string` | n/a | yes | +| `namespace` | Kubernetes namespace to install the release into | `string` | n/a | yes | +| `create_namespace` | Whether to create the namespace if it doesn't exist | `bool` | `false` | no | +| `repo_name` | Name of the Helm repository | `string` | n/a | yes | +| `repo_url` | URL of the Helm repository | `string` | n/a | yes | +| `cluster_ca_certificate` | Base64 encoded CA certificate of the Kubernetes cluster | `string` | n/a | yes | +| `cluster_endpoint` | Endpoint of the Kubernetes cluster | `string` | n/a | yes | +| `token` | Authentication token for the Kubernetes cluster | `string` | n/a | yes | +| `set_values` | Map of values to pass to the Helm chart | `any` | `{}` | no | + +## How it works + +1. The module creates temporary files for the kubeconfig and chart values. +2. It then uses these temporary files to run Helm commands via a `local-exec` provisioner. +3. The Helm repository is added and updated. +4. The chart is installed or upgraded using the provided values. +5. Temporary files are cleaned up after the Helm command execution. + +## Notes + +- Ensure that the machine running Terraform has Helm installed and configured. +- The module uses a `null_resource` with a `local-exec` provisioner, which means the Helm commands are executed on the machine running Terraform, not within Terraform itself. +- Be cautious with sensitive information in `set_values`. While this module uses temporary files, it's generally a good practice to manage secrets separately. + +## Contributing + +Contributions to improve this module are welcome. Please submit a pull request or open an issue on the repository. + +## License + +This module is released under the MIT License. See the [LICENSE](./LICENSE) file for more details. + + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.13 | + +## Providers + +| Name | Version | +|------|---------| +| [null](#provider\_null) | n/a | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [null_resource.helm_install](https://registry.terraform.io/providers/hashicorp/null/latest/docs/resources/resource) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [chart\_name](#input\_chart\_name) | Name of the chart | `string` | n/a | yes | +| [chart\_version](#input\_chart\_version) | Version of the chart | `string` | n/a | yes | +| [cluster\_ca\_certificate](#input\_cluster\_ca\_certificate) | CA certificate of the cluster | `string` | n/a | yes | +| [cluster\_endpoint](#input\_cluster\_endpoint) | Endpoint of the cluster | `string` | n/a | yes | +| [create\_namespace](#input\_create\_namespace) | Create the namespace if it does not exist. Defaults to false | `bool` | `false` | no | +| [namespace](#input\_namespace) | Namespace to install the chart | `string` | n/a | yes | +| [release\_name](#input\_release\_name) | Release name of the chart | `string` | n/a | yes | +| [repo\_name](#input\_repo\_name) | Name of the Helm repository | `string` | n/a | yes | +| [repo\_url](#input\_repo\_url) | URL of the Helm repository | `string` | n/a | yes | +| [set\_values](#input\_set\_values) | A map of values to pass to the Helm chart | `any` | `{}` | no | +| [token](#input\_token) | Token to authenticate with the cluster | `string` | n/a | yes | + +## Outputs + +No outputs. + \ No newline at end of file diff --git a/main.tf b/main.tf new file mode 100644 index 0000000..6ffb5f7 --- /dev/null +++ b/main.tf @@ -0,0 +1,72 @@ +resource "null_resource" "helm_install" { + triggers = { + chart_name = var.chart_name + chart_version = var.chart_version + release_name = var.release_name + namespace = var.namespace + always_run = "${timestamp()}" + } + + provisioner "local-exec" { + command = <<-EOT + echo "Starting Helm install process..." + + # Create a temporary kubeconfig file + KUBECONFIG_FILE=$(mktemp) + echo "Created temporary KUBECONFIG file: $KUBECONFIG_FILE" + + # Write the kubeconfig content + cat < $KUBECONFIG_FILE + apiVersion: v1 + kind: Config + clusters: + - cluster: + server: ${var.cluster_endpoint} + certificate-authority-data: ${var.cluster_ca_certificate} + name: kubernetes + contexts: + - context: + cluster: kubernetes + user: aws + name: aws + current-context: aws + users: + - name: aws + user: + token: ${var.token} + EOF + echo "Wrote kubeconfig content to $KUBECONFIG_FILE" + + # Create a temporary values file + VALUES_FILE=$(mktemp) + echo "Created temporary values file: $VALUES_FILE" + + # Write the values content + cat < $VALUES_FILE + ${jsonencode(var.set_values)} + EOF + echo "Wrote values content to $VALUES_FILE" + + # Run Helm command with the temporary kubeconfig and values file + echo "Running Helm command..." + KUBECONFIG=$KUBECONFIG_FILE helm repo add ${var.repo_name} ${var.repo_url} + KUBECONFIG=$KUBECONFIG_FILE helm repo update + KUBECONFIG=$KUBECONFIG_FILE helm upgrade --install ${var.release_name} ${var.repo_name}/${var.chart_name} \ + --version ${var.chart_version} \ + --namespace ${var.namespace} \ + ${var.create_namespace ? "--create-namespace" : ""} \ + -f $VALUES_FILE \ + --debug + + HELM_EXIT_CODE=$? + echo "Helm command exited with code: $HELM_EXIT_CODE" + + # Clean up the temporary files + rm $KUBECONFIG_FILE + rm $VALUES_FILE + echo "Removed temporary KUBECONFIG and values files" + + exit $HELM_EXIT_CODE + EOT + } +} diff --git a/variables.tf b/variables.tf new file mode 100644 index 0000000..ab665d6 --- /dev/null +++ b/variables.tf @@ -0,0 +1,56 @@ +variable "chart_name" { + type = string + description = "Name of the chart" +} + +variable "chart_version" { + type = string + description = "Version of the chart" +} + +variable "release_name" { + type = string + description = "Release name of the chart" +} + +variable "namespace" { + type = string + description = "Namespace to install the chart" +} + +variable "create_namespace" { + type = bool + default = false + description = "Create the namespace if it does not exist. Defaults to false" +} + +variable "repo_name" { + type = string + description = "Name of the Helm repository" +} + +variable "repo_url" { + type = string + description = "URL of the Helm repository" +} + +variable "cluster_ca_certificate" { + type = string + description = "CA certificate of the cluster" +} + +variable "cluster_endpoint" { + type = string + description = "Endpoint of the cluster" +} + +variable "token" { + type = string + description = "Token to authenticate with the cluster" +} + +variable "set_values" { + type = any + description = "A map of values to pass to the Helm chart" + default = {} +} \ No newline at end of file diff --git a/versions.tf b/versions.tf new file mode 100644 index 0000000..ab85202 --- /dev/null +++ b/versions.tf @@ -0,0 +1,4 @@ +terraform { + required_version = ">= 0.13" + # Remove the required_providers block if you're not using any providers in this module +}