From 3a58fa43c951e02ebfeefa90ef19ab7d3c48d455 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sinclert=20P=C3=A9rez?= Date: Mon, 29 Sep 2025 14:32:29 +0200 Subject: [PATCH 1/4] Tweak terraform module --- terraform/main.tf | 12 ++++------ terraform/outputs.tf | 15 +++++++----- terraform/variables.tf | 54 +++++++++++++++++++----------------------- terraform/versions.tf | 3 ++- 4 files changed, 40 insertions(+), 44 deletions(-) diff --git a/terraform/main.tf b/terraform/main.tf index 1879af188b..5a040b859e 100644 --- a/terraform/main.tf +++ b/terraform/main.tf @@ -1,21 +1,19 @@ -resource "juju_application" "k8s_mysql" { +resource "juju_application" "mysql_server" { name = var.app_name - model = var.juju_model_name - trust = true + model = var.model_name charm { name = "mysql-k8s" + base = var.base channel = var.channel revision = var.revision - base = var.base } storage_directives = { database = var.storage_size } - units = var.units - constraints = var.constraints config = var.config - resources = var.resources + constraints = var.constraints + units = var.units } diff --git a/terraform/outputs.tf b/terraform/outputs.tf index e2ce666aae..838cbbf0e9 100644 --- a/terraform/outputs.tf +++ b/terraform/outputs.tf @@ -1,20 +1,23 @@ -output "application_name" { - value = juju_application.k8s_mysql.name +output "app_name" { + description = "Name of the MySQL Server K8s application" + value = juju_application.mysql_server.name } - output "provides" { + description = "Map of all the provided endpoints" value = { - database = "database", - metrics_endpoint = "metrics-endpoint", + database = "database" grafana_dashboard = "grafana-dashboard" + metrics_endpoint = "metrics-endpoint" } } output "requires" { + description = "Map of all the required endpoints" value = { - logging = "logging" certificates = "certificates" s3_parameters = "s3-parameters" + logging = "logging" + tracing = "tracing" } } diff --git a/terraform/variables.tf b/terraform/variables.tf index 6fdabfe80a..d8500a3050 100644 --- a/terraform/variables.tf +++ b/terraform/variables.tf @@ -1,42 +1,48 @@ -variable "juju_model_name" { - description = "Juju model name" +variable "model_name" { + description = "Juju model to deploy to" type = string } variable "app_name" { - description = "Name of the application in the Juju model." + description = "Name of the juju application" type = string default = "mysql-k8s" } +variable "base" { + description = "Application base" + type = string + default = "ubuntu@22.04" +} + +variable "config" { + description = "Application configuration. Details at https://charmhub.io/mysql-k8s/configurations" + type = map(string) + default = {} +} + +variable "constraints" { + description = "Juju constraints for the application" + type = string + default = "arch=amd64" +} + variable "channel" { - description = "Charm channel to use when deploying" + description = "Charm channel to deploy from" type = string default = "8.0/stable" } variable "revision" { - description = "Revision number to deploy charm" + description = "Charm revision to deploy" type = number default = null } -variable "base" { - description = "Application base" - type = string - default = "ubuntu@22.04" -} - variable "units" { description = "Number of units to deploy" type = number - default = 1 -} - -variable "constraints" { - description = "Juju constraints to apply for this application." - type = string - default = "arch=amd64" + default = 3 } variable "storage_size" { @@ -44,15 +50,3 @@ variable "storage_size" { type = string default = "10G" } - -variable "config" { - description = "Application configuration. Details at https://charmhub.io/mysql-k8s/configurations" - type = map(string) - default = {} -} - -variable "resources" { - description = "Resources to use with the application" - type = map(string) - default = {} -} diff --git a/terraform/versions.tf b/terraform/versions.tf index 3586261576..846960ec80 100644 --- a/terraform/versions.tf +++ b/terraform/versions.tf @@ -1,9 +1,10 @@ terraform { required_version = ">= 1.6.6" + required_providers { juju = { source = "juju/juju" - version = ">= 0.14.0" + version = ">= 0.20.0, < 1.0.0" } } } From 2858691f93945605fa4205fd8409e3e94779b1c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sinclert=20P=C3=A9rez?= Date: Mon, 29 Sep 2025 14:32:40 +0200 Subject: [PATCH 2/4] Define terraform command --- .gitignore | 4 ++++ tox.ini | 11 +++++++++++ 2 files changed, 15 insertions(+) diff --git a/.gitignore b/.gitignore index f2fd5aee31..ec43f17710 100644 --- a/.gitignore +++ b/.gitignore @@ -145,4 +145,8 @@ build # local pyright settings pyrightconfig.json +# Terraform +.terraform +.terraform.lock.hcl + wt*/ diff --git a/tox.ini b/tox.ini index 6d7bbbc67f..3d11ae4b3e 100644 --- a/tox.ini +++ b/tox.ini @@ -9,6 +9,7 @@ env_list = lint, unit src_path = "{tox_root}/src" tests_path = "{tox_root}/tests" scripts_path = "{tox_root}/scripts" +terraform_path = "{tox_root}/terraform" all_path = {[vars]src_path} {[vars]tests_path} {[vars]scripts_path} [testenv] @@ -41,6 +42,16 @@ commands = poetry run ruff format --check --diff {[vars]all_path} find {[vars]all_path} -type f \( -name "*.sh" -o -name "*.bash" \) -exec poetry run shellcheck --color=always \{\} + +[testenv:lint-terraform] +description = Check code against Terraform style standards +allowlist_externals = + {[testenv]allowlist_externals} + terraform +commands = + terraform fmt -check -diff -recursive {[vars]terraform_path} + terraform -chdir={[vars]terraform_path} init -backend=false + terraform -chdir={[vars]terraform_path} validate + [testenv:unit] description = Run unit tests commands_pre = From 4096dd3a10981238aa7d6d3d356e26ae95f9756b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sinclert=20P=C3=A9rez?= Date: Mon, 29 Sep 2025 14:32:48 +0200 Subject: [PATCH 3/4] Extend CI with terraform linting --- .github/workflows/ci.yaml | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 3602362312..1cc391442a 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -24,7 +24,22 @@ on: jobs: lint: name: Lint - uses: canonical/data-platform-workflows/.github/workflows/lint.yaml@v32.2.1 + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - name: Checkout + uses: actions/checkout@v5 + - name: Install terraform + run: | + sudo snap install terraform --classic + - name: Install tox & poetry + run: | + pipx install tox + pipx install poetry + - name: Run linters + run: | + tox run -e lint + tox run -e lint-terraform unit-test: name: Unit test charm From c112fa038fb683107084925a7a579eb6a4bd7058 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sinclert=20P=C3=A9rez?= Date: Thu, 2 Oct 2025 12:47:23 +0200 Subject: [PATCH 4/4] Tweak terraform docs --- docs/how-to/deploy/terraform.md | 84 ++++++++++++--------------------- 1 file changed, 30 insertions(+), 54 deletions(-) diff --git a/docs/how-to/deploy/terraform.md b/docs/how-to/deploy/terraform.md index 707a973e9e..abe4934332 100644 --- a/docs/how-to/deploy/terraform.md +++ b/docs/how-to/deploy/terraform.md @@ -1,32 +1,30 @@ -# How to deploy using Terraform -[Terraform](https://www.terraform.io/) is an infrastructure automation tool to provision and manage resources in clouds or data centers. To deploy Charmed MySQL K8s using Terraform and Juju, you can use the [Juju Terraform Provider](https://registry.terraform.io/providers/juju/juju/latest). +# How to deploy using Terraform -The easiest way is to start from [these examples of terraform modules](https://github.com/canonical/terraform-modules) prepared by Canonical. This page will guide you through a deployment using an example module for MySQL on Kubernetes. +[Terraform](https://www.terraform.io/) is an infrastructure automation tool to provision and manage resources in clouds or data centers. +To deploy Charmed MySQL using Terraform and Juju, you can use the [Juju Terraform Provider](https://registry.terraform.io/providers/juju/juju/latest). For an in-depth introduction to the Juju Terraform Provider, read [this Discourse post](https://discourse.charmhub.io/t/6939). -```{note} -**Note**: Storage support was added in [Juju Terraform Provider version 0.13+](https://github.com/juju/terraform-provider-juju/releases/tag/v0.13.0). -``` - ## Install Terraform tooling -This guide assumes Juju is installed and you have a K8s controller already bootstrapped. For more information, check the [Charmed MySQL K8s tutorial](/tutorial/index). +This guide assumes Juju is installed, and you have a K8s controller already bootstrapped. For more information, check the [Charmed MySQL K8s tutorial](/tutorial/index). Let's install Terraform Provider and example modules: ```shell sudo snap install terraform --classic ``` + Switch to the K8s provider and create a new model: ```shell juju switch microk8s juju add-model my-model ``` -Clone examples and navigate to the MySQL machine module: + +Clone the MySQL K8s operator repository and navigate to the terraform module: ```shell -git clone https://github.com/canonical/terraform-modules.git -cd terraform-modules/modules/k8s/mysql +git clone https://github.com/canonical/mysql-k8s-operator.git +cd terraform ``` Initialise the Juju Terraform Provider: @@ -36,27 +34,10 @@ terraform init ## Verify the deployment -Open the `main.tf` file to see the brief contents of the Terraform module: - -```tf -resource "juju_application" "k8s_mysql" { - name = var.mysql_application_name - model = var.juju_model_name - trust = true - - charm { - name = "mysql-k8s" - channel = var.mysql_charm_channel - } - - units = 1 -} -``` - -Run `terraform plan` to get a preview of the changes that will be made: +Open the `main.tf` file to see the brief contents of the Terraform module, and run `terraform plan` to get a preview of the changes that will be made: ```shell -terraform plan -var "juju_model_name=my-model" +terraform plan -var "model_name=my-model" ``` ## Apply the deployment @@ -64,7 +45,7 @@ terraform plan -var "juju_model_name=my-model" If everything looks correct, deploy the resources (skip the approval): ```shell -terraform apply -auto-approve -var "juju_model_name=my-model" +terraform apply -auto-approve -var "model_name=my-model" ``` ## Check deployment status @@ -78,48 +59,47 @@ juju status --model k8s:my-model --watch 1s Sample output: ```shell -Model Controller Cloud/Region Version SLA Timestamp -my-model k8s-controller microk8s/localhost 3.5.3 unsupported 12:37:25Z +Model Controller Cloud/Region Version SLA Timestamp +my-model k8s-controller microk8s/localhost 3.5.3 unsupported 12:37:25Z App Version Status Scale Charm Channel Rev Address Exposed Message -mysql-k8s 8.0.36-0ubuntu0.22.04.1 active 1 mysql-k8s 8.0/stable 153 10.152.183.112 no +mysql-k8s 8.0.41-0ubuntu0.22.04.1 active 1 mysql-k8s 8.0/stable 255 10.152.183.112 no Unit Workload Agent Address Ports Message mysql-k8s/0* active idle 10.1.77.76 Primary - ``` Continue to operate the charm as usual from here or apply further Terraform changes. ## Clean up -To keep the house clean, remove the newly deployed Charmed MySQL K8s by running +To keep the house clean, remove the newly deployed MySQL K8s charm by running ```shell -terraform destroy -var "juju_model_name=my-model" +terraform destroy -var "model_name=my-model" ``` Sample output: ```shell -juju_application.k8s_mysql: Refreshing state... [id=terra-k8s:mysql-k8s] +juju_application.mysql_server: Refreshing state... [id=my-model:mysql-k8s] Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: - destroy Terraform will perform the following actions: - # juju_application.k8s_mysql will be destroyed - - resource "juju_application" "k8s_mysql" { + # juju_application.mysql_server will be destroyed + - resource "juju_application" "mysql_server" { - constraints = "arch=amd64" -> null - - id = "terra-k8s:mysql-k8s" -> null - - model = "terra-k8s" -> null + - id = "my-model:mysql-k8s" -> null + - model = "my-model" -> null - name = "mysql-k8s" -> null - placement = "" -> null - storage = [ - { - count = 1 -> null - - label = "database-1" -> null + - label = "database" -> null - pool = "kubernetes" -> null - - size = "1G" -> null + - size = "10G" -> null }, ] -> null - trust = true -> null @@ -129,7 +109,7 @@ Terraform will perform the following actions: - base = "ubuntu@22.04" -> null - channel = "8.0/stable" -> null - name = "mysql-k8s" -> null - - revision = 153 -> null + - revision = 255 -> null - series = "jammy" -> null } } @@ -137,7 +117,7 @@ Terraform will perform the following actions: Plan: 0 to add, 0 to change, 1 to destroy. Changes to Outputs: - - application_name = "mysql-k8s" -> null + - application_name = "mysql" -> null Do you really want to destroy all resources? Terraform will destroy all your managed infrastructure, as shown above. @@ -145,16 +125,12 @@ Do you really want to destroy all resources? Enter a value: yes -juju_application.k8s_mysql: Destroying... [id=terra-k8s:mysql-k8s] -juju_application.k8s_mysql: Destruction complete after 0s +juju_application.mysql_server: Destroying... [id=my-model:mysql-k8s] +juju_application.mysql_server: Destruction complete after 0s Destroy complete! Resources: 1 destroyed. ``` ---- - -```{note} -For more examples of Terraform modules for K8s, see the other directories in the [`terraform-modules` repository](https://github.com/canonical/terraform-modules/tree/main/modules/k8s). -``` -Feel free to [contact us](/reference/contacts) if you have any question and [collaborate with us on GitHub](https://github.com/canonical/terraform-modules)! +--- +Feel free to [contact us](/reference/contacts) if you have any question and collaborate with us on GitHub!