From 631f0034a1c5145e5ae69ace9fc0a42a19d40938 Mon Sep 17 00:00:00 2001
From: Felipe Reyes <felipe.reyes@canonical.com>
Date: Mon, 22 May 2023 21:32:37 -0400
Subject: [PATCH] Migrate charm to charmhub

Summary of changes:

- Add charmcraft.yaml to build the charm using charmcraft-2.2
- Add osci.yaml to run CI jobs on zosci
- Align tox.ini and src/tox.ini with the rest of the charms
- Add testing bundles jammy-zed, jammy-antelope and lunar-antelope. The
  other bundles are dropped
- Clean up requirements.txt removing unneeded dependencies
- Update metadata.yaml to declare jammy and lunar only
- Use generic zuul job templates
- Add src/wheelhouse.txt
- Install python3-apt instead of python-apt
- Drop pip.sh
- Drop unneeded pining from test-requirements.txt

Change-Id: I28df31910c869f813682c3b436e5481dc607772e
---
 .gitignore                                    |  1 +
 .zuul.yaml                                    |  2 +-
 charmcraft.yaml                               | 28 ++++++
 metadata.yaml                                 |  1 +
 osci.yaml                                     |  9 ++
 pip.sh                                        | 18 ----
 rename.sh                                     | 13 +++
 requirements.txt                              | 24 +----
 src/lib/charm/openstack/watcher.py            |  2 +-
 src/metadata.yaml                             |  5 +-
 src/tests/bundles/bionic-train.yaml           | 36 --------
 src/tests/bundles/bionic-ussuri.yaml          | 36 --------
 src/tests/bundles/focal-victoria.yaml         | 61 -------------
 src/tests/bundles/groovy-victoria.yaml        | 61 -------------
 src/tests/bundles/jammy-antelope.yaml         | 62 +++++++++++++
 src/tests/bundles/jammy-zed.yaml              | 62 +++++++++++++
 ...{focal-ussuri.yaml => lunar-antelope.yaml} | 53 +++++------
 src/tests/tests.yaml                          | 18 ++--
 src/tox.ini                                   | 23 +++--
 src/wheelhouse.txt                            |  2 +
 test-requirements.txt                         | 48 +---------
 tox.ini                                       | 90 +++++++++----------
 22 files changed, 279 insertions(+), 376 deletions(-)
 create mode 100644 charmcraft.yaml
 create mode 120000 metadata.yaml
 create mode 100644 osci.yaml
 delete mode 100755 pip.sh
 create mode 100755 rename.sh
 delete mode 100644 src/tests/bundles/bionic-train.yaml
 delete mode 100644 src/tests/bundles/bionic-ussuri.yaml
 delete mode 100644 src/tests/bundles/focal-victoria.yaml
 delete mode 100644 src/tests/bundles/groovy-victoria.yaml
 create mode 100644 src/tests/bundles/jammy-antelope.yaml
 create mode 100644 src/tests/bundles/jammy-zed.yaml
 rename src/tests/bundles/{focal-ussuri.yaml => lunar-antelope.yaml} (50%)
 create mode 100644 src/wheelhouse.txt

diff --git a/.gitignore b/.gitignore
index 32ddcf4..8680599 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,3 +7,4 @@ build
 .venv
 cover
 .coverage
+*.charm
diff --git a/.zuul.yaml b/.zuul.yaml
index 0eed196..fd20909 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -1,4 +1,4 @@
 - project:
     templates:
-      - openstack-python3-ussuri-jobs
+      - openstack-python3-charm-jobs
       - openstack-cover-jobs
diff --git a/charmcraft.yaml b/charmcraft.yaml
new file mode 100644
index 0000000..8a4572e
--- /dev/null
+++ b/charmcraft.yaml
@@ -0,0 +1,28 @@
+type: charm
+
+parts:
+  charm:
+    plugin: reactive
+    build-packages:
+      - tox
+      - git
+    source: src/
+    build-packages:
+      - python3-dev
+    build-snaps:
+      - charm
+    build-environment:
+      - CHARM_INTERFACES_DIR: $CRAFT_PROJECT_DIR/interfaces/
+      - CHARM_LAYERS_DIR: $CRAFT_PROJECT_DIR/layers/
+bases:
+  - build-on:
+      - name: ubuntu
+        channel: "22.04"
+        architectures: [amd64]
+    run-on:
+      - name: ubuntu
+        channel: "22.04"
+        architectures: [amd64, arm64, ppc64el, s390x]
+      - name: ubuntu
+        channel: "23.04"
+        architectures: [amd64, arm64, ppc64el, s390x]
diff --git a/metadata.yaml b/metadata.yaml
new file mode 120000
index 0000000..0768683
--- /dev/null
+++ b/metadata.yaml
@@ -0,0 +1 @@
+src/metadata.yaml
\ No newline at end of file
diff --git a/osci.yaml b/osci.yaml
new file mode 100644
index 0000000..d08e6e8
--- /dev/null
+++ b/osci.yaml
@@ -0,0 +1,9 @@
+- project:
+    templates:
+      - charm-unit-jobs
+      - charm-functional-jobs
+    vars:
+      needs_charm_build: true
+      charm_build_name: watcher
+      build_type: charmcraft
+      charmcraft_channel: "2.2/stable"
diff --git a/pip.sh b/pip.sh
deleted file mode 100755
index 9a7e6b0..0000000
--- a/pip.sh
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/usr/bin/env bash
-#
-# This file is managed centrally by release-tools and should not be modified
-# within individual charm repos.  See the 'global' dir contents for available
-# choices of tox.ini for OpenStack Charms:
-#     https://github.com/openstack-charmers/release-tools
-#
-# setuptools 58.0 dropped the support for use_2to3=true which is needed to
-# install blessings (an indirect dependency of charm-tools).
-#
-# More details on the beahvior of tox and virtualenv creation can be found at
-# https://github.com/tox-dev/tox/issues/448
-#
-# This script is wrapper to force the use of the pinned versions early in the
-# process when the virtualenv was created and upgraded before installing the
-# depedencies declared in the target.
-pip install 'pip<20.3' 'setuptools<50.0.0'
-pip "$@"
diff --git a/rename.sh b/rename.sh
new file mode 100755
index 0000000..d0c35c9
--- /dev/null
+++ b/rename.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+charm=$(grep "charm_build_name" osci.yaml | awk '{print $2}')
+echo "renaming ${charm}_*.charm to ${charm}.charm"
+echo -n "pwd: "
+pwd
+ls -al
+echo "Removing bad downloaded charm maybe?"
+if [[ -e "${charm}.charm" ]];
+then
+    rm "${charm}.charm"
+fi
+echo "Renaming charm here."
+mv ${charm}_*.charm ${charm}.charm
diff --git a/requirements.txt b/requirements.txt
index a68620f..9335978 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,23 +1 @@
-# This file is managed centrally by release-tools and should not be modified
-# within individual charm repos.  See the 'global' dir contents for available
-# choices of *requirements.txt files for OpenStack Charms:
-#     https://github.com/openstack-charmers/release-tools
-#
-# NOTE(lourot): This might look like a duplication of test-requirements.txt but
-# some tox targets use only test-requirements.txt whereas charm-build uses only
-# requirements.txt
-setuptools<50.0.0  # https://github.com/pypa/setuptools/commit/04e3df22df840c6bb244e9b27bc56750c44b7c85
-
-# Build requirements
-cffi==1.14.6; python_version < '3.6'  # cffi 1.15.0 drops support for py35.
-charm-tools==2.8.3
-
-simplejson
-
-# Newer versions use keywords that didn't exist in python 3.5 yet (e.g.
-# "ModuleNotFoundError")
-# NOTE(lourot): This might look like a duplication of test-requirements.txt but
-# some tox targets use only test-requirements.txt whereas charm-build uses only
-# requirements.txt
-importlib-metadata<3.0.0; python_version < '3.6'
-importlib-resources<3.0.0; python_version < '3.6'
+charm-tools
diff --git a/src/lib/charm/openstack/watcher.py b/src/lib/charm/openstack/watcher.py
index afce378..1bd836a 100644
--- a/src/lib/charm/openstack/watcher.py
+++ b/src/lib/charm/openstack/watcher.py
@@ -91,7 +91,7 @@ class WatcherCharm(openstack_charm.HAOpenStackCharm):
     packages = [
         'watcher-common', 'watcher-api', 'watcher-decision-engine',
         'watcher-applier', 'python3-watcher', 'libapache2-mod-wsgi-py3',
-        'python-apt',  # NOTE: workaround for hacluster subordinate
+        'python3-apt',  # NOTE: workaround for hacluster subordinate
     ]
 
     python_version = 3
diff --git a/src/metadata.yaml b/src/metadata.yaml
index 2980c20..d9e880f 100644
--- a/src/metadata.yaml
+++ b/src/metadata.yaml
@@ -10,9 +10,8 @@ description: |
 tags:
   - openstack
 series:
-  - bionic
-  - eoan
-  - focal
+  - jammy
+  - lunar
 subordinate: false
 requires:
   shared-db:
diff --git a/src/tests/bundles/bionic-train.yaml b/src/tests/bundles/bionic-train.yaml
deleted file mode 100644
index 7764deb..0000000
--- a/src/tests/bundles/bionic-train.yaml
+++ /dev/null
@@ -1,36 +0,0 @@
-series: bionic
-relations:
-- - mysql:shared-db
-  - keystone:shared-db
-- - mysql:shared-db
-  - watcher:shared-db
-- - keystone:identity-service
-  - watcher:identity-service
-- - rabbitmq-server:amqp
-  - watcher:amqp
-applications:
-  keystone:
-    charm: cs:~openstack-charmers-next/keystone
-    num_units: 1
-    options:
-      openstack-origin: cloud:bionic-train
-  mysql:
-    constraints: mem=3072M
-    charm: cs:~openstack-charmers-next/percona-cluster
-    num_units: 1
-  rabbitmq-server:
-    charm: cs:~openstack-charmers-next/rabbitmq-server
-    num_units: 1
-  watcher:
-    series: bionic
-    charm: ../../../watcher
-    num_units: 1
-    options:
-      openstack-origin: cloud:bionic-train
-      datasources: gnocchi
-      planner: weight
-      planner-config: >
-        {
-            "weights": "change_node_power_state:9,change_nova_service_state:50,migrate:30,nop:70,resize:20,sleep:40,turn_host_to_acpi_s3_state:10,volume_migrate:60",
-            "parallelization": "change_node_power_state:2,change_nova_service_state:1,migrate:2,nop:1,resize:2,sleep:1,turn_host_to_acpi_s3_state:2,volume_migrate:2"
-        }
diff --git a/src/tests/bundles/bionic-ussuri.yaml b/src/tests/bundles/bionic-ussuri.yaml
deleted file mode 100644
index 4f84976..0000000
--- a/src/tests/bundles/bionic-ussuri.yaml
+++ /dev/null
@@ -1,36 +0,0 @@
-series: bionic
-relations:
-- - mysql:shared-db
-  - keystone:shared-db
-- - mysql:shared-db
-  - watcher:shared-db
-- - keystone:identity-service
-  - watcher:identity-service
-- - rabbitmq-server:amqp
-  - watcher:amqp
-applications:
-  keystone:
-    charm: cs:~openstack-charmers-next/keystone
-    num_units: 1
-    options:
-      openstack-origin: cloud:bionic-ussuri
-  mysql:
-    constraints: mem=3072M
-    charm: cs:~openstack-charmers-next/percona-cluster
-    num_units: 1
-  rabbitmq-server:
-    charm: cs:~openstack-charmers-next/rabbitmq-server
-    num_units: 1
-  watcher:
-    series: bionic
-    charm: ../../../watcher
-    num_units: 1
-    options:
-      openstack-origin: cloud:bionic-ussuri
-      datasources: gnocchi
-      planner: weight
-      planner-config: >
-        {
-            "weights": "change_node_power_state:9,change_nova_service_state:50,migrate:30,nop:70,resize:20,sleep:40,turn_host_to_acpi_s3_state:10,volume_migrate:60",
-            "parallelization": "change_node_power_state:2,change_nova_service_state:1,migrate:2,nop:1,resize:2,sleep:1,turn_host_to_acpi_s3_state:2,volume_migrate:2"
-        }
diff --git a/src/tests/bundles/focal-victoria.yaml b/src/tests/bundles/focal-victoria.yaml
deleted file mode 100644
index 9394c87..0000000
--- a/src/tests/bundles/focal-victoria.yaml
+++ /dev/null
@@ -1,61 +0,0 @@
-variables:
-  openstack-origin: &openstack-origin cloud:focal-victoria
-
-series: &series focal
-
-applications:
-
-  keystone-mysql-router:
-    charm: cs:~openstack-charmers-next/mysql-router
-  watcher-mysql-router:
-    charm: cs:~openstack-charmers-next/mysql-router
-
-  mysql-innodb-cluster:
-    charm: cs:~openstack-charmers-next/mysql-innodb-cluster
-    num_units: 3
-    options:
-      source: *openstack-origin
-
-  keystone:
-    charm: cs:~openstack-charmers-next/keystone
-    num_units: 1
-    options:
-      openstack-origin: *openstack-origin
-
-  rabbitmq-server:
-    charm: cs:~openstack-charmers-next/rabbitmq-server
-    num_units: 1
-    options:
-      source: *openstack-origin
-
-  watcher:
-    series: *series
-    charm: ../../../watcher
-    num_units: 1
-    options:
-      openstack-origin: *openstack-origin
-      datasources: gnocchi
-      planner: weight
-      planner-config: >
-        {
-            "weights": "change_node_power_state:9,change_nova_service_state:50,migrate:30,nop:70,resize:20,sleep:40,turn_host_to_acpi_s3_state:10,volume_migrate:60",
-            "parallelization": "change_node_power_state:2,change_nova_service_state:1,migrate:2,nop:1,resize:2,sleep:1,turn_host_to_acpi_s3_state:2,volume_migrate:2"
-        }
-
-relations:
-
-  - - 'keystone:shared-db'
-    - 'keystone-mysql-router:shared-db'
-  - - 'keystone-mysql-router:db-router'
-    - 'mysql-innodb-cluster:db-router'
-
-  - - 'watcher:shared-db'
-    - 'watcher-mysql-router:shared-db'
-  - - 'watcher-mysql-router:db-router'
-    - 'mysql-innodb-cluster:db-router'
-
-  - - 'keystone:identity-service'
-    - 'watcher:identity-service'
-
-  - - 'rabbitmq-server:amqp'
-    - 'watcher:amqp'
diff --git a/src/tests/bundles/groovy-victoria.yaml b/src/tests/bundles/groovy-victoria.yaml
deleted file mode 100644
index a5ab889..0000000
--- a/src/tests/bundles/groovy-victoria.yaml
+++ /dev/null
@@ -1,61 +0,0 @@
-variables:
-  openstack-origin: &openstack-origin distro
-
-series: &series groovy
-
-applications:
-
-  keystone-mysql-router:
-    charm: cs:~openstack-charmers-next/mysql-router
-  watcher-mysql-router:
-    charm: cs:~openstack-charmers-next/mysql-router
-
-  mysql-innodb-cluster:
-    charm: cs:~openstack-charmers-next/mysql-innodb-cluster
-    num_units: 3
-    options:
-      source: *openstack-origin
-
-  keystone:
-    charm: cs:~openstack-charmers-next/keystone
-    num_units: 1
-    options:
-      openstack-origin: *openstack-origin
-
-  rabbitmq-server:
-    charm: cs:~openstack-charmers-next/rabbitmq-server
-    num_units: 1
-    options:
-      source: *openstack-origin
-
-  watcher:
-    series: *series
-    charm: ../../../watcher
-    num_units: 1
-    options:
-      openstack-origin: *openstack-origin
-      datasources: gnocchi
-      planner: weight
-      planner-config: >
-        {
-            "weights": "change_node_power_state:9,change_nova_service_state:50,migrate:30,nop:70,resize:20,sleep:40,turn_host_to_acpi_s3_state:10,volume_migrate:60",
-            "parallelization": "change_node_power_state:2,change_nova_service_state:1,migrate:2,nop:1,resize:2,sleep:1,turn_host_to_acpi_s3_state:2,volume_migrate:2"
-        }
-
-relations:
-
-  - - 'keystone:shared-db'
-    - 'keystone-mysql-router:shared-db'
-  - - 'keystone-mysql-router:db-router'
-    - 'mysql-innodb-cluster:db-router'
-
-  - - 'watcher:shared-db'
-    - 'watcher-mysql-router:shared-db'
-  - - 'watcher-mysql-router:db-router'
-    - 'mysql-innodb-cluster:db-router'
-
-  - - 'keystone:identity-service'
-    - 'watcher:identity-service'
-
-  - - 'rabbitmq-server:amqp'
-    - 'watcher:amqp'
diff --git a/src/tests/bundles/jammy-antelope.yaml b/src/tests/bundles/jammy-antelope.yaml
new file mode 100644
index 0000000..151ff70
--- /dev/null
+++ b/src/tests/bundles/jammy-antelope.yaml
@@ -0,0 +1,62 @@
+variables:
+  openstack-origin: &openstack-origin cloud:jammy-antelope
+
+series: &series jammy
+
+applications:
+
+  keystone-mysql-router:
+    charm: ch:mysql-router
+    channel: latest/edge
+  watcher-mysql-router:
+    charm: ch:mysql-router
+    channel: latest/edge
+
+  mysql-innodb-cluster:
+    charm: ch:mysql-innodb-cluster
+    channel: latest/edge
+    num_units: 3
+    options:
+      source: distro
+
+  keystone:
+    charm: ch:keystone
+    channel: latest/edge
+    num_units: 1
+    options:
+      openstack-origin: *openstack-origin
+
+  rabbitmq-server:
+    charm: ch:rabbitmq-server
+    channel: latest/edge
+    num_units: 1
+    options:
+      source: distro
+
+  watcher:
+    charm: ../../../watcher.charm
+    num_units: 1
+    options:
+      openstack-origin: *openstack-origin
+      debug: True
+      datasources: gnocchi
+      planner: weight
+      planner-config: >
+        {
+            "weights": "change_node_power_state:9,change_nova_service_state:50,migrate:30,nop:70,resize:20,sleep:40,turn_host_to_acpi_s3_state:10,volume_migrate:60",
+            "parallelization": "change_node_power_state:2,change_nova_service_state:1,migrate:2,nop:1,resize:2,sleep:1,turn_host_to_acpi_s3_state:2,volume_migrate:2"
+        }
+
+relations:
+- - 'keystone:shared-db'
+  - 'keystone-mysql-router:shared-db'
+- - 'keystone-mysql-router:db-router'
+  - 'mysql-innodb-cluster:db-router'
+- - 'watcher:shared-db'
+  - 'watcher-mysql-router:shared-db'
+- - 'watcher-mysql-router:db-router'
+  - 'mysql-innodb-cluster:db-router'
+- - 'keystone:identity-service'
+  - 'watcher:identity-service'
+- - 'rabbitmq-server:amqp'
+  - 'watcher:amqp'
diff --git a/src/tests/bundles/jammy-zed.yaml b/src/tests/bundles/jammy-zed.yaml
new file mode 100644
index 0000000..d2e91af
--- /dev/null
+++ b/src/tests/bundles/jammy-zed.yaml
@@ -0,0 +1,62 @@
+variables:
+  openstack-origin: &openstack-origin cloud:jammy-zed
+
+series: &series jammy
+
+applications:
+
+  keystone-mysql-router:
+    charm: ch:mysql-router
+    channel: latest/edge
+  watcher-mysql-router:
+    charm: ch:mysql-router
+    channel: latest/edge
+
+  mysql-innodb-cluster:
+    charm: ch:mysql-innodb-cluster
+    channel: latest/edge
+    num_units: 3
+    options:
+      source: distro
+
+  keystone:
+    charm: ch:keystone
+    channel: latest/edge
+    num_units: 1
+    options:
+      openstack-origin: *openstack-origin
+
+  rabbitmq-server:
+    charm: ch:rabbitmq-server
+    channel: latest/edge
+    num_units: 1
+    options:
+      source: distro
+
+  watcher:
+    charm: ../../../watcher.charm
+    num_units: 1
+    options:
+      openstack-origin: *openstack-origin
+      debug: True
+      datasources: gnocchi
+      planner: weight
+      planner-config: >
+        {
+            "weights": "change_node_power_state:9,change_nova_service_state:50,migrate:30,nop:70,resize:20,sleep:40,turn_host_to_acpi_s3_state:10,volume_migrate:60",
+            "parallelization": "change_node_power_state:2,change_nova_service_state:1,migrate:2,nop:1,resize:2,sleep:1,turn_host_to_acpi_s3_state:2,volume_migrate:2"
+        }
+
+relations:
+- - 'keystone:shared-db'
+  - 'keystone-mysql-router:shared-db'
+- - 'keystone-mysql-router:db-router'
+  - 'mysql-innodb-cluster:db-router'
+- - 'watcher:shared-db'
+  - 'watcher-mysql-router:shared-db'
+- - 'watcher-mysql-router:db-router'
+  - 'mysql-innodb-cluster:db-router'
+- - 'keystone:identity-service'
+  - 'watcher:identity-service'
+- - 'rabbitmq-server:amqp'
+  - 'watcher:amqp'
diff --git a/src/tests/bundles/focal-ussuri.yaml b/src/tests/bundles/lunar-antelope.yaml
similarity index 50%
rename from src/tests/bundles/focal-ussuri.yaml
rename to src/tests/bundles/lunar-antelope.yaml
index 3b4d0ea..8fba371 100644
--- a/src/tests/bundles/focal-ussuri.yaml
+++ b/src/tests/bundles/lunar-antelope.yaml
@@ -1,39 +1,44 @@
 variables:
   openstack-origin: &openstack-origin distro
 
-series: &series focal
+series: &series lunar
 
 applications:
 
   keystone-mysql-router:
-    charm: cs:~openstack-charmers-next/mysql-router
+    charm: ch:mysql-router
+    channel: latest/edge
   watcher-mysql-router:
-    charm: cs:~openstack-charmers-next/mysql-router
+    charm: ch:mysql-router
+    channel: latest/edge
 
   mysql-innodb-cluster:
-    charm: cs:~openstack-charmers-next/mysql-innodb-cluster
+    charm: ch:mysql-innodb-cluster
+    channel: latest/edge
     num_units: 3
     options:
-      source: *openstack-origin
+      source: distro
 
   keystone:
-    charm: cs:~openstack-charmers-next/keystone
+    charm: ch:keystone
+    channel: latest/edge
     num_units: 1
     options:
       openstack-origin: *openstack-origin
 
   rabbitmq-server:
-    charm: cs:~openstack-charmers-next/rabbitmq-server
+    charm: ch:rabbitmq-server
+    channel: latest/edge
     num_units: 1
     options:
-      source: *openstack-origin
+      source: distro
 
   watcher:
-    series: *series
-    charm: ../../../watcher
+    charm: ../../../watcher.charm
     num_units: 1
     options:
       openstack-origin: *openstack-origin
+      debug: True
       datasources: gnocchi
       planner: weight
       planner-config: >
@@ -43,19 +48,15 @@ applications:
         }
 
 relations:
-
-  - - 'keystone:shared-db'
-    - 'keystone-mysql-router:shared-db'
-  - - 'keystone-mysql-router:db-router'
-    - 'mysql-innodb-cluster:db-router'
-
-  - - 'watcher:shared-db'
-    - 'watcher-mysql-router:shared-db'
-  - - 'watcher-mysql-router:db-router'
-    - 'mysql-innodb-cluster:db-router'
-
-  - - 'keystone:identity-service'
-    - 'watcher:identity-service'
-
-  - - 'rabbitmq-server:amqp'
-    - 'watcher:amqp'
+- - 'keystone:shared-db'
+  - 'keystone-mysql-router:shared-db'
+- - 'keystone-mysql-router:db-router'
+  - 'mysql-innodb-cluster:db-router'
+- - 'watcher:shared-db'
+  - 'watcher-mysql-router:shared-db'
+- - 'watcher-mysql-router:db-router'
+  - 'mysql-innodb-cluster:db-router'
+- - 'keystone:identity-service'
+  - 'watcher:identity-service'
+- - 'rabbitmq-server:amqp'
+  - 'watcher:amqp'
diff --git a/src/tests/tests.yaml b/src/tests/tests.yaml
index 4b90592..35777d5 100644
--- a/src/tests/tests.yaml
+++ b/src/tests/tests.yaml
@@ -1,17 +1,17 @@
 charm_name: watcher
 gate_bundles:
-- bionic-train
-- bionic-ussuri
-- focal-ussuri
-- focal-victoria
+- jammy-zed
+- jammy-antelope
+- lunar-antelope
+
 smoke_bundles:
-- focal-ussuri
+- jammy-antelope
+
 configure:
 - zaza.charm_tests.noop.setup.basic_setup
+
 tests:
 - zaza.charm_tests.noop.tests.NoopTest
-dev_bundles:
-  - groovy-victoria
+
 tests_options:
-  force_deploy:
-    - groovy-victoria
+  force_deploy: []
diff --git a/src/tox.ini b/src/tox.ini
index 00c1134..6094813 100644
--- a/src/tox.ini
+++ b/src/tox.ini
@@ -1,29 +1,34 @@
 [tox]
 envlist = pep8
-skipsdist = True
-# NOTE(beisner): Avoid build/test env pollution by not enabling sitepackages.
+# NOTE: Avoid build/test env pollution by not enabling sitepackages.
 sitepackages = False
-# NOTE(beisner): Avoid false positives by not skipping missing interpreters.
+# NOTE: Avoid false positives by not skipping missing interpreters.
 skip_missing_interpreters = False
 
 [testenv]
+# We use tox mainly for virtual environment management for test requirements
+# and do not install the charm code as a Python package into that environment.
+# Ref: https://tox.wiki/en/latest/config.html#skip_install
+skip_install = True
 setenv = VIRTUAL_ENV={envdir}
          PYTHONHASHSEED=0
-whitelist_externals = juju
-passenv = HOME TERM CS_API_* OS_*
+allowlist_externals = juju
+passenv =
+    HOME
+    TERM
+    CS_*
+    OS_*
+    TEST_*
 deps = -r{toxinidir}/test-requirements.txt
-install_command =
-  pip install {opts} {packages}
 
 [testenv:pep8]
 basepython = python3
-deps=charm-tools
 commands = charm-proof
 
 [testenv:func-noop]
 basepython = python3
 commands =
-    true
+    functest-run-suite --help
 
 [testenv:func]
 basepython = python3
diff --git a/src/wheelhouse.txt b/src/wheelhouse.txt
new file mode 100644
index 0000000..c0ad3c2
--- /dev/null
+++ b/src/wheelhouse.txt
@@ -0,0 +1,2 @@
+git+https://github.com/juju/charm-helpers.git#egg=charmhelpers
+git+https://github.com/openstack/charms.openstack.git#egg=charms.openstack
diff --git a/test-requirements.txt b/test-requirements.txt
index 425409b..d5a1447 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -1,49 +1,5 @@
-# This file is managed centrally by release-tools and should not be modified
-# within individual charm repos.  See the 'global' dir contents for available
-# choices of *requirements.txt files for OpenStack Charms:
-#     https://github.com/openstack-charmers/release-tools
-#
-pyparsing<3.0.0  # aodhclient is pinned in zaza and needs pyparsing < 3.0.0, but cffi also needs it, so pin here.
-cffi==1.14.6; python_version < '3.6'  # cffi 1.15.0 drops support for py35.
-setuptools<50.0.0  # https://github.com/pypa/setuptools/commit/04e3df22df840c6bb244e9b27bc56750c44b7c85
-
 stestr>=2.2.0
-
-# Dependency of stestr. Workaround for
-# https://github.com/mtreinish/stestr/issues/145
-cliff<3.0.0
-
-# Dependencies of stestr. Newer versions use keywords that didn't exist in
-# python 3.5 yet (e.g. "ModuleNotFoundError")
-importlib-metadata<3.0.0; python_version < '3.6'
-importlib-resources<3.0.0; python_version < '3.6'
-
-# Some Zuul nodes sometimes pull newer versions of these dependencies which
-# dropped support for python 3.5:
-osprofiler<2.7.0;python_version<'3.6'
-stevedore<1.31.0;python_version<'3.6'
-debtcollector<1.22.0;python_version<'3.6'
-oslo.utils<=3.41.0;python_version<'3.6'
-
-requests>=2.18.4
-charms.reactive
-
-nose>=1.3.7
 coverage>=3.6
+
+charms.reactive
 git+https://github.com/openstack/charms.openstack.git#egg=charms.openstack
-#
-# Revisit for removal / mock improvement:
-#
-# NOTE(lourot): newer versions of cryptography require a Rust compiler to build,
-# see
-# * https://github.com/openstack-charmers/zaza/issues/421
-# * https://mail.python.org/pipermail/cryptography-dev/2021-January/001003.html
-#
-netifaces        # vault
-psycopg2-binary  # vault
-tenacity         # vault
-pbr==5.6.0       # vault
-cryptography<3.4 # vault, keystone-saml-mellon
-lxml             # keystone-saml-mellon
-hvac             # vault, barbican-vault
-psutil           # cinder-lvm
diff --git a/tox.ini b/tox.ini
index faf6092..e960b14 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,47 +1,47 @@
-# Source charm: ./tox.ini
-# This file is managed centrally by release-tools and should not be modified
-# within individual charm repos.  See the 'global' dir contents for available
-# choices of tox.ini for OpenStack Charms:
-#     https://github.com/openstack-charmers/release-tools
-
 [tox]
-skipsdist = True
 envlist = pep8,py3
 # NOTE: Avoid build/test env pollution by not enabling sitepackages.
 sitepackages = False
 # NOTE: Avoid false positives by not skipping missing interpreters.
 skip_missing_interpreters = False
-# NOTES:
-# * We avoid the new dependency resolver by pinning pip < 20.3, see
-#   https://github.com/pypa/pip/issues/9187
-# * Pinning dependencies requires tox >= 3.2.0, see
-#   https://tox.readthedocs.io/en/latest/config.html#conf-requires
-# * It is also necessary to pin virtualenv as a newer virtualenv would still
-#   lead to fetching the latest pip in the func* tox targets, see
-#   https://stackoverflow.com/a/38133283
-requires =
-  pip < 20.3
-  virtualenv < 20.0
-  setuptools<50.0.0
-
-# NOTE: https://wiki.canonical.com/engineering/OpenStack/InstallLatestToxOnOsci
-minversion = 3.18.0
 
 [testenv]
+skip_install = True
 setenv = VIRTUAL_ENV={envdir}
          PYTHONHASHSEED=0
          TERM=linux
-         LAYER_PATH={toxinidir}/layers
-         INTERFACE_PATH={toxinidir}/interfaces
+         CHARM_LAYERS_DIR={toxinidir}/layers
+         CHARM_INTERFACES_DIR={toxinidir}/interfaces
          JUJU_REPOSITORY={toxinidir}/build
-passenv = http_proxy https_proxy INTERFACE_PATH LAYER_PATH JUJU_REPOSITORY
-install_command =
-  {toxinidir}/pip.sh install {opts} {packages}
+passenv =
+    no_proxy
+    http_proxy
+    https_proxy
+    CHARM_INTERFACES_DIR
+    CHARM_LAYERS_DIR
+    JUJU_REPOSITORY
+allowlist_externals =
+    charmcraft
+    bash
+    tox
+    {toxinidir}/rename.sh
 deps =
     -r{toxinidir}/requirements.txt
 
 [testenv:build]
 basepython = python3
+# charmcraft clean is done to ensure that
+# `tox -e build` always performs a clean, repeatable build.
+# For faster rebuilds during development,
+# directly run `charmcraft -v pack && ./rename.sh`.
+commands =
+    charmcraft clean
+    charmcraft -v pack
+    {toxinidir}/rename.sh
+    charmcraft clean
+
+[testenv:build-reactive]
+basepython = python3
 commands =
     charm-build --log-level DEBUG --use-lock-file-branches -o {toxinidir}/build/builds src {posargs}
 
@@ -55,37 +55,35 @@ basepython = python3
 deps = -r{toxinidir}/test-requirements.txt
 commands = stestr run --slowest {posargs}
 
-[testenv:py35]
-basepython = python3.5
-deps = -r{toxinidir}/test-requirements.txt
-commands = stestr run --slowest {posargs}
-
-[testenv:py36]
-basepython = python3.6
-deps = -r{toxinidir}/test-requirements.txt
-commands = stestr run --slowest {posargs}
-
-[testenv:py37]
-basepython = python3.7
-deps = -r{toxinidir}/test-requirements.txt
-commands = stestr run --slowest {posargs}
-
 [testenv:py38]
 basepython = python3.8
 deps = -r{toxinidir}/test-requirements.txt
 commands = stestr run --slowest {posargs}
 
-[testenv:py39]
-basepython = python3.9
+[testenv:py310]
+basepython = python3.10
+deps = -r{toxinidir}/test-requirements.txt
+commands = stestr run --slowest {posargs}
+
+[testenv:py311]
+basepython = python3.11
 deps = -r{toxinidir}/test-requirements.txt
 commands = stestr run --slowest {posargs}
 
 [testenv:pep8]
 basepython = python3
-deps = flake8==3.9.2
-       charm-tools==2.8.3
+deps = flake8
+       charm-tools
 commands = flake8 {posargs} src unit_tests
 
+[testenv:func-target]
+basepython = python3
+changedir = {toxinidir}/src
+deps =
+  -r{toxinidir}/test-requirements.txt
+  -r{toxinidir}/src/test-requirements.txt
+commands = functest-run-suite --keep-model --bundle {posargs}
+
 [testenv:cover]
 # Technique based heavily upon
 # https://github.com/openstack/nova/blob/master/tox.ini