diff --git a/.github/workflows/tflint.yml b/.github/workflows/tflint.yml index c157502..a58827f 100644 --- a/.github/workflows/tflint.yml +++ b/.github/workflows/tflint.yml @@ -1,8 +1,9 @@ name: Lint on: push: - branches: [ main ] + branches: [main] pull_request: + types: [opened, synchronize] jobs: tflint: @@ -13,26 +14,23 @@ jobs: os: [ubuntu-latest] steps: - - uses: actions/checkout@v3 - name: Checkout source code + - uses: actions/checkout@v4 + name: Checkout source code - - uses: actions/cache@v2 - name: Cache plugin dir - with: - path: ~/.tflint.d/plugins - key: ${{ matrix.os }}-tflint-${{ hashFiles('.tflint.hcl') }} + - 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@v1 - name: Setup TFLint - with: - tflint_version: v0.29.0 + - uses: terraform-linters/setup-tflint@v4 + name: Setup TFLint - - name: Show version - run: tflint --version + - name: Show version + run: tflint --version - - name: Init TFLint - run: tflint --init - - - name: Run TFLint - run: tflint -f compact + - name: Init TFLint + run: tflint --init + - name: Run TFLint + run: tflint -f compact diff --git a/.gitignore b/.gitignore index 73abd8d..696ec96 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,26 @@ +# Local .terraform directories +**/.terraform/* +.terraform.lock.hcl + +# .tfstate files +*.tfstate +*.tfstate.* + +# Crash log files +crash.log + +# IDE files .idea -/tmp -.vscode + +# Ignore any .tfvars files that are generated automatically for each Terraform run. Most +# .tfvars files are managed as part of configuration and so should be included in +# version control. +# +# example.tfvars + +# Ignore override files as they are usually used to override resources locally and so +# are not checked in +override.tf +override.tf.json +*_override.tf +*_override.tf.json diff --git a/.terraform-docs.yml b/.terraform-docs.yml new file mode 100644 index 0000000..9633cc5 --- /dev/null +++ b/.terraform-docs.yml @@ -0,0 +1,61 @@ +# Refs: https://github.com/terraform-docs/terraform-docs +formatter: "" # this is required + +version: "" + +header-from: main.tf +footer-from: "" + +recursive: + enabled: false + path: modules + +sections: + hide: [] + show: [] + +content: |- + {{ .Providers }} + + {{ .Requirements }} + + {{ .Inputs }} + + {{ .Outputs }} + + {{ .Resources }} + + {{ .Modules }} + + {{ .Footer }} + +output: + file: "" + mode: inject + template: |- + + {{ .Content }} + + +output-values: + enabled: false + from: "" + +sort: + enabled: true + by: name + +settings: + anchor: true + color: true + default: true + description: false + escape: true + hide-empty: false + html: true + indent: 2 + lockfile: true + read-comments: true + required: true + sensitive: true + type: true diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b5bc35..a8911b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ---- +## [3.0.0] - 2023-11-30 + +[Compare with previous version](https://github.com/sparkfabrik/terraform-sparkfabrik-prometheus-stack/compare/2.1.0...3.0.0) + +### Changed + +- refs platform/#2586: the `prometheus_stack_additional_values` and `prometheus_adapter_additional_values` variables are now lists of strings instead of a single string. This allows to pass multiple values to the chart. +- The kubernetes resources are now created using the `v1` version. +- The `template_file` data sources are replaced with `templatefile` function calls. + +### Added + +- The `versions.tf` file is now present in the module root directory. ## [2.1.0] - 2023-06-13 @@ -28,7 +40,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [1.1.0] - 2022-09-07 - ## [1.0.0] - 2022-02-11 ### Added diff --git a/Makefile b/Makefile index e8f6329..16aac4e 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,11 @@ -.PHONY: lint - lint: - docker run --rm -v $${PWD}:/data -t ghcr.io/terraform-linters/tflint + docker run --rm -v $${PWD}:/data -t ghcr.io/terraform-linters/tflint --var-file=/data/examples/test.tfvars + +tfsec: + docker run --rm -it -v "$$(pwd):/src" aquasec/tfsec /src --tfvars-file=/src/examples/test.tfvars + +generate-docs: lint + docker run --rm -u $$(id -u) \ + --volume "$(PWD):/terraform-docs" \ + -w /terraform-docs \ + quay.io/terraform-docs/terraform-docs:0.16.0 markdown table --config .terraform-docs.yml --output-file README.md --output-mode inject . diff --git a/README.md b/README.md index d14cdc7..9b6838e 100644 --- a/README.md +++ b/README.md @@ -66,8 +66,8 @@ module "kube_prometheus_stack" { ``` # Updgrade from 1.1.0 to 2.0.0 - -Upgrading to 2.0.0 from 1.1.0 will destroy and recreate the basic auth password, which is now different from Grafana admin password, + +Upgrading to 2.0.0 from 1.1.0 will destroy and recreate the basic auth password, which is now different from Grafana admin password, and will update the relative basic auth secret value. Upgrading to version 2.0.0 will also cause the destruction of the namespace, which now becomes an array. @@ -80,3 +80,94 @@ moved { to = moudle.MODULE_NAME.kubernetes_namespace.kube_prometheus_stack_namespace[0] } ``` + +# Upgrading from 2.X.Y to 3.0.0 + +Upgrading to `3.0.0` from `2.X.Y` will cause the destruction of the namespace and the basic auth secret. +You will need to use the `moved` resource, to move the namespace and the secret as shown below: + +```hcl +moved { + from = module.MODULE_NAME.kubernetes_namespace.kube_prometheus_stack_namespace[0] + to = moudle.MODULE_NAME.kubernetes_namespace_v1.kube_prometheus_stack_namespace[0] +} + +moved { + from = moudle.MODULE_NAME.kubernetes_secret.kube_prometheus_ingress_auth[0] + to = moudle.MODULE_NAME.kubernetes_secret_v1.kube_prometheus_ingress_auth[0] +} +``` + +Because of the change of the the `prometheus_stack_additional_values` and `prometheus_adapter_additional_values` variable types, from `string` to `list(string)`, you will need to change the way you pass the values to the module. If you are using a single value, you only need to wrap it in a list, as shown below: + +```hcl +prometheus_stack_additional_values = [templatefile( + "${path.module}/files/kube-prometheus-stack/values.yaml", + { + var01 = "value01" + var02 = "value02" + } +)] +``` + + +## Providers + +| Name | Version | +|------|---------| +| [helm](#provider\_helm) | >= 2.0 | +| [kubernetes](#provider\_kubernetes) | >= 2.23 | +| [random](#provider\_random) | >= 3.0 | + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.0 | +| [helm](#requirement\_helm) | >= 2.0 | +| [kubernetes](#requirement\_kubernetes) | >= 2.23 | +| [random](#requirement\_random) | >= 3.0 | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [create\_namespace](#input\_create\_namespace) | If true, the namespace will be created. If false, a namespace called as specified in you var.namespace variable, must exists in your Kubernetes cluster. | `bool` | `true` | no | +| [grafana\_admin\_user](#input\_grafana\_admin\_user) | Grafana basic auth username. If the variable is left empty, the basic auth will not be activated and you will use only the standard Grafana authentication. | `string` | `"admin"` | no | +| [grafana\_cluster\_issuer\_name](#input\_grafana\_cluster\_issuer\_name) | Resource representing the cluster issuer of cert-manager (used to deploy a TLS certificate for Grafana ingress). If the variable is left empty, the annotations will not be added. | `string` | `""` | no | +| [grafana\_ingress\_basic\_auth\_message](#input\_grafana\_ingress\_basic\_auth\_message) | Grafana basic auth message. | `string` | `"Authentication Required"` | no | +| [grafana\_ingress\_basic\_auth\_username](#input\_grafana\_ingress\_basic\_auth\_username) | Grafana basic auth username. If the variable is left empty, the basic auth will not be activated and you will use only the standard Grafana authentication. | `string` | `"admin"` | no | +| [grafana\_ingress\_class](#input\_grafana\_ingress\_class) | Ingress Class | `string` | `"nginx"` | no | +| [grafana\_ingress\_host](#input\_grafana\_ingress\_host) | Grafana ingress host. If the variable is left empty, the ingress will not be enabled. | `string` | `""` | no | +| [grafana\_tls\_secret\_name](#input\_grafana\_tls\_secret\_name) | TLS secret name. If the variable is left empty, the value will be filled by the module using default value. | `string` | `""` | no | +| [namespace](#input\_namespace) | This is the namespace used to install kube-prometheus-stack. | `string` | `"kube-prometheus-stack"` | no | +| [prometheus\_adapter\_additional\_values](#input\_prometheus\_adapter\_additional\_values) | Override values for prometheus-adapter release. If this variable is not an empy list, it will be merged with the other values. | `list(string)` | `[]` | no | +| [prometheus\_adapter\_chart\_version](#input\_prometheus\_adapter\_chart\_version) | Chart version Prometheus Adapter. If the variable is left empty, the Prometheus Adapter Chart will not be installed. | `string` | `""` | no | +| [prometheus\_stack\_additional\_values](#input\_prometheus\_stack\_additional\_values) | Override values for kube-prometheus-stack release. If this variable is not an empy list, it will be merged with the other values. | `list(string)` | `[]` | no | +| [prometheus\_stack\_chart\_version](#input\_prometheus\_stack\_chart\_version) | Chart version Prometheus-stack. | `string` | n/a | yes | +| [regcred](#input\_regcred) | Name of the secret of the docker credentials. | `string` | n/a | yes | + +## Outputs + +| Name | Description | +|------|-------------| +| [grafana\_admin\_password](#output\_grafana\_admin\_password) | Grafana administrator password | +| [grafana\_admin\_user](#output\_grafana\_admin\_user) | Grafana administrator username | + +## Resources + +| Name | Type | +|------|------| +| [helm_release.kube_prometheus_stack](https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release) | resource | +| [helm_release.prometheus_adapter](https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release) | resource | +| [kubernetes_namespace_v1.kube_prometheus_stack_namespace](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/namespace_v1) | resource | +| [kubernetes_secret_v1.kube_prometheus_ingress_auth](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/secret_v1) | resource | +| [random_password.basic_auth_password](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/password) | resource | +| [random_password.grafana_admin_password](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/password) | resource | + +## Modules + +No modules. + + + diff --git a/examples/main.tf b/examples/main.tf index 93c9a77..f413959 100644 --- a/examples/main.tf +++ b/examples/main.tf @@ -1,15 +1,15 @@ locals { prometheus_stack_additional_values = yamlencode({ - commonLabels: { - label1: "this-is-my-first-label" - label2: "this-is-my-second-label" + commonLabels : { + label1 : "this-is-my-first-label" + label2 : "this-is-my-second-label" } }) prometheus_adapter_additional_values = yamlencode({ - resources: { - requests: { - cpu: "10m", - memory: "32Mi" + resources : { + requests : { + cpu : "10m", + memory : "32Mi" } } }) @@ -18,16 +18,16 @@ locals { module "kube_prometheus_stack" { source = "sparkfabrik/terraform-sparkfabrik-prometheus-stack" - prometheus_stack_chart_version = var.prometheus_stack_chart_version - prometheus_adapter_chart_version = var.prometheus_adapter_chart_version - namespace = var.namespace - regcred = var.regcred - grafana_ingress_host = var.grafana_ingress_host - grafana_ingress_class = var.grafana_ingress_class - grafana_cluster_issuer_name = var.grafana_cluster_issuer_name - grafana_tls_secret_name = var.grafana_tls_secret_name - grafana_ingress_basic_auth_username = var.grafana_ingress_basic_auth_username - grafana_ingress_basic_auth_message = var.grafana_ingress_basic_auth_message - prometheus_stack_additional_values = local.prometheus_stack_additional_values - prometheus_adapter_additional_values = local.prometheus_adapter_additional_values + prometheus_stack_chart_version = var.prometheus_stack_chart_version + prometheus_adapter_chart_version = var.prometheus_adapter_chart_version + namespace = var.namespace + regcred = var.regcred + grafana_ingress_host = var.grafana_ingress_host + grafana_ingress_class = var.grafana_ingress_class + grafana_cluster_issuer_name = var.grafana_cluster_issuer_name + grafana_tls_secret_name = var.grafana_tls_secret_name + grafana_ingress_basic_auth_username = var.grafana_ingress_basic_auth_username + grafana_ingress_basic_auth_message = var.grafana_ingress_basic_auth_message + prometheus_stack_additional_values = [local.prometheus_stack_additional_values] + prometheus_adapter_additional_values = [local.prometheus_adapter_additional_values] } diff --git a/examples/test.tfvars b/examples/test.tfvars index 0a0dc0c..0e2b201 100644 --- a/examples/test.tfvars +++ b/examples/test.tfvars @@ -1,10 +1,10 @@ -prometheus_stack_chart_version = "31.0.0" -prometheus_adapter_chart_version = "3.0.1" -namespace = "kube-prometheus-stack" -regcred = "regcred-secret" -grafana_ingress_host = "monitoring.example.com" -grafana_ingress_class = "nginx" -grafana_cluster_issuer_name = "prod-certmanager" -grafana_tls_secret_name = "monitoring-tls" +prometheus_stack_chart_version = "31.0.0" +prometheus_adapter_chart_version = "3.0.1" +namespace = "kube-prometheus-stack" +regcred = "regcred-secret" +grafana_ingress_host = "monitoring.example.com" +grafana_ingress_class = "nginx" +grafana_cluster_issuer_name = "prod-certmanager" +grafana_tls_secret_name = "monitoring-tls" grafana_ingress_basic_auth_username = "admin" -grafana_ingress_basic_auth_message = "Grafana basic auth" +grafana_ingress_basic_auth_message = "Grafana basic auth" diff --git a/main.tf b/main.tf index 2c4d913..6269560 100644 --- a/main.tf +++ b/main.tf @@ -1,11 +1,46 @@ locals { - app_name = "kube-prometheus-stack" - adapter_app_name = "prometheus-adapter" + app_name_stack = "kube-prometheus-stack" + app_name_adapter = "prometheus-adapter" prometheus_service_name = "kube-prometheus-stack-prometheus" - cert_manager_secret_name = trimspace(var.grafana_tls_secret_name) != "" ? var.grafana_tls_secret_name : join("-", [local.app_name, "certmanager-def.tls"]) + cert_manager_secret_name = trimspace(var.grafana_tls_secret_name) != "" ? var.grafana_tls_secret_name : join("-", [local.app_name_stack, "certmanager-def.tls"]) + + # Kubernetes Prometheus Stack values + base_kube_prometheus_stack = templatefile( + "${path.module}/values/kube-prometheus-stack.yml", + { + regcred = var.regcred + grafana_ingress_host = var.grafana_ingress_host + grafana_ingress_class = var.grafana_ingress_class + grafana_cluster_issuer_name = var.grafana_cluster_issuer_name + cert_manager_secret_name = local.cert_manager_secret_name + grafana_ingress_basic_auth_username = var.grafana_ingress_basic_auth_username + grafana_ingress_basic_auth_message = var.grafana_ingress_basic_auth_message + grafana_ingress_basic_auth_secret = trimspace(var.grafana_ingress_basic_auth_username) != "" ? "${var.namespace}/${kubernetes_secret_v1.kube_prometheus_ingress_auth[0].metadata[0].name}" : "" + } + ) + + kube_prometheus_stack_values = concat( + [ + local.base_kube_prometheus_stack + ], + var.prometheus_stack_additional_values + ) + # Prometheus Adapter values + base_prometheus_adapter = templatefile( + "${path.module}/values/prometheus-adapter.yml", + { + prometheus_internal_url = "${local.prometheus_service_name}.${var.namespace}.svc" + } + ) + prometheus_adapter_values = concat( + [ + local.base_prometheus_adapter + ], + var.prometheus_adapter_additional_values + ) } -resource "kubernetes_namespace" "kube_prometheus_stack_namespace" { +resource "kubernetes_namespace_v1" "kube_prometheus_stack_namespace" { count = var.create_namespace ? 1 : 0 metadata { name = var.namespace @@ -27,14 +62,14 @@ resource "random_password" "grafana_admin_password" { override_special = "_%@" } -resource "kubernetes_secret" "kube_prometheus_ingress_auth" { +resource "kubernetes_secret_v1" "kube_prometheus_ingress_auth" { count = trimspace(var.grafana_ingress_basic_auth_username) != "" ? 1 : 0 metadata { - name = "${local.app_name}-basic-auth" - namespace = var.namespace + name = "${local.app_name_stack}-basic-auth" + namespace = kubernetes_namespace_v1.kube_prometheus_stack_namespace[0].metadata[0].name labels = { - app = local.app_name + app = local.app_name_stack } } data = { @@ -43,34 +78,17 @@ resource "kubernetes_secret" "kube_prometheus_ingress_auth" { auth = "${var.grafana_ingress_basic_auth_username}:{PLAIN}${random_password.basic_auth_password.result}" } - depends_on = [resource.kubernetes_namespace.kube_prometheus_stack_namespace] -} - -data "template_file" "kube_prometheus_stack_config" { - template = templatefile( - "${path.module}/values/kube-prometheus-stack.yml", - { - regcred = var.regcred - grafana_ingress_host = var.grafana_ingress_host - grafana_ingress_class = var.grafana_ingress_class - grafana_cluster_issuer_name = var.grafana_cluster_issuer_name - cert_manager_secret_name = local.cert_manager_secret_name - grafana_ingress_basic_auth_username = var.grafana_ingress_basic_auth_username - grafana_ingress_basic_auth_message = var.grafana_ingress_basic_auth_message - grafana_ingress_basic_auth_secret = trimspace(var.grafana_ingress_basic_auth_username) != "" ? "${var.namespace}/${kubernetes_secret.kube_prometheus_ingress_auth[0].metadata[0].name}" : "" - } - ) + type = "kubernetes.io/basic-auth" } resource "helm_release" "kube_prometheus_stack" { - name = local.app_name - repository = "https://prometheus-community.github.io/helm-charts" - chart = "kube-prometheus-stack" - namespace = var.namespace - version = var.prometheus_stack_chart_version - create_namespace = true + name = local.app_name_stack + repository = "https://prometheus-community.github.io/helm-charts" + chart = "kube-prometheus-stack" + namespace = kubernetes_namespace_v1.kube_prometheus_stack_namespace[0].metadata[0].name + version = var.prometheus_stack_chart_version - values = trimspace(var.prometheus_stack_additional_values) != "" ? [data.template_file.kube_prometheus_stack_config.template, var.prometheus_stack_additional_values] : [data.template_file.kube_prometheus_stack_config.template] + values = local.kube_prometheus_stack_values set_sensitive { name = "grafana.adminPassword" @@ -82,26 +100,17 @@ resource "helm_release" "kube_prometheus_stack" { value = var.grafana_admin_user } - depends_on = [resource.kubernetes_secret.kube_prometheus_ingress_auth] -} - -data "template_file" "prometheus_adapter_config" { - template = templatefile( - "${path.module}/values/prometheus-adapter.yml", - { - prometheus_internal_url = "${local.prometheus_service_name}.${var.namespace}.svc" - } - ) + depends_on = [kubernetes_secret_v1.kube_prometheus_ingress_auth] } resource "helm_release" "prometheus_adapter" { count = trimspace(var.prometheus_adapter_chart_version) != "" ? 1 : 0 - name = local.adapter_app_name + name = local.app_name_adapter repository = "https://prometheus-community.github.io/helm-charts" chart = "prometheus-adapter" - namespace = var.namespace + namespace = kubernetes_namespace_v1.kube_prometheus_stack_namespace[0].metadata[0].name version = var.prometheus_adapter_chart_version - values = trimspace(var.prometheus_adapter_additional_values) != "" ? [data.template_file.prometheus_adapter_config.template, var.prometheus_adapter_additional_values] : [data.template_file.prometheus_adapter_config.template] + values = local.prometheus_adapter_values } diff --git a/variables.tf b/variables.tf index a030b4c..e4698b0 100644 --- a/variables.tf +++ b/variables.tf @@ -1,81 +1,81 @@ variable "prometheus_stack_chart_version" { - type = string + type = string description = "Chart version Prometheus-stack." } variable "prometheus_adapter_chart_version" { - type = string + type = string description = "Chart version Prometheus Adapter. If the variable is left empty, the Prometheus Adapter Chart will not be installed." - default = "" + default = "" } variable "create_namespace" { - type = bool + type = bool description = "If true, the namespace will be created. If false, a namespace called as specified in you var.namespace variable, must exists in your Kubernetes cluster." - default = true + default = true } variable "namespace" { - type = string + type = string description = "This is the namespace used to install kube-prometheus-stack." - default = "kube-prometheus-stack" + default = "kube-prometheus-stack" } variable "regcred" { - type = string + type = string description = "Name of the secret of the docker credentials." } variable "grafana_ingress_host" { - type = string + type = string description = "Grafana ingress host. If the variable is left empty, the ingress will not be enabled." - default = "" + default = "" } variable "grafana_ingress_class" { - type = string + type = string description = "Ingress Class" - default = "nginx" + default = "nginx" } variable "grafana_cluster_issuer_name" { - type = string + type = string description = "Resource representing the cluster issuer of cert-manager (used to deploy a TLS certificate for Grafana ingress). If the variable is left empty, the annotations will not be added." - default = "" + default = "" } variable "grafana_tls_secret_name" { - type = string + type = string description = "TLS secret name. If the variable is left empty, the value will be filled by the module using default value." - default = "" + default = "" } variable "grafana_ingress_basic_auth_username" { - type = string + type = string description = "Grafana basic auth username. If the variable is left empty, the basic auth will not be activated and you will use only the standard Grafana authentication." - default = "admin" + default = "admin" } variable "grafana_admin_user" { - type = string + type = string description = "Grafana basic auth username. If the variable is left empty, the basic auth will not be activated and you will use only the standard Grafana authentication." - default = "admin" + default = "admin" } variable "grafana_ingress_basic_auth_message" { - type = string + type = string description = "Grafana basic auth message." - default = "Authentication Required" + default = "Authentication Required" } variable "prometheus_stack_additional_values" { - type = string - description = "Override values for kube-prometheus-stack release. If this variable is configured, its content will be merged with the other values." - default = "" + type = list(string) + description = "Override values for kube-prometheus-stack release. If this variable is not an empy list, it will be merged with the other values." + default = [] } variable "prometheus_adapter_additional_values" { - type = string - description = "Override values for prometheus-adapter release. If this variable is configured, its content will be merged with the other values." - default = "" + type = list(string) + description = "Override values for prometheus-adapter release. If this variable is not an empy list, it will be merged with the other values." + default = [] } diff --git a/versions.tf b/versions.tf new file mode 100644 index 0000000..9340ef6 --- /dev/null +++ b/versions.tf @@ -0,0 +1,18 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + kubernetes = { + source = "hashicorp/kubernetes" + version = ">= 2.23" + } + helm = { + source = "hashicorp/helm" + version = ">= 2.0" + } + random = { + source = "hashicorp/random" + version = ">= 3.0" + } + } +}