juju / terraform-provider-juju

A Terraform provider for Juju
Apache License 2.0
19 stars 37 forks source link

Existing juju offer cannot be consumed by multiple juju applications in the plan #323

Open wood-push-melon opened 11 months ago

wood-push-melon commented 11 months ago

Description

Multiple juju integrations in juju model A consuming an existing juju offer in juju model B will generate the following error:

Error: Client Error
│ Unable to consume remote offer, got error: cannot add saas application: saas application already exists

Urgency

Blocker for our release

Terraform Juju Provider version

0.8.0,0.9.1

Terraform version

v1.5.2

Terraform Configuration(s)

terraform {
  required_providers {
    juju = {
      source  = "juju/juju"
      version = "~> 0.9.1"
    }
  }

  required_version = ">= 1.5.0"
}

Reproduce / Test

  1. Create a traefik-k8s charm and a juju offer manually in model X.
Model    Controller          Cloud/Region        Version  SLA          Timestamp
traefik  microk8s-localhost  microk8s/localhost  3.2.0    unsupported  01:48:36Z

App             Version  Status  Scale  Charm        Channel      Rev  Address       Exposed  Message
traefik-public  2.10.4   active      1  traefik-k8s  latest/edge  161  10.64.140.44  no

Unit               Workload  Agent  Address      Ports  Message
traefik-public/0*  active    idle   10.1.48.121

Offer           Application     Charm        Rev  Connected  Endpoint  Interface  Role
traefik-public  traefik-public  traefik-k8s  161  4/4        ingress   ingress    provider
  1. Create multiple charmed operators in model Y to consume the offer above in Terraform. The part of the terraform plan output is:
# juju_integration.cmi_integration["0"] will be created
  + resource "juju_integration" "cmi_integration" {
      + id    = (known after apply)
      + model = "identity-platform"

      + application {
          + endpoint  = "public-ingress"
          + name      = "hydra"
          + offer_url = (known after apply)
        }
      + application {
          + endpoint  = (known after apply)
          + offer_url = "admin/traefik.traefik-public"
        }
    }

  # juju_integration.cmi_integration["1"] will be created
  + resource "juju_integration" "cmi_integration" {
      + id    = (known after apply)
      + model = "identity-platform"

      + application {
          + endpoint  = "public-ingress"
          + name      = "kratos"
          + offer_url = (known after apply)
        }
      + application {
          + endpoint  = (known after apply)
          + offer_url = "admin/traefik.traefik-public"
        }
    }

  # juju_integration.cmi_integration["2"] will be created
  + resource "juju_integration" "cmi_integration" {
      + id    = (known after apply)
      + model = "identity-platform"

      + application {
          + endpoint  = "ingress"
          + name      = "login-ui"
          + offer_url = (known after apply)
        }
      + application {
          + endpoint  = (known after apply)
          + offer_url = "admin/traefik.traefik-public"
        }
    }

Debug/Panic Output

The output of terraform apply is:

module.postgresql.juju_application.postgresql: Creating...
juju_application.kratos: Creating...
module.kratos_external_idp_integrator.juju_application.external_idp_integrator: Creating...
juju_application.login_ui: Creating...
juju_application.hydra: Creating...
module.kratos_external_idp_integrator.juju_application.external_idp_integrator: Creation complete after 1s [id=identity-platform:kratos-external-idp-integrator]
juju_application.hydra: Creation complete after 1s [id=identity-platform:hydra]
juju_offer.oauth_offer: Creating...
juju_application.kratos: Creation complete after 1s [id=identity-platform:kratos]
juju_application.login_ui: Creation complete after 1s [id=identity-platform:login-ui]
juju_integration.cmi_integration["0"]: Creating...
juju_integration.cmi_integration["1"]: Creating...
juju_integration.cmi_integration["2"]: Creating...
module.postgresql.juju_application.postgresql: Creation complete after 1s [id=identity-platform:postgresql]
juju_integration.integration["5"]: Creating...
juju_integration.integration["2"]: Creating...
juju_integration.integration["7"]: Creating...
juju_integration.integration["9"]: Creating...
juju_integration.integration["4"]: Creating...
juju_integration.integration["6"]: Creating...
juju_integration.integration["3"]: Creating...
juju_offer.oauth_offer: Creation complete after 5s [id=admin/identity-platform.oauth-offer]
juju_integration.integration["8"]: Creating...
juju_integration.integration["6"]: Creation complete after 6s [id=identity-platform:login-ui:ui-endpoint-info:hydra:ui-endpoint-info]
juju_integration.integration["2"]: Creation complete after 6s [id=identity-platform:kratos-external-idp-integrator:kratos-external-idp:kratos:kratos-external-idp]
juju_integration.integration["1"]: Creating...
juju_integration.integration["0"]: Creating...
juju_integration.integration["5"]: Creation complete after 6s [id=identity-platform:kratos:kratos-endpoint-info:login-ui:kratos-endpoint-info]
juju_integration.integration["4"]: Creation complete after 6s [id=identity-platform:hydra:hydra-endpoint-info:login-ui:hydra-endpoint-info]
juju_integration.cmi_integration["2"]: Creation complete after 6s [id=identity-platform:traefik-public:ingress:login-ui:ingress]
juju_integration.integration["9"]: Creation complete after 6s [id=identity-platform:internal-ingress:ingress:kratos:admin-ingress]
juju_integration.integration["7"]: Creation complete after 6s [id=identity-platform:login-ui:ui-endpoint-info:kratos:ui-endpoint-info]
juju_integration.cmi_integration["0"]: Creation complete after 6s [id=identity-platform:traefik-public:ingress:hydra:public-ingress]
juju_integration.integration["3"]: Creation complete after 6s [id=identity-platform:hydra:hydra-endpoint-info:kratos:hydra-endpoint-info]
juju_integration.integration["8"]: Creation complete after 5s [id=identity-platform:internal-ingress:ingress:hydra:admin-ingress]
juju_integration.integration["0"]: Creation complete after 5s [id=identity-platform:postgresql:database:hydra:pg-database]
juju_integration.integration["1"]: Creation complete after 5s [id=identity-platform:postgresql:database:kratos:pg-database]
╷
│ Error: cannot add saas application "traefik-public": saas application already exists
│
│   with juju_integration.cmi_integration["1"],
│   on integrations.tf line 105, in resource "juju_integration" "cmi_integration":
│  105: resource "juju_integration" "cmi_integration" {

Notes & References

The involved Terraform code can be found in this PR. The integrations with the manually created offer can be found here.

This was originally reported on Mattermost: https://chat.charmhub.io/charmhub/pl/qpuggy3s43fm3ywwn4dypwwzoe

This issue is flaky. It might not show up sometimes.

hmlanigan commented 11 months ago

@wood-push-melon try adding an offer data source and referencing the data source in the integration resources.

The integration resource doc is ambiguous. However resources have the exception of creating things, in this case consuming the supplied offer. We can make some changes however it's more correct to provide the offer data source in your plan. Especially as you have 3 resources referencing it.

wood-push-melon commented 11 months ago

Yeah, I did that in here.

wood-push-melon commented 11 months ago

Attach snapshots of DEBUG and TRACE logs for the terraform plan and terraform apply operations. Search cmi_integrations to reach the problematic integration creations.

And CODE in interest.

hmlanigan commented 9 months ago

@wood-push-melon please provide a simple, one file, reproducer for this problem.

hmlanigan commented 9 months ago

@wood-push-melon are you able to reproduce in v0.10.0?