From b9e31079a20c10868b78e306de1e52f7df877a1a Mon Sep 17 00:00:00 2001 From: Ahmad Hassan Date: Tue, 24 Jun 2025 16:02:58 +0500 Subject: [PATCH] [epa-orchestrator] epa-orchestrator charm for installing epa-orchestrator snap The epa-orchestrator charm is an operator designed to configure and install epa-orchestrator snap. Change-Id: Ib74ec522a67f8f06996d8ff4fdd1c87ae9311de3 Signed-off-by: Ahmad Hassan --- .gitignore | 1 + charms/epa-orchestrator/.sunbeam-build.yaml | 6 + charms/epa-orchestrator/CONTRIBUTING.md | 35 ++ charms/epa-orchestrator/LICENSE | 202 +++++++++ charms/epa-orchestrator/README.md | 13 + charms/epa-orchestrator/__init__.py | 15 + charms/epa-orchestrator/charmcraft.yaml | 46 +++ charms/epa-orchestrator/pyproject.toml | 17 + charms/epa-orchestrator/rebuild | 3 + charms/epa-orchestrator/src/charm.py | 64 +++ .../epa-orchestrator/tests/unit/__init__.py | 15 + .../epa-orchestrator/tests/unit/test_charm.py | 88 ++++ charms/epa-orchestrator/uv.lock | 382 ++++++++++++++++++ ops-sunbeam/tests/unit_tests/test_core.py | 8 + render_bundles.py | 2 +- .../charm_tests/epa_orchestrator/__init__.py | 14 + .../charm_tests/epa_orchestrator/tests.py | 80 ++++ tests/machine/smoke.yaml.j2 | 22 +- tests/machine/tests.yaml | 4 + zuul.d/jobs.yaml | 29 ++ zuul.d/project-templates.yaml | 6 + zuul.d/secrets.yaml | 162 ++++---- zuul.d/zuul.yaml | 1 + 23 files changed, 1128 insertions(+), 87 deletions(-) create mode 100644 charms/epa-orchestrator/.sunbeam-build.yaml create mode 100644 charms/epa-orchestrator/CONTRIBUTING.md create mode 100644 charms/epa-orchestrator/LICENSE create mode 100644 charms/epa-orchestrator/README.md create mode 100644 charms/epa-orchestrator/__init__.py create mode 100644 charms/epa-orchestrator/charmcraft.yaml create mode 100644 charms/epa-orchestrator/pyproject.toml create mode 100644 charms/epa-orchestrator/rebuild create mode 100755 charms/epa-orchestrator/src/charm.py create mode 100644 charms/epa-orchestrator/tests/unit/__init__.py create mode 100644 charms/epa-orchestrator/tests/unit/test_charm.py create mode 100644 charms/epa-orchestrator/uv.lock create mode 100644 tests/local/zaza/sunbeam/charm_tests/epa_orchestrator/__init__.py create mode 100644 tests/local/zaza/sunbeam/charm_tests/epa_orchestrator/tests.py diff --git a/.gitignore b/.gitignore index 403f2bb6..80ebdadb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.cursor venv/ build/ .idea/ diff --git a/charms/epa-orchestrator/.sunbeam-build.yaml b/charms/epa-orchestrator/.sunbeam-build.yaml new file mode 100644 index 00000000..5471e8b2 --- /dev/null +++ b/charms/epa-orchestrator/.sunbeam-build.yaml @@ -0,0 +1,6 @@ +external-libraries: + - charms.operator_libs_linux.v2.snap + - charms.tempo_k8s.v2.tracing + - charms.tempo_k8s.v1.charm_tracing +internal-libraries: [] +templates: [] diff --git a/charms/epa-orchestrator/CONTRIBUTING.md b/charms/epa-orchestrator/CONTRIBUTING.md new file mode 100644 index 00000000..54bd8afc --- /dev/null +++ b/charms/epa-orchestrator/CONTRIBUTING.md @@ -0,0 +1,35 @@ +# 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 +virtualenv venv +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 fmt +tox run -e linters +tox run -e pep8 +tox -e py3 -- epa-orchestrator +``` + +## Smoke testing +```shell +tox -e func -- --smoke --test-directory=/root/sunbeam-charms/tests/machine/ +``` + +## Build the charm + +Build the charm in this git repository using: + +```shell +tox -e build -- epa-orchestrator +``` diff --git a/charms/epa-orchestrator/LICENSE b/charms/epa-orchestrator/LICENSE new file mode 100644 index 00000000..20f6a4e3 --- /dev/null +++ b/charms/epa-orchestrator/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2025 ahmad + + 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. diff --git a/charms/epa-orchestrator/README.md b/charms/epa-orchestrator/README.md new file mode 100644 index 00000000..865bdcc8 --- /dev/null +++ b/charms/epa-orchestrator/README.md @@ -0,0 +1,13 @@ +# epa-orchestrator + +## Description + +The epa-orchestrator charm is an operator designed to manage the EPA (Enhanced Platform Awareness) orchestrator service as part of an OpenStack deployment. This charm installs and configures the epa-orchestrator snap, which provides enhanced platform awareness capabilities for OpenStack cloud. + +### Testing + +Run the unit tests: + +```bash +tox -e py3 -- epa-orchestrator +``` \ No newline at end of file diff --git a/charms/epa-orchestrator/__init__.py b/charms/epa-orchestrator/__init__.py new file mode 100644 index 00000000..6375e72b --- /dev/null +++ b/charms/epa-orchestrator/__init__.py @@ -0,0 +1,15 @@ +# Copyright 2025 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/epa-orchestrator/charmcraft.yaml b/charms/epa-orchestrator/charmcraft.yaml new file mode 100644 index 00000000..2d3cf9a4 --- /dev/null +++ b/charms/epa-orchestrator/charmcraft.yaml @@ -0,0 +1,46 @@ +type: charm +name: epa-orchestrator +title: Epa Orchestrator +summary: Deploy the epa-orchestrator snap. +description: | + Configures the epa-orchestrator snap as a part of the openstack deployment. +assumes: + - juju >= 3.1 +base: ubuntu@24.04 +platforms: + amd64: +config: + options: + snap-name: + default: epa-orchestrator + type: string + description: The name of the snap to install. + snap-channel: + default: latest/edge + type: string + description: The channel of the snap to install. +requires: + tracing: + interface: tracing + optional: true + limit: 1 + +parts: + charm: + build-packages: + - git + - libffi-dev + - libssl-dev + - rustc-1.80 + - cargo-1.80 + - pkg-config + charm-binary-python-packages: + - cryptography + - jsonschema + - pydantic + - jinja2 + build-snaps: [astral-uv] + override-build: | + uv export --frozen --no-hashes --format=requirements-txt -o requirements.txt + craftctl default + charm-requirements: [requirements.txt] diff --git a/charms/epa-orchestrator/pyproject.toml b/charms/epa-orchestrator/pyproject.toml new file mode 100644 index 00000000..6012eb41 --- /dev/null +++ b/charms/epa-orchestrator/pyproject.toml @@ -0,0 +1,17 @@ +# Copyright 2025 Canonical Ltd. +# See LICENSE file for licensing details. + +[project] +name = "epa-orchestrator" +version = "2025.1" +requires-python = "~=3.12.0" + +dependencies = [ + "cryptography", + "jinja2", + "jsonschema", + "pydantic", + "ops", + "tenacity", # From ops_sunbeam + "opentelemetry-api~=1.21.0", # charm_tracing library -> opentelemetry-sdk requires 1.21.0 +] diff --git a/charms/epa-orchestrator/rebuild b/charms/epa-orchestrator/rebuild new file mode 100644 index 00000000..1e7e5423 --- /dev/null +++ b/charms/epa-orchestrator/rebuild @@ -0,0 +1,3 @@ +# This file is used to trigger a build. +# Change uuid to trigger a new build. +29a571a6-411d-49f0-80fb-07fa8c4f7e49 diff --git a/charms/epa-orchestrator/src/charm.py b/charms/epa-orchestrator/src/charm.py new file mode 100755 index 00000000..bec94cbf --- /dev/null +++ b/charms/epa-orchestrator/src/charm.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 + +# Copyright 2023 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. + +"""EPA Orchestrator Charm operator. + +This charm is used to install the epa-orchestrator snap as a part of the openstack deployment. +""" + +import logging + +import charms.operator_libs_linux.v2.snap as snap +import ops +import ops_sunbeam.charm as sunbeam_charm +import ops_sunbeam.tracing as sunbeam_tracing + +logger = logging.getLogger(__name__) + + +@sunbeam_tracing.trace_sunbeam_charm(extra_types=(snap.SnapCache, snap.Snap)) +class EpaOrchestratorCharm(sunbeam_charm.OSBaseOperatorCharmSnap): + """Charm the service.""" + + service_name = "epa-orchestrator" + + @property + def snap_name(self) -> str: + """Returns the snap name.""" + return str(self.model.config["snap-name"]) + + @property + def snap_channel(self) -> str: + """Returns the snap channel.""" + return str(self.model.config["snap-channel"]) + + def ensure_services_running(self) -> None: + """Override to prevent service start - this snap has no services.""" + logger.debug( + "Skipping service start - %s snap has no services", self.snap_name + ) + pass + + def stop_services(self) -> None: + """Override to prevent service stop - this snap has no services.""" + logger.debug( + "Skipping service stop - %s snap has no services", self.snap_name + ) + pass + + +if __name__ == "__main__": # pragma: nocover + ops.main(EpaOrchestratorCharm) diff --git a/charms/epa-orchestrator/tests/unit/__init__.py b/charms/epa-orchestrator/tests/unit/__init__.py new file mode 100644 index 00000000..6375e72b --- /dev/null +++ b/charms/epa-orchestrator/tests/unit/__init__.py @@ -0,0 +1,15 @@ +# Copyright 2025 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/epa-orchestrator/tests/unit/test_charm.py b/charms/epa-orchestrator/tests/unit/test_charm.py new file mode 100644 index 00000000..afb27449 --- /dev/null +++ b/charms/epa-orchestrator/tests/unit/test_charm.py @@ -0,0 +1,88 @@ +# Copyright 2023 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 EPA Orchestrator charm.""" + + +import charm +import ops_sunbeam.test_utils as test_utils + + +class _EpaOrchestratorCharm(charm.EpaOrchestratorCharm): + """EPA Orchestrator test charm.""" + + def __init__(self, framework): + super().__init__(framework) + + +class TestEpaOrchestratorCharm(test_utils.CharmTestCase): + """Test charm to test EPA Orchestrator charm.""" + + PATCHES = [] + + def setUp(self): + """Setup EPA Orchestrator tests.""" + super().setUp(charm, self.PATCHES) + + self.harness = test_utils.get_harness( + _EpaOrchestratorCharm, + container_calls=self.container_calls, + ) + self.addCleanup(self.harness.cleanup) + + def initial_setup(self): + """Setting up configuration.""" + self.harness.update_config( + {"snap-name": "epa-orchestrator", "snap-channel": "latest/edge"} + ) + self.harness.begin_with_initial_hooks() + + def test_snap_name_property_default(self): + """Test snap_name property returns default value.""" + self.harness.begin() + + self.assertEqual(self.harness.charm.snap_name, "epa-orchestrator") + + def test_snap_channel_property(self): + """Test snap_channel property returns configured channel.""" + self.harness.begin() + self.harness.update_config({"snap-channel": "latest/edge"}) + + self.assertEqual(self.harness.charm.snap_channel, "latest/edge") + + def test_snap_channel_property_default(self): + """Test snap_channel property returns default value.""" + self.harness.begin() + + self.assertEqual(self.harness.charm.snap_channel, "latest/edge") + + def test_ensure_services_running_no_op(self): + """Test ensure_services_running is a no-op and doesn't raise errors.""" + self.harness.begin() + + # This should not raise any exceptions + result = self.harness.charm.ensure_services_running() + + # Should return None (no-op) + self.assertIsNone(result) + + def test_stop_services_no_op(self): + """Test stop_services is a no-op and doesn't raise errors.""" + self.harness.begin() + + # This should not raise any exceptions + result = self.harness.charm.stop_services() + + # Should return None (no-op) + self.assertIsNone(result) diff --git a/charms/epa-orchestrator/uv.lock b/charms/epa-orchestrator/uv.lock new file mode 100644 index 00000000..e7103a67 --- /dev/null +++ b/charms/epa-orchestrator/uv.lock @@ -0,0 +1,382 @@ +version = 1 +revision = 2 +requires-python = ">=3.12.0, <3.13" + +[[package]] +name = "annotated-types" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, +] + +[[package]] +name = "attrs" +version = "25.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5a/b0/1367933a8532ee6ff8d63537de4f1177af4bff9f3e829baf7331f595bb24/attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b", size = 812032, upload-time = "2025-03-13T11:10:22.779Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3", size = 63815, upload-time = "2025-03-13T11:10:21.14Z" }, +] + +[[package]] +name = "cffi" +version = "1.17.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", size = 516621, upload-time = "2024-09-04T20:45:21.852Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/84/e94227139ee5fb4d600a7a4927f322e1d4aea6fdc50bd3fca8493caba23f/cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4", size = 183178, upload-time = "2024-09-04T20:44:12.232Z" }, + { url = "https://files.pythonhosted.org/packages/da/ee/fb72c2b48656111c4ef27f0f91da355e130a923473bf5ee75c5643d00cca/cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c", size = 178840, upload-time = "2024-09-04T20:44:13.739Z" }, + { url = "https://files.pythonhosted.org/packages/cc/b6/db007700f67d151abadf508cbfd6a1884f57eab90b1bb985c4c8c02b0f28/cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", size = 454803, upload-time = "2024-09-04T20:44:15.231Z" }, + { url = "https://files.pythonhosted.org/packages/1a/df/f8d151540d8c200eb1c6fba8cd0dfd40904f1b0682ea705c36e6c2e97ab3/cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", size = 478850, upload-time = "2024-09-04T20:44:17.188Z" }, + { url = "https://files.pythonhosted.org/packages/28/c0/b31116332a547fd2677ae5b78a2ef662dfc8023d67f41b2a83f7c2aa78b1/cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", size = 485729, upload-time = "2024-09-04T20:44:18.688Z" }, + { url = "https://files.pythonhosted.org/packages/91/2b/9a1ddfa5c7f13cab007a2c9cc295b70fbbda7cb10a286aa6810338e60ea1/cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", size = 471256, upload-time = "2024-09-04T20:44:20.248Z" }, + { url = "https://files.pythonhosted.org/packages/b2/d5/da47df7004cb17e4955df6a43d14b3b4ae77737dff8bf7f8f333196717bf/cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", size = 479424, upload-time = "2024-09-04T20:44:21.673Z" }, + { url = "https://files.pythonhosted.org/packages/0b/ac/2a28bcf513e93a219c8a4e8e125534f4f6db03e3179ba1c45e949b76212c/cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", size = 484568, upload-time = "2024-09-04T20:44:23.245Z" }, + { url = "https://files.pythonhosted.org/packages/d4/38/ca8a4f639065f14ae0f1d9751e70447a261f1a30fa7547a828ae08142465/cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", size = 488736, upload-time = "2024-09-04T20:44:24.757Z" }, + { url = "https://files.pythonhosted.org/packages/86/c5/28b2d6f799ec0bdecf44dced2ec5ed43e0eb63097b0f58c293583b406582/cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", size = 172448, upload-time = "2024-09-04T20:44:26.208Z" }, + { url = "https://files.pythonhosted.org/packages/50/b9/db34c4755a7bd1cb2d1603ac3863f22bcecbd1ba29e5ee841a4bc510b294/cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", size = 181976, upload-time = "2024-09-04T20:44:27.578Z" }, +] + +[[package]] +name = "cryptography" +version = "45.0.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fe/c8/a2a376a8711c1e11708b9c9972e0c3223f5fc682552c82d8db844393d6ce/cryptography-45.0.4.tar.gz", hash = "sha256:7405ade85c83c37682c8fe65554759800a4a8c54b2d96e0f8ad114d31b808d57", size = 744890, upload-time = "2025-06-10T00:03:51.297Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cc/1c/92637793de053832523b410dbe016d3f5c11b41d0cf6eef8787aabb51d41/cryptography-45.0.4-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:425a9a6ac2823ee6e46a76a21a4e8342d8fa5c01e08b823c1f19a8b74f096069", size = 7055712, upload-time = "2025-06-10T00:02:38.826Z" }, + { url = "https://files.pythonhosted.org/packages/ba/14/93b69f2af9ba832ad6618a03f8a034a5851dc9a3314336a3d71c252467e1/cryptography-45.0.4-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:680806cf63baa0039b920f4976f5f31b10e772de42f16310a6839d9f21a26b0d", size = 4205335, upload-time = "2025-06-10T00:02:41.64Z" }, + { url = "https://files.pythonhosted.org/packages/67/30/fae1000228634bf0b647fca80403db5ca9e3933b91dd060570689f0bd0f7/cryptography-45.0.4-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4ca0f52170e821bc8da6fc0cc565b7bb8ff8d90d36b5e9fdd68e8a86bdf72036", size = 4431487, upload-time = "2025-06-10T00:02:43.696Z" }, + { url = "https://files.pythonhosted.org/packages/6d/5a/7dffcf8cdf0cb3c2430de7404b327e3db64735747d641fc492539978caeb/cryptography-45.0.4-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:f3fe7a5ae34d5a414957cc7f457e2b92076e72938423ac64d215722f6cf49a9e", size = 4208922, upload-time = "2025-06-10T00:02:45.334Z" }, + { url = "https://files.pythonhosted.org/packages/c6/f3/528729726eb6c3060fa3637253430547fbaaea95ab0535ea41baa4a6fbd8/cryptography-45.0.4-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:25eb4d4d3e54595dc8adebc6bbd5623588991d86591a78c2548ffb64797341e2", size = 3900433, upload-time = "2025-06-10T00:02:47.359Z" }, + { url = "https://files.pythonhosted.org/packages/d9/4a/67ba2e40f619e04d83c32f7e1d484c1538c0800a17c56a22ff07d092ccc1/cryptography-45.0.4-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:ce1678a2ccbe696cf3af15a75bb72ee008d7ff183c9228592ede9db467e64f1b", size = 4464163, upload-time = "2025-06-10T00:02:49.412Z" }, + { url = "https://files.pythonhosted.org/packages/7e/9a/b4d5aa83661483ac372464809c4b49b5022dbfe36b12fe9e323ca8512420/cryptography-45.0.4-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:49fe9155ab32721b9122975e168a6760d8ce4cffe423bcd7ca269ba41b5dfac1", size = 4208687, upload-time = "2025-06-10T00:02:50.976Z" }, + { url = "https://files.pythonhosted.org/packages/db/b7/a84bdcd19d9c02ec5807f2ec2d1456fd8451592c5ee353816c09250e3561/cryptography-45.0.4-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:2882338b2a6e0bd337052e8b9007ced85c637da19ef9ecaf437744495c8c2999", size = 4463623, upload-time = "2025-06-10T00:02:52.542Z" }, + { url = "https://files.pythonhosted.org/packages/d8/84/69707d502d4d905021cac3fb59a316344e9f078b1da7fb43ecde5e10840a/cryptography-45.0.4-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:23b9c3ea30c3ed4db59e7b9619272e94891f8a3a5591d0b656a7582631ccf750", size = 4332447, upload-time = "2025-06-10T00:02:54.63Z" }, + { url = "https://files.pythonhosted.org/packages/f3/ee/d4f2ab688e057e90ded24384e34838086a9b09963389a5ba6854b5876598/cryptography-45.0.4-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b0a97c927497e3bc36b33987abb99bf17a9a175a19af38a892dc4bbb844d7ee2", size = 4572830, upload-time = "2025-06-10T00:02:56.689Z" }, + { url = "https://files.pythonhosted.org/packages/70/d4/994773a261d7ff98034f72c0e8251fe2755eac45e2265db4c866c1c6829c/cryptography-45.0.4-cp311-abi3-win32.whl", hash = "sha256:e00a6c10a5c53979d6242f123c0a97cff9f3abed7f064fc412c36dc521b5f257", size = 2932769, upload-time = "2025-06-10T00:02:58.467Z" }, + { url = "https://files.pythonhosted.org/packages/5a/42/c80bd0b67e9b769b364963b5252b17778a397cefdd36fa9aa4a5f34c599a/cryptography-45.0.4-cp311-abi3-win_amd64.whl", hash = "sha256:817ee05c6c9f7a69a16200f0c90ab26d23a87701e2a284bd15156783e46dbcc8", size = 3410441, upload-time = "2025-06-10T00:03:00.14Z" }, + { url = "https://files.pythonhosted.org/packages/ce/0b/2488c89f3a30bc821c9d96eeacfcab6ff3accc08a9601ba03339c0fd05e5/cryptography-45.0.4-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:964bcc28d867e0f5491a564b7debb3ffdd8717928d315d12e0d7defa9e43b723", size = 7031836, upload-time = "2025-06-10T00:03:01.726Z" }, + { url = "https://files.pythonhosted.org/packages/fe/51/8c584ed426093aac257462ae62d26ad61ef1cbf5b58d8b67e6e13c39960e/cryptography-45.0.4-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6a5bf57554e80f75a7db3d4b1dacaa2764611ae166ab42ea9a72bcdb5d577637", size = 4195746, upload-time = "2025-06-10T00:03:03.94Z" }, + { url = "https://files.pythonhosted.org/packages/5c/7d/4b0ca4d7af95a704eef2f8f80a8199ed236aaf185d55385ae1d1610c03c2/cryptography-45.0.4-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:46cf7088bf91bdc9b26f9c55636492c1cce3e7aaf8041bbf0243f5e5325cfb2d", size = 4424456, upload-time = "2025-06-10T00:03:05.589Z" }, + { url = "https://files.pythonhosted.org/packages/1d/45/5fabacbc6e76ff056f84d9f60eeac18819badf0cefc1b6612ee03d4ab678/cryptography-45.0.4-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:7bedbe4cc930fa4b100fc845ea1ea5788fcd7ae9562e669989c11618ae8d76ee", size = 4198495, upload-time = "2025-06-10T00:03:09.172Z" }, + { url = "https://files.pythonhosted.org/packages/55/b7/ffc9945b290eb0a5d4dab9b7636706e3b5b92f14ee5d9d4449409d010d54/cryptography-45.0.4-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:eaa3e28ea2235b33220b949c5a0d6cf79baa80eab2eb5607ca8ab7525331b9ff", size = 3885540, upload-time = "2025-06-10T00:03:10.835Z" }, + { url = "https://files.pythonhosted.org/packages/7f/e3/57b010282346980475e77d414080acdcb3dab9a0be63071efc2041a2c6bd/cryptography-45.0.4-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:7ef2dde4fa9408475038fc9aadfc1fb2676b174e68356359632e980c661ec8f6", size = 4452052, upload-time = "2025-06-10T00:03:12.448Z" }, + { url = "https://files.pythonhosted.org/packages/37/e6/ddc4ac2558bf2ef517a358df26f45bc774a99bf4653e7ee34b5e749c03e3/cryptography-45.0.4-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:6a3511ae33f09094185d111160fd192c67aa0a2a8d19b54d36e4c78f651dc5ad", size = 4198024, upload-time = "2025-06-10T00:03:13.976Z" }, + { url = "https://files.pythonhosted.org/packages/3a/c0/85fa358ddb063ec588aed4a6ea1df57dc3e3bc1712d87c8fa162d02a65fc/cryptography-45.0.4-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:06509dc70dd71fa56eaa138336244e2fbaf2ac164fc9b5e66828fccfd2b680d6", size = 4451442, upload-time = "2025-06-10T00:03:16.248Z" }, + { url = "https://files.pythonhosted.org/packages/33/67/362d6ec1492596e73da24e669a7fbbaeb1c428d6bf49a29f7a12acffd5dc/cryptography-45.0.4-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:5f31e6b0a5a253f6aa49be67279be4a7e5a4ef259a9f33c69f7d1b1191939872", size = 4325038, upload-time = "2025-06-10T00:03:18.4Z" }, + { url = "https://files.pythonhosted.org/packages/53/75/82a14bf047a96a1b13ebb47fb9811c4f73096cfa2e2b17c86879687f9027/cryptography-45.0.4-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:944e9ccf67a9594137f942d5b52c8d238b1b4e46c7a0c2891b7ae6e01e7c80a4", size = 4560964, upload-time = "2025-06-10T00:03:20.06Z" }, + { url = "https://files.pythonhosted.org/packages/cd/37/1a3cba4c5a468ebf9b95523a5ef5651244693dc712001e276682c278fc00/cryptography-45.0.4-cp37-abi3-win32.whl", hash = "sha256:c22fe01e53dc65edd1945a2e6f0015e887f84ced233acecb64b4daadb32f5c97", size = 2924557, upload-time = "2025-06-10T00:03:22.563Z" }, + { url = "https://files.pythonhosted.org/packages/2a/4b/3256759723b7e66380397d958ca07c59cfc3fb5c794fb5516758afd05d41/cryptography-45.0.4-cp37-abi3-win_amd64.whl", hash = "sha256:627ba1bc94f6adf0b0a2e35d87020285ead22d9f648c7e75bb64f367375f3b22", size = 3395508, upload-time = "2025-06-10T00:03:24.586Z" }, +] + +[[package]] +name = "deprecated" +version = "1.2.18" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "wrapt" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/98/97/06afe62762c9a8a86af0cfb7bfdab22a43ad17138b07af5b1a58442690a2/deprecated-1.2.18.tar.gz", hash = "sha256:422b6f6d859da6f2ef57857761bfb392480502a64c3028ca9bbe86085d72115d", size = 2928744, upload-time = "2025-01-27T10:46:25.7Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6e/c6/ac0b6c1e2d138f1002bcf799d330bd6d85084fece321e662a14223794041/Deprecated-1.2.18-py2.py3-none-any.whl", hash = "sha256:bd5011788200372a32418f888e326a09ff80d0214bd961147cfed01b5c018eec", size = 9998, upload-time = "2025-01-27T10:46:09.186Z" }, +] + +[[package]] +name = "epa-orchestrator" +version = "2025.1" +source = { virtual = "." } +dependencies = [ + { name = "cryptography" }, + { name = "jinja2" }, + { name = "jsonschema" }, + { name = "opentelemetry-api" }, + { name = "ops" }, + { name = "pydantic" }, + { name = "tenacity" }, +] + +[package.metadata] +requires-dist = [ + { name = "cryptography" }, + { name = "jinja2" }, + { name = "jsonschema" }, + { name = "opentelemetry-api", specifier = "~=1.21.0" }, + { name = "ops" }, + { name = "pydantic" }, + { name = "tenacity" }, +] + +[[package]] +name = "importlib-metadata" +version = "6.11.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "zipp" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ee/eb/58c2ab27ee628ad801f56d4017fe62afab0293116f6d0b08f1d5bd46e06f/importlib_metadata-6.11.0.tar.gz", hash = "sha256:1231cf92d825c9e03cfc4da076a16de6422c863558229ea0b22b675657463443", size = 54593, upload-time = "2023-12-03T17:33:10.693Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/59/9b/ecce94952ab5ea74c31dcf9ccf78ccd484eebebef06019bf8cb579ab4519/importlib_metadata-6.11.0-py3-none-any.whl", hash = "sha256:f0afba6205ad8f8947c7d338b5342d5db2afbfd82f9cbef7879a9539cc12eb9b", size = 23427, upload-time = "2023-12-03T17:33:08.965Z" }, +] + +[[package]] +name = "jinja2" +version = "3.1.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, +] + +[[package]] +name = "jsonschema" +version = "4.24.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "jsonschema-specifications" }, + { name = "referencing" }, + { name = "rpds-py" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bf/d3/1cf5326b923a53515d8f3a2cd442e6d7e94fcc444716e879ea70a0ce3177/jsonschema-4.24.0.tar.gz", hash = "sha256:0b4e8069eb12aedfa881333004bccaec24ecef5a8a6a4b6df142b2cc9599d196", size = 353480, upload-time = "2025-05-26T18:48:10.459Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a2/3d/023389198f69c722d039351050738d6755376c8fd343e91dc493ea485905/jsonschema-4.24.0-py3-none-any.whl", hash = "sha256:a462455f19f5faf404a7902952b6f0e3ce868f3ee09a359b05eca6673bd8412d", size = 88709, upload-time = "2025-05-26T18:48:08.417Z" }, +] + +[[package]] +name = "jsonschema-specifications" +version = "2025.4.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "referencing" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bf/ce/46fbd9c8119cfc3581ee5643ea49464d168028cfb5caff5fc0596d0cf914/jsonschema_specifications-2025.4.1.tar.gz", hash = "sha256:630159c9f4dbea161a6a2205c3011cc4f18ff381b189fff48bb39b9bf26ae608", size = 15513, upload-time = "2025-04-23T12:34:07.418Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/01/0e/b27cdbaccf30b890c40ed1da9fd4a3593a5cf94dae54fb34f8a4b74fcd3f/jsonschema_specifications-2025.4.1-py3-none-any.whl", hash = "sha256:4653bffbd6584f7de83a67e0d620ef16900b390ddc7939d56684d6c81e33f1af", size = 18437, upload-time = "2025-04-23T12:34:05.422Z" }, +] + +[[package]] +name = "markupsafe" +version = "3.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537, upload-time = "2024-10-18T15:21:54.129Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274, upload-time = "2024-10-18T15:21:13.777Z" }, + { url = "https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348, upload-time = "2024-10-18T15:21:14.822Z" }, + { url = "https://files.pythonhosted.org/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149, upload-time = "2024-10-18T15:21:15.642Z" }, + { url = "https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", size = 23118, upload-time = "2024-10-18T15:21:17.133Z" }, + { url = "https://files.pythonhosted.org/packages/d5/da/f2eeb64c723f5e3777bc081da884b414671982008c47dcc1873d81f625b6/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", size = 22993, upload-time = "2024-10-18T15:21:18.064Z" }, + { url = "https://files.pythonhosted.org/packages/da/0e/1f32af846df486dce7c227fe0f2398dc7e2e51d4a370508281f3c1c5cddc/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", size = 24178, upload-time = "2024-10-18T15:21:18.859Z" }, + { url = "https://files.pythonhosted.org/packages/c4/f6/bb3ca0532de8086cbff5f06d137064c8410d10779c4c127e0e47d17c0b71/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", size = 23319, upload-time = "2024-10-18T15:21:19.671Z" }, + { url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352, upload-time = "2024-10-18T15:21:20.971Z" }, + { url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097, upload-time = "2024-10-18T15:21:22.646Z" }, + { url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601, upload-time = "2024-10-18T15:21:23.499Z" }, +] + +[[package]] +name = "opentelemetry-api" +version = "1.21.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "deprecated" }, + { name = "importlib-metadata" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4d/aa/1a10f310275fdd05a1062d4a8a641a5f041db2377956a80ff3c4dc325a6c/opentelemetry_api-1.21.0.tar.gz", hash = "sha256:d6185fd5043e000075d921822fd2d26b953eba8ca21b1e2fa360dd46a7686316", size = 56674, upload-time = "2023-11-07T23:16:23.155Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/51/3a/945e6c21f405ac4ea526f91ee09cc1568c04e0c95d3392903e6984c8f0e0/opentelemetry_api-1.21.0-py3-none-any.whl", hash = "sha256:4bb86b28627b7e41098f0e93280fe4892a1abed1b79a19aec6f928f39b17dffb", size = 57947, upload-time = "2023-11-07T23:15:46.656Z" }, +] + +[[package]] +name = "ops" +version = "2.22.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "importlib-metadata" }, + { name = "opentelemetry-api" }, + { name = "pyyaml" }, + { name = "websocket-client" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/1f/44/b13d1722ea3211390a9ba3c65acb7c8806168858d8568dcb52192fff161d/ops-2.22.0.tar.gz", hash = "sha256:bd1cd1229e83efb8ae2d97d8878c7db3deceb6819eb5a38fb6e235a959528ec2", size = 500975, upload-time = "2025-05-29T04:18:46.521Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/19/09/9636766721d4d34fc0fc768d0c74f006a772368d5e68ceba6b9c32407ce5/ops-2.22.0-py3-none-any.whl", hash = "sha256:ad44326bc065e33357b47e1cf4c73e811b2fdb3c89dd0c9bdf421a7a028bdcf7", size = 182680, upload-time = "2025-05-29T04:18:44.01Z" }, +] + +[[package]] +name = "pycparser" +version = "2.22" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1d/b2/31537cf4b1ca988837256c910a668b553fceb8f069bedc4b1c826024b52c/pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", size = 172736, upload-time = "2024-03-30T13:22:22.564Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/13/a3/a812df4e2dd5696d1f351d58b8fe16a405b234ad2886a0dab9183fb78109/pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc", size = 117552, upload-time = "2024-03-30T13:22:20.476Z" }, +] + +[[package]] +name = "pydantic" +version = "2.11.7" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-types" }, + { name = "pydantic-core" }, + { name = "typing-extensions" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/00/dd/4325abf92c39ba8623b5af936ddb36ffcfe0beae70405d456ab1fb2f5b8c/pydantic-2.11.7.tar.gz", hash = "sha256:d989c3c6cb79469287b1569f7447a17848c998458d49ebe294e975b9baf0f0db", size = 788350, upload-time = "2025-06-14T08:33:17.137Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6a/c0/ec2b1c8712ca690e5d61979dee872603e92b8a32f94cc1b72d53beab008a/pydantic-2.11.7-py3-none-any.whl", hash = "sha256:dde5df002701f6de26248661f6835bbe296a47bf73990135c7d07ce741b9623b", size = 444782, upload-time = "2025-06-14T08:33:14.905Z" }, +] + +[[package]] +name = "pydantic-core" +version = "2.33.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ad/88/5f2260bdfae97aabf98f1778d43f69574390ad787afb646292a638c923d4/pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc", size = 435195, upload-time = "2025-04-23T18:33:52.104Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/8a/2b41c97f554ec8c71f2a8a5f85cb56a8b0956addfe8b0efb5b3d77e8bdc3/pydantic_core-2.33.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc", size = 2009000, upload-time = "2025-04-23T18:31:25.863Z" }, + { url = "https://files.pythonhosted.org/packages/a1/02/6224312aacb3c8ecbaa959897af57181fb6cf3a3d7917fd44d0f2917e6f2/pydantic_core-2.33.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7", size = 1847996, upload-time = "2025-04-23T18:31:27.341Z" }, + { url = "https://files.pythonhosted.org/packages/d6/46/6dcdf084a523dbe0a0be59d054734b86a981726f221f4562aed313dbcb49/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025", size = 1880957, upload-time = "2025-04-23T18:31:28.956Z" }, + { url = "https://files.pythonhosted.org/packages/ec/6b/1ec2c03837ac00886ba8160ce041ce4e325b41d06a034adbef11339ae422/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011", size = 1964199, upload-time = "2025-04-23T18:31:31.025Z" }, + { url = "https://files.pythonhosted.org/packages/2d/1d/6bf34d6adb9debd9136bd197ca72642203ce9aaaa85cfcbfcf20f9696e83/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f", size = 2120296, upload-time = "2025-04-23T18:31:32.514Z" }, + { url = "https://files.pythonhosted.org/packages/e0/94/2bd0aaf5a591e974b32a9f7123f16637776c304471a0ab33cf263cf5591a/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88", size = 2676109, upload-time = "2025-04-23T18:31:33.958Z" }, + { url = "https://files.pythonhosted.org/packages/f9/41/4b043778cf9c4285d59742281a769eac371b9e47e35f98ad321349cc5d61/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1", size = 2002028, upload-time = "2025-04-23T18:31:39.095Z" }, + { url = "https://files.pythonhosted.org/packages/cb/d5/7bb781bf2748ce3d03af04d5c969fa1308880e1dca35a9bd94e1a96a922e/pydantic_core-2.33.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b", size = 2100044, upload-time = "2025-04-23T18:31:41.034Z" }, + { url = "https://files.pythonhosted.org/packages/fe/36/def5e53e1eb0ad896785702a5bbfd25eed546cdcf4087ad285021a90ed53/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1", size = 2058881, upload-time = "2025-04-23T18:31:42.757Z" }, + { url = "https://files.pythonhosted.org/packages/01/6c/57f8d70b2ee57fc3dc8b9610315949837fa8c11d86927b9bb044f8705419/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6", size = 2227034, upload-time = "2025-04-23T18:31:44.304Z" }, + { url = "https://files.pythonhosted.org/packages/27/b9/9c17f0396a82b3d5cbea4c24d742083422639e7bb1d5bf600e12cb176a13/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea", size = 2234187, upload-time = "2025-04-23T18:31:45.891Z" }, + { url = "https://files.pythonhosted.org/packages/b0/6a/adf5734ffd52bf86d865093ad70b2ce543415e0e356f6cacabbc0d9ad910/pydantic_core-2.33.2-cp312-cp312-win32.whl", hash = "sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290", size = 1892628, upload-time = "2025-04-23T18:31:47.819Z" }, + { url = "https://files.pythonhosted.org/packages/43/e4/5479fecb3606c1368d496a825d8411e126133c41224c1e7238be58b87d7e/pydantic_core-2.33.2-cp312-cp312-win_amd64.whl", hash = "sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2", size = 1955866, upload-time = "2025-04-23T18:31:49.635Z" }, + { url = "https://files.pythonhosted.org/packages/0d/24/8b11e8b3e2be9dd82df4b11408a67c61bb4dc4f8e11b5b0fc888b38118b5/pydantic_core-2.33.2-cp312-cp312-win_arm64.whl", hash = "sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab", size = 1888894, upload-time = "2025-04-23T18:31:51.609Z" }, +] + +[[package]] +name = "pyyaml" +version = "6.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631, upload-time = "2024-08-06T20:33:50.674Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/86/0c/c581167fc46d6d6d7ddcfb8c843a4de25bdd27e4466938109ca68492292c/PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", size = 183873, upload-time = "2024-08-06T20:32:25.131Z" }, + { url = "https://files.pythonhosted.org/packages/a8/0c/38374f5bb272c051e2a69281d71cba6fdb983413e6758b84482905e29a5d/PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", size = 173302, upload-time = "2024-08-06T20:32:26.511Z" }, + { url = "https://files.pythonhosted.org/packages/c3/93/9916574aa8c00aa06bbac729972eb1071d002b8e158bd0e83a3b9a20a1f7/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", size = 739154, upload-time = "2024-08-06T20:32:28.363Z" }, + { url = "https://files.pythonhosted.org/packages/95/0f/b8938f1cbd09739c6da569d172531567dbcc9789e0029aa070856f123984/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", size = 766223, upload-time = "2024-08-06T20:32:30.058Z" }, + { url = "https://files.pythonhosted.org/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", size = 767542, upload-time = "2024-08-06T20:32:31.881Z" }, + { url = "https://files.pythonhosted.org/packages/d4/00/dd137d5bcc7efea1836d6264f049359861cf548469d18da90cd8216cf05f/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", size = 731164, upload-time = "2024-08-06T20:32:37.083Z" }, + { url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611, upload-time = "2024-08-06T20:32:38.898Z" }, + { url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591, upload-time = "2024-08-06T20:32:40.241Z" }, + { url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338, upload-time = "2024-08-06T20:32:41.93Z" }, +] + +[[package]] +name = "referencing" +version = "0.36.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "rpds-py" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2f/db/98b5c277be99dd18bfd91dd04e1b759cad18d1a338188c936e92f921c7e2/referencing-0.36.2.tar.gz", hash = "sha256:df2e89862cd09deabbdba16944cc3f10feb6b3e6f18e902f7cc25609a34775aa", size = 74744, upload-time = "2025-01-25T08:48:16.138Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/b1/3baf80dc6d2b7bc27a95a67752d0208e410351e3feb4eb78de5f77454d8d/referencing-0.36.2-py3-none-any.whl", hash = "sha256:e8699adbbf8b5c7de96d8ffa0eb5c158b3beafce084968e2ea8bb08c6794dcd0", size = 26775, upload-time = "2025-01-25T08:48:14.241Z" }, +] + +[[package]] +name = "rpds-py" +version = "0.25.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8c/a6/60184b7fc00dd3ca80ac635dd5b8577d444c57e8e8742cecabfacb829921/rpds_py-0.25.1.tar.gz", hash = "sha256:8960b6dac09b62dac26e75d7e2c4a22efb835d827a7278c34f72b2b84fa160e3", size = 27304, upload-time = "2025-05-21T12:46:12.502Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7f/81/28ab0408391b1dc57393653b6a0cf2014cc282cc2909e4615e63e58262be/rpds_py-0.25.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:b5ffe453cde61f73fea9430223c81d29e2fbf412a6073951102146c84e19e34c", size = 364647, upload-time = "2025-05-21T12:43:28.559Z" }, + { url = "https://files.pythonhosted.org/packages/2c/9a/7797f04cad0d5e56310e1238434f71fc6939d0bc517192a18bb99a72a95f/rpds_py-0.25.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:115874ae5e2fdcfc16b2aedc95b5eef4aebe91b28e7e21951eda8a5dc0d3461b", size = 350454, upload-time = "2025-05-21T12:43:30.615Z" }, + { url = "https://files.pythonhosted.org/packages/69/3c/93d2ef941b04898011e5d6eaa56a1acf46a3b4c9f4b3ad1bbcbafa0bee1f/rpds_py-0.25.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a714bf6e5e81b0e570d01f56e0c89c6375101b8463999ead3a93a5d2a4af91fa", size = 389665, upload-time = "2025-05-21T12:43:32.629Z" }, + { url = "https://files.pythonhosted.org/packages/c1/57/ad0e31e928751dde8903a11102559628d24173428a0f85e25e187defb2c1/rpds_py-0.25.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:35634369325906bcd01577da4c19e3b9541a15e99f31e91a02d010816b49bfda", size = 403873, upload-time = "2025-05-21T12:43:34.576Z" }, + { url = "https://files.pythonhosted.org/packages/16/ad/c0c652fa9bba778b4f54980a02962748479dc09632e1fd34e5282cf2556c/rpds_py-0.25.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d4cb2b3ddc16710548801c6fcc0cfcdeeff9dafbc983f77265877793f2660309", size = 525866, upload-time = "2025-05-21T12:43:36.123Z" }, + { url = "https://files.pythonhosted.org/packages/2a/39/3e1839bc527e6fcf48d5fec4770070f872cdee6c6fbc9b259932f4e88a38/rpds_py-0.25.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9ceca1cf097ed77e1a51f1dbc8d174d10cb5931c188a4505ff9f3e119dfe519b", size = 416886, upload-time = "2025-05-21T12:43:38.034Z" }, + { url = "https://files.pythonhosted.org/packages/7a/95/dd6b91cd4560da41df9d7030a038298a67d24f8ca38e150562644c829c48/rpds_py-0.25.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c2cd1a4b0c2b8c5e31ffff50d09f39906fe351389ba143c195566056c13a7ea", size = 390666, upload-time = "2025-05-21T12:43:40.065Z" }, + { url = "https://files.pythonhosted.org/packages/64/48/1be88a820e7494ce0a15c2d390ccb7c52212370badabf128e6a7bb4cb802/rpds_py-0.25.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1de336a4b164c9188cb23f3703adb74a7623ab32d20090d0e9bf499a2203ad65", size = 425109, upload-time = "2025-05-21T12:43:42.263Z" }, + { url = "https://files.pythonhosted.org/packages/cf/07/3e2a17927ef6d7720b9949ec1b37d1e963b829ad0387f7af18d923d5cfa5/rpds_py-0.25.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9fca84a15333e925dd59ce01da0ffe2ffe0d6e5d29a9eeba2148916d1824948c", size = 567244, upload-time = "2025-05-21T12:43:43.846Z" }, + { url = "https://files.pythonhosted.org/packages/d2/e5/76cf010998deccc4f95305d827847e2eae9c568099c06b405cf96384762b/rpds_py-0.25.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:88ec04afe0c59fa64e2f6ea0dd9657e04fc83e38de90f6de201954b4d4eb59bd", size = 596023, upload-time = "2025-05-21T12:43:45.932Z" }, + { url = "https://files.pythonhosted.org/packages/52/9a/df55efd84403736ba37a5a6377b70aad0fd1cb469a9109ee8a1e21299a1c/rpds_py-0.25.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a8bd2f19e312ce3e1d2c635618e8a8d8132892bb746a7cf74780a489f0f6cdcb", size = 561634, upload-time = "2025-05-21T12:43:48.263Z" }, + { url = "https://files.pythonhosted.org/packages/ab/aa/dc3620dd8db84454aaf9374bd318f1aa02578bba5e567f5bf6b79492aca4/rpds_py-0.25.1-cp312-cp312-win32.whl", hash = "sha256:e5e2f7280d8d0d3ef06f3ec1b4fd598d386cc6f0721e54f09109a8132182fbfe", size = 222713, upload-time = "2025-05-21T12:43:49.897Z" }, + { url = "https://files.pythonhosted.org/packages/a3/7f/7cef485269a50ed5b4e9bae145f512d2a111ca638ae70cc101f661b4defd/rpds_py-0.25.1-cp312-cp312-win_amd64.whl", hash = "sha256:db58483f71c5db67d643857404da360dce3573031586034b7d59f245144cc192", size = 235280, upload-time = "2025-05-21T12:43:51.893Z" }, + { url = "https://files.pythonhosted.org/packages/99/f2/c2d64f6564f32af913bf5f3f7ae41c7c263c5ae4c4e8f1a17af8af66cd46/rpds_py-0.25.1-cp312-cp312-win_arm64.whl", hash = "sha256:6d50841c425d16faf3206ddbba44c21aa3310a0cebc3c1cdfc3e3f4f9f6f5728", size = 225399, upload-time = "2025-05-21T12:43:53.351Z" }, +] + +[[package]] +name = "tenacity" +version = "9.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0a/d4/2b0cd0fe285e14b36db076e78c93766ff1d529d70408bd1d2a5a84f1d929/tenacity-9.1.2.tar.gz", hash = "sha256:1169d376c297e7de388d18b4481760d478b0e99a777cad3a9c86e556f4b697cb", size = 48036, upload-time = "2025-04-02T08:25:09.966Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e5/30/643397144bfbfec6f6ef821f36f33e57d35946c44a2352d3c9f0ae847619/tenacity-9.1.2-py3-none-any.whl", hash = "sha256:f77bf36710d8b73a50b2dd155c97b870017ad21afe6ab300326b0371b3b05138", size = 28248, upload-time = "2025-04-02T08:25:07.678Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.14.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d1/bc/51647cd02527e87d05cb083ccc402f93e441606ff1f01739a62c8ad09ba5/typing_extensions-4.14.0.tar.gz", hash = "sha256:8676b788e32f02ab42d9e7c61324048ae4c6d844a399eebace3d4979d75ceef4", size = 107423, upload-time = "2025-06-02T14:52:11.399Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/69/e0/552843e0d356fbb5256d21449fa957fa4eff3bbc135a74a691ee70c7c5da/typing_extensions-4.14.0-py3-none-any.whl", hash = "sha256:a1514509136dd0b477638fc68d6a91497af5076466ad0fa6c338e44e359944af", size = 43839, upload-time = "2025-06-02T14:52:10.026Z" }, +] + +[[package]] +name = "typing-inspection" +version = "0.4.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f8/b1/0c11f5058406b3af7609f121aaa6b609744687f1d158b3c3a5bf4cc94238/typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28", size = 75726, upload-time = "2025-05-21T18:55:23.885Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/17/69/cd203477f944c353c31bade965f880aa1061fd6bf05ded0726ca845b6ff7/typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51", size = 14552, upload-time = "2025-05-21T18:55:22.152Z" }, +] + +[[package]] +name = "websocket-client" +version = "1.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e6/30/fba0d96b4b5fbf5948ed3f4681f7da2f9f64512e1d303f94b4cc174c24a5/websocket_client-1.8.0.tar.gz", hash = "sha256:3239df9f44da632f96012472805d40a23281a991027ce11d2f45a6f24ac4c3da", size = 54648, upload-time = "2024-04-23T22:16:16.976Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/84/44687a29792a70e111c5c477230a72c4b957d88d16141199bf9acb7537a3/websocket_client-1.8.0-py3-none-any.whl", hash = "sha256:17b44cc997f5c498e809b22cdf2d9c7a9e71c02c8cc2b6c56e7c2d1239bfa526", size = 58826, upload-time = "2024-04-23T22:16:14.422Z" }, +] + +[[package]] +name = "wrapt" +version = "1.17.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/fc/e91cc220803d7bc4db93fb02facd8461c37364151b8494762cc88b0fbcef/wrapt-1.17.2.tar.gz", hash = "sha256:41388e9d4d1522446fe79d3213196bd9e3b301a336965b9e27ca2788ebd122f3", size = 55531, upload-time = "2025-01-14T10:35:45.465Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a1/bd/ab55f849fd1f9a58ed7ea47f5559ff09741b25f00c191231f9f059c83949/wrapt-1.17.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:d5e2439eecc762cd85e7bd37161d4714aa03a33c5ba884e26c81559817ca0925", size = 53799, upload-time = "2025-01-14T10:33:57.4Z" }, + { url = "https://files.pythonhosted.org/packages/53/18/75ddc64c3f63988f5a1d7e10fb204ffe5762bc663f8023f18ecaf31a332e/wrapt-1.17.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3fc7cb4c1c744f8c05cd5f9438a3caa6ab94ce8344e952d7c45a8ed59dd88392", size = 38821, upload-time = "2025-01-14T10:33:59.334Z" }, + { url = "https://files.pythonhosted.org/packages/48/2a/97928387d6ed1c1ebbfd4efc4133a0633546bec8481a2dd5ec961313a1c7/wrapt-1.17.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8fdbdb757d5390f7c675e558fd3186d590973244fab0c5fe63d373ade3e99d40", size = 38919, upload-time = "2025-01-14T10:34:04.093Z" }, + { url = "https://files.pythonhosted.org/packages/73/54/3bfe5a1febbbccb7a2f77de47b989c0b85ed3a6a41614b104204a788c20e/wrapt-1.17.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5bb1d0dbf99411f3d871deb6faa9aabb9d4e744d67dcaaa05399af89d847a91d", size = 88721, upload-time = "2025-01-14T10:34:07.163Z" }, + { url = "https://files.pythonhosted.org/packages/25/cb/7262bc1b0300b4b64af50c2720ef958c2c1917525238d661c3e9a2b71b7b/wrapt-1.17.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d18a4865f46b8579d44e4fe1e2bcbc6472ad83d98e22a26c963d46e4c125ef0b", size = 80899, upload-time = "2025-01-14T10:34:09.82Z" }, + { url = "https://files.pythonhosted.org/packages/2a/5a/04cde32b07a7431d4ed0553a76fdb7a61270e78c5fd5a603e190ac389f14/wrapt-1.17.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc570b5f14a79734437cb7b0500376b6b791153314986074486e0b0fa8d71d98", size = 89222, upload-time = "2025-01-14T10:34:11.258Z" }, + { url = "https://files.pythonhosted.org/packages/09/28/2e45a4f4771fcfb109e244d5dbe54259e970362a311b67a965555ba65026/wrapt-1.17.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6d9187b01bebc3875bac9b087948a2bccefe464a7d8f627cf6e48b1bbae30f82", size = 86707, upload-time = "2025-01-14T10:34:12.49Z" }, + { url = "https://files.pythonhosted.org/packages/c6/d2/dcb56bf5f32fcd4bd9aacc77b50a539abdd5b6536872413fd3f428b21bed/wrapt-1.17.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:9e8659775f1adf02eb1e6f109751268e493c73716ca5761f8acb695e52a756ae", size = 79685, upload-time = "2025-01-14T10:34:15.043Z" }, + { url = "https://files.pythonhosted.org/packages/80/4e/eb8b353e36711347893f502ce91c770b0b0929f8f0bed2670a6856e667a9/wrapt-1.17.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e8b2816ebef96d83657b56306152a93909a83f23994f4b30ad4573b00bd11bb9", size = 87567, upload-time = "2025-01-14T10:34:16.563Z" }, + { url = "https://files.pythonhosted.org/packages/17/27/4fe749a54e7fae6e7146f1c7d914d28ef599dacd4416566c055564080fe2/wrapt-1.17.2-cp312-cp312-win32.whl", hash = "sha256:468090021f391fe0056ad3e807e3d9034e0fd01adcd3bdfba977b6fdf4213ea9", size = 36672, upload-time = "2025-01-14T10:34:17.727Z" }, + { url = "https://files.pythonhosted.org/packages/15/06/1dbf478ea45c03e78a6a8c4be4fdc3c3bddea5c8de8a93bc971415e47f0f/wrapt-1.17.2-cp312-cp312-win_amd64.whl", hash = "sha256:ec89ed91f2fa8e3f52ae53cd3cf640d6feff92ba90d62236a81e4e563ac0e991", size = 38865, upload-time = "2025-01-14T10:34:19.577Z" }, + { url = "https://files.pythonhosted.org/packages/2d/82/f56956041adef78f849db6b289b282e72b55ab8045a75abad81898c28d19/wrapt-1.17.2-py3-none-any.whl", hash = "sha256:b18f2d1533a71f069c7f82d524a52599053d4c7166e9dd374ae2136b7f40f7c8", size = 23594, upload-time = "2025-01-14T10:35:44.018Z" }, +] + +[[package]] +name = "zipp" +version = "3.23.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e3/02/0f2892c661036d50ede074e376733dca2ae7c6eb617489437771209d4180/zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166", size = 25547, upload-time = "2025-06-08T17:06:39.4Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e", size = 10276, upload-time = "2025-06-08T17:06:38.034Z" }, +] diff --git a/ops-sunbeam/tests/unit_tests/test_core.py b/ops-sunbeam/tests/unit_tests/test_core.py index 9cb62cf5..c421e735 100644 --- a/ops-sunbeam/tests/unit_tests/test_core.py +++ b/ops-sunbeam/tests/unit_tests/test_core.py @@ -598,6 +598,14 @@ class TestOSBaseOperatorCharmSnap(test_utils.CharmTestCase): self.harness.begin() self.addCleanup(self.harness.cleanup) + def test_snap_name_property(self): + """Test snap_name property returns configured snap name.""" + self.assertEqual(self.harness.charm.snap_name, "mysnap") + + def test_snap_channel_property_default(self): + """Test snap_channel property returns default value.""" + self.assertEqual(self.harness.charm.snap_channel, "latest/stable") + def test_set_snap_data(self) -> None: """Test snap set data.""" charm = self.harness.charm diff --git a/render_bundles.py b/render_bundles.py index d8bae7a3..29a58a17 100644 --- a/render_bundles.py +++ b/render_bundles.py @@ -37,7 +37,7 @@ from jinja2 import ( test_directories = [dir_.name for dir_ in list(Path("tests").glob('*')) if dir_.name != "local"] built_charms = glob.glob("*.charm") context = { - charm.rstrip(".charm").replace("-", "_"): True for charm in built_charms + charm.replace(".charm", "").replace("-", "_"): True for charm in built_charms } print(f"Using context: {context}") diff --git a/tests/local/zaza/sunbeam/charm_tests/epa_orchestrator/__init__.py b/tests/local/zaza/sunbeam/charm_tests/epa_orchestrator/__init__.py new file mode 100644 index 00000000..04665cf0 --- /dev/null +++ b/tests/local/zaza/sunbeam/charm_tests/epa_orchestrator/__init__.py @@ -0,0 +1,14 @@ +# Copyright (c) 2025 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. \ No newline at end of file diff --git a/tests/local/zaza/sunbeam/charm_tests/epa_orchestrator/tests.py b/tests/local/zaza/sunbeam/charm_tests/epa_orchestrator/tests.py new file mode 100644 index 00000000..3ac6fef6 --- /dev/null +++ b/tests/local/zaza/sunbeam/charm_tests/epa_orchestrator/tests.py @@ -0,0 +1,80 @@ +# Copyright (c) 2025 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 logging +import subprocess + +import zaza.model as model +import zaza.openstack.charm_tests.test_utils as test_utils + + +class EpaOrchestratorTest(test_utils.BaseCharmTest): + """Charm tests for epa-orchestrator.""" + snap_name = "epa-orchestrator" + + @classmethod + def setUpClass(cls): + """Run class setup for running tests.""" + super(EpaOrchestratorTest, cls).setUpClass( + application_name="epa-orchestrator" + ) + + def _get_units(self) -> list[str]: + """Get the units.""" + return [unit.name for unit in model.get_units(self.application_name)] + + def _run_ssh_command(self, unit: str, command: list[str]): + """Run a command on a unit via SSH.""" + cmd = ["juju", "ssh", unit] + command + try: + stdout = subprocess.check_output(cmd, stderr=subprocess.STDOUT) + return stdout.decode("utf-8").strip() + except subprocess.CalledProcessError as e: + logging.exception("Failed to run command on %s: %s", unit, e.output) + self.fail("Failed to run command on {}: {}".format(unit, e.output)) + + def _check_snap_installed(self, unit: str, snap_name: str) -> bool: + """Check if a snap is installed on the unit.""" + try: + output = self._run_ssh_command(unit, ["snap", "list", snap_name]) + return snap_name in output + except Exception: + return False + + def test_100_snap_installed(self): + """Test that the epa-orchestrator snap is installed.""" + units = self._get_units() + for unit in units: + with self.subTest(unit=unit): + logging.info("Checking if snap %s is installed on %s", self.snap_name, unit) + self.assertTrue( + self._check_snap_installed(unit, self.snap_name), + f"Snap {self.snap_name} is not installed on {unit}" + ) + + def test_200_charm_status_active(self): + """Test that all units are in active status.""" + units = self._get_units() + for unit in units: + with self.subTest(unit=unit): + model.block_until_unit_wl_status(unit, "active", timeout=60 * 5) + status = model.get_status() + unit_status = status.applications[self.application_name]["units"][unit] + current_status = unit_status.workload_status.status + self.assertEqual( + current_status, + "active", + f"Unit {unit} is not in active status, current: {current_status}" + ) \ No newline at end of file diff --git a/tests/machine/smoke.yaml.j2 b/tests/machine/smoke.yaml.j2 index c17110b5..99b2ec4a 100644 --- a/tests/machine/smoke.yaml.j2 +++ b/tests/machine/smoke.yaml.j2 @@ -4,7 +4,7 @@ variables: machines: '0': constraints: *constraints - base: ubuntu@22.04 + base: ubuntu@24.04 applications: sunbeam-machine: @@ -14,7 +14,7 @@ applications: charm: ch:sunbeam-machine channel: 2025.1/edge {% endif -%} - base: ubuntu@22.04 + base: ubuntu@24.04 constraints: *constraints scale: 1 to: @@ -26,20 +26,32 @@ applications: charm: ch:sunbeam-clusterd channel: 2025.1/edge {% endif -%} - base: ubuntu@22.04 + base: ubuntu@24.04 constraints: *constraints scale: 1 to: - '0' tls-operator: charm: self-signed-certificates - channel: latest/beta - base: ubuntu@22.04 + channel: 1/beta + base: ubuntu@24.04 scale: 1 options: ca-common-name: internal-ca to: - '0' + epa-orchestrator: + {% if epa_orchestrator is defined and epa_orchestrator is sameas true -%} + charm: ../../../epa-orchestrator.charm + {% else -%} + charm: ch:epa-orchestrator + channel: latest/edge + {% endif -%} + base: ubuntu@24.04 + constraints: *constraints + scale: 1 + to: + - '0' relations: - - tls-operator:certificates diff --git a/tests/machine/tests.yaml b/tests/machine/tests.yaml index 2599c5b0..6bc7551a 100644 --- a/tests/machine/tests.yaml +++ b/tests/machine/tests.yaml @@ -6,6 +6,7 @@ configure: - zaza.charm_tests.noop.setup.basic_setup tests: - zaza.sunbeam.charm_tests.clusterd.tests.ClusterdTest + - zaza.sunbeam.charm_tests.epa_orchestrator.tests.EpaOrchestratorTest tests_options: trust: - smoke @@ -26,3 +27,6 @@ target_deploy_status: tls-operator: workload-status: active workload-status-message-regex: '^$' + epa-orchestrator: + workload-status: active + workload-status-message-regex: '^$' diff --git a/zuul.d/jobs.yaml b/zuul.d/jobs.yaml index 489a2968..b6edd511 100644 --- a/zuul.d/jobs.yaml +++ b/zuul.d/jobs.yaml @@ -142,6 +142,18 @@ - rebuild vars: charm: cinder-ceph-k8s +- job: + name: charm-build-epa-orchestrator + description: Build sunbeam epa-orchestrator charm + run: playbooks/charm/build.yaml + timeout: 3600 + match-on-config-updates: false + files: + - ops-sunbeam/ops_sunbeam/* + - charms/epa-orchestrator/* + - rebuild + vars: + charm: epa-orchestrator - job: name: charm-build-horizon-k8s description: Build sunbeam horizon-k8s charm @@ -601,10 +613,13 @@ soft: true - name: charm-build-sunbeam-clusterd soft: true + - name: charm-build-epa-orchestrator + soft: true files: - ops-sunbeam/ops_sunbeam/ - charms/sunbeam-machine/ - charms/sunbeam-clusterd/ + - charms/epa-orchestrator/ - rebuild - zuul.d/zuul.yaml vars: @@ -612,6 +627,7 @@ charm_jobs: - charm-build-sunbeam-machine - charm-build-sunbeam-clusterd + - charm-build-epa-orchestrator test_dir: tests/machine - job: @@ -705,6 +721,19 @@ - charmhub_token timeout: 3600 +- job: + name: publish-charm-epa-orchestrator + description: | + Publish epa-orchestrator built in gate pipeline. + run: playbooks/charm/publish.yaml + files: + - ops-sunbeam/ops_sunbeam/ + - charms/epa-orchestrator/ + - rebuild + secrets: + - charmhub_token + timeout: 3600 + - job: name: publish-charm-designate-bind-k8s description: | diff --git a/zuul.d/project-templates.yaml b/zuul.d/project-templates.yaml index 22b55745..4873601c 100644 --- a/zuul.d/project-templates.yaml +++ b/zuul.d/project-templates.yaml @@ -60,6 +60,8 @@ nodeset: ubuntu-jammy - charm-build-cinder-volume-ceph: nodeset: ubuntu-jammy + - charm-build-epa-orchestrator: + nodeset: ubuntu-jammy - charm-build-horizon-k8s: nodeset: ubuntu-jammy - charm-build-heat-k8s: @@ -123,6 +125,8 @@ nodeset: ubuntu-jammy - charm-build-cinder-volume-ceph: nodeset: ubuntu-jammy + - charm-build-epa-orchestrator: + nodeset: ubuntu-jammy - charm-build-horizon-k8s: nodeset: ubuntu-jammy - charm-build-heat-k8s: @@ -190,6 +194,8 @@ nodeset: ubuntu-jammy - publish-charm-cinder-volume-ceph: nodeset: ubuntu-jammy + - publish-charm-epa-orchestrator: + nodeset: ubuntu-jammy - publish-charm-horizon-k8s: nodeset: ubuntu-jammy - publish-charm-heat-k8s: diff --git a/zuul.d/secrets.yaml b/zuul.d/secrets.yaml index 1b70c27e..07498c89 100644 --- a/zuul.d/secrets.yaml +++ b/zuul.d/secrets.yaml @@ -1,85 +1,85 @@ - secret: name: charmhub_token data: - # Generated on 2025-05-06T09:43:50+00:00 with 90 days ttl + # Generated on 2025-06-26T07:38:31+00:00 with 90 days ttl value: !encrypted/pkcs1-oaep - - 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 diff --git a/zuul.d/zuul.yaml b/zuul.d/zuul.yaml index 5d7ab0e4..0bd04ef7 100644 --- a/zuul.d/zuul.yaml +++ b/zuul.d/zuul.yaml @@ -50,3 +50,4 @@ sunbeam-clusterd: 2025.1/edge tempest-k8s: 2025.1/edge watcher-k8s: 2025.1/edge + epa-orchestrator: 2025.1/edge