← Back to team overview

canonical-ubuntu-qa team mailing list archive

[Merge] ~andersson123/autopkgtest-cloud:dump-service-bundle-move-to-terraform into autopkgtest-cloud:master

 

Tim Andersson has proposed merging ~andersson123/autopkgtest-cloud:dump-service-bundle-move-to-terraform into autopkgtest-cloud:master.

Requested reviews:
  Canonical's Ubuntu QA (canonical-ubuntu-qa)

For more details, see:
https://code.launchpad.net/~andersson123/autopkgtest-cloud/+git/autopkgtest-cloud/+merge/467108
-- 
Your team Canonical's Ubuntu QA is requested to review the proposed merge of ~andersson123/autopkgtest-cloud:dump-service-bundle-move-to-terraform into autopkgtest-cloud:master.
diff --git a/.launchpad.yaml b/.launchpad.yaml
index bf8ccf2..ac9e82a 100644
--- a/.launchpad.yaml
+++ b/.launchpad.yaml
@@ -14,6 +14,7 @@ jobs:
         ppa: canonical-ubuntu-qa/backport-pre-commit
     snaps:
       - name: yq
+      - name: tflint
     packages:
       - git
       - pre-commit
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 87d3323..574b10e 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -12,6 +12,10 @@ repos:
       - id: end-of-file-fixer
       - id: trailing-whitespace
       - id: check-yaml
+  - repo: https://github.com/antonbabenko/pre-commit-terraform
+    rev: v1.89.1
+    hooks:
+      - id: terraform_tflint
   - repo: https://github.com/shellcheck-py/shellcheck-py
     rev: v0.9.0.5
     hooks:
diff --git a/terraform/local/locals.tf b/terraform/local/locals.tf
new file mode 100644
index 0000000..d1e3ef9
--- /dev/null
+++ b/terraform/local/locals.tf
@@ -0,0 +1,19 @@
+#####################################################
+#####################################################
+# Local variable declarations
+locals {
+    # Everything with XXX needs to be replaced by the dev using this.
+    hostname = "localhost"
+    https_proxy = ""
+    no_proxy = ""
+    storage_host_internal = "XXX"
+    storage_path_internal = "XXX"
+    stage_name = "devel"
+    base = "ubuntu@20.04"
+    releases = "focal jammy noble oracular plucky"
+    channel = "latest/edge"
+    # local_dir = "XXX"
+    local_dir = "/home/andersson123/.local/autopkgtest-cloud/"
+    # model_name = "XXX"
+    model_name = "dev-model"
+}
diff --git a/terraform/local/main.tf b/terraform/local/main.tf
new file mode 100644
index 0000000..f1514c3
--- /dev/null
+++ b/terraform/local/main.tf
@@ -0,0 +1,338 @@
+#####################################################
+#####################################################
+# Application declarations
+
+#####################################################
+# cloud worker applications
+resource "juju_application" "autopkgtest_cloud_worker" {
+  name = "autopkgtest-cloud-worker"
+  model = local.model_name
+
+  charm {
+    name = "ubuntu-release-autopkgtest-cloud-worker"
+    channel = local.channel
+    base = local.base
+  }
+
+  units = 1
+  constraints = "arch=amd64 cores=2 mem=4096M root-disk=20480M"
+
+  config = {
+    # Everything with XXX needs to be replaced by the dev using this.
+    swift-password = file("${local.local_dir}/${local.stage_name}/swift_password")
+    releases = local.releases
+    influxdb-hostname = file("${local.local_dir}/${local.stage_name}/influx-hostname.txt")
+    influxdb-password = file("${local.local_dir}/${local.stage_name}/influx-password.txt")
+    influxdb-database = "XXX"
+    influxdb-username = "XXX"
+    influxdb-context = local.stage_name
+    swift-username = "XXX"
+    swift-region = "XXX"
+    swift-auth-url = "XXX"
+    swift-tenant = "XXX"
+    swift-auth-version = 3
+    swift-project-domain-name = "XXX"
+    swift-project-name = "XXX"
+    swift-user-domain-name = "XXX"
+    nova-rcs = filebase64("${local.local_dir}/${local.stage_name}/novarcs.tar")
+    worker-tmp-cleanup-config = "D /tmp 1777 root root 30d"
+    worker-upstream-percentage = 33
+    stable-release-percentage = 100
+    worker-net-names = <<-EOT
+        default: net_stg-proposed-migration
+        EOT
+    worker-flavor-config = <<-EOT
+        default: autopkgtest
+        big: autopkgtest-big
+        EOT
+    mirror = "http://ftpmaster.internal/ubuntu";
+    worker-args = "ssh -s /CHECKOUTDIR//ssh-setup/nova -- --flavor $PACKAGESIZE --security-groups $SECGROUP --name adt-$RELEASE-$ARCHITECTURE-$PACKAGENAME-$TIMESTAMP-$HOSTNAME-$UUID --image adt/ubuntu-$RELEASE-$HOSTARCH-server --keyname testbed-/HOSTNAME/ --net-id=/NET_NAME/ -e TERM=linux -e 'http_proxy={{ http_proxy }}' -e 'https_proxy={{ https_proxy }}' -e 'no_proxy={{ no_proxy }}' --mirror=/MIRROR/"
+    worker-setup-command = "/AUTOPKGTEST_CLOUD_DIR//worker-config-production/setup-canonical.sh"
+    n-workers = <<-EOT
+        lcy02:
+            amd64: 1  # can add more dc's below as required
+        EOT
+  }
+}
+
+resource "juju_application" "autopkgtest_lxd_worker" {
+  name = "autopkgtest-lxd-worker"
+  model = local.model_name
+
+  charm {
+    name = "ubuntu-release-autopkgtest-cloud-worker"
+    channel = local.channel
+    base = local.base
+  }
+
+  units = 1
+  constraints = "arch=amd64 cores=2 mem=4096M root-disk=20480M"
+  config = {
+    releases = local.releases
+    worker-args = "lxd -r $LXD_REMOTE $LXD_REMOTE:autopkgtest/ubuntu/$RELEASE/$ARCHITECTURE"
+    worker-setup-command2 = "ln -s /dev/null /etc/systemd/system/bluetooth.service; printf \"http_proxy={{ http_proxy }}\nhttps_proxy={{ https_proxy }}\nno_proxy={{ no_proxy }}\n\" >> /etc/environment"
+    lxd-remotes = <<-EOT
+      armhf:
+        10.44.83.56: 3
+      EOT
+  }
+}
+
+#####################################################
+# web applications
+resource "juju_application" "apache2" {
+  name = "apache2"
+  model = local.model_name
+  trust = true
+  charm {
+    name = "apache2"
+    channel = "latest/stable"
+    base = local.base
+  }
+  constraints = "arch=amd64 cores=2 mem=4096M root-disk=20480M"
+  units = 1
+  config = {
+    enable_modules = "include cgi proxy proxy_http remoteip"
+    mpm_type = "prefork"
+  }
+}
+
+resource "juju_application" "autopkgtest_web" {
+  name = "autopkgtest-web"
+
+  model = local.model_name
+
+  charm {
+    name     = "ubuntu-release-autopkgtest-web"
+    channel  = local.channel
+    base = local.base
+  }
+  units = 0
+
+  config = {
+    hostname = local.hostname
+    allowed-requestor-teams = <<-EOT
+        autopkgtest-requestors
+        canonical-foundations
+        canonical-kernel-distro-team
+        canonical-partner-eng
+        canonical-security
+        canonical-server
+        canonical-ubuntu-qa
+        EOT
+    storage-url-internal = "https://${local.storage_host_internal}${local.storage_path_internal}";
+    influxdb-username = "stg_proposed_migration"
+    influxdb-context = "staging"
+    influxdb-hostname = file("${local.local_dir}/${local.stage_name}/influx-hostname.txt")
+    influxdb-password = file("${local.local_dir}/${local.stage_name}/influx-password.txt")
+    influxdb-database = "metrics"
+    github-secrets = file("${local.local_dir}/${local.stage_name}/github-secrets.json")
+    github-status-credentials = file("${local.local_dir}/${local.stage_name}/github-status-credentials.txt")
+    swift-web-credentials = file("${local.local_dir}/${local.stage_name}/swift-web-credentials.conf")
+    public-swift-creds = file("${local.local_dir}/${local.stage_name}/public-swift-creds")
+    external-web-requests-api-keys = file("${local.local_dir}/${local.stage_name}/external-web-requests-api-keys.json")
+    https-proxy = local.https_proxy
+    no-proxy = local.no_proxy
+    cookies = "S0 S1"
+    indexed-packages-fp = "/home/ubuntu/indexed-packages.json"
+  }
+}
+
+#####################################################
+# haproxy applications
+resource "juju_application" "haproxy" {
+  name = "haproxy"
+  model = local.model_name
+  charm {
+    name = "haproxy"
+    base = local.base
+    revision = 79
+  }
+  units = 1
+  constraints = "arch=amd64 cores=2 mem=4098M"
+  config = {
+    default_options = "httplog, dontlognull, forwardfor"
+    services = <<-EOT
+      - service_name: https_service
+        service_host: "::"
+        service_port: 443
+        crts: [DEFAULT]
+        service_options:
+            - acl path_results path_beg /swift/v1/
+            - balance source
+            - cookie SRVNAME insert
+            - timeout client 240s
+            - timeout server 240s
+            - option httpchk HEAD / HTTP/1.0
+            - http-request set-header X-Forwarded-Proto https
+            - http-request capture req.hdr(User-Agent) len 100
+            - http-request replace-pathq  ^/results/(.*)     "${local.storage_path_internal}"/\1
+            - "redirect prefix https://${local.hostname} code 301 unless { hdr(host) -i ${local.hostname} }"
+            - use_backend results_reverse_proxy if path_results
+        server_options: check inter 10000 rise 2 fall 5 maxconn 512 cookie S{i}
+        backends:
+          - backend_name: results_reverse_proxy
+            servers: [[swift, objectstorage.prodstack5.canonical.com, 443, [ssl, verify, required, ca-file /etc/ssl/certs/ca-certificates.crt]]]
+      - service_name: http_redirect_to_https
+        service_host: "::"
+        service_port: 80
+        service_options:
+            - "redirect prefix https://${local.hostname} code 301 unless { hdr(host) -i ${local.hostname} }"
+            - "redirect scheme https code 301 if ! { ssl_fc }"
+      EOT
+    ssl_cert = "DEFAULT"
+    ssl_key = ""
+  }
+}
+
+resource "juju_application" "autocert_haproxy" {
+  name = "autocert-haproxy"
+  model = local.model_name
+  charm {
+    name = "autocert"
+    channel = "latest/stable"
+    revision = 53
+  }
+  units = 0
+  config = {
+    autocert_host = "autocert.canonical.com"
+    cert_additional_names = "${local.hostname}=default"
+    cert_auth_pairs = file("${local.local_dir}/${local.stage_name}/cert_auth_pairs")
+    dir_certs = "/var/lib/haproxy"
+    dir_keys = "/var/lib/haproxy"
+    service_action = "reload"
+    service_name = "haproxy"
+    suffix_cert = ".pem"
+    suffix_chain = ".pem"
+    suffix_key = ".pem"
+  }
+}
+
+#####################################################
+# rabbitmq applications
+resource "juju_application" "rabbitmq_server" {
+  name = "rabbitmq-server"
+  model = local.model_name
+  charm {
+    name = "rabbitmq-server"
+  }
+  units = 1
+  expose {}
+  constraints = "arch=amd64 cores=2 mem=4098M"
+}
+
+
+
+#####################################################
+#####################################################
+# Integration declarations
+
+#####################################################
+# web unit integrations
+resource "juju_integration" "apache2-autopkgtest-web" {
+  model = local.model_name
+  application {
+    name = juju_application.apache2.name
+    endpoint = "apache-website"
+  }
+  application {
+    name = juju_application.autopkgtest_web.name
+    endpoint = "website"
+  }
+  lifecycle {
+    replace_triggered_by = [
+      juju_application.apache2.name,
+      juju_application.apache2.model,
+      juju_application.apache2.constraints,
+      juju_application.apache2.placement,
+      juju_application.apache2.charm.name,
+      juju_application.autopkgtest_web.name,
+      juju_application.autopkgtest_web.model,
+      juju_application.autopkgtest_web.constraints,
+      juju_application.autopkgtest_web.placement,
+      juju_application.autopkgtest_web.charm.name,
+    ]
+  }
+}
+
+#####################################################
+# rabbitmq integrations
+resource "juju_integration" "rabbitmq-autopkgtest-web" {
+  model = local.model_name
+  application {
+    name = juju_application.rabbitmq_server.name
+    endpoint = "amqp"
+  }
+  application {
+    name = juju_application.autopkgtest_web.name
+    endpoint = "amqp"
+  }
+  lifecycle {
+    replace_triggered_by = [
+      juju_application.rabbitmq_server.name,
+      juju_application.rabbitmq_server.model,
+      juju_application.rabbitmq_server.constraints,
+      juju_application.rabbitmq_server.placement,
+      juju_application.rabbitmq_server.charm.name,
+      juju_application.autopkgtest_web.name,
+      juju_application.autopkgtest_web.model,
+      juju_application.autopkgtest_web.constraints,
+      juju_application.autopkgtest_web.placement,
+      juju_application.autopkgtest_web.charm.name,
+    ]
+  }
+}
+
+resource "juju_integration" "rabbitmq-autopkgtest-cloud-worker" {
+  model = local.model_name
+  application {
+    name = juju_application.rabbitmq_server.name
+    endpoint = "amqp"
+  }
+  application {
+    name = juju_application.autopkgtest_cloud_worker.name
+    endpoint = "amqp"
+  }
+  lifecycle {
+    replace_triggered_by = [
+      juju_application.rabbitmq_server.name,
+      juju_application.rabbitmq_server.model,
+      juju_application.rabbitmq_server.constraints,
+      juju_application.rabbitmq_server.placement,
+      juju_application.rabbitmq_server.charm.name,
+      juju_application.autopkgtest_cloud_worker.name,
+      juju_application.autopkgtest_cloud_worker.model,
+      juju_application.autopkgtest_cloud_worker.constraints,
+      juju_application.autopkgtest_cloud_worker.placement,
+      juju_application.autopkgtest_cloud_worker.charm.name,
+    ]
+  }
+}
+
+#####################################################
+# Other integrations
+resource "juju_integration" "haproxy-autocert-haproxy" {
+  model = local.model_name
+  application {
+    name = juju_application.haproxy.name
+    endpoint = "juju-info"
+  }
+  application {
+    name = juju_application.autocert_haproxy.name
+    endpoint = "juju-info"
+  }
+  lifecycle {
+    replace_triggered_by = [
+      juju_application.haproxy.name,
+      juju_application.haproxy.model,
+      juju_application.haproxy.constraints,
+      juju_application.haproxy.placement,
+      juju_application.haproxy.charm.name,
+      juju_application.autocert_haproxy.name,
+      juju_application.autocert_haproxy.model,
+      juju_application.autocert_haproxy.constraints,
+      juju_application.autocert_haproxy.placement,
+      juju_application.autocert_haproxy.charm.name,
+    ]
+  }
+}
diff --git a/terraform/local/providers.tf b/terraform/local/providers.tf
new file mode 100644
index 0000000..9747525
--- /dev/null
+++ b/terraform/local/providers.tf
@@ -0,0 +1,4 @@
+#####################################################
+#####################################################
+# Provider declaration
+provider "juju" {}
diff --git a/terraform/local/versions.tf b/terraform/local/versions.tf
new file mode 100644
index 0000000..e1f982b
--- /dev/null
+++ b/terraform/local/versions.tf
@@ -0,0 +1,9 @@
+terraform {
+  required_version = ">= 1.0"
+  required_providers {
+    juju = {
+      version = "0.15.0"
+      source  = "juju/juju"
+    }
+  }
+}
diff --git a/terraform/prod/locals.tf b/terraform/prod/locals.tf
new file mode 100644
index 0000000..2e4f831
--- /dev/null
+++ b/terraform/prod/locals.tf
@@ -0,0 +1,17 @@
+#####################################################
+#####################################################
+# Local variable declarations
+locals {
+    hostname = "autopkgtest.ubuntu.com"
+    https_proxy = "http://squid.internal:3128";
+    no_proxy = "127.0.0.1,127.0.1.1,login.ubuntu.com,localhost,localdomain,novalocal,internal,archive.ubuntu.com,ports.ubuntu.com,security.ubuntu.com,ddebs.ubuntu.com,changelogs.ubuntu.com,keyserver.ubuntu.com,launchpadlibrarian.net,launchpadcontent.net,launchpad.net,10.24.0.0/24,keystone.ps5.canonical.com,objectstorage.prodstack5.canonical.com"
+    storage_host_internal = "objectstorage.prodstack5.canonical.com:443"
+    storage_path_internal = "/swift/v1/AUTH_0f9aae918d5b4744bf7b827671c86842"
+    stage_name = "production"
+    base = "ubuntu@20.04"
+    releases = "trusty xenial bionic focal jammy noble oracular plucky"
+    channel = "latest/stable"
+    # These values are for ps5
+    local_dir = "/home/prod-proposed-migration-environment/.local/share/mojo/LOCAL/autopkgtest-cloud/"
+    model_name = "prod-proposed-migration-environment"
+}
diff --git a/terraform/prod/main.tf b/terraform/prod/main.tf
new file mode 100644
index 0000000..68d0a52
--- /dev/null
+++ b/terraform/prod/main.tf
@@ -0,0 +1,401 @@
+#####################################################
+#####################################################
+# Application declarations
+
+#####################################################
+# cloud worker applications
+resource "juju_application" "autopkgtest_cloud_worker" {
+  name = "autopkgtest-cloud-worker"
+  model = local.model_name
+
+  charm {
+    name = "ubuntu-release-autopkgtest-cloud-worker"
+    channel = local.channel
+    base = local.base
+  }
+
+  storage_directives = {
+    tmp = "350G"
+  }
+
+  units = 3
+  # This is for testing deployment in environments with a smaller quota.
+  # constraints = "arch=amd64 cores=2 mem=4096M root-disk=20480M root-disk-source=volume"
+  constraints = "arch=amd64 cores=8 mem=16384M root-disk=40960M root-disk-source=volume"
+
+  config = {
+    swift-password = file("${local.local_dir}/${local.stage_name}/swift_password")
+    releases = local.releases
+    influxdb-hostname = file("${local.local_dir}/${local.stage_name}/influx-hostname.txt")
+    influxdb-password = file("${local.local_dir}/${local.stage_name}/influx-password.txt")
+    influxdb-database = "metrics"
+    influxdb-username = "prod_proposed_migration"
+    influxdb-context = local.stage_name
+    swift-username = "prod-proposed-migration-environment"
+    swift-region = "prodstack5"
+    swift-auth-url = "https://keystone.ps5.canonical.com:5000/v3";
+    swift-tenant = "prod-proposed-migration-environment_project"
+    swift-auth-version = "3"
+    swift-project-domain-name = "Default"
+    swift-project-name = "prod-proposed-migration-environment_project"
+    swift-user-domain-name = "Default"
+    nova-rcs = filebase64("${local.local_dir}/${local.stage_name}/novarcs.tar")
+    worker-tmp-cleanup-config = "D /tmp 1777 root root 30d"
+    worker-upstream-percentage = 33
+    stable-release-percentage = 100
+    worker-net-names = <<-EOT
+        default: net_prod-proposed-migration
+        bos03:
+          amd64: net_prod-proposed-migration-amd64
+          ppc64el: net_prod-proposed-migration-ppc64el
+          s390x: net_prod-proposed-migration-s390x
+        EOT
+    worker-flavor-config = <<-EOT
+        default: autopkgtest
+        big: autopkgtest-big
+        bos03:
+          amd64:
+            default: builder-cpu2-ram4-disk20
+            big: builder-cpu4-ram8-disk100
+          ppc64el:
+            default: autopkgtest-ppc64el
+            big: autopkgtest-big-ppc64el
+          s390x:
+            default: autopkgtest-s390x
+            big: autopkgtest-big-s390x
+        EOT
+    mirror = "http://ftpmaster.internal/ubuntu";
+    worker-args = "ssh -s /CHECKOUTDIR//ssh-setup/nova -- --flavor $PACKAGESIZE --security-groups $SECGROUP --name adt-$RELEASE-$ARCHITECTURE-$PACKAGENAME-$TIMESTAMP-$HOSTNAME-$UUID --image adt/ubuntu-$RELEASE-$HOSTARCH-server --keyname testbed-/HOSTNAME/ --net-id=/NET_NAME/ -e TERM=linux -e 'http_proxy={{ http_proxy }}' -e 'https_proxy={{ https_proxy }}' -e 'no_proxy={{ no_proxy }}' --mirror=/MIRROR/"
+    worker-setup-command = "/AUTOPKGTEST_CLOUD_DIR//worker-config-production/setup-canonical.sh"
+    n-workers = <<-EOT
+        lcy02:
+            amd64: 10
+        bos03:
+            amd64: 32
+            arm64: 43
+            ppc64el: 32
+            s390x: 32
+        EOT
+  }
+}
+
+resource "juju_application" "autopkgtest_lxd_worker" {
+  name = "autopkgtest-lxd-worker"
+  model = local.model_name
+
+  charm {
+    name = "ubuntu-release-autopkgtest-cloud-worker"
+    channel = local.channel
+    base = local.base
+  }
+
+  storage_directives = {
+    tmp = "200G"
+  }
+
+  units = 1
+  # This is for test deployment in envs with small quotas.
+  # constraints = "arch=amd64 cores=2 mem=4096M root-disk=20480M root-disk-source=volume"
+  constraints = "arch=amd64 cores=8 mem=16384M root-disk=40960M root-disk-source=volume"
+  config = {
+    releases = local.releases
+    worker-args = "lxd -r $LXD_REMOTE $LXD_REMOTE:autopkgtest/ubuntu/$RELEASE/$ARCHITECTURE"
+    worker-setup-command2 = "ln -s /dev/null /etc/systemd/system/bluetooth.service; printf \"http_proxy={{ http_proxy }}\nhttps_proxy={{ https_proxy }}\nno_proxy={{ no_proxy }}\n\" >> /etc/environment"
+    lxd-remotes = <<-EOT
+      armhf:
+        10.145.243.201: 3  #  lxd-armhf-bos03-01  @  ps6-ra2-arm64-n1
+        10.145.243.115: 3  #  lxd-armhf-bos03-02  @  ps6-ra4-arm64-n1
+        10.145.243.202: 3  #  lxd-armhf-bos03-03  @  ps6-rb1-arm64-n1
+        10.145.243.52:  3  #  lxd-armhf-bos03-04  @  ps6-ra2-arm64-n1
+        10.145.243.234: 3  #  lxd-armhf-bos03-05  @  ps6-rb1-arm64-n1
+        10.145.243.9:   3  #  lxd-armhf-bos03-06  @  ps6-rb1-arm64-n1
+        10.145.243.36:  3  #  lxd-armhf-bos03-07  @  ps6-ra2-arm64-n1
+        10.145.243.28:  3  #  lxd-armhf-bos03-08  @  ps6-ra4-arm64-n1
+        10.145.243.254: 3  #  lxd-armhf-bos03-09  @  ps6-ra2-arm64-n1
+        10.145.243.242: 3  #  lxd-armhf-bos03-10  @  ps6-rb2-arm64-n1
+        10.145.243.171: 3  #  lxd-armhf-bos03-11  @  ps6-ra4-arm64-n1
+        10.145.243.142: 3  #  lxd-armhf-bos03-12  @  ps6-ra2-arm64-n1
+        10.145.243.188: 3  #  lxd-armhf-bos03-13  @  ps6-ra2-arm64-n1
+        10.145.243.141: 3  #  lxd-armhf-bos03-14  @  ps6-rb1-arm64-n1
+        10.145.243.158: 3  #  lxd-armhf-bos03-15  @  ps6-ra2-arm64-n1
+        10.145.243.21:  3  #  lxd-armhf-bos03-16  @  ps6-rb1-arm64-n1
+        10.145.243.227: 3  #  lxd-armhf-bos03-17  @  ps6-ra1-arm64-n1
+        10.145.243.51:  3  #  lxd-armhf-bos03-18  @  ps6-ra1-arm64-n1
+        10.145.243.149: 3  #  lxd-armhf-bos03-19  @  ps6-ra3-arm64-n1
+        10.145.243.247: 3  #  lxd-armhf-bos03-20  @  ps6-ra2-arm64-n1
+        10.145.243.85:  3  #  lxd-armhf-bos03-21  @  ps6-ra4-arm64-n1
+        10.145.243.240: 3  #  lxd-armhf-bos03-22  @  ps6-ra3-arm64-n1
+        10.145.243.27:  3  #  lxd-armhf-bos03-23  @  ps6-ra2-arm64-n1
+        10.145.243.76:  3  #  lxd-armhf-bos03-24  @  ps6-rb1-arm64-n1
+        10.145.243.16:  3  #  lxd-armhf-bos03-25  @  ps6-ra1-arm64-n1
+        10.145.243.232: 3  #  lxd-armhf-bos03-26  @  ps6-ra2-arm64-n1
+        10.145.243.229: 3  #  lxd-armhf-bos03-27  @  ps6-ra3-arm64-n1
+        10.145.243.197: 3  #  lxd-armhf-bos03-28  @  ps6-rb1-arm64-n1
+        10.145.243.184: 3  #  lxd-armhf-bos03-29  @  ps6-ra1-arm64-n1
+        10.145.243.53:  3  #  lxd-armhf-bos03-30  @  ps6-ra2-arm64-n1
+      EOT
+  }
+}
+
+#####################################################
+# web applications
+resource "juju_application" "apache2" {
+  name = "apache2"
+  model = local.model_name
+  trust = true
+  charm {
+    name = "apache2"
+    channel = "latest/stable"
+    base = local.base
+  }
+  # This is for test deployment in envs with small quotas.
+  # constraints = "arch=amd64 cores=2 mem=4096M root-disk=20480M"
+  constraints = "arch=amd64 cores=2 mem=16384M root-disk=51200M"
+  units = 1
+  config = {
+    enable_modules = "include cgi proxy proxy_http remoteip"
+    mpm_type = "prefork"
+  }
+}
+
+resource "juju_application" "autopkgtest_web" {
+  name = "autopkgtest-web"
+
+  model = local.model_name
+
+  charm {
+    name     = "ubuntu-release-autopkgtest-web"
+    channel  = local.channel
+    base = local.base
+  }
+  units = 0
+
+  config = {
+    hostname = local.hostname
+    allowed-requestor-teams = <<-EOT
+        autopkgtest-requestors
+        canonical-foundations
+        canonical-kernel-distro-team
+        canonical-partner-eng
+        canonical-security
+        canonical-server
+        canonical-ubuntu-qa
+        EOT
+    storage_host_internal = local.storage_host_internal
+    storage_path_internal = local.storage_path_internal
+    storage-url-internal = "https://${local.storage_host_internal}${local.storage_path_internal}";
+    influxdb-username = "prod_proposed_migration"
+    influxdb-context = "production"
+    influxdb-hostname = file("${local.local_dir}/${local.stage_name}/influx-hostname.txt")
+    influxdb-password = file("${local.local_dir}/${local.stage_name}/influx-password.txt")
+    influxdb-database = "metrics"
+    github-secrets = file("${local.local_dir}/${local.stage_name}/github-secrets.json")
+    github-status-credentials = file("${local.local_dir}/${local.stage_name}/github-status-credentials.txt")
+    swift-web-credentials = file("${local.local_dir}/${local.stage_name}/swift-web-credentials.conf")
+    public-swift-creds = file("${local.local_dir}/${local.stage_name}/public-swift-creds")
+    external-web-requests-api-keys = file("${local.local_dir}/${local.stage_name}/external-web-requests-api-keys.json")
+    https-proxy = local.https_proxy
+    no-proxy = local.no_proxy
+    cookies = "S0 S1"
+    indexed-packges-fp = "/home/ubuntu/indexed-packages.json"
+  }
+}
+
+#####################################################
+# haproxy applications
+resource "juju_application" "haproxy" {
+  name = "haproxy"
+  model = local.model_name
+  charm {
+    name = "haproxy"
+    base = local.base
+    revision = 79
+  }
+  # placement = juju_machine.haproxy_machine.machine_id
+  units = 1
+  config = {
+    default_options = "httplog, dontlognull, forwardfor"
+    services = <<-EOT
+      - service_name: https_service
+        service_host: "::"
+        service_port: 443
+        crts: [DEFAULT]
+        service_options:
+            - acl path_results path_beg /swift/v1/
+            - balance source
+            - cookie SRVNAME insert
+            - timeout client 240s
+            - timeout server 240s
+            - option httpchk HEAD / HTTP/1.0
+            - http-request set-header X-Forwarded-Proto https
+            - http-request capture req.hdr(User-Agent) len 100
+            - http-request replace-pathq  ^/results/(.*)     "${local.storage_path_internal}"/\1
+            - "redirect prefix https://${local.hostname} code 301 unless { hdr(host) -i ${local.hostname} }"
+            - use_backend results_reverse_proxy if path_results
+        server_options: check inter 10000 rise 2 fall 5 maxconn 512 cookie S{i}
+        backends:
+          - backend_name: results_reverse_proxy
+            servers: [[swift, objectstorage.prodstack5.canonical.com, 443, [ssl, verify, required, ca-file /etc/ssl/certs/ca-certificates.crt]]]
+      - service_name: http_redirect_to_https
+        service_host: "::"
+        service_port: 80
+        service_options:
+            - "redirect prefix https://${local.hostname} code 301 unless { hdr(host) -i ${local.hostname} }"
+            - "redirect scheme https code 301 if ! { ssl_fc }"
+      EOT
+    ssl_cert = "DEFAULT"
+    ssl_key = ""
+  }
+}
+
+resource "juju_application" "autocert_haproxy" {
+  name = "autocert-haproxy"
+  model = local.model_name
+  charm {
+    name = "autocert"
+    channel = "latest/stable"
+    revision = 53
+  }
+  units = 0
+  config = {
+    autocert_host = "autocert.canonical.com"
+    cert_additional_names = "${local.hostname}=default"
+    cert_auth_pairs = file("${local.local_dir}/${local.stage_name}/cert_auth_pairs")
+    dir_certs = "/var/lib/haproxy"
+    dir_keys = "/var/lib/haproxy"
+    service_action = "reload"
+    service_name = "haproxy"
+    suffix_cert = ".pem"
+    suffix_chain = ".pem"
+    suffix_key = ".pem"
+  }
+}
+
+#####################################################
+# rabbitmq applications
+resource "juju_application" "rabbitmq_server" {
+  name = "rabbitmq-server"
+  model = local.model_name
+  charm {
+    name = "rabbitmq-server"
+  }
+  units = 1
+  expose {}
+  constraints = "arch=amd64 mem=8192M root-disk-source=volume"
+}
+
+
+
+#####################################################
+#####################################################
+# Integration declarations
+
+#####################################################
+# web unit integrations
+resource "juju_integration" "apache2-autopkgtest-web" {
+  model = local.model_name
+  application {
+    name = juju_application.apache2.name
+    endpoint = "apache-website"
+  }
+  application {
+    name = juju_application.autopkgtest_web.name
+    endpoint = "website"
+  }
+  lifecycle {
+    replace_triggered_by = [
+      juju_application.apache2.name,
+      juju_application.apache2.model,
+      juju_application.apache2.constraints,
+      juju_application.apache2.placement,
+      juju_application.apache2.charm.name,
+      juju_application.autopkgtest_web.name,
+      juju_application.autopkgtest_web.model,
+      juju_application.autopkgtest_web.constraints,
+      juju_application.autopkgtest_web.placement,
+      juju_application.autopkgtest_web.charm.name,
+    ]
+  }
+}
+
+#####################################################
+# rabbitmq integrations
+resource "juju_integration" "rabbitmq-autopkgtest-web" {
+  model = local.model_name
+  application {
+    name = juju_application.rabbitmq_server.name
+    endpoint = "amqp"
+  }
+  application {
+    name = juju_application.autopkgtest_web.name
+    endpoint = "amqp"
+  }
+  lifecycle {
+    replace_triggered_by = [
+      juju_application.rabbitmq_server.name,
+      juju_application.rabbitmq_server.model,
+      juju_application.rabbitmq_server.constraints,
+      juju_application.rabbitmq_server.placement,
+      juju_application.rabbitmq_server.charm.name,
+      juju_application.autopkgtest_web.name,
+      juju_application.autopkgtest_web.model,
+      juju_application.autopkgtest_web.constraints,
+      juju_application.autopkgtest_web.placement,
+      juju_application.autopkgtest_web.charm.name,
+    ]
+  }
+}
+
+resource "juju_integration" "rabbitmq-autopkgtest-cloud-worker" {
+  model = local.model_name
+  application {
+    name = juju_application.rabbitmq_server.name
+    endpoint = "amqp"
+  }
+  application {
+    name = juju_application.autopkgtest_cloud_worker.name
+    endpoint = "amqp"
+  }
+  lifecycle {
+    replace_triggered_by = [
+      juju_application.rabbitmq_server.name,
+      juju_application.rabbitmq_server.model,
+      juju_application.rabbitmq_server.constraints,
+      juju_application.rabbitmq_server.placement,
+      juju_application.rabbitmq_server.charm.name,
+      juju_application.autopkgtest_cloud_worker.name,
+      juju_application.autopkgtest_cloud_worker.model,
+      juju_application.autopkgtest_cloud_worker.constraints,
+      juju_application.autopkgtest_cloud_worker.placement,
+      juju_application.autopkgtest_cloud_worker.charm.name,
+    ]
+  }
+}
+
+#####################################################
+# Other integrations
+resource "juju_integration" "haproxy-autocert-haproxy" {
+  model = local.model_name
+  application {
+    name = juju_application.haproxy.name
+    endpoint = "juju-info"
+  }
+  application {
+    name = juju_application.autocert_haproxy.name
+    endpoint = "juju-info"
+  }
+  lifecycle {
+    replace_triggered_by = [
+      juju_application.haproxy.name,
+      juju_application.haproxy.model,
+      juju_application.haproxy.constraints,
+      juju_application.haproxy.placement,
+      juju_application.haproxy.charm.name,
+      juju_application.autocert_haproxy.name,
+      juju_application.autocert_haproxy.model,
+      juju_application.autocert_haproxy.constraints,
+      juju_application.autocert_haproxy.placement,
+      juju_application.autocert_haproxy.charm.name,
+    ]
+  }
+}
diff --git a/terraform/prod/providers.tf b/terraform/prod/providers.tf
new file mode 100644
index 0000000..9747525
--- /dev/null
+++ b/terraform/prod/providers.tf
@@ -0,0 +1,4 @@
+#####################################################
+#####################################################
+# Provider declaration
+provider "juju" {}
diff --git a/terraform/prod/versions.tf b/terraform/prod/versions.tf
new file mode 100644
index 0000000..e1f982b
--- /dev/null
+++ b/terraform/prod/versions.tf
@@ -0,0 +1,9 @@
+terraform {
+  required_version = ">= 1.0"
+  required_providers {
+    juju = {
+      version = "0.15.0"
+      source  = "juju/juju"
+    }
+  }
+}
diff --git a/terraform/staging/locals.tf b/terraform/staging/locals.tf
new file mode 100644
index 0000000..449b83c
--- /dev/null
+++ b/terraform/staging/locals.tf
@@ -0,0 +1,17 @@
+#####################################################
+#####################################################
+# Local variable declarations
+locals {
+    hostname = "autopkgtest.staging.ubuntu.com"
+    https_proxy = "http://squid.internal:3128";
+    no_proxy = "127.0.0.1,127.0.1.1,login.ubuntu.com,localhost,localdomain,novalocal,internal,archive.ubuntu.com,ports.ubuntu.com,security.ubuntu.com,ddebs.ubuntu.com,changelogs.ubuntu.com,keyserver.ubuntu.com,launchpadlibrarian.net,launchpadcontent.net,launchpad.net,10.24.0.0/24,keystone.ps5.canonical.com,objectstorage.prodstack5.canonical.com"
+    storage_host_internal = "objectstorage.prodstack5.canonical.com:443"
+    storage_path_internal = "/swift/v1/AUTH_cc509e38c54f4edebda2fd17557309bb"
+    stage_name = "staging"
+    base = "ubuntu@20.04"
+    releases = "focal jammy noble oracular plucky"
+    channel = "latest/edge"
+    # These values are for ps5
+    local_dir = "/home/stg-proposed-migration-environment/.local/share/mojo/LOCAL/autopkgtest-cloud/"
+    model_name = "stg-proposed-migration-environment"
+}
diff --git a/terraform/staging/main.tf b/terraform/staging/main.tf
new file mode 100644
index 0000000..385dc65
--- /dev/null
+++ b/terraform/staging/main.tf
@@ -0,0 +1,366 @@
+#####################################################
+#####################################################
+# Application declarations
+
+#####################################################
+# cloud worker applications
+resource "juju_application" "autopkgtest_cloud_worker" {
+  name = "autopkgtest-cloud-worker"
+  model = local.model_name
+
+  charm {
+    name = "ubuntu-release-autopkgtest-cloud-worker"
+    channel = local.channel
+    base = local.base
+  }
+
+  storage_directives = {
+    tmp = "200G"
+  }
+
+  units = 1
+  # This is for testing deployment in environments with a smaller quota.
+  # constraints = "arch=amd64 cores=2 mem=4096M root-disk=20480M root-disk-source=volume"
+  constraints = "arch=amd64 cores=8 mem=16384M root-disk=40960M root-disk-source=volume"
+
+  config = {
+    swift-password = file("${local.local_dir}/${local.stage_name}/swift_password")
+    releases = local.releases
+    influxdb-hostname = file("${local.local_dir}/${local.stage_name}/influx-hostname.txt")
+    influxdb-password = file("${local.local_dir}/${local.stage_name}/influx-password.txt")
+    influxdb-database = "metrics"
+    influxdb-username = "stg_proposed_migration"
+    influxdb-context = local.stage_name
+    swift-username = "stg-proposed-migration-environment"
+    swift-region = "prodstack5"
+    swift-auth-url = "https://keystone.ps5.canonical.com:5000/v3";
+    swift-tenant = "stg-proposed-migration-environment_project"
+    swift-auth-version = "3"
+    swift-project-domain-name = "Default"
+    swift-project-name = "stg-proposed-migration-environment_project"
+    swift-user-domain-name = "Default"
+    nova-rcs = filebase64("${local.local_dir}/${local.stage_name}/novarcs.tar")
+    worker-tmp-cleanup-config = "D /tmp 1777 root root 30d"
+    worker-upstream-percentage = 33
+    stable-release-percentage = 100
+    worker-net-names = <<-EOT
+        default: net_stg-proposed-migration
+        bos03:
+          ppc64el: net_stg-proposed-migration-ppc64el
+          s390x: net_stg-proposed-migration-s390x
+        EOT
+    worker-flavor-config = <<-EOT
+        default: stag-cpu2-ram4-disk20
+        big: stag-cpu4-ram16-disk50
+        bos03:
+          ppc64el:
+            default: builder-ppc64el-cpu2-ram4-disk20
+            big: builder-ppc64el-cpu2-ram4-disk100
+          s390x:
+            default: autopkgtest-s390x
+            big: autopkgtest-big-s390x
+        EOT
+    mirror = "http://ftpmaster.internal/ubuntu";
+    worker-args = "ssh -s /CHECKOUTDIR//ssh-setup/nova -- --flavor $PACKAGESIZE --security-groups $SECGROUP --name adt-$RELEASE-$ARCHITECTURE-$PACKAGENAME-$TIMESTAMP-$HOSTNAME-$UUID --image adt/ubuntu-$RELEASE-$HOSTARCH-server --keyname testbed-/HOSTNAME/ --net-id=/NET_NAME/ -e TERM=linux -e 'http_proxy={{ http_proxy }}' -e 'https_proxy={{ https_proxy }}' -e 'no_proxy={{ no_proxy }}' --mirror=/MIRROR/"
+    worker-setup-command = "/AUTOPKGTEST_CLOUD_DIR//worker-config-production/setup-canonical.sh"
+    n-workers = <<-EOT
+        lcy02:
+            amd64: 1
+        bos03:
+            amd64: 1
+            arm64: 1
+            ppc64el: 1
+            s390x: 1
+        EOT
+  }
+}
+
+resource "juju_application" "autopkgtest_lxd_worker" {
+  name = "autopkgtest-lxd-worker"
+  model = local.model_name
+
+  charm {
+    name = "ubuntu-release-autopkgtest-cloud-worker"
+    channel = local.channel
+    base = local.base
+  }
+
+  storage_directives = {
+    tmp = "200G"
+  }
+
+  units = 1
+  # This is for test deployment in envs with small quotas.
+  # constraints = "arch=amd64 cores=2 mem=4096M root-disk=20480M root-disk-source=volume"
+  constraints = "arch=amd64 cores=8 mem=16384M root-disk=40960M root-disk-source=volume"
+  config = {
+    releases = local.releases
+    worker-args = "lxd -r $LXD_REMOTE $LXD_REMOTE:autopkgtest/ubuntu/$RELEASE/$ARCHITECTURE"
+    worker-setup-command2 = "ln -s /dev/null /etc/systemd/system/bluetooth.service; printf \"http_proxy={{ http_proxy }}\nhttps_proxy={{ https_proxy }}\nno_proxy={{ no_proxy }}\n\" >> /etc/environment"
+    lxd-remotes = <<-EOT
+      armhf:
+        10.44.83.56: 3
+      EOT
+  }
+}
+
+#####################################################
+# web applications
+resource "juju_application" "apache2" {
+  name = "apache2"
+  model = local.model_name
+  trust = true
+  charm {
+    name = "apache2"
+    channel = "latest/stable"
+    base = local.base
+  }
+  # This is for test deployment in envs with small quotas.
+  # constraints = "arch=amd64 cores=2 mem=4096M root-disk=20480M"
+  constraints = "arch=amd64 cores=2 mem=16384M root-disk=51200M"
+  units = 1
+  config = {
+    enable_modules = "include cgi proxy proxy_http remoteip"
+    mpm_type = "prefork"
+  }
+}
+
+resource "juju_application" "autopkgtest_web" {
+  name = "autopkgtest-web"
+
+  model = local.model_name
+
+  charm {
+    name     = "ubuntu-release-autopkgtest-web"
+    channel  = local.channel
+    base = local.base
+  }
+  units = 0
+
+  config = {
+    hostname = local.hostname
+    allowed-requestor-teams = <<-EOT
+        autopkgtest-requestors
+        canonical-foundations
+        canonical-kernel-distro-team
+        canonical-partner-eng
+        canonical-security
+        canonical-server
+        canonical-ubuntu-qa
+        EOT
+    storage-url-internal = "https://${local.storage_host_internal}${local.storage_path_internal}";
+    influxdb-username = "stg_proposed_migration"
+    influxdb-context = "staging"
+    influxdb-hostname = file("${local.local_dir}/${local.stage_name}/influx-hostname.txt")
+    influxdb-password = file("${local.local_dir}/${local.stage_name}/influx-password.txt")
+    influxdb-database = "metrics"
+    github-secrets = file("${local.local_dir}/${local.stage_name}/github-secrets.json")
+    github-status-credentials = file("${local.local_dir}/${local.stage_name}/github-status-credentials.txt")
+    swift-web-credentials = file("${local.local_dir}/${local.stage_name}/swift-web-credentials.conf")
+    public-swift-creds = file("${local.local_dir}/${local.stage_name}/public-swift-creds")
+    external-web-requests-api-keys = file("${local.local_dir}/${local.stage_name}/external-web-requests-api-keys.json")
+    https-proxy = local.https_proxy
+    no-proxy = local.no_proxy
+    cookies = "S0 S1"
+    indexed-packages-fp = "/home/ubuntu/indexed-packages.json"
+  }
+}
+
+#####################################################
+# haproxy applications
+resource "juju_application" "haproxy" {
+  name = "haproxy"
+  model = local.model_name
+  charm {
+    name = "haproxy"
+    base = local.base
+    revision = 79
+  }
+  # placement = juju_machine.haproxy_machine.machine_id
+  units = 1
+  config = {
+    default_options = "httplog, dontlognull, forwardfor"
+    services = <<-EOT
+      - service_name: https_service
+        service_host: "::"
+        service_port: 443
+        crts: [DEFAULT]
+        service_options:
+            - acl path_results path_beg /swift/v1/
+            - balance source
+            - cookie SRVNAME insert
+            - timeout client 240s
+            - timeout server 240s
+            - option httpchk HEAD / HTTP/1.0
+            - http-request set-header X-Forwarded-Proto https
+            - http-request capture req.hdr(User-Agent) len 100
+            - http-request replace-pathq  ^/results/(.*)     "${local.storage_path_internal}"/\1
+            - "redirect prefix https://${local.hostname} code 301 unless { hdr(host) -i ${local.hostname} }"
+            - use_backend results_reverse_proxy if path_results
+        server_options: check inter 10000 rise 2 fall 5 maxconn 512 cookie S{i}
+        backends:
+          - backend_name: results_reverse_proxy
+            servers: [[swift, objectstorage.prodstack5.canonical.com, 443, [ssl, verify, required, ca-file /etc/ssl/certs/ca-certificates.crt]]]
+      - service_name: http_redirect_to_https
+        service_host: "::"
+        service_port: 80
+        service_options:
+            - "redirect prefix https://${local.hostname} code 301 unless { hdr(host) -i ${local.hostname} }"
+            - "redirect scheme https code 301 if ! { ssl_fc }"
+      EOT
+    ssl_cert = "DEFAULT"
+    ssl_key = ""
+  }
+}
+
+resource "juju_application" "autocert_haproxy" {
+  name = "autocert-haproxy"
+  model = local.model_name
+  charm {
+    name = "autocert"
+    channel = "latest/stable"
+    revision = 53
+  }
+  units = 0
+  config = {
+    autocert_host = "autocert.canonical.com"
+    cert_additional_names = "${local.hostname}=default"
+    cert_auth_pairs = file("${local.local_dir}/${local.stage_name}/cert_auth_pairs")
+    dir_certs = "/var/lib/haproxy"
+    dir_keys = "/var/lib/haproxy"
+    service_action = "reload"
+    service_name = "haproxy"
+    suffix_cert = ".pem"
+    suffix_chain = ".pem"
+    suffix_key = ".pem"
+  }
+}
+
+#####################################################
+# rabbitmq applications
+resource "juju_application" "rabbitmq_server" {
+  name = "rabbitmq-server"
+  model = local.model_name
+  charm {
+    name = "rabbitmq-server"
+  }
+  units = 1
+  expose {}
+  constraints = "arch=amd64 mem=8192M root-disk-source=volume"
+}
+
+
+
+#####################################################
+#####################################################
+# Integration declarations
+
+#####################################################
+# web unit integrations
+resource "juju_integration" "apache2-autopkgtest-web" {
+  model = local.model_name
+  application {
+    name = juju_application.apache2.name
+    endpoint = "apache-website"
+  }
+  application {
+    name = juju_application.autopkgtest_web.name
+    endpoint = "website"
+  }
+  lifecycle {
+    replace_triggered_by = [
+      juju_application.apache2.name,
+      juju_application.apache2.model,
+      juju_application.apache2.constraints,
+      juju_application.apache2.placement,
+      juju_application.apache2.charm.name,
+      juju_application.autopkgtest_web.name,
+      juju_application.autopkgtest_web.model,
+      juju_application.autopkgtest_web.constraints,
+      juju_application.autopkgtest_web.placement,
+      juju_application.autopkgtest_web.charm.name,
+    ]
+  }
+}
+
+#####################################################
+# rabbitmq integrations
+resource "juju_integration" "rabbitmq-autopkgtest-web" {
+  model = local.model_name
+  application {
+    name = juju_application.rabbitmq_server.name
+    endpoint = "amqp"
+  }
+  application {
+    name = juju_application.autopkgtest_web.name
+    endpoint = "amqp"
+  }
+  lifecycle {
+    replace_triggered_by = [
+      juju_application.rabbitmq_server.name,
+      juju_application.rabbitmq_server.model,
+      juju_application.rabbitmq_server.constraints,
+      juju_application.rabbitmq_server.placement,
+      juju_application.rabbitmq_server.charm.name,
+      juju_application.autopkgtest_web.name,
+      juju_application.autopkgtest_web.model,
+      juju_application.autopkgtest_web.constraints,
+      juju_application.autopkgtest_web.placement,
+      juju_application.autopkgtest_web.charm.name,
+    ]
+  }
+}
+
+resource "juju_integration" "rabbitmq-autopkgtest-cloud-worker" {
+  model = local.model_name
+  application {
+    name = juju_application.rabbitmq_server.name
+    endpoint = "amqp"
+  }
+  application {
+    name = juju_application.autopkgtest_cloud_worker.name
+    endpoint = "amqp"
+  }
+  lifecycle {
+    replace_triggered_by = [
+      juju_application.rabbitmq_server.name,
+      juju_application.rabbitmq_server.model,
+      juju_application.rabbitmq_server.constraints,
+      juju_application.rabbitmq_server.placement,
+      juju_application.rabbitmq_server.charm.name,
+      juju_application.autopkgtest_cloud_worker.name,
+      juju_application.autopkgtest_cloud_worker.model,
+      juju_application.autopkgtest_cloud_worker.constraints,
+      juju_application.autopkgtest_cloud_worker.placement,
+      juju_application.autopkgtest_cloud_worker.charm.name,
+    ]
+  }
+}
+
+#####################################################
+# Other integrations
+resource "juju_integration" "haproxy-autocert-haproxy" {
+  model = local.model_name
+  application {
+    name = juju_application.haproxy.name
+    endpoint = "juju-info"
+  }
+  application {
+    name = juju_application.autocert_haproxy.name
+    endpoint = "juju-info"
+  }
+  lifecycle {
+    replace_triggered_by = [
+      juju_application.haproxy.name,
+      juju_application.haproxy.model,
+      juju_application.haproxy.constraints,
+      juju_application.haproxy.placement,
+      juju_application.haproxy.charm.name,
+      juju_application.autocert_haproxy.name,
+      juju_application.autocert_haproxy.model,
+      juju_application.autocert_haproxy.constraints,
+      juju_application.autocert_haproxy.placement,
+      juju_application.autocert_haproxy.charm.name,
+    ]
+  }
+}
diff --git a/terraform/staging/providers.tf b/terraform/staging/providers.tf
new file mode 100644
index 0000000..9747525
--- /dev/null
+++ b/terraform/staging/providers.tf
@@ -0,0 +1,4 @@
+#####################################################
+#####################################################
+# Provider declaration
+provider "juju" {}
diff --git a/terraform/staging/versions.tf b/terraform/staging/versions.tf
new file mode 100644
index 0000000..e1f982b
--- /dev/null
+++ b/terraform/staging/versions.tf
@@ -0,0 +1,9 @@
+terraform {
+  required_version = ">= 1.0"
+  required_providers {
+    juju = {
+      version = "0.15.0"
+      source  = "juju/juju"
+    }
+  }
+}

Follow ups