diff --git a/.github/workflows/plan-terraform.yaml b/.github/workflows/plan-terraform.yaml index 9c68061..c635af3 100644 --- a/.github/workflows/plan-terraform.yaml +++ b/.github/workflows/plan-terraform.yaml @@ -24,7 +24,7 @@ jobs: yaml: test/vanilla.yaml cloud_integration: '' env: - TF_VAR_model: test + TF_VAR_model: '{"name": "test", "cloud": "prod-k8s-openstack", "config": {"test": true}}' TF_VAR_manifest_yaml: ${{ matrix.test.yaml }} TF_VAR_cloud_integration: ${{ matrix.test.cloud_integration }} WORKING_DIR: 'terraform' diff --git a/.gitignore b/.gitignore index 4245f9e..c744d27 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,5 @@ main/.charmcraft_output_packages.txt **/.terraform **/.terraform.lock.hcl **/*.tfstate +**/*.tfstate.backup **/tfplan diff --git a/terraform/README.md b/terraform/README.md index 7b9d644..66cfb15 100644 --- a/terraform/README.md +++ b/terraform/README.md @@ -9,19 +9,32 @@ charm configuration. ## TODO - [ ] Set outputs for each charm deployed - [ ] Add COS integration -- [ ] Find a home for this module -- [ ] Add required subordinate (Landscape, NTP, etc..) see [This private Terraform Plan for details](https://git.launchpad.net/canonical-terraform-modules/tree/services/compute/canonical_k8s_cluster/main.tf#n214) +- [ ] Add required subordinate (Landscape, NTP, etc..) see [This private Terraform Plan for details][private-details] ## Applications * [k8s](https://charmhub.io/k8s) * [k8s-worker](https://charmhub.io/k8s-worker) ## Inputs -| Name | Type | Description | Required | -| - | - | - | - | -| `manifest_yaml` | string | Absolute path to the manifest yaml for the deployment | True | -| `model` | string | Name of the Juju model to deploy into | True | -| `cloud_integration` | string | Selection of a cloud integration | False | +| Name | Type | Description | Required | +| --- | --- | --- | --- | +| `manifest_yaml` | string | Absolute path to the manifest yaml for the deployment | True | +| `model` | object | Juju model attributes | True | +| `cloud_integration` | bool | Enablement of a cloud integration | False | + +### Model Input: +Juju Model resource definition borrows its schema from [Juju Model Resource]. + +The schema requires only: +- **name**: Name of the model +- **cloud**: Cloud name + +Default fields are: +- **region**: Region name (optional) +- **config**: Configuration map (optional) +- **constraints**: Constraints string (optional) +- **credential**: Credential name (optional) + ## Outputs TODO @@ -30,29 +43,33 @@ TODO Add the following to your main.tf for the canonical k8s solution: -``` +```hcl module "k8s" { source = "git::https://github.com/canonical/k8s-bundles//terraform?ref=main" - model = "my-canonical-k8s" + model = { + name = "my-canonical-k8s" + cloud = "prod-example-openstack" + } + cloud_integration = "openstack" manifest_yaml = "/path/to/manifest.yaml" } ``` -Define your manifest.yaml based on the requirements for your deployment. Specific configuration -options can be found under the charm URLs linked above. +Define your manifest.yaml based on the requirements for your deployment. Specific configuration options can be found under the charm URLs linked above. -``` +```yaml k8s: - units: 2 - base: ubuntu@24.04 - constraints: arch=amd64 cores=2 mem=4096M root-disk=16384M - channel: 1.31/beta + units: 3 + base: ubuntu@24.04 + constraints: arch=amd64 cores=2 mem=4096M root-disk=16384M + channel: 1.32/stable k8s_worker: - units: 2 - base: ubuntu@24.04 - constraints: arch=amd64 cores=2 mem=8192M root-disk=16384M - channel: 1.31/beta + units: 2 + base: ubuntu@24.04 + constraints: arch=amd64 cores=2 mem=8192M root-disk=16384M + channel: 1.32/stable ``` - - + +[Juju Model Resource]: https://registry.terraform.io/providers/juju/juju/0.16.0/docs/resources/model +[private-details]: https://git.launchpad.net/canonical-terraform-modules/tree/services/compute/canonical_k8s_cluster/main.tf#n214 \ No newline at end of file diff --git a/terraform/applications.tf b/terraform/applications.tf index e3cdf47..cf69fce 100644 --- a/terraform/applications.tf +++ b/terraform/applications.tf @@ -2,7 +2,7 @@ # See LICENSE file for licensing details. module "k8s" { - source = "git::https://github.com/canonical/k8s-operator//charms/worker/k8s/terraform" + source = "git::https://github.com/canonical/k8s-operator//charms/worker/k8s/terraform?ref=main" app_name = module.k8s_config.config.app_name channel = module.k8s_config.config.channel # This currently just sets the bootstrap-node-taints to have the right no schedule value @@ -13,7 +13,7 @@ module "k8s" { {"bootstrap-node-taints": "node-role.kubernetes.io/control-plane:NoSchedule"} ) constraints = module.k8s_config.config.constraints - model = var.model + model = resource.juju_model.this.name resources = module.k8s_config.config.resources revision = module.k8s_config.config.revision base = module.k8s_config.config.base @@ -21,22 +21,22 @@ module "k8s" { } module "k8s_worker" { - source = "git::https://github.com/canonical/k8s-operator//charms/worker/terraform" + source = "git::https://github.com/canonical/k8s-operator//charms/worker/terraform?ref=main" app_name = module.k8s_worker_config.config.app_name base = coalesce(module.k8s_worker_config.config.base, module.k8s_config.config.base) constraints = coalesce(module.k8s_worker_config.config.constraints, module.k8s_config.config.constraints) channel = coalesce(module.k8s_worker_config.config.channel, module.k8s_config.config.channel) config = module.k8s_worker_config.config.config - model = var.model + model = resource.juju_model.this.name resources = module.k8s_worker_config.config.resources revision = module.k8s_worker_config.config.revision units = module.k8s_worker_config.config.units } module "openstack" { - count = var.cloud_integration == "openstack" ? 1 : 0 + count = (var.cloud_integration == "openstack" ) ? 1 : 0 source = "./openstack" - model = var.model + model = resource.juju_model.this.name manifest_yaml = var.manifest_yaml k8s = { app_name = module.k8s.app_name diff --git a/terraform/configs.tf b/terraform/configs.tf index f038b0f..bb88fc2 100644 --- a/terraform/configs.tf +++ b/terraform/configs.tf @@ -2,13 +2,13 @@ # See LICENSE file for licensing details. module "k8s_config" { - source = "git::https://github.com/canonical/k8s-bundles//terraform/manifest?ref=main" + source = "./manifest/" manifest = var.manifest_yaml app = "k8s" } module "k8s_worker_config" { - source = "git::https://github.com/canonical/k8s-bundles//terraform/manifest?ref=main" + source = "./manifest/" manifest = var.manifest_yaml app = "k8s_worker" } diff --git a/terraform/integrations.tf b/terraform/integrations.tf index a33fc8b..1e9c200 100644 --- a/terraform/integrations.tf +++ b/terraform/integrations.tf @@ -1,8 +1,43 @@ # Copyright 2024 Canonical Ltd. # See LICENSE file for licensing details. +resource "juju_model" "this" { + name = var.model.name + + cloud { + name = var.model.cloud + region = var.model.region + } + + config = merge( + # Here we drop 2 model-config options the user may naively set + # fan-config + # container-networking-method + { + for k, v in var.model.config != null ? var.model.config : {} : + k => v + if !contains(["fan-config", "container-networking-method"], k) + }, + # Then we merge in the required settings + # fan-config - required to be empty for k8s + # container-networking-method - required to be local for k8s + { + fan-config = "" + container-networking-method = "local" + } + ) + + constraints = var.model.constraints + credential = var.model.credential + + provisioner "local-exec" { + # workaround for https://github.com/juju/terraform-provider-juju/issues/667 + command = "juju model-config fan-config=''" + } +} + resource "juju_integration" "k8s_cluster_integration" { - model = var.model + model = resource.juju_model.this.name application { name = module.k8s.app_name endpoint = module.k8s.provides.k8s_cluster @@ -14,7 +49,7 @@ resource "juju_integration" "k8s_cluster_integration" { } resource "juju_integration" "k8s_containerd" { - model = var.model + model = resource.juju_model.this.name application { name = module.k8s.app_name endpoint = module.k8s.provides.containerd @@ -26,7 +61,7 @@ resource "juju_integration" "k8s_containerd" { } resource "juju_integration" "k8s_cos_worker_tokens" { - model = var.model + model = resource.juju_model.this.name application { name = module.k8s.app_name endpoint = module.k8s.provides.cos_worker_tokens diff --git a/terraform/openstack/configs.tf b/terraform/openstack/configs.tf index f359553..1c441d0 100644 --- a/terraform/openstack/configs.tf +++ b/terraform/openstack/configs.tf @@ -2,19 +2,19 @@ # See LICENSE file for licensing details. module "openstack_integrator_config" { - source = "git::https://github.com/canonical/k8s-bundles//terraform/manifest?ref=main" + source = "../manifest/" manifest = var.manifest_yaml app = "openstack_integrator" } module "cinder_csi_config" { - source = "git::https://github.com/canonical/k8s-bundles//terraform/manifest?ref=main" + source = "../manifest/" manifest = var.manifest_yaml app = "cinder_csi" } module "openstack_cloud_controller_config" { - source = "git::https://github.com/canonical/k8s-bundles//terraform/manifest?ref=main" + source = "../manifest" manifest = var.manifest_yaml app = "openstack_cloud_controller" } diff --git a/terraform/openstack/versions.tf b/terraform/openstack/versions.tf index e25f438..6e3674e 100644 --- a/terraform/openstack/versions.tf +++ b/terraform/openstack/versions.tf @@ -6,7 +6,7 @@ terraform { required_providers { juju = { source = "juju/juju" - version = "~> 0.14.0" + version = ">= 0.14.0, < 1.0.0" } } } diff --git a/terraform/test/openstack.yaml b/terraform/test/openstack.yaml index 7dd7acd..53f6cf9 100644 --- a/terraform/test/openstack.yaml +++ b/terraform/test/openstack.yaml @@ -1,15 +1,15 @@ k8s: - units: 3 - base: ubuntu@24.04 - constraints: arch=amd64 cores=2 mem=8G root-disk=16G - channel: latest/edge + units: 3 + base: ubuntu@24.04 + constraints: arch=amd64 cores=2 mem=8192M root-disk=16384M + channel: latest/edge k8s_worker: - units: 3 - base: ubuntu@24.04 - constraints: arch=amd64 cores=2 mem=8G root-disk=16G - channel: latest/edge + units: 3 + base: ubuntu@24.04 + constraints: arch=amd64 cores=2 mem=8192M root-disk=16384M + channel: latest/edge openstack_integrator: - channel: 1.31/stable - base: ubuntu@22.04 + channel: 1.31/stable + base: ubuntu@22.04 cinder_csi: {} openstack_cloud_controller: {} diff --git a/terraform/test/vanilla.yaml b/terraform/test/vanilla.yaml index c151259..ba25cf4 100644 --- a/terraform/test/vanilla.yaml +++ b/terraform/test/vanilla.yaml @@ -1,10 +1,10 @@ k8s: - units: 3 - base: ubuntu@24.04 - constraints: arch=amd64 cores=2 mem=8G root-disk=16G - channel: latest/edge + units: 3 + base: ubuntu@24.04 + constraints: arch=amd64 cores=2 mem=8192M root-disk=16384M + channel: latest/edge k8s_worker: - units: 3 - base: ubuntu@24.04 - constraints: arch=amd64 cores=2 mem=8G root-disk=16G - channel: latest/edge + units: 3 + base: ubuntu@24.04 + constraints: arch=amd64 cores=2 mem=8192M root-disk=16384M + channel: latest/edge diff --git a/terraform/variables.tf b/terraform/variables.tf index 82ca19e..2429b17 100644 --- a/terraform/variables.tf +++ b/terraform/variables.tf @@ -6,19 +6,48 @@ variable "manifest_yaml" { type = string } -variable "model" { - description = "Name of the Juju model to deploy to." - type = string -} - variable "cloud_integration" { - description = "Selection of a cloud integration" + description = "Selection of a cloud integration." type = string default = "" validation { - condition = contains(["", "openstack"], var.cloud_integration) - error_message = "Cloud must be one of '', or 'openstack'" + condition = can(regex("^(|openstack)$", var.cloud_integration)) + error_message = "Cloud integration must be one of: '', openstack." } } +variable "model" { + description = <