diff --git a/docs/tutorial/index.rst b/docs/tutorial/index.rst index ba75c2fb..fd1fd2fd 100644 --- a/docs/tutorial/index.rst +++ b/docs/tutorial/index.rst @@ -19,6 +19,16 @@ or COS Lite, Juju-based observability stacks running on Kubernetes. 1. Deploy the observability stack +Refresh +============= + +In this part of the tutorial you will learn how to refresh COS (or COS Lite) to a new channel using Terraform. + +.. toctree:: + :maxdepth: 1 + + 2. Refresh COS to a new channel + Configuration ============= @@ -29,7 +39,7 @@ charm. .. toctree:: :maxdepth: 1 - 2. Sync alert rules from Git + 3. Sync alert rules from Git Instrumentation =============== @@ -41,7 +51,7 @@ application using the Grafana Agent machine charm. .. toctree:: :maxdepth: 1 - 3. Instrument machine charms + 4. Instrument machine charms Redaction @@ -52,4 +62,4 @@ By implementing a solid redaction strategy you can mitigate the risk of unwanted .. toctree:: :maxdepth: 1 - 4. Redact sensitive data + 5. Redact sensitive data diff --git a/docs/tutorial/installation/cos-lite-microk8s-sandbox.md b/docs/tutorial/installation/cos-lite-microk8s-sandbox.md index b3d2ab2a..b18bd1fa 100644 --- a/docs/tutorial/installation/cos-lite-microk8s-sandbox.md +++ b/docs/tutorial/installation/cos-lite-microk8s-sandbox.md @@ -173,6 +173,8 @@ $ juju deploy cos-lite \ --overlay ./storage-small-overlay.yaml ``` +(deploy-cos-ref)= + ## Deploy COS Lite using Terraform Create a `cos-lite-microk8s-sandbox.tf` file with the following Terraform module, or include it in your Terraform plan: diff --git a/docs/tutorial/installation/cos-lite-microk8s-sandbox.tf b/docs/tutorial/installation/cos-lite-microk8s-sandbox.tf index c3d1a1b0..630acc71 100644 --- a/docs/tutorial/installation/cos-lite-microk8s-sandbox.tf +++ b/docs/tutorial/installation/cos-lite-microk8s-sandbox.tf @@ -8,6 +8,8 @@ terraform { } } +# before-cos + resource "juju_model" "cos" { name = "cos" config = { logging-config = "=WARNING; unit=DEBUG" } diff --git a/docs/tutorial/refresh-product-module.md b/docs/tutorial/refresh-product-module.md new file mode 100644 index 00000000..c9f94323 --- /dev/null +++ b/docs/tutorial/refresh-product-module.md @@ -0,0 +1,111 @@ +# Refresh COS to a new channel + +In this example, you will learn how to deploy COS Lite and refresh from channel `2/stable` to `2/edge`. To do this, we can deploy COS Lite via Terraform in the same way as [in the tutorial](https://documentation.ubuntu.com/observability/track-2/tutorial/installation/cos-lite-microk8s-sandbox). + +## Prerequisites + +This tutorial assumes that you already: + +- Know how to deploy {ref}`COS Lite with Terraform ` + +## Introduction + +Imagine you have COS Lite (or COS) deployed on a specific channel like `2/stable` and want to +refresh to a different channel (or track) e.g., `2/edge`. To do so, an admin would have to manually +`juju refresh` each COS charm and address any refresh errors. Alternatively, they can determine the +correct charm `channel` and `revision`(s), update the Terraform module, and apply. + +This is simplified within COS (and COS Lite) by mimicking the `juju refresh` behavior on a product +level, allowing the juju admin to specify a list of charms to refresh within the specified +`track/channel`. The rest is handled by Terraform. + +## Update the COS Lite Terraform module + +Once deployed, we can determine which charms to refresh with the `charms_to_refresh` input variable, detailed in the [README](https://github.com/canonical/observability-stack/tree/main/terraform/cos-lite). This defaults to: all charms owned by the `observability-team`. + +```{note} +This tutorial assumed you have deployed COS Lite from a root module located at `./main.tf`. +``` + +Then, replace `2/stable` with `2/edge` in your `cos-lite` module within the existing `./main.tf` file: + +```{literalinclude} /tutorial/installation/cos-lite-microk8s-sandbox.tf +--- +language: hcl +start-after: "# before-cos" +--- +``` + +```{note} +The `base` input variable for the `cos-lite` module is important if the `track/channel` deploys charms to a different base than the default, detailed in the [README](https://github.com/canonical/observability-stack/tree/main/terraform/cos-lite). +``` + +Finally, add the provider definitions into the same `./main.tf` file: + +```hcl +terraform { + required_providers { + juju = { + source = "juju/juju" + version = "~> 1.0" + } + http = { + source = "hashicorp/http" + version = "~> 3.0" + } + } +} +``` + +At this point, you will have one `main.tf` file ready for deployment. Now you can plan these changes with: + +```shell +terraform plan +``` + +and Terraform plans to update each charm to the latest revision in the `2/edge` channel: + +```shell +Terraform used the selected providers to generate the following +execution plan. Resource actions are indicated with the following +symbols: + + create + ~ update in-place + +Terraform will perform the following actions: + + # module.cos.module.alertmanager.juju_application.alertmanager will be updated in-place + ~ resource "juju_application" "alertmanager" { + +# snip ... + + ~ charm { + ~ channel = "2/stable" -> "2/edge" + name = "alertmanager-k8s" + ~ revision = 191 -> 192 + # (1 unchanged attribute hidden) + } + +# snip ... + +Plan: 0 to add, 5 to change, 0 to destroy. +``` + +and finally apply the changes with: + +```shell +terraform apply +``` + +At this point, you will have successfully upgraded COS Lite from `2/stable` to `2/edge`! + +## Refresh information + +This tutorial only considers upgrading COS Lite. However, the `charmhub` module is product-agnostic +and can be used to refresh charms, and other products e.g., COS. + +You can consult the follow release documentation for refresh compatibility: + +- [how-to cross-track upgrade](/how-to/upgrade/) +- [release policy](/reference/release-policy/) +- [release notes](/reference/release-notes/) diff --git a/terraform/cos-lite/applications.tf b/terraform/cos-lite/applications.tf index dd1bd5ab..5ca748bd 100644 --- a/terraform/cos-lite/applications.tf +++ b/terraform/cos-lite/applications.tf @@ -29,7 +29,7 @@ module "grafana" { config = var.grafana.config constraints = var.grafana.constraints model_uuid = var.model_uuid - revision = var.grafana.revision + revision = data.juju_charm.grafana_info.revision storage_directives = var.grafana.storage_directives units = var.grafana.units } diff --git a/terraform/cos-lite/integrations.tf b/terraform/cos-lite/integrations.tf index b976f953..86622d2c 100644 --- a/terraform/cos-lite/integrations.tf +++ b/terraform/cos-lite/integrations.tf @@ -239,13 +239,16 @@ resource "juju_integration" "grafana_ingress" { application { name = module.traefik.app_name - endpoint = module.traefik.endpoints.ingress } application { name = module.grafana.app_name endpoint = module.grafana.endpoints.ingress } + + lifecycle { + replace_triggered_by = [terraform_data.grafana_ingress_interface] + } } resource "juju_integration" "prometheus_ingress" { diff --git a/terraform/cos-lite/upgrades.tf b/terraform/cos-lite/upgrades.tf new file mode 100644 index 00000000..f3629133 --- /dev/null +++ b/terraform/cos-lite/upgrades.tf @@ -0,0 +1,16 @@ +# -------------- Upgrade logic -------------- + +## -------- grafana.revision >= 174 ---------- +# the ingress endpoint changes from traefik_route to ingress_per_app so we need a lifecycle to +# trigger integration replacement, otherwise the upgrade will fail +data "juju_charm" "grafana_info" { + charm = "grafana-k8s" + channel = var.channel + base = var.base +} + +resource "terraform_data" "grafana_ingress_interface" { + input = data.juju_charm.grafana_info.requires["ingress"] +} + +# -------------- End upgrade logic -------------- \ No newline at end of file diff --git a/terraform/cos-lite/variables.tf b/terraform/cos-lite/variables.tf index 8767a8d5..9df6f36a 100644 --- a/terraform/cos-lite/variables.tf +++ b/terraform/cos-lite/variables.tf @@ -10,16 +10,23 @@ locals { tls_termination = var.external_certificates_offer_url != null ? true : false } +# TODO: Discuss how this was missed bc we don't have any base terraform tests. TF plan would catch this error +variable "base" { + description = "The operating system on which to deploy. E.g. ubuntu@22.04. Changing this value for machine charms will trigger a replace by terraform. Check Charmhub for per-charm base support." + default = "ubuntu@24.04" + type = string +} + variable "channel" { description = "Channel that the applications are (unless overwritten by individual channels) deployed from" type = string default = "dev/edge" - validation { - # the TF Juju provider correctly identifies invalid risks; no need to validate it - condition = startswith(var.channel, "dev/") - error_message = "The track of the channel must be 'dev/'. e.g. 'dev/edge'." - } + # validation { + # # the TF Juju provider correctly identifies invalid risks; no need to validate it + # condition = startswith(var.channel, "dev/") + # error_message = "The track of the channel must be 'dev/'. e.g. 'dev/edge'." + # } } variable "model_uuid" { @@ -81,6 +88,8 @@ variable "catalogue" { description = "Application configuration for Catalogue. For more details: https://registry.terraform.io/providers/juju/juju/latest/docs/resources/application" } +# TODO: Update all charms to surface their channel input, since we will have fine-grained channels per charm +# TODO: Update the channel defaults to be the track variable "grafana" { type = object({ app_name = optional(string, "grafana") diff --git a/tests/integration/cos/tls_external/track-2.tf b/tests/integration/cos/tls_external/track-2.tf index 9766172c..a11343ac 100644 --- a/tests/integration/cos/tls_external/track-2.tf +++ b/tests/integration/cos/tls_external/track-2.tf @@ -47,7 +47,7 @@ module "cos" { source = "git::https://github.com/canonical/observability-stack//terraform/cos?ref=track/2" model_uuid = data.juju_model.cos-model.uuid channel = "2/stable" - internal_tls = "false" + internal_tls = false external_certificates_offer_url = "admin/${var.ca_model}.certificates" external_ca_cert_offer_url = "admin/${var.ca_model}.send-ca-cert" diff --git a/tests/integration/cos/tls_external/track-dev.tf b/tests/integration/cos/tls_external/track-dev.tf index b55c8a24..55b2e8da 100644 --- a/tests/integration/cos/tls_external/track-dev.tf +++ b/tests/integration/cos/tls_external/track-dev.tf @@ -47,7 +47,7 @@ module "cos" { source = "git::https://github.com/canonical/observability-stack//terraform/cos" model_uuid = data.juju_model.cos-model.uuid channel = "dev/edge" - internal_tls = "false" + internal_tls = false external_certificates_offer_url = "admin/${var.ca_model}.certificates" external_ca_cert_offer_url = "admin/${var.ca_model}.send-ca-cert" diff --git a/tests/integration/cos/tls_full/track-2.tf b/tests/integration/cos/tls_full/track-2.tf index ce4b36bd..53d6e62f 100644 --- a/tests/integration/cos/tls_full/track-2.tf +++ b/tests/integration/cos/tls_full/track-2.tf @@ -47,7 +47,7 @@ module "cos" { source = "git::https://github.com/canonical/observability-stack//terraform/cos?ref=track/2" model_uuid = data.juju_model.cos-model.uuid channel = "2/stable" - internal_tls = "true" + internal_tls = true external_certificates_offer_url = "admin/${var.ca_model}.certificates" external_ca_cert_offer_url = "admin/${var.ca_model}.send-ca-cert" diff --git a/tests/integration/cos/tls_full/track-dev.tf b/tests/integration/cos/tls_full/track-dev.tf index e0ad2d26..7296728e 100644 --- a/tests/integration/cos/tls_full/track-dev.tf +++ b/tests/integration/cos/tls_full/track-dev.tf @@ -47,7 +47,7 @@ module "cos" { source = "git::https://github.com/canonical/observability-stack//terraform/cos" model_uuid = data.juju_model.cos-model.uuid channel = "dev/edge" - internal_tls = "true" + internal_tls = true external_certificates_offer_url = "admin/${var.ca_model}.certificates" external_ca_cert_offer_url = "admin/${var.ca_model}.send-ca-cert" diff --git a/tests/integration/cos/tls_internal/track-2.tf b/tests/integration/cos/tls_internal/track-2.tf index 15e31d5a..8d5188fd 100644 --- a/tests/integration/cos/tls_internal/track-2.tf +++ b/tests/integration/cos/tls_internal/track-2.tf @@ -33,7 +33,7 @@ module "cos" { source = "git::https://github.com/canonical/observability-stack//terraform/cos?ref=track/2" model_uuid = data.juju_model.model.uuid channel = "2/stable" - internal_tls = "true" + internal_tls = true s3_endpoint = var.s3_endpoint s3_secret_key = var.s3_secret_key diff --git a/tests/integration/cos/tls_internal/track-dev.tf b/tests/integration/cos/tls_internal/track-dev.tf index c0f76b45..cb4349ee 100644 --- a/tests/integration/cos/tls_internal/track-dev.tf +++ b/tests/integration/cos/tls_internal/track-dev.tf @@ -33,7 +33,7 @@ module "cos" { source = "git::https://github.com/canonical/observability-stack//terraform/cos" model_uuid = data.juju_model.model.uuid channel = "dev/edge" - internal_tls = "true" + internal_tls = true s3_endpoint = var.s3_endpoint s3_secret_key = var.s3_secret_key diff --git a/tests/integration/cos/tls_none/track-2.tf b/tests/integration/cos/tls_none/track-2.tf index 479becba..e92679e1 100644 --- a/tests/integration/cos/tls_none/track-2.tf +++ b/tests/integration/cos/tls_none/track-2.tf @@ -33,7 +33,7 @@ module "cos" { source = "git::https://github.com/canonical/observability-stack//terraform/cos?ref=track/2" model_uuid = data.juju_model.model.uuid channel = "2/stable" - internal_tls = "false" + internal_tls = false s3_endpoint = var.s3_endpoint s3_secret_key = var.s3_secret_key diff --git a/tests/integration/cos/tls_none/track-dev.tf b/tests/integration/cos/tls_none/track-dev.tf index 5707bea3..6d929cec 100644 --- a/tests/integration/cos/tls_none/track-dev.tf +++ b/tests/integration/cos/tls_none/track-dev.tf @@ -33,7 +33,7 @@ module "cos" { source = "git::https://github.com/canonical/observability-stack//terraform/cos" model_uuid = data.juju_model.model.uuid channel = "dev/edge" - internal_tls = "false" + internal_tls = false s3_endpoint = var.s3_endpoint s3_secret_key = var.s3_secret_key diff --git a/tests/integration/cos_lite/tls_external/track-2.tf b/tests/integration/cos_lite/tls_external/track-2.tf index a4920e07..4fe046d6 100644 --- a/tests/integration/cos_lite/tls_external/track-2.tf +++ b/tests/integration/cos_lite/tls_external/track-2.tf @@ -35,7 +35,7 @@ module "cos-lite" { source = "git::https://github.com/canonical/observability-stack//terraform/cos-lite?ref=track/2" model_uuid = data.juju_model.cos-model.uuid channel = "2/stable" - internal_tls = "false" + internal_tls = false external_certificates_offer_url = "admin/${var.ca_model}.certificates" external_ca_cert_offer_url = "admin/${var.ca_model}.send-ca-cert" diff --git a/tests/integration/cos_lite/tls_external/track-dev.tf b/tests/integration/cos_lite/tls_external/track-dev.tf index 8cd3de8f..637404cb 100644 --- a/tests/integration/cos_lite/tls_external/track-dev.tf +++ b/tests/integration/cos_lite/tls_external/track-dev.tf @@ -35,7 +35,7 @@ module "cos-lite" { source = "git::https://github.com/canonical/observability-stack//terraform/cos-lite" model_uuid = data.juju_model.cos-model.uuid channel = "dev/edge" - internal_tls = "false" + internal_tls = false external_certificates_offer_url = "admin/${var.ca_model}.certificates" external_ca_cert_offer_url = "admin/${var.ca_model}.send-ca-cert" diff --git a/tests/integration/cos_lite/tls_full/track-2.tf b/tests/integration/cos_lite/tls_full/track-2.tf index 2e5b67a5..ed12b224 100644 --- a/tests/integration/cos_lite/tls_full/track-2.tf +++ b/tests/integration/cos_lite/tls_full/track-2.tf @@ -35,7 +35,7 @@ module "cos-lite" { source = "git::https://github.com/canonical/observability-stack//terraform/cos-lite?ref=track/2" model_uuid = data.juju_model.cos-model.uuid channel = "2/stable" - internal_tls = "true" + internal_tls = true external_certificates_offer_url = "admin/${var.ca_model}.certificates" external_ca_cert_offer_url = "admin/${var.ca_model}.send-ca-cert" diff --git a/tests/integration/cos_lite/tls_full/track-dev.tf b/tests/integration/cos_lite/tls_full/track-dev.tf index bb4e48a5..e3e689f1 100644 --- a/tests/integration/cos_lite/tls_full/track-dev.tf +++ b/tests/integration/cos_lite/tls_full/track-dev.tf @@ -35,7 +35,7 @@ module "cos-lite" { source = "git::https://github.com/canonical/observability-stack//terraform/cos-lite" model_uuid = data.juju_model.cos-model.uuid channel = "dev/edge" - internal_tls = "true" + internal_tls = true external_certificates_offer_url = "admin/${var.ca_model}.certificates" external_ca_cert_offer_url = "admin/${var.ca_model}.send-ca-cert" diff --git a/tests/integration/cos_lite/tls_internal/track-2.tf b/tests/integration/cos_lite/tls_internal/track-2.tf index fbcbdaa3..2d5ba7e8 100644 --- a/tests/integration/cos_lite/tls_internal/track-2.tf +++ b/tests/integration/cos_lite/tls_internal/track-2.tf @@ -21,7 +21,7 @@ module "cos-lite" { source = "git::https://github.com/canonical/observability-stack//terraform/cos-lite?ref=track/2" model_uuid = data.juju_model.model.uuid channel = "2/stable" - internal_tls = "true" + internal_tls = true traefik = { channel = "latest/edge" } # TODO: Switch to latest/stable when rev257 hits stable } diff --git a/tests/integration/cos_lite/tls_internal/track-dev.tf b/tests/integration/cos_lite/tls_internal/track-dev.tf index 266cb6aa..59394cdc 100644 --- a/tests/integration/cos_lite/tls_internal/track-dev.tf +++ b/tests/integration/cos_lite/tls_internal/track-dev.tf @@ -21,7 +21,7 @@ module "cos-lite" { source = "git::https://github.com/canonical/observability-stack//terraform/cos-lite" model_uuid = data.juju_model.model.uuid channel = "dev/edge" - internal_tls = "true" + internal_tls = true traefik = { channel = "latest/edge" } # TODO: Switch to latest/stable when rev257 hits stable } diff --git a/tests/integration/cos_lite/tls_none/track-2.tf b/tests/integration/cos_lite/tls_none/track-2.tf index e94708d5..60fe604c 100644 --- a/tests/integration/cos_lite/tls_none/track-2.tf +++ b/tests/integration/cos_lite/tls_none/track-2.tf @@ -21,7 +21,7 @@ module "cos-lite" { source = "git::https://github.com/canonical/observability-stack//terraform/cos-lite?ref=track/2" model_uuid = data.juju_model.model.uuid channel = "2/stable" - internal_tls = "false" + internal_tls = false traefik = { channel = "latest/edge" } # TODO: Switch to latest/stable when rev257 hits stable } diff --git a/tests/integration/cos_lite/tls_none/track-dev.tf b/tests/integration/cos_lite/tls_none/track-dev.tf index 3cbe40ef..fe0bcc9c 100644 --- a/tests/integration/cos_lite/tls_none/track-dev.tf +++ b/tests/integration/cos_lite/tls_none/track-dev.tf @@ -21,7 +21,7 @@ module "cos-lite" { source = "git::https://github.com/canonical/observability-stack//terraform/cos-lite" model_uuid = data.juju_model.model.uuid channel = "dev/edge" - internal_tls = "false" + internal_tls = false traefik = { channel = "latest/edge" } # TODO: Switch to latest/stable when rev257 hits stable }