Manage charms¶
See also: Juju | Charm
Deploy a charm¶
The Terraform Provider for Juju does not support deploying a local charm.
To deploy a Charmhub charm, in your Terraform plan add a juju_application resource, specifying the target model and the charm you want to deploy:
resource "juju_application" "this" {
model_uuid = juju_model.development.uuid
charm {
name = "hello-kubecon"
}
}
You can also specify a charm channel and revision. For example:
resource "juju_application" "this" {
model = <model>
charm {
name = "<charm-name>"
channel = "<channel-name>"
revision = "<revision-number>"
}
}
This works as follows:
If both
channelandrevisionare specified (recommended for reproducibility), the Terraform provider will deploy the requested revision.If only
channelis specified, the provider will deploy the latest revision available in that channel. On subsequentterraform applyruns, Terraform keeps the deployed revision unless you change thechannel; changing thechannelrefreshes the application to the latest revision in the new channel.If only
revisionis specified, the provider will try to deploy that revision from the default channel (as set for the charm on Charmhub); if not available, the result will be an error.If neither field is specified, the provider will deploy the latest revision from the default channel (as set for the charm on Charmhub). On subsequent
terraform applyruns, Terraform keeps the deployed revision unless you setchannelorrevision, or refresh the application manually with thejujuCLI.
If the charm has any resources, and your Terraform plan does not specify them explicitly, resources will come from the tip of the specified or inferred channel.
See more:
juju_application(resource)
Compute a charm’s revision automatically¶
For reproducible deployments, we recommend specifying both the charm channel and the charm revision.
For scenarios where you only specify a channel note that the juju_application resource does not automatically pick up newer revisions from the same channel on later terraform apply runs.
Fully specifying all inputs keeps your deployments reproducible, however, it can be cumbersome.
This section shows how to compute a charm’s latest revision (based on a channel and a base) automatically using the built-in juju_charm data source.
The way it works is:
The
juju_charmdata source queries Charmhub for the specified charm, channel, and base.The resolved revision is available as
data.juju_charm.<name>.revision.The
juju_applicationresource references this revision, ensuring reproducible deployments.When you change the
channelorbasevariables and runterraform apply, the data source fetches the new latest revision, and Terraform refreshes the charm.
For example:
locals {
channel = "2/edge"
base = "ubuntu@24.04"
}
data "juju_charm" "alertmanager" {
charm = "alertmanager-k8s"
channel = local.channel
base = local.base
}
resource "juju_application" "alertmanager" {
model_uuid = juju_model.development.uuid
trust = true
charm {
name = "alertmanager-k8s"
channel = local.channel
revision = data.juju_charm.alertmanager.revision
base = local.base
}
}
For deployments with multiple charms, use for_each to query revisions efficiently:
locals {
channel = "2/edge"
base = "ubuntu@24.04"
charms = {
alertmanager = "alertmanager-k8s"
prometheus = "prometheus-k8s"
grafana = "grafana-k8s"
}
}
data "juju_charm" "charms" {
for_each = local.charms
charm = each.value
channel = local.channel
base = local.base
}
resource "juju_application" "apps" {
for_each = local.charms
model_uuid = juju_model.development.uuid
charm {
name = each.value
channel = local.channel
revision = data.juju_charm.charms[each.key].revision
base = local.base
}
}
Update a charm¶
To update a charm, change channel, revision, or base in the application’s charm block and run terraform apply.
resource "juju_application" "this" {
model_uuid = juju_model.development.uuid
charm {
name = "hello-kubecon"
channel = "latest/stable"
}
}
Changing channel in Terraform is equivalent to refreshing the application to a new channel with the juju CLI. If revision is unset, the latest revision in the new channel is applied in-place.
If revision is unset and the channel stays the same, Terraform does not automatically refresh the charm to newer revisions from that same channel on later terraform apply runs. In that case, pin revision for a reproducible deployment, use the juju_charm data source to resolve the current revision automatically, or refresh the application manually with the juju CLI.
Changing channel or revision updates the application in place. Changing base updates Kubernetes applications in place, but changing it for machine charms requires replacement.
When the charm is changed, its resources will also be updated unless pinned.
Tip: You can also use the
juju_charmdata source to automatically fetch the latest revision for a given channel. See Compute a charm’s revision automatically.See more:
juju_application>charm> nested schema
Update a charm when a relation would break¶
When a charm’s relation interface changes between revisions, updating the application while an existing relation is in place causes an error similar to:
cannot upgrade application "<consumer>" to charm "ch:amd64/<consumer>-<revision>":
would break relation "<consumer>:<relation> <offerer>:<relation>"
This happens because Juju refuses to update an application when doing so would invalidate a live relation.
The solution is to use the juju_charm data source to track the relation’s interface name, store it in a terraform_data resource, and attach a replace_triggered_by lifecycle to the juju_integration. When the interface name changes, Terraform will destroy the relation, update the application, and recreate the relation — in the correct order.
locals {
channel = "dev/edge"
}
data "juju_charm" "grafana_info" {
charm = "grafana-k8s"
channel = local.channel
base = "ubuntu@24.04"
}
resource "juju_application" "grafana" {
model_uuid = juju_model.development.uuid
trust = true
charm {
name = "grafana-k8s"
channel = local.channel
revision = data.juju_charm.grafana_info.revision
}
}
resource "juju_application" "traefik" {
model_uuid = juju_model.development.uuid
trust = true
charm {
name = "traefik-k8s"
channel = "latest/stable"
}
}
resource "terraform_data" "interface" {
input = data.juju_charm.grafana_info.requires["ingress"]
}
resource "juju_integration" "ingress" {
model_uuid = juju_model.development.uuid
application {
name = juju_application.traefik.name
}
application {
name = juju_application.grafana.name
endpoint = "ingress"
}
lifecycle {
replace_triggered_by = [
terraform_data.interface
]
}
}
This works as follows:
The
juju_charmdata source fetches the current interface name for theingressendpoint from Charmhub.The
terraform_dataresource stores that interface name. When the channel or revision changes and the interface name changes with it,terraform_data.interfaceis updated.The
replace_triggered_bylifecycle onjuju_integrationdetects the change toterraform_data.interfaceand triggers a replacement of the integration resource.Terraform destroys the integration first, then updates the application, then recreates the integration with the correct endpoint — avoiding the “would break relation” error.
Remove a charm¶
As a charm is just the means by which (an) application(s) are deployed, there is no way to remove the charm / bundle. What you can do, however, is remove the application / model.
See more: Remove an application, Destroy a model