diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 7f32dc1c..44fc00ce 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -1,4 +1,4 @@ -# Copyright 2025 Canonical Ltd. +# Copyright 2026 Canonical Ltd. # See LICENSE file for licensing details. # Adapted from: https://github.com/canonical/postgresql-operator/blob/main/.github/workflows/ci.yaml name: Build charm diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index 5ea9d19b..4fcac0e8 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -1,4 +1,4 @@ -# Copyright 2025 Canonical Ltd. +# Copyright 2026 Canonical Ltd. # See LICENSE file for licensing details. # Adapted from: https://github.com/canonical/postgresql-operator/blob/main/.github/workflows/ci.yaml name: Lint charm @@ -31,7 +31,7 @@ jobs: - uses: actions/checkout@v5 - uses: hashicorp/setup-terraform@v3 with: - terraform_version: "~1.10" + terraform_version: "~1.12" - uses: terraform-linters/setup-tflint@v4 - run: make terraform-check-all diff --git a/.github/workflows/test_terraform_modules.yaml b/.github/workflows/test_terraform_modules.yaml new file mode 100644 index 00000000..5331fef3 --- /dev/null +++ b/.github/workflows/test_terraform_modules.yaml @@ -0,0 +1,19 @@ +# Copyright 2026 Canonical Ltd. +# See LICENSE file for licensing details. + +name: Terraform modules tests + +on: + workflow_dispatch: + pull_request: + paths: + - "terraform/**" + +jobs: + terraform-tests: + uses: canonical/operator-workflows/.github/workflows/terraform_modules_test.yaml@main + secrets: inherit + with: + lxd-controller: true + self-hosted-runner: true + terraform-directories: '["terraform/charm", "terraform/product/modules/landscape-scalable"]' diff --git a/.github/workflows/unit-test.yaml b/.github/workflows/unit-test.yaml index 8c1f64df..28600be0 100644 --- a/.github/workflows/unit-test.yaml +++ b/.github/workflows/unit-test.yaml @@ -1,4 +1,4 @@ -# Copyright 2025 Canonical Ltd. +# Copyright 2026 Canonical Ltd. # See LICENSE file for licensing details. # Adapted from: https://github.com/canonical/postgresql-operator/blob/main/.github/workflows/ci.yaml name: Unit test charm @@ -42,7 +42,7 @@ jobs: - uses: hashicorp/setup-terraform@v3 with: - terraform_version: "~1.10" + terraform_version: "~1.12" - name: Run terraform tests run: make terraform-test-all diff --git a/actions.yaml b/actions.yaml index 94ef6b3c..8c0a4596 100644 --- a/actions.yaml +++ b/actions.yaml @@ -1,4 +1,4 @@ -# Copyright 2025 Canonical Ltd +# Copyright 2026 Canonical Ltd # See LICENSE file for licensing details. hash-id-databases: diff --git a/copyright b/copyright index a285045c..9bab65d1 100644 --- a/copyright +++ b/copyright @@ -1,7 +1,7 @@ Format: http://dep.debian.net/deps/dep5/ Files: * -Copyright: Copyright 2025, Canonical Ltd., All Rights Reserved. +Copyright: Copyright 2026, Canonical Ltd., All Rights Reserved. License: GPL-2 This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/lib/charms/grafana_agent/LICENSE b/lib/charms/grafana_agent/LICENSE index 8a83a559..5823fae5 100644 --- a/lib/charms/grafana_agent/LICENSE +++ b/lib/charms/grafana_agent/LICENSE @@ -198,4 +198,4 @@ distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file + limitations under the License. diff --git a/metadata.yaml b/metadata.yaml index 74aa6d7b..204f69cb 100644 --- a/metadata.yaml +++ b/metadata.yaml @@ -1,4 +1,4 @@ -# Copyright 2025 Canonical Ltd +# Copyright 2026 Canonical Ltd # See LICENSE file for licensing details. # For a complete list of supported options, see: diff --git a/renovate.json b/renovate.json new file mode 100644 index 00000000..d6ede418 --- /dev/null +++ b/renovate.json @@ -0,0 +1,79 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "automerge": true, + "customDatasources": { + "charmhub": { + "defaultRegistryUrlTemplate": "https://api.charmhub.io/v2/charms/info/{{packageName}}?fields=channel-map", + "format": "json", + "transformTemplates": [ + "{\"releases\": [{\"version\": $string($$.(`channel-map`[channel.risk = 'edge' and channel.track = 'latest' and channel.base.architecture = 'amd64' and channel.base.channel = '24.04'].revision.revision))}]}" + ] + } + }, + "customManagers": [ + { + "customType": "regex", + "datasourceTemplate": "docker", + "description": "Update base image references", + "managerFilePatterns": [ + "/(^|/)rockcraft.yaml$/" + ], + "matchStrings": [ + "# renovate: build-base:\\s+(?[^:]*):(?[^\\s@]*)(@(?sha256:[0-9a-f]*))?", + "# renovate: base:\\s+(?[^:]*):(?[^\\s@]*)(@(?sha256:[0-9a-f]*))?" + ], + "matchStringsStrategy": "any", + "versioningTemplate": "ubuntu" + }, + { + "customType": "regex", + "datasourceTemplate": "custom.charmhub", + "fileMatch": [ + "\\.tftest\\.hcl$", + "\\.tf$" + ], + "matchStrings": [ + "# renovate: depName=\"(?[^\"]+)\"\\s*\\n\\s*(?[a-zA-Z0-9_]+)\\s*=\\s*(?\\d+)" + ], + "versioningTemplate": "semver-coerced" + } + ], + "extends": [ + "config:recommended", + "group:allNonMajor" + ], + "ignorePaths": [], + "packageRules": [ + { + "enabled": true, + "matchDatasources": [ + "docker" + ], + "pinDigests": true + }, + { + "automerge": true, + "enabled": true, + "matchDatasources": [ + "custom.charmhub" + ] + }, + { + "enabled": false, + "matchFileNames": [ + "rockcraft.yaml" + ], + "matchUpdateTypes": [ + "major", + "minor", + "patch" + ] + } + ], + "schedule": [ + "* * * * 0,6" + ], + "vulnerabilityAlerts": { + "enabled": true + } +} diff --git a/src/charm.py b/src/charm.py index 22fe829e..8505bcff 100755 --- a/src/charm.py +++ b/src/charm.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright 2025 Canonical Ltd +# Copyright 2026 Canonical Ltd # See LICENSE file for licensing details. # # Learn more at: https://juju.is/docs/sdk diff --git a/src/settings_files.py b/src/settings_files.py index 82773c14..d5636433 100644 --- a/src/settings_files.py +++ b/src/settings_files.py @@ -1,4 +1,4 @@ -# Copyright 2025 Canonical Ltd +# Copyright 2026 Canonical Ltd """ Functions for manipulating Landscape Server service settings in the diff --git a/terraform/.tflint.hcl b/terraform/.tflint.hcl new file mode 100644 index 00000000..5668c825 --- /dev/null +++ b/terraform/.tflint.hcl @@ -0,0 +1,5 @@ +# © 2026 Canonical Ltd. + +rule "terraform_required_version" { + enabled = true +} diff --git a/terraform/charm/Makefile b/terraform/charm/Makefile index b2cc8f4f..64bb1b5a 100644 --- a/terraform/charm/Makefile +++ b/terraform/charm/Makefile @@ -8,7 +8,7 @@ test-charm-module: terraform init -backend=false && \ - terraform test + terraform test -filter=tests/outputs.tftest.hcl fmt-check: terraform init -backend=false && \ diff --git a/terraform/charm/README.md b/terraform/charm/README.md index a544618c..0cf0433e 100644 --- a/terraform/charm/README.md +++ b/terraform/charm/README.md @@ -91,7 +91,7 @@ make fix-charm-module | Name | Version | |------|---------| -| [terraform](#requirement\_terraform) | >= 1.10 | +| [terraform](#requirement\_terraform) | ~> 1.12 | | [juju](#requirement\_juju) | ~> 1.0 | ## Providers diff --git a/terraform/charm/main.tf b/terraform/charm/main.tf index daa1f8cc..ceb05da5 100644 --- a/terraform/charm/main.tf +++ b/terraform/charm/main.tf @@ -1,4 +1,4 @@ -# © 2025 Canonical Ltd. +# © 2026 Canonical Ltd. resource "juju_application" "landscape_server" { name = var.app_name diff --git a/terraform/charm/tests/main.tftest.hcl b/terraform/charm/tests/main.tftest.hcl new file mode 100644 index 00000000..f9e8f61c --- /dev/null +++ b/terraform/charm/tests/main.tftest.hcl @@ -0,0 +1,21 @@ +# © 2026 Canonical Ltd. + +run "setup_tests" { + module { + source = "./tests/setup" + } +} + +run "basic_deploy" { + variables { + model_uuid = run.setup_tests.model_uuid + channel = "26.04/edge" + # renovate: depName="landscape-server" + revision = 355 + } + + assert { + condition = output.app_name == "landscape-server" + error_message = "landscape-server app_name did not match expected" + } +} diff --git a/terraform/charm/tests/outputs.tftest.hcl b/terraform/charm/tests/outputs.tftest.hcl index 959bd3c3..d8e770b2 100644 --- a/terraform/charm/tests/outputs.tftest.hcl +++ b/terraform/charm/tests/outputs.tftest.hcl @@ -1,4 +1,4 @@ -# © 2025 Canonical Ltd. +# © 2026 Canonical Ltd. mock_provider "juju" {} diff --git a/terraform/charm/tests/setup/main.tf b/terraform/charm/tests/setup/main.tf new file mode 100644 index 00000000..65589272 --- /dev/null +++ b/terraform/charm/tests/setup/main.tf @@ -0,0 +1,21 @@ +# © 2026 Canonical Ltd. + +terraform { + required_version = "~> 1.12" + required_providers { + juju = { + version = "~> 1.0" + source = "juju/juju" + } + } +} + +provider "juju" {} + +resource "juju_model" "test_model" { + name = "tf-testing-${formatdate("YYYYMMDDhhmmss", timestamp())}" +} + +output "model_uuid" { + value = juju_model.test_model.uuid +} diff --git a/terraform/charm/variables.tf b/terraform/charm/variables.tf index 21c503ff..fabddd96 100644 --- a/terraform/charm/variables.tf +++ b/terraform/charm/variables.tf @@ -1,4 +1,4 @@ -# © 2025 Canonical Ltd. +# © 2026 Canonical Ltd. variable "app_name" { description = "Name of the application in the Juju model." diff --git a/terraform/charm/versions.tf b/terraform/charm/versions.tf index 72e33ceb..2ed5732e 100644 --- a/terraform/charm/versions.tf +++ b/terraform/charm/versions.tf @@ -1,7 +1,7 @@ -# © 2025 Canonical Ltd. +# © 2026 Canonical Ltd. terraform { - required_version = ">= 1.10" + required_version = "~> 1.12" required_providers { juju = { source = "juju/juju" diff --git a/terraform/product/Makefile b/terraform/product/Makefile index a3f30020..4ea9a681 100644 --- a/terraform/product/Makefile +++ b/terraform/product/Makefile @@ -24,5 +24,8 @@ test-product-modules: for m in $(MODULE_PATHS); do \ cd $$m && \ terraform init -backend=false && \ - terraform test; \ + terraform test \ + -filter=tests/defaults.tftest.hcl \ + -filter=tests/outputs.tftest.hcl \ + -filter=tests/integrations.tftest.hcl; \ done diff --git a/terraform/product/modules/landscape-scalable/README.md b/terraform/product/modules/landscape-scalable/README.md index 70754d59..36719b79 100644 --- a/terraform/product/modules/landscape-scalable/README.md +++ b/terraform/product/modules/landscape-scalable/README.md @@ -56,82 +56,82 @@ This module uses the [Landscape Server charm module](https://github.com/canonica ## Requirements -| Name | Version | -|------|---------| +| Name | Version | +| ------------------------------------------------------------------------- | ------- | | [terraform](#requirement\_terraform) | >= 1.10 | -| [juju](#requirement\_juju) | ~> 1.0 | +| [juju](#requirement\_juju) | ~> 1.0 | ## Providers -| Name | Version | -|------|---------| -| [juju](#provider\_juju) | ~> 1.0 | +| Name | Version | +| ---------------------------------------------------- | ------- | +| [juju](#provider\_juju) | ~> 1.0 | ## Modules -| Name | Source | Version | -|------|--------|---------| -| [haproxy](#module\_haproxy) | git::https://github.com/canonical/haproxy-operator.git//terraform/charm/haproxy | haproxy-rev331 | -| [landscape\_server](#module\_landscape\_server) | ../../../charm | n/a | -| [postgresql](#module\_postgresql) | git::https://github.com/canonical/postgresql-operator.git//terraform | v16/1.165.0 | +| Name | Source | Version | +| -------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | -------------- | +| [haproxy](#module\_haproxy) | git::https://github.com/canonical/haproxy-operator.git//terraform/charm/haproxy | haproxy-rev331 | +| [landscape\_server](#module\_landscape\_server) | ../../../charm | n/a | +| [postgresql](#module\_postgresql) | git::https://github.com/canonical/postgresql-operator.git//terraform | v16/1.165.0 | ## Resources -| Name | Type | -|------|------| -| [juju_application.pgbouncer](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/application) | resource | -| [juju_application.rabbitmq_server](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/application) | resource | -| [juju_application.tls_certificates](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/application) | resource | -| [juju_integration.haproxy_certificates](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/integration) | resource | -| [juju_integration.haproxy_receive_ca_certs](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/integration) | resource | -| [juju_integration.landscape_server_api_haproxy_route_in_model](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/integration) | resource | -| [juju_integration.landscape_server_api_haproxy_route_lbaas](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/integration) | resource | -| [juju_integration.landscape_server_appserver_haproxy_route_in_model](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/integration) | resource | -| [juju_integration.landscape_server_appserver_haproxy_route_lbaas](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/integration) | resource | -| [juju_integration.landscape_server_haproxy](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/integration) | resource | -| [juju_integration.landscape_server_hostagent_messenger_haproxy_route_in_model](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/integration) | resource | -| [juju_integration.landscape_server_hostagent_messenger_haproxy_route_lbaas](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/integration) | resource | -| [juju_integration.landscape_server_inbound_amqp](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/integration) | resource | -| [juju_integration.landscape_server_message_server_haproxy_route_in_model](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/integration) | resource | -| [juju_integration.landscape_server_message_server_haproxy_route_lbaas](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/integration) | resource | -| [juju_integration.landscape_server_outbound_amqp](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/integration) | resource | -| [juju_integration.landscape_server_package_upload_haproxy_route_in_model](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/integration) | resource | -| [juju_integration.landscape_server_package_upload_haproxy_route_lbaas](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/integration) | resource | -| [juju_integration.landscape_server_pgbouncer](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/integration) | resource | -| [juju_integration.landscape_server_pingserver_haproxy_route_in_model](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/integration) | resource | -| [juju_integration.landscape_server_pingserver_haproxy_route_lbaas](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/integration) | resource | -| [juju_integration.landscape_server_postgresql_legacy](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/integration) | resource | -| [juju_integration.landscape_server_postgresql_modern](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/integration) | resource | -| [juju_integration.landscape_server_rabbitmq_server](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/integration) | resource | -| [juju_integration.landscape_server_repository_haproxy_route_in_model](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/integration) | resource | -| [juju_integration.landscape_server_repository_haproxy_route_lbaas](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/integration) | resource | +| Name | Type | +| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | +| [juju_application.pgbouncer](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/application) | resource | +| [juju_application.rabbitmq_server](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/application) | resource | +| [juju_application.tls_certificates](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/application) | resource | +| [juju_integration.haproxy_certificates](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/integration) | resource | +| [juju_integration.haproxy_receive_ca_certs](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/integration) | resource | +| [juju_integration.landscape_server_api_haproxy_route_in_model](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/integration) | resource | +| [juju_integration.landscape_server_api_haproxy_route_lbaas](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/integration) | resource | +| [juju_integration.landscape_server_appserver_haproxy_route_in_model](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/integration) | resource | +| [juju_integration.landscape_server_appserver_haproxy_route_lbaas](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/integration) | resource | +| [juju_integration.landscape_server_haproxy](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/integration) | resource | +| [juju_integration.landscape_server_hostagent_messenger_haproxy_route_in_model](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/integration) | resource | +| [juju_integration.landscape_server_hostagent_messenger_haproxy_route_lbaas](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/integration) | resource | +| [juju_integration.landscape_server_inbound_amqp](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/integration) | resource | +| [juju_integration.landscape_server_message_server_haproxy_route_in_model](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/integration) | resource | +| [juju_integration.landscape_server_message_server_haproxy_route_lbaas](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/integration) | resource | +| [juju_integration.landscape_server_outbound_amqp](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/integration) | resource | +| [juju_integration.landscape_server_package_upload_haproxy_route_in_model](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/integration) | resource | +| [juju_integration.landscape_server_package_upload_haproxy_route_lbaas](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/integration) | resource | +| [juju_integration.landscape_server_pgbouncer](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/integration) | resource | +| [juju_integration.landscape_server_pingserver_haproxy_route_in_model](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/integration) | resource | +| [juju_integration.landscape_server_pingserver_haproxy_route_lbaas](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/integration) | resource | +| [juju_integration.landscape_server_postgresql_legacy](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/integration) | resource | +| [juju_integration.landscape_server_postgresql_modern](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/integration) | resource | +| [juju_integration.landscape_server_rabbitmq_server](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/integration) | resource | +| [juju_integration.landscape_server_repository_haproxy_route_in_model](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/integration) | resource | +| [juju_integration.landscape_server_repository_haproxy_route_lbaas](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/integration) | resource | | [juju_integration.landscape_server_ubuntu_installer_attach_haproxy_route_in_model](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/integration) | resource | -| [juju_integration.landscape_server_ubuntu_installer_attach_haproxy_route_lbaas](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/integration) | resource | -| [juju_integration.pgbouncer_postgresql](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/integration) | resource | +| [juju_integration.landscape_server_ubuntu_installer_attach_haproxy_route_lbaas](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/integration) | resource | +| [juju_integration.pgbouncer_postgresql](https://registry.terraform.io/providers/juju/juju/latest/docs/resources/integration) | resource | ## Inputs -| Name | Description | Type | Default | Required | -|------|-------------|------|---------|:--------:| -| [haproxy](#input\_haproxy) | Configuration for the HAProxy charm. Set to null to skip deployment. |
object({
app_name = optional(string, "haproxy")
channel = optional(string, "2.8/edge")
config = optional(map(string), {})
constraints = optional(string, "arch=amd64")
resources = optional(map(string), {})
revision = optional(number)
base = optional(string, "ubuntu@24.04")
units = optional(number, 1)
})
| `{}` | no | -| [haproxy\_route\_offer\_url](#input\_haproxy\_route\_offer\_url) | Offer URL for the haproxy-route endpoint from a cross-model haproxy deployment (LBaaS). Set to null to skip. | `string` | `null` | no | -| [landscape\_server](#input\_landscape\_server) | Configuration for the Landscape Server charm. |
object({
app_name = optional(string, "landscape-server")
channel = optional(string, "26.04/beta")
charm_name = optional(string, "landscape-server")
config = optional(map(string), {
autoregistration = "true"
landscape_ppa = "ppa:landscape/self-hosted-26.04"
min_install = "true"
root_url = "https://landscape.local/"
enable_hostagent_messenger = "true"
enable_ubuntu_installer_attach = "true"
})
constraints = optional(string, "arch=amd64")
resources = optional(map(string), {})
revision = optional(number)
base = optional(string, "ubuntu@24.04")
units = optional(number, 1)
})
| `{}` | no | -| [model\_uuid](#input\_model\_uuid) | UUID of the Juju model to deploy Landscape Server to. | `string` | n/a | yes | -| [pgbouncer](#input\_pgbouncer) | Configuration for the PgBouncer charm. Set to null to skip deployment. PgBouncer is a subordinate charm and does not have its own units. |
object({
app_name = optional(string, "pgbouncer")
channel = optional(string, "1/stable")
config = optional(map(string), {})
revision = optional(number)
base = optional(string, "ubuntu@24.04")
})
| `null` | no | -| [postgresql](#input\_postgresql) | Configuration for the PostgreSQL charm. Set to null to skip deployment. |
object({
app_name = optional(string, "postgresql")
channel = optional(string, "16/stable")
config = optional(map(string), {
plugin_plpython3u_enable = "true"
plugin_ltree_enable = "true"
plugin_intarray_enable = "true"
plugin_debversion_enable = "true"
plugin_pg_trgm_enable = "true"
experimental_max_connections = "500"
})
constraints = optional(string, "arch=amd64")
resources = optional(map(string), {})
revision = optional(number)
base = optional(string, "ubuntu@24.04")
units = optional(number, 1)
})
| `{}` | no | -| [rabbitmq\_server](#input\_rabbitmq\_server) | Configuration for the RabbitMQ charm. Set to null to skip deployment. |
object({
app_name = optional(string, "rabbitmq-server")
channel = optional(string, "latest/edge")
config = optional(map(string), {
consumer-timeout = "259200000"
})
constraints = optional(string, "arch=amd64")
resources = optional(map(string), {})
revision = optional(number)
base = optional(string, "ubuntu@24.04")
units = optional(number, 1)
})
| `{}` | no | -| [tls\_certificates](#input\_tls\_certificates) | Configuration for the certificates charm deployed. Currently only integrated with HAProxy automatically. Set to null to skip deployment. |
object({
app_name = optional(string, "tls-certificates")
channel = optional(string, "1/stable")
charm_name = optional(string, "self-signed-certificates")
constraints = optional(string, "arch=amd64")
revision = optional(number)
base = optional(string, "ubuntu@24.04")
})
| `{}` | no | +| Name | Description | Type | Default | Required | +| ------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | :------: | +| [haproxy](#input\_haproxy) | Configuration for the HAProxy charm. Set to null to skip deployment. |
object({
app_name = optional(string, "haproxy")
channel = optional(string, "2.8/edge")
config = optional(map(string), {})
constraints = optional(string, "arch=amd64")
resources = optional(map(string), {})
revision = optional(number)
base = optional(string, "ubuntu@24.04")
units = optional(number, 1)
})
| `{}` | no | +| [haproxy\_route\_offer\_url](#input\_haproxy\_route\_offer\_url) | Offer URL for the haproxy-route endpoint from a cross-model haproxy deployment (LBaaS). Set to null to skip. | `string` | `null` | no | +| [landscape\_server](#input\_landscape\_server) | Configuration for the Landscape Server charm. |
object({
app_name = optional(string, "landscape-server")
channel = optional(string, "26.04/beta")
charm_name = optional(string, "landscape-server")
config = optional(map(string), {
autoregistration = "true"
landscape_ppa = "ppa:landscape/self-hosted-26.04"
min_install = "true"
root_url = "https://landscape.local/"
enable_hostagent_messenger = "true"
enable_ubuntu_installer_attach = "true"
})
constraints = optional(string, "arch=amd64")
resources = optional(map(string), {})
revision = optional(number)
base = optional(string, "ubuntu@24.04")
units = optional(number, 1)
})
| `{}` | no | +| [model\_uuid](#input\_model\_uuid) | UUID of the Juju model to deploy Landscape Server to. | `string` | n/a | yes | +| [pgbouncer](#input\_pgbouncer) | Configuration for the PgBouncer charm. Set to null to skip deployment. PgBouncer is a subordinate charm and does not have its own units. |
object({
app_name = optional(string, "pgbouncer")
channel = optional(string, "1/stable")
config = optional(map(string), {})
revision = optional(number)
base = optional(string, "ubuntu@24.04")
})
| `null` | no | +| [postgresql](#input\_postgresql) | Configuration for the PostgreSQL charm. Set to null to skip deployment. |
object({
app_name = optional(string, "postgresql")
channel = optional(string, "16/stable")
config = optional(map(string), {
plugin_plpython3u_enable = "true"
plugin_ltree_enable = "true"
plugin_intarray_enable = "true"
plugin_debversion_enable = "true"
plugin_pg_trgm_enable = "true"
experimental_max_connections = "500"
})
constraints = optional(string, "arch=amd64")
resources = optional(map(string), {})
revision = optional(number)
base = optional(string, "ubuntu@24.04")
units = optional(number, 1)
})
| `{}` | no | +| [rabbitmq\_server](#input\_rabbitmq\_server) | Configuration for the RabbitMQ charm. Set to null to skip deployment. |
object({
app_name = optional(string, "rabbitmq-server")
channel = optional(string, "latest/edge")
config = optional(map(string), {
consumer-timeout = "259200000"
})
constraints = optional(string, "arch=amd64")
resources = optional(map(string), {})
revision = optional(number)
base = optional(string, "ubuntu@24.04")
units = optional(number, 1)
})
| `{}` | no | +| [tls\_certificates](#input\_tls\_certificates) | Configuration for the certificates charm deployed. Currently only integrated with HAProxy automatically. Set to null to skip deployment. |
object({
app_name = optional(string, "tls-certificates")
channel = optional(string, "1/stable")
charm_name = optional(string, "self-signed-certificates")
constraints = optional(string, "arch=amd64")
revision = optional(number)
base = optional(string, "ubuntu@24.04")
})
| `{}` | no | ## Outputs -| Name | Description | -|------|-------------| -| [admin\_email](#output\_admin\_email) | Administrator email from the Landscape Server config. | -| [admin\_password](#output\_admin\_password) | Administrator password from the Landscape Server config (sensitive). | -| [applications](#output\_applications) | The charms included in the module. | -| [haproxy\_self\_signed](#output\_haproxy\_self\_signed) | Indicates whether HAProxy is using self-signed TLS certificates. True when self-signed-certificates is deployed alongside haproxy, null when haproxy is not deployed. | -| [has\_haproxy\_route\_interface](#output\_has\_haproxy\_route\_interface) | Indicates whether the deployment uses the modern haproxy-route relation/interface instead of the legacy website interface. | -| [has\_modern\_amqp\_relations](#output\_has\_modern\_amqp\_relations) | Indicates whether the deployment uses the modern inbound/outbound AMQP endpoints. | -| [has\_modern\_postgres\_interface](#output\_has\_modern\_postgres\_interface) | Indicates whether the deployment supports the modern PostgreSQL charm interface. | -| [registration\_key](#output\_registration\_key) | Registration key from the Landscape Server config. | +| Name | Description | +| --------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [admin\_email](#output\_admin\_email) | Administrator email from the Landscape Server config. | +| [admin\_password](#output\_admin\_password) | Administrator password from the Landscape Server config (sensitive). | +| [applications](#output\_applications) | The charms included in the module. | +| [haproxy\_self\_signed](#output\_haproxy\_self\_signed) | Indicates whether HAProxy is using self-signed TLS certificates. True when self-signed-certificates is deployed alongside haproxy, null when haproxy is not deployed. | +| [has\_haproxy\_route\_interface](#output\_has\_haproxy\_route\_interface) | Indicates whether the deployment uses the modern haproxy-route relation/interface instead of the legacy website interface. | +| [has\_modern\_amqp\_relations](#output\_has\_modern\_amqp\_relations) | Indicates whether the deployment uses the modern inbound/outbound AMQP endpoints. | +| [has\_modern\_postgres\_interface](#output\_has\_modern\_postgres\_interface) | Indicates whether the deployment supports the modern PostgreSQL charm interface. | +| [registration\_key](#output\_registration\_key) | Registration key from the Landscape Server config. | diff --git a/terraform/product/modules/landscape-scalable/outputs.tf b/terraform/product/modules/landscape-scalable/outputs.tf index 86c78f16..88126bf5 100644 --- a/terraform/product/modules/landscape-scalable/outputs.tf +++ b/terraform/product/modules/landscape-scalable/outputs.tf @@ -1,4 +1,4 @@ -# © 2025 Canonical Ltd. +# © 2026 Canonical Ltd. output "registration_key" { description = "Registration key from the Landscape Server config." diff --git a/terraform/product/modules/landscape-scalable/tests/defaults.tftest.hcl b/terraform/product/modules/landscape-scalable/tests/defaults.tftest.hcl index 933bc805..8bd977e7 100644 --- a/terraform/product/modules/landscape-scalable/tests/defaults.tftest.hcl +++ b/terraform/product/modules/landscape-scalable/tests/defaults.tftest.hcl @@ -1,4 +1,4 @@ -# © 2025 Canonical Ltd. +# © 2026 Canonical Ltd. mock_provider "juju" {} diff --git a/terraform/product/modules/landscape-scalable/tests/integrations.tftest.hcl b/terraform/product/modules/landscape-scalable/tests/integrations.tftest.hcl index a71962d0..54079b0e 100644 --- a/terraform/product/modules/landscape-scalable/tests/integrations.tftest.hcl +++ b/terraform/product/modules/landscape-scalable/tests/integrations.tftest.hcl @@ -1,4 +1,4 @@ -# © 2025 Canonical Ltd. +# © 2026 Canonical Ltd. mock_provider "juju" {} diff --git a/terraform/product/modules/landscape-scalable/tests/main.tftest.hcl b/terraform/product/modules/landscape-scalable/tests/main.tftest.hcl new file mode 100644 index 00000000..801f563d --- /dev/null +++ b/terraform/product/modules/landscape-scalable/tests/main.tftest.hcl @@ -0,0 +1,21 @@ +# © 2026 Canonical Ltd. + +run "setup_tests" { + module { + source = "./tests/setup" + } +} + +run "basic_deploy" { + variables { + model_uuid = run.setup_tests.model_uuid + landscape_server = { + channel = "26.04/edge" + } + } + + assert { + condition = output.applications.landscape_server.app_name == "landscape-server" + error_message = "landscape-server app_name did not match expected" + } +} diff --git a/terraform/product/modules/landscape-scalable/tests/outputs.tftest.hcl b/terraform/product/modules/landscape-scalable/tests/outputs.tftest.hcl index a86e3d71..ad408a3f 100644 --- a/terraform/product/modules/landscape-scalable/tests/outputs.tftest.hcl +++ b/terraform/product/modules/landscape-scalable/tests/outputs.tftest.hcl @@ -1,4 +1,4 @@ -# © 2025 Canonical Ltd. +# © 2026 Canonical Ltd. mock_provider "juju" {} diff --git a/terraform/product/modules/landscape-scalable/tests/setup/main.tf b/terraform/product/modules/landscape-scalable/tests/setup/main.tf new file mode 100644 index 00000000..65589272 --- /dev/null +++ b/terraform/product/modules/landscape-scalable/tests/setup/main.tf @@ -0,0 +1,21 @@ +# © 2026 Canonical Ltd. + +terraform { + required_version = "~> 1.12" + required_providers { + juju = { + version = "~> 1.0" + source = "juju/juju" + } + } +} + +provider "juju" {} + +resource "juju_model" "test_model" { + name = "tf-testing-${formatdate("YYYYMMDDhhmmss", timestamp())}" +} + +output "model_uuid" { + value = juju_model.test_model.uuid +} diff --git a/terraform/product/modules/landscape-scalable/versions.tf b/terraform/product/modules/landscape-scalable/versions.tf index 72e33ceb..2ed5732e 100644 --- a/terraform/product/modules/landscape-scalable/versions.tf +++ b/terraform/product/modules/landscape-scalable/versions.tf @@ -1,7 +1,7 @@ -# © 2025 Canonical Ltd. +# © 2026 Canonical Ltd. terraform { - required_version = ">= 1.10" + required_version = "~> 1.12" required_providers { juju = { source = "juju/juju" diff --git a/tests/unit/test_charm.py b/tests/unit/test_charm.py index b2df262a..c6ace79a 100644 --- a/tests/unit/test_charm.py +++ b/tests/unit/test_charm.py @@ -1,4 +1,4 @@ -# Copyright 2025 Canonical Ltd +# Copyright 2026 Canonical Ltd # See LICENSE file for licensing details. # # Learn more about testing at diff --git a/tests/unit/test_settings_files.py b/tests/unit/test_settings_files.py index fe526290..4c692165 100644 --- a/tests/unit/test_settings_files.py +++ b/tests/unit/test_settings_files.py @@ -1,4 +1,4 @@ -# Copyright 2025 Canonical Ltd +# Copyright 2026 Canonical Ltd from base64 import b64encode from io import BytesIO, StringIO