From f0adcefc647d98610c0101945791cb0b9de38317 Mon Sep 17 00:00:00 2001 From: Guillaume Boutry Date: Wed, 10 Apr 2024 09:56:24 +0200 Subject: [PATCH] Implement openstack-images-sync on k8s Change-Id: Ie9a6559762a1180657f06307674daf4eba559a0f --- .../openstack-images-sync-k8s/CONTRIBUTING.md | 34 +++ charms/openstack-images-sync-k8s/LICENSE | 202 +++++++++++++ charms/openstack-images-sync-k8s/README.md | 66 +++++ .../openstack-images-sync-k8s/charmcraft.yaml | 93 ++++++ charms/openstack-images-sync-k8s/rebuild | 3 + .../requirements.txt | 6 + charms/openstack-images-sync-k8s/src/charm.py | 267 ++++++++++++++++++ .../src/templates/config.yaml.j2 | 20 ++ .../src/templates/http-sync.conf.j2 | 18 ++ .../tests/unit/__init__.py | 15 + .../tests/unit/test_charm.py | 125 ++++++++ common.sh | 11 + tests/core/smoke.yaml.j2 | 22 ++ tests/core/tests.yaml | 4 + .../openstack_images_sync_k8s/__init__.py | 0 .../openstack_images_sync_k8s/tests.py | 51 ++++ zuul.d/jobs.yaml | 31 ++ zuul.d/project-templates.yaml | 6 + zuul.d/secrets.yaml | 142 +++++----- zuul.d/zuul.yaml | 1 + 20 files changed, 1046 insertions(+), 71 deletions(-) create mode 100644 charms/openstack-images-sync-k8s/CONTRIBUTING.md create mode 100644 charms/openstack-images-sync-k8s/LICENSE create mode 100644 charms/openstack-images-sync-k8s/README.md create mode 100644 charms/openstack-images-sync-k8s/charmcraft.yaml create mode 100644 charms/openstack-images-sync-k8s/rebuild create mode 100644 charms/openstack-images-sync-k8s/requirements.txt create mode 100755 charms/openstack-images-sync-k8s/src/charm.py create mode 100644 charms/openstack-images-sync-k8s/src/templates/config.yaml.j2 create mode 100644 charms/openstack-images-sync-k8s/src/templates/http-sync.conf.j2 create mode 100644 charms/openstack-images-sync-k8s/tests/unit/__init__.py create mode 100644 charms/openstack-images-sync-k8s/tests/unit/test_charm.py create mode 100644 tests/local/zaza/sunbeam/charm_tests/openstack_images_sync_k8s/__init__.py create mode 100644 tests/local/zaza/sunbeam/charm_tests/openstack_images_sync_k8s/tests.py diff --git a/charms/openstack-images-sync-k8s/CONTRIBUTING.md b/charms/openstack-images-sync-k8s/CONTRIBUTING.md new file mode 100644 index 00000000..20e88bcc --- /dev/null +++ b/charms/openstack-images-sync-k8s/CONTRIBUTING.md @@ -0,0 +1,34 @@ +# Contributing + +To make contributions to this charm, you'll need a working [development setup](https://juju.is/docs/sdk/dev-setup). + +You can create an environment for development with `tox`: + +```shell +tox devenv -e integration +source venv/bin/activate +``` + +## Testing + +This project uses `tox` for managing test environments. There are some pre-configured environments +that can be used for linting and formatting code when you're preparing contributions to the charm: + +```shell +tox run -e format # update your code according to linting rules +tox run -e lint # code style +tox run -e static # static type checking +tox run -e unit # unit tests +tox run -e integration # integration tests +tox # runs 'format', 'lint', 'static', and 'unit' environments +``` + +## Build the charm + +Build the charm in this git repository using: + +```shell +charmcraft pack +``` + + + +[contributors-guide]: https://opendev.org/openstack/sunbeam-charms/src/branch/main/charms/openstack-images-sync-k8s/CONTRIBUTING.md +[juju-docs-actions]: https://jaas.ai/docs/actions +[juju-docs-config-apps]: https://juju.is/docs/configuring-applications +[lp-bugs-charm-ois-k8s]: https://bugs.launchpad.net/sunbeam-charms/+filebug diff --git a/charms/openstack-images-sync-k8s/charmcraft.yaml b/charms/openstack-images-sync-k8s/charmcraft.yaml new file mode 100644 index 00000000..e3049ed9 --- /dev/null +++ b/charms/openstack-images-sync-k8s/charmcraft.yaml @@ -0,0 +1,93 @@ +name: openstack-images-sync-k8s + +type: charm + +title: OpenStack Images Sync K8S + +summary: Keep OpenStack images in sync with the latest versions + +description: | + Openstack Images Sync operator allows synchronization from a SimpleStreams source to an OpenStack cloud. + +bases: + - build-on: + - name: ubuntu + channel: "22.04" + run-on: + - name: ubuntu + channel: "22.04" + +config: + options: + debug: + default: False + type: boolean + frequency: + default: hourly + description: | + The frequency at which the charm should check for new images. + Valid values are hourly, daily, weekly. + type: string + architecture: + default: amd64 + description: | + The architectures to sync images for. Space delimited list of architectures. + type: string + release: + default: focal jammy + description: | + The releases to sync images for. Space delimited list of releases. + type: string + cloud-name: + default: simplestreams-glance-sync + description: | + The name of the cloud to sync images for. + type: string + max-items: + default: 1 + description: | + The maximum number of images to keep in sync per version. + type: int + os-admin-hostname: + default: openstack-images-sync.juju + description: | + The hostname or address of the admin endpoints that should be advertised + in the openstack image sync. + type: string + os-internal-hostname: + default: openstack-images-sync.juju + description: | + The hostname or address of the internal endpoints that should be advertised + in the openstack image sync. + type: string + os-public-hostname: + default: openstack-images-sync.juju + description: | + The hostname or address of the internal endpoints that should be advertised + in the openstack image sync. + type: string + region: + default: RegionOne + description: Space delimited list of OpenStack regions + type: string + +containers: + openstack-images-sync: + resource: openstack-images-sync-image + +resources: + openstack-images-sync-image: + type: oci-image + description: OCI image for OpenStack Images Sync + upstream-source: ghcr.io/canonical/openstack-images-sync:2024.1 + +requires: + ingress-internal: + interface: ingress + limit: 1 + optional: true + ingress-public: + interface: ingress + limit: 1 + identity-service: + interface: keystone diff --git a/charms/openstack-images-sync-k8s/rebuild b/charms/openstack-images-sync-k8s/rebuild new file mode 100644 index 00000000..2358b681 --- /dev/null +++ b/charms/openstack-images-sync-k8s/rebuild @@ -0,0 +1,3 @@ +# This file is used to trigger a build. +# Change uuid to trigger a new build. +886a46db-8f02-4271-a825-91153f83c579 diff --git a/charms/openstack-images-sync-k8s/requirements.txt b/charms/openstack-images-sync-k8s/requirements.txt new file mode 100644 index 00000000..00cb1d4d --- /dev/null +++ b/charms/openstack-images-sync-k8s/requirements.txt @@ -0,0 +1,6 @@ +ops +jinja2 +lightkube +lightkube-models + +tenacity diff --git a/charms/openstack-images-sync-k8s/src/charm.py b/charms/openstack-images-sync-k8s/src/charm.py new file mode 100755 index 00000000..86a3e806 --- /dev/null +++ b/charms/openstack-images-sync-k8s/src/charm.py @@ -0,0 +1,267 @@ +#!/usr/bin/env python3 + +# +# Copyright 2024 Canonical Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Openstack Images Sync Operator. + +This charm deploys the openstack images sync service on Kubernetes. +""" + +import logging +import os +from typing import ( + TYPE_CHECKING, +) + +import ops +import ops_sunbeam.charm as sunbeam_charm +import ops_sunbeam.config_contexts as sunbeam_config_contexts +import ops_sunbeam.container_handlers as sunbeam_chandlers +import ops_sunbeam.core as sunbeam_core +from charms.keystone_k8s.v1.identity_service import ( + IdentityServiceRequires, +) + +logger = logging.getLogger(__name__) + + +def _frequency_to_seconds(frequency: str) -> int: + """Convert given frequency word to seconds. + + test-do-not-use is for testing purposes only. + """ + match frequency: + case "hourly": + return 3600 + case "daily": + return 86400 + case "weekly": + return 604800 + case "test-do-not-use": + return 30 + case _: + raise ValueError(f"Unknown frequency {frequency!r}") + + +class SyncCharmConfigContext(sunbeam_config_contexts.CharmConfigContext): + """Configure context for templates.""" + + def context(self) -> dict: + """Return context for template rendering.""" + return { + **self.charm.config, + "architecture": "|".join( + self.charm.config["architecture"].split() + ), + "release": "|".join(self.charm.config["release"].split()), + "region": ", ".join(self.charm.config["region"].split()), + "frequency": _frequency_to_seconds(self.charm.config["frequency"]), + } + + +class HttpSyncConfigContext(sunbeam_config_contexts.ConfigContext): + """Configuration context for the http sync service.""" + + if TYPE_CHECKING: + charm: "OpenstackImagesSyncK8SCharm" + + def context(self) -> dict: + """Httpd configuration options.""" + return { + "name": self.charm.service_name, + "public_port": self.charm.default_public_ingress_port, + "error_log": "/dev/stdout", + "custom_log": "/dev/stdout", + } + + +class OpenstackImagesSyncPebbleHandler(sunbeam_chandlers.ServicePebbleHandler): + """Handler for openstack images sync container.""" + + if TYPE_CHECKING: + charm: "OpenstackImagesSyncK8SCharm" + + @property + def directories(self) -> list[sunbeam_chandlers.ContainerDir]: + """List of directories to create in container.""" + return [ + sunbeam_chandlers.ContainerDir( + "/var/www/html/simplestreams", + self.charm.service_user, + self.charm.service_group, + ), + ] + + def get_layer(self) -> dict: + """Openstack Images Sync service pebble layer. + + :returns: pebble layer configuration for openstack images sync service + """ + return { + "summary": f"{self.service_name} layer", + "description": f"pebble config layer for {self.service_name}", + "services": { + "images-sync": { + "override": "replace", + "summary": self.service_name, + "command": ( + "/usr/bin/openstack-images-sync sync" + " --config /etc/openstack-images-sync/config.yaml" + ), + "user": "_daemon_", + "group": "_daemon_", + "environment": { + **self.charm.keystone_auth(), + **self.charm.proxy_env(), + }, + }, + "http-mirror": { + "override": "replace", + "summary": "apache", + "command": "/usr/sbin/apache2ctl -DFOREGROUND", + }, + }, + } + + def init_service(self, context: sunbeam_core.OPSCharmContexts) -> None: + """Initialise service ready for use. + + Write configuration files to the container and record + that service is ready for us. Enable apache modules. + """ + self.execute(["a2dissite", "000-default"], exception_on_error=True) + return super().init_service(context) + + +class OpenstackImagesSyncK8SCharm(sunbeam_charm.OSBaseOperatorAPICharm): + """Charm the application.""" + + service_name = "openstack-images-sync" + mandatory_relations = { + "identity-service", + "ingress-public", + } + + @property + def service_conf(self) -> str: + """Service default configuration file.""" + return "/etc/openstack-images-sync/config.yaml" + + @property + def service_user(self) -> str: + """Service user file and directory ownership.""" + return "_daemon_" + + @property + def service_group(self) -> str: + """Service group file and directory ownership.""" + return "_daemon_" + + @property + def default_public_ingress_port(self) -> int: + """Default ingress port.""" + return 80 + + @property + def service_endpoints(self): + """Describe the openstack images sync service endpoint.""" + slash_region = "/" + self.config["region"].split()[0] + return [ + { + "service_name": "image-stream", + "type": "product-streams", + "description": "Image stream service", + "internal_url": self.internal_url + slash_region, + "public_url": self.public_url + slash_region, + "admin_url": self.admin_url + slash_region, + } + ] + + @property + def config_contexts(self) -> list[sunbeam_config_contexts.ConfigContext]: + """Generate list of configuration adapters for the charm.""" + return [ + SyncCharmConfigContext(self, "options"), + # don't use wsgi-context here + HttpSyncConfigContext(self, "httpd_config"), + ] + + def get_pebble_handlers(self) -> list[sunbeam_chandlers.PebbleHandler]: + """Pebble handlers for the service.""" + return [ + OpenstackImagesSyncPebbleHandler( + self, + self.service_name, + self.service_name, + self.container_configs, + self.template_dir, + self.configure_charm, + ) + ] + + @property + def container_configs(self) -> list[sunbeam_core.ContainerConfigFile]: + """Container configurations for the operator.""" + _cconfigs = [ + sunbeam_core.ContainerConfigFile( + self.service_conf, + self.service_user, + self.service_group, + 0o640, + ), + sunbeam_core.ContainerConfigFile( + "/etc/apache2/sites-enabled/http-sync.conf", + "root", + "root", + 0o640, + ), + ] + return _cconfigs + + def keystone_auth(self) -> dict[str, str]: + """Keystone authentication.""" + if self.id_svc.ready: + interface: IdentityServiceRequires = self.id_svc.interface # type: ignore + return { + # Using public auth url because openstack-images-sync will output an index.json + # referencing this auth url. Later on, client will want to match the clouds and + # will use a combo of auth_url + region. + "OS_AUTH_URL": interface.public_auth_url, + "OS_IDENTITY_API_VERSION": "3", + "OS_USERNAME": interface.service_user_name, + "OS_PASSWORD": interface.service_password, + "OS_PROJECT_NAME": interface.service_project_name, + "OS_USER_DOMAIN_NAME": interface.service_domain_name, + "OS_PROJECT_DOMAIN_NAME": interface.service_domain_name, + } + return {} + + def proxy_env(self) -> dict[str, str]: + """Get proxy settings from environment.""" + juju_proxy_vars = [ + "JUJU_CHARM_HTTP_PROXY", + "JUJU_CHARM_HTTPS_PROXY", + "JUJU_CHARM_NO_PROXY", + ] + return { + proxy_var.removeprefix("JUJU_CHARM_"): value + for proxy_var in juju_proxy_vars + if (value := os.environ.get(proxy_var)) + } + + +if __name__ == "__main__": # pragma: nocover + ops.main(OpenstackImagesSyncK8SCharm) # type: ignore diff --git a/charms/openstack-images-sync-k8s/src/templates/config.yaml.j2 b/charms/openstack-images-sync-k8s/src/templates/config.yaml.j2 new file mode 100644 index 00000000..b4bd5394 --- /dev/null +++ b/charms/openstack-images-sync-k8s/src/templates/config.yaml.j2 @@ -0,0 +1,20 @@ +cloud_name: {{ options.cloud_name}} +frequency: {{ options.frequency }} +mirrors: +- content_id: '%(region)s' # Content ID choice + custom_properties: {} + hypervisor_mapping: false + image_conversion: false + item_filters: + - release~({{ options.release }}) + - arch~({{ options.architecture }}) + - ftype~(disk1.img|disk.img) + keep_items: false + latest_property: false + max_items: {{ options.max_items }} + url: http://cloud-images.ubuntu.com/releases + path: streams/v1/index.sjson + regions: [{{ options.region }}] + visibility: public +name_prefix: auto-sync/ +output_directory: /var/www/html/simplestreams diff --git a/charms/openstack-images-sync-k8s/src/templates/http-sync.conf.j2 b/charms/openstack-images-sync-k8s/src/templates/http-sync.conf.j2 new file mode 100644 index 00000000..e01e9c56 --- /dev/null +++ b/charms/openstack-images-sync-k8s/src/templates/http-sync.conf.j2 @@ -0,0 +1,18 @@ +Listen {{ httpd_config.public_port }} + + + DocumentRoot "/var/www/html/simplestreams" + + {% if ingress_public and ingress_public.ingress_path %} + Alias {{ ingress_public.ingress_path }} "/var/www/html/simplestreams" + {% endif %} + + + Options Indexes + AllowOverride None + Require all granted + + + ErrorLog {{ httpd_config.error_log }} + CustomLog {{ httpd_config.custom_log }} combined + diff --git a/charms/openstack-images-sync-k8s/tests/unit/__init__.py b/charms/openstack-images-sync-k8s/tests/unit/__init__.py new file mode 100644 index 00000000..19f143b5 --- /dev/null +++ b/charms/openstack-images-sync-k8s/tests/unit/__init__.py @@ -0,0 +1,15 @@ +# Copyright 2024 Canonical Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Unit tests for charm.""" diff --git a/charms/openstack-images-sync-k8s/tests/unit/test_charm.py b/charms/openstack-images-sync-k8s/tests/unit/test_charm.py new file mode 100644 index 00000000..f8e0f9f2 --- /dev/null +++ b/charms/openstack-images-sync-k8s/tests/unit/test_charm.py @@ -0,0 +1,125 @@ +#!/usr/bin/env python3 + +# Copyright 2024 Canonical Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Tests for openstack images sync charm.""" +import pathlib + +import charm +import ops_sunbeam.test_utils as test_utils +import yaml + +charmcraft = ( + pathlib.Path(__file__).parents[2] / "charmcraft.yaml" +).read_text() +config = yaml.dump(yaml.safe_load(charmcraft)["config"]) + + +class _OISOperatorCharm(charm.OpenstackImagesSyncK8SCharm): + """Openstack Images Sync test charm.""" + + def __init__(self, framework): + """Setup event logging.""" + self.seen_events = [] + super().__init__(framework) + + def _log_event(self, event): + """Log events.""" + self.seen_events.append(type(event).__name__) + + def configure_charm(self, event): + """Log configure charm call.""" + super().configure_charm(event) + self._log_event(event) + + @property + def public_ingress_address(self): + """Ingress address for charm.""" + return "openstack-images-sync.juju" + + +class TestOISOperatorCharm(test_utils.CharmTestCase): + """Classes for testing openstack images sync charms.""" + + PATCHES = [] + maxDiff = None + + def setUp(self): + """Setup openstack images sync tests.""" + super().setUp(charm, self.PATCHES) + self.harness = test_utils.get_harness( + _OISOperatorCharm, + charm_metadata=charmcraft, + container_calls=self.container_calls, + charm_config=config, + ) + + self.addCleanup(self.harness.cleanup) + self.harness.begin() + + def test_pebble_ready_handler(self): + """Test Pebble ready event is captured.""" + self.assertEqual(self.harness.charm.seen_events, []) + test_utils.set_all_pebbles_ready(self.harness) + self.assertEqual(self.harness.charm.seen_events, ["PebbleReadyEvent"]) + + def test_all_relations(self): + """Test all the charms relations.""" + self.harness.set_leader() + test_utils.set_all_pebbles_ready(self.harness) + test_utils.add_all_relations(self.harness) + id_svc_rel = self.harness.model.get_relation("identity-service") + self.harness.update_relation_data( + id_svc_rel.id, "keystone", {"service-domain-id": "svcdomid"} + ) + test_utils.add_complete_ingress_relation(self.harness) + + setup_cmds = [ + ["a2dissite", "000-default"], + ] + for cmd in setup_cmds: + self.assertIn( + cmd, + self.container_calls.execute[self.harness.charm.service_name], + ) + self.check_file( + self.harness.charm.service_name, + "/etc/apache2/sites-enabled/http-sync.conf", + ) + expect_entries = """cloud_name: simplestreams-glance-sync +frequency: 3600 +mirrors: +- content_id: '%(region)s' # Content ID choice + custom_properties: {} + hypervisor_mapping: false + image_conversion: false + item_filters: + - release~(focal|jammy) + - arch~(amd64) + - ftype~(disk1.img|disk.img) + keep_items: false + latest_property: false + max_items: 1 + url: http://cloud-images.ubuntu.com/releases + path: streams/v1/index.sjson + regions: [RegionOne] + visibility: public +name_prefix: auto-sync/ +output_directory: /var/www/html/simplestreams""" + self.check_file( + self.harness.charm.service_name, + "/etc/openstack-images-sync/config.yaml", + contents=expect_entries, + ) diff --git a/common.sh b/common.sh index f55e9f85..e8611017 100644 --- a/common.sh +++ b/common.sh @@ -70,6 +70,10 @@ INTERNAL_OPENSTACK_HYPERVISOR_LIBS=( "nova_k8s" ) +INTERNAL_OPENSTACK_IMAGES_SYNC_LIBS=( + "keystone_k8s" +) + INTERNAL_OVN_CENTRAL_LIBS=( "ovn_central_k8s" ) @@ -145,6 +149,10 @@ EXTERNAL_OPENSTACK_HYPERVISOR_LIBS=( "certificate_transfer_interface" ) +EXTERNAL_OPENSTACK_IMAGES_SYNC_LIBS=( + "traefik_k8s" +) + EXTERNAL_SUNBEAM_CLUSTERD_LIBS=( "operator_libs_linux" ) @@ -321,6 +329,7 @@ declare -A INTERNAL_LIBS=( [octavia-k8s]=${INTERNAL_NEUTRON_LIBS[@]} [openstack-exporter-k8s]=${INTERNAL_KEYSTONE_LIBS[@]} [openstack-hypervisor]=${INTERNAL_OPENSTACK_HYPERVISOR_LIBS[@]} + [openstack-images-sync-k8s]=${INTERNAL_OPENSTACK_IMAGES_SYNC_LIBS[@]} [sunbeam-clusterd]=${NULL_ARRAY[@]} [sunbeam-machine]=${NULL_ARRAY[@]} [ovn-central-k8s]=${INTERNAL_OVN_CENTRAL_LIBS[@]} @@ -349,6 +358,7 @@ declare -A EXTERNAL_LIBS=( [octavia-k8s]=${EXTERNAL_OCTAVIA_LIBS[@]} [openstack-exporter-k8s]=${EXTERNAL_OPENSTACK_EXPORTER_LIBS[@]} [openstack-hypervisor]=${EXTERNAL_OPENSTACK_HYPERVISOR_LIBS[@]} + [openstack-images-sync-k8s]=${EXTERNAL_OPENSTACK_IMAGES_SYNC_LIBS[@]} [sunbeam-clusterd]=${EXTERNAL_SUNBEAM_CLUSTERD_LIBS[@]} [sunbeam-machine]=${EXTERNAL_SUNBEAM_MACHINE_LIBS[@]} [ovn-central-k8s]=${EXTERNAL_OVN_CENTRAL_LIBS[@]} @@ -377,6 +387,7 @@ declare -A CONFIG_TEMPLATES=( [octavia-k8s]=${CONFIG_TEMPLATES_OCTAVIA[@]} [openstack-exporter-k8s]=${CONFIG_TEMPLATES_HORIZON[@]} [openstack-hypervisor]=${NULL_ARRAY[@]} + [openstack-images-sync-k8s]=${NULL_ARRAY[@]} [sunbeam-clusterd]=${NULL_ARRAY[@]} [sunbeam-machine]=${NULL_ARRAY[@]} [ovn-central-k8s]=${NULL_ARRAY[@]} diff --git a/tests/core/smoke.yaml.j2 b/tests/core/smoke.yaml.j2 index e2c7ddc3..83407e9f 100644 --- a/tests/core/smoke.yaml.j2 +++ b/tests/core/smoke.yaml.j2 @@ -129,6 +129,23 @@ applications: debug: true resources: neutron-server-image: ghcr.io/canonical/neutron-server:2024.1 + openstack-images-sync: + {% if openstack_images_sync_k8s is defined and openstack_images_sync_k8s is sameas true -%} + charm: ../../../openstack-images-sync-k8s.charm + {% else -%} + charm: ch:openstack-images-sync-k8s + channel: 2024.1/edge + {% endif -%} + base: ubuntu@22.04 + scale: 1 + trust: true + options: + frequency: test-do-not-use + architecture: amd64 + release: jammy + max-items: 1 + resources: + openstack-images-sync-image: ghcr.io/canonical/openstack-images-sync:2024.1 relations: - - tls-operator:certificates @@ -193,3 +210,8 @@ relations: - ovn-central:ovsdb-cms - - keystone:send-ca-cert - neutron:receive-ca-cert + +- - keystone:identity-service + - openstack-images-sync:identity-service +- - traefik:ingress + - openstack-images-sync:ingress-public diff --git a/tests/core/tests.yaml b/tests/core/tests.yaml index 3509dd6e..232c3e8f 100644 --- a/tests/core/tests.yaml +++ b/tests/core/tests.yaml @@ -9,6 +9,7 @@ configure: - zaza.openstack.charm_tests.nova.setup.manage_ssh_key tests: - zaza.openstack.charm_tests.tempest.tests.TempestTestWithKeystoneMinimal + - zaza.sunbeam.charm_tests.openstack_images_sync_k8s.tests.OpenStackImagesSyncK8sTest tests_options: trust: - smoke @@ -67,3 +68,6 @@ target_deploy_status: neutron: workload-status: active workload-status-message-regex: '^$' + openstack-images-sync: + workload-status: active + workload-status-message-regex: '^$' diff --git a/tests/local/zaza/sunbeam/charm_tests/openstack_images_sync_k8s/__init__.py b/tests/local/zaza/sunbeam/charm_tests/openstack_images_sync_k8s/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/local/zaza/sunbeam/charm_tests/openstack_images_sync_k8s/tests.py b/tests/local/zaza/sunbeam/charm_tests/openstack_images_sync_k8s/tests.py new file mode 100644 index 00000000..3fe6d99c --- /dev/null +++ b/tests/local/zaza/sunbeam/charm_tests/openstack_images_sync_k8s/tests.py @@ -0,0 +1,51 @@ +# Copyright (c) 2024 Canonical Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import zaza.openstack.charm_tests.test_utils as test_utils +from zaza.openstack.utilities import openstack as openstack_utils + +from glanceclient.v2.client import Client as GlanceClient +import tenacity + +class OpenStackImagesSyncK8sTest(test_utils.BaseCharmTest): + """Charm tests for clusterd.""" + + @classmethod + def setUpClass(cls): + """Run class setup for running tests.""" + super(OpenStackImagesSyncK8sTest, cls).setUpClass( + application_name="openstack-images-sync" + ) + + keystone_session = openstack_utils.get_overcloud_keystone_session() + cls.glance_client: GlanceClient = openstack_utils.get_glance_session_client( + keystone_session + ) + + @tenacity.retry(wait=tenacity.wait_fixed(10), stop=tenacity.stop_after_delay(180), reraise=True) + def _wait_for_images(self): + """Wait for images to be downloaded.""" + images = list(self.glance_client.images.list()) + for image in images: + if image.name.startswith("auto-sync"): + return + raise ValueError("No auto-sync images found") + + def test_100_check_autosync_images_downloaded(self): + """Checking if glance as any auto-sync image.""" + try: + self._wait_for_images() + except ValueError as e: + self.fail(str(e)) diff --git a/zuul.d/jobs.yaml b/zuul.d/jobs.yaml index 70ab24d3..4785ca52 100644 --- a/zuul.d/jobs.yaml +++ b/zuul.d/jobs.yaml @@ -274,6 +274,18 @@ - rebuild vars: charm: openstack-hypervisor +- job: + name: charm-build-openstack-images-sync-k8s + description: Build sunbeam openstack-images-sync-k8s charm + run: playbooks/charm/build.yaml + timeout: 3600 + match-on-config-updates: false + files: + - ops-sunbeam/ops_sunbeam/* + - charms/openstack-images-sync-k8s/* + - rebuild + vars: + charm: openstack-images-sync-k8s - job: name: charm-build-sunbeam-machine description: Build sunbeam-machine charm @@ -317,6 +329,8 @@ soft: true - name: charm-build-neutron-k8s soft: true + - name: charm-build-openstack-images-sync-k8s + soft: true - name: charm-build-ovn-central-k8s soft: true - name: charm-build-ovn-relay-k8s @@ -328,6 +342,7 @@ - charms/nova-k8s/* - charms/neutron-k8s/* - charms/placement-k8s/* + - charms/openstack-images-sync-k8s/* - charms/ovn-central-k8s/* - charms/ovn-relay-k8s/* - rebuild @@ -339,6 +354,7 @@ - charm-build-nova-k8s - charm-build-placement-k8s - charm-build-neutron-k8s + - charm-build-openstack-images-sync-k8s - charm-build-ovn-central-k8s - charm-build-ovn-relay-k8s # test_dir relative to project src dir @@ -448,6 +464,7 @@ soft: true - name: charm-build-ovn-central-k8s soft: true + files: - ops-sunbeam/ops_sunbeam/* - charms/heat-k8s/* @@ -486,6 +503,7 @@ soft: true - name: charm-build-horizon-k8s soft: true + files: - ops-sunbeam/ops_sunbeam/* - charms/designate-k8s/* @@ -774,6 +792,19 @@ - charmhub_token timeout: 3600 +- job: + name: publish-charm-openstack-images-sync-k8s + description: | + Publish openstack-images-sync-k8s built in gate pipeline. + run: playbooks/charm/publish.yaml + files: + - ops-sunbeam/ops_sunbeam/* + - charms/openstack-images-sync-k8s/* + - rebuild + secrets: + - charmhub_token + timeout: 3600 + - job: name: publish-charm-ovn-central-k8s description: | diff --git a/zuul.d/project-templates.yaml b/zuul.d/project-templates.yaml index 5eeceb29..8beeb170 100644 --- a/zuul.d/project-templates.yaml +++ b/zuul.d/project-templates.yaml @@ -80,6 +80,8 @@ nodeset: ubuntu-jammy - charm-build-openstack-hypervisor: nodeset: ubuntu-jammy + - charm-build-openstack-images-sync-k8s: + nodeset: ubuntu-jammy - charm-build-sunbeam-machine: nodeset: ubuntu-jammy - charm-build-sunbeam-clusterd: @@ -133,6 +135,8 @@ nodeset: ubuntu-jammy - charm-build-openstack-hypervisor: nodeset: ubuntu-jammy + - charm-build-openstack-images-sync-k8s: + nodeset: ubuntu-jammy - charm-build-sunbeam-machine: nodeset: ubuntu-jammy - charm-build-sunbeam-clusterd: @@ -190,6 +194,8 @@ nodeset: ubuntu-jammy - publish-charm-openstack-hypervisor: nodeset: ubuntu-jammy + - publish-charm-openstack-images-sync-k8s: + nodeset: ubuntu-jammy - publish-charm-sunbeam-machine: nodeset: ubuntu-jammy - publish-charm-sunbeam-clusterd: diff --git a/zuul.d/secrets.yaml b/zuul.d/secrets.yaml index 2a08788c..e2426361 100644 --- a/zuul.d/secrets.yaml +++ b/zuul.d/secrets.yaml @@ -1,75 +1,75 @@ - secret: name: charmhub_token data: - # Generated on 2024-02-02T09:33:56+00:00 with 90 days ttl + # Generated on 2024-04-11T11:37:37+00:00 with 90 days ttl value: !encrypted/pkcs1-oaep - - E2LjWpipAf7UmhKuEmrkexepo7UZ1jsJgVJB4F52+03TTDPOX7a3X8ega2R5i1QOL7Lx0 - plbApmumymNvOakx/itdxwNKyhY52cRLE7QJuA/p/sSp+NX20xT4xGCfRCPomgCAFUYpD - dIWIiBINGAIm/emmR9RytaBFNstTJS0syiXOL0NIF0sR4e5ZaVMbtNsSpZJgjooovoflD - 8ubvpUMOMoVFTUrGHpUp6Jw6j9xPM2UJjBovN0/PrhufCcfFZxbAq9OU3/AJNOncTwefe - d779Ib13Sp8nJmpepIVl3iIPnRblnan4RIt3c7PHf9ln705qM6mESTACWwLmKu1Zd6lHJ - KrTCma55YVnt4Dc89+XmgoEH2BmSwvcI8Xz0LsfPvicAW8Oi+2cgTPV2clp8byktO6WeM - UCU+I08+7UxtVK47IyI6g0Znv/xomoCmFwAcjWPW96spa2WCHQ56ky6A3gK4DX4ZuBECL - ogyhfSPkfIS6TVk4bkvy1JMp/JOmy/fL0R6L74lbxL33K+fsN7IAvjzjcxU97NRGnU70g - d9X5nYshYQrk4zhR3zMqkFeBGGME/H3R/erg0MGnCeLH8wGA/d0dIhPqf8kksxLZ9VwJE - +r1cGbaXlz51Sm8+Wis5GitREYkEBZ91D3+7MI0Miw4S+GCJZIEmOHyBg349Os= - - pk0HL56MAA100asUuR0d/wGMIGKO0gHb3f8RgXd8yUSdw9egwWNx/ucdU1IeQargEJ+0a - zBgwvmb3r6Gj7x5nEfZng9oLg2Xn1nhx4tCEki46abUVSHvd+qaBZIfRwDKJYeyXVmK4x - lep16mfMoX5V9x01vwrKOfnXnMNp9j5p9GzfLYHgk5H5KK2i/jxX/qQAizQSiDruObezZ - dR6DJnMwI7uNXEV2PSy10H7otnuw6kJH9lnADCvH6XMrghMMZeZ1+805yhOI9JeAOV+0q - XqUtICbBfvESi1XHsv5RXwI32pgDldPCUfgxgnLfFa4tOrbeL6HffdPwpEgXVnAZIyLLz - yAaG5PMs338fFkcsgLhz3ESsSWdaOmeZ70GIhpvyxz9inIhMPePm1+mtIdEEJ5KofHSuk - h6Gb9kR7JaNtYDo3DtCf7hsx8a4wPqg3+pZCCw0KFeVTA7FTaQw3CKTooLyjf9cNRhipp - YA+RIboq/vwO/6THNaY6WhdUxRodN3XhAd9iik1X9kxcWdS4U5RckIWwfja/YELH6ksdD - WKRkpCqf1OEt9evsMySNltEcfPZeapu2fEDUdtXhtX8HKjdtRGkiH494gnaTwDZszobrz - h6kkehNCRytA7lZSMQGWv/NWz36pn2oaJ6AAljrMV1J9fvySmgV7DAVLOXEASQ= - - DeBL3VLvT9hQuAkMUzVF+w3YvGM9yMhuebbezrdb8H6CEA8Iw4N1rNJOQXz4iuhRvpsWR - gmyfsz2XZoauJ5lXxnFB71jx5imQMer30254C6EJMdswju7YjwXsueUAU6RDe+/zaRTn0 - PGIQ4xo18EJBN7CU1YTmVBnCCFAP8H1dyZRKhfW5tt8UDF4HjulZsdmFlBmCEr8jV17t7 - uqv6qGLid6WOsD/uXGWzA8rh+r/+CQBi5YdwbMLd0xu4uqunKygFqr3TUwE2lhDd2qs7D - JuoZcQeUzdwrXaTcLuHkPQyLh28ifwIyytXzjXd6Y10rpategUf5KCxg1IeJYLmS68JPz - 8cE1DRcq2YspGrxz2vn6UL76+5fHnK5fLCXt3iT/aatSkEHxXG787ADLJPxYrUlFZMufG - 2isAY90s2pK4eVwABHLrwZrW8B6HG2zULk9j1A7PEKHLsAHFxEYZ+irA8Jwp3USXlfS2B - nVwdi3yKfht0hL+huYfSpSaZIv5hZtPViKoW8mPPT8J4sNzRLwKVpAAtlgJqihy00uoBw - ssSmDKXOXyw3/vtq6FTtSwc3OK0b5tOAPQEAfBx+Yn+S17qhyF4I3LzlHMIgxyYXhf45G - FWg5l7iimi2yrvfNKypLBv6LWtZKZKxOAf/HhXaJ8Myh/HDkKYtWaJvVKJfOBI= - - Cj3F5/Q4BSkkT/X+UJ8hdPeJTjxKwOHjW8vKFgiknnGCpQb1v8HRbnIfAHeslL6i7KXOZ - RUuiyq40PRtTKxq+tJcaivxwr4s/NztE2vs5LW41gp5wK8H8O4eCRv1YAnX5tK3R9TbnU - gwfV8CJ3liXIFKZyGyBHeQfyQ/NKByNcwnINz4uYowuzODktgeyMsTBLtzctfVuHCCAIp - r1TDGvYofmtH/ctVpSXdS39MzZzSaG80NyQrqy/tLCekOj95Nyd7eQpAvVe/DjHZziw+k - 69P/YdC6kWpfVpBZoxufLQW29I+/HihihrvatVQLqDXCnOsOCMaGV10ph5VpT+g/uHzT3 - i/rUbC/GUfYrYW8BXDWZzK30S7glvS4SChPcoxFdlSW0XT2xfCLKwyfQ6TG17S4HDmO0m - cRUXBbwDAeUKRNGKA6lCUjNd6piS9y5uoTfeWQIuwOBqhLv0yTWD2TiE1U3tCNVHCQVsu - uXDlMCFiPqvmJfrHPSiKPsyLAHNB4dBv689b9msFYyYZneAua4xYbUrPH8Vk4PHzM6LgR - gHI/6u9e8pTX5zGY3iYNIpY0krCORCuXt8mcGSUEI2pkgNnJLfCnBsHnxpMXb+AVTMxj6 - SsrqWBB1GQmI0GCFLUdYC+nAev3pFGCwT17qK70B1ynZzfmsYTaQ70BuLYhFu0= - - OeO3RyZ5X9Yc28k/Q8TlL8tpwD9CeWO9nPIfJm6rlbJxcjfp2XQuwumdGsVL5+whIUMx+ - egiSYJMFOYaLxq9y8EKZiWEL80HjpjeSBnG/6dPylway/s0kpdcmytvAqqIFtLTNCuLPM - zf3GSMzEMY8lyqWfjzoy9QzE/uOfdtlkuAGWIC7sAE+OZdzeBiv48CJQosldfe8kwZN42 - mVa5axikzrSHNeB0R0f4okqa5itbbESY4rex6I7+7qt+Ggd186GmPP+ri0SqINJnsMdkX - 7GEHwlPtSa6shiOyfS+mlMPMCCDZb+ITZIUoZdLOIQhu1IQMy0Abr1PPOIwUFAxHCGlwy - 5cFmmk8ndISdqOQBc6n6A216zaKKBfhwb0xnBHqJ5Y+BEknGkvUdkOhOTjgV3ldRcP//d - BGuVgmvTln2Uh+XwZwjFYKxqgYV0Xc+O+XtIl1K9HwjPqYEAxKypy+ow/Yw8Iq0iWr95S - QfwjCklfVRyL8yoi7oC8yzPIMgKrDMPFnNvtHckyrNndPbK9aTOaUxFL7X+iVctUa7YZD - HO2rfo5MDaDKclOc7bmxNOTL2kUvdpu0LL1djoUXeaOEfpNClPh3WX65eTt/zMYW7NUN/ - fLW6Zn1lQ+jT8q1ji3QoDBY9JnW7ho7ShkecnSwcwArrQh4vLhqAWkC7sM0QFU= - - G2UwVZr/NaK+KyhsblOAOroHLEO4WP7HLedPvTnNAWGOnCTE8066w+aupdO8q9z3RQhoW - dyztaDgQ1Nz4Uk5Mr8gh7Dkh1wrUyr9sc6tqZXxGrF809bm5Fd41xOq+W2dAsBS292Qmd - 9pzJPT2yHbZ6KtYrsQmx3mHtnJRmFhdqetG2gEZxI1HgM9y4V5yB43D1pqrLwLtTkw7T7 - jtaJkSHXlBRlFgyVsdfVJ6lc2Xx32rcXeNw3zb2sKNO2JOUgj0ZC4MVAKpbRlrywDllB2 - PV6PwVOF3Jc3og5cLEB0XWnrkLCYSHYoTEML/uqG/5N/tjnCjvVC89CMXan0Wx6kh9n3L - kgZxDJDRqkFiJI1KAQomkxqabaKgyISIsQvzN3ClWU6t2x1+3KInfSpGHYacSv/wvuhaY - YxcZY5j55lXIsHuczTomDJJnmS1ehB4DCVGLAHZc9hrcqA7FQN8rrJ/QZO8KLYr8ZfPvo - QLfEUWgNTq+DigZQcz1VN5An1+0krdmvZtp7OLcA7TEhcryeMGvo4HJ2ZjfcBbutGfz0w - FUkEsd+I+iubJ7kikI5GZFcpRRqHBiFBivDc4nvmNr/xfdza+gKjNTmg9LeQxa8cImuEu - JAMsnu1jMC9CrO1pd+4E1ZiQK+gElRtTGJAI7vDzaWD3m/oqNPKmUN+4SxZzxM= - - GRUjjglKHpnSuaDwxAlBOG0uAivPfLj3CPcgMZLdW1NAA1S6Xfug8ZLNBSyPhEm8u090Z - 965AlNu1Y76BBJzJBIITmUZ5Le9Hrn544mMASrdrnhuZsj/B/Je7mZ3cKT0dVg3uuHuZW - HLiByJGRoCVJqpxwboEEV16AoF1j7eXCC5kaxs2d1IPuL8ii1HIaDJCmALHekK/AQ92GX - ub8NXQrM58BukXwbtTzILk/5gAAHX8u0M0zDc24QSV/jLaYdBj0Yk+T0hPUAO8u7lJsZ5 - o+6hXawQdlcgm2qX6skPzn9zvdFrugouP1kz31UXmxa76fBkwiqqUjPvKXI3t6YMyEsEC - PYl2limC/zTf7tXq5qUbbzjiwrfa8lM85FyTs8tQKcXMlRez4mp7bY4L1NYH/1Ewz1TtE - cgW53PllZZhy6yI0fQSIW3y0e3BDCpNAjE+OAOtA331t4XtaDvBThb18wqMxIaJ93EpqW - YD6iLmOiWB6kCQVe9ZBfPjofki9HSuCkzsoK8LX7YT44IjqgMDSQbzmRQ0OOAZI11WEgg - m9USmDTgK9Ytjm/RjggiJ5kpTHtNwX6DrHWivXvWjKbfN8sCRj+dJj/ce1O5DcAPmhH8B - caBDNuPFWaPoS7U9FTnQsZ0H1O/uR5DbeIUwU5Y4O/32ni2nCmVyiXlTV0rNIE= + - EuLCbjwc9nopE5Cm5QYAWRDt3GpgCMx1kPPRwfKWgbYACImiSgSlDOtBB9TZiYBNWVIYZ + 3szgFVL2eFx1cLCr1YKDAJUDseXfthqMXkMFg9bblhRlz2HA5akTR/bGrz3VByPHD89wE + RIwGgCyVlkHozcqlCPmASefJDXl1eMFn1jcJqu7wsR8e+Zb5vgeHrOpcjsbEwNnuJ6I08 + Y7l0NuXHCunz7yJu4HYY51AeXXq/nUXb8+OP2myV5dB9vaqmsacVbNMZotAcIthS3iipS + DJYe4PzntIsPSLH5IL+Jx8iwB4FknXt4aatGVttafZC8GDSRFUjoTn69/9gaVVclYjY44 + anQ75ZVTe9O2JLIjs2wm0h+scvQshgcO+x4v+gq7+drY1RDl+QXAxAD3wEcT+0YHK7DmH + zjk85F8+oXzogpeCLsj+EQlrXlZAqywGaVPkcyAyJhjksR8qxkF8lnDszPN8jiieo6lrA + J64X71d/zWNlKhN2lD856bn1KQrO2yncqqwTcHOxLIQyrgl71vRdZZM4jfx1V/hYmKL5s + BjyC/VS9+iQjbE6szviiPBPAC6gthiwpSu6sKFVtiW6gAY4CduIKiff4j9trT1JdOndMG + sKz3bf4T4SL/3SYMba32CWcVmxo2KZnjDqh6FIB8r/YBxl5SeX+glOW5ShLAHw= + - Mok+xU4HJPYMF5//MbTPfbB/RSsAdXgtuxloMONkd4kDhH2LhuuvJoJUFhAW00rnhM0st + h9qy7jcAtxIznevfNY24kgw8jcF9i4G9jJi2GFdhIDS29IPVHsEOgRbzOIZtyTYVdLxBK + 4qJZcd/QcdNLmD/Uo1zPfxXHX9SURsK1vRrQas+yege2xbg8/wyxRTS7MGFYjNY6bvwzD + ipUBGMvMTJkl+9muVn86FMrIQKq9CEXB/fhY7x85QWZyx0rqnYoBg9LMlhvQwlbQE5TsU + hfYPFtyLYlePSB7VzXy4EkHOdShabZB9QNKNp8UO6/z3erL8ILo+PM0Q+JCTp42eAmDa+ + zP6DZSD1vJSynpgv+MsTsPWoZ8AqqoEJcHKMtYABX3GRP6swFgGDGW4Nwae5nh5tklbWE + ciImnwxDmqztoiPqQyc/9QEnmNQ/KnsNwCloNCSdmw+1wUZYgGMn4ewSlVQ0M3Kl5KUfq + k9UWPVQRVdTQtlloWQRxD7Gbg/0UsaLCnT992KO8Qb6Hyf5h/ZUviQEK4TOGsoBLOCHRB + zufT6QmALBIM5vSE4bQdEi/zUIWhz/iC2AWe9uMnHr7Nd/kBJ7seZ5IORIXBq6Wn7AeZH + KxEbMPJ86pN/OPYqOZvXH/2NoWokXOPHLX9cBjdppT7iwUdto4d/imIpTvKcOg= + - eh8Cv8PHxVNy7RfyZ15RSpyeQLPPRU58+IKr+VxgbpLtdwgfMu2w58Uj3AeQlfHCg4+/0 + PUv+926/8WemH380dh4hx0pnSHyHvof2h2dMoThCt/vLcF09YhNZMY1bW5NY3uWu98Gqs + fNvGb8qGOGRZjm2mys+FqcDeyLoSb+YrFTHjYKZLwbvyJeiWUR9SHYuyu0/0WeJMZoKFK + beLvk3kawCObDGxEm8EBMEwIRUl8SfORwzGO3SATBB+jen4Dd63uwkOutcqt10cvvRbTJ + QzLTLGh2vYRhGTXggMKpEfTZY8xc0CVdRyaK7uEfnbqMEUdsDFBDlfQ8EWDgOo9EW2Ggp + EJ0SYFOBbQOU0CuU9Y/QVt2aXAe3T4AzKINqEmayaZvNqmQH4WgVVG9stddKg8B89nnMG + BYgfg+H+emBdaSNtkDUKi0VPotxA2iVurrqDekOEBvjavmI3mlKHwUyZZYffEIP7lNt7N + lvpTZQd+J6nKy6vF3i2DU+Ti9l7zah8EnfCS8so5qCcGm1IkZn+6Ji+twIR8RPoJdqDkH + cqAtAsyGb5/reCMOVsUVu9dYB5yt7G7OYerIA/cDCstyYWf5oXcIwQpvFb9NxO0v2/vNx + zh9kUQkvW03QM++37T3O/2wEFOBDVV3oTyACMhZjWhX5oTC8v4I1orYJE8ej4U= + - XEEtczynmIDXCM2GSZnzhpHGysCH45FKd+T4JVNUgqJdHv0UlYgidC13XrLfXnhh8c4Ck + q0StbxF4s1wtAEDrRu5qiO4mo084M4DEyYRkeRsPr+9wnJshGsGK2QS8VotJWxS7TTjwI + Y0LOiqajJbmPutkBU9u73WtN149cdJJ4LxlB6QfuDq/M8XwRPjmI47j/kq7VAtSC/YQLS + 2boRux2MoqBCkYGhmGKL2G1zS5Se7W3Wzt4Gl1DP2eXeJNLuvlVc3O6vQ5jGSlz4zzwfY + qK0rZBzQzKi8nO9FqPiQGv6t5Mjg6dXI+vg607Uti6aW4tbnSboJNBgh2F4/Ea3vY3/mR + wdlpHQw+lxCgWzz4RjXpueXYpbcc2x/Kg0kYm6k+hqrL6UBgAUzKCo+nGxJ5EegwiBEnJ + +LbsPxpo82ywBvVb0jCvIm0g7LTYsqS0dpP9J6YxpU8eEo2oQHSqiEtY0HIR0yaauzQvQ + 1LN8XD6StmbrEMeAP4ygxnEECNmW0IY5FT0Ve04gKvtO4Z0LNcN92UPeHkXNflLIMzjCs + SBHpxfcvQwgfTS9Z3Ow0rkMk0Xyj4ersdWAgbWhiFe2EyrLeQ8z4eOZ8RlfTMaP4FnvUS + 9j/z56XVveag8x9y0zWiLnAsYCgYzDajiwur+SOB/irRTFw7FBnpSxZlUXfAas= + - Xtr7b+gDOKgQTzTNtezWah0XRcs6V6ogXuRbxnafz7PIAmxYuRzKgFEwSvQXOD1fC2bmf + HPDTsMC+3JZJwXYTYPzYuQaDeCNJQ/uuYfrLPm2fJgF2xmf1izggbqeLOctHuGVnVJpAs + DqltQn4FMFnamFWSLi0tmwDsxTJSn1rR57cODSALss7a1Att92CI8QdkJVn3r6wc09dHc + lhILo3lOu8DWC9jznvmCb4tVl3K16Cz3VbtGkepId4avzEbDxbsn2VBFsueMBrk/MBc4M + 7LUCdxLma7wyTc3uhtdQGOmKdjaWdKOE2AR9DMV+oNtQHGLNDvzeogUTOVmxHFpq0D/cl + 5NQVLoXdkzpJq4zLZViiaNl70LcBIF04ht5ZXguUkfc/RZeYeQQs21GiBFo337BfIqHhv + HiTGAcYRL0hX9RrfVINVm/5GeC8ebj26sIW6AGd0jog/W9NDrMZa0ryJJfiUEbJhjCh7S + kK+zqBcMxHf9WDwFtuNfmNseEDUvcdofg5k/RsjWrCpWB4Fzg+n+ackgz9M5X3aqwpVD7 + 9EzxHPiLej0iRVS/VrAdp0fTQ225XU7lEJBsSBaj2pxdx6wxM3KGVL1aB7rUiDohBHCQ7 + SYh8AifcMzskQPLkk7L7KezedTamBGw0+crguwoSikQI0e08Lm6JFGNHVLl6AM= + - Sfak9Ud92Rr5PHIMkMhJT5btyWsJ9FnyjszgcIYmlrGa+iaQFEqCzg6hMY0S+I12zXbO0 + y+JnKeJueDfuFzxBoyw4GlTNjPUiGC4xeQz4E+MeiPotHqaZeLKUIpDND4eapDWHc3QmH + jsUk2RIFknDnYiZJ+V4wvO7b6bToH8qYbbzIos2a2odtSy8yoPnKcnz5Fq/W0WxRUoqz5 + iGwIbGLzG3KMy3QQtj2fTWp54g0Ttbz5h4UyPX2kjWKjR0AsVyJ/XBmnlU6nSrJ2dCfW0 + ocGpTGOYW/8DhRBrDYGyhhGfm8GI/hrF7KLHFufjXzELBGfdXeALHMv5tDnMHxD3T5UqC + aisVmlKBq0DmhsZPZgSUUBZQD+lBgksBy2nZt+awtYfUhhrak1NQfGkVcSku4SJ5Qmbcp + MXEqBy6b0Ay/suP8YqeY8gJpogotm+MdwU0FreAgPXNeSP8xePB9FQq5mFeovDmUqq6GH + rWI+3syoUFGlPum/vKB7+tHpqpz1ropaQRjy2kbybL8wDMHcgUj9RwxXxAwwv3c7UmIhX + /FXp91m6nZVyCaYQhYg8Q2kyB0WPPUcC6H/OTFGng15GMA4QC0JJY3RkSsTMg7Oti9wbo + FXy1CsOonhdhMKBBWNOEGom4nXSvC+g5TXJuIauH+/jECIXQZsNAwwS0gmGeSg= + - ImwOP7I3dDKrBmhzyXI8q0DIlXTW6fWxSKCER055khP/z5lNaRJ8QSfO8ku7gV7aF3Fdt + j3YuV4crT1A/RtDrZZRFjGAFudGcLUzj0AcctrH+D4MkJExHmtV7N8AtxurtObVg92EfY + T6VADbKyvWK7HDPTL5l2q81pl3F2CDdEQVgIcckmk7WcKRSv39GcQG/dBG43wkgQnL/SS + dMVNza8On5/Z9hPVwr4VQCVsJextckTTnkwRCyC8ADkCoTWe9keFVfmupJI2HuRVzBghJ + 8/8hBUYyr0MCcQI833r6C4tClWNXjEGRqzLli1K8gfYQbYBOYXBSqhNvxXs5D730G6Cfw + 3ynmCJvjhpFGZEGBWJLv3T89tJgQCl3hf/AxWs1zUtvCz/lpEjEZo5PaPpQwz2YobbV6g + erFEvUitSgQiKv3M2b+spgj3E0g8HuNdGUSETbjy8pNkn49yq/YCb/Xk+m5CLffkLba+d + YoFXfGiePC8rU0ZhgruMFfZHyailiZnnEEzBFFLyT2srLzpib6jcNd2ITsCJGtH81c6cl + pTMgp+FuAU2dYpWo+bf0b1i1bdxhnp4yRiSKSE7ZRDFF4bUkMx7HVMYzb7G+eFAiLofZs + 6itfIdHVXBxaluvtWsZ1kFYZL8e1Dla4geYLNSOjPj1I6UuXJTuBNqShe7rqV0= diff --git a/zuul.d/zuul.yaml b/zuul.d/zuul.yaml index a61db486..6fcc995b 100644 --- a/zuul.d/zuul.yaml +++ b/zuul.d/zuul.yaml @@ -48,6 +48,7 @@ keystone-ldap-k8s: 2024.1/edge openstack-exporter-k8s: 2024.1/edge openstack-hypervisor: 2024.1/edge + openstack-images-sync-k8s: 2024.1/edge sunbeam-machine: 2024.1/edge sunbeam-clusterd: 2024.1/edge tempest-k8s: 2024.1/edge