From 7686dd0278adea33e74197b1e4a1105e14b19084 Mon Sep 17 00:00:00 2001 From: Dragomir Penev <6687393+dragomirp@users.noreply.github.com> Date: Tue, 25 Mar 2025 04:48:39 +0200 Subject: [PATCH 001/112] [MISC] Use latest/stable lxd (#804) * Use latest stable lxd * Test tweaks * Test tweaks --- concierge.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/concierge.yaml b/concierge.yaml index 15a78cc947..29d78b95b5 100644 --- a/concierge.yaml +++ b/concierge.yaml @@ -5,6 +5,7 @@ providers: lxd: enable: true bootstrap: true + channel: latest/stable host: snaps: jhack: From 5b34439898bfe201294268504d7a2176cccffc39 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 26 Mar 2025 23:23:32 +0100 Subject: [PATCH 002/112] Update canonical/data-platform-workflows action to v31.0.1 (#805) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/approve_renovate_pr.yaml | 2 +- .github/workflows/check_pr.yaml | 2 +- .github/workflows/ci.yaml | 4 ++-- .github/workflows/promote.yaml | 2 +- .github/workflows/release.yaml | 2 +- .github/workflows/sync_docs.yaml | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/approve_renovate_pr.yaml b/.github/workflows/approve_renovate_pr.yaml index 422766f800..450111576b 100644 --- a/.github/workflows/approve_renovate_pr.yaml +++ b/.github/workflows/approve_renovate_pr.yaml @@ -10,6 +10,6 @@ on: jobs: approve-pr: name: Approve Renovate pull request - uses: canonical/data-platform-workflows/.github/workflows/approve_renovate_pr.yaml@v31.0.0 + uses: canonical/data-platform-workflows/.github/workflows/approve_renovate_pr.yaml@v31.0.1 permissions: pull-requests: write # Needed to approve PR diff --git a/.github/workflows/check_pr.yaml b/.github/workflows/check_pr.yaml index beaa1541a3..84c56d20c7 100644 --- a/.github/workflows/check_pr.yaml +++ b/.github/workflows/check_pr.yaml @@ -15,4 +15,4 @@ on: jobs: check-pr: name: Check pull request - uses: canonical/data-platform-workflows/.github/workflows/check_charm_pr.yaml@v31.0.0 + uses: canonical/data-platform-workflows/.github/workflows/check_charm_pr.yaml@v31.0.1 diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 9d203b8633..cdf5a0e2e6 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -27,7 +27,7 @@ on: jobs: lint: name: Lint - uses: canonical/data-platform-workflows/.github/workflows/lint.yaml@v31.0.0 + uses: canonical/data-platform-workflows/.github/workflows/lint.yaml@v31.0.1 unit-test: name: Unit test charm @@ -49,7 +49,7 @@ jobs: build: name: Build charm - uses: canonical/data-platform-workflows/.github/workflows/build_charm.yaml@v31.0.0 + uses: canonical/data-platform-workflows/.github/workflows/build_charm.yaml@v31.0.1 integration-test: name: Integration test charm diff --git a/.github/workflows/promote.yaml b/.github/workflows/promote.yaml index 7b4c329c6f..03e7bc7a29 100644 --- a/.github/workflows/promote.yaml +++ b/.github/workflows/promote.yaml @@ -25,7 +25,7 @@ on: jobs: promote: name: Promote charm - uses: canonical/data-platform-workflows/.github/workflows/_promote_charm.yaml@v31.0.0 + uses: canonical/data-platform-workflows/.github/workflows/_promote_charm.yaml@v31.0.1 with: track: '14' from-risk: ${{ inputs.from-risk }} diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 5e893a873a..28b9ddc5e1 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -27,7 +27,7 @@ jobs: name: Release charm needs: - ci-tests - uses: canonical/data-platform-workflows/.github/workflows/release_charm.yaml@v31.0.0 + uses: canonical/data-platform-workflows/.github/workflows/release_charm.yaml@v31.0.1 with: channel: 14/edge artifact-prefix: ${{ needs.ci-tests.outputs.artifact-prefix }} diff --git a/.github/workflows/sync_docs.yaml b/.github/workflows/sync_docs.yaml index 475fe4dae0..4b6e361979 100644 --- a/.github/workflows/sync_docs.yaml +++ b/.github/workflows/sync_docs.yaml @@ -10,7 +10,7 @@ on: jobs: sync-docs: name: Sync docs from Discourse - uses: canonical/data-platform-workflows/.github/workflows/sync_docs.yaml@v31.0.0 + uses: canonical/data-platform-workflows/.github/workflows/sync_docs.yaml@v31.0.1 with: reviewers: a-velasco,izmalk permissions: From 667756029e3e92e97e0745b3023647fd845ccee1 Mon Sep 17 00:00:00 2001 From: Dragomir Penev <6687393+dragomirp@users.noreply.github.com> Date: Fri, 28 Mar 2025 15:15:44 +0200 Subject: [PATCH 003/112] [DPE-6874] Poll all members in the cluster topology script (#810) * Poll all members in the cluster topology script * Dual branch config * Unit tests and bugfixes * Add peers when starting the observer * Retry sync up checks --- .github/renovate.json5 | 26 +------ .github/workflows/check_pr.yaml | 1 + scripts/cluster_topology_observer.py | 45 +++++++++--- src/charm.py | 42 +++++------ src/cluster_topology_observer.py | 7 +- tests/integration/ha_tests/helpers.py | 12 ++- tests/unit/test_charm.py | 6 -- tests/unit/test_cluster_topology_observer.py | 77 ++++++++++++++------ 8 files changed, 124 insertions(+), 92 deletions(-) diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 34085c9225..cd60ef68a5 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -6,6 +6,7 @@ reviewers: [ 'team:data-platform-postgresql', ], + "baseBranches": ["main", "/^*\\/edge$/"], packageRules: [ { matchPackageNames: [ @@ -13,32 +14,7 @@ ], allowedVersions: '<2.0.0', }, - { - matchManagers: [ - 'custom.regex', - ], - matchDepNames: [ - 'juju', - ], - matchDatasources: [ - 'pypi', - ], - allowedVersions: '<3', - groupName: 'Juju agents', - }, ], customManagers: [ - { - customType: 'regex', - fileMatch: [ - '^\\.github/workflows/[^/]+\\.ya?ml$', - ], - matchStrings: [ - '(libjuju: )==(?.*?) +# renovate: latest libjuju 2', - ], - depNameTemplate: 'juju', - datasourceTemplate: 'pypi', - versioningTemplate: 'loose', - }, ], } diff --git a/.github/workflows/check_pr.yaml b/.github/workflows/check_pr.yaml index 84c56d20c7..f613a6aed9 100644 --- a/.github/workflows/check_pr.yaml +++ b/.github/workflows/check_pr.yaml @@ -11,6 +11,7 @@ on: - edited branches: - main + - '*/edge' jobs: check-pr: diff --git a/scripts/cluster_topology_observer.py b/scripts/cluster_topology_observer.py index 346d461319..c41ee34207 100644 --- a/scripts/cluster_topology_observer.py +++ b/scripts/cluster_topology_observer.py @@ -8,6 +8,7 @@ import sys from ssl import CERT_NONE, create_default_context from time import sleep +from urllib.parse import urljoin from urllib.request import urlopen API_REQUEST_TIMEOUT = 5 @@ -17,6 +18,10 @@ LOG_FILE_PATH = "/var/log/cluster_topology_observer.log" +class UnreachableUnitsError(Exception): + """Cannot reach any known cluster member.""" + + def dispatch(run_cmd, unit, charm_dir): """Use the input juju-run command to dispatch a :class:`ClusterTopologyChangeEvent`.""" dispatch_sub_cmd = "JUJU_DISPATCH_PATH=hooks/cluster_topology_change {}/dispatch" @@ -29,25 +34,43 @@ def main(): Watch the Patroni API cluster info. When changes are detected, dispatch the change event. """ - patroni_url, run_cmd, unit, charm_dir = sys.argv[1:] + patroni_urls, run_cmd, unit, charm_dir = sys.argv[1:] previous_cluster_topology = {} + urls = [urljoin(url, PATRONI_CLUSTER_STATUS_ENDPOINT) for url in patroni_urls.split(",")] + member_name = unit.replace("/", "-") while True: # Disable TLS chain verification context = create_default_context() context.check_hostname = False context.verify_mode = CERT_NONE - # Scheme is generated by the charm - resp = urlopen( # noqa: S310 - f"{patroni_url}/{PATRONI_CLUSTER_STATUS_ENDPOINT}", - timeout=API_REQUEST_TIMEOUT, - context=context, - ) - cluster_status = json.loads(resp.read()) - current_cluster_topology = { - member["name"]: member["role"] for member in cluster_status["members"] - } + cluster_status = None + for url in urls: + try: + # Scheme is generated by the charm + resp = urlopen( # noqa: S310 + url, + timeout=API_REQUEST_TIMEOUT, + context=context, + ) + cluster_status = json.loads(resp.read()) + break + except Exception as e: + print(f"Failed to contact {url} with {e}") + continue + if not cluster_status: + raise UnreachableUnitsError("Unable to reach cluster members") + current_cluster_topology = {} + urls = [] + for member in cluster_status["members"]: + current_cluster_topology[member["name"]] = member["role"] + member_url = urljoin(member["api_url"], PATRONI_CLUSTER_STATUS_ENDPOINT) + # Call the current unit first + if member["name"] == member_name: + urls.insert(0, member_url) + else: + urls.append(member_url) # If it's the first time the cluster topology was retrieved, then store it and use # it for subsequent checks. diff --git a/src/charm.py b/src/charm.py index 30ca8117a9..ad4f6c2d1a 100755 --- a/src/charm.py +++ b/src/charm.py @@ -385,30 +385,22 @@ def primary_endpoint(self) -> str | None: logger.debug("primary endpoint early exit: Peer relation not joined yet.") return None try: - for attempt in Retrying(stop=stop_after_delay(5), wait=wait_fixed(3)): - with attempt: - primary = self._patroni.get_primary() - if primary is None and (standby_leader := self._patroni.get_standby_leader()): - primary = standby_leader - primary_endpoint = self._patroni.get_member_ip(primary) - # Force a retry if there is no primary or the member that was - # returned is not in the list of the current cluster members - # (like when the cluster was not updated yet after a failed switchover). - if not primary_endpoint or primary_endpoint not in self._units_ips: - # TODO figure out why peer data is not available - if ( - primary_endpoint - and len(self._units_ips) == 1 - and len(self._peers.units) > 1 - ): - logger.warning( - "Possibly incoplete peer data: Will not map primary IP to unit IP" - ) - return primary_endpoint - logger.debug( - "primary endpoint early exit: Primary IP not in cached peer list." - ) - primary_endpoint = None + primary = self._patroni.get_primary() + if primary is None and (standby_leader := self._patroni.get_standby_leader()): + primary = standby_leader + primary_endpoint = self._patroni.get_member_ip(primary) + # Force a retry if there is no primary or the member that was + # returned is not in the list of the current cluster members + # (like when the cluster was not updated yet after a failed switchover). + if not primary_endpoint or primary_endpoint not in self._units_ips: + # TODO figure out why peer data is not available + if primary_endpoint and len(self._units_ips) == 1 and len(self._peers.units) > 1: + logger.warning( + "Possibly incoplete peer data: Will not map primary IP to unit IP" + ) + return primary_endpoint + logger.debug("primary endpoint early exit: Primary IP not in cached peer list.") + primary_endpoint = None except RetryError: return None else: @@ -952,6 +944,8 @@ def _units_ips(self) -> set[str]: # Get all members IPs and remove the current unit IP from the list. addresses = {self._get_unit_ip(unit) for unit in self._peers.units} addresses.add(self._unit_ip) + if None in addresses: + addresses.remove(None) return addresses @property diff --git a/src/cluster_topology_observer.py b/src/cluster_topology_observer.py index 6aff9b29c3..aa85a0e48e 100644 --- a/src/cluster_topology_observer.py +++ b/src/cluster_topology_observer.py @@ -70,12 +70,17 @@ def start_observer(self): if "JUJU_CONTEXT_ID" in new_env: new_env.pop("JUJU_CONTEXT_ID") + urls = [self._charm._patroni._patroni_url] + [ + self._charm._patroni._patroni_url.replace(self._charm._patroni.unit_ip, peer) + for peer in list(self._charm._patroni.peers_ips) + ] + # Input is generated by the charm pid = subprocess.Popen( # noqa: S603 [ "/usr/bin/python3", "scripts/cluster_topology_observer.py", - self._charm._patroni._patroni_url, + ",".join(urls), self._run_cmd, self._charm.unit.name, self._charm.charm_dir, diff --git a/tests/integration/ha_tests/helpers.py b/tests/integration/ha_tests/helpers.py index d9ea25543d..c22cc85c2c 100644 --- a/tests/integration/ha_tests/helpers.py +++ b/tests/integration/ha_tests/helpers.py @@ -240,13 +240,17 @@ async def is_cluster_updated( # Verify that no writes to the database were missed after stopping the writes. logger.info("checking that no writes to the database were missed after stopping the writes") - total_expected_writes = await check_writes(ops_test, use_ip_from_inside) + for attempt in Retrying(stop=stop_after_attempt(3), wait=wait_fixed(5), reraise=True): + with attempt: + total_expected_writes = await check_writes(ops_test, use_ip_from_inside) # Verify that old primary is up-to-date. logger.info("checking that the former primary is up to date with the cluster after restarting") - assert await is_secondary_up_to_date( - ops_test, primary_name, total_expected_writes, use_ip_from_inside - ), "secondary not up to date with the cluster after restarting." + for attempt in Retrying(stop=stop_after_attempt(3), wait=wait_fixed(5), reraise=True): + with attempt: + assert await is_secondary_up_to_date( + ops_test, primary_name, total_expected_writes, use_ip_from_inside + ), "secondary not up to date with the cluster after restarting." async def check_writes( diff --git a/tests/unit/test_charm.py b/tests/unit/test_charm.py index 7de1a502cf..e500a8d099 100644 --- a/tests/unit/test_charm.py +++ b/tests/unit/test_charm.py @@ -177,8 +177,6 @@ def test_patroni_scrape_config_tls(harness): def test_primary_endpoint(harness): with ( - patch("charm.stop_after_delay", new_callable=PropertyMock) as _stop_after_delay, - patch("charm.wait_fixed", new_callable=PropertyMock) as _wait_fixed, patch( "charm.PostgresqlOperatorCharm._units_ips", new_callable=PropertyMock, @@ -190,10 +188,6 @@ def test_primary_endpoint(harness): _patroni.return_value.get_primary.return_value = sentinel.primary assert harness.charm.primary_endpoint == "1.1.1.1" - # Check needed to ensure a fast charm deployment. - _stop_after_delay.assert_called_once_with(5) - _wait_fixed.assert_called_once_with(3) - _patroni.return_value.get_member_ip.assert_called_once_with(sentinel.primary) _patroni.return_value.get_primary.assert_called_once_with() diff --git a/tests/unit/test_cluster_topology_observer.py b/tests/unit/test_cluster_topology_observer.py index f079990251..3d0495b8eb 100644 --- a/tests/unit/test_cluster_topology_observer.py +++ b/tests/unit/test_cluster_topology_observer.py @@ -1,7 +1,9 @@ # Copyright 2023 Canonical Ltd. # See LICENSE file for licensing details. import signal -from unittest.mock import Mock, PropertyMock, patch +import sys +from json import dumps +from unittest.mock import Mock, PropertyMock, call, patch, sentinel import pytest from ops.charm import CharmBase @@ -13,25 +15,7 @@ ClusterTopologyChangeCharmEvents, ClusterTopologyObserver, ) -from scripts.cluster_topology_observer import dispatch - - -# This method will be used by the mock to replace requests.get -def mocked_requests_get(*args, **kwargs): - class MockResponse: - def __init__(self, json_data): - self.json_data = json_data - - def json(self): - return self.json_data - - data = { - "http://server1/cluster": { - "members": [{"name": "postgresql-0", "host": "1.1.1.1", "role": "leader", "lag": "1"}] - } - } - if args[0] in data: - return MockResponse(data[args[0]]) +from scripts.cluster_topology_observer import UnreachableUnitsError, dispatch, main class MockCharm(CharmBase): @@ -48,7 +32,7 @@ def _on_cluster_topology_change(self, _) -> None: @property def _patroni(self) -> Patroni: - return Mock(_patroni_url="http://1.1.1.1:8008/", verify=True) + return Mock(_patroni_url="http://1.1.1.1:8008/", peers_ips={}, verify=True) @property def _peers(self) -> Relation | None: @@ -153,3 +137,54 @@ def test_dispatch(harness): harness.charm.unit.name, f"JUJU_DISPATCH_PATH=hooks/cluster_topology_change {charm_dir}/dispatch", ]) + + +def test_main(): + with ( + patch.object( + sys, + "argv", + ["cmd", "http://server1:8008,http://server2:8008", "run_cmd", "unit/0", "charm_dir"], + ), + patch("scripts.cluster_topology_observer.sleep", return_value=None), + patch("scripts.cluster_topology_observer.urlopen") as _urlopen, + patch("scripts.cluster_topology_observer.subprocess") as _subprocess, + patch( + "scripts.cluster_topology_observer.create_default_context", + return_value=sentinel.sslcontext, + ), + ): + response1 = { + "members": [ + {"name": "unit-2", "api_url": "http://server3:8008/patroni", "role": "standby"}, + {"name": "unit-0", "api_url": "http://server1:8008/patroni", "role": "leader"}, + ] + } + mock1 = Mock() + mock1.read.return_value = dumps(response1) + response2 = { + "members": [ + {"name": "unit-2", "api_url": "https://server3:8008/patroni", "role": "leader"}, + ] + } + mock2 = Mock() + mock2.read.return_value = dumps(response2) + _urlopen.side_effect = [mock1, Exception, mock2] + with pytest.raises(UnreachableUnitsError): + main() + assert _urlopen.call_args_list == [ + # Iteration 1. server2 is not called + call("http://server1:8008/cluster", timeout=5, context=sentinel.sslcontext), + # Iteration 2 local unit server1 is called first + call("http://server1:8008/cluster", timeout=5, context=sentinel.sslcontext), + call("http://server3:8008/cluster", timeout=5, context=sentinel.sslcontext), + # Iteration 3 Last known member is server3 + call("https://server3:8008/cluster", timeout=5, context=sentinel.sslcontext), + ] + + _subprocess.run.assert_called_once_with([ + "run_cmd", + "-u", + "unit/0", + "JUJU_DISPATCH_PATH=hooks/cluster_topology_change charm_dir/dispatch", + ]) From d35b18dd19fb61b1cea25e37e95ee1f67b388cc6 Mon Sep 17 00:00:00 2001 From: Marcelo Henrique Neppel Date: Fri, 4 Apr 2025 09:21:38 -0300 Subject: [PATCH 004/112] [DPE-6572] Add wal_keep_size config option (#799) * Add wal_keep_size config option Signed-off-by: Marcelo Henrique Neppel * Remove parameter addition Signed-off-by: Marcelo Henrique Neppel * Reset durability_wal_keep_size value to PG default Signed-off-by: Marcelo Henrique Neppel --------- Signed-off-by: Marcelo Henrique Neppel --- config.yaml | 6 ++++++ src/charm.py | 1 + src/config.py | 10 ++++++++++ tests/integration/test_db_admin.py | 2 +- 4 files changed, 18 insertions(+), 1 deletion(-) diff --git a/config.yaml b/config.yaml index efcc18d790..8819015d79 100644 --- a/config.yaml +++ b/config.yaml @@ -32,6 +32,12 @@ options: crashes and there are replicas. type: string default: "on" + durability_wal_keep_size: + description: | + Sets the minimum size of the WAL file to be kept for the replication. + Allowed values are: from 0 to 2147483647. + type: int + default: 4096 experimental_max_connections: type: int description: | diff --git a/src/charm.py b/src/charm.py index ad4f6c2d1a..accd6844be 100755 --- a/src/charm.py +++ b/src/charm.py @@ -1919,6 +1919,7 @@ def update_config(self, is_creating_backup: bool = False, no_peers: bool = False self._patroni.bulk_update_parameters_controller_by_patroni({ "max_connections": max_connections, "max_prepared_transactions": self.config.memory_max_prepared_transactions, + "wal_keep_size": self.config.durability_wal_keep_size, }) self._handle_postgresql_restart_need(enable_tls) diff --git a/src/config.py b/src/config.py index d5cb030102..a755ca0f6d 100644 --- a/src/config.py +++ b/src/config.py @@ -23,6 +23,7 @@ class CharmConfig(BaseConfigModel): connection_statement_timeout: int | None cpu_parallel_leader_participation: bool | None durability_synchronous_commit: str | None + durability_wal_keep_size: int | None experimental_max_connections: int | None instance_default_text_search_config: str | None instance_max_locks_per_transaction: int | None @@ -205,6 +206,15 @@ def durability_synchronous_commit_values(cls, value: str) -> str | None: return value + @validator("durability_wal_keep_size") + @classmethod + def durability_wal_keep_size_values(cls, value: int) -> int | None: + """Check durability_wal_keep_size config option is between 0 and 2147483647.""" + if value < 0 or value > 2147483647: + raise ValueError("Value is not between 0 and 2147483647") + + return value + @validator("instance_password_encryption") @classmethod def instance_password_encryption_values(cls, value: str) -> str | None: diff --git a/tests/integration/test_db_admin.py b/tests/integration/test_db_admin.py index 763b7a93cb..81cc03907b 100644 --- a/tests/integration/test_db_admin.py +++ b/tests/integration/test_db_admin.py @@ -44,7 +44,7 @@ async def test_landscape_scalable_bundle_db(ops_test: OpsTest, charm: str) -> No application_name=DATABASE_APP_NAME, num_units=DATABASE_UNITS, base=CHARM_BASE, - config={"profile": "testing"}, + config={"durability_wal_keep_size": 0, "profile": "testing"}, ) # Deploy and test the Landscape Scalable bundle (using this PostgreSQL charm). From dec80ef2ca39620250689e6e91494fef71519327 Mon Sep 17 00:00:00 2001 From: Andreia Date: Tue, 8 Apr 2025 12:54:00 +0200 Subject: [PATCH 005/112] Create pull_request_template.md (#814) --- .github/pull_request_template.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .github/pull_request_template.md diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000000..9a15830dbd --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,7 @@ +## Issue + +## Solution + +## Checklist +- [ ] I have added or updated any relevant documentation. +- [ ] I have cleaned any remaining cloud resources from my accounts. From 727900b8ab87e9360462790105e98fca9862f061 Mon Sep 17 00:00:00 2001 From: Marcelo Henrique Neppel Date: Wed, 9 Apr 2025 08:53:55 -0300 Subject: [PATCH 006/112] Create SECURITY.md (#822) --- SECURITY.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000000..ddba86ad9e --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,25 @@ +# Security policy + +## What qualifies as a security issue + +Credentials leakage, outdated dependencies with known vulnerabilities, and +other issues that could lead to unprivileged or unauthorized access to the +database or the system. + +## Reporting a vulnerability + +The easiest way to report a security issue is through +[GitHub](https://github.com/canonical/postgresql-operator/security/advisories/new). See +[Privately reporting a security +vulnerability](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing/privately-reporting-a-security-vulnerability) +for instructions. + +The repository admins will be notified of the issue and will work with you +to determine whether the issue qualifies as a security issue and, if so, in +which component. We will then handle figuring out a fix, getting a CVE +assigned and coordinating the release of the fix. + +The [Ubuntu Security disclosure and embargo +policy](https://ubuntu.com/security/disclosure-policy) contains more +information about what you can expect when you contact us, and what we +expect from you. From f874a7bef91bbc62e850e12a45eb63f3347a6540 Mon Sep 17 00:00:00 2001 From: Vladimir Izmalkov <48120135+izmalk@users.noreply.github.com> Date: Thu, 10 Apr 2025 09:20:19 +0100 Subject: [PATCH 007/112] Update README file's security section (#827) * Refactor headings for syntax best practice * Update the Security section --- README.md | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 7c3e83c644..cbfdaf3a37 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ To deploy on Kubernetes, please use [Charmed PostgreSQL K8s Operator](https://ch This operator provides a PostgreSQL database with replication enabled: one primary instance and one (or more) hot standby replicas. The Operator in this repository is a Python script which wraps PostgreSQL versions distributed by Ubuntu Jammy series and adding [Patroni](https://github.com/zalando/patroni) on top of it, providing lifecycle management and handling events (install, configure, integrate, remove, etc). ## README contents + * [Basic usage](#basic-usage): Deploy and scale Charmerd PostgreSQL * [Integrations](#integrations-relations): Supported interfaces for integrations * [Contributing](#contributing) @@ -20,6 +21,7 @@ This operator provides a PostgreSQL database with replication enabled: one prima ## Basic usage ### Deployment + Bootstrap a [lxd controller](https://juju.is/docs/olm/lxd#heading--create-a-controller) and create a new Juju model: ```shell @@ -46,7 +48,9 @@ To add replicas to an existing deployment, see the [Add replicas](#add-replicas) >It is generally recommended to have an odd number of units to avoid a "[split-brain](https://en.wikipedia.org/wiki/Split-brain_(computing))" scenario ### Primary replica + To retrieve the primary replica, use the action `get-primary` on any of the units running PostgreSQL. + ```shell juju run postgresql/leader get-primary ``` @@ -58,17 +62,21 @@ Similarly, the primary replica is displayed as a status message in `juju status` #### Add replicas To add more replicas one can use the `juju add-unit` functionality i.e. + ```shell juju add-unit postgresql -n ``` + The implementation of `add-unit` allows the operator to add more than one unit, but functions internally by adding one replica at a time. This is done to avoid multiple replicas syncing from the primary at the same time. #### Remove replicas To scale down the number of replicas the `juju remove-unit` functionality may be used i.e. + ```shell juju remove-unit postgresql ``` + The implementation of `remove-unit` allows the operator to remove more than one unit. The functionality of `remove-unit` functions by removing one replica at a time to avoid downtime. ### Password rotation @@ -76,9 +84,11 @@ The implementation of `remove-unit` allows the operator to remove more than one #### Charm users To rotate the password of users internal to the Charmed PostgreSQL operator, use the `set-password` action as follows: + ```shell juju run postgresql/leader set-password username= password= ``` + >[!NOTE] >Currently, internal users are `operator`, `replication`, `backup` and `rewind`. These users should not be used outside the operator. @@ -90,7 +100,7 @@ To rotate the passwords of users created for integrated applications, the integr Supported [integrations](https://juju.is/docs/olm/relations): -#### New `postgresql_client` interface: +#### New `postgresql_client` interface Current charm relies on [Data Platform libraries](https://charmhub.io/data-platform-libs). Your application should define an interface in `metadata.yaml`: @@ -125,14 +135,15 @@ To remove a relation: juju remove-relation postgresql ``` -#### Legacy `pgsql` interface: +#### Legacy `pgsql` interface + We have also added support for the two database legacy relations from the [original version](https://launchpad.net/postgresql-charm) of the charm via the `pgsql` interface. Please note that these relations will be deprecated. ```shell juju relate postgresql:db mailman3-core juju relate postgresql:db-admin landscape-server ``` -#### `tls-certificates` interface: +#### `tls-certificates` interface The Charmed PostgreSQL Operator also supports TLS encryption on internal and external connections. Below is an example of enabling TLS with the [self-signed certificates charm](https://charmhub.io/self-signed-certificates). @@ -146,19 +157,24 @@ juju integrate postgresql self-signed-certificates # Disable TLS by removing relation. juju remove-relation postgresql self-signed-certificates ``` + >[!WARNING] >The TLS settings shown here are for self-signed-certificates, which are not recommended for production clusters. See the guide [Security with X.509 certificates](https://charmhub.io/topics/security-with-x-509-certificates) for an overview of available certificates charms. ## Security -Security issues in the Charmed PostgreSQL Operator can be reported through [LaunchPad](https://wiki.ubuntu.com/DebuggingSecurity#How%20to%20File). Please do not use GitHub to submit security issues. + +Security issues in the Charmed PostgreSQL Operator can be reported through [private security reports](https://github.com/canonical/postgresql-operator/security/advisories/new) on GitHub. +For more information, see the [Security policy](SECURITY.md). ## Contributing + * For best practices on how to write and contribute to charms, see the [Juju SDK docs](https://juju.is/docs/sdk/how-to) * For more specific developer guidance for contributions to Charmed PostgreSQL, see the file [CONTRIBUTING.md](CONTRIBUTING.md) * Report security issues for the Charmed PostgreSQL Operator through [LaunchPad](https://wiki.ubuntu.com/DebuggingSecurity#How%20to%20File). * Report technical issues, bug reports and feature requests through the [GitHub Issues tab](https://github.com/canonical/postgresql-operator/issues). ## Licensing and trademark + The Charmed PostgreSQL Operator is distributed under the [Apache Software License, version 2.0](https://github.com/canonical/postgresql-operator/blob/main/LICENSE). It installs, operates and depends on [PostgreSQL](https://www.postgresql.org/ftp/source/), which is licensed under the [PostgreSQL License](https://www.postgresql.org/about/licence/), a liberal Open Source license similar to the BSD or MIT licenses. PostgreSQL is a trademark or registered trademark of PostgreSQL Global Development Group. Other trademarks are property of their respective owners. From 852d80c80d53166408c20bc8045d214c76cffd3c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 10 Apr 2025 09:21:04 -0300 Subject: [PATCH 008/112] Sync docs from Discourse (#796) Co-authored-by: GitHub Actions <41898282+github-actions[bot]@users.noreply.github.com> --- docs/explanation.md | 18 ++- docs/explanation/e-architecture.md | 4 + docs/explanation/e-users.md | 15 ++- docs/how-to.md | 6 +- docs/how-to/h-deploy.md | 2 +- docs/how-to/h-enable-profiling.md | 174 +++++++++++++++++++++++++++++ docs/how-to/h-enable-tls.md | 16 +-- docs/how-to/h-external-access.md | 2 +- docs/how-to/h-integrate.md | 6 +- docs/overview.md | 10 +- docs/reference.md | 5 +- docs/reference/r-contacts.md | 11 +- docs/reference/r-sos-report.md | 114 +++++++++++++++++++ docs/tutorial/t-enable-tls.md | 4 +- docs/tutorial/t-set-up.md | 2 +- 15 files changed, 352 insertions(+), 37 deletions(-) create mode 100644 docs/how-to/h-enable-profiling.md create mode 100644 docs/reference/r-sos-report.md diff --git a/docs/explanation.md b/docs/explanation.md index 8fc131b9e6..05c2add64e 100644 --- a/docs/explanation.md +++ b/docs/explanation.md @@ -1,14 +1,22 @@ # Explanation -This section contains pages with more detailed explanations that provide additional context about some of the key concepts behind the PostgreSQL charm: +This section contains pages with more detailed explanations that provide additional context about key concepts behind the PostgreSQL charm. +## Core concepts and design * [Architecture] * [Interfaces and endpoints] +* [Juju] +* [Legacy charm] + +## Operational concepts * [Connection pooling] * [Users] * [Logs] -* [Juju] -* [Legacy charm] + +## Security and hardening +* [Security hardening guide][Security] + * [Cryptography] + @@ -18,4 +26,6 @@ This section contains pages with more detailed explanations that provide additio [Logs]: /t/12099 [Juju]: /t/11985 [Legacy charm]: /t/10690 -[Connection pooling]: /t/15777 \ No newline at end of file +[Connection pooling]: /t/15777 +[Security]: /t/16852 +[Cryptography]: /t/16853 \ No newline at end of file diff --git a/docs/explanation/e-architecture.md b/docs/explanation/e-architecture.md index 25beb72f43..2a9885f514 100644 --- a/docs/explanation/e-architecture.md +++ b/docs/explanation/e-architecture.md @@ -75,6 +75,10 @@ The snap "charmed-postgresql" also ships list of tools used by charm: The charm "[PostgreSQL Test App](https://charmhub.io/postgresql-test-app)" is a Canonical test application to validate the charm installation / functionality and perform the basic performance tests. +### GLAuth + +GLAuth is a secure, easy-to-use and open-sourced LDAP server which provides capabilities to centrally manage accounts across infrastructures. The charm is only available for Kubernetes clouds, under the [GLAuth-K8s operator](https://charmhub.io/glauth-k8s) page, so a cross-controller relation is needed in order to integrate both charms. + ### Grafana Grafana is an open-source visualization tools that allows to query, visualize, alert on, and visualize metrics from mixed datasources in configurable dashboards for observability. This charms is shipped with its own Grafana dashboard and supports integration with the [Grafana Operator](https://charmhub.io/grafana-k8s) to simplify observability. Please follow [COS Monitoring](/t/10600) setup. diff --git a/docs/explanation/e-users.md b/docs/explanation/e-users.md index 2a2c85d186..f0f9ce86da 100644 --- a/docs/explanation/e-users.md +++ b/docs/explanation/e-users.md @@ -1,9 +1,10 @@ # Charm Users explanations -There are two types of users in PostgreSQL: +There are three types of users in PostgreSQL: * Internal users (used by charm operator) -* Relation/integration users (used by related applications) +* Relation users (used by related applications) * Extra user roles (if default permissions are not enough) +* Identity users (used when LDAP is enabled) ## Internal users explanations: @@ -72,7 +73,7 @@ unit-postgresql-1: **Note**: the action `set-password` must be executed on juju leader unit (to update peer relation data with new value). -## Relation/integration users explanations: +## Relation users explanations: The operator created a dedicated user for every application related/integrated with database. Those users are removed on the juju relation/integration removal request. However, DB data stays in place and can be reused on re-created relations (using new user credentials): @@ -99,4 +100,10 @@ postgres=# \du When an application charm requests a new user through the relation/integration it can specify that the user should have the `admin` role in the `extra-user-roles` field. The `admin` role enables the new user to read and write to all databases (for the `postgres` system database it can only read data) and also to create and delete non-system databases. -**Note**: `extra-user-roles` is supported by modern interface `postgresql_client` only and missing for legacy `pgsql` interface. Read more about the supported charm interfaces [here](/t/10251). \ No newline at end of file +**Note**: `extra-user-roles` is supported by modern interface `postgresql_client` only and missing for legacy `pgsql` interface. Read more about the supported charm interfaces [here](/t/10251). + + +## Identity users explanations: +The operator considers Identity users all those that are automatically created when the LDAP integration is enabled, or in other words, the [GLAuth](https://charmhub.io/glauth-k8s) charm is related/integrated. + +When synchronized from the LDAP server, these users do not have any permissions by default, so the LDAP group they belonged to must be mapped to a PostgreSQL pre-defined authorization role by using the `ldap_map` configuration option. \ No newline at end of file diff --git a/docs/how-to.md b/docs/how-to.md index 497d33ce18..c21e3a5086 100644 --- a/docs/how-to.md +++ b/docs/how-to.md @@ -4,7 +4,7 @@ The following guides cover key processes and common tasks for managing and using ## Deployment and setup -The following guides walk you through the details of how to install different cloud services and bootstrap them to Juju: +Installation of different cloud services with Juju: * [Sunbeam] * [LXD] * [MAAS] @@ -13,7 +13,7 @@ The following guides walk you through the details of how to install different cl * [Azure] * [Multi-availability zones (AZ)][Multi-AZ] -The following guides cover some specific deployment scenarios and architectures: +Specific deployment scenarios and architectures: * [Terraform] * [Air-gapped] * [TLS VIP access] @@ -54,7 +54,7 @@ The following guides cover some specific deployment scenarios and architectures: ## Development -This section is aimed at charm developers looking to support PostgreSQL integrations with their charm. +This section is for charm developers looking to support PostgreSQL integrations with their charm. * [Integrate with your charm] * [Migrate data via pg_dump] diff --git a/docs/how-to/h-deploy.md b/docs/how-to/h-deploy.md index 4769d863c6..f73fcb80ac 100644 --- a/docs/how-to/h-deploy.md +++ b/docs/how-to/h-deploy.md @@ -21,7 +21,7 @@ Then, either continue with the `juju` client **or** use the `terraform juju` cli To deploy with the `juju` client: ```shell -juju deploy postgresql +juju deploy postgresql -n ``` > See also: [`juju deploy` command](https://canonical-juju.readthedocs-hosted.com/en/latest/user/reference/juju-cli/list-of-juju-cli-commands/deploy/) diff --git a/docs/how-to/h-enable-profiling.md b/docs/how-to/h-enable-profiling.md new file mode 100644 index 0000000000..aabc52bc34 --- /dev/null +++ b/docs/how-to/h-enable-profiling.md @@ -0,0 +1,174 @@ +[note] +**Note**: All commands are written for `juju >= v3.1` + +If you're using `juju 2.9`, check the [`juju 3.0` Release Notes](https://juju.is/docs/juju/roadmap#heading--juju-3-0-0---22-oct-2022). +[/note] + +# Enable profiling with Parca + +This guide contains the steps to enable profiling with [Parca](https://www.parca.dev/docs/overview/) for your PostgreSQL application. + +## Summary +* [Prerequisites](#prerequisites) +* [Set up the Parca backend](#set-up-the-parca-backend) + * [Charmed Parca K8s](#charmed-parca-k8s) + * [Polar Signals Cloud](#polar-signals-cloud) +* [View profiles](#view-profiles) + +--- + +## Prerequisites + +[note type=caution] +**Do not skip this section** if you are deploying PostgreSQL in an LXD model or if your base is `ubuntu@22.04`. +[/note] + + +This guide assumes you already have a juju model with Charmed PostgreSQL deployed. + +> See: [How to deploy PostgreSQL](/t/16811) + +In order for your Charmed PostgreSQL deployment to be correctly set up for integration with Parca, there are two important considerations: +* [LXD virtualization type](#lxd-virtualization-type) +* [Base (Ubuntu version)](#base-ubuntu-version) + +### LXD virtualization type + +**If you are deploying Charmed PostgreSQL in a LXD model, you will need to ensure that LXD's virtualization type is set to `virtual-machine` for the Juju application.** + +This is because LXD does not allow `/sys/kernel/tracing` to be mounted in a system container (even in privileged mode) due to security isolation concerns. + +To ensure that a virtual machine is used instead of a system container, you would need to add constraints, for example: +``` +juju deploy postgresql --constraints="virt-type=virtual-machine"`. +``` + +### Base (Ubuntu version) +**If your base is `ubuntu@22.04`, you will need to ensure that your are using the `generic` flavor of Linux.** +> See the output of `uname -r` to confirm. + +If you do not have the `generic` flavor, you can enable it on a unit to be profiled as follows: + +``` +juju ssh postgresql/0 bash +sudo apt-get update && sudo apt-get install linux-image-virtual +sudo apt-get autopurge linux-image-kvm +``` + +If your application is deployed in an LXD model, run the following command: +``` +rm /etc/default/grub.d/40-force-partuuid.cfg +``` + +Open the `/etc/default/grub` file with your editor of choice and replace the line that starts with `GRUB_DEFAULT=` with: +``` +release=$(linux-version list | grep -e '-generic$' | sort -V | tail -n1) +GRUB_DEFAULT="Advanced options for Ubuntu>Ubuntu, with Linux $release" +``` + +Exit out of the `/etc/default/grub file`, update GRUB, and reboot: +``` +sudo update-grub +sudo reboot +``` + +Nothing needs to be done if the base is `ubuntu@24.04`, which already loads the kernel symbol table for debugging by default. + +## Set up the Parca backend + +There are two potential backends: +* [Charmed Parca K8s](#charmed-parca-k8s) (requires COS and cross-model integrations) +* [Polar Signals Cloud](#polar-signals-cloud) (COS is optional) + +### Charmed Parca K8s + +This section goes through the steps for enabling profiling with Charmed Parca K8s as the backend. + +#### 1. Deploy `cos-lite` and `parca-k8s` + +Refer to [Getting started on MicroK8s](https://charmhub.io/topics/canonical-observability-stack/tutorials/install-microk8s) and deploy the `cos-lite` bundle from the `latest/edge` track in a Kubernetes environment. + +Then, refer to [Deploy Charmed Parca on top of COS-lite](https://discourse.charmhub.io/t/how-to-deploy-charmed-parca-on-top-of-cos-lite/16579) to deploy Charmed Parca K8s in the same model as the `cos-lite` bundle. + +#### 2. Offer interfaces + +Offer interfaces for cross-model integrations: + +``` +juju offer :parca-store-endpoint +``` + +#### 3. Deploy and integrate `parca-agent` with `postgresql` + +Switch to the model containing the Charmed PostgreSQL deployment, deploy Charmed Parca Agent, and integrate it with Charmed PostgreSQL: + +``` +juju switch : + +juju deploy parca-agent --channel latest/edge +juju integrate postgresql parca-agent +``` + +#### 4. Integrate `parca-agent` with `parca-k8s` + +Consume the parca offer from [Step 2](#2-offer-interfaces) and integrate with them: + +``` +juju find-offers : +``` + +> :exclamation: Do not miss the colon "`:`" in the command above. + +Below is a sample output where `k8s` is the K8s controller name and `cos` is the model where `cos-lite` and `parca-k8s` are deployed: + +``` +Store URL Access Interfaces +k8s admin/cos.parca admin parca_store:parca-store-endpoint +``` + +Next, consume this offer so that is reachable from the current machine model: + +``` +juju consume k8s:admin/cos.parca +``` + +Finally, relate Charmed Parca Agent with the consumed offer endpoint: +``` +juju integrate parca-agent parca +``` + +### Polar Signals Cloud + +This section goes through the steps for enabling profiling with Polar Signals Cloud (PSC) as the backend. + +[note] +With PSC, `cos-lite` and `parca-k8s` are not required. This section goes through the recommended setup, where `polar-signals-cloud-integrator` is deployed in the same model as `postgresql`, and `parca-agent` is used to relay traffic to PSC. + +If you would like to use `parca-k8s` to relay traffic to PSC instead, refer to [Steps 1 and 2](#1-deploy-cos-lite-and-parca-k8s) in the Charmed Parca K8s section. +[/note] + +#### 1. Deploy and integrate `parca-agent` with `postgresql` + +In the machine model where PostgreSQL is deployed, deploy `parca-agent` and integrate it with `postgresql`: + +``` +juju deploy parca-agent --channel latest/edge +juju integrate postgresql parca-agent +``` + +#### 2. Integrate `parca-agent` with `polar-signals-cloud-integrator` + +Follow the guide [How to integrate with Polar Signals Cloud](https://discourse.charmhub.io/t/charmed-parca-docs-how-to-integrate-with-polar-signals-cloud/16559). + + +## View profiles + +After the backend setup is complete, the profiles for the machines where the PostgreSQL units are running will be accessible from the Parca web interface. + +If you are running Charmed Parca K8s, you can also access the link for Parca's web interface from COS catalogue (`juju run traefik/0 show-proxied-endpoints` in the K8s model where `cos-lite` is deployed). + +![Example profile with Parca Web UI690x753](upload://zFOOKY8nokrg2Q4xUVTbD8UGjD3.png) + +Furthermore, if you have `cos-lite` deployed, you can use Grafana to explore profiles under the `Explore` section with `parca-k8s` as the data source. + +![Example profile with Grafana's Parca plugin|690x383](upload://w3G5STYOxMZHCpIA48gEJHUniLi.jpeg) \ No newline at end of file diff --git a/docs/how-to/h-enable-tls.md b/docs/how-to/h-enable-tls.md index c8d8640870..c5a872288d 100644 --- a/docs/how-to/h-enable-tls.md +++ b/docs/how-to/h-enable-tls.md @@ -32,15 +32,9 @@ First, deploy the TLS charm: juju deploy self-signed-certificates ``` -To enable TLS on `postgresql`, integrate the two applications: +To enable TLS integrate (formerly known as “relate”) the two applications: ```shell -juju integrate self-signed-certificates postgresql -``` - -## Disable TLS -Disable TLS by removing the integration. -```shell -juju remove-relation self-signed-certificates postgresql +juju integrate postgresql:certificates self-signed-certificates:certificates ``` ## Check certificates in use @@ -79,4 +73,10 @@ Updates can also be done with auto-generated keys: juju run postgresql/0 set-tls-private-key juju run postgresql/1 set-tls-private-key juju run postgresql/2 set-tls-private-key +``` + +## Disable TLS +Disable TLS by removing the integration. +```shell +juju remove-relation postgresql:certificates self-signed-certificates:certificates ``` \ No newline at end of file diff --git a/docs/how-to/h-external-access.md b/docs/how-to/h-external-access.md index 7182b626d9..023177692b 100644 --- a/docs/how-to/h-external-access.md +++ b/docs/how-to/h-external-access.md @@ -8,7 +8,7 @@ This page summarizes resources for setting up deployments where an external appl There are many possible ways to connect the Charmed PostgreSQL database from outside of the LAN where the database cluster is located. The available options are heavily dependent on the cloud/hardware/virtualization in use. -One of the possible options is to use [virtual IP addresses (VIP)](https://en.wikipedia.org/wiki/Virtual_IP_address) which the charm PgBouncer provides with assistance from the charm/interface `hacluster`. Please follow the [PgBouncer documentation](https://charmhub.io/pgbouncer/docs/h-external-access?channel=1/stable) for such configuration. +One of the possible options is to use [virtual IP addresses (VIP)](https://en.wikipedia.org/wiki/Virtual_IP_address) which the charm PgBouncer provides with assistance from the charm/interface `hacluster`. Please follow the [PgBouncer documentation](https://charmhub.io/pgbouncer/docs/h-external-access) for such configuration. > See also: [How to deploy for external TLS VIP access](/t/16576). diff --git a/docs/how-to/h-integrate.md b/docs/how-to/h-integrate.md index 54a9761380..fa8438764e 100644 --- a/docs/how-to/h-integrate.md +++ b/docs/how-to/h-integrate.md @@ -25,7 +25,9 @@ This guide shows how to integrate Charmed PostgreSQL with both charmed and non-c Integrations with charmed applications are supported via the modern [`postgresql_client`](https://github.com/canonical/charm-relation-interfaces/blob/main/interfaces/postgresql_client/v0/README.md) interface, and the legacy `psql` interface from the [original version](https://launchpad.net/postgresql-charm) of the charm. -> You can see which existing charms are compatible with PostgreSQL in the [Integrations](https://charmhub.io/postgresql/integrations) tab. +[note] +You can see which existing charms are compatible with PostgreSQL in the [Integrations](https://charmhub.io/postgresql/integrations) tab. +[/note] ### Modern `postgresql_client` interface To integrate with a charmed application that supports the `postgresql_client` interface, run @@ -41,7 +43,7 @@ juju remove-relation postgresql ### Legacy `pgsql` interface [note type="caution"] Note that this interface is **deprecated**. -See more information in [Explanation > Legacy charm](/t/10690). +See the [legacy charm explanation page](/t/10690). [/note] To integrate via the legacy interface, run diff --git a/docs/overview.md b/docs/overview.md index 273a9b0f53..958348ebd8 100644 --- a/docs/overview.md +++ b/docs/overview.md @@ -77,6 +77,7 @@ PostgreSQL is a trademark or registered trademark of PostgreSQL Global Developme | 3 | h-enable-monitoring | [Enable monitoring](/t/10600) | | 3 | h-enable-alert-rules | [Enable alert rules](/t/13084) | | 3 | h-enable-tracing | [Enable tracing](/t/14521) | +| 3 | h-enable-profiling | [Enable profiling](/t/17172) | | 2 | h-upgrade | [Upgrade](/t/12086) | | 3 | h-upgrade-minor | [Perform a minor upgrade](/t/12089) | | 3 | h-rollback-minor | [Perform a minor rollback](/t/12090) | @@ -94,20 +95,21 @@ PostgreSQL is a trademark or registered trademark of PostgreSQL Global Developme | 2 | r-software-testing | [Software testing](/t/11773) | | 2 | r-performance | [Performance and resources](/t/11974) | | 2 | r-troubleshooting | [Troubleshooting](/t/11864) | +| 3 | r-sos-report | [SOS report](/t/17228) | | 2 | r-plugins-extensions | [Plugins/extensions](/t/10946) | | 2 | r-alert-rules | [Alert rules](/t/15841) | | 2 | r-statuses | [Statuses](/t/10844) | | 2 | r-contacts | [Contacts](/t/11863) | | 1 | explanation | [Explanation](/t/16768) | | 2 | e-architecture | [Architecture](/t/11857) | -| 2 | e-security | [Security](/t/16852) | -| 2 | e-cryptography | [Cryptography](/t/16853) | | 2 | e-interfaces-endpoints | [Interfaces and endpoints](/t/10251) | +| 2 | e-juju-details | [Juju](/t/11985) | +| 2 | e-legacy-charm | [Legacy charm](/t/10690) | | 2 | e-connection-pooling| [Connection pooling](/t/15777) | | 2 | e-users | [Users](/t/10798) | | 2 | e-logs | [Logs](/t/12099) | -| 2 | e-juju-details | [Juju](/t/11985) | -| 2 | e-legacy-charm | [Legacy charm](/t/10690) | +| 2 | e-security | [Security](/t/16852) | +| 3 | e-cryptography | [Cryptography](/t/16853) | | 1 | search | [Search](https://canonical.com/data/docs/postgresql/iaas) | [/details] diff --git a/docs/reference.md b/docs/reference.md index f686a8f86b..2decbe04cb 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -1,6 +1,6 @@ # Reference -The Reference section of our documentation contains pages for technical specifications, APIs, release notes, and other reference material for fast lookup. +Technical specifications, APIs, release notes, and other reference material for fast lookup. **In the left sidebar navigation**, you will find the following references: | Page | Description | @@ -20,8 +20,7 @@ The Reference section of our documentation contains pages for technical specific | Page | Description | |----------------------------------------------------------------------------|---------------------------------------------------------| -| [Resources](https://charmhub.io/postgresql/resources) | :construction: Under construction | | [Integrations](https://charmhub.io/postgresql/integrations) | Integration/relation interfaces supported by this charm | | [Libraries](https://charmhub.io/postgresql/libraries) | VM charm library is empty as charm uses [K8s library](https://charmhub.io/postgresql-k8s/libraries/) (more info [here](/t/11857)) | -| [Configuration](https://charmhub.io/postgresql/configuration) | Application configuration parameters (more info [here](https://juju.is/docs/juju/configuration?&_ga=2.95573596.1153611399.1713171630-773562698.1708605078#heading--application-configuration)) | +| [Configuration](https://charmhub.io/postgresql/configuration) | Application configuration parameters | | [Actions](https://charmhub.io/postgresql/actions) | Juju actions supported by this charm | \ No newline at end of file diff --git a/docs/reference/r-contacts.md b/docs/reference/r-contacts.md index 8447eab17f..ed3075fe4a 100644 --- a/docs/reference/r-contacts.md +++ b/docs/reference/r-contacts.md @@ -1,15 +1,18 @@ # Contact -Charmed PostgreSQL is an open source project that warmly welcomes community contributions, suggestions, fixes, and constructive feedback. -* Raise software issues or feature requests on [**GitHub**](https://github.com/canonical/postgresql-operator/issues/new/choose) -* Report security issues through [**Launchpad**](https://wiki.ubuntu.com/DebuggingSecurity#How%20to%20File) -* Contact the Canonical Data Platform team through our [Matrix](https://matrix.to/#/#charmhub-data-platform:ubuntu.com) channel. +Charmed PostgreSQL is an open source project that warmly welcomes community contributions, suggestions, fixes, and constructive feedback: + +* [Raise](https://github.com/canonical/postgresql-operator/issues/new/choose) software issues or feature requests +* [Report](https://github.com/canonical/postgresql-operator/security/advisories/new) security issues +* Contact the Canonical Data Platform team directly through our [Matrix](https://matrix.to/#/#charmhub-data-platform:ubuntu.com) channel. + [note] Our legacy [Mattermost](https://chat.charmhub.io/charmhub/channels/data-platform) channel is read-only until January 31, 2025. [/note] Useful links: + * [Canonical Data Fabric](https://ubuntu.com/data/) * [Charmed PostgreSQL](https://charmhub.io/postgresql) * [Git sources for Charmed PostgreSQL](https://github.com/canonical/postgresql-operator) diff --git a/docs/reference/r-sos-report.md b/docs/reference/r-sos-report.md new file mode 100644 index 0000000000..7c1a3a0441 --- /dev/null +++ b/docs/reference/r-sos-report.md @@ -0,0 +1,114 @@ +# SoS report + +SoS is an extensible, portable, support data collection tool primarily aimed at Linux distributions and other UNIX-like operating systems. + +You can use the [built-in version of SoS](#use-built-in-sos-recommended), or [retrieve the latest version from GitHub](#use-the-latest-sos-plugins-from-git). + +[note type=caution] +Always review the collected data before sharing it! + +The generated archive may contain sensitive data. Its content should be reviewed by the originating organization before being passed to any third party. +[/note] + +## Use built-in SoS (recommended) + +Charmed PostgreSQL shipped with built-in [SoS](https://github.com/sosreport/sos) reporting tool. You can use it to collect logs on a specific unit or multiple units at once. + +### Collect logs on one unit + +To generate the troubleshooting report archiving all logs simply call `sos report` inside the relevant Juju unit: +```shell +juju ssh postgresql/0 +> sudo sos report -o system,systemd,snap,charmed_postgresql --low-priority +``` +As a result, the archive will all logs will be generated and can be shared with your support representative: +```shell +... +Your sos report has been generated and saved in: + /tmp/sosreport-juju-d4c067-1-2025-04-07-chdmwlz.tar.xz + + Size 216.36KiB + Owner root + sha256 b3bf2c54bb3d934ca61ab2a17c19e98b2abeafd45589f268b62bd02f6b2a4c5f +... +``` + +Use `juju scp` to copy logs from Juju unit to localhost: +```shell +juju scp postgresql/0:/tmp/sosreport-juju-d4c067-1-2025-04-07-chdmwlz.tar.xz . +``` + +[details="Example output"] +```shell +juju ssh postgresql/0 + +ubuntu@juju-d4c067-1:~$ sudo sos report -o system,systemd,snap,charmed_postgresql --low-priority + +sos report (version 4.8.2) + +This command will collect system configuration and diagnostic +information from this Ubuntu system. + +For more information on Canonical visit: + + Community Website : https://www.ubuntu.com/ + Commercial Support : https://www.canonical.com + +The generated archive may contain data considered sensitive and its +content should be reviewed by the originating organization before being +passed to any third party. + +No changes will be made to system configuration. + + +Press ENTER to continue, or CTRL-C to quit. + +Optionally, please enter the case id that you are generating this report for []: + + Setting up archive ... + Setting up plugins ... + Running plugins. Please wait ... + + Starting 4/4 systemd [Running: charmed_postgresql system snap systemd] + Finishing plugins [Running: charmed_postgresql] + Finished running plugins +Creating compressed archive... + +Your sos report has been generated and saved in: + /tmp/sosreport-juju-d4c067-1-2025-04-07-qntyqpz.tar.xz + + Size 285.60KiB + Owner root + sha256 d318d7de7595ebae1bce093a375129fafbd397c297317de3006fbfe45e93d43d + +Please send this file to your support representative. + +ubuntu@juju-d4c067-1:~$ exit + +juju scp postgresql/0:/tmp/sosreport-juju-d4c067-1-2025-04-07-qntyqpz.tar.xz . +``` +[/details] + +### Collect logs from several units + +The sos tool allows you to collect logs from several Juju units (replace labels with proper Juju unit like `postgresql/0`). + +Run the following command from outside the Juju units: +```shell +sos collect --cluster-type juju --no-local -c "juju.units=,,<...>" --batch -o system,systemd,snap,charmed_postgresql --low-priority +``` + +## Use the latest sos plugins from Git + +The latest version of [sos plugins](https://github.com/sosreport/sos/tree/main/sos/report/plugins) can be retrieved from Git easily: +```shell +git clone https://github.com/sosreport/sos.git +cd sos +sudo ./bin/sos report -­a +``` + +The output will be the same to the example above providing archive with all logs as above: +```shell +Your sos report has been generated and saved in: + /tmp/sosreport-juju-d4c067-1-2025-04-07-egosqmi.tar.xz +``` \ No newline at end of file diff --git a/docs/tutorial/t-enable-tls.md b/docs/tutorial/t-enable-tls.md index 0a425966fb..55f3b1b7e4 100644 --- a/docs/tutorial/t-enable-tls.md +++ b/docs/tutorial/t-enable-tls.md @@ -55,7 +55,7 @@ Machine State Address Inst id Series AZ Message To enable TLS on Charmed PostgreSQL VM, integrate the two applications: ```shell -juju integrate postgresql self-signed-certificates +juju integrate postgresql:certificates self-signed-certificates:certificates ``` PostgreSQL is now using TLS certificate generated by the `self-signed-certificates` charm. @@ -72,7 +72,7 @@ verify error:num=19:self-signed certificate in certificate chain

Remove TLS certificate

To remove the external TLS, remove the integration: ```shell -juju remove-relation postgresql self-signed-certificates +juju remove-relation postgresql:certificates self-signed-certificates:certificates ``` If you once again check the TLS certificates in use via the OpenSSL client, you will see something similar to the output below: diff --git a/docs/tutorial/t-set-up.md b/docs/tutorial/t-set-up.md index bf2ddb57b9..3223686f32 100644 --- a/docs/tutorial/t-set-up.md +++ b/docs/tutorial/t-set-up.md @@ -1,4 +1,4 @@ -> [Charmed PostgreSQL K8s Tutorial](/t/9707) > 1. Set up the environment +> [Charmed PostgreSQL VM Tutorial](/t/9707) > 1. Set up the environment # Set up the environment From 7897bfce5becfc44ba924f3837e382fed4e54d2b Mon Sep 17 00:00:00 2001 From: Dragomir Penev <6687393+dragomirp@users.noreply.github.com> Date: Fri, 11 Apr 2025 05:03:56 +0300 Subject: [PATCH 009/112] [MISC] Conditional checksum calculation (#812) * Bump boto * Conditional checksum calculation --- poetry.lock | 74 +++++++++++++++++++------------------- pyproject.toml | 2 +- src/backups.py | 51 +++++++++++--------------- tests/unit/test_backups.py | 33 ++++++++++++++++- 4 files changed, 90 insertions(+), 70 deletions(-) diff --git a/poetry.lock b/poetry.lock index c776be907a..c70ec34a9b 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.0.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.1.1 and should not be changed by hand. [[package]] name = "allure-pytest" @@ -68,7 +68,7 @@ typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""} [package.extras] doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx_rtd_theme"] -test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "trustme", "truststore (>=0.9.1)", "uvloop (>=0.21)"] +test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "trustme", "truststore (>=0.9.1) ; python_version >= \"3.10\"", "uvloop (>=0.21) ; platform_python_implementation == \"CPython\" and platform_system != \"Windows\" and python_version < \"3.14\""] trio = ["trio (>=0.26.1)"] [[package]] @@ -100,12 +100,12 @@ files = [ ] [package.extras] -benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"] -cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] -dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit-uv", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +benchmark = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] +cov = ["cloudpickle ; platform_python_implementation == \"CPython\"", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] +dev = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pre-commit-uv", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"] -tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] -tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"] +tests = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] +tests-mypy = ["mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\""] [[package]] name = "backoff" @@ -173,34 +173,34 @@ typecheck = ["mypy"] [[package]] name = "boto3" -version = "1.35.99" +version = "1.37.22" description = "The AWS SDK for Python" optional = false python-versions = ">=3.8" groups = ["main", "integration"] files = [ - {file = "boto3-1.35.99-py3-none-any.whl", hash = "sha256:83e560faaec38a956dfb3d62e05e1703ee50432b45b788c09e25107c5058bd71"}, - {file = "boto3-1.35.99.tar.gz", hash = "sha256:e0abd794a7a591d90558e92e29a9f8837d25ece8e3c120e530526fe27eba5fca"}, + {file = "boto3-1.37.22-py3-none-any.whl", hash = "sha256:a14324d5fa5f4fea00c0e3c69754cbd28100f7fe194693eeecf2dc07446cf4ef"}, + {file = "boto3-1.37.22.tar.gz", hash = "sha256:78a0ec0aafbf6044104c98ad80b69e6d1c83d8233fda2c2d241029e6c705c510"}, ] [package.dependencies] -botocore = ">=1.35.99,<1.36.0" +botocore = ">=1.37.22,<1.38.0" jmespath = ">=0.7.1,<2.0.0" -s3transfer = ">=0.10.0,<0.11.0" +s3transfer = ">=0.11.0,<0.12.0" [package.extras] crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.35.99" +version = "1.37.22" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">=3.8" groups = ["main", "integration"] files = [ - {file = "botocore-1.35.99-py3-none-any.whl", hash = "sha256:b22d27b6b617fc2d7342090d6129000af2efd20174215948c0d7ae2da0fab445"}, - {file = "botocore-1.35.99.tar.gz", hash = "sha256:1eab44e969c39c5f3d9a3104a0836c24715579a455f12b3979a31d7cde51b3c3"}, + {file = "botocore-1.37.22-py3-none-any.whl", hash = "sha256:184db7c9314d13002bc827f511a5140574b5da1acda342d51e093dad6317de98"}, + {file = "botocore-1.37.22.tar.gz", hash = "sha256:b3b26f1a90236bcd17d4092f8c85a256b44e9955a16b633319a2f5678d605e9f"}, ] [package.dependencies] @@ -209,7 +209,7 @@ python-dateutil = ">=2.1,<3.0.0" urllib3 = {version = ">=1.25.4,<2.2.0 || >2.2.0,<3", markers = "python_version >= \"3.10\""} [package.extras] -crt = ["awscrt (==0.22.0)"] +crt = ["awscrt (==0.23.8)"] [[package]] name = "cachetools" @@ -433,7 +433,7 @@ files = [ [package.extras] dev = ["Pygments", "build", "chardet", "pre-commit", "pytest", "pytest-cov", "pytest-dependency", "ruff", "tomli", "twine"] hard-encoding-detection = ["chardet"] -toml = ["tomli"] +toml = ["tomli ; python_version < \"3.11\""] types = ["chardet (>=5.1.0)", "mypy", "pytest", "pytest-cov", "pytest-dependency"] [[package]] @@ -546,7 +546,7 @@ files = [ tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} [package.extras] -toml = ["tomli"] +toml = ["tomli ; python_full_version <= \"3.11.0a6\""] [[package]] name = "cryptography" @@ -593,10 +593,10 @@ files = [ cffi = {version = ">=1.12", markers = "platform_python_implementation != \"PyPy\""} [package.extras] -docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=3.0.0)"] +docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=3.0.0) ; python_version >= \"3.8\""] docstest = ["pyenchant (>=3)", "readme-renderer (>=30.0)", "sphinxcontrib-spelling (>=7.3.1)"] -nox = ["nox (>=2024.4.15)", "nox[uv] (>=2024.3.2)"] -pep8test = ["check-sdist", "click (>=8.0.1)", "mypy (>=1.4)", "ruff (>=0.3.6)"] +nox = ["nox (>=2024.4.15)", "nox[uv] (>=2024.3.2) ; python_version >= \"3.8\""] +pep8test = ["check-sdist ; python_version >= \"3.8\"", "click (>=8.0.1)", "mypy (>=1.4)", "ruff (>=0.3.6)"] sdist = ["build (>=1.0.0)"] ssh = ["bcrypt (>=3.1.5)"] test = ["certifi (>=2024)", "cryptography-vectors (==44.0.1)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"] @@ -630,7 +630,7 @@ files = [ wrapt = ">=1.10,<2" [package.extras] -dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "setuptools", "tox"] +dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "setuptools ; python_version >= \"3.12\"", "tox"] [[package]] name = "exceptiongroup" @@ -661,7 +661,7 @@ files = [ ] [package.extras] -tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich"] +tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich ; python_version >= \"3.11\""] [[package]] name = "google-auth" @@ -759,7 +759,7 @@ httpcore = "==1.*" idna = "*" [package.extras] -brotli = ["brotli", "brotlicffi"] +brotli = ["brotli ; platform_python_implementation == \"CPython\"", "brotlicffi ; platform_python_implementation != \"CPython\""] cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] http2 = ["h2 (>=3,<5)"] socks = ["socksio (==1.*)"] @@ -816,7 +816,7 @@ zipp = ">=0.5" [package.extras] docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] perf = ["ipython"] -testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"] +testing = ["flufl.flake8", "importlib-resources (>=1.3) ; python_version < \"3.9\"", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7) ; platform_python_implementation != \"PyPy\"", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1) ; platform_python_implementation != \"PyPy\"", "pytest-perf (>=0.9.2)", "pytest-ruff"] [[package]] name = "iniconfig" @@ -875,7 +875,7 @@ typing_extensions = {version = ">=4.6", markers = "python_version < \"3.12\""} [package.extras] all = ["ipython[black,doc,kernel,matplotlib,nbconvert,nbformat,notebook,parallel,qtconsole]", "ipython[test,test-extra]"] black = ["black"] -doc = ["docrepr", "exceptiongroup", "intersphinx_registry", "ipykernel", "ipython[test]", "matplotlib", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "sphinxcontrib-jquery", "tomli", "typing_extensions"] +doc = ["docrepr", "exceptiongroup", "intersphinx_registry", "ipykernel", "ipython[test]", "matplotlib", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "sphinxcontrib-jquery", "tomli ; python_version < \"3.11\"", "typing_extensions"] kernel = ["ipykernel"] matplotlib = ["matplotlib"] nbconvert = ["nbconvert"] @@ -1398,8 +1398,8 @@ cryptography = ">=3.3" pynacl = ">=1.5" [package.extras] -all = ["gssapi (>=1.4.1)", "invoke (>=2.0)", "pyasn1 (>=0.1.7)", "pywin32 (>=2.1.8)"] -gssapi = ["gssapi (>=1.4.1)", "pyasn1 (>=0.1.7)", "pywin32 (>=2.1.8)"] +all = ["gssapi (>=1.4.1) ; platform_system != \"Windows\"", "invoke (>=2.0)", "pyasn1 (>=0.1.7)", "pywin32 (>=2.1.8) ; platform_system == \"Windows\""] +gssapi = ["gssapi (>=1.4.1) ; platform_system != \"Windows\"", "pyasn1 (>=0.1.7)", "pywin32 (>=2.1.8) ; platform_system == \"Windows\""] invoke = ["invoke (>=2.0)"] [[package]] @@ -2219,21 +2219,21 @@ files = [ [[package]] name = "s3transfer" -version = "0.10.4" +version = "0.11.4" description = "An Amazon S3 Transfer Manager" optional = false python-versions = ">=3.8" groups = ["main", "integration"] files = [ - {file = "s3transfer-0.10.4-py3-none-any.whl", hash = "sha256:244a76a24355363a68164241438de1b72f8781664920260c48465896b712a41e"}, - {file = "s3transfer-0.10.4.tar.gz", hash = "sha256:29edc09801743c21eb5ecbc617a152df41d3c287f67b615f73e5f750583666a7"}, + {file = "s3transfer-0.11.4-py3-none-any.whl", hash = "sha256:ac265fa68318763a03bf2dc4f39d5cbd6a9e178d81cc9483ad27da33637e320d"}, + {file = "s3transfer-0.11.4.tar.gz", hash = "sha256:559f161658e1cf0a911f45940552c696735f5c74e64362e515f333ebed87d679"}, ] [package.dependencies] -botocore = ">=1.33.2,<2.0a.0" +botocore = ">=1.37.4,<2.0a.0" [package.extras] -crt = ["botocore[crt] (>=1.33.2,<2.0a.0)"] +crt = ["botocore[crt] (>=1.37.4,<2.0a.0)"] [[package]] name = "six" @@ -2408,7 +2408,7 @@ files = [ ] [package.extras] -brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +brotli = ["brotli (>=1.0.9) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\""] h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] @@ -2623,14 +2623,14 @@ files = [ ] [package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] enabler = ["pytest-enabler (>=2.2)"] -test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"] +test = ["big-O", "importlib-resources ; python_version < \"3.9\"", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"] type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = "^3.10" -content-hash = "32f3b67d60393e53e28f1c3856b0c6f5c32ea538d4ae6cae1847cdd37a001ceb" +content-hash = "d6d1a9eb1d741b25733acdae41d5ad4c8f3a1948bb519a31b676c5f6b1f21550" diff --git a/pyproject.toml b/pyproject.toml index 82e0129586..c044782906 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ requires-poetry = ">=2.0.0" [tool.poetry.dependencies] python = "^3.10" ops = "^2.18.1" -boto3 = "^1.35.99" +boto3 = "^1.37.22" pgconnstr = "^1.0.1" requests = "^2.32.3" tenacity = "^9.0.0" diff --git a/src/backups.py b/src/backups.py index 903ba028f6..4c414d75e8 100644 --- a/src/backups.py +++ b/src/backups.py @@ -100,6 +100,23 @@ def _tls_ca_chain_filename(self) -> str: return f"{self.charm._storage_path}/pgbackrest-tls-ca-chain.crt" return "" + def _get_s3_session_resource(self, s3_parameters: dict): + session = boto3.session.Session( + aws_access_key_id=s3_parameters["access-key"], + aws_secret_access_key=s3_parameters["secret-key"], + region_name=s3_parameters["region"], + ) + return session.resource( + "s3", + endpoint_url=self._construct_endpoint(s3_parameters), + verify=(self._tls_ca_chain_filename or None), + config=botocore.client.Config( + # https://github.com/boto/boto3/issues/4400#issuecomment-2600742103 + request_checksum_calculation="when_required", + response_checksum_validation="when_required", + ), + ) + def _are_backup_settings_ok(self) -> tuple[bool, str | None]: """Validates whether backup settings are OK.""" if self.model.get_relation(self.relation_name) is None: @@ -258,18 +275,9 @@ def _create_bucket_if_not_exists(self) -> None: bucket_name = s3_parameters["bucket"] region = s3_parameters.get("region") - session = boto3.session.Session( - aws_access_key_id=s3_parameters["access-key"], - aws_secret_access_key=s3_parameters["secret-key"], - region_name=s3_parameters["region"], - ) try: - s3 = session.resource( - "s3", - endpoint_url=self._construct_endpoint(s3_parameters), - verify=(self._tls_ca_chain_filename or None), - ) + s3 = self._get_s3_session_resource(s3_parameters) except ValueError as e: logger.exception("Failed to create a session '%s' in region=%s.", bucket_name, region) raise e @@ -1372,17 +1380,7 @@ def _upload_content_to_s3( processed_s3_path = os.path.join(s3_parameters["path"], s3_path).lstrip("/") try: logger.info(f"Uploading content to bucket={bucket_name}, path={processed_s3_path}") - session = boto3.session.Session( - aws_access_key_id=s3_parameters["access-key"], - aws_secret_access_key=s3_parameters["secret-key"], - region_name=s3_parameters["region"], - ) - - s3 = session.resource( - "s3", - endpoint_url=self._construct_endpoint(s3_parameters), - verify=(self._tls_ca_chain_filename or None), - ) + s3 = self._get_s3_session_resource(s3_parameters) bucket = s3.Bucket(bucket_name) with tempfile.NamedTemporaryFile() as temp_file: @@ -1415,16 +1413,7 @@ def _read_content_from_s3(self, s3_path: str, s3_parameters: dict) -> str | None processed_s3_path = os.path.join(s3_parameters["path"], s3_path).lstrip("/") try: logger.info(f"Reading content from bucket={bucket_name}, path={processed_s3_path}") - session = boto3.session.Session( - aws_access_key_id=s3_parameters["access-key"], - aws_secret_access_key=s3_parameters["secret-key"], - region_name=s3_parameters["region"], - ) - s3 = session.resource( - "s3", - endpoint_url=self._construct_endpoint(s3_parameters), - verify=(self._tls_ca_chain_filename or None), - ) + s3 = self._get_s3_session_resource(s3_parameters) bucket = s3.Bucket(bucket_name) with BytesIO() as buf: bucket.download_fileobj(processed_s3_path, buf) diff --git a/tests/unit/test_backups.py b/tests/unit/test_backups.py index 3df0653190..1ca2d3a469 100644 --- a/tests/unit/test_backups.py +++ b/tests/unit/test_backups.py @@ -342,6 +342,7 @@ def test_create_bucket_if_not_exists(harness, tls_ca_chain_filename): new_callable=PropertyMock(return_value=tls_ca_chain_filename), ) as _tls_ca_chain_filename, patch("charm.PostgreSQLBackups._retrieve_s3_parameters") as _retrieve_s3_parameters, + patch("backups.botocore.client.Config") as _config, ): # Test when there are missing S3 parameters. _retrieve_s3_parameters.return_value = ([], ["bucket", "access-key", "secret-key"]) @@ -366,13 +367,22 @@ def test_create_bucket_if_not_exists(harness, tls_ca_chain_filename): # Test when the bucket already exists. _resource.reset_mock() + _config.reset_mock() _resource.side_effect = None head_bucket = _resource.return_value.Bucket.return_value.meta.client.head_bucket create = _resource.return_value.Bucket.return_value.create wait_until_exists = _resource.return_value.Bucket.return_value.wait_until_exists harness.charm.backup._create_bucket_if_not_exists() _resource.assert_called_once_with( - "s3", endpoint_url="test-endpoint", verify=(tls_ca_chain_filename or None) + "s3", + endpoint_url="test-endpoint", + verify=(tls_ca_chain_filename or None), + config=_config.return_value, + ) + _config.assert_called_once_with( + # https://github.com/boto/boto3/issues/4400#issuecomment-2600742103 + request_checksum_calculation="when_required", + response_checksum_validation="when_required", ) head_bucket.assert_called_once() create.assert_not_called() @@ -1950,6 +1960,7 @@ def test_upload_content_to_s3(harness, tls_ca_chain_filename): patch("tempfile.NamedTemporaryFile") as _named_temporary_file, patch("charm.PostgreSQLBackups._construct_endpoint") as _construct_endpoint, patch("boto3.session.Session.resource") as _resource, + patch("backups.botocore.client.Config") as _config, patch( "charm.PostgreSQLBackups._tls_ca_chain_filename", new_callable=PropertyMock(return_value=tls_ca_chain_filename), @@ -1977,11 +1988,18 @@ def test_upload_content_to_s3(harness, tls_ca_chain_filename): "s3", endpoint_url="https://s3.us-east-1.amazonaws.com", verify=(tls_ca_chain_filename or None), + config=_config.return_value, + ) + _config.assert_called_once_with( + # https://github.com/boto/boto3/issues/4400#issuecomment-2600742103 + request_checksum_calculation="when_required", + response_checksum_validation="when_required", ) _named_temporary_file.assert_not_called() upload_file.assert_not_called() _resource.reset_mock() + _config.reset_mock() _resource.side_effect = None upload_file.side_effect = S3UploadFailedError assert not harness.charm.backup._upload_content_to_s3(content, s3_path, s3_parameters) @@ -1989,12 +2007,19 @@ def test_upload_content_to_s3(harness, tls_ca_chain_filename): "s3", endpoint_url="https://s3.us-east-1.amazonaws.com", verify=(tls_ca_chain_filename or None), + config=_config.return_value, + ) + _config.assert_called_once_with( + # https://github.com/boto/boto3/issues/4400#issuecomment-2600742103 + request_checksum_calculation="when_required", + response_checksum_validation="when_required", ) _named_temporary_file.assert_called_once() upload_file.assert_called_once_with("/tmp/test-file", "test-path/test-file.") # Test when the upload succeeds _resource.reset_mock() + _config.reset_mock() _named_temporary_file.reset_mock() upload_file.reset_mock() upload_file.side_effect = None @@ -2003,6 +2028,12 @@ def test_upload_content_to_s3(harness, tls_ca_chain_filename): "s3", endpoint_url="https://s3.us-east-1.amazonaws.com", verify=(tls_ca_chain_filename or None), + config=_config.return_value, + ) + _config.assert_called_once_with( + # https://github.com/boto/boto3/issues/4400#issuecomment-2600742103 + request_checksum_calculation="when_required", + response_checksum_validation="when_required", ) _named_temporary_file.assert_called_once() upload_file.assert_called_once_with("/tmp/test-file", "test-path/test-file.") From 03598a48e221bc3719563912584e0812124d4c4e Mon Sep 17 00:00:00 2001 From: Marcelo Henrique Neppel Date: Tue, 15 Apr 2025 08:32:29 -0300 Subject: [PATCH 010/112] [DPE-6218] Static code analysis (#828) * Create tiobe_scan.yaml * Remove push trigger --- .github/workflows/tiobe_scan.yaml | 44 +++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 .github/workflows/tiobe_scan.yaml diff --git a/.github/workflows/tiobe_scan.yaml b/.github/workflows/tiobe_scan.yaml new file mode 100644 index 0000000000..b81b022ef0 --- /dev/null +++ b/.github/workflows/tiobe_scan.yaml @@ -0,0 +1,44 @@ +# Copyright 2025 Canonical Ltd. +# See LICENSE file for licensing details. + +name: Weekly TICS scan + +on: + schedule: + - cron: "0 2 * * 6" # Every Saturday 2:00 AM UTC + workflow_dispatch: + +jobs: + TICS: + runs-on: ubuntu-24.04 + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Create and activate virtual environment + run: | + python3 -m venv .venv + . .venv/bin/activate + pip install flake8 poetry pylint pytest tox + poetry install --all-groups + echo PATH="$PATH" >> "$GITHUB_ENV" + + - name: Run coverage tests + run: | + tox -e unit + + - name: Move results to the necessary folder for TICS + run: | + mkdir -p .cover + mv coverage.xml .cover/cobertura.xml + + - name: TICS GitHub Action + uses: tiobe/tics-github-action@v3 + with: + mode: qserver + project: postgresql-operator + viewerUrl: https://canonical.tiobe.com/tiobeweb/TICS/api/cfg?name=default + branchdir: ${{ env.GITHUB_WORKSPACE }} + ticsAuthToken: ${{ secrets.TICSAUTHTOKEN }} + installTics: true + calc: ALL From 0f9ab15f9cf700b4a164dd69672235d16f4077a3 Mon Sep 17 00:00:00 2001 From: Dragomir Penev <6687393+dragomirp@users.noreply.github.com> Date: Tue, 15 Apr 2025 16:39:29 +0300 Subject: [PATCH 011/112] [MISC] Disable landscape subordinate test lxd (#831) * Set series for ubuntu-advantage test and disable the landscape test * Revert to LTS LXD --- concierge.yaml | 1 - tests/integration/test_subordinates.py | 10 ++++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/concierge.yaml b/concierge.yaml index 29d78b95b5..15a78cc947 100644 --- a/concierge.yaml +++ b/concierge.yaml @@ -5,7 +5,6 @@ providers: lxd: enable: true bootstrap: true - channel: latest/stable host: snaps: jhack: diff --git a/tests/integration/test_subordinates.py b/tests/integration/test_subordinates.py index 585bd765db..e41cd96219 100644 --- a/tests/integration/test_subordinates.py +++ b/tests/integration/test_subordinates.py @@ -46,6 +46,9 @@ async def test_deploy(ops_test: OpsTest, charm: str, check_subordinate_env_vars) channel="latest/edge", num_units=0, base=CHARM_BASE, + # TODO switch back to series when pylib juju can figure out the base: + # https://github.com/juju/python-libjuju/issues/1240 + series="jammy", ), ops_test.model.deploy( LS_CLIENT, @@ -61,12 +64,11 @@ async def test_deploy(ops_test: OpsTest, charm: str, check_subordinate_env_vars) ) await ops_test.model.wait_for_idle(apps=[DATABASE_APP_NAME], status="active", timeout=2000) - await ops_test.model.relate(f"{DATABASE_APP_NAME}:juju-info", f"{LS_CLIENT}:container") await ops_test.model.relate( f"{DATABASE_APP_NAME}:juju-info", f"{UBUNTU_PRO_APP_NAME}:juju-info" ) await ops_test.model.wait_for_idle( - apps=[LS_CLIENT, UBUNTU_PRO_APP_NAME, DATABASE_APP_NAME], status="active" + apps=[UBUNTU_PRO_APP_NAME, DATABASE_APP_NAME], status="active" ) @@ -74,7 +76,7 @@ async def test_scale_up(ops_test: OpsTest, check_subordinate_env_vars): await scale_application(ops_test, DATABASE_APP_NAME, 4) await ops_test.model.wait_for_idle( - apps=[LS_CLIENT, UBUNTU_PRO_APP_NAME, DATABASE_APP_NAME], status="active", timeout=1500 + apps=[UBUNTU_PRO_APP_NAME, DATABASE_APP_NAME], status="active", timeout=1500 ) @@ -82,5 +84,5 @@ async def test_scale_down(ops_test: OpsTest, check_subordinate_env_vars): await scale_application(ops_test, DATABASE_APP_NAME, 3) await ops_test.model.wait_for_idle( - apps=[LS_CLIENT, UBUNTU_PRO_APP_NAME, DATABASE_APP_NAME], status="active", timeout=1500 + apps=[UBUNTU_PRO_APP_NAME, DATABASE_APP_NAME], status="active", timeout=1500 ) From a014fd4f0454a903e1f69ae85e94622d388f9613 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 16 Apr 2025 03:20:37 +0300 Subject: [PATCH 012/112] Update charmcraft.yaml build tools (#815) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- charmcraft.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/charmcraft.yaml b/charmcraft.yaml index 93a258dad9..cd332e9ed5 100644 --- a/charmcraft.yaml +++ b/charmcraft.yaml @@ -27,7 +27,7 @@ parts: PIP_BREAK_SYSTEM_PACKAGES=true python3 -m pip install --user --upgrade pip==25.0.1 # renovate: charmcraft-pip-latest # Use uv to install poetry so that a newer version of Python can be installed if needed by poetry - curl --proto '=https' --tlsv1.2 -LsSf https://github.com/astral-sh/uv/releases/download/0.6.7/uv-installer.sh | sh # renovate: charmcraft-uv-latest + curl --proto '=https' --tlsv1.2 -LsSf https://github.com/astral-sh/uv/releases/download/0.6.14/uv-installer.sh | sh # renovate: charmcraft-uv-latest # poetry 2.0.0 requires Python >=3.9 if ! "$HOME/.local/bin/uv" python find '>=3.9' then @@ -35,7 +35,7 @@ parts: # (to reduce the number of Python versions we use) "$HOME/.local/bin/uv" python install 3.10.12 # renovate: charmcraft-python-ubuntu-22.04 fi - "$HOME/.local/bin/uv" tool install --no-python-downloads --python '>=3.9' poetry==2.1.1 --with poetry-plugin-export==1.9.0 # renovate: charmcraft-poetry-latest + "$HOME/.local/bin/uv" tool install --no-python-downloads --python '>=3.9' poetry==2.1.2 --with poetry-plugin-export==1.9.0 # renovate: charmcraft-poetry-latest ln -sf "$HOME/.local/bin/poetry" /usr/local/bin/poetry # "charm-poetry" part name is arbitrary; use for consistency @@ -75,7 +75,7 @@ parts: # rpds-py (Python package) >=0.19.0 requires rustc >=1.76, which is not available in the # Ubuntu 22.04 archive. Install rustc and cargo using rustup instead of the Ubuntu archive rustup set profile minimal - rustup default 1.85.0 # renovate: charmcraft-rust-latest + rustup default 1.86.0 # renovate: charmcraft-rust-latest craftctl default # Include requirements.txt in *.charm artifact for easier debugging From a11291793901833d1925ee0ed892d88a1fd71c20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sinclert=20P=C3=A9rez?= Date: Wed, 16 Apr 2025 09:03:47 +0200 Subject: [PATCH 013/112] [MISC] Update snapped PostgreSQL (#832) --- src/constants.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/constants.py b/src/constants.py index 0fa63efd04..4dd91be625 100644 --- a/src/constants.py +++ b/src/constants.py @@ -35,7 +35,7 @@ SNAP_PACKAGES = [ ( POSTGRESQL_SNAP_NAME, - {"revision": {"aarch64": "156", "x86_64": "155"}}, + {"revision": {"aarch64": "168", "x86_64": "167"}}, ) ] From 0ebf12d6da02fae267d7748c2510401c354e1a63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sinclert=20P=C3=A9rez?= Date: Wed, 16 Apr 2025 09:03:55 +0200 Subject: [PATCH 014/112] [DPE-6345] LDAP I: Create access groups (#823) --- lib/charms/postgresql_k8s/v0/postgresql.py | 134 ++++++++++++++++++++- src/charm.py | 6 + src/relations/db.py | 6 +- src/relations/postgresql_provider.py | 10 +- src/upgrade.py | 12 ++ tests/unit/test_db.py | 13 +- tests/unit/test_postgresql_provider.py | 5 +- 7 files changed, 177 insertions(+), 9 deletions(-) diff --git a/lib/charms/postgresql_k8s/v0/postgresql.py b/lib/charms/postgresql_k8s/v0/postgresql.py index 9fe1957e4f..f5c4d0e02b 100644 --- a/lib/charms/postgresql_k8s/v0/postgresql.py +++ b/lib/charms/postgresql_k8s/v0/postgresql.py @@ -35,7 +35,19 @@ # Increment this PATCH version before using `charmcraft publish-lib` or reset # to 0 if you are raising the major API version -LIBPATCH = 46 +LIBPATCH = 47 + +# Groups to distinguish HBA access +ACCESS_GROUP_IDENTITY = "identity_access" +ACCESS_GROUP_INTERNAL = "internal_access" +ACCESS_GROUP_RELATION = "relation_access" + +# List of access groups to filter role assignments by +ACCESS_GROUPS = [ + ACCESS_GROUP_IDENTITY, + ACCESS_GROUP_INTERNAL, + ACCESS_GROUP_RELATION, +] # Groups to distinguish database permissions PERMISSIONS_GROUP_ADMIN = "admin" @@ -57,10 +69,18 @@ logger = logging.getLogger(__name__) +class PostgreSQLAssignGroupError(Exception): + """Exception raised when assigning to a group fails.""" + + class PostgreSQLCreateDatabaseError(Exception): """Exception raised when creating a database fails.""" +class PostgreSQLCreateGroupError(Exception): + """Exception raised when creating a group fails.""" + + class PostgreSQLCreateUserError(Exception): """Exception raised when creating a user fails.""" @@ -93,6 +113,10 @@ class PostgreSQLGetPostgreSQLVersionError(Exception): """Exception raised when retrieving PostgreSQL version fails.""" +class PostgreSQLListGroupsError(Exception): + """Exception raised when retrieving PostgreSQL groups list fails.""" + + class PostgreSQLListUsersError(Exception): """Exception raised when retrieving PostgreSQL users list fails.""" @@ -160,6 +184,24 @@ def _connect_to_database( connection.autocommit = True return connection + def create_access_groups(self) -> None: + """Create access groups to distinguish HBA authentication methods.""" + connection = None + try: + with self._connect_to_database() as connection, connection.cursor() as cursor: + for group in ACCESS_GROUPS: + cursor.execute( + SQL("CREATE ROLE {} NOLOGIN;").format( + Identifier(group), + ) + ) + except psycopg2.Error as e: + logger.error(f"Failed to create access groups: {e}") + raise PostgreSQLCreateGroupError() from e + finally: + if connection is not None: + connection.close() + def create_database( self, database: str, @@ -321,6 +363,50 @@ def delete_user(self, user: str) -> None: logger.error(f"Failed to delete user: {e}") raise PostgreSQLDeleteUserError() from e + def grant_internal_access_group_memberships(self) -> None: + """Grant membership to the internal access-group to existing internal users.""" + connection = None + try: + with self._connect_to_database() as connection, connection.cursor() as cursor: + for user in self.system_users: + cursor.execute( + SQL("GRANT {} TO {};").format( + Identifier(ACCESS_GROUP_INTERNAL), + Identifier(user), + ) + ) + except psycopg2.Error as e: + logger.error(f"Failed to grant internal access group memberships: {e}") + raise PostgreSQLAssignGroupError() from e + finally: + if connection is not None: + connection.close() + + def grant_relation_access_group_memberships(self) -> None: + """Grant membership to the relation access-group to existing relation users.""" + rel_users = self.list_users_from_relation() + if not rel_users: + return + + connection = None + try: + with self._connect_to_database() as connection, connection.cursor() as cursor: + rel_groups = SQL(",").join(Identifier(group) for group in [ACCESS_GROUP_RELATION]) + rel_users = SQL(",").join(Identifier(user) for user in rel_users) + + cursor.execute( + SQL("GRANT {groups} TO {users};").format( + groups=rel_groups, + users=rel_users, + ) + ) + except psycopg2.Error as e: + logger.error(f"Failed to grant relation access group memberships: {e}") + raise PostgreSQLAssignGroupError() from e + finally: + if connection is not None: + connection.close() + def enable_disable_extensions( self, extensions: Dict[str, bool], database: Optional[str] = None ) -> None: @@ -534,12 +620,34 @@ def is_tls_enabled(self, check_current_host: bool = False) -> bool: # Connection errors happen when PostgreSQL has not started yet. return False + def list_access_groups(self) -> Set[str]: + """Returns the list of PostgreSQL database access groups. + + Returns: + List of PostgreSQL database access groups. + """ + connection = None + try: + with self._connect_to_database() as connection, connection.cursor() as cursor: + cursor.execute( + "SELECT groname FROM pg_catalog.pg_group WHERE groname LIKE '%_access';" + ) + access_groups = cursor.fetchall() + return {group[0] for group in access_groups} + except psycopg2.Error as e: + logger.error(f"Failed to list PostgreSQL database access groups: {e}") + raise PostgreSQLListGroupsError() from e + finally: + if connection is not None: + connection.close() + def list_users(self) -> Set[str]: """Returns the list of PostgreSQL database users. Returns: List of PostgreSQL database users. """ + connection = None try: with self._connect_to_database() as connection, connection.cursor() as cursor: cursor.execute("SELECT usename FROM pg_catalog.pg_user;") @@ -548,6 +656,30 @@ def list_users(self) -> Set[str]: except psycopg2.Error as e: logger.error(f"Failed to list PostgreSQL database users: {e}") raise PostgreSQLListUsersError() from e + finally: + if connection is not None: + connection.close() + + def list_users_from_relation(self) -> Set[str]: + """Returns the list of PostgreSQL database users that were created by a relation. + + Returns: + List of PostgreSQL database users. + """ + connection = None + try: + with self._connect_to_database() as connection, connection.cursor() as cursor: + cursor.execute( + "SELECT usename FROM pg_catalog.pg_user WHERE usename LIKE 'relation_id_%';" + ) + usernames = cursor.fetchall() + return {username[0] for username in usernames} + except psycopg2.Error as e: + logger.error(f"Failed to list PostgreSQL database users: {e}") + raise PostgreSQLListUsersError() from e + finally: + if connection is not None: + connection.close() def list_valid_privileges_and_roles(self) -> Tuple[Set[str], Set[str]]: """Returns two sets with valid privileges and roles. diff --git a/src/charm.py b/src/charm.py index accd6844be..ee1a4c9ceb 100755 --- a/src/charm.py +++ b/src/charm.py @@ -23,6 +23,7 @@ from charms.grafana_agent.v0.cos_agent import COSAgentProvider, charm_tracing_config from charms.operator_libs_linux.v2 import snap from charms.postgresql_k8s.v0.postgresql import ( + ACCESS_GROUPS, REQUIRED_PLUGINS, PostgreSQL, PostgreSQLCreateUserError, @@ -1360,6 +1361,11 @@ def _start_primary(self, event: StartEvent) -> None: self.postgresql.set_up_database() + access_groups = self.postgresql.list_access_groups() + if access_groups != set(ACCESS_GROUPS): + self.postgresql.create_access_groups() + self.postgresql.grant_internal_access_group_memberships() + self.postgresql_client_relation.oversee_users() # Set the flag to enable the replicas to start the Patroni service. diff --git a/src/relations/db.py b/src/relations/db.py index 5f7d8f9ea5..a77070fc3b 100644 --- a/src/relations/db.py +++ b/src/relations/db.py @@ -7,6 +7,7 @@ from collections.abc import Iterable from charms.postgresql_k8s.v0.postgresql import ( + ACCESS_GROUP_RELATION, PostgreSQLCreateDatabaseError, PostgreSQLCreateUserError, PostgreSQLGetPostgreSQLVersionError, @@ -198,10 +199,11 @@ def set_up_relation(self, relation: Relation) -> bool: # non-leader units when the cluster topology changes. self.charm.set_secret(APP_SCOPE, user, password) self.charm.set_secret(APP_SCOPE, f"{user}-database", database) + self.charm.postgresql.create_user( + user, password, self.admin, extra_user_roles=[ACCESS_GROUP_RELATION] + ) - self.charm.postgresql.create_user(user, password, self.admin) plugins = self.charm.get_plugins() - self.charm.postgresql.create_database( database, user, plugins=plugins, client_relations=self.charm.client_relations ) diff --git a/src/relations/postgresql_provider.py b/src/relations/postgresql_provider.py index c2fa16add0..ef0dec90dc 100644 --- a/src/relations/postgresql_provider.py +++ b/src/relations/postgresql_provider.py @@ -10,6 +10,8 @@ DatabaseRequestedEvent, ) from charms.postgresql_k8s.v0.postgresql import ( + ACCESS_GROUP_RELATION, + ACCESS_GROUPS, INVALID_EXTRA_USER_ROLE_BLOCKING_MESSAGE, PostgreSQLCreateDatabaseError, PostgreSQLCreateUserError, @@ -71,7 +73,10 @@ def _sanitize_extra_roles(extra_roles: str | None) -> list[str]: if extra_roles is None: return [] - return [role.lower() for role in extra_roles.split(",")] + # Make sure the access-groups are not in the list + extra_roles_list = [role.lower() for role in extra_roles.split(",")] + extra_roles_list = [role for role in extra_roles_list if role not in ACCESS_GROUPS] + return extra_roles_list def _on_database_requested(self, event: DatabaseRequestedEvent) -> None: """Generate password and handle user and database creation for the related application.""" @@ -93,8 +98,9 @@ def _on_database_requested(self, event: DatabaseRequestedEvent) -> None: # Retrieve the database name and extra user roles using the charm library. database = event.database - # Make sure that certain groups are not in the list + # Make sure the relation access-group is added to the list extra_user_roles = self._sanitize_extra_roles(event.extra_user_roles) + extra_user_roles.append(ACCESS_GROUP_RELATION) try: # Creates the user and the database for this specific relation. diff --git a/src/upgrade.py b/src/upgrade.py index c24d2952af..db4fb5f978 100644 --- a/src/upgrade.py +++ b/src/upgrade.py @@ -12,6 +12,7 @@ DependencyModel, UpgradeGrantedEvent, ) +from charms.postgresql_k8s.v0.postgresql import ACCESS_GROUPS from ops.model import MaintenanceStatus, RelationDataContent, WaitingStatus from pydantic import BaseModel from tenacity import RetryError, Retrying, stop_after_attempt, wait_fixed @@ -247,6 +248,17 @@ def _prepare_upgrade_from_legacy(self) -> None: extra_user_roles="pg_monitor", ) self.charm.postgresql.set_up_database() + self._set_up_new_access_roles_for_legacy() + + def _set_up_new_access_roles_for_legacy(self) -> None: + """Create missing access groups and their memberships.""" + access_groups = self.charm.postgresql.list_access_groups() + if access_groups == set(ACCESS_GROUPS): + return + + self.charm.postgresql.create_access_groups() + self.charm.postgresql.grant_internal_access_group_memberships() + self.charm.postgresql.grant_relation_access_group_memberships() @property def unit_upgrade_data(self) -> RelationDataContent: diff --git a/tests/unit/test_db.py b/tests/unit/test_db.py index d5ebd95e97..a400ef708e 100644 --- a/tests/unit/test_db.py +++ b/tests/unit/test_db.py @@ -5,6 +5,7 @@ import pytest from charms.postgresql_k8s.v0.postgresql import ( + ACCESS_GROUP_RELATION, PostgreSQLCreateDatabaseError, PostgreSQLCreateUserError, PostgreSQLGetPostgreSQLVersionError, @@ -226,7 +227,9 @@ def test_set_up_relation(harness): ) assert harness.charm.legacy_db_relation.set_up_relation(relation) user = f"relation-{rel_id}" - postgresql_mock.create_user.assert_called_once_with(user, "test-password", False) + postgresql_mock.create_user.assert_called_once_with( + user, "test-password", False, extra_user_roles=[ACCESS_GROUP_RELATION] + ) postgresql_mock.create_database.assert_called_once_with( DATABASE, user, plugins=["pgaudit"], client_relations=[relation] ) @@ -253,7 +256,9 @@ def test_set_up_relation(harness): {"database": DATABASE}, ) assert harness.charm.legacy_db_relation.set_up_relation(relation) - postgresql_mock.create_user.assert_called_once_with(user, "test-password", False) + postgresql_mock.create_user.assert_called_once_with( + user, "test-password", False, extra_user_roles=[ACCESS_GROUP_RELATION] + ) postgresql_mock.create_database.assert_called_once_with( DATABASE, user, plugins=["pgaudit"], client_relations=[relation] ) @@ -274,7 +279,9 @@ def test_set_up_relation(harness): {"database": ""}, ) assert harness.charm.legacy_db_relation.set_up_relation(relation) - postgresql_mock.create_user.assert_called_once_with(user, "test-password", False) + postgresql_mock.create_user.assert_called_once_with( + user, "test-password", False, extra_user_roles=[ACCESS_GROUP_RELATION] + ) postgresql_mock.create_database.assert_called_once_with( "test_database", user, plugins=["pgaudit"], client_relations=[relation] ) diff --git a/tests/unit/test_postgresql_provider.py b/tests/unit/test_postgresql_provider.py index 27efac383a..13b065d299 100644 --- a/tests/unit/test_postgresql_provider.py +++ b/tests/unit/test_postgresql_provider.py @@ -5,6 +5,7 @@ import pytest from charms.postgresql_k8s.v0.postgresql import ( + ACCESS_GROUP_RELATION, PostgreSQLCreateDatabaseError, PostgreSQLCreateUserError, PostgreSQLGetPostgreSQLVersionError, @@ -124,10 +125,12 @@ def test_on_database_requested(harness): # Assert that the correct calls were made. user = f"relation-{rel_id}" + expected_user_roles = [role.lower() for role in EXTRA_USER_ROLES.split(",")] + expected_user_roles.append(ACCESS_GROUP_RELATION) postgresql_mock.create_user.assert_called_once_with( user, "test-password", - extra_user_roles=[role.lower() for role in EXTRA_USER_ROLES.split(",")], + extra_user_roles=expected_user_roles, ) database_relation = harness.model.get_relation(RELATION_NAME) client_relations = [database_relation] From 3c2c894f3131465ce8db8f287ad19c4919c2b3da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sinclert=20P=C3=A9rez?= Date: Wed, 16 Apr 2025 09:04:06 +0200 Subject: [PATCH 015/112] [DPE-6345] LDAP II: Include charm libs (#824) --- .../v0/certificate_transfer.py | 432 +++++++++++++ lib/charms/glauth_k8s/v0/ldap.py | 571 ++++++++++++++++++ .../postgresql_k8s/v0/postgresql_tls.py | 87 ++- metadata.yaml | 7 + pyproject.toml | 2 + src/charm.py | 30 + src/constants.py | 2 + tests/integration/helpers.py | 4 +- tests/integration/test_backups_pitr_aws.py | 4 +- tests/integration/test_backups_pitr_gcp.py | 4 +- tests/integration/test_tls.py | 4 +- tests/unit/test_charm.py | 44 +- 12 files changed, 1174 insertions(+), 17 deletions(-) create mode 100644 lib/charms/certificate_transfer_interface/v0/certificate_transfer.py create mode 100644 lib/charms/glauth_k8s/v0/ldap.py diff --git a/lib/charms/certificate_transfer_interface/v0/certificate_transfer.py b/lib/charms/certificate_transfer_interface/v0/certificate_transfer.py new file mode 100644 index 0000000000..d5c2aa1692 --- /dev/null +++ b/lib/charms/certificate_transfer_interface/v0/certificate_transfer.py @@ -0,0 +1,432 @@ +# Copyright 2023 Canonical Ltd. +# See LICENSE file for licensing details. + +"""Library for the certificate_transfer relation. + +This library contains the Requires and Provides classes for handling the +ertificate-transfer interface. + +## Getting Started +From a charm directory, fetch the library using `charmcraft`: + +```shell +charmcraft fetch-lib charms.certificate_transfer_interface.v0.certificate_transfer +``` + +### Provider charm +The provider charm is the charm providing public certificates to another charm that requires them. + +Example: +```python +from ops.charm import CharmBase, RelationJoinedEvent +from ops.main import main + +from lib.charms.certificate_transfer_interface.v0.certificate_transfer import( + CertificateTransferProvides, +) + + +class DummyCertificateTransferProviderCharm(CharmBase): + def __init__(self, *args): + super().__init__(*args) + self.certificate_transfer = CertificateTransferProvides(self, "certificates") + self.framework.observe( + self.on.certificates_relation_joined, self._on_certificates_relation_joined + ) + + def _on_certificates_relation_joined(self, event: RelationJoinedEvent): + certificate = "my certificate" + ca = "my CA certificate" + chain = ["certificate 1", "certificate 2"] + self.certificate_transfer.set_certificate( + certificate=certificate, ca=ca, chain=chain, relation_id=event.relation.id + ) + + +if __name__ == "__main__": + main(DummyCertificateTransferProviderCharm) +``` + +### Requirer charm +The requirer charm is the charm requiring certificates from another charm that provides them. + +Example: +```python + +from ops.charm import CharmBase +from ops.main import main + +from lib.charms.certificate_transfer_interface.v0.certificate_transfer import ( + CertificateAvailableEvent, + CertificateRemovedEvent, + CertificateTransferRequires, +) + + +class DummyCertificateTransferRequirerCharm(CharmBase): + def __init__(self, *args): + super().__init__(*args) + self.certificate_transfer = CertificateTransferRequires(self, "certificates") + self.framework.observe( + self.certificate_transfer.on.certificate_available, self._on_certificate_available + ) + self.framework.observe( + self.certificate_transfer.on.certificate_removed, self._on_certificate_removed + ) + + def _on_certificate_available(self, event: CertificateAvailableEvent): + print(event.certificate) + print(event.ca) + print(event.chain) + print(event.relation_id) + + def _on_certificate_removed(self, event: CertificateRemovedEvent): + print(event.relation_id) + + +if __name__ == "__main__": + main(DummyCertificateTransferRequirerCharm) +``` + +You can relate both charms by running: + +```bash +juju relate +``` + +""" + +import json +import logging +from typing import List, Mapping + +from jsonschema import exceptions, validate # type: ignore[import-untyped] +from ops import Relation +from ops.charm import ( + CharmBase, + CharmEvents, + RelationBrokenEvent, + RelationChangedEvent, + RelationCreatedEvent, +) +from ops.framework import EventBase, EventSource, Handle, Object + +# The unique Charmhub library identifier, never change it +LIBID = "3785165b24a743f2b0c60de52db25c8b" + +# Increment this major API version when introducing breaking changes +LIBAPI = 0 + +# Increment this PATCH version before using `charmcraft publish-lib` or reset +# to 0 if you are raising the major API version +LIBPATCH = 11 + +PYDEPS = ["jsonschema"] + + +logger = logging.getLogger(__name__) + + +PROVIDER_JSON_SCHEMA = { + "$schema": "http://json-schema.org/draft-07/schema", + "$id": "https://canonical.github.io/charm-relation-interfaces/interfaces/certificate_transfer/schemas/provider.json", + "type": "object", + "title": "`certificate_transfer` provider schema", + "description": "The `certificate_transfer` root schema comprises the entire provider application databag for this interface.", + "default": {}, + "examples": [ + { + "certificate": "-----BEGIN CERTIFICATE-----\nMIIC6DCCAdCgAwIBAgIUW42TU9LSjEZLMCclWrvSwAsgRtcwDQYJKoZIhvcNAQEL\nBQAwIDELMAkGA1UEBhMCVVMxETAPBgNVBAMMCHdoYXRldmVyMB4XDTIzMDMyNDE4\nNDMxOVoXDTI0MDMyMzE4NDMxOVowPDELMAkGA1UEAwwCb2sxLTArBgNVBC0MJGUw\nNjVmMWI3LTE2OWEtNDE5YS1iNmQyLTc3OWJkOGM4NzIwNjCCASIwDQYJKoZIhvcN\nAQEBBQADggEPADCCAQoCggEBAK42ixoklDH5K5i1NxXo/AFACDa956pE5RA57wlC\nBfgUYaIDRmv7TUVJh6zoMZSD6wjSZl3QgP7UTTZeHbvs3QE9HUwEkH1Lo3a8vD3z\neqsE2vSnOkpWWnPbfxiQyrTm77/LAWBt7lRLRLdfL6WcucD3wsGqm58sWXM3HG0f\nSN7PHCZUFqU6MpkHw8DiKmht5hBgWG+Vq3Zw8MNaqpwb/NgST3yYdcZwb58G2FTS\nZvDSdUfRmD/mY7TpciYV8EFylXNNFkth8oGNLunR9adgZ+9IunfRKj1a7S5GSwXU\nAZDaojw+8k5i3ikztsWH11wAVCiLj/3euIqq95z8xGycnKcCAwEAATANBgkqhkiG\n9w0BAQsFAAOCAQEAWMvcaozgBrZ/MAxzTJmp5gZyLxmMNV6iT9dcqbwzDtDtBvA/\n46ux6ytAQ+A7Bd3AubvozwCr1Id6g66ae0blWYRRZmF8fDdX/SBjIUkv7u9A3NVQ\nXN9gsEvK9pdpfN4ZiflfGSLdhM1STHycLmhG6H5s7HklbukMRhQi+ejbSzm/wiw1\nipcxuKhSUIVNkTLusN5b+HE2gwF1fn0K0z5jWABy08huLgbaEKXJEx5/FKLZGJga\nfpIzAdf25kMTu3gggseaAmzyX3AtT1i8A8nqYfe8fnnVMkvud89kq5jErv/hlMC9\n49g5yWQR2jilYYM3j9BHDuB+Rs+YS5BCep1JnQ==\n-----END CERTIFICATE-----\n", + "ca": "-----BEGIN CERTIFICATE-----\nMIIC6DCCAdCgAwIBAgIUdiBwE/CtaBXJl3MArjZen6Y8kigwDQYJKoZIhvcNAQEL\nBQAwIDELMAkGA1UEBhMCVVMxETAPBgNVBAMMCHdoYXRldmVyMB4XDTIzMDMyNDE4\nNDg1OVoXDTI0MDMyMzE4NDg1OVowPDELMAkGA1UEAwwCb2sxLTArBgNVBC0MJDEw\nMDdjNDBhLWUwYzMtNDVlOS05YTAxLTVlYjY0NWQ0ZmEyZDCCASIwDQYJKoZIhvcN\nAQEBBQADggEPADCCAQoCggEBANOnUl6JDlXpLMRr/PxgtfE/E5Yk6E/TkPkPL/Kk\ntUGjEi42XZDg9zn3U6cjTDYu+rfKY2jiitfsduW6DQIkEpz3AvbuCMbbgnFpcjsB\nYysLSMTmuz/AVPrfnea/tQTALcONCSy1VhAjGSr81ZRSMB4khl9StSauZrbkpJ1P\nshqkFSUyAi31mKrnXz0Es/v0Yi0FzAlgWrZ4u1Ld+Bo2Xz7oK4mHf7/93Jc+tEaM\nIqG6ocD0q8bjPp0tlSxftVADNUzWlZfM6fue5EXzOsKqyDrxYOSchfU9dNzKsaBX\nkxbHEeSUPJeYYj7aVPEfAs/tlUGsoXQvwWfRie8grp2BoLECAwEAATANBgkqhkiG\n9w0BAQsFAAOCAQEACZARBpHYH6Gr2a1ka0mCWfBmOZqfDVan9rsI5TCThoylmaXW\nquEiZ2LObI+5faPzxSBhr9TjJlQamsd4ywout7pHKN8ZGqrCMRJ1jJbUfobu1n2k\nUOsY4+jzV1IRBXJzj64fLal4QhUNv341lAer6Vz3cAyRk7CK89b/DEY0x+jVpyZT\n1osx9JtsOmkDTgvdStGzq5kPKWOfjwHkmKQaZXliCgqbhzcCERppp1s/sX6K7nIh\n4lWiEmzUSD3Hngk51KGWlpZszO5KQ4cSZ3HUt/prg+tt0ROC3pY61k+m5dDUa9M8\nRtMI6iTjzSj/UV8DiAx0yeM+bKoy4jGeXmaL3g==\n-----END CERTIFICATE-----\n", + "chain": [ + "-----BEGIN CERTIFICATE-----\nMIIC6DCCAdCgAwIBAgIUW42TU9LSjEZLMCclWrvSwAsgRtcwDQYJKoZIhvcNAQEL\nBQAwIDELMAkGA1UEBhMCVVMxETAPBgNVBAMMCHdoYXRldmVyMB4XDTIzMDMyNDE4\nNDMxOVoXDTI0MDMyMzE4NDMxOVowPDELMAkGA1UEAwwCb2sxLTArBgNVBC0MJGUw\nNjVmMWI3LTE2OWEtNDE5YS1iNmQyLTc3OWJkOGM4NzIwNjCCASIwDQYJKoZIhvcN\nAQEBBQADggEPADCCAQoCggEBAK42ixoklDH5K5i1NxXo/AFACDa956pE5RA57wlC\nBfgUYaIDRmv7TUVJh6zoMZSD6wjSZl3QgP7UTTZeHbvs3QE9HUwEkH1Lo3a8vD3z\neqsE2vSnOkpWWnPbfxiQyrTm77/LAWBt7lRLRLdfL6WcucD3wsGqm58sWXM3HG0f\nSN7PHCZUFqU6MpkHw8DiKmht5hBgWG+Vq3Zw8MNaqpwb/NgST3yYdcZwb58G2FTS\nZvDSdUfRmD/mY7TpciYV8EFylXNNFkth8oGNLunR9adgZ+9IunfRKj1a7S5GSwXU\nAZDaojw+8k5i3ikztsWH11wAVCiLj/3euIqq95z8xGycnKcCAwEAATANBgkqhkiG\n9w0BAQsFAAOCAQEAWMvcaozgBrZ/MAxzTJmp5gZyLxmMNV6iT9dcqbwzDtDtBvA/\n46ux6ytAQ+A7Bd3AubvozwCr1Id6g66ae0blWYRRZmF8fDdX/SBjIUkv7u9A3NVQ\nXN9gsEvK9pdpfN4ZiflfGSLdhM1STHycLmhG6H5s7HklbukMRhQi+ejbSzm/wiw1\nipcxuKhSUIVNkTLusN5b+HE2gwF1fn0K0z5jWABy08huLgbaEKXJEx5/FKLZGJga\nfpIzAdf25kMTu3gggseaAmzyX3AtT1i8A8nqYfe8fnnVMkvud89kq5jErv/hlMC9\n49g5yWQR2jilYYM3j9BHDuB+Rs+YS5BCep1JnQ==\n-----END CERTIFICATE-----\n", + "-----BEGIN CERTIFICATE-----\nMIIC6DCCAdCgAwIBAgIUdiBwE/CtaBXJl3MArjZen6Y8kigwDQYJKoZIhvcNAQEL\nBQAwIDELMAkGA1UEBhMCVVMxETAPBgNVBAMMCHdoYXRldmVyMB4XDTIzMDMyNDE4\nNDg1OVoXDTI0MDMyMzE4NDg1OVowPDELMAkGA1UEAwwCb2sxLTArBgNVBC0MJDEw\nMDdjNDBhLWUwYzMtNDVlOS05YTAxLTVlYjY0NWQ0ZmEyZDCCASIwDQYJKoZIhvcN\nAQEBBQADggEPADCCAQoCggEBANOnUl6JDlXpLMRr/PxgtfE/E5Yk6E/TkPkPL/Kk\ntUGjEi42XZDg9zn3U6cjTDYu+rfKY2jiitfsduW6DQIkEpz3AvbuCMbbgnFpcjsB\nYysLSMTmuz/AVPrfnea/tQTALcONCSy1VhAjGSr81ZRSMB4khl9StSauZrbkpJ1P\nshqkFSUyAi31mKrnXz0Es/v0Yi0FzAlgWrZ4u1Ld+Bo2Xz7oK4mHf7/93Jc+tEaM\nIqG6ocD0q8bjPp0tlSxftVADNUzWlZfM6fue5EXzOsKqyDrxYOSchfU9dNzKsaBX\nkxbHEeSUPJeYYj7aVPEfAs/tlUGsoXQvwWfRie8grp2BoLECAwEAATANBgkqhkiG\n9w0BAQsFAAOCAQEACZARBpHYH6Gr2a1ka0mCWfBmOZqfDVan9rsI5TCThoylmaXW\nquEiZ2LObI+5faPzxSBhr9TjJlQamsd4ywout7pHKN8ZGqrCMRJ1jJbUfobu1n2k\nUOsY4+jzV1IRBXJzj64fLal4QhUNv341lAer6Vz3cAyRk7CK89b/DEY0x+jVpyZT\n1osx9JtsOmkDTgvdStGzq5kPKWOfjwHkmKQaZXliCgqbhzcCERppp1s/sX6K7nIh\n4lWiEmzUSD3Hngk51KGWlpZszO5KQ4cSZ3HUt/prg+tt0ROC3pY61k+m5dDUa9M8\nRtMI6iTjzSj/UV8DiAx0yeM+bKoy4jGeXmaL3g==\n-----END CERTIFICATE-----\n", + ], + "version": 0, + } + ], + "properties": { + "certificate": { + "$id": "#/properties/certificate", + "type": "string", + "title": "Public TLS certificate", + "description": "Public TLS certificate", + }, + "ca": { + "$id": "#/properties/ca", + "type": "string", + "title": "CA public TLS certificate", + "description": "CA Public TLS certificate", + }, + "chain": { + "$id": "#/properties/chain", + "type": "array", + "items": {"type": "string", "$id": "#/properties/chain/items"}, + "title": "CA public TLS certificate chain", + "description": "CA public TLS certificate chain", + }, + "version": { + "$id": "#/properties/version", + "type": "integer", + "title": "Interface version", + "minimum": 0, + "description": "Highest supported version of this interface", + }, + }, + "anyOf": [{"required": ["certificate"]}, {"required": ["ca"]}, {"required": ["chain"]}], + "additionalProperties": True, +} + + +class CertificateAvailableEvent(EventBase): + """Charm Event triggered when a TLS certificate is available.""" + + def __init__( + self, + handle: Handle, + certificate: str, + ca: str, + chain: List[str], + relation_id: int, + ): + super().__init__(handle) + self.certificate = certificate + self.ca = ca + self.chain = chain + self.relation_id = relation_id + + def snapshot(self) -> dict: + """Return snapshot.""" + return { + "certificate": self.certificate, + "ca": self.ca, + "chain": self.chain, + "relation_id": self.relation_id, + } + + def restore(self, snapshot: dict): + """Restores snapshot.""" + self.certificate = snapshot["certificate"] + self.ca = snapshot["ca"] + self.chain = snapshot["chain"] + self.relation_id = snapshot["relation_id"] + + +class CertificateRemovedEvent(EventBase): + """Charm Event triggered when a TLS certificate is removed.""" + + def __init__(self, handle: Handle, relation_id: int): + super().__init__(handle) + self.relation_id = relation_id + + def snapshot(self) -> dict: + """Return snapshot.""" + return {"relation_id": self.relation_id} + + def restore(self, snapshot: dict): + """Restores snapshot.""" + self.relation_id = snapshot["relation_id"] + + +def _load_relation_data(raw_relation_data: Mapping[str, str]) -> dict: + """Load relation data from the relation data bag. + + Args: + raw_relation_data: Relation data from the databag + + Returns: + dict: Relation data in dict format. + """ + loaded_relation_data = {} + for key in raw_relation_data: + try: + loaded_relation_data[key] = json.loads(raw_relation_data[key]) + except (json.decoder.JSONDecodeError, TypeError): + loaded_relation_data[key] = raw_relation_data[key] + return loaded_relation_data + + +class CertificateTransferRequirerCharmEvents(CharmEvents): + """List of events that the Certificate Transfer requirer charm can leverage.""" + + certificate_available = EventSource(CertificateAvailableEvent) + certificate_removed = EventSource(CertificateRemovedEvent) + + +class CertificateTransferProvides(Object): + """Certificate Transfer provider class.""" + + def __init__(self, charm: CharmBase, relationship_name: str): + super().__init__(charm, relationship_name) + self.charm = charm + self.relationship_name = relationship_name + + def set_certificate( + self, + certificate: str, + ca: str, + chain: List[str], + relation_id: int, + ) -> None: + """Add certificates to relation data. + + Args: + certificate (str): Certificate + ca (str): CA Certificate + chain (list): CA Chain + relation_id (int): Juju relation ID + + Returns: + None + """ + relation = self.model.get_relation( + relation_name=self.relationship_name, + relation_id=relation_id, + ) + if not relation: + raise RuntimeError( + f"No relation found with relation name {self.relationship_name} and " + f"relation ID {relation_id}" + ) + relation.data[self.model.unit]["certificate"] = certificate + relation.data[self.model.unit]["ca"] = ca + relation.data[self.model.unit]["chain"] = json.dumps(chain) + relation.data[self.model.unit]["version"] = str(LIBAPI) + + def remove_certificate(self, relation_id: int) -> None: + """Remove a given certificate from relation data. + + Args: + relation_id (int): Relation ID + + Returns: + None + """ + relation = self.model.get_relation( + relation_name=self.relationship_name, + relation_id=relation_id, + ) + if not relation: + logger.warning( + "Can't remove certificate - Non-existent relation '%s'", self.relationship_name + ) + return + unit_relation_data = relation.data[self.model.unit] + certificate_removed = False + if "certificate" in unit_relation_data: + relation.data[self.model.unit].pop("certificate") + certificate_removed = True + if "ca" in unit_relation_data: + relation.data[self.model.unit].pop("ca") + certificate_removed = True + if "chain" in unit_relation_data: + relation.data[self.model.unit].pop("chain") + certificate_removed = True + + if certificate_removed: + logger.warning("Certificate removed from relation data") + else: + logger.warning("Can't remove certificate - No certificate in relation data") + + +class CertificateTransferRequires(Object): + """TLS certificates requirer class to be instantiated by TLS certificates requirers.""" + + on = CertificateTransferRequirerCharmEvents() # type: ignore + + def __init__( + self, + charm: CharmBase, + relationship_name: str, + ): + """Generates/use private key and observes relation changed event. + + Args: + charm: Charm object + relationship_name: Juju relation name + """ + super().__init__(charm, relationship_name) + self.relationship_name = relationship_name + self.charm = charm + self.framework.observe( + charm.on[relationship_name].relation_changed, self._on_relation_changed + ) + self.framework.observe( + charm.on[relationship_name].relation_broken, self._on_relation_broken + ) + self.framework.observe( + charm.on[relationship_name].relation_created, self._on_relation_created + ) + + @staticmethod + def _relation_data_is_valid(relation_data: dict) -> bool: + """Return whether relation data is valid based on json schema. + + Args: + relation_data: Relation data in dict format. + + Returns: + bool: Whether relation data is valid. + """ + try: + validate(instance=relation_data, schema=PROVIDER_JSON_SCHEMA) + return True + except exceptions.ValidationError: + return False + + def _on_relation_changed(self, event: RelationChangedEvent) -> None: + """Emit certificate available event. + + Args: + event: Juju event + + Returns: + None + """ + if not event.unit: + logger.info("No remote unit in relation: %s", self.relationship_name) + return + remote_unit_relation_data = _load_relation_data(event.relation.data[event.unit]) + if not self._relation_data_is_valid(remote_unit_relation_data): + logger.warning( + "Provider relation data did not pass JSON Schema validation: %s", + event.relation.data[event.unit], + ) + return + self.on.certificate_available.emit( + certificate=remote_unit_relation_data.get("certificate"), + ca=remote_unit_relation_data.get("ca"), + chain=remote_unit_relation_data.get("chain"), + relation_id=event.relation.id, + ) + + def _on_relation_broken(self, event: RelationBrokenEvent) -> None: + """Handle relation broken event. + + Args: + event: Juju event + + Returns: + None + """ + self.on.certificate_removed.emit(relation_id=event.relation.id) + + def _on_relation_created(self, event: RelationCreatedEvent) -> None: + """Handle relation created event. + + Args: + event: Juju event + + Returns: + None + """ + if self.model.unit.is_leader(): + event.relation.data[self.model.app]["version"] = str(LIBAPI) + + def is_ready(self, relation: Relation) -> bool: + """Check if the relation is ready by checking that it has valid relation data.""" + relation_data = _load_relation_data(relation.data[relation.units.pop()]) + if not self._relation_data_is_valid(relation_data): + logger.warning("Provider relation data did not pass JSON Schema validation: ") + return False + return True diff --git a/lib/charms/glauth_k8s/v0/ldap.py b/lib/charms/glauth_k8s/v0/ldap.py new file mode 100644 index 0000000000..b68e1d2f30 --- /dev/null +++ b/lib/charms/glauth_k8s/v0/ldap.py @@ -0,0 +1,571 @@ +# Copyright 2023 Canonical Ltd. +# See LICENSE file for licensing details. + +"""# Juju Charm Library for the `ldap` Juju Interface. + +This juju charm library contains the Provider and Requirer classes for handling +the `ldap` interface. + +## Requirer Charm + +The requirer charm is expected to: + +- Provide information for the provider charm to deliver LDAP related +information in the juju integration, in order to communicate with the LDAP +server and authenticate LDAP operations +- Listen to the custom juju event `LdapReadyEvent` to obtain the LDAP +related information from the integration +- Listen to the custom juju event `LdapUnavailableEvent` to handle the +situation when the LDAP integration is broken + +```python + +from charms.glauth_k8s.v0.ldap import ( + LdapRequirer, + LdapReadyEvent, + LdapUnavailableEvent, +) + +class RequirerCharm(CharmBase): + # LDAP requirer charm that integrates with an LDAP provider charm. + + def __init__(self, *args): + super().__init__(*args) + + self.ldap_requirer = LdapRequirer(self) + self.framework.observe( + self.ldap_requirer.on.ldap_ready, + self._on_ldap_ready, + ) + self.framework.observe( + self.ldap_requirer.on.ldap_unavailable, + self._on_ldap_unavailable, + ) + + def _on_ldap_ready(self, event: LdapReadyEvent) -> None: + # Consume the LDAP related information + ldap_data = self.ldap_requirer.consume_ldap_relation_data( + relation=event.relation, + ) + + # Configure the LDAP requirer charm + ... + + def _on_ldap_unavailable(self, event: LdapUnavailableEvent) -> None: + # Handle the situation where the LDAP integration is broken + ... +``` + +As shown above, the library offers custom juju events to handle specific +situations, which are listed below: + +- ldap_ready: event emitted when the LDAP related information is ready for +requirer charm to use. +- ldap_unavailable: event emitted when the LDAP integration is broken. + +Additionally, the requirer charmed operator needs to declare the `ldap` +interface in the `metadata.yaml`: + +```yaml +requires: + ldap: + interface: ldap +``` + +## Provider Charm + +The provider charm is expected to: + +- Use the information provided by the requirer charm to provide LDAP related +information for the requirer charm to connect and authenticate to the LDAP +server +- Listen to the custom juju event `LdapRequestedEvent` to offer LDAP related +information in the integration + +```python + +from charms.glauth_k8s.v0.ldap import ( + LdapProvider, + LdapRequestedEvent, +) + +class ProviderCharm(CharmBase): + # LDAP provider charm. + + def __init__(self, *args): + super().__init__(*args) + + self.ldap_provider = LdapProvider(self) + self.framework.observe( + self.ldap_provider.on.ldap_requested, + self._on_ldap_requested, + ) + + def _on_ldap_requested(self, event: LdapRequestedEvent) -> None: + # Consume the information provided by the requirer charm + requirer_data = event.data + + # Prepare the LDAP related information using the requirer's data + ldap_data = ... + + # Update the integration data + self.ldap_provider.update_relations_app_data( + relation.id, + ldap_data, + ) +``` + +As shown above, the library offers custom juju events to handle specific +situations, which are listed below: + +- ldap_requested: event emitted when the requirer charm is requesting the +LDAP related information in order to connect and authenticate to the LDAP server +""" + +import json +from functools import wraps +from string import Template +from typing import Any, Callable, Dict, List, Literal, Optional, Tuple, Union + +import ops +from ops.charm import ( + CharmBase, + RelationBrokenEvent, + RelationChangedEvent, + RelationCreatedEvent, + RelationEvent, +) +from ops.framework import EventSource, Handle, Object, ObjectEvents +from ops.model import Relation, SecretNotFoundError +from pydantic import StrictBool, ValidationError, version + +# The unique CharmHub library identifier, never change it +LIBID = "5a535b3c4d0b40da98e29867128e57b9" + +# Increment this major API version when introducing breaking changes +LIBAPI = 0 + +# Increment this PATCH version before using `charmcraft publish-lib` or reset +# to 0 if you are raising the major API version +LIBPATCH = 10 + +PYDEPS = ["pydantic"] + +DEFAULT_RELATION_NAME = "ldap" +BIND_ACCOUNT_SECRET_LABEL_TEMPLATE = Template("relation-$relation_id-bind-account-secret") + +PYDANTIC_IS_V1 = int(version.VERSION.split(".")[0]) < 2 +if PYDANTIC_IS_V1: + # Pydantic v1 backwards compatibility logic, + # see https://docs.pydantic.dev/latest/migration/ for more info. + # This does not offer complete backwards compatibility + + from pydantic import BaseModel as BaseModelV1 + from pydantic import Field as FieldV1 + from pydantic import validator + from pydantic.main import ModelMetaclass + + def Field(*args: Any, **kwargs: Any) -> FieldV1: # noqa N802 + if frozen := kwargs.pop("frozen", None): + kwargs["allow_mutations"] = not frozen + return FieldV1(*args, **kwargs) + + def field_validator(*args: Any, **kwargs: Any) -> Callable: + if kwargs.get("mode") == "before": + kwargs.pop("mode") + kwargs["pre"] = True + return validator(*args, **kwargs) + + encoders_config = {} + + def field_serializer(*fields: str, mode: Optional[str] = None) -> Callable: + def _field_serializer(f: Callable, *args: Any, **kwargs: Any) -> Callable: + @wraps(f) + def wrapper(self: object, *args: Any, **kwargs: Any) -> Any: + return f(self, *args, **kwargs) + + encoders_config[wrapper] = fields + return wrapper + + return _field_serializer + + class ModelCompatibilityMeta(ModelMetaclass): + def __init__(self, name: str, bases: Tuple[object], attrs: Dict) -> None: + if not hasattr(self, "_encoders"): + self._encoders = {} + + self._encoders.update({ + encoder: func + for func in attrs.values() + if callable(func) and func in encoders_config + for encoder in encoders_config[func] + }) + + super().__init__(name, bases, attrs) + + class BaseModel(BaseModelV1, metaclass=ModelCompatibilityMeta): + def model_dump(self, *args: Any, **kwargs: Any) -> Dict: + d = self.dict(*args, **kwargs) + for name, f in self._encoders.items(): + d[name] = f(self, d[name]) + return d + +else: + from pydantic import ( # type: ignore[no-redef] + BaseModel, + Field, + field_serializer, + field_validator, + ) + + +def leader_unit(func: Callable) -> Callable: + @wraps(func) + def wrapper( + obj: Union["LdapProvider", "LdapRequirer"], *args: Any, **kwargs: Any + ) -> Optional[Any]: + if not obj.unit.is_leader(): + return None + + return func(obj, *args, **kwargs) + + return wrapper + + +@leader_unit +def _update_relation_app_databag( + ldap: Union["LdapProvider", "LdapRequirer"], relation: Relation, data: dict +) -> None: + if relation is None: + return + + data = {k: str(v) if v else "" for k, v in data.items()} + relation.data[ldap.app].update(data) + + +class Secret: + def __init__(self, secret: ops.Secret = None) -> None: + self._secret: ops.Secret = secret + + @property + def uri(self) -> str: + return self._secret.id if self._secret else "" + + @classmethod + def load( + cls, + charm: CharmBase, + label: str, + *, + content: Optional[dict[str, str]] = None, + ) -> "Secret": + try: + secret = charm.model.get_secret(label=label) + except SecretNotFoundError: + secret = charm.app.add_secret(label=label, content=content) + + return Secret(secret) + + @classmethod + def create_or_update(cls, charm: CharmBase, label: str, content: dict[str, str]) -> "Secret": + try: + secret = charm.model.get_secret(label=label) + secret.set_content(content=content) + except SecretNotFoundError: + secret = charm.app.add_secret(label=label, content=content) + + return Secret(secret) + + def grant(self, relation: Relation) -> None: + self._secret.grant(relation) + + def remove(self) -> None: + self._secret.remove_all_revisions() + + +class LdapProviderBaseData(BaseModel): + urls: List[str] = Field(frozen=True) + ldaps_urls: List[str] = Field(frozen=True) + base_dn: str = Field(frozen=True) + starttls: StrictBool = Field(frozen=True) + + @field_validator("urls", mode="before") + @classmethod + def validate_ldap_urls(cls, vs: List[str] | str) -> List[str]: + if isinstance(vs, str): + vs = json.loads(vs) + if isinstance(vs, str): + vs = [vs] + + for v in vs: + if not v.startswith("ldap://"): + raise ValidationError.from_exception_data("Invalid LDAP URL scheme.") + + return vs + + @field_validator("ldaps_urls", mode="before") + @classmethod + def validate_ldaps_urls(cls, vs: List[str] | str) -> List[str]: + if isinstance(vs, str): + vs = json.loads(vs) + if isinstance(vs, str): + vs = [vs] + + for v in vs: + if not v.startswith("ldaps://"): + raise ValidationError.from_exception_data("Invalid LDAPS URL scheme.") + + return vs + + @field_serializer("urls", "ldaps_urls") + def serialize_list(self, urls: List[str]) -> str: + return str(json.dumps(urls)) + + @field_validator("starttls", mode="before") + @classmethod + def deserialize_bool(cls, v: str | bool) -> bool: + if isinstance(v, str): + return True if v.casefold() == "true" else False + + return v + + @field_serializer("starttls") + def serialize_bool(self, starttls: bool) -> str: + return str(starttls) + + +class LdapProviderData(LdapProviderBaseData): + bind_dn: str = Field(frozen=True) + bind_password: str = Field(exclude=True) + bind_password_secret: Optional[str] = None + auth_method: Literal["simple"] = Field(frozen=True) + + +class LdapRequirerData(BaseModel): + user: str = Field(frozen=True) + group: str = Field(frozen=True) + + +class LdapRequestedEvent(RelationEvent): + """An event emitted when the LDAP integration is built.""" + + def __init__(self, handle: Handle, relation: Relation) -> None: + super().__init__(handle, relation, relation.app) + + @property + def data(self) -> Optional[LdapRequirerData]: + relation_data = self.relation.data.get(self.relation.app) + return LdapRequirerData(**relation_data) if relation_data else None + + +class LdapProviderEvents(ObjectEvents): + ldap_requested = EventSource(LdapRequestedEvent) + + +class LdapReadyEvent(RelationEvent): + """An event when the LDAP related information is ready.""" + + +class LdapUnavailableEvent(RelationEvent): + """An event when the LDAP integration is unavailable.""" + + +class LdapRequirerEvents(ObjectEvents): + ldap_ready = EventSource(LdapReadyEvent) + ldap_unavailable = EventSource(LdapUnavailableEvent) + + +class LdapProvider(Object): + on = LdapProviderEvents() + + def __init__( + self, + charm: CharmBase, + relation_name: str = DEFAULT_RELATION_NAME, + ) -> None: + super().__init__(charm, relation_name) + + self.charm = charm + self.app = charm.app + self.unit = charm.unit + self._relation_name = relation_name + + self.framework.observe( + self.charm.on[self._relation_name].relation_changed, + self._on_relation_changed, + ) + self.framework.observe( + self.charm.on[self._relation_name].relation_broken, + self._on_relation_broken, + ) + + @leader_unit + def _on_relation_changed(self, event: RelationChangedEvent) -> None: + """Handle the event emitted when the requirer charm provides the necessary data.""" + self.on.ldap_requested.emit(event.relation) + + @leader_unit + def _on_relation_broken(self, event: RelationBrokenEvent) -> None: + """Handle the event emitted when the LDAP integration is broken.""" + secret = Secret.load( + self.charm, + label=BIND_ACCOUNT_SECRET_LABEL_TEMPLATE.substitute(relation_id=event.relation.id), + ) + secret.remove() + + def get_bind_password(self, relation_id: int) -> Optional[str]: + """Retrieve the bind account password for a given integration.""" + try: + secret = self.charm.model.get_secret( + label=BIND_ACCOUNT_SECRET_LABEL_TEMPLATE.substitute(relation_id=relation_id) + ) + except SecretNotFoundError: + return None + return secret.get_content().get("password") + + def update_relations_app_data( + self, + data: Union[LdapProviderBaseData, LdapProviderData], + /, + relation_id: Optional[int] = None, + ) -> None: + """An API for the provider charm to provide the LDAP related information.""" + if not (relations := self.charm.model.relations.get(self._relation_name)): + return + + if relation_id is not None and isinstance(data, LdapProviderData): + relations = [relation for relation in relations if relation.id == relation_id] + secret = Secret.create_or_update( + self.charm, + BIND_ACCOUNT_SECRET_LABEL_TEMPLATE.substitute(relation_id=relation_id), + {"password": data.bind_password}, + ) + secret.grant(relations[0]) + data.bind_password_secret = secret.uri + + for relation in relations: + _update_relation_app_databag(self.charm, relation, data.model_dump()) + + +class LdapRequirer(Object): + """An LDAP requirer to consume data delivered by an LDAP provider charm.""" + + on = LdapRequirerEvents() + + def __init__( + self, + charm: CharmBase, + relation_name: str = DEFAULT_RELATION_NAME, + *, + data: Optional[LdapRequirerData] = None, + ) -> None: + super().__init__(charm, relation_name) + + self.charm = charm + self.app = charm.app + self.unit = charm.unit + self._relation_name = relation_name + self._data = data + + self.framework.observe( + self.charm.on[self._relation_name].relation_created, + self._on_ldap_relation_created, + ) + self.framework.observe( + self.charm.on[self._relation_name].relation_changed, + self._on_ldap_relation_changed, + ) + self.framework.observe( + self.charm.on[self._relation_name].relation_broken, + self._on_ldap_relation_broken, + ) + + def _on_ldap_relation_created(self, event: RelationCreatedEvent) -> None: + """Handle the event emitted when an LDAP integration is created.""" + user = self._data.user if self._data else self.app.name + group = self._data.group if self._data else self.model.name + _update_relation_app_databag(self.charm, event.relation, {"user": user, "group": group}) + + def _on_ldap_relation_changed(self, event: RelationChangedEvent) -> None: + """Handle the event emitted when the LDAP related information is ready.""" + provider_app = event.relation.app + + if not event.relation.data.get(provider_app): + return + + self.on.ldap_ready.emit(event.relation) + + def _on_ldap_relation_broken(self, event: RelationBrokenEvent) -> None: + """Handle the event emitted when the LDAP integration is broken.""" + self.on.ldap_unavailable.emit(event.relation) + + def consume_ldap_relation_data( + self, + /, + relation: Optional[Relation] = None, + relation_id: Optional[int] = None, + ) -> Optional[LdapProviderData]: + """An API for the requirer charm to consume the LDAP related information in the application databag.""" + if not relation: + relation = self.charm.model.get_relation(self._relation_name, relation_id) + + if not relation: + return None + + provider_data = dict(relation.data.get(relation.app)) + if secret_id := provider_data.get("bind_password_secret"): + secret = self.charm.model.get_secret(id=secret_id) + provider_data["bind_password"] = secret.get_content().get("password") + return LdapProviderData(**provider_data) if provider_data else None + + def _is_relation_active(self, relation: Relation) -> bool: + """Whether the relation is active based on contained data.""" + try: + _ = repr(relation.data) + return True + except (RuntimeError, ops.ModelError): + return False + + @property + def relations(self) -> List[Relation]: + """The list of Relation instances associated with this relation_name.""" + return [ + relation + for relation in self.charm.model.relations[self._relation_name] + if self._is_relation_active(relation) + ] + + def _ready_for_relation(self, relation: Relation) -> bool: + if not relation.app: + return False + + return "urls" in relation.data[relation.app] and "bind_dn" in relation.data[relation.app] + + def ready(self, relation_id: Optional[int] = None) -> bool: + """Check if the resource has been created. + + This function can be used to check if the Provider answered with data in the charm code + when outside an event callback. + + Args: + relation_id (int, optional): When provided the check is done only for the relation id + provided, otherwise the check is done for all relations + + Returns: + True or False + + Raises: + IndexError: If relation_id is provided but that relation does not exist + """ + if relation_id is None: + return ( + all(self._ready_for_relation(relation) for relation in self.relations) + if self.relations + else False + ) + + try: + relation = [relation for relation in self.relations if relation.id == relation_id][0] + return self._ready_for_relation(relation) + except IndexError: + raise IndexError(f"relation id {relation_id} cannot be accessed") diff --git a/lib/charms/postgresql_k8s/v0/postgresql_tls.py b/lib/charms/postgresql_k8s/v0/postgresql_tls.py index f55543e0cb..2aeaa52af6 100644 --- a/lib/charms/postgresql_k8s/v0/postgresql_tls.py +++ b/lib/charms/postgresql_k8s/v0/postgresql_tls.py @@ -6,8 +6,9 @@ This class handles certificate request and renewal through the interaction with the TLS Certificates Operator. -This library needs that https://charmhub.io/tls-certificates-interface/libraries/tls_certificates -library is imported to work. +This library needs that the following libraries are imported to work: +- https://charmhub.io/certificate-transfer-interface/libraries/certificate_transfer +- https://charmhub.io/tls-certificates-interface/libraries/tls_certificates It also needs the following methods in the charm class: — get_hostname_by_unit: to retrieve the DNS hostname of the unit. @@ -24,6 +25,15 @@ import socket from typing import List, Optional +from charms.certificate_transfer_interface.v0.certificate_transfer import ( + CertificateAvailableEvent as CertificateAddedEvent, +) +from charms.certificate_transfer_interface.v0.certificate_transfer import ( + CertificateRemovedEvent as CertificateRemovedEvent, +) +from charms.certificate_transfer_interface.v0.certificate_transfer import ( + CertificateTransferRequires, +) from charms.tls_certificates_interface.v2.tls_certificates import ( CertificateAvailableEvent, CertificateExpiringEvent, @@ -45,11 +55,12 @@ # Increment this PATCH version before using `charmcraft publish-lib` or reset # to 0 if you are raising the major API version. -LIBPATCH = 13 +LIBPATCH = 14 logger = logging.getLogger(__name__) SCOPE = "unit" -TLS_RELATION = "certificates" +TLS_CREATION_RELATION = "certificates" +TLS_TRANSFER_RELATION = "receive-ca-cert" class PostgreSQLTLS(Object): @@ -63,18 +74,29 @@ def __init__( self.charm = charm self.peer_relation = peer_relation self.additional_dns_names = additional_dns_names or [] - self.certs = TLSCertificatesRequiresV2(self.charm, TLS_RELATION) + self.certs_creation = TLSCertificatesRequiresV2(self.charm, TLS_CREATION_RELATION) + self.certs_transfer = CertificateTransferRequires(self.charm, TLS_TRANSFER_RELATION) self.framework.observe( self.charm.on.set_tls_private_key_action, self._on_set_tls_private_key ) self.framework.observe( - self.charm.on[TLS_RELATION].relation_joined, self._on_tls_relation_joined + self.charm.on[TLS_CREATION_RELATION].relation_joined, self._on_tls_relation_joined + ) + self.framework.observe( + self.charm.on[TLS_CREATION_RELATION].relation_broken, self._on_tls_relation_broken + ) + self.framework.observe( + self.certs_creation.on.certificate_available, self._on_certificate_available + ) + self.framework.observe( + self.certs_creation.on.certificate_expiring, self._on_certificate_expiring ) self.framework.observe( - self.charm.on[TLS_RELATION].relation_broken, self._on_tls_relation_broken + self.certs_transfer.on.certificate_available, self._on_certificate_added + ) + self.framework.observe( + self.certs_transfer.on.certificate_removed, self._on_certificate_removed ) - self.framework.observe(self.certs.on.certificate_available, self._on_certificate_available) - self.framework.observe(self.certs.on.certificate_expiring, self._on_certificate_expiring) def _on_set_tls_private_key(self, event: ActionEvent) -> None: """Set the TLS private key, which will be used for requesting the certificate.""" @@ -93,8 +115,8 @@ def _request_certificate(self, param: Optional[str]): self.charm.set_secret(SCOPE, "key", key.decode("utf-8")) self.charm.set_secret(SCOPE, "csr", csr.decode("utf-8")) - if self.charm.model.get_relation(TLS_RELATION): - self.certs.request_certificate_creation(certificate_signing_request=csr) + if self.charm.model.get_relation(TLS_CREATION_RELATION): + self.certs_creation.request_certificate_creation(certificate_signing_request=csr) @staticmethod def _parse_tls_file(raw_content: str) -> bytes: @@ -117,6 +139,7 @@ def _on_tls_relation_broken(self, event: RelationBrokenEvent) -> None: self.charm.set_secret(SCOPE, "ca", None) self.charm.set_secret(SCOPE, "cert", None) self.charm.set_secret(SCOPE, "chain", None) + if not self.charm.update_config(): logger.debug("Cannot update config at this moment") event.defer() @@ -163,12 +186,52 @@ def _on_certificate_expiring(self, event: CertificateExpiringEvent) -> None: subject=self.charm.get_hostname_by_unit(self.charm.unit.name), **self._get_sans(), ) - self.certs.request_certificate_renewal( + self.certs_creation.request_certificate_renewal( old_certificate_signing_request=old_csr, new_certificate_signing_request=new_csr, ) self.charm.set_secret(SCOPE, "csr", new_csr.decode("utf-8")) + def _on_certificate_added(self, event: CertificateAddedEvent) -> None: + """Enable TLS when TLS certificate is added.""" + relation = self.charm.model.get_relation(TLS_TRANSFER_RELATION, event.relation_id) + if relation is None: + logger.error("Relationship not established anymore.") + return + + secret_name = f"ca-{relation.app.name}" + self.charm.set_secret(SCOPE, secret_name, event.ca) + + try: + if not self.charm.push_ca_file_into_workload(secret_name): + logger.debug("Cannot push TLS certificates at this moment") + event.defer() + return + except (PebbleConnectionError, PathError, ProtocolError, RetryError) as e: + logger.error("Cannot push TLS certificates: %r", e) + event.defer() + return + + def _on_certificate_removed(self, event: CertificateRemovedEvent) -> None: + """Disable TLS when TLS certificate is removed.""" + relation = self.charm.model.get_relation(TLS_TRANSFER_RELATION, event.relation_id) + if relation is None: + logger.error("Relationship not established anymore.") + return + + secret_name = f"ca-{relation.app.name}" + self.charm.set_secret(SCOPE, secret_name, None) + + try: + if not self.charm.clean_ca_file_from_workload(secret_name): + logger.debug("Cannot clean CA certificates at this moment") + event.defer() + return + except (PebbleConnectionError, PathError, ProtocolError, RetryError) as e: + logger.error("Cannot clean CA certificates: %r", e) + event.defer() + return + def _get_sans(self) -> dict: """Create a list of Subject Alternative Names for a PostgreSQL unit. diff --git a/metadata.yaml b/metadata.yaml index 94cb47ec89..61d7ae7533 100644 --- a/metadata.yaml +++ b/metadata.yaml @@ -49,10 +49,17 @@ requires: interface: tls-certificates limit: 1 optional: true + receive-ca-cert: + interface: certificate_transfer + optional: true s3-parameters: interface: s3 limit: 1 optional: true + ldap: + interface: ldap + limit: 1 + optional: true tracing: interface: tracing limit: 1 diff --git a/pyproject.toml b/pyproject.toml index c044782906..1a7c1b7d51 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,6 +30,8 @@ pydantic = "^1.10" cosl = ">=0.0.50" # tls_certificates_interface/v2/tls_certificates.py cryptography = "*" +# certificate_transfer_interface/v0/certificate_transfer.py +# tls_certificates_interface/v2/tls_certificates.py jsonschema = "*" # tempo_coordinator_k8s/v0/charm_tracing.py opentelemetry-exporter-otlp-proto-http = "1.21.0" diff --git a/src/charm.py b/src/charm.py index ee1a4c9ceb..7a9e49830d 100755 --- a/src/charm.py +++ b/src/charm.py @@ -96,6 +96,7 @@ TLS_KEY_FILE, TRACING_PROTOCOL, UNIT_SCOPE, + UPDATE_CERTS_BIN_PATH, USER, USER_PASSWORD_KEY, ) @@ -191,6 +192,8 @@ def __init__(self, *args): self.framework.observe(self.on.update_status, self._on_update_status) self.cluster_name = self.app.name self._member_name = self.unit.name.replace("/", "-") + + self._certs_path = "/usr/local/share/ca-certificates" self._storage_path = self.meta.storages["pgdata"].location self.upgrade = PostgreSQLUpgrade( @@ -1803,6 +1806,33 @@ def push_tls_files_to_workload(self) -> bool: logger.exception("TLS files failed to push. Error in config update") return False + def push_ca_file_into_workload(self, secret_name: str) -> bool: + """Move CA certificates file into the PostgreSQL storage path.""" + certs = self.get_secret(UNIT_SCOPE, secret_name) + if certs is not None: + certs_file = Path(self._certs_path, f"{secret_name}.crt") + certs_file.write_text(certs) + subprocess.check_call([UPDATE_CERTS_BIN_PATH]) # noqa: S603 + + try: + return self.update_config() + except Exception: + logger.exception("CA file failed to push. Error in config update") + return False + + def clean_ca_file_from_workload(self, secret_name: str) -> bool: + """Cleans up CA certificates from the PostgreSQL storage path.""" + certs_file = Path(self._certs_path, f"{secret_name}.crt") + certs_file.unlink() + + subprocess.check_call([UPDATE_CERTS_BIN_PATH]) # noqa: S603 + + try: + return self.update_config() + except Exception: + logger.exception("CA file failed to clean. Error in config update") + return False + def _reboot_on_detached_storage(self, event: EventBase) -> None: """Reboot on detached storage. diff --git a/src/constants.py b/src/constants.py index 4dd91be625..7a431a1640 100644 --- a/src/constants.py +++ b/src/constants.py @@ -56,6 +56,8 @@ POSTGRESQL_DATA_PATH = f"{SNAP_DATA_PATH}/postgresql" POSTGRESQL_LOGS_PATH = f"{SNAP_LOGS_PATH}/postgresql" +UPDATE_CERTS_BIN_PATH = "/usr/sbin/update-ca-certificates" + PGBACKREST_CONFIGURATION_FILE = f"--config={PGBACKREST_CONF_PATH}/pgbackrest.conf" METRICS_PORT = "9187" diff --git a/tests/integration/helpers.py b/tests/integration/helpers.py index 6fe8fd144f..9794364a4b 100644 --- a/tests/integration/helpers.py +++ b/tests/integration/helpers.py @@ -1131,7 +1131,9 @@ async def backup_operations( config={"profile": "testing"}, ) - await ops_test.model.relate(database_app_name, tls_certificates_app_name) + await ops_test.model.relate( + f"{database_app_name}:certificates", f"{tls_certificates_app_name}:certificates" + ) async with ops_test.fast_forward(fast_interval="60s"): await ops_test.model.wait_for_idle(apps=[database_app_name], status="active", timeout=1000) diff --git a/tests/integration/test_backups_pitr_aws.py b/tests/integration/test_backups_pitr_aws.py index d835110179..d291337b7c 100644 --- a/tests/integration/test_backups_pitr_aws.py +++ b/tests/integration/test_backups_pitr_aws.py @@ -68,7 +68,9 @@ async def pitr_backup_operations( logger.info( "integrating self-signed-certificates with postgresql and waiting them to stabilize" ) - await ops_test.model.relate(database_app_name, tls_certificates_app_name) + await ops_test.model.relate( + f"{database_app_name}:certificates", f"{tls_certificates_app_name}:certificates" + ) async with ops_test.fast_forward(fast_interval="60s"): await ops_test.model.wait_for_idle( apps=[database_app_name, tls_certificates_app_name], status="active", timeout=1000 diff --git a/tests/integration/test_backups_pitr_gcp.py b/tests/integration/test_backups_pitr_gcp.py index 40b9e3a41f..99ecb5f72d 100644 --- a/tests/integration/test_backups_pitr_gcp.py +++ b/tests/integration/test_backups_pitr_gcp.py @@ -68,7 +68,9 @@ async def pitr_backup_operations( logger.info( "integrating self-signed-certificates with postgresql and waiting them to stabilize" ) - await ops_test.model.relate(database_app_name, tls_certificates_app_name) + await ops_test.model.relate( + f"{database_app_name}:certificates", f"{tls_certificates_app_name}:certificates" + ) async with ops_test.fast_forward(fast_interval="60s"): await ops_test.model.wait_for_idle( apps=[database_app_name, tls_certificates_app_name], status="active", timeout=1000 diff --git a/tests/integration/test_tls.py b/tests/integration/test_tls.py index 8a02a03755..f37131907b 100644 --- a/tests/integration/test_tls.py +++ b/tests/integration/test_tls.py @@ -66,7 +66,9 @@ async def test_tls_enabled(ops_test: OpsTest) -> None: ) # Relate it to the PostgreSQL to enable TLS. - await ops_test.model.relate(DATABASE_APP_NAME, tls_certificates_app_name) + await ops_test.model.relate( + f"{DATABASE_APP_NAME}:certificates", f"{tls_certificates_app_name}:certificates" + ) await ops_test.model.wait_for_idle(status="active", timeout=1500, raise_on_error=False) # Wait for all units enabling TLS. diff --git a/tests/unit/test_charm.py b/tests/unit/test_charm.py index e500a8d099..50776ef87d 100644 --- a/tests/unit/test_charm.py +++ b/tests/unit/test_charm.py @@ -41,7 +41,13 @@ SwitchoverFailedError, SwitchoverNotSyncError, ) -from constants import PEER, POSTGRESQL_SNAP_NAME, SECRET_INTERNAL_LABEL, SNAP_PACKAGES +from constants import ( + PEER, + POSTGRESQL_SNAP_NAME, + SECRET_INTERNAL_LABEL, + SNAP_PACKAGES, + UPDATE_CERTS_BIN_PATH, +) CREATE_CLUSTER_CONF_PATH = "/etc/postgresql-common/createcluster.d/pgcharm.conf" @@ -1766,6 +1772,42 @@ def test_push_tls_files_to_workload(harness): assert _render_file.call_count == 2 +def test_push_ca_file_into_workload(harness): + with ( + patch("charm.PostgresqlOperatorCharm.update_config") as _update_config, + patch("pathlib.Path.write_text") as _write_text, + patch("subprocess.check_call") as _check_call, + ): + harness.charm.set_secret("unit", "ca-app", "test-ca") + + assert harness.charm.push_ca_file_into_workload("ca-app") + _write_text.assert_called_once() + _check_call.assert_called_once_with([UPDATE_CERTS_BIN_PATH]) + _update_config.assert_called_once() + + +def test_clean_ca_file_from_workload(harness): + with ( + patch("charm.PostgresqlOperatorCharm.update_config") as _update_config, + patch("pathlib.Path.write_text") as _write_text, + patch("pathlib.Path.unlink") as _unlink, + patch("subprocess.check_call") as _check_call, + ): + harness.charm.set_secret("unit", "ca-app", "test-ca") + + assert harness.charm.push_ca_file_into_workload("ca-app") + _write_text.assert_called_once() + _check_call.assert_called_once_with([UPDATE_CERTS_BIN_PATH]) + _update_config.assert_called_once() + + _check_call.reset_mock() + _update_config.reset_mock() + + assert harness.charm.clean_ca_file_from_workload("ca-app") + _unlink.assert_called_once() + _check_call.assert_called_once_with([UPDATE_CERTS_BIN_PATH]) + + def test_is_workload_running(harness): with patch("charm.snap.SnapCache") as _snap_cache: pg_snap = _snap_cache.return_value[POSTGRESQL_SNAP_NAME] From 13b82793977e2cb0355eb1128cbb70385901f340 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sinclert=20P=C3=A9rez?= Date: Wed, 16 Apr 2025 19:20:49 +0200 Subject: [PATCH 016/112] [DPE-6345] LDAP III: Define config and handlers (#825) --- config.yaml | 8 +++- src/charm.py | 61 ++++++++++++++++++++++++++++-- src/cluster.py | 18 +++++++++ src/config.py | 1 + src/ldap.py | 66 +++++++++++++++++++++++++++++++++ templates/patroni.yml.j2 | 10 +++-- tests/unit/test_charm.py | 34 +++++++++++++++++ tests/unit/test_cluster.py | 18 +++++++++ tests/unit/test_ldap.py | 76 ++++++++++++++++++++++++++++++++++++++ 9 files changed, 285 insertions(+), 7 deletions(-) create mode 100644 src/ldap.py create mode 100644 tests/unit/test_ldap.py diff --git a/config.yaml b/config.yaml index 8819015d79..f509a0eca1 100644 --- a/config.yaml +++ b/config.yaml @@ -69,6 +69,12 @@ options: Enable synchronized sequential scans. type: boolean default: true + ldap_search_filter: + description: | + The LDAP search filter to match users with. + Example: (|(uid=$username)(email=$username)) + type: string + default: "(uid=$username)" logging_client_min_messages: description: | Sets the message levels that are sent to the client. @@ -889,4 +895,4 @@ options: Multixact age at which VACUUM should scan whole table to freeze tuples. Allowed values are: from 0 to 2000000000. type: int - default: 150000000 \ No newline at end of file + default: 150000000 diff --git a/src/charm.py b/src/charm.py index 7a9e49830d..d2c2b1ba5a 100755 --- a/src/charm.py +++ b/src/charm.py @@ -100,6 +100,7 @@ USER, USER_PASSWORD_KEY, ) +from ldap import PostgreSQLLDAP from relations.async_replication import ( REPLICATION_CONSUMER_RELATION, REPLICATION_OFFER_RELATION, @@ -135,6 +136,7 @@ class CannotConnectError(Exception): PostgreSQL, PostgreSQLAsyncReplication, PostgreSQLBackups, + PostgreSQLLDAP, PostgreSQLProvider, PostgreSQLTLS, PostgreSQLUpgrade, @@ -206,6 +208,7 @@ def __init__(self, *args): self.legacy_db_relation = DbProvides(self, admin=False) self.legacy_db_admin_relation = DbProvides(self, admin=True) self.backup = PostgreSQLBackups(self, "s3-parameters") + self.ldap = PostgreSQLLDAP(self, "ldap") self.tls = PostgreSQLTLS(self, PEER) self.async_replication = PostgreSQLAsyncReplication(self) self.restart_manager = RollingOpsManager( @@ -909,6 +912,21 @@ def _patroni(self) -> Patroni: self.get_secret(APP_SCOPE, PATRONI_PASSWORD_KEY), ) + @property + def is_connectivity_enabled(self) -> bool: + """Return whether this unit can be connected externally.""" + return self.unit_peer_data.get("connectivity", "on") == "on" + + @property + def is_ldap_charm_related(self) -> bool: + """Return whether this unit has an LDAP charm related.""" + return self.app_peer_data.get("ldap_enabled", "False") == "True" + + @property + def is_ldap_enabled(self) -> bool: + """Return whether this unit has LDAP enabled.""" + return self.is_ldap_charm_related and self.is_cluster_initialised + @property def is_primary(self) -> bool: """Return whether this unit is the primary instance.""" @@ -1407,12 +1425,16 @@ def _on_get_password(self, event: ActionEvent) -> None: If no user is provided, the password of the operator user is returned. """ username = event.params.get("username", USER) + if username not in PASSWORD_USERS and self.is_ldap_enabled: + event.fail("The action can be run only for system users when LDAP is enabled") + return if username not in PASSWORD_USERS: event.fail( - f"The action can be run only for users used by the charm or Patroni:" + f"The action can be run only for system users or Patroni:" f" {', '.join(PASSWORD_USERS)} not {username}" ) return + event.set_results({"password": self.get_secret(APP_SCOPE, f"{username}-password")}) def _on_set_password(self, event: ActionEvent) -> None: @@ -1423,9 +1445,12 @@ def _on_set_password(self, event: ActionEvent) -> None: return username = event.params.get("username", USER) + if username not in SYSTEM_USERS and self.is_ldap_enabled: + event.fail("The action can be run only for system users when LDAP is enabled") + return if username not in SYSTEM_USERS: event.fail( - f"The action can be run only for users used by the charm:" + f"The action can be run only for system users:" f" {', '.join(SYSTEM_USERS)} not {username}" ) return @@ -1911,8 +1936,9 @@ def update_config(self, is_creating_backup: bool = False, no_peers: bool = False # Update and reload configuration based on TLS files availability. self._patroni.render_patroni_yml_file( - connectivity=self.unit_peer_data.get("connectivity", "on") == "on", + connectivity=self.is_connectivity_enabled, is_creating_backup=is_creating_backup, + enable_ldap=self.is_ldap_enabled, enable_tls=enable_tls, backup_id=self.app_peer_data.get("restoring-backup"), pitr_target=self.app_peer_data.get("restore-to-time"), @@ -2177,6 +2203,35 @@ def get_plugins(self) -> list[str]: plugins.append(ext) return plugins + def get_ldap_parameters(self) -> dict: + """Returns the LDAP configuration to use.""" + if not self.is_cluster_initialised: + return {} + if not self.is_ldap_charm_related: + logger.debug("LDAP is not enabled") + return {} + + data = self.ldap.get_relation_data() + if data is None: + return {} + + params = { + "ldapbasedn": data.base_dn, + "ldapbinddn": data.bind_dn, + "ldapbindpasswd": data.bind_password, + "ldaptls": data.starttls, + "ldapurl": data.urls[0], + } + + # LDAP authentication parameters that are exclusive to + # one of the two supported modes (simple bind or search+bind) + # must be put at the very end of the parameters string + params.update({ + "ldapsearchfilter": self.config.ldap_search_filter, + }) + + return params + if __name__ == "__main__": main(PostgresqlOperatorCharm) diff --git a/src/cluster.py b/src/cluster.py index b321a4cac4..3ca1a46d4d 100644 --- a/src/cluster.py +++ b/src/cluster.py @@ -162,6 +162,17 @@ def _patroni_url(self) -> str: """Patroni REST API URL.""" return f"{'https' if self.tls_enabled else 'http'}://{self.unit_ip}:8008" + @staticmethod + def _dict_to_hba_string(_dict: dict[str, Any]) -> str: + """Transform a dictionary into a Host Based Authentication valid string.""" + for key, value in _dict.items(): + if isinstance(value, bool): + _dict[key] = int(value) + if isinstance(value, str): + _dict[key] = f'"{value}"' + + return " ".join(f"{key}={value}" for key, value in _dict.items()) + def bootstrap_cluster(self) -> bool: """Bootstrap a PostgreSQL cluster using Patroni.""" # Render the configuration files and start the cluster. @@ -610,6 +621,7 @@ def render_patroni_yml_file( self, connectivity: bool = False, is_creating_backup: bool = False, + enable_ldap: bool = False, enable_tls: bool = False, stanza: str | None = None, restore_stanza: str | None = None, @@ -626,6 +638,7 @@ def render_patroni_yml_file( Args: connectivity: whether to allow external connections to the database. is_creating_backup: whether this unit is creating a backup. + enable_ldap: whether to enable LDAP authentication. enable_tls: whether to enable TLS. stanza: name of the stanza created by pgBackRest. restore_stanza: name of the stanza used when restoring a backup. @@ -640,6 +653,9 @@ def render_patroni_yml_file( # Open the template patroni.yml file. with open("templates/patroni.yml.j2") as file: template = Template(file.read()) + + ldap_params = self.charm.get_ldap_parameters() + # Render the template file with the correct values. rendered = template.render( conf_path=PATRONI_CONF_PATH, @@ -648,6 +664,7 @@ def render_patroni_yml_file( log_path=PATRONI_LOGS_PATH, postgresql_log_path=POSTGRESQL_LOGS_PATH, data_path=POSTGRESQL_DATA_PATH, + enable_ldap=enable_ldap, enable_tls=enable_tls, member_name=self.member_name, partner_addrs=self.charm.async_replication.get_partner_addresses() @@ -677,6 +694,7 @@ def render_patroni_yml_file( primary_cluster_endpoint=self.charm.async_replication.get_primary_cluster_endpoint(), extra_replication_endpoints=self.charm.async_replication.get_standby_endpoints(), raft_password=self.raft_password, + ldap_parameters=self._dict_to_hba_string(ldap_params), patroni_password=self.patroni_password, ) self.render_file(f"{PATRONI_CONF_PATH}/patroni.yaml", rendered, 0o600) diff --git a/src/config.py b/src/config.py index a755ca0f6d..610723291b 100644 --- a/src/config.py +++ b/src/config.py @@ -29,6 +29,7 @@ class CharmConfig(BaseConfigModel): instance_max_locks_per_transaction: int | None instance_password_encryption: str | None instance_synchronize_seqscans: bool | None + ldap_search_filter: str | None logging_client_min_messages: str | None logging_log_connections: bool | None logging_log_disconnections: bool | None diff --git a/src/ldap.py b/src/ldap.py new file mode 100644 index 0000000000..ae737494d1 --- /dev/null +++ b/src/ldap.py @@ -0,0 +1,66 @@ +# Copyright 2025 Canonical Ltd. +# See LICENSE file for licensing details. + +"""LDAP implementation.""" + +import logging + +from charms.glauth_k8s.v0.ldap import ( + LdapProviderData, + LdapReadyEvent, + LdapRequirer, + LdapUnavailableEvent, +) +from ops import Relation +from ops.framework import Object +from ops.model import ActiveStatus + +logger = logging.getLogger(__name__) + + +class PostgreSQLLDAP(Object): + """In this class, we manage PostgreSQL LDAP access.""" + + def __init__(self, charm, relation_name: str): + """Manager of PostgreSQL LDAP.""" + super().__init__(charm, "ldap") + self.charm = charm + self.relation_name = relation_name + + # LDAP relation handles the config options for LDAP access + self.ldap = LdapRequirer(self.charm, self.relation_name) + self.framework.observe(self.ldap.on.ldap_ready, self._on_ldap_ready) + self.framework.observe(self.ldap.on.ldap_unavailable, self._on_ldap_unavailable) + + @property + def _relation(self) -> Relation: + """Return the relation object.""" + return self.model.get_relation(self.relation_name) + + def _on_ldap_ready(self, _: LdapReadyEvent) -> None: + """Handler for the LDAP ready event.""" + logger.debug("Enabling LDAP connection") + if self.charm.unit.is_leader(): + self.charm.app_peer_data.update({"ldap_enabled": "True"}) + + self.charm.update_config() + self.charm.unit.status = ActiveStatus() + + def _on_ldap_unavailable(self, _: LdapUnavailableEvent) -> None: + """Handler for the LDAP unavailable event.""" + logger.debug("Disabling LDAP connection") + if self.charm.unit.is_leader(): + self.charm.app_peer_data.update({"ldap_enabled": "False"}) + + self.charm.update_config() + + def get_relation_data(self) -> LdapProviderData | None: + """Get the LDAP info from the LDAP Provider class.""" + data = self.ldap.consume_ldap_relation_data(relation=self._relation) + if data is None: + logger.warning("LDAP relation is not ready") + + if not self.charm.is_connectivity_enabled: + logger.warning("LDAP server will not be accessible") + + return data diff --git a/templates/patroni.yml.j2 b/templates/patroni.yml.j2 index 63d99c160f..0ff720d698 100644 --- a/templates/patroni.yml.j2 +++ b/templates/patroni.yml.j2 @@ -161,10 +161,14 @@ postgresql: {%- if not connectivity %} - {{ 'hostssl' if enable_tls else 'host' }} all all 0.0.0.0/0 reject - {{ 'hostssl' if enable_tls else 'host' }} all all {{ self_ip }} md5 - {% else %} - - {{ 'hostssl' if enable_tls else 'host' }} replication replication 127.0.0.1/32 md5 - {%- endif %} + {%- elif enable_ldap %} + - {{ 'hostssl' if enable_tls else 'host' }} all +identity_access 0.0.0.0/0 ldap {{ ldap_parameters }} + - {{ 'hostssl' if enable_tls else 'host' }} all +internal_access 0.0.0.0/0 md5 + - {{ 'hostssl' if enable_tls else 'host' }} all +relation_access 0.0.0.0/0 md5 + {%- else %} - {{ 'hostssl' if enable_tls else 'host' }} all all 0.0.0.0/0 md5 + {%- endif %} + - {{ 'hostssl' if enable_tls else 'host' }} replication replication 127.0.0.1/32 md5 # Allow replications connections from other cluster members. {%- for endpoint in extra_replication_endpoints %} - {{ 'hostssl' if enable_tls else 'host' }} replication replication {{ endpoint }}/32 md5 diff --git a/tests/unit/test_charm.py b/tests/unit/test_charm.py index 50776ef87d..025ab68e01 100644 --- a/tests/unit/test_charm.py +++ b/tests/unit/test_charm.py @@ -1301,6 +1301,7 @@ def test_update_config(harness): _render_patroni_yml_file.assert_called_once_with( connectivity=True, is_creating_backup=False, + enable_ldap=False, enable_tls=False, backup_id=None, stanza=None, @@ -1325,6 +1326,7 @@ def test_update_config(harness): _render_patroni_yml_file.assert_called_once_with( connectivity=True, is_creating_backup=False, + enable_ldap=False, enable_tls=True, backup_id=None, stanza=None, @@ -2845,3 +2847,35 @@ def test_on_promote_to_primary(harness): harness.charm._on_promote_to_primary(event) _raft_reinitialisation.assert_called_once_with() assert harness.charm.unit_peer_data["raft_candidate"] == "True" + + +def test_get_ldap_parameters(harness): + with ( + patch("charm.PostgreSQLLDAP.get_relation_data") as _get_relation_data, + patch( + target="charm.PostgresqlOperatorCharm.is_cluster_initialised", + new_callable=PropertyMock, + return_value=True, + ) as _cluster_initialised, + ): + with harness.hooks_disabled(): + harness.update_relation_data( + harness.model.get_relation(PEER).id, + harness.charm.app.name, + {"ldap_enabled": "False"}, + ) + + harness.charm.get_ldap_parameters() + _get_relation_data.assert_not_called() + _get_relation_data.reset_mock() + + with harness.hooks_disabled(): + harness.update_relation_data( + harness.model.get_relation(PEER).id, + harness.charm.app.name, + {"ldap_enabled": "True"}, + ) + + harness.charm.get_ldap_parameters() + _get_relation_data.assert_called_once() + _get_relation_data.reset_mock() diff --git a/tests/unit/test_cluster.py b/tests/unit/test_cluster.py index 7dd1e1ddf7..4e02f37beb 100644 --- a/tests/unit/test_cluster.py +++ b/tests/unit/test_cluster.py @@ -181,6 +181,24 @@ def test_get_postgresql_version(peers_ips, patroni): _get_installed_snaps.assert_called_once_with() +def test_dict_to_hba_string(harness, patroni): + mock_data = { + "ldapbasedn": "dc=example,dc=net", + "ldapbinddn": "cn=serviceuser,dc=example,dc=net", + "ldapbindpasswd": "password", + "ldaptls": False, + "ldapurl": "ldap://0.0.0.0:3893", + } + + assert patroni._dict_to_hba_string(mock_data) == ( + 'ldapbasedn="dc=example,dc=net" ' + 'ldapbinddn="cn=serviceuser,dc=example,dc=net" ' + 'ldapbindpasswd="password" ' + "ldaptls=0 " + 'ldapurl="ldap://0.0.0.0:3893"' + ) + + def test_get_primary(peers_ips, patroni): with ( patch("requests.get", side_effect=mocked_requests_get) as _get, diff --git a/tests/unit/test_ldap.py b/tests/unit/test_ldap.py new file mode 100644 index 0000000000..9fe8edcbca --- /dev/null +++ b/tests/unit/test_ldap.py @@ -0,0 +1,76 @@ +# Copyright 2025 Canonical Ltd. +# See LICENSE file for licensing details. + +from unittest.mock import ( + MagicMock, + patch, +) + +import pytest +from charms.glauth_k8s.v0.ldap import LdapProviderData +from ops.testing import Harness + +from charm import PostgresqlOperatorCharm +from constants import PEER + + +@pytest.fixture(autouse=True) +def harness(): + harness = Harness(PostgresqlOperatorCharm) + + # Set up the initial relation and hooks. + peer_relation_id = harness.add_relation(PEER, "postgresql") + harness.add_relation_unit(peer_relation_id, "postgresql/0") + harness.set_leader(True) + + harness.begin() + yield harness + harness.cleanup() + + +def test_on_ldap_ready(harness): + mock_event = MagicMock() + + with patch("charm.PostgresqlOperatorCharm.update_config") as _update_config: + harness.charm.ldap._on_ldap_ready(mock_event) + _update_config.assert_called_once() + + peer_rel_id = harness.model.get_relation(PEER).id + app_databag = harness.get_relation_data(peer_rel_id, harness.charm.app) + assert "ldap_enabled" in app_databag + + +def test_on_ldap_unavailable(harness): + mock_event = MagicMock() + + with patch("charm.PostgresqlOperatorCharm.update_config") as _update_config: + harness.charm.ldap._on_ldap_unavailable(mock_event) + _update_config.assert_called_once() + + peer_rel_id = harness.model.get_relation(PEER).id + app_databag = harness.get_relation_data(peer_rel_id, harness.charm.app) + assert app_databag["ldap_enabled"] == "False" + + +def test_get_relation_data(harness): + mock_data = LdapProviderData( + auth_method="simple", + base_dn="dc=example,dc=net", + bind_dn="cn=serviceuser,dc=example,dc=net", + bind_password="password", + bind_password_secret=None, + starttls=False, + ldaps_urls=[], + urls=[], + ) + + mock_data_dict = mock_data.model_dump(exclude_none=True) + mock_data_dict["bind_password"] = mock_data.bind_password + + assert harness.charm.ldap.get_relation_data() is None + + with harness.hooks_disabled(): + ldap_relation_id = harness.add_relation("ldap", "glauth-k8s") + harness.update_relation_data(ldap_relation_id, "glauth-k8s", mock_data_dict) + + assert harness.charm.ldap.get_relation_data() == mock_data From 327d491f39723ce76e4875d46f673412ac7be093 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sinclert=20P=C3=A9rez?= Date: Tue, 22 Apr 2025 09:17:59 +0200 Subject: [PATCH 017/112] [DPE-6345] LDAP IV: Define snap service (#838) --- src/charm.py | 95 +++++++++++++++++++++++++++++++--------- src/utils.py | 19 ++++++++ tests/unit/test_charm.py | 17 +++++++ tests/unit/test_utils.py | 20 ++++++++- 4 files changed, 130 insertions(+), 21 deletions(-) diff --git a/src/charm.py b/src/charm.py index d2c2b1ba5a..af3bdac712 100755 --- a/src/charm.py +++ b/src/charm.py @@ -16,6 +16,7 @@ from datetime import datetime from pathlib import Path from typing import Literal, get_args +from urllib.parse import urlparse import psycopg2 from charms.data_platform_libs.v0.data_interfaces import DataPeerData, DataPeerUnitData @@ -73,6 +74,7 @@ APP_SCOPE, BACKUP_USER, DATABASE_DEFAULT_NAME, + DATABASE_PORT, METRICS_PORT, MONITORING_PASSWORD_KEY, MONITORING_SNAP_SERVICE, @@ -110,7 +112,7 @@ from relations.postgresql_provider import PostgreSQLProvider from rotate_logs import RotateLogs from upgrade import PostgreSQLUpgrade, get_postgresql_dependencies_model -from utils import new_password +from utils import new_password, snap_refreshed logger = logging.getLogger(__name__) @@ -1316,29 +1318,86 @@ def _restart_services_after_reboot(self): self._patroni.start_patroni() self.backup.start_stop_pgbackrest_service() - def _setup_exporter(self) -> None: - """Set up postgresql_exporter options.""" - cache = snap.SnapCache() - postgres_snap = cache[POSTGRESQL_SNAP_NAME] + def _restart_metrics_service(self, postgres_snap: snap.Snap) -> None: + """Restart the monitoring service if the password was rotated.""" + try: + snap_password = postgres_snap.get("exporter.password") + except snap.SnapError: + logger.warning("Early exit: Trying to reset metrics service with no configuration set") + return None - if postgres_snap.revision != next( - filter(lambda snap_package: snap_package[0] == POSTGRESQL_SNAP_NAME, SNAP_PACKAGES) - )[1]["revision"].get(platform.machine()): - logger.debug( - "Early exit _setup_exporter: snap was not refreshed to the right version yet" - ) + if snap_password != self.get_secret(APP_SCOPE, MONITORING_PASSWORD_KEY): + self._setup_exporter(postgres_snap) + + def _restart_ldap_sync_service(self, postgres_snap: snap.Snap) -> None: + """Restart the LDAP sync service in case any configuration changed.""" + if not self._patroni.member_started: + logger.debug("Restart LDAP sync early exit: Patroni has not started yet") return + sync_service = postgres_snap.services["ldap-sync"] + + if not self.is_primary and sync_service["active"]: + logger.debug("Stopping LDAP sync service. It must only run in the primary") + postgres_snap.stop(services=["ldap-sync"]) + + if self.is_primary and not self.is_ldap_enabled: + logger.debug("Stopping LDAP sync service") + postgres_snap.stop(services=["ldap-sync"]) + return + + if self.is_primary and self.is_ldap_enabled: + self._setup_ldap_sync(postgres_snap) + + def _setup_exporter(self, postgres_snap: snap.Snap | None = None) -> None: + """Set up postgresql_exporter options.""" + if postgres_snap is None: + cache = snap.SnapCache() + postgres_snap = cache[POSTGRESQL_SNAP_NAME] + postgres_snap.set({ "exporter.user": MONITORING_USER, "exporter.password": self.get_secret(APP_SCOPE, MONITORING_PASSWORD_KEY), }) + if postgres_snap.services[MONITORING_SNAP_SERVICE]["active"] is False: postgres_snap.start(services=[MONITORING_SNAP_SERVICE], enable=True) else: postgres_snap.restart(services=[MONITORING_SNAP_SERVICE]) + self.unit_peer_data.update({"exporter-started": "True"}) + def _setup_ldap_sync(self, postgres_snap: snap.Snap | None = None) -> None: + """Set up postgresql_ldap_sync options.""" + if postgres_snap is None: + cache = snap.SnapCache() + postgres_snap = cache[POSTGRESQL_SNAP_NAME] + + ldap_params = self.get_ldap_parameters() + ldap_url = urlparse(ldap_params["ldapurl"]) + ldap_host = ldap_url.hostname + ldap_port = ldap_url.port + + ldap_base_dn = ldap_params["ldapbasedn"] + ldap_bind_username = ldap_params["ldapbinddn"] + ldap_bind_password = ldap_params["ldapbindpasswd"] + + postgres_snap.set({ + "ldap-sync.ldap_host": ldap_host, + "ldap-sync.ldap_port": ldap_port, + "ldap-sync.ldap_base_dn": ldap_base_dn, + "ldap-sync.ldap_bind_username": ldap_bind_username, + "ldap-sync.ldap_bind_password": ldap_bind_password, + "ldap-sync.postgres_host": "127.0.0.1", + "ldap-sync.postgres_port": DATABASE_PORT, + "ldap-sync.postgres_database": DATABASE_DEFAULT_NAME, + "ldap-sync.postgres_username": USER, + "ldap-sync.postgres_password": self._get_password(), + }) + + logger.debug("Starting LDAP sync service") + postgres_snap.restart(services=["ldap-sync"]) + def _start_primary(self, event: StartEvent) -> None: """Bootstrap the cluster.""" # Set some information needed by Patroni to bootstrap the cluster. @@ -1986,19 +2045,15 @@ def update_config(self, is_creating_backup: bool = False, no_peers: bool = False self._handle_postgresql_restart_need(enable_tls) - # Restart the monitoring service if the password was rotated cache = snap.SnapCache() postgres_snap = cache[POSTGRESQL_SNAP_NAME] - try: - snap_password = postgres_snap.get("exporter.password") - except snap.SnapError: - logger.warning( - "Early exit update_config: Trying to reset metrics service with no configuration set" - ) + if not snap_refreshed(postgres_snap.revision): + logger.debug("Early exit: snap was not refreshed to the right version yet") return True - if snap_password != self.get_secret(APP_SCOPE, MONITORING_PASSWORD_KEY): - self._setup_exporter() + + self._restart_metrics_service(postgres_snap) + self._restart_ldap_sync_service(postgres_snap) return True diff --git a/src/utils.py b/src/utils.py index b3f0e1abad..4f07ec87fe 100644 --- a/src/utils.py +++ b/src/utils.py @@ -3,9 +3,15 @@ """A collection of utility functions that are used in the charm.""" +import platform import secrets import string +from constants import ( + POSTGRESQL_SNAP_NAME, + SNAP_PACKAGES, +) + def new_password() -> str: """Generate a random password string. @@ -16,3 +22,16 @@ def new_password() -> str: choices = string.ascii_letters + string.digits password = "".join([secrets.choice(choices) for i in range(16)]) return password + + +def snap_refreshed(target_rev: str) -> bool: + """Whether the snap was refreshed to the target version.""" + arch = platform.machine() + + for snap_package in SNAP_PACKAGES: + snap_name = snap_package[0] + snap_revs = snap_package[1]["revision"] + if snap_name == POSTGRESQL_SNAP_NAME and target_rev != snap_revs.get(arch): + return False + + return True diff --git a/tests/unit/test_charm.py b/tests/unit/test_charm.py index 025ab68e01..ee773ed31f 100644 --- a/tests/unit/test_charm.py +++ b/tests/unit/test_charm.py @@ -1270,10 +1270,17 @@ def test_restart(harness): def test_update_config(harness): with ( patch("subprocess.check_output", return_value=b"C"), + patch("charm.snap_refreshed", return_value=True), patch("charm.snap.SnapCache"), patch( "charm.PostgresqlOperatorCharm._handle_postgresql_restart_need" ) as _handle_postgresql_restart_need, + patch( + "charm.PostgresqlOperatorCharm._restart_metrics_service" + ) as _restart_metrics_service, + patch( + "charm.PostgresqlOperatorCharm._restart_ldap_sync_service" + ) as _restart_ldap_sync_service, patch("charm.Patroni.bulk_update_parameters_controller_by_patroni"), patch("charm.Patroni.member_started", new_callable=PropertyMock) as _member_started, patch( @@ -1313,10 +1320,14 @@ def test_update_config(harness): no_peers=False, ) _handle_postgresql_restart_need.assert_called_once_with(False) + _restart_ldap_sync_service.assert_called_once() + _restart_metrics_service.assert_called_once() assert "tls" not in harness.get_relation_data(rel_id, harness.charm.unit.name) # Test with TLS files available. _handle_postgresql_restart_need.reset_mock() + _restart_ldap_sync_service.reset_mock() + _restart_metrics_service.reset_mock() harness.update_relation_data( rel_id, harness.charm.unit.name, {"tls": ""} ) # Mock some data in the relation to test that it change. @@ -1338,6 +1349,8 @@ def test_update_config(harness): no_peers=False, ) _handle_postgresql_restart_need.assert_called_once() + _restart_ldap_sync_service.assert_called_once() + _restart_metrics_service.assert_called_once() assert "tls" not in harness.get_relation_data( rel_id, harness.charm.unit.name ) # The "tls" flag is set in handle_postgresql_restart_need. @@ -1347,6 +1360,8 @@ def test_update_config(harness): rel_id, harness.charm.unit.name, {"tls": ""} ) # Mock some data in the relation to test that it change. _handle_postgresql_restart_need.reset_mock() + _restart_ldap_sync_service.reset_mock() + _restart_metrics_service.reset_mock() harness.charm.update_config() _handle_postgresql_restart_need.assert_not_called() assert harness.get_relation_data(rel_id, harness.charm.unit.name)["tls"] == "enabled" @@ -1357,6 +1372,8 @@ def test_update_config(harness): ) # Mock some data in the relation to test that it doesn't change. harness.charm.update_config() _handle_postgresql_restart_need.assert_not_called() + _restart_ldap_sync_service.assert_not_called() + _restart_metrics_service.assert_not_called() assert "tls" not in harness.get_relation_data(rel_id, harness.charm.unit.name) diff --git a/tests/unit/test_utils.py b/tests/unit/test_utils.py index 6da8995d02..56b46a01ef 100644 --- a/tests/unit/test_utils.py +++ b/tests/unit/test_utils.py @@ -2,8 +2,10 @@ # See LICENSE file for licensing details. import re +from unittest.mock import patch -from utils import new_password +from constants import POSTGRESQL_SNAP_NAME +from utils import new_password, snap_refreshed def test_new_password(): @@ -16,3 +18,19 @@ def test_new_password(): second_password = new_password() assert re.fullmatch("[a-zA-Z0-9\b]{16}$", second_password) is not None assert second_password != first_password + + +def test_snap_refreshed(): + with patch( + "utils.SNAP_PACKAGES", + [(POSTGRESQL_SNAP_NAME, {"revision": {"aarch64": "100", "x86_64": "100"}})], + ): + assert snap_refreshed("100") is True + assert snap_refreshed("200") is False + + with patch( + "utils.SNAP_PACKAGES", + [(POSTGRESQL_SNAP_NAME, {"revision": {}})], + ): + assert snap_refreshed("100") is False + assert snap_refreshed("200") is False From 138095b5be1af7b7138028973019d850d94618c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sinclert=20P=C3=A9rez?= Date: Tue, 22 Apr 2025 14:51:54 +0200 Subject: [PATCH 018/112] [DPE-6345] LDAP V: Define mapping option (#849) --- config.yaml | 6 ++ lib/charms/postgresql_k8s/v0/postgresql.py | 69 +++++++++++++++++++++- src/charm.py | 7 +++ src/config.py | 1 + tests/unit/test_charm.py | 12 ++++ 5 files changed, 94 insertions(+), 1 deletion(-) diff --git a/config.yaml b/config.yaml index f509a0eca1..b20e0bf2ed 100644 --- a/config.yaml +++ b/config.yaml @@ -69,6 +69,12 @@ options: Enable synchronized sequential scans. type: boolean default: true + ldap_map: + description: | + List of mapped LDAP group names to PostgreSQL group names, separated by commas. + The map is used to assign LDAP synchronized users to PostgreSQL authorization groups. + Example: =,= + type: string ldap_search_filter: description: | The LDAP search filter to match users with. diff --git a/lib/charms/postgresql_k8s/v0/postgresql.py b/lib/charms/postgresql_k8s/v0/postgresql.py index f5c4d0e02b..b7eb90908b 100644 --- a/lib/charms/postgresql_k8s/v0/postgresql.py +++ b/lib/charms/postgresql_k8s/v0/postgresql.py @@ -35,7 +35,7 @@ # Increment this PATCH version before using `charmcraft publish-lib` or reset # to 0 if you are raising the major API version -LIBPATCH = 47 +LIBPATCH = 49 # Groups to distinguish HBA access ACCESS_GROUP_IDENTITY = "identity_access" @@ -776,6 +776,42 @@ def is_restart_pending(self) -> bool: if connection: connection.close() + @staticmethod + def build_postgresql_group_map(group_map: Optional[str]) -> List[Tuple]: + """Build the PostgreSQL authorization group-map. + + Args: + group_map: serialized group-map with the following format: + =, + =, + ... + + Returns: + List of LDAP group to PostgreSQL group tuples. + """ + if group_map is None: + return [] + + group_mappings = group_map.split(",") + group_mappings = (mapping.strip() for mapping in group_mappings) + group_map_list = [] + + for mapping in group_mappings: + mapping_parts = mapping.split("=") + if len(mapping_parts) != 2: + raise ValueError("The group-map must contain value pairs split by commas") + + ldap_group = mapping_parts[0] + psql_group = mapping_parts[1] + + if psql_group in [*ACCESS_GROUPS, PERMISSIONS_GROUP_ADMIN]: + logger.warning(f"Tried to assign LDAP users to forbidden group: {psql_group}") + continue + + group_map_list.append((ldap_group, psql_group)) + + return group_map_list + @staticmethod def build_postgresql_parameters( config_options: dict, available_memory: int, limit_memory: Optional[int] = None @@ -855,3 +891,34 @@ def validate_date_style(self, date_style: str) -> bool: return True except psycopg2.Error: return False + + def validate_group_map(self, group_map: Optional[str]) -> bool: + """Validate the PostgreSQL authorization group-map. + + Args: + group_map: serialized group-map with the following format: + =, + =, + ... + + Returns: + Whether the group-map is valid. + """ + if group_map is None: + return True + + try: + group_map = self.build_postgresql_group_map(group_map) + except ValueError: + return False + + for _, psql_group in group_map: + with self._connect_to_database() as connection, connection.cursor() as cursor: + query = SQL("SELECT TRUE FROM pg_roles WHERE rolname={};") + query = query.format(Literal(psql_group)) + cursor.execute(query) + + if cursor.fetchone() is None: + return False + + return True diff --git a/src/charm.py b/src/charm.py index af3bdac712..bc6fd78a3c 100755 --- a/src/charm.py +++ b/src/charm.py @@ -24,6 +24,7 @@ from charms.grafana_agent.v0.cos_agent import COSAgentProvider, charm_tracing_config from charms.operator_libs_linux.v2 import snap from charms.postgresql_k8s.v0.postgresql import ( + ACCESS_GROUP_IDENTITY, ACCESS_GROUPS, REQUIRED_PLUGINS, PostgreSQL, @@ -1381,6 +1382,7 @@ def _setup_ldap_sync(self, postgres_snap: snap.Snap | None = None) -> None: ldap_base_dn = ldap_params["ldapbasedn"] ldap_bind_username = ldap_params["ldapbinddn"] ldap_bind_password = ldap_params["ldapbindpasswd"] + ldap_group_mappings = self.postgresql.build_postgresql_group_map(self.config.ldap_map) postgres_snap.set({ "ldap-sync.ldap_host": ldap_host, @@ -1388,6 +1390,8 @@ def _setup_ldap_sync(self, postgres_snap: snap.Snap | None = None) -> None: "ldap-sync.ldap_base_dn": ldap_base_dn, "ldap-sync.ldap_bind_username": ldap_bind_username, "ldap-sync.ldap_bind_password": ldap_bind_password, + "ldap-sync.ldap_group_identity": json.dumps(ACCESS_GROUP_IDENTITY), + "ldap-sync.ldap_group_mappings": json.dumps(ldap_group_mappings), "ldap-sync.postgres_host": "127.0.0.1", "ldap-sync.postgres_port": DATABASE_PORT, "ldap-sync.postgres_database": DATABASE_DEFAULT_NAME, @@ -2067,6 +2071,9 @@ def _validate_config_options(self) -> None: "instance_default_text_search_config config option has an invalid value" ) + if not self.postgresql.validate_group_map(self.config.ldap_map): + raise ValueError("ldap_map config option has an invalid value") + if not self.postgresql.validate_date_style(self.config.request_date_style): raise ValueError("request_date_style config option has an invalid value") diff --git a/src/config.py b/src/config.py index 610723291b..16dda4d06f 100644 --- a/src/config.py +++ b/src/config.py @@ -29,6 +29,7 @@ class CharmConfig(BaseConfigModel): instance_max_locks_per_transaction: int | None instance_password_encryption: str | None instance_synchronize_seqscans: bool | None + ldap_map: str | None ldap_search_filter: str | None logging_client_min_messages: str | None logging_log_connections: bool | None diff --git a/tests/unit/test_charm.py b/tests/unit/test_charm.py index ee773ed31f..3ff54bccce 100644 --- a/tests/unit/test_charm.py +++ b/tests/unit/test_charm.py @@ -1445,6 +1445,7 @@ def test_validate_config_options(harness): ): _charm_lib.return_value.get_postgresql_text_search_configs.return_value = [] _charm_lib.return_value.validate_date_style.return_value = False + _charm_lib.return_value.validate_group_map.return_value = False _charm_lib.return_value.get_postgresql_timezones.return_value = [] # Test instance_default_text_search_config exception @@ -1463,6 +1464,17 @@ def test_validate_config_options(harness): "pg_catalog.test" ] + # Test ldap_map exception + with harness.hooks_disabled(): + harness.update_config({"ldap_map": "ldap_group="}) + + with pytest.raises(ValueError) as e: + harness.charm._validate_config_options() + assert str(e.value) == "ldap_map config option has an invalid value" + + _charm_lib.return_value.validate_group_map.assert_called_once_with("ldap_group=") + _charm_lib.return_value.validate_group_map.return_value = True + # Test request_date_style exception with harness.hooks_disabled(): harness.update_config({"request_date_style": "ISO, TEST"}) From 6434998e6646ef69e7c301070a8c927ba073ccd1 Mon Sep 17 00:00:00 2001 From: Dragomir Penev <6687393+dragomirp@users.noreply.github.com> Date: Tue, 22 Apr 2025 22:41:54 +0300 Subject: [PATCH 019/112] [MISC] Disable network cut tests on arm (#844) * Disable network cut tests on arm * Back to LXD 5 --- tests/integration/ha_tests/test_self_healing.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/integration/ha_tests/test_self_healing.py b/tests/integration/ha_tests/test_self_healing.py index f3ddc6fe88..a5b4faddac 100644 --- a/tests/integration/ha_tests/test_self_healing.py +++ b/tests/integration/ha_tests/test_self_healing.py @@ -9,6 +9,7 @@ from pytest_operator.plugin import OpsTest from tenacity import Retrying, stop_after_delay, wait_fixed +from .. import markers from ..helpers import ( CHARM_BASE, db_connect, @@ -380,6 +381,7 @@ async def test_forceful_restart_without_data_and_transaction_logs( @pytest.mark.abort_on_fail +@markers.amd64_only async def test_network_cut(ops_test: OpsTest, continuous_writes, primary_start_timeout): """Completely cut and restore network.""" # Locate primary unit. @@ -468,6 +470,7 @@ async def test_network_cut(ops_test: OpsTest, continuous_writes, primary_start_t @pytest.mark.abort_on_fail +@markers.amd64_only async def test_network_cut_without_ip_change( ops_test: OpsTest, continuous_writes, primary_start_timeout ): From f8ed45af59320b50f6ffe6b66e6ac30e49aa1673 Mon Sep 17 00:00:00 2001 From: Dragomir Penev <6687393+dragomirp@users.noreply.github.com> Date: Wed, 23 Apr 2025 05:52:41 +0300 Subject: [PATCH 020/112] [DPE-6815] disable pgaudit during extensions changes (#842) * disable pgaudit during extensions changes * Bump libs --- .../data_platform_libs/v0/data_interfaces.py | 1068 +++++++++++------ lib/charms/postgresql_k8s/v0/postgresql.py | 8 +- 2 files changed, 716 insertions(+), 360 deletions(-) diff --git a/lib/charms/data_platform_libs/v0/data_interfaces.py b/lib/charms/data_platform_libs/v0/data_interfaces.py index 7fff3c4751..c0ddec58c9 100644 --- a/lib/charms/data_platform_libs/v0/data_interfaces.py +++ b/lib/charms/data_platform_libs/v0/data_interfaces.py @@ -331,7 +331,7 @@ def _on_topic_requested(self, event: TopicRequestedEvent): # Increment this PATCH version before using `charmcraft publish-lib` or reset # to 0 if you are raising the major API version -LIBPATCH = 42 +LIBPATCH = 46 PYDEPS = ["ops>=2.0.0"] @@ -351,6 +351,7 @@ def _on_topic_requested(self, event: TopicRequestedEvent): PROV_SECRET_PREFIX = "secret-" +PROV_SECRET_FIELDS = "provided-secrets" REQ_SECRET_FIELDS = "requested-secrets" GROUP_MAPPING_FIELD = "secret_group_mapping" GROUP_SEPARATOR = "@" @@ -585,6 +586,7 @@ class SecretGroupsAggregate(str): def __init__(self): self.USER = SecretGroup("user") self.TLS = SecretGroup("tls") + self.MTLS = SecretGroup("mtls") self.EXTRA = SecretGroup("extra") def __setattr__(self, name, value): @@ -963,8 +965,11 @@ class Data(ABC): "read-only-uris": SECRET_GROUPS.USER, "tls": SECRET_GROUPS.TLS, "tls-ca": SECRET_GROUPS.TLS, + "mtls-cert": SECRET_GROUPS.MTLS, } + SECRET_FIELDS = [] + def __init__( self, model: Model, @@ -978,15 +983,13 @@ def __init__( self.component = self.local_app if self.SCOPE == Scope.APP else self.local_unit self.secrets = SecretCache(self._model, self.component) self.data_component = None + self._local_secret_fields = [] + self._remote_secret_fields = list(self.SECRET_FIELDS) @property def relations(self) -> List[Relation]: """The list of Relation instances associated with this relation_name.""" - return [ - relation - for relation in self._model.relations[self.relation_name] - if self._is_relation_active(relation) - ] + return self._model.relations[self.relation_name] @property def secrets_enabled(self): @@ -1000,38 +1003,250 @@ def secret_label_map(self): """Exposing secret-label map via a property -- could be overridden in descendants!""" return self.SECRET_LABEL_MAP + @property + def local_secret_fields(self) -> Optional[List[str]]: + """Local access to secrets field, in case they are being used.""" + if self.secrets_enabled: + return self._local_secret_fields + + @property + def remote_secret_fields(self) -> Optional[List[str]]: + """Local access to secrets field, in case they are being used.""" + if self.secrets_enabled: + return self._remote_secret_fields + + @property + def my_secret_groups(self) -> Optional[List[SecretGroup]]: + """Local access to secrets field, in case they are being used.""" + if self.secrets_enabled: + return [ + self.SECRET_LABEL_MAP[field] + for field in self._local_secret_fields + if field in self.SECRET_LABEL_MAP + ] + # Mandatory overrides for internal/helper methods - @abstractmethod + @juju_secrets_only def _get_relation_secret( self, relation_id: int, group_mapping: SecretGroup, relation_name: Optional[str] = None ) -> Optional[CachedSecret]: """Retrieve a Juju Secret that's been stored in the relation databag.""" - raise NotImplementedError + if not relation_name: + relation_name = self.relation_name + + label = self._generate_secret_label(relation_name, relation_id, group_mapping) + if secret := self.secrets.get(label): + return secret + + relation = self._model.get_relation(relation_name, relation_id) + if not relation: + return + + if secret_uri := self.get_secret_uri(relation, group_mapping): + return self.secrets.get(label, secret_uri) + # Mandatory overrides for requirer and peer, implemented for Provider + # Requirer uses local component and switched keys + # _local_secret_fields -> PROV_SECRET_FIELDS + # _remote_secret_fields -> REQ_SECRET_FIELDS + # provider uses remote component and + # _local_secret_fields -> REQ_SECRET_FIELDS + # _remote_secret_fields -> PROV_SECRET_FIELDS @abstractmethod + def _load_secrets_from_databag(self, relation: Relation) -> None: + """Load secrets from the databag.""" + raise NotImplementedError + def _fetch_specific_relation_data( self, relation: Relation, fields: Optional[List[str]] ) -> Dict[str, str]: - """Fetch data available (directily or indirectly -- i.e. secrets) from the relation.""" - raise NotImplementedError + """Fetch data available (directily or indirectly -- i.e. secrets) from the relation (remote app data).""" + if not relation.app: + return {} + self._load_secrets_from_databag(relation) + return self._fetch_relation_data_with_secrets( + relation.app, self.remote_secret_fields, relation, fields + ) - @abstractmethod def _fetch_my_specific_relation_data( self, relation: Relation, fields: Optional[List[str]] - ) -> Dict[str, str]: - """Fetch data available (directily or indirectly -- i.e. secrets) from the relation for owner/this_app.""" - raise NotImplementedError + ) -> dict: + """Fetch our own relation data.""" + # load secrets + self._load_secrets_from_databag(relation) + return self._fetch_relation_data_with_secrets( + self.local_app, + self.local_secret_fields, + relation, + fields, + ) - @abstractmethod def _update_relation_data(self, relation: Relation, data: Dict[str, str]) -> None: - """Update data available (directily or indirectly -- i.e. secrets) from the relation for owner/this_app.""" - raise NotImplementedError + """Set values for fields not caring whether it's a secret or not.""" + self._load_secrets_from_databag(relation) + + _, normal_fields = self._process_secret_fields( + relation, + self.local_secret_fields, + list(data), + self._add_or_update_relation_secrets, + data=data, + ) + + normal_content = {k: v for k, v in data.items() if k in normal_fields} + self._update_relation_data_without_secrets(self.local_app, relation, normal_content) + + def _add_or_update_relation_secrets( + self, + relation: Relation, + group: SecretGroup, + secret_fields: Set[str], + data: Dict[str, str], + uri_to_databag=True, + ) -> bool: + """Update contents for Secret group. If the Secret doesn't exist, create it.""" + if self._get_relation_secret(relation.id, group): + return self._update_relation_secret(relation, group, secret_fields, data) + + return self._add_relation_secret(relation, group, secret_fields, data, uri_to_databag) + + @juju_secrets_only + def _add_relation_secret( + self, + relation: Relation, + group_mapping: SecretGroup, + secret_fields: Set[str], + data: Dict[str, str], + uri_to_databag=True, + ) -> bool: + """Add a new Juju Secret that will be registered in the relation databag.""" + if uri_to_databag and self.get_secret_uri(relation, group_mapping): + logging.error("Secret for relation %s already exists, not adding again", relation.id) + return False + + content = self._content_for_secret_group(data, secret_fields, group_mapping) + + label = self._generate_secret_label(self.relation_name, relation.id, group_mapping) + secret = self.secrets.add(label, content, relation) + + if uri_to_databag: + # According to lint we may not have a Secret ID + if not secret.meta or not secret.meta.id: + logging.error("Secret is missing Secret ID") + raise SecretError("Secret added but is missing Secret ID") + + self.set_secret_uri(relation, group_mapping, secret.meta.id) + + # Return the content that was added + return True + + @juju_secrets_only + def _update_relation_secret( + self, + relation: Relation, + group_mapping: SecretGroup, + secret_fields: Set[str], + data: Dict[str, str], + ) -> bool: + """Update the contents of an existing Juju Secret, referred in the relation databag.""" + secret = self._get_relation_secret(relation.id, group_mapping) + + if not secret: + logging.error("Can't update secret for relation %s", relation.id) + return False + + content = self._content_for_secret_group(data, secret_fields, group_mapping) + + old_content = secret.get_content() + full_content = copy.deepcopy(old_content) + full_content.update(content) + secret.set_content(full_content) + + # Return True on success + return True + + @juju_secrets_only + def _delete_relation_secret( + self, relation: Relation, group: SecretGroup, secret_fields: List[str], fields: List[str] + ) -> bool: + """Update the contents of an existing Juju Secret, referred in the relation databag.""" + secret = self._get_relation_secret(relation.id, group) + + if not secret: + logging.error("Can't delete secret for relation %s", str(relation.id)) + return False + + old_content = secret.get_content() + new_content = copy.deepcopy(old_content) + for field in fields: + try: + new_content.pop(field) + except KeyError: + logging.debug( + "Non-existing secret was attempted to be removed %s, %s", + str(relation.id), + str(field), + ) + return False + + # Remove secret from the relation if it's fully gone + if not new_content: + field = self._generate_secret_field_name(group) + try: + relation.data[self.component].pop(field) + except KeyError: + pass + label = self._generate_secret_label(self.relation_name, relation.id, group) + self.secrets.remove(label) + else: + secret.set_content(new_content) + + # Return the content that was removed + return True - @abstractmethod def _delete_relation_data(self, relation: Relation, fields: List[str]) -> None: """Delete data available (directily or indirectly -- i.e. secrets) from the relation for owner/this_app.""" - raise NotImplementedError + if relation.app: + self._load_secrets_from_databag(relation) + + _, normal_fields = self._process_secret_fields( + relation, self.local_secret_fields, fields, self._delete_relation_secret, fields=fields + ) + self._delete_relation_data_without_secrets(self.local_app, relation, list(normal_fields)) + + def _register_secret_to_relation( + self, relation_name: str, relation_id: int, secret_id: str, group: SecretGroup + ): + """Fetch secrets and apply local label on them. + + [MAGIC HERE] + If we fetch a secret using get_secret(id=, label=), + then will be "stuck" on the Secret object, whenever it may + appear (i.e. as an event attribute, or fetched manually) on future occasions. + + This will allow us to uniquely identify the secret on Provider side (typically on + 'secret-changed' events), and map it to the corresponding relation. + """ + label = self._generate_secret_label(relation_name, relation_id, group) + + # Fetching the Secret's meta information ensuring that it's locally getting registered with + CachedSecret(self._model, self.component, label, secret_id).meta + + def _register_secrets_to_relation(self, relation: Relation, params_name_list: List[str]): + """Make sure that secrets of the provided list are locally 'registered' from the databag. + + More on 'locally registered' magic is described in _register_secret_to_relation() method + """ + if not relation.app: + return + + for group in SECRET_GROUPS.groups(): + secret_field = self._generate_secret_field_name(group) + if secret_field in params_name_list and ( + secret_uri := self.get_secret_uri(relation, group) + ): + self._register_secret_to_relation(relation.name, relation.id, secret_uri, group) # Optional overrides @@ -1052,15 +1267,6 @@ def _legacy_apply_on_delete(self, fields: List[str]) -> None: # Internal helper methods - @staticmethod - def _is_relation_active(relation: Relation): - """Whether the relation is active based on contained data.""" - try: - _ = repr(relation.data) - return True - except (RuntimeError, ModelError): - return False - @staticmethod def _is_secret_field(field: str) -> bool: """Is the field in question a secret reference (URI) field or not?""" @@ -1178,7 +1384,6 @@ def _process_secret_fields( and (self.local_unit == self._model.unit and self.local_unit.is_leader()) and set(req_secret_fields) & set(relation.data[self.component]) ) - normal_fields = set(impacted_rel_fields) if req_secret_fields and self.secrets_enabled and not fallback_to_databag: normal_fields = normal_fields - set(req_secret_fields) @@ -1305,7 +1510,14 @@ def get_relation(self, relation_name, relation_id) -> Relation: def get_secret_uri(self, relation: Relation, group: SecretGroup) -> Optional[str]: """Get the secret URI for the corresponding group.""" secret_field = self._generate_secret_field_name(group) - return relation.data[self.component].get(secret_field) + # if the secret is not managed by this component, + # we need to fetch it from the other side + + # Fix for the linter + if self.my_secret_groups is None: + raise DataInterfacesError("Secrets are not enabled for this component") + component = self.component if group in self.my_secret_groups else relation.app + return relation.data[component].get(secret_field) def set_secret_uri(self, relation: Relation, group: SecretGroup, secret_uri: str) -> None: """Set the secret URI for the corresponding group.""" @@ -1434,6 +1646,32 @@ def __init__(self, charm: CharmBase, relation_data: Data, unique_key: str = ""): self._on_relation_changed_event, ) + self.framework.observe( + self.charm.on[relation_data.relation_name].relation_created, + self._on_relation_created_event, + ) + + self.framework.observe( + charm.on.secret_changed, + self._on_secret_changed_event, + ) + + # Event handlers + + def _on_relation_created_event(self, event: RelationCreatedEvent) -> None: + """Event emitted when the relation is created.""" + pass + + @abstractmethod + def _on_relation_changed_event(self, event: RelationChangedEvent) -> None: + """Event emitted when the relation data has changed.""" + raise NotImplementedError + + @abstractmethod + def _on_secret_changed_event(self, event: SecretChangedEvent) -> None: + """Event emitted when the relation data has changed.""" + raise NotImplementedError + def _diff(self, event: RelationChangedEvent) -> Diff: """Retrieves the diff of the data in the relation changed databag. @@ -1446,11 +1684,6 @@ def _diff(self, event: RelationChangedEvent) -> Diff: """ return diff(event, self.relation_data.data_component) - @abstractmethod - def _on_relation_changed_event(self, event: RelationChangedEvent) -> None: - """Event emitted when the relation data has changed.""" - raise NotImplementedError - # Base ProviderData and RequiresData @@ -1467,165 +1700,11 @@ def __init__( ) -> None: super().__init__(model, relation_name) self.data_component = self.local_app - - # Private methods handling secrets - - @juju_secrets_only - def _add_relation_secret( - self, - relation: Relation, - group_mapping: SecretGroup, - secret_fields: Set[str], - data: Dict[str, str], - uri_to_databag=True, - ) -> bool: - """Add a new Juju Secret that will be registered in the relation databag.""" - if uri_to_databag and self.get_secret_uri(relation, group_mapping): - logging.error("Secret for relation %s already exists, not adding again", relation.id) - return False - - content = self._content_for_secret_group(data, secret_fields, group_mapping) - - label = self._generate_secret_label(self.relation_name, relation.id, group_mapping) - secret = self.secrets.add(label, content, relation) - - # According to lint we may not have a Secret ID - if uri_to_databag and secret.meta and secret.meta.id: - self.set_secret_uri(relation, group_mapping, secret.meta.id) - - # Return the content that was added - return True - - @juju_secrets_only - def _update_relation_secret( - self, - relation: Relation, - group_mapping: SecretGroup, - secret_fields: Set[str], - data: Dict[str, str], - ) -> bool: - """Update the contents of an existing Juju Secret, referred in the relation databag.""" - secret = self._get_relation_secret(relation.id, group_mapping) - - if not secret: - logging.error("Can't update secret for relation %s", relation.id) - return False - - content = self._content_for_secret_group(data, secret_fields, group_mapping) - - old_content = secret.get_content() - full_content = copy.deepcopy(old_content) - full_content.update(content) - secret.set_content(full_content) - - # Return True on success - return True - - def _add_or_update_relation_secrets( - self, - relation: Relation, - group: SecretGroup, - secret_fields: Set[str], - data: Dict[str, str], - uri_to_databag=True, - ) -> bool: - """Update contents for Secret group. If the Secret doesn't exist, create it.""" - if self._get_relation_secret(relation.id, group): - return self._update_relation_secret(relation, group, secret_fields, data) - else: - return self._add_relation_secret(relation, group, secret_fields, data, uri_to_databag) - - @juju_secrets_only - def _delete_relation_secret( - self, relation: Relation, group: SecretGroup, secret_fields: List[str], fields: List[str] - ) -> bool: - """Update the contents of an existing Juju Secret, referred in the relation databag.""" - secret = self._get_relation_secret(relation.id, group) - - if not secret: - logging.error("Can't delete secret for relation %s", str(relation.id)) - return False - - old_content = secret.get_content() - new_content = copy.deepcopy(old_content) - for field in fields: - try: - new_content.pop(field) - except KeyError: - logging.debug( - "Non-existing secret was attempted to be removed %s, %s", - str(relation.id), - str(field), - ) - return False - - # Remove secret from the relation if it's fully gone - if not new_content: - field = self._generate_secret_field_name(group) - try: - relation.data[self.component].pop(field) - except KeyError: - pass - label = self._generate_secret_label(self.relation_name, relation.id, group) - self.secrets.remove(label) - else: - secret.set_content(new_content) - - # Return the content that was removed - return True - - # Mandatory internal overrides - - @juju_secrets_only - def _get_relation_secret( - self, relation_id: int, group_mapping: SecretGroup, relation_name: Optional[str] = None - ) -> Optional[CachedSecret]: - """Retrieve a Juju Secret that's been stored in the relation databag.""" - if not relation_name: - relation_name = self.relation_name - - label = self._generate_secret_label(relation_name, relation_id, group_mapping) - if secret := self.secrets.get(label): - return secret - - relation = self._model.get_relation(relation_name, relation_id) - if not relation: - return - - if secret_uri := self.get_secret_uri(relation, group_mapping): - return self.secrets.get(label, secret_uri) - - def _fetch_specific_relation_data( - self, relation: Relation, fields: Optional[List[str]] - ) -> Dict[str, str]: - """Fetching relation data for Provider. - - NOTE: Since all secret fields are in the Provider side of the databag, we don't need to worry about that - """ - if not relation.app: - return {} - - return self._fetch_relation_data_without_secrets(relation.app, relation, fields) - - def _fetch_my_specific_relation_data( - self, relation: Relation, fields: Optional[List[str]] - ) -> dict: - """Fetching our own relation data.""" - secret_fields = None - if relation.app: - secret_fields = get_encoded_list(relation, relation.app, REQ_SECRET_FIELDS) - - return self._fetch_relation_data_with_secrets( - self.local_app, - secret_fields, - relation, - fields, - ) + self._local_secret_fields = [] + self._remote_secret_fields = list(self.SECRET_FIELDS) def _update_relation_data(self, relation: Relation, data: Dict[str, str]) -> None: """Set values for fields not caring whether it's a secret or not.""" - req_secret_fields = [] - keys = set(data.keys()) if self.fetch_relation_field(relation.id, self.RESOURCE_FIELD) is None and ( keys - {"endpoints", "read-only-endpoints", "replset"} @@ -1633,31 +1712,7 @@ def _update_relation_data(self, relation: Relation, data: Dict[str, str]) -> Non raise PrematureDataAccessError( "Premature access to relation data, update is forbidden before the connection is initialized." ) - - if relation.app: - req_secret_fields = get_encoded_list(relation, relation.app, REQ_SECRET_FIELDS) - - _, normal_fields = self._process_secret_fields( - relation, - req_secret_fields, - list(data), - self._add_or_update_relation_secrets, - data=data, - ) - - normal_content = {k: v for k, v in data.items() if k in normal_fields} - self._update_relation_data_without_secrets(self.local_app, relation, normal_content) - - def _delete_relation_data(self, relation: Relation, fields: List[str]) -> None: - """Delete fields from the Relation not caring whether it's a secret or not.""" - req_secret_fields = [] - if relation.app: - req_secret_fields = get_encoded_list(relation, relation.app, REQ_SECRET_FIELDS) - - _, normal_fields = self._process_secret_fields( - relation, req_secret_fields, fields, self._delete_relation_secret, fields=fields - ) - self._delete_relation_data_without_secrets(self.local_app, relation, list(normal_fields)) + super()._update_relation_data(relation, data) # Public methods - "native" @@ -1697,6 +1752,16 @@ def set_tls_ca(self, relation_id: int, tls_ca: str) -> None: fetch_my_relation_data = leader_only(Data.fetch_my_relation_data) fetch_my_relation_field = leader_only(Data.fetch_my_relation_field) + def _load_secrets_from_databag(self, relation: Relation) -> None: + """Load secrets from the databag.""" + requested_secrets = get_encoded_list(relation, relation.app, REQ_SECRET_FIELDS) + provided_secrets = get_encoded_list(relation, relation.app, PROV_SECRET_FIELDS) + if requested_secrets is not None: + self._local_secret_fields = requested_secrets + + if provided_secrets is not None: + self._remote_secret_fields = provided_secrets + class RequirerData(Data): """Requirer-side of the relation.""" @@ -1713,52 +1778,18 @@ def __init__( """Manager of base client relations.""" super().__init__(model, relation_name) self.extra_user_roles = extra_user_roles - self._secret_fields = list(self.SECRET_FIELDS) + self._remote_secret_fields = list(self.SECRET_FIELDS) + self._local_secret_fields = [ + field + for field in self.SECRET_LABEL_MAP.keys() + if field not in self._remote_secret_fields + ] if additional_secret_fields: - self._secret_fields += additional_secret_fields + self._remote_secret_fields += additional_secret_fields self.data_component = self.local_unit - @property - def secret_fields(self) -> Optional[List[str]]: - """Local access to secrets field, in case they are being used.""" - if self.secrets_enabled: - return self._secret_fields - # Internal helper functions - def _register_secret_to_relation( - self, relation_name: str, relation_id: int, secret_id: str, group: SecretGroup - ): - """Fetch secrets and apply local label on them. - - [MAGIC HERE] - If we fetch a secret using get_secret(id=, label=), - then will be "stuck" on the Secret object, whenever it may - appear (i.e. as an event attribute, or fetched manually) on future occasions. - - This will allow us to uniquely identify the secret on Provider side (typically on - 'secret-changed' events), and map it to the corresponding relation. - """ - label = self._generate_secret_label(relation_name, relation_id, group) - - # Fetching the Secret's meta information ensuring that it's locally getting registered with - CachedSecret(self._model, self.component, label, secret_id).meta - - def _register_secrets_to_relation(self, relation: Relation, params_name_list: List[str]): - """Make sure that secrets of the provided list are locally 'registered' from the databag. - - More on 'locally registered' magic is described in _register_secret_to_relation() method - """ - if not relation.app: - return - - for group in SECRET_GROUPS.groups(): - secret_field = self._generate_secret_field_name(group) - if secret_field in params_name_list and ( - secret_uri := self.get_secret_uri(relation, group) - ): - self._register_secret_to_relation(relation.name, relation.id, secret_uri, group) - def _is_resource_created_for_relation(self, relation: Relation) -> bool: if not relation.app: return False @@ -1769,16 +1800,6 @@ def _is_resource_created_for_relation(self, relation: Relation) -> bool: return bool(data.get("username")) and bool(data.get("password")) # Public functions - - def get_secret_uri(self, relation: Relation, group: SecretGroup) -> Optional[str]: - """Getting relation secret URI for the corresponding Secret Group.""" - secret_field = self._generate_secret_field_name(group) - return relation.data[relation.app].get(secret_field) - - def set_secret_uri(self, relation: Relation, group: SecretGroup, uri: str) -> None: - """Setting relation secret URI is not possible for a Requirer.""" - raise NotImplementedError("Requirer can not change the relation secret URI.") - def is_resource_created(self, relation_id: Optional[int] = None) -> bool: """Check if the resource has been created. @@ -1805,70 +1826,28 @@ def is_resource_created(self, relation_id: Optional[int] = None) -> bool: raise IndexError(f"relation id {relation_id} cannot be accessed") else: return ( - all( - self._is_resource_created_for_relation(relation) for relation in self.relations - ) - if self.relations - else False - ) - - # Mandatory internal overrides - - @juju_secrets_only - def _get_relation_secret( - self, relation_id: int, group: SecretGroup, relation_name: Optional[str] = None - ) -> Optional[CachedSecret]: - """Retrieve a Juju Secret that's been stored in the relation databag.""" - if not relation_name: - relation_name = self.relation_name - - label = self._generate_secret_label(relation_name, relation_id, group) - return self.secrets.get(label) - - def _fetch_specific_relation_data( - self, relation, fields: Optional[List[str]] = None - ) -> Dict[str, str]: - """Fetching Requirer data -- that may include secrets.""" - if not relation.app: - return {} - return self._fetch_relation_data_with_secrets( - relation.app, self.secret_fields, relation, fields - ) - - def _fetch_my_specific_relation_data(self, relation, fields: Optional[List[str]]) -> dict: - """Fetching our own relation data.""" - return self._fetch_relation_data_without_secrets(self.local_app, relation, fields) - - def _update_relation_data(self, relation: Relation, data: dict) -> None: - """Updates a set of key-value pairs in the relation. - - This function writes in the application data bag, therefore, - only the leader unit can call it. - - Args: - relation: the particular relation. - data: dict containing the key-value pairs - that should be updated in the relation. - """ - return self._update_relation_data_without_secrets(self.local_app, relation, data) - - def _delete_relation_data(self, relation: Relation, fields: List[str]) -> None: - """Deletes a set of fields from the relation. - - This function writes in the application data bag, therefore, - only the leader unit can call it. - - Args: - relation: the particular relation. - fields: list containing the field names that should be removed from the relation. - """ - return self._delete_relation_data_without_secrets(self.local_app, relation, fields) + all( + self._is_resource_created_for_relation(relation) for relation in self.relations + ) + if self.relations + else False + ) # Public functions -- inherited fetch_my_relation_data = leader_only(Data.fetch_my_relation_data) fetch_my_relation_field = leader_only(Data.fetch_my_relation_field) + def _load_secrets_from_databag(self, relation: Relation) -> None: + """Load secrets from the databag.""" + requested_secrets = get_encoded_list(relation, self.local_unit, REQ_SECRET_FIELDS) + provided_secrets = get_encoded_list(relation, self.local_unit, PROV_SECRET_FIELDS) + if requested_secrets: + self._remote_secret_fields = requested_secrets + + if provided_secrets: + self._local_secret_fields = provided_secrets + class RequirerEventHandlers(EventHandlers): """Requires-side of the relation.""" @@ -1877,15 +1856,6 @@ def __init__(self, charm: CharmBase, relation_data: RequirerData, unique_key: st """Manager of base client relations.""" super().__init__(charm, relation_data, unique_key) - self.framework.observe( - self.charm.on[relation_data.relation_name].relation_created, - self._on_relation_created_event, - ) - self.framework.observe( - charm.on.secret_changed, - self._on_secret_changed_event, - ) - # Event handlers def _on_relation_created_event(self, event: RelationCreatedEvent) -> None: @@ -1893,18 +1863,56 @@ def _on_relation_created_event(self, event: RelationCreatedEvent) -> None: if not self.relation_data.local_unit.is_leader(): return - if self.relation_data.secret_fields: # pyright: ignore [reportAttributeAccessIssue] + if self.relation_data.remote_secret_fields: + if self.relation_data.SCOPE == Scope.APP: + set_encoded_field( + event.relation, + self.relation_data.local_app, + REQ_SECRET_FIELDS, + self.relation_data.remote_secret_fields, + ) + set_encoded_field( event.relation, - self.relation_data.component, + self.relation_data.local_unit, REQ_SECRET_FIELDS, - self.relation_data.secret_fields, # pyright: ignore [reportAttributeAccessIssue] + self.relation_data.remote_secret_fields, ) - @abstractmethod - def _on_secret_changed_event(self, event: RelationChangedEvent) -> None: + if self.relation_data.local_secret_fields: + if self.relation_data.SCOPE == Scope.APP: + set_encoded_field( + event.relation, + self.relation_data.local_app, + PROV_SECRET_FIELDS, + self.relation_data.local_secret_fields, + ) + set_encoded_field( + event.relation, + self.relation_data.local_unit, + PROV_SECRET_FIELDS, + self.relation_data.local_secret_fields, + ) + + +class ProviderEventHandlers(EventHandlers): + """Provider-side of the relation.""" + + def __init__(self, charm: CharmBase, relation_data: ProviderData, unique_key: str = ""): + """Manager of base client relations.""" + super().__init__(charm, relation_data, unique_key) + + # Event handlers + + def _on_relation_changed_event(self, event: RelationChangedEvent) -> None: """Event emitted when the relation data has changed.""" - raise NotImplementedError + requested_secrets = get_encoded_list(event.relation, event.relation.app, REQ_SECRET_FIELDS) + provided_secrets = get_encoded_list(event.relation, event.relation.app, PROV_SECRET_FIELDS) + if requested_secrets is not None: + self.relation_data._local_secret_fields = requested_secrets + + if provided_secrets is not None: + self.relation_data._remote_secret_fields = provided_secrets ################################################################################ @@ -1955,7 +1963,7 @@ def __init__( secret_group = SECRET_GROUPS.get_group(group) internal_field = self._field_to_internal_name(field, secret_group) self._secret_label_map.setdefault(group, []).append(internal_field) - self._secret_fields.append(internal_field) + self._remote_secret_fields.append(internal_field) @property def scope(self) -> Optional[Scope]: @@ -1973,10 +1981,10 @@ def secret_label_map(self) -> Dict[str, str]: @property def static_secret_fields(self) -> List[str]: """Re-definition of the property in a way that dynamically extended list is retrieved.""" - return self._secret_fields + return self._remote_secret_fields @property - def secret_fields(self) -> List[str]: + def local_secret_fields(self) -> List[str]: """Re-definition of the property in a way that dynamically extended list is retrieved.""" return ( self.static_secret_fields if self.static_secret_fields else self.current_secret_fields @@ -1994,7 +2002,11 @@ def current_secret_fields(self) -> List[str]: relation = self._model.relations[self.relation_name][0] fields = [] - ignores = [SECRET_GROUPS.get_group("user"), SECRET_GROUPS.get_group("tls")] + ignores = [ + SECRET_GROUPS.get_group("user"), + SECRET_GROUPS.get_group("tls"), + SECRET_GROUPS.get_group("mtls"), + ] for group in SECRET_GROUPS.groups(): if group in ignores: continue @@ -2103,11 +2115,11 @@ def _content_for_secret_group( ) -> Dict[str, str]: """Select : pairs from input, that belong to this particular Secret group.""" if group_mapping == SECRET_GROUPS.EXTRA: - return {k: v for k, v in content.items() if k in self.secret_fields} + return {k: v for k, v in content.items() if k in self.local_secret_fields} return { self._internal_name_to_field(k)[0]: v for k, v in content.items() - if k in self.secret_fields + if k in self.local_secret_fields } def valid_field_pattern(self, field: str, full_field: str) -> bool: @@ -2122,6 +2134,16 @@ def valid_field_pattern(self, field: str, full_field: str) -> bool: return False return True + def _load_secrets_from_databag(self, relation: Relation) -> None: + """Load secrets from the databag.""" + requested_secrets = get_encoded_list(relation, self.component, REQ_SECRET_FIELDS) + provided_secrets = get_encoded_list(relation, self.component, PROV_SECRET_FIELDS) + if requested_secrets: + self._remote_secret_fields = requested_secrets + + if provided_secrets: + self._local_secret_fields = provided_secrets + ########################################################################## # Backwards compatibility / Upgrades ########################################################################## @@ -2177,7 +2199,7 @@ def _legacy_compat_check_deleted_label(self, relation, fields) -> None: if current_data is not None: # Check if the secret we wanna delete actually exists # Given the "deleted label", here we can't rely on the default mechanism (i.e. 'key not found') - if non_existent := (set(fields) & set(self.secret_fields)) - set( + if non_existent := (set(fields) & set(self.local_secret_fields)) - set( current_data.get(relation.id, []) ): logger.debug( @@ -2227,10 +2249,10 @@ def _legacy_migration_remove_secret_from_databag(self, relation, fields: List[st Practically what happens here is to remove stuff from the databag that is to be stored in secrets. """ - if not self.secret_fields: + if not self.local_secret_fields: return - secret_fields_passed = set(self.secret_fields) & set(fields) + secret_fields_passed = set(self.local_secret_fields) & set(fields) for field in secret_fields_passed: if self._fetch_relation_data_without_secrets(self.component, relation, [field]): self._delete_relation_data_without_secrets(self.component, relation, [field]) @@ -2342,15 +2364,17 @@ def _fetch_my_specific_relation_data( ) -> Dict[str, str]: """Fetch data available (directily or indirectly -- i.e. secrets) from the relation for owner/this_app.""" return self._fetch_relation_data_with_secrets( - self.component, self.secret_fields, relation, fields + self.component, self.local_secret_fields, relation, fields ) @either_static_or_dynamic_secrets def _update_relation_data(self, relation: Relation, data: Dict[str, str]) -> None: """Update data available (directily or indirectly -- i.e. secrets) from the relation for owner/this_app.""" + self._load_secrets_from_databag(relation) + _, normal_fields = self._process_secret_fields( relation, - self.secret_fields, + self.local_secret_fields, list(data), self._add_or_update_relation_secrets, data=data, @@ -2363,17 +2387,22 @@ def _update_relation_data(self, relation: Relation, data: Dict[str, str]) -> Non @either_static_or_dynamic_secrets def _delete_relation_data(self, relation: Relation, fields: List[str]) -> None: """Delete data available (directily or indirectly -- i.e. secrets) from the relation for owner/this_app.""" - if self.secret_fields and self.deleted_label: + self._load_secrets_from_databag(relation) + if self.local_secret_fields and self.deleted_label: _, normal_fields = self._process_secret_fields( relation, - self.secret_fields, + self.local_secret_fields, fields, self._update_relation_secret, data=dict.fromkeys(fields, self.deleted_label), ) else: _, normal_fields = self._process_secret_fields( - relation, self.secret_fields, fields, self._delete_relation_secret, fields=fields + relation, + self.local_secret_fields, + fields, + self._delete_relation_secret, + fields=fields, ) self._delete_relation_data_without_secrets(self.component, relation, list(normal_fields)) @@ -2896,7 +2925,7 @@ def set_subordinated(self, relation_id: int) -> None: self.update_relation_data(relation_id, {"subordinated": "true"}) -class DatabaseProviderEventHandlers(EventHandlers): +class DatabaseProviderEventHandlers(ProviderEventHandlers): """Provider-side of the database relation handlers.""" on = DatabaseProvidesEvents() # pyright: ignore [reportAssignmentType] @@ -2911,6 +2940,7 @@ def __init__( def _on_relation_changed_event(self, event: RelationChangedEvent) -> None: """Event emitted when the relation has changed.""" + super()._on_relation_changed_event(event) # Leader only if not self.relation_data.local_unit.is_leader(): return @@ -2924,6 +2954,10 @@ def _on_relation_changed_event(self, event: RelationChangedEvent) -> None: event.relation, app=event.app, unit=event.unit ) + def _on_secret_changed_event(self, event: SecretChangedEvent) -> None: + """Event emitted when the secret has changed.""" + pass + class DatabaseProvides(DatabaseProviderData, DatabaseProviderEventHandlers): """Provider-side of the database relations.""" @@ -3369,7 +3403,7 @@ def set_zookeeper_uris(self, relation_id: int, zookeeper_uris: str) -> None: self.update_relation_data(relation_id, {"zookeeper-uris": zookeeper_uris}) -class KafkaProviderEventHandlers(EventHandlers): +class KafkaProviderEventHandlers(ProviderEventHandlers): """Provider-side of the Kafka relation.""" on = KafkaProvidesEvents() # pyright: ignore [reportAssignmentType] @@ -3381,6 +3415,7 @@ def __init__(self, charm: CharmBase, relation_data: KafkaProviderData) -> None: def _on_relation_changed_event(self, event: RelationChangedEvent) -> None: """Event emitted when the relation has changed.""" + super()._on_relation_changed_event(event) # Leader only if not self.relation_data.local_unit.is_leader(): return @@ -3613,7 +3648,7 @@ def set_version(self, relation_id: int, version: str) -> None: self.update_relation_data(relation_id, {"version": version}) -class OpenSearchProvidesEventHandlers(EventHandlers): +class OpenSearchProvidesEventHandlers(ProviderEventHandlers): """Provider-side of the OpenSearch relation.""" on = OpenSearchProvidesEvents() # pyright: ignore[reportAssignmentType] @@ -3625,6 +3660,8 @@ def __init__(self, charm: CharmBase, relation_data: OpenSearchProvidesData) -> N def _on_relation_changed_event(self, event: RelationChangedEvent) -> None: """Event emitted when the relation has changed.""" + super()._on_relation_changed_event(event) + # Leader only if not self.relation_data.local_unit.is_leader(): return @@ -3778,3 +3815,320 @@ def __init__( additional_secret_fields, ) OpenSearchRequiresEventHandlers.__init__(self, charm, self) + + +# Etcd related events + + +class EtcdProviderEvent(RelationEventWithSecret): + """Base class for Etcd events.""" + + @property + def prefix(self) -> Optional[str]: + """Returns the index that was requested.""" + if not self.relation.app: + return None + + return self.relation.data[self.relation.app].get("prefix") + + @property + def mtls_cert(self) -> Optional[str]: + """Returns TLS cert of the client.""" + if not self.relation.app: + return None + + if not self.secrets_enabled: + raise SecretsUnavailableError("Secrets unavailable on current Juju version") + + secret_field = f"{PROV_SECRET_PREFIX}{SECRET_GROUPS.MTLS}" + if secret_uri := self.relation.data[self.app].get(secret_field): + secret = self.framework.model.get_secret(id=secret_uri) + content = secret.get_content(refresh=True) + if content: + return content.get("mtls-cert") + + +class MTLSCertUpdatedEvent(EtcdProviderEvent): + """Event emitted when the mtls relation is updated.""" + + def __init__(self, handle, relation, old_mtls_cert: Optional[str] = None, app=None, unit=None): + super().__init__(handle, relation, app, unit) + + self.old_mtls_cert = old_mtls_cert + + def snapshot(self): + """Return a snapshot of the event.""" + return super().snapshot() | {"old_mtls_cert": self.old_mtls_cert} + + def restore(self, snapshot): + """Restore the event from a snapshot.""" + super().restore(snapshot) + self.old_mtls_cert = snapshot["old_mtls_cert"] + + +class EtcdProviderEvents(CharmEvents): + """Etcd events. + + This class defines the events that Etcd can emit. + """ + + mtls_cert_updated = EventSource(MTLSCertUpdatedEvent) + + +class EtcdReadyEvent(AuthenticationEvent, DatabaseRequiresEvent): + """Event emitted when the etcd relation is ready to be consumed.""" + + +class EtcdRequirerEvents(CharmEvents): + """Etcd events. + + This class defines the events that the etcd requirer can emit. + """ + + endpoints_changed = EventSource(DatabaseEndpointsChangedEvent) + etcd_ready = EventSource(EtcdReadyEvent) + + +# Etcd Provides and Requires Objects + + +class EtcdProviderData(ProviderData): + """Provider-side of the Etcd relation.""" + + RESOURCE_FIELD = "prefix" + + def __init__(self, model: Model, relation_name: str) -> None: + super().__init__(model, relation_name) + + def set_uris(self, relation_id: int, uris: str) -> None: + """Set the database connection URIs in the application relation databag. + + Args: + relation_id: the identifier for a particular relation. + uris: connection URIs. + """ + self.update_relation_data(relation_id, {"uris": uris}) + + def set_endpoints(self, relation_id: int, endpoints: str) -> None: + """Set the endpoints in the application relation databag. + + Args: + relation_id: the identifier for a particular relation. + endpoints: the endpoint addresses for etcd nodes "ip:port" format. + """ + self.update_relation_data(relation_id, {"endpoints": endpoints}) + + def set_version(self, relation_id: int, version: str) -> None: + """Set the etcd version in the application relation databag. + + Args: + relation_id: the identifier for a particular relation. + version: etcd API version. + """ + self.update_relation_data(relation_id, {"version": version}) + + def set_tls_ca(self, relation_id: int, tls_ca: str) -> None: + """Set the TLS CA in the application relation databag. + + Args: + relation_id: the identifier for a particular relation. + tls_ca: TLS certification authority. + """ + self.update_relation_data(relation_id, {"tls-ca": tls_ca, "tls": "True"}) + + +class EtcdProviderEventHandlers(ProviderEventHandlers): + """Provider-side of the Etcd relation.""" + + on = EtcdProviderEvents() # pyright: ignore[reportAssignmentType] + + def __init__(self, charm: CharmBase, relation_data: EtcdProviderData) -> None: + super().__init__(charm, relation_data) + # Just to keep lint quiet, can't resolve inheritance. The same happened in super().__init__() above + self.relation_data = relation_data + + def _on_relation_changed_event(self, event: RelationChangedEvent) -> None: + """Event emitted when the relation has changed.""" + super()._on_relation_changed_event(event) + # register all new secrets with their labels + new_data_keys = list(event.relation.data[event.app].keys()) + if any(newval for newval in new_data_keys if self.relation_data._is_secret_field(newval)): + self.relation_data._register_secrets_to_relation(event.relation, new_data_keys) + + getattr(self.on, "mtls_cert_updated").emit(event.relation, app=event.app, unit=event.unit) + return + + def _on_secret_changed_event(self, event: SecretChangedEvent): + """Event notifying about a new value of a secret.""" + if not event.secret.label: + return + + relation = self.relation_data._relation_from_secret_label(event.secret.label) + if not relation: + logging.info( + f"Received secret {event.secret.label} but couldn't parse, seems irrelevant" + ) + return + + if relation.app == self.charm.app: + logging.info("Secret changed event ignored for Secret Owner") + + remote_unit = None + for unit in relation.units: + if unit.app != self.charm.app: + remote_unit = unit + + old_mtls_cert = event.secret.get_content().get("mtls-cert") + # mtls-cert is the only secret that can be updated + logger.info("mtls-cert updated") + getattr(self.on, "mtls_cert_updated").emit( + relation, app=relation.app, unit=remote_unit, old_mtls_cert=old_mtls_cert + ) + + +class EtcdProvides(EtcdProviderData, EtcdProviderEventHandlers): + """Provider-side of the Etcd relation.""" + + def __init__(self, charm: CharmBase, relation_name: str) -> None: + EtcdProviderData.__init__(self, charm.model, relation_name) + EtcdProviderEventHandlers.__init__(self, charm, self) + if not self.secrets_enabled: + raise SecretsUnavailableError("Secrets unavailable on current Juju version") + + +class EtcdRequirerData(RequirerData): + """Requires data side of the Etcd relation.""" + + def __init__( + self, + model: Model, + relation_name: str, + prefix: str, + mtls_cert: Optional[str], + extra_user_roles: Optional[str] = None, + additional_secret_fields: Optional[List[str]] = [], + ): + """Manager of Etcd client relations.""" + super().__init__(model, relation_name, extra_user_roles, additional_secret_fields) + self.prefix = prefix + self.mtls_cert = mtls_cert + + def set_mtls_cert(self, relation_id: int, mtls_cert: str) -> None: + """Set the mtls cert in the application relation databag / secret. + + Args: + relation_id: the identifier for a particular relation. + mtls_cert: mtls cert. + """ + self.update_relation_data(relation_id, {"mtls-cert": mtls_cert}) + + +class EtcdRequirerEventHandlers(RequirerEventHandlers): + """Requires events side of the Etcd relation.""" + + on = EtcdRequirerEvents() # pyright: ignore[reportAssignmentType] + + def __init__(self, charm: CharmBase, relation_data: EtcdRequirerData) -> None: + super().__init__(charm, relation_data) + # Just to keep lint quiet, can't resolve inheritance. The same happened in super().__init__() above + self.relation_data = relation_data + + def _on_relation_created_event(self, event: RelationCreatedEvent) -> None: + """Event emitted when the Etcd relation is created.""" + super()._on_relation_created_event(event) + + payload = { + "prefix": self.relation_data.prefix, + } + if self.relation_data.mtls_cert: + payload["mtls-cert"] = self.relation_data.mtls_cert + + self.relation_data.update_relation_data( + event.relation.id, + payload, + ) + + def _on_relation_changed_event(self, event: RelationChangedEvent) -> None: + """Event emitted when the Etcd relation has changed. + + This event triggers individual custom events depending on the changing relation. + """ + # Check which data has changed to emit customs events. + diff = self._diff(event) + # Register all new secrets with their labels + if any(newval for newval in diff.added if self.relation_data._is_secret_field(newval)): + self.relation_data._register_secrets_to_relation(event.relation, diff.added) + + secret_field_user = self.relation_data._generate_secret_field_name(SECRET_GROUPS.USER) + secret_field_tls = self.relation_data._generate_secret_field_name(SECRET_GROUPS.TLS) + + # Emit a endpoints changed event if the etcd application added or changed this info + # in the relation databag. + if "endpoints" in diff.added or "endpoints" in diff.changed: + # Emit the default event (the one without an alias). + logger.info("endpoints changed on %s", datetime.now()) + getattr(self.on, "endpoints_changed").emit( + event.relation, app=event.app, unit=event.unit + ) + + if ( + secret_field_tls in diff.added + or secret_field_tls in diff.changed + or secret_field_user in diff.added + or secret_field_user in diff.changed + or "username" in diff.added + or "username" in diff.changed + ): + # Emit the default event (the one without an alias). + logger.info("etcd ready on %s", datetime.now()) + getattr(self.on, "etcd_ready").emit(event.relation, app=event.app, unit=event.unit) + + def _on_secret_changed_event(self, event: SecretChangedEvent): + """Event notifying about a new value of a secret.""" + if not event.secret.label: + return + + relation = self.relation_data._relation_from_secret_label(event.secret.label) + if not relation: + logging.info( + f"Received secret {event.secret.label} but couldn't parse, seems irrelevant" + ) + return + + if relation.app == self.charm.app: + logging.info("Secret changed event ignored for Secret Owner") + + remote_unit = None + for unit in relation.units: + if unit.app != self.charm.app: + remote_unit = unit + + # secret-user or secret-tls updated + logger.info("etcd_ready updated") + getattr(self.on, "etcd_ready").emit(relation, app=relation.app, unit=remote_unit) + + +class EtcdRequires(EtcdRequirerData, EtcdRequirerEventHandlers): + """Requires-side of the Etcd relation.""" + + def __init__( + self, + charm: CharmBase, + relation_name: str, + prefix: str, + mtls_cert: Optional[str], + extra_user_roles: Optional[str] = None, + additional_secret_fields: Optional[List[str]] = [], + ) -> None: + EtcdRequirerData.__init__( + self, + charm.model, + relation_name, + prefix, + mtls_cert, + extra_user_roles, + additional_secret_fields, + ) + EtcdRequirerEventHandlers.__init__(self, charm, self) + if not self.secrets_enabled: + raise SecretsUnavailableError("Secrets unavailable on current Juju version") diff --git a/lib/charms/postgresql_k8s/v0/postgresql.py b/lib/charms/postgresql_k8s/v0/postgresql.py index b7eb90908b..7e6a9d7631 100644 --- a/lib/charms/postgresql_k8s/v0/postgresql.py +++ b/lib/charms/postgresql_k8s/v0/postgresql.py @@ -35,7 +35,7 @@ # Increment this PATCH version before using `charmcraft publish-lib` or reset # to 0 if you are raising the major API version -LIBPATCH = 49 +LIBPATCH = 51 # Groups to distinguish HBA access ACCESS_GROUP_IDENTITY = "identity_access" @@ -153,7 +153,7 @@ def _configure_pgaudit(self, enable: bool) -> None: if enable: cursor.execute("ALTER SYSTEM SET pgaudit.log = 'ROLE,DDL,MISC,MISC_SET';") cursor.execute("ALTER SYSTEM SET pgaudit.log_client TO off;") - cursor.execute("ALTER SYSTEM SET pgaudit.log_parameter TO off") + cursor.execute("ALTER SYSTEM SET pgaudit.log_parameter TO off;") else: cursor.execute("ALTER SYSTEM RESET pgaudit.log;") cursor.execute("ALTER SYSTEM RESET pgaudit.log_client;") @@ -258,7 +258,7 @@ def create_database( raise PostgreSQLCreateDatabaseError() from e # Enable preset extensions - self.enable_disable_extensions({plugin: True for plugin in plugins}, database) + self.enable_disable_extensions(dict.fromkeys(plugins, True), database) def create_user( self, @@ -435,6 +435,8 @@ def enable_disable_extensions( for extension, enable in extensions.items(): ordered_extensions[extension] = enable + self._configure_pgaudit(False) + # Enable/disabled the extension in each database. for database in databases: with self._connect_to_database( From 26923b1cb82e5cc69764a2f72f82b35900b23041 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 23 Apr 2025 15:21:44 +0300 Subject: [PATCH 021/112] Lock file maintenance Python dependencies (main) (#816) * Lock file maintenance Python dependencies * Fix linting --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Dragomir Penev --- poetry.lock | 964 ++++++++++++++++++++----------------- pyproject.toml | 22 +- src/charm.py | 9 +- src/cluster.py | 3 +- src/rotate_logs.py | 3 +- tests/unit/test_backups.py | 2 +- tests/unit/test_charm.py | 6 +- 7 files changed, 553 insertions(+), 456 deletions(-) diff --git a/poetry.lock b/poetry.lock index c70ec34a9b..497df5734d 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2,18 +2,18 @@ [[package]] name = "allure-pytest" -version = "2.13.5" +version = "2.14.0" description = "Allure pytest integration" optional = false python-versions = "*" groups = ["integration"] files = [ - {file = "allure-pytest-2.13.5.tar.gz", hash = "sha256:0ef8e1790c44a988db6b83c4d4f5e91451e2c4c8ea10601dfa88528d23afcf6e"}, - {file = "allure_pytest-2.13.5-py3-none-any.whl", hash = "sha256:94130bac32964b78058e62cf4b815ad97a5ac82a065e6dd2d43abac2be7640fc"}, + {file = "allure_pytest-2.14.0-py3-none-any.whl", hash = "sha256:6ddb68ef42bd5a2dfbcc136a184bf3e78e631ede7b8c54750026ffd407bda9af"}, + {file = "allure_pytest-2.14.0.tar.gz", hash = "sha256:2b485dc307755f8f3207783a69558ca1cc72f1e2c97bedc65c93fdb77adf328f"}, ] [package.dependencies] -allure-python-commons = "2.13.5" +allure-python-commons = "2.14.0" pytest = ">=4.5.0" [[package]] @@ -34,14 +34,14 @@ pytest = "*" [[package]] name = "allure-python-commons" -version = "2.13.5" -description = "('Contains the API for end users as well as helper functions and classes to build Allure adapters for Python test frameworks',)" +version = "2.14.0" +description = "Contains the API for end users as well as helper functions and classes to build Allure adapters for Python test frameworks" optional = false python-versions = ">=3.6" groups = ["integration"] files = [ - {file = "allure-python-commons-2.13.5.tar.gz", hash = "sha256:a232e7955811f988e49a4c1dd6c16cce7e9b81d0ea0422b1e5654d3254e2caf3"}, - {file = "allure_python_commons-2.13.5-py3-none-any.whl", hash = "sha256:8b0e837b6e32d810adec563f49e1d04127a5b6770e0232065b7cb09b9953980d"}, + {file = "allure_python_commons-2.14.0-py3-none-any.whl", hash = "sha256:9200f40abee697133e9ed9f68887cde996a24b9eb33fcf528da8fe50fae88e43"}, + {file = "allure_python_commons-2.14.0.tar.gz", hash = "sha256:9b217e2f6c74cdbd0e253f89059d4165346e95fcb28228fae333ff4dccea0bd5"}, ] [package.dependencies] @@ -50,14 +50,14 @@ pluggy = ">=0.4.0" [[package]] name = "anyio" -version = "4.8.0" +version = "4.9.0" description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = false python-versions = ">=3.9" groups = ["charm-libs"] files = [ - {file = "anyio-4.8.0-py3-none-any.whl", hash = "sha256:b5011f270ab5eb0abf13385f851315585cc37ef330dd88e27ec3d34d651fd47a"}, - {file = "anyio-4.8.0.tar.gz", hash = "sha256:1d9fe889df5212298c0c0723fa20479d1b94883a2df44bd3897aa91083316f7a"}, + {file = "anyio-4.9.0-py3-none-any.whl", hash = "sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c"}, + {file = "anyio-4.9.0.tar.gz", hash = "sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028"}, ] [package.dependencies] @@ -67,8 +67,8 @@ sniffio = ">=1.1" typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""} [package.extras] -doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx_rtd_theme"] -test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "trustme", "truststore (>=0.9.1) ; python_version >= \"3.10\"", "uvloop (>=0.21) ; platform_python_implementation == \"CPython\" and platform_system != \"Windows\" and python_version < \"3.14\""] +doc = ["Sphinx (>=8.2,<9.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx_rtd_theme"] +test = ["anyio[trio]", "blockbuster (>=1.5.23)", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "trustme", "truststore (>=0.9.1) ; python_version >= \"3.10\"", "uvloop (>=0.21) ; platform_python_implementation == \"CPython\" and platform_system != \"Windows\" and python_version < \"3.14\""] trio = ["trio (>=0.26.1)"] [[package]] @@ -89,21 +89,21 @@ test = ["astroid (>=2,<4)", "pytest", "pytest-cov", "pytest-xdist"] [[package]] name = "attrs" -version = "25.1.0" +version = "25.3.0" description = "Classes Without Boilerplate" optional = false python-versions = ">=3.8" groups = ["charm-libs", "integration", "unit"] files = [ - {file = "attrs-25.1.0-py3-none-any.whl", hash = "sha256:c75a69e28a550a7e93789579c22aa26b0f5b83b75dc4e08fe092980051e1090a"}, - {file = "attrs-25.1.0.tar.gz", hash = "sha256:1c97078a80c814273a76b2a298a932eb681c87415c11dee0a6921de7f1b02c3e"}, + {file = "attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3"}, + {file = "attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b"}, ] [package.extras] benchmark = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] cov = ["cloudpickle ; platform_python_implementation == \"CPython\"", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] dev = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pre-commit-uv", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] -docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"] +docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier"] tests = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] tests-mypy = ["mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\""] @@ -119,6 +119,63 @@ files = [ {file = "backoff-2.2.1.tar.gz", hash = "sha256:03f829f5bb1923180821643f8753b0502c3b682293992485b0eef2807afa5cba"}, ] +[[package]] +name = "backports-datetime-fromisoformat" +version = "2.0.3" +description = "Backport of Python 3.11's datetime.fromisoformat" +optional = false +python-versions = ">3" +groups = ["integration"] +files = [ + {file = "backports_datetime_fromisoformat-2.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5f681f638f10588fa3c101ee9ae2b63d3734713202ddfcfb6ec6cea0778a29d4"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:cd681460e9142f1249408e5aee6d178c6d89b49e06d44913c8fdfb6defda8d1c"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:ee68bc8735ae5058695b76d3bb2aee1d137c052a11c8303f1e966aa23b72b65b"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8273fe7932db65d952a43e238318966eab9e49e8dd546550a41df12175cc2be4"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39d57ea50aa5a524bb239688adc1d1d824c31b6094ebd39aa164d6cadb85de22"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ac6272f87693e78209dc72e84cf9ab58052027733cd0721c55356d3c881791cf"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:44c497a71f80cd2bcfc26faae8857cf8e79388e3d5fbf79d2354b8c360547d58"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:6335a4c9e8af329cb1ded5ab41a666e1448116161905a94e054f205aa6d263bc"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e2e4b66e017253cdbe5a1de49e0eecff3f66cd72bcb1229d7db6e6b1832c0443"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:43e2d648e150777e13bbc2549cc960373e37bf65bd8a5d2e0cef40e16e5d8dd0"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp311-cp311-macosx_11_0_x86_64.whl", hash = "sha256:4ce6326fd86d5bae37813c7bf1543bae9e4c215ec6f5afe4c518be2635e2e005"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7c8fac333bf860208fd522a5394369ee3c790d0aa4311f515fcc4b6c5ef8d75"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24a4da5ab3aa0cc293dc0662a0c6d1da1a011dc1edcbc3122a288cfed13a0b45"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:58ea11e3bf912bd0a36b0519eae2c5b560b3cb972ea756e66b73fb9be460af01"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8a375c7dbee4734318714a799b6c697223e4bbb57232af37fbfff88fb48a14c6"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:ac677b1664c4585c2e014739f6678137c8336815406052349c85898206ec7061"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:66ce47ee1ba91e146149cf40565c3d750ea1be94faf660ca733d8601e0848147"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:8b7e069910a66b3bba61df35b5f879e5253ff0821a70375b9daf06444d046fa4"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp312-cp312-macosx_11_0_x86_64.whl", hash = "sha256:a3b5d1d04a9e0f7b15aa1e647c750631a873b298cdd1255687bb68779fe8eb35"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec1b95986430e789c076610aea704db20874f0781b8624f648ca9fb6ef67c6e1"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffe5f793db59e2f1d45ec35a1cf51404fdd69df9f6952a0c87c3060af4c00e32"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:620e8e73bd2595dfff1b4d256a12b67fce90ece3de87b38e1dde46b910f46f4d"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4cf9c0a985d68476c1cabd6385c691201dda2337d7453fb4da9679ce9f23f4e7"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:d144868a73002e6e2e6fef72333e7b0129cecdd121aa8f1edba7107fd067255d"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e81b26497a17c29595bc7df20bc6a872ceea5f8c9d6537283945d4b6396aec10"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:5ba00ead8d9d82fd6123eb4891c566d30a293454e54e32ff7ead7644f5f7e575"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:24d574cb4072e1640b00864e94c4c89858033936ece3fc0e1c6f7179f120d0a8"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9735695a66aad654500b0193525e590c693ab3368478ce07b34b443a1ea5e824"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63d39709e17eb72685d052ac82acf0763e047f57c86af1b791505b1fec96915d"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:1ea2cc84224937d6b9b4c07f5cb7c667f2bde28c255645ba27f8a675a7af8234"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:4024e6d35a9fdc1b3fd6ac7a673bd16cb176c7e0b952af6428b7129a70f72cce"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:5e2dcc94dc9c9ab8704409d86fcb5236316e9dcef6feed8162287634e3568f4c"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fa2de871801d824c255fac7e5e7e50f2be6c9c376fd9268b40c54b5e9da91f42"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:1314d4923c1509aa9696712a7bc0c7160d3b7acf72adafbbe6c558d523f5d491"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:b750ecba3a8815ad8bc48311552f3f8ab99dd2326d29df7ff670d9c49321f48f"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2d5117dce805d8a2f78baeddc8c6127281fa0a5e2c40c6dd992ba6b2b367876"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb35f607bd1cbe37b896379d5f5ed4dc298b536f4b959cb63180e05cacc0539d"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:61c74710900602637d2d145dda9720c94e303380803bf68811b2a151deec75c2"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:ece59af54ebf67ecbfbbf3ca9066f5687879e36527ad69d8b6e3ac565d565a62"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:d0a7c5f875068efe106f62233bc712d50db4d07c13c7db570175c7857a7b5dbd"}, + {file = "backports_datetime_fromisoformat-2.0.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:90e202e72a3d5aae673fcc8c9a4267d56b2f532beeb9173361293625fe4d2039"}, + {file = "backports_datetime_fromisoformat-2.0.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2df98ef1b76f5a58bb493dda552259ba60c3a37557d848e039524203951c9f06"}, + {file = "backports_datetime_fromisoformat-2.0.3-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7100adcda5e818b5a894ad0626e38118bb896a347f40ebed8981155675b9ba7b"}, + {file = "backports_datetime_fromisoformat-2.0.3-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e410383f5d6a449a529d074e88af8bc80020bb42b402265f9c02c8358c11da5"}, + {file = "backports_datetime_fromisoformat-2.0.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2797593760da6bcc32c4a13fa825af183cd4bfd333c60b3dbf84711afca26ef"}, + {file = "backports_datetime_fromisoformat-2.0.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35a144fd681a0bea1013ccc4cd3fd4dc758ea17ee23dca019c02b82ec46fc0c4"}, + {file = "backports_datetime_fromisoformat-2.0.3.tar.gz", hash = "sha256:b58edc8f517b66b397abc250ecc737969486703a66eb97e01e6d51291b1a139d"}, +] + [[package]] name = "backports-strenum" version = "1.3.1" @@ -134,37 +191,63 @@ files = [ [[package]] name = "bcrypt" -version = "4.2.1" +version = "4.3.0" description = "Modern password hashing for your software and your servers" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" groups = ["integration"] files = [ - {file = "bcrypt-4.2.1-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:1340411a0894b7d3ef562fb233e4b6ed58add185228650942bdc885362f32c17"}, - {file = "bcrypt-4.2.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1ee315739bc8387aa36ff127afc99120ee452924e0df517a8f3e4c0187a0f5f"}, - {file = "bcrypt-4.2.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8dbd0747208912b1e4ce730c6725cb56c07ac734b3629b60d4398f082ea718ad"}, - {file = "bcrypt-4.2.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:aaa2e285be097050dba798d537b6efd9b698aa88eef52ec98d23dcd6d7cf6fea"}, - {file = "bcrypt-4.2.1-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:76d3e352b32f4eeb34703370e370997065d28a561e4a18afe4fef07249cb4396"}, - {file = "bcrypt-4.2.1-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:b7703ede632dc945ed1172d6f24e9f30f27b1b1a067f32f68bf169c5f08d0425"}, - {file = "bcrypt-4.2.1-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:89df2aea2c43be1e1fa066df5f86c8ce822ab70a30e4c210968669565c0f4685"}, - {file = "bcrypt-4.2.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:04e56e3fe8308a88b77e0afd20bec516f74aecf391cdd6e374f15cbed32783d6"}, - {file = "bcrypt-4.2.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:cfdf3d7530c790432046c40cda41dfee8c83e29482e6a604f8930b9930e94139"}, - {file = "bcrypt-4.2.1-cp37-abi3-win32.whl", hash = "sha256:adadd36274510a01f33e6dc08f5824b97c9580583bd4487c564fc4617b328005"}, - {file = "bcrypt-4.2.1-cp37-abi3-win_amd64.whl", hash = "sha256:8c458cd103e6c5d1d85cf600e546a639f234964d0228909d8f8dbeebff82d526"}, - {file = "bcrypt-4.2.1-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:8ad2f4528cbf0febe80e5a3a57d7a74e6635e41af1ea5675282a33d769fba413"}, - {file = "bcrypt-4.2.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:909faa1027900f2252a9ca5dfebd25fc0ef1417943824783d1c8418dd7d6df4a"}, - {file = "bcrypt-4.2.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cde78d385d5e93ece5479a0a87f73cd6fa26b171c786a884f955e165032b262c"}, - {file = "bcrypt-4.2.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:533e7f3bcf2f07caee7ad98124fab7499cb3333ba2274f7a36cf1daee7409d99"}, - {file = "bcrypt-4.2.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:687cf30e6681eeda39548a93ce9bfbb300e48b4d445a43db4298d2474d2a1e54"}, - {file = "bcrypt-4.2.1-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:041fa0155c9004eb98a232d54da05c0b41d4b8e66b6fc3cb71b4b3f6144ba837"}, - {file = "bcrypt-4.2.1-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:f85b1ffa09240c89aa2e1ae9f3b1c687104f7b2b9d2098da4e923f1b7082d331"}, - {file = "bcrypt-4.2.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c6f5fa3775966cca251848d4d5393ab016b3afed251163c1436fefdec3b02c84"}, - {file = "bcrypt-4.2.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:807261df60a8b1ccd13e6599c779014a362ae4e795f5c59747f60208daddd96d"}, - {file = "bcrypt-4.2.1-cp39-abi3-win32.whl", hash = "sha256:b588af02b89d9fad33e5f98f7838bf590d6d692df7153647724a7f20c186f6bf"}, - {file = "bcrypt-4.2.1-cp39-abi3-win_amd64.whl", hash = "sha256:e84e0e6f8e40a242b11bce56c313edc2be121cec3e0ec2d76fce01f6af33c07c"}, - {file = "bcrypt-4.2.1-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:76132c176a6d9953cdc83c296aeaed65e1a708485fd55abf163e0d9f8f16ce0e"}, - {file = "bcrypt-4.2.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e158009a54c4c8bc91d5e0da80920d048f918c61a581f0a63e4e93bb556d362f"}, - {file = "bcrypt-4.2.1.tar.gz", hash = "sha256:6765386e3ab87f569b276988742039baab087b2cdb01e809d74e74503c2faafe"}, + {file = "bcrypt-4.3.0-cp313-cp313t-macosx_10_12_universal2.whl", hash = "sha256:f01e060f14b6b57bbb72fc5b4a83ac21c443c9a2ee708e04a10e9192f90a6281"}, + {file = "bcrypt-4.3.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5eeac541cefd0bb887a371ef73c62c3cd78535e4887b310626036a7c0a817bb"}, + {file = "bcrypt-4.3.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59e1aa0e2cd871b08ca146ed08445038f42ff75968c7ae50d2fdd7860ade2180"}, + {file = "bcrypt-4.3.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:0042b2e342e9ae3d2ed22727c1262f76cc4f345683b5c1715f0250cf4277294f"}, + {file = "bcrypt-4.3.0-cp313-cp313t-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74a8d21a09f5e025a9a23e7c0fd2c7fe8e7503e4d356c0a2c1486ba010619f09"}, + {file = "bcrypt-4.3.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:0142b2cb84a009f8452c8c5a33ace5e3dfec4159e7735f5afe9a4d50a8ea722d"}, + {file = "bcrypt-4.3.0-cp313-cp313t-manylinux_2_34_aarch64.whl", hash = "sha256:12fa6ce40cde3f0b899729dbd7d5e8811cb892d31b6f7d0334a1f37748b789fd"}, + {file = "bcrypt-4.3.0-cp313-cp313t-manylinux_2_34_x86_64.whl", hash = "sha256:5bd3cca1f2aa5dbcf39e2aa13dd094ea181f48959e1071265de49cc2b82525af"}, + {file = "bcrypt-4.3.0-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:335a420cfd63fc5bc27308e929bee231c15c85cc4c496610ffb17923abf7f231"}, + {file = "bcrypt-4.3.0-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:0e30e5e67aed0187a1764911af023043b4542e70a7461ad20e837e94d23e1d6c"}, + {file = "bcrypt-4.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:3b8d62290ebefd49ee0b3ce7500f5dbdcf13b81402c05f6dafab9a1e1b27212f"}, + {file = "bcrypt-4.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2ef6630e0ec01376f59a006dc72918b1bf436c3b571b80fa1968d775fa02fe7d"}, + {file = "bcrypt-4.3.0-cp313-cp313t-win32.whl", hash = "sha256:7a4be4cbf241afee43f1c3969b9103a41b40bcb3a3f467ab19f891d9bc4642e4"}, + {file = "bcrypt-4.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5c1949bf259a388863ced887c7861da1df681cb2388645766c89fdfd9004c669"}, + {file = "bcrypt-4.3.0-cp38-abi3-macosx_10_12_universal2.whl", hash = "sha256:f81b0ed2639568bf14749112298f9e4e2b28853dab50a8b357e31798686a036d"}, + {file = "bcrypt-4.3.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:864f8f19adbe13b7de11ba15d85d4a428c7e2f344bac110f667676a0ff84924b"}, + {file = "bcrypt-4.3.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3e36506d001e93bffe59754397572f21bb5dc7c83f54454c990c74a468cd589e"}, + {file = "bcrypt-4.3.0-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:842d08d75d9fe9fb94b18b071090220697f9f184d4547179b60734846461ed59"}, + {file = "bcrypt-4.3.0-cp38-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7c03296b85cb87db865d91da79bf63d5609284fc0cab9472fdd8367bbd830753"}, + {file = "bcrypt-4.3.0-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:62f26585e8b219cdc909b6a0069efc5e4267e25d4a3770a364ac58024f62a761"}, + {file = "bcrypt-4.3.0-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:beeefe437218a65322fbd0069eb437e7c98137e08f22c4660ac2dc795c31f8bb"}, + {file = "bcrypt-4.3.0-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:97eea7408db3a5bcce4a55d13245ab3fa566e23b4c67cd227062bb49e26c585d"}, + {file = "bcrypt-4.3.0-cp38-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:191354ebfe305e84f344c5964c7cd5f924a3bfc5d405c75ad07f232b6dffb49f"}, + {file = "bcrypt-4.3.0-cp38-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:41261d64150858eeb5ff43c753c4b216991e0ae16614a308a15d909503617732"}, + {file = "bcrypt-4.3.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:33752b1ba962ee793fa2b6321404bf20011fe45b9afd2a842139de3011898fef"}, + {file = "bcrypt-4.3.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:50e6e80a4bfd23a25f5c05b90167c19030cf9f87930f7cb2eacb99f45d1c3304"}, + {file = "bcrypt-4.3.0-cp38-abi3-win32.whl", hash = "sha256:67a561c4d9fb9465ec866177e7aebcad08fe23aaf6fbd692a6fab69088abfc51"}, + {file = "bcrypt-4.3.0-cp38-abi3-win_amd64.whl", hash = "sha256:584027857bc2843772114717a7490a37f68da563b3620f78a849bcb54dc11e62"}, + {file = "bcrypt-4.3.0-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:0d3efb1157edebfd9128e4e46e2ac1a64e0c1fe46fb023158a407c7892b0f8c3"}, + {file = "bcrypt-4.3.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:08bacc884fd302b611226c01014eca277d48f0a05187666bca23aac0dad6fe24"}, + {file = "bcrypt-4.3.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6746e6fec103fcd509b96bacdfdaa2fbde9a553245dbada284435173a6f1aef"}, + {file = "bcrypt-4.3.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:afe327968aaf13fc143a56a3360cb27d4ad0345e34da12c7290f1b00b8fe9a8b"}, + {file = "bcrypt-4.3.0-cp39-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d9af79d322e735b1fc33404b5765108ae0ff232d4b54666d46730f8ac1a43676"}, + {file = "bcrypt-4.3.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f1e3ffa1365e8702dc48c8b360fef8d7afeca482809c5e45e653af82ccd088c1"}, + {file = "bcrypt-4.3.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:3004df1b323d10021fda07a813fd33e0fd57bef0e9a480bb143877f6cba996fe"}, + {file = "bcrypt-4.3.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:531457e5c839d8caea9b589a1bcfe3756b0547d7814e9ce3d437f17da75c32b0"}, + {file = "bcrypt-4.3.0-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:17a854d9a7a476a89dcef6c8bd119ad23e0f82557afbd2c442777a16408e614f"}, + {file = "bcrypt-4.3.0-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:6fb1fd3ab08c0cbc6826a2e0447610c6f09e983a281b919ed721ad32236b8b23"}, + {file = "bcrypt-4.3.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e965a9c1e9a393b8005031ff52583cedc15b7884fce7deb8b0346388837d6cfe"}, + {file = "bcrypt-4.3.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:79e70b8342a33b52b55d93b3a59223a844962bef479f6a0ea318ebbcadf71505"}, + {file = "bcrypt-4.3.0-cp39-abi3-win32.whl", hash = "sha256:b4d4e57f0a63fd0b358eb765063ff661328f69a04494427265950c71b992a39a"}, + {file = "bcrypt-4.3.0-cp39-abi3-win_amd64.whl", hash = "sha256:e53e074b120f2877a35cc6c736b8eb161377caae8925c17688bd46ba56daaa5b"}, + {file = "bcrypt-4.3.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c950d682f0952bafcceaf709761da0a32a942272fad381081b51096ffa46cea1"}, + {file = "bcrypt-4.3.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:107d53b5c67e0bbc3f03ebf5b030e0403d24dda980f8e244795335ba7b4a027d"}, + {file = "bcrypt-4.3.0-pp310-pypy310_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:b693dbb82b3c27a1604a3dff5bfc5418a7e6a781bb795288141e5f80cf3a3492"}, + {file = "bcrypt-4.3.0-pp310-pypy310_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:b6354d3760fcd31994a14c89659dee887f1351a06e5dac3c1142307172a79f90"}, + {file = "bcrypt-4.3.0-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:a839320bf27d474e52ef8cb16449bb2ce0ba03ca9f44daba6d93fa1d8828e48a"}, + {file = "bcrypt-4.3.0-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:bdc6a24e754a555d7316fa4774e64c6c3997d27ed2d1964d55920c7c227bc4ce"}, + {file = "bcrypt-4.3.0-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:55a935b8e9a1d2def0626c4269db3fcd26728cbff1e84f0341465c31c4ee56d8"}, + {file = "bcrypt-4.3.0-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:57967b7a28d855313a963aaea51bf6df89f833db4320da458e5b3c5ab6d4c938"}, + {file = "bcrypt-4.3.0.tar.gz", hash = "sha256:3a3fd2204178b6d2adcf09cb4f6426ffef54762577a7c9b54c159008cb288c18"}, ] [package.extras] @@ -173,34 +256,34 @@ typecheck = ["mypy"] [[package]] name = "boto3" -version = "1.37.22" +version = "1.38.0" description = "The AWS SDK for Python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main", "integration"] files = [ - {file = "boto3-1.37.22-py3-none-any.whl", hash = "sha256:a14324d5fa5f4fea00c0e3c69754cbd28100f7fe194693eeecf2dc07446cf4ef"}, - {file = "boto3-1.37.22.tar.gz", hash = "sha256:78a0ec0aafbf6044104c98ad80b69e6d1c83d8233fda2c2d241029e6c705c510"}, + {file = "boto3-1.38.0-py3-none-any.whl", hash = "sha256:96898facb164b47859d40a4271007824a0a791c3811a7079ce52459d753d4474"}, + {file = "boto3-1.38.0.tar.gz", hash = "sha256:8b6544eca17e31d1bfd538e5d152b96a68d6c92950352a0cd9679f89d217d53a"}, ] [package.dependencies] -botocore = ">=1.37.22,<1.38.0" +botocore = ">=1.38.0,<1.39.0" jmespath = ">=0.7.1,<2.0.0" -s3transfer = ">=0.11.0,<0.12.0" +s3transfer = ">=0.12.0,<0.13.0" [package.extras] crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.37.22" +version = "1.38.0" description = "Low-level, data-driven core of boto 3." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main", "integration"] files = [ - {file = "botocore-1.37.22-py3-none-any.whl", hash = "sha256:184db7c9314d13002bc827f511a5140574b5da1acda342d51e093dad6317de98"}, - {file = "botocore-1.37.22.tar.gz", hash = "sha256:b3b26f1a90236bcd17d4092f8c85a256b44e9955a16b633319a2f5678d605e9f"}, + {file = "botocore-1.38.0-py3-none-any.whl", hash = "sha256:f9d58404796a44746d54c4a9318a8970fb4dbcbdc45aa0e75bf528af4213b6b5"}, + {file = "botocore-1.38.0.tar.gz", hash = "sha256:ac8997291bcfd28d329a779ceda429fbe9f8950ba051429a37ba93cbda025e94"}, ] [package.dependencies] @@ -213,14 +296,14 @@ crt = ["awscrt (==0.23.8)"] [[package]] name = "cachetools" -version = "5.5.1" +version = "5.5.2" description = "Extensible memoizing collections and decorators" optional = false python-versions = ">=3.7" groups = ["integration"] files = [ - {file = "cachetools-5.5.1-py3-none-any.whl", hash = "sha256:b76651fdc3b24ead3c648bbdeeb940c1b04d365b38b4af66788f9ec4a81d42bb"}, - {file = "cachetools-5.5.1.tar.gz", hash = "sha256:70f238fbba50383ef62e55c6aff6d9673175fe59f7c6782c7a0b9e38f4a9df95"}, + {file = "cachetools-5.5.2-py3-none-any.whl", hash = "sha256:d26a22bcc62eb95c3beabd9f1ee5e820d3d2704fe2967cbe350e20c8ffcd3f0a"}, + {file = "cachetools-5.5.2.tar.gz", hash = "sha256:1a661caa9175d26759571b2e19580f9d6393969e5dfca11fdb1f947a23e640d4"}, ] [[package]] @@ -451,14 +534,14 @@ files = [ [[package]] name = "cosl" -version = "0.0.55" +version = "0.0.57" description = "Utils for COS Lite charms" optional = false python-versions = ">=3.8" groups = ["charm-libs"] files = [ - {file = "cosl-0.0.55-py3-none-any.whl", hash = "sha256:bf641d611f982c8f494f3cf72ac4181b24e30c69504cfbd55aa8f54964797f90"}, - {file = "cosl-0.0.55.tar.gz", hash = "sha256:d3b8ee6f78302ac111d3a15d36c42a38c298a806161d762869513d348d778316"}, + {file = "cosl-0.0.57-py3-none-any.whl", hash = "sha256:0f2bac6dd84a636747e63acd6cb277f1cc642d3c5f80caa13cd9b51644b8ff67"}, + {file = "cosl-0.0.57.tar.gz", hash = "sha256:7ed489973e6e72a9b9533dddf0da1df3499a0aacdc513ad0b579cb04b4671b04"}, ] [package.dependencies] @@ -471,75 +554,75 @@ typing-extensions = "*" [[package]] name = "coverage" -version = "7.6.12" +version = "7.8.0" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.9" groups = ["unit"] files = [ - {file = "coverage-7.6.12-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:704c8c8c6ce6569286ae9622e534b4f5b9759b6f2cd643f1c1a61f666d534fe8"}, - {file = "coverage-7.6.12-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ad7525bf0241e5502168ae9c643a2f6c219fa0a283001cee4cf23a9b7da75879"}, - {file = "coverage-7.6.12-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06097c7abfa611c91edb9e6920264e5be1d6ceb374efb4986f38b09eed4cb2fe"}, - {file = "coverage-7.6.12-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:220fa6c0ad7d9caef57f2c8771918324563ef0d8272c94974717c3909664e674"}, - {file = "coverage-7.6.12-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3688b99604a24492bcfe1c106278c45586eb819bf66a654d8a9a1433022fb2eb"}, - {file = "coverage-7.6.12-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d1a987778b9c71da2fc8948e6f2656da6ef68f59298b7e9786849634c35d2c3c"}, - {file = "coverage-7.6.12-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:cec6b9ce3bd2b7853d4a4563801292bfee40b030c05a3d29555fd2a8ee9bd68c"}, - {file = "coverage-7.6.12-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ace9048de91293e467b44bce0f0381345078389814ff6e18dbac8fdbf896360e"}, - {file = "coverage-7.6.12-cp310-cp310-win32.whl", hash = "sha256:ea31689f05043d520113e0552f039603c4dd71fa4c287b64cb3606140c66f425"}, - {file = "coverage-7.6.12-cp310-cp310-win_amd64.whl", hash = "sha256:676f92141e3c5492d2a1596d52287d0d963df21bf5e55c8b03075a60e1ddf8aa"}, - {file = "coverage-7.6.12-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e18aafdfb3e9ec0d261c942d35bd7c28d031c5855dadb491d2723ba54f4c3015"}, - {file = "coverage-7.6.12-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:66fe626fd7aa5982cdebad23e49e78ef7dbb3e3c2a5960a2b53632f1f703ea45"}, - {file = "coverage-7.6.12-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ef01d70198431719af0b1f5dcbefc557d44a190e749004042927b2a3fed0702"}, - {file = "coverage-7.6.12-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07e92ae5a289a4bc4c0aae710c0948d3c7892e20fd3588224ebe242039573bf0"}, - {file = "coverage-7.6.12-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e695df2c58ce526eeab11a2e915448d3eb76f75dffe338ea613c1201b33bab2f"}, - {file = "coverage-7.6.12-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d74c08e9aaef995f8c4ef6d202dbd219c318450fe2a76da624f2ebb9c8ec5d9f"}, - {file = "coverage-7.6.12-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e995b3b76ccedc27fe4f477b349b7d64597e53a43fc2961db9d3fbace085d69d"}, - {file = "coverage-7.6.12-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b1f097878d74fe51e1ddd1be62d8e3682748875b461232cf4b52ddc6e6db0bba"}, - {file = "coverage-7.6.12-cp311-cp311-win32.whl", hash = "sha256:1f7ffa05da41754e20512202c866d0ebfc440bba3b0ed15133070e20bf5aeb5f"}, - {file = "coverage-7.6.12-cp311-cp311-win_amd64.whl", hash = "sha256:e216c5c45f89ef8971373fd1c5d8d1164b81f7f5f06bbf23c37e7908d19e8558"}, - {file = "coverage-7.6.12-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b172f8e030e8ef247b3104902cc671e20df80163b60a203653150d2fc204d1ad"}, - {file = "coverage-7.6.12-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:641dfe0ab73deb7069fb972d4d9725bf11c239c309ce694dd50b1473c0f641c3"}, - {file = "coverage-7.6.12-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e549f54ac5f301e8e04c569dfdb907f7be71b06b88b5063ce9d6953d2d58574"}, - {file = "coverage-7.6.12-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:959244a17184515f8c52dcb65fb662808767c0bd233c1d8a166e7cf74c9ea985"}, - {file = "coverage-7.6.12-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bda1c5f347550c359f841d6614fb8ca42ae5cb0b74d39f8a1e204815ebe25750"}, - {file = "coverage-7.6.12-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1ceeb90c3eda1f2d8c4c578c14167dbd8c674ecd7d38e45647543f19839dd6ea"}, - {file = "coverage-7.6.12-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f16f44025c06792e0fb09571ae454bcc7a3ec75eeb3c36b025eccf501b1a4c3"}, - {file = "coverage-7.6.12-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b076e625396e787448d27a411aefff867db2bffac8ed04e8f7056b07024eed5a"}, - {file = "coverage-7.6.12-cp312-cp312-win32.whl", hash = "sha256:00b2086892cf06c7c2d74983c9595dc511acca00665480b3ddff749ec4fb2a95"}, - {file = "coverage-7.6.12-cp312-cp312-win_amd64.whl", hash = "sha256:7ae6eabf519bc7871ce117fb18bf14e0e343eeb96c377667e3e5dd12095e0288"}, - {file = "coverage-7.6.12-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:488c27b3db0ebee97a830e6b5a3ea930c4a6e2c07f27a5e67e1b3532e76b9ef1"}, - {file = "coverage-7.6.12-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5d1095bbee1851269f79fd8e0c9b5544e4c00c0c24965e66d8cba2eb5bb535fd"}, - {file = "coverage-7.6.12-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0533adc29adf6a69c1baa88c3d7dbcaadcffa21afbed3ca7a225a440e4744bf9"}, - {file = "coverage-7.6.12-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:53c56358d470fa507a2b6e67a68fd002364d23c83741dbc4c2e0680d80ca227e"}, - {file = "coverage-7.6.12-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64cbb1a3027c79ca6310bf101014614f6e6e18c226474606cf725238cf5bc2d4"}, - {file = "coverage-7.6.12-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:79cac3390bfa9836bb795be377395f28410811c9066bc4eefd8015258a7578c6"}, - {file = "coverage-7.6.12-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:9b148068e881faa26d878ff63e79650e208e95cf1c22bd3f77c3ca7b1d9821a3"}, - {file = "coverage-7.6.12-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8bec2ac5da793c2685ce5319ca9bcf4eee683b8a1679051f8e6ec04c4f2fd7dc"}, - {file = "coverage-7.6.12-cp313-cp313-win32.whl", hash = "sha256:200e10beb6ddd7c3ded322a4186313d5ca9e63e33d8fab4faa67ef46d3460af3"}, - {file = "coverage-7.6.12-cp313-cp313-win_amd64.whl", hash = "sha256:2b996819ced9f7dbb812c701485d58f261bef08f9b85304d41219b1496b591ef"}, - {file = "coverage-7.6.12-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:299cf973a7abff87a30609879c10df0b3bfc33d021e1adabc29138a48888841e"}, - {file = "coverage-7.6.12-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4b467a8c56974bf06e543e69ad803c6865249d7a5ccf6980457ed2bc50312703"}, - {file = "coverage-7.6.12-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2458f275944db8129f95d91aee32c828a408481ecde3b30af31d552c2ce284a0"}, - {file = "coverage-7.6.12-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a9d8be07fb0832636a0f72b80d2a652fe665e80e720301fb22b191c3434d924"}, - {file = "coverage-7.6.12-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14d47376a4f445e9743f6c83291e60adb1b127607a3618e3185bbc8091f0467b"}, - {file = "coverage-7.6.12-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b95574d06aa9d2bd6e5cc35a5bbe35696342c96760b69dc4287dbd5abd4ad51d"}, - {file = "coverage-7.6.12-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:ecea0c38c9079570163d663c0433a9af4094a60aafdca491c6a3d248c7432827"}, - {file = "coverage-7.6.12-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2251fabcfee0a55a8578a9d29cecfee5f2de02f11530e7d5c5a05859aa85aee9"}, - {file = "coverage-7.6.12-cp313-cp313t-win32.whl", hash = "sha256:eb5507795caabd9b2ae3f1adc95f67b1104971c22c624bb354232d65c4fc90b3"}, - {file = "coverage-7.6.12-cp313-cp313t-win_amd64.whl", hash = "sha256:f60a297c3987c6c02ffb29effc70eadcbb412fe76947d394a1091a3615948e2f"}, - {file = "coverage-7.6.12-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e7575ab65ca8399c8c4f9a7d61bbd2d204c8b8e447aab9d355682205c9dd948d"}, - {file = "coverage-7.6.12-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8161d9fbc7e9fe2326de89cd0abb9f3599bccc1287db0aba285cb68d204ce929"}, - {file = "coverage-7.6.12-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a1e465f398c713f1b212400b4e79a09829cd42aebd360362cd89c5bdc44eb87"}, - {file = "coverage-7.6.12-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f25d8b92a4e31ff1bd873654ec367ae811b3a943583e05432ea29264782dc32c"}, - {file = "coverage-7.6.12-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a936309a65cc5ca80fa9f20a442ff9e2d06927ec9a4f54bcba9c14c066323f2"}, - {file = "coverage-7.6.12-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:aa6f302a3a0b5f240ee201297fff0bbfe2fa0d415a94aeb257d8b461032389bd"}, - {file = "coverage-7.6.12-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:f973643ef532d4f9be71dd88cf7588936685fdb576d93a79fe9f65bc337d9d73"}, - {file = "coverage-7.6.12-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:78f5243bb6b1060aed6213d5107744c19f9571ec76d54c99cc15938eb69e0e86"}, - {file = "coverage-7.6.12-cp39-cp39-win32.whl", hash = "sha256:69e62c5034291c845fc4df7f8155e8544178b6c774f97a99e2734b05eb5bed31"}, - {file = "coverage-7.6.12-cp39-cp39-win_amd64.whl", hash = "sha256:b01a840ecc25dce235ae4c1b6a0daefb2a203dba0e6e980637ee9c2f6ee0df57"}, - {file = "coverage-7.6.12-pp39.pp310-none-any.whl", hash = "sha256:7e39e845c4d764208e7b8f6a21c541ade741e2c41afabdfa1caa28687a3c98cf"}, - {file = "coverage-7.6.12-py3-none-any.whl", hash = "sha256:eb8668cfbc279a536c633137deeb9435d2962caec279c3f8cf8b91fff6ff8953"}, - {file = "coverage-7.6.12.tar.gz", hash = "sha256:48cfc4641d95d34766ad41d9573cc0f22a48aa88d22657a1fe01dca0dbae4de2"}, + {file = "coverage-7.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2931f66991175369859b5fd58529cd4b73582461877ecfd859b6549869287ffe"}, + {file = "coverage-7.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:52a523153c568d2c0ef8826f6cc23031dc86cffb8c6aeab92c4ff776e7951b28"}, + {file = "coverage-7.8.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c8a5c139aae4c35cbd7cadca1df02ea8cf28a911534fc1b0456acb0b14234f3"}, + {file = "coverage-7.8.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5a26c0c795c3e0b63ec7da6efded5f0bc856d7c0b24b2ac84b4d1d7bc578d676"}, + {file = "coverage-7.8.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:821f7bcbaa84318287115d54becb1915eece6918136c6f91045bb84e2f88739d"}, + {file = "coverage-7.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a321c61477ff8ee705b8a5fed370b5710c56b3a52d17b983d9215861e37b642a"}, + {file = "coverage-7.8.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:ed2144b8a78f9d94d9515963ed273d620e07846acd5d4b0a642d4849e8d91a0c"}, + {file = "coverage-7.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:042e7841a26498fff7a37d6fda770d17519982f5b7d8bf5278d140b67b61095f"}, + {file = "coverage-7.8.0-cp310-cp310-win32.whl", hash = "sha256:f9983d01d7705b2d1f7a95e10bbe4091fabc03a46881a256c2787637b087003f"}, + {file = "coverage-7.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:5a570cd9bd20b85d1a0d7b009aaf6c110b52b5755c17be6962f8ccd65d1dbd23"}, + {file = "coverage-7.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e7ac22a0bb2c7c49f441f7a6d46c9c80d96e56f5a8bc6972529ed43c8b694e27"}, + {file = "coverage-7.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bf13d564d310c156d1c8e53877baf2993fb3073b2fc9f69790ca6a732eb4bfea"}, + {file = "coverage-7.8.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5761c70c017c1b0d21b0815a920ffb94a670c8d5d409d9b38857874c21f70d7"}, + {file = "coverage-7.8.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5ff52d790c7e1628241ffbcaeb33e07d14b007b6eb00a19320c7b8a7024c040"}, + {file = "coverage-7.8.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d39fc4817fd67b3915256af5dda75fd4ee10621a3d484524487e33416c6f3543"}, + {file = "coverage-7.8.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b44674870709017e4b4036e3d0d6c17f06a0e6d4436422e0ad29b882c40697d2"}, + {file = "coverage-7.8.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8f99eb72bf27cbb167b636eb1726f590c00e1ad375002230607a844d9e9a2318"}, + {file = "coverage-7.8.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b571bf5341ba8c6bc02e0baeaf3b061ab993bf372d982ae509807e7f112554e9"}, + {file = "coverage-7.8.0-cp311-cp311-win32.whl", hash = "sha256:e75a2ad7b647fd8046d58c3132d7eaf31b12d8a53c0e4b21fa9c4d23d6ee6d3c"}, + {file = "coverage-7.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:3043ba1c88b2139126fc72cb48574b90e2e0546d4c78b5299317f61b7f718b78"}, + {file = "coverage-7.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:bbb5cc845a0292e0c520656d19d7ce40e18d0e19b22cb3e0409135a575bf79fc"}, + {file = "coverage-7.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4dfd9a93db9e78666d178d4f08a5408aa3f2474ad4d0e0378ed5f2ef71640cb6"}, + {file = "coverage-7.8.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f017a61399f13aa6d1039f75cd467be388d157cd81f1a119b9d9a68ba6f2830d"}, + {file = "coverage-7.8.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0915742f4c82208ebf47a2b154a5334155ed9ef9fe6190674b8a46c2fb89cb05"}, + {file = "coverage-7.8.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a40fcf208e021eb14b0fac6bdb045c0e0cab53105f93ba0d03fd934c956143a"}, + {file = "coverage-7.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a1f406a8e0995d654b2ad87c62caf6befa767885301f3b8f6f73e6f3c31ec3a6"}, + {file = "coverage-7.8.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:77af0f6447a582fdc7de5e06fa3757a3ef87769fbb0fdbdeba78c23049140a47"}, + {file = "coverage-7.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f2d32f95922927186c6dbc8bc60df0d186b6edb828d299ab10898ef3f40052fe"}, + {file = "coverage-7.8.0-cp312-cp312-win32.whl", hash = "sha256:769773614e676f9d8e8a0980dd7740f09a6ea386d0f383db6821df07d0f08545"}, + {file = "coverage-7.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:e5d2b9be5b0693cf21eb4ce0ec8d211efb43966f6657807f6859aab3814f946b"}, + {file = "coverage-7.8.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5ac46d0c2dd5820ce93943a501ac5f6548ea81594777ca585bf002aa8854cacd"}, + {file = "coverage-7.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:771eb7587a0563ca5bb6f622b9ed7f9d07bd08900f7589b4febff05f469bea00"}, + {file = "coverage-7.8.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42421e04069fb2cbcbca5a696c4050b84a43b05392679d4068acbe65449b5c64"}, + {file = "coverage-7.8.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:554fec1199d93ab30adaa751db68acec2b41c5602ac944bb19187cb9a41a8067"}, + {file = "coverage-7.8.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5aaeb00761f985007b38cf463b1d160a14a22c34eb3f6a39d9ad6fc27cb73008"}, + {file = "coverage-7.8.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:581a40c7b94921fffd6457ffe532259813fc68eb2bdda60fa8cc343414ce3733"}, + {file = "coverage-7.8.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f319bae0321bc838e205bf9e5bc28f0a3165f30c203b610f17ab5552cff90323"}, + {file = "coverage-7.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:04bfec25a8ef1c5f41f5e7e5c842f6b615599ca8ba8391ec33a9290d9d2db3a3"}, + {file = "coverage-7.8.0-cp313-cp313-win32.whl", hash = "sha256:dd19608788b50eed889e13a5d71d832edc34fc9dfce606f66e8f9f917eef910d"}, + {file = "coverage-7.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:a9abbccd778d98e9c7e85038e35e91e67f5b520776781d9a1e2ee9d400869487"}, + {file = "coverage-7.8.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:18c5ae6d061ad5b3e7eef4363fb27a0576012a7447af48be6c75b88494c6cf25"}, + {file = "coverage-7.8.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:95aa6ae391a22bbbce1b77ddac846c98c5473de0372ba5c463480043a07bff42"}, + {file = "coverage-7.8.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e013b07ba1c748dacc2a80e69a46286ff145935f260eb8c72df7185bf048f502"}, + {file = "coverage-7.8.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d766a4f0e5aa1ba056ec3496243150698dc0481902e2b8559314368717be82b1"}, + {file = "coverage-7.8.0-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad80e6b4a0c3cb6f10f29ae4c60e991f424e6b14219d46f1e7d442b938ee68a4"}, + {file = "coverage-7.8.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b87eb6fc9e1bb8f98892a2458781348fa37e6925f35bb6ceb9d4afd54ba36c73"}, + {file = "coverage-7.8.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:d1ba00ae33be84066cfbe7361d4e04dec78445b2b88bdb734d0d1cbab916025a"}, + {file = "coverage-7.8.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f3c38e4e5ccbdc9198aecc766cedbb134b2d89bf64533973678dfcf07effd883"}, + {file = "coverage-7.8.0-cp313-cp313t-win32.whl", hash = "sha256:379fe315e206b14e21db5240f89dc0774bdd3e25c3c58c2c733c99eca96f1ada"}, + {file = "coverage-7.8.0-cp313-cp313t-win_amd64.whl", hash = "sha256:2e4b6b87bb0c846a9315e3ab4be2d52fac905100565f4b92f02c445c8799e257"}, + {file = "coverage-7.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fa260de59dfb143af06dcf30c2be0b200bed2a73737a8a59248fcb9fa601ef0f"}, + {file = "coverage-7.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:96121edfa4c2dfdda409877ea8608dd01de816a4dc4a0523356067b305e4e17a"}, + {file = "coverage-7.8.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b8af63b9afa1031c0ef05b217faa598f3069148eeee6bb24b79da9012423b82"}, + {file = "coverage-7.8.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:89b1f4af0d4afe495cd4787a68e00f30f1d15939f550e869de90a86efa7e0814"}, + {file = "coverage-7.8.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94ec0be97723ae72d63d3aa41961a0b9a6f5a53ff599813c324548d18e3b9e8c"}, + {file = "coverage-7.8.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:8a1d96e780bdb2d0cbb297325711701f7c0b6f89199a57f2049e90064c29f6bd"}, + {file = "coverage-7.8.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:f1d8a2a57b47142b10374902777e798784abf400a004b14f1b0b9eaf1e528ba4"}, + {file = "coverage-7.8.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:cf60dd2696b457b710dd40bf17ad269d5f5457b96442f7f85722bdb16fa6c899"}, + {file = "coverage-7.8.0-cp39-cp39-win32.whl", hash = "sha256:be945402e03de47ba1872cd5236395e0f4ad635526185a930735f66710e1bd3f"}, + {file = "coverage-7.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:90e7fbc6216ecaffa5a880cdc9c77b7418c1dcb166166b78dbc630d07f278cc3"}, + {file = "coverage-7.8.0-pp39.pp310.pp311-none-any.whl", hash = "sha256:b8194fb8e50d556d5849753de991d390c5a1edeeba50f68e3a9253fbd8bf8ccd"}, + {file = "coverage-7.8.0-py3-none-any.whl", hash = "sha256:dbf364b4c5e7bae9250528167dfe40219b62e2d573c854d74be213e1e52069f7"}, + {file = "coverage-7.8.0.tar.gz", hash = "sha256:7a3d62b3b03b4b6fd41a085f3574874cf946cb4604d2b4d3e8dca8cd570ca501"}, ] [package.dependencies] @@ -550,43 +633,47 @@ toml = ["tomli ; python_full_version <= \"3.11.0a6\""] [[package]] name = "cryptography" -version = "44.0.1" +version = "44.0.2" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false python-versions = "!=3.9.0,!=3.9.1,>=3.7" groups = ["charm-libs", "integration"] files = [ - {file = "cryptography-44.0.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:bf688f615c29bfe9dfc44312ca470989279f0e94bb9f631f85e3459af8efc009"}, - {file = "cryptography-44.0.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd7c7e2d71d908dc0f8d2027e1604102140d84b155e658c20e8ad1304317691f"}, - {file = "cryptography-44.0.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:887143b9ff6bad2b7570da75a7fe8bbf5f65276365ac259a5d2d5147a73775f2"}, - {file = "cryptography-44.0.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:322eb03ecc62784536bc173f1483e76747aafeb69c8728df48537eb431cd1911"}, - {file = "cryptography-44.0.1-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:21377472ca4ada2906bc313168c9dc7b1d7ca417b63c1c3011d0c74b7de9ae69"}, - {file = "cryptography-44.0.1-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:df978682c1504fc93b3209de21aeabf2375cb1571d4e61907b3e7a2540e83026"}, - {file = "cryptography-44.0.1-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:eb3889330f2a4a148abead555399ec9a32b13b7c8ba969b72d8e500eb7ef84cd"}, - {file = "cryptography-44.0.1-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:8e6a85a93d0642bd774460a86513c5d9d80b5c002ca9693e63f6e540f1815ed0"}, - {file = "cryptography-44.0.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:6f76fdd6fd048576a04c5210d53aa04ca34d2ed63336d4abd306d0cbe298fddf"}, - {file = "cryptography-44.0.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6c8acf6f3d1f47acb2248ec3ea261171a671f3d9428e34ad0357148d492c7864"}, - {file = "cryptography-44.0.1-cp37-abi3-win32.whl", hash = "sha256:24979e9f2040c953a94bf3c6782e67795a4c260734e5264dceea65c8f4bae64a"}, - {file = "cryptography-44.0.1-cp37-abi3-win_amd64.whl", hash = "sha256:fd0ee90072861e276b0ff08bd627abec29e32a53b2be44e41dbcdf87cbee2b00"}, - {file = "cryptography-44.0.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:a2d8a7045e1ab9b9f803f0d9531ead85f90c5f2859e653b61497228b18452008"}, - {file = "cryptography-44.0.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b8272f257cf1cbd3f2e120f14c68bff2b6bdfcc157fafdee84a1b795efd72862"}, - {file = "cryptography-44.0.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e8d181e90a777b63f3f0caa836844a1182f1f265687fac2115fcf245f5fbec3"}, - {file = "cryptography-44.0.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:436df4f203482f41aad60ed1813811ac4ab102765ecae7a2bbb1dbb66dcff5a7"}, - {file = "cryptography-44.0.1-cp39-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4f422e8c6a28cf8b7f883eb790695d6d45b0c385a2583073f3cec434cc705e1a"}, - {file = "cryptography-44.0.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:72198e2b5925155497a5a3e8c216c7fb3e64c16ccee11f0e7da272fa93b35c4c"}, - {file = "cryptography-44.0.1-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:2a46a89ad3e6176223b632056f321bc7de36b9f9b93b2cc1cccf935a3849dc62"}, - {file = "cryptography-44.0.1-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:53f23339864b617a3dfc2b0ac8d5c432625c80014c25caac9082314e9de56f41"}, - {file = "cryptography-44.0.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:888fcc3fce0c888785a4876ca55f9f43787f4c5c1cc1e2e0da71ad481ff82c5b"}, - {file = "cryptography-44.0.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:00918d859aa4e57db8299607086f793fa7813ae2ff5a4637e318a25ef82730f7"}, - {file = "cryptography-44.0.1-cp39-abi3-win32.whl", hash = "sha256:9b336599e2cb77b1008cb2ac264b290803ec5e8e89d618a5e978ff5eb6f715d9"}, - {file = "cryptography-44.0.1-cp39-abi3-win_amd64.whl", hash = "sha256:e403f7f766ded778ecdb790da786b418a9f2394f36e8cc8b796cc056ab05f44f"}, - {file = "cryptography-44.0.1-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:1f9a92144fa0c877117e9748c74501bea842f93d21ee00b0cf922846d9d0b183"}, - {file = "cryptography-44.0.1-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:610a83540765a8d8ce0f351ce42e26e53e1f774a6efb71eb1b41eb01d01c3d12"}, - {file = "cryptography-44.0.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:5fed5cd6102bb4eb843e3315d2bf25fede494509bddadb81e03a859c1bc17b83"}, - {file = "cryptography-44.0.1-pp310-pypy310_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:f4daefc971c2d1f82f03097dc6f216744a6cd2ac0f04c68fb935ea2ba2a0d420"}, - {file = "cryptography-44.0.1-pp310-pypy310_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:94f99f2b943b354a5b6307d7e8d19f5c423a794462bde2bf310c770ba052b1c4"}, - {file = "cryptography-44.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d9c5b9f698a83c8bd71e0f4d3f9f839ef244798e5ffe96febfa9714717db7af7"}, - {file = "cryptography-44.0.1.tar.gz", hash = "sha256:f51f5705ab27898afda1aaa430f34ad90dc117421057782022edf0600bec5f14"}, + {file = "cryptography-44.0.2-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:efcfe97d1b3c79e486554efddeb8f6f53a4cdd4cf6086642784fa31fc384e1d7"}, + {file = "cryptography-44.0.2-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29ecec49f3ba3f3849362854b7253a9f59799e3763b0c9d0826259a88efa02f1"}, + {file = "cryptography-44.0.2-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc821e161ae88bfe8088d11bb39caf2916562e0a2dc7b6d56714a48b784ef0bb"}, + {file = "cryptography-44.0.2-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:3c00b6b757b32ce0f62c574b78b939afab9eecaf597c4d624caca4f9e71e7843"}, + {file = "cryptography-44.0.2-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7bdcd82189759aba3816d1f729ce42ffded1ac304c151d0a8e89b9996ab863d5"}, + {file = "cryptography-44.0.2-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:4973da6ca3db4405c54cd0b26d328be54c7747e89e284fcff166132eb7bccc9c"}, + {file = "cryptography-44.0.2-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:4e389622b6927d8133f314949a9812972711a111d577a5d1f4bee5e58736b80a"}, + {file = "cryptography-44.0.2-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:f514ef4cd14bb6fb484b4a60203e912cfcb64f2ab139e88c2274511514bf7308"}, + {file = "cryptography-44.0.2-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:1bc312dfb7a6e5d66082c87c34c8a62176e684b6fe3d90fcfe1568de675e6688"}, + {file = "cryptography-44.0.2-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:3b721b8b4d948b218c88cb8c45a01793483821e709afe5f622861fc6182b20a7"}, + {file = "cryptography-44.0.2-cp37-abi3-win32.whl", hash = "sha256:51e4de3af4ec3899d6d178a8c005226491c27c4ba84101bfb59c901e10ca9f79"}, + {file = "cryptography-44.0.2-cp37-abi3-win_amd64.whl", hash = "sha256:c505d61b6176aaf982c5717ce04e87da5abc9a36a5b39ac03905c4aafe8de7aa"}, + {file = "cryptography-44.0.2-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:8e0ddd63e6bf1161800592c71ac794d3fb8001f2caebe0966e77c5234fa9efc3"}, + {file = "cryptography-44.0.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81276f0ea79a208d961c433a947029e1a15948966658cf6710bbabb60fcc2639"}, + {file = "cryptography-44.0.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a1e657c0f4ea2a23304ee3f964db058c9e9e635cc7019c4aa21c330755ef6fd"}, + {file = "cryptography-44.0.2-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:6210c05941994290f3f7f175a4a57dbbb2afd9273657614c506d5976db061181"}, + {file = "cryptography-44.0.2-cp39-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d1c3572526997b36f245a96a2b1713bf79ce99b271bbcf084beb6b9b075f29ea"}, + {file = "cryptography-44.0.2-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:b042d2a275c8cee83a4b7ae30c45a15e6a4baa65a179a0ec2d78ebb90e4f6699"}, + {file = "cryptography-44.0.2-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:d03806036b4f89e3b13b6218fefea8d5312e450935b1a2d55f0524e2ed7c59d9"}, + {file = "cryptography-44.0.2-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:c7362add18b416b69d58c910caa217f980c5ef39b23a38a0880dfd87bdf8cd23"}, + {file = "cryptography-44.0.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:8cadc6e3b5a1f144a039ea08a0bdb03a2a92e19c46be3285123d32029f40a922"}, + {file = "cryptography-44.0.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6f101b1f780f7fc613d040ca4bdf835c6ef3b00e9bd7125a4255ec574c7916e4"}, + {file = "cryptography-44.0.2-cp39-abi3-win32.whl", hash = "sha256:3dc62975e31617badc19a906481deacdeb80b4bb454394b4098e3f2525a488c5"}, + {file = "cryptography-44.0.2-cp39-abi3-win_amd64.whl", hash = "sha256:5f6f90b72d8ccadb9c6e311c775c8305381db88374c65fa1a68250aa8a9cb3a6"}, + {file = "cryptography-44.0.2-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:af4ff3e388f2fa7bff9f7f2b31b87d5651c45731d3e8cfa0944be43dff5cfbdb"}, + {file = "cryptography-44.0.2-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:0529b1d5a0105dd3731fa65680b45ce49da4d8115ea76e9da77a875396727b41"}, + {file = "cryptography-44.0.2-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:7ca25849404be2f8e4b3c59483d9d3c51298a22c1c61a0e84415104dacaf5562"}, + {file = "cryptography-44.0.2-pp310-pypy310_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:268e4e9b177c76d569e8a145a6939eca9a5fec658c932348598818acf31ae9a5"}, + {file = "cryptography-44.0.2-pp310-pypy310_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:9eb9d22b0a5d8fd9925a7764a054dca914000607dff201a24c791ff5c799e1fa"}, + {file = "cryptography-44.0.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:2bf7bf75f7df9715f810d1b038870309342bff3069c5bd8c6b96128cb158668d"}, + {file = "cryptography-44.0.2-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:909c97ab43a9c0c0b0ada7a1281430e4e5ec0458e6d9244c0e821bbf152f061d"}, + {file = "cryptography-44.0.2-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:96e7a5e9d6e71f9f4fca8eebfd603f8e86c5225bb18eb621b2c1e50b290a9471"}, + {file = "cryptography-44.0.2-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:d1b3031093a366ac767b3feb8bcddb596671b3aaff82d4050f984da0c248b615"}, + {file = "cryptography-44.0.2-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:04abd71114848aa25edb28e225ab5f268096f44cf0127f3d36975bdf1bdf3390"}, + {file = "cryptography-44.0.2.tar.gz", hash = "sha256:c63454aa261a0cf0c5b4718349629793e9e634993538db841165b3df74f37ec0"}, ] [package.dependencies] @@ -599,19 +686,19 @@ nox = ["nox (>=2024.4.15)", "nox[uv] (>=2024.3.2) ; python_version >= \"3.8\""] pep8test = ["check-sdist ; python_version >= \"3.8\"", "click (>=8.0.1)", "mypy (>=1.4)", "ruff (>=0.3.6)"] sdist = ["build (>=1.0.0)"] ssh = ["bcrypt (>=3.1.5)"] -test = ["certifi (>=2024)", "cryptography-vectors (==44.0.1)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"] +test = ["certifi (>=2024)", "cryptography-vectors (==44.0.2)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"] test-randomorder = ["pytest-randomly"] [[package]] name = "decorator" -version = "5.1.1" +version = "5.2.1" description = "Decorators for Humans" optional = false -python-versions = ">=3.5" +python-versions = ">=3.8" groups = ["integration"] files = [ - {file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"}, - {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"}, + {file = "decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a"}, + {file = "decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360"}, ] [[package]] @@ -665,14 +752,14 @@ tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipyth [[package]] name = "google-auth" -version = "2.38.0" +version = "2.39.0" description = "Google Authentication Library" optional = false python-versions = ">=3.7" groups = ["integration"] files = [ - {file = "google_auth-2.38.0-py2.py3-none-any.whl", hash = "sha256:e7dae6694313f434a2727bf2906f27ad259bae090d7aa896590d86feec3d9d4a"}, - {file = "google_auth-2.38.0.tar.gz", hash = "sha256:8285113607d3b80a3f1543b75962447ba8a09fe85783432a784fdeef6ac094c4"}, + {file = "google_auth-2.39.0-py2.py3-none-any.whl", hash = "sha256:0150b6711e97fb9f52fe599f55648950cc4540015565d8fbb31be2ad6e1548a2"}, + {file = "google_auth-2.39.0.tar.gz", hash = "sha256:73222d43cdc35a3aeacbfdcaf73142a97839f10de930550d89ebfe1d0a00cde7"}, ] [package.dependencies] @@ -681,30 +768,32 @@ pyasn1-modules = ">=0.2.1" rsa = ">=3.1.4,<5" [package.extras] -aiohttp = ["aiohttp (>=3.6.2,<4.0.0.dev0)", "requests (>=2.20.0,<3.0.0.dev0)"] +aiohttp = ["aiohttp (>=3.6.2,<4.0.0)", "requests (>=2.20.0,<3.0.0)"] enterprise-cert = ["cryptography", "pyopenssl"] -pyjwt = ["cryptography (>=38.0.3)", "pyjwt (>=2.0)"] -pyopenssl = ["cryptography (>=38.0.3)", "pyopenssl (>=20.0.0)"] +pyjwt = ["cryptography (<39.0.0) ; python_version < \"3.8\"", "cryptography (>=38.0.3)", "pyjwt (>=2.0)"] +pyopenssl = ["cryptography (<39.0.0) ; python_version < \"3.8\"", "cryptography (>=38.0.3)", "pyopenssl (>=20.0.0)"] reauth = ["pyu2f (>=0.1.5)"] -requests = ["requests (>=2.20.0,<3.0.0.dev0)"] +requests = ["requests (>=2.20.0,<3.0.0)"] +testing = ["aiohttp (<3.10.0)", "aiohttp (>=3.6.2,<4.0.0)", "aioresponses", "cryptography (<39.0.0) ; python_version < \"3.8\"", "cryptography (>=38.0.3)", "flask", "freezegun", "grpcio", "mock", "oauth2client", "packaging", "pyjwt (>=2.0)", "pyopenssl (<24.3.0)", "pyopenssl (>=20.0.0)", "pytest", "pytest-asyncio", "pytest-cov", "pytest-localserver", "pyu2f (>=0.1.5)", "requests (>=2.20.0,<3.0.0)", "responses", "urllib3"] +urllib3 = ["packaging", "urllib3"] [[package]] name = "googleapis-common-protos" -version = "1.67.0" +version = "1.70.0" description = "Common protobufs used in Google APIs" optional = false python-versions = ">=3.7" groups = ["charm-libs"] files = [ - {file = "googleapis_common_protos-1.67.0-py2.py3-none-any.whl", hash = "sha256:579de760800d13616f51cf8be00c876f00a9f146d3e6510e19d1f4111758b741"}, - {file = "googleapis_common_protos-1.67.0.tar.gz", hash = "sha256:21398025365f138be356d5923e9168737d94d46a72aefee4a6110a1f23463c86"}, + {file = "googleapis_common_protos-1.70.0-py3-none-any.whl", hash = "sha256:b8bfcca8c25a2bb253e0e0b0adaf8c00773e5e6af6fd92397576680b807e0fd8"}, + {file = "googleapis_common_protos-1.70.0.tar.gz", hash = "sha256:0e1b44e0ea153e6594f9f394fef15193a68aaaea2d843f83e2742717ca753257"}, ] [package.dependencies] -protobuf = ">=3.20.2,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<6.0.0.dev0" +protobuf = ">=3.20.2,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<7.0.0" [package.extras] -grpc = ["grpcio (>=1.44.0,<2.0.0.dev0)"] +grpc = ["grpcio (>=1.44.0,<2.0.0)"] [[package]] name = "h11" @@ -720,14 +809,14 @@ files = [ [[package]] name = "httpcore" -version = "1.0.7" +version = "1.0.8" description = "A minimal low-level HTTP client." optional = false python-versions = ">=3.8" groups = ["charm-libs"] files = [ - {file = "httpcore-1.0.7-py3-none-any.whl", hash = "sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd"}, - {file = "httpcore-1.0.7.tar.gz", hash = "sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c"}, + {file = "httpcore-1.0.8-py3-none-any.whl", hash = "sha256:5254cf149bcb5f75e9d1b2b9f729ea4a4b883d1ad7379fc632b727cec23674be"}, + {file = "httpcore-1.0.8.tar.gz", hash = "sha256:86e94505ed24ea06514883fd44d2bc02d90e77e7979c8eb71b90f41d364a1bad"}, ] [package.dependencies] @@ -820,14 +909,14 @@ testing = ["flufl.flake8", "importlib-resources (>=1.3) ; python_version < \"3.9 [[package]] name = "iniconfig" -version = "2.0.0" +version = "2.1.0" description = "brain-dead simple config-ini parsing" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" groups = ["integration", "unit"] files = [ - {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, - {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, + {file = "iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760"}, + {file = "iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7"}, ] [[package]] @@ -849,14 +938,14 @@ tomli = {version = "*", markers = "python_version > \"3.6\" and python_version < [[package]] name = "ipython" -version = "8.32.0" +version = "8.35.0" description = "IPython: Productive Interactive Computing" optional = false python-versions = ">=3.10" groups = ["integration"] files = [ - {file = "ipython-8.32.0-py3-none-any.whl", hash = "sha256:cae85b0c61eff1fc48b0a8002de5958b6528fa9c8defb1894da63f42613708aa"}, - {file = "ipython-8.32.0.tar.gz", hash = "sha256:be2c91895b0b9ea7ba49d33b23e2040c352b33eb6a519cca7ce6e0c743444251"}, + {file = "ipython-8.35.0-py3-none-any.whl", hash = "sha256:e6b7470468ba6f1f0a7b116bb688a3ece2f13e2f94138e508201fad677a788ba"}, + {file = "ipython-8.35.0.tar.gz", hash = "sha256:d200b7d93c3f5883fc36ab9ce28a18249c7706e51347681f80a0aef9895f2520"}, ] [package.dependencies] @@ -884,7 +973,7 @@ notebook = ["ipywidgets", "notebook"] parallel = ["ipyparallel"] qtconsole = ["qtconsole"] test = ["packaging", "pickleshare", "pytest", "pytest-asyncio (<0.22)", "testpath"] -test-extra = ["curio", "ipython[test]", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.23)", "pandas", "trio"] +test-extra = ["curio", "ipython[test]", "jupyter_ai", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.23)", "pandas", "trio"] [[package]] name = "jedi" @@ -975,17 +1064,18 @@ referencing = ">=0.31.0" [[package]] name = "juju" -version = "3.6.1.0" +version = "3.6.1.1" description = "Python library for Juju" optional = false python-versions = ">=3.8.6" groups = ["integration"] files = [ - {file = "juju-3.6.1.0-py3-none-any.whl", hash = "sha256:28b6a10093f2e0243ad0ddd5ef25a3f59d710e9da5a188456ba704142819fbb3"}, - {file = "juju-3.6.1.0.tar.gz", hash = "sha256:59cfde55185bb53877a2bddc2855f3c48471537e130653d77984681676a448bc"}, + {file = "juju-3.6.1.1-py3-none-any.whl", hash = "sha256:19ede730130b03cd5a99850f812521c2eb93199771207b50e1edf86e5e47acb2"}, + {file = "juju-3.6.1.1.tar.gz", hash = "sha256:2289abd450515b7883f12f06d42f965d31939e711c496cb8713b4b058408e589"}, ] [package.dependencies] +backports-datetime-fromisoformat = ">=2.0.2" "backports.strenum" = {version = ">=1.3.1", markers = "python_version < \"3.11\""} hvac = "*" kubernetes = ">=12.0.1,<31.0.0" @@ -993,7 +1083,6 @@ macaroonbakery = ">=1.1,<2.0" packaging = "*" paramiko = ">=2.4.0" pyasn1 = ">=0.4.4" -pyRFC3339 = ">=1.0,<2.0" pyyaml = ">=5.1.2" toposort = ">=1.5,<2" typing-extensions = ">=4.5.0" @@ -1001,7 +1090,7 @@ typing_inspect = ">=0.6.0" websockets = ">=13.0.1" [package.extras] -dev = ["Twine", "freezegun", "pytest", "pytest-asyncio", "typing-inspect"] +dev = ["Twine", "freezegun", "pytest", "pytest-asyncio (<=0.25.0)", "typing-inspect"] docs = ["sphinx (==5.3.0)", "sphinx_rtd_theme", "sphinxcontrib-asyncio"] [[package]] @@ -1205,14 +1294,14 @@ traitlets = "*" [[package]] name = "mypy-extensions" -version = "1.0.0" +version = "1.1.0" description = "Type system extensions for programs checked with the mypy type checker." optional = false -python-versions = ">=3.5" +python-versions = ">=3.8" groups = ["integration"] files = [ - {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, - {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, + {file = "mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505"}, + {file = "mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558"}, ] [[package]] @@ -1335,14 +1424,14 @@ files = [ [[package]] name = "ops" -version = "2.18.1" +version = "2.20.0" description = "The Python library behind great charms" optional = false python-versions = ">=3.8" groups = ["main", "charm-libs"] files = [ - {file = "ops-2.18.1-py3-none-any.whl", hash = "sha256:ba0312366e25b3ae90cf4b8d0af6ea6b612d4951500f856bce609cdb25c9bdeb"}, - {file = "ops-2.18.1.tar.gz", hash = "sha256:5619deb370c00ea851f9579b780a09b88b1a1d020e58e1ed81d31c8fb7b28c8a"}, + {file = "ops-2.20.0-py3-none-any.whl", hash = "sha256:94791a4b45f00c6902494a4934480c85947880b27f5ebf3a0ec32e8cc6279c99"}, + {file = "ops-2.20.0.tar.gz", hash = "sha256:be1dcfd0bb748839fbc200bbd073a6acf9648401c3729db22d8594ebb4301e05"}, ] [package.dependencies] @@ -1351,18 +1440,18 @@ websocket-client = "==1.*" [package.extras] docs = ["canonical-sphinx-extensions", "furo", "linkify-it-py", "myst-parser", "pyspelling", "sphinx (>=8.0.0,<8.1.0)", "sphinx-autobuild", "sphinx-copybutton", "sphinx-design", "sphinx-notfound-page", "sphinx-tabs", "sphinxcontrib-jquery", "sphinxext-opengraph"] -testing = ["ops-scenario (>=7.0.5,<8)"] +testing = ["ops-scenario (==7.20.0)"] [[package]] name = "packaging" -version = "24.2" +version = "25.0" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" groups = ["integration", "unit"] files = [ - {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, - {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, + {file = "packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484"}, + {file = "packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f"}, ] [[package]] @@ -1464,26 +1553,26 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "poetry-core" -version = "2.1.1" +version = "2.1.2" description = "Poetry PEP 517 Build Backend" optional = false python-versions = "<4.0,>=3.9" groups = ["charm-libs"] files = [ - {file = "poetry_core-2.1.1-py3-none-any.whl", hash = "sha256:bc3b0382ab4d00d5d780277fd0aad1580eb4403613b37fc60fec407b5bee1fe6"}, - {file = "poetry_core-2.1.1.tar.gz", hash = "sha256:c1a1f6f00e4254742f40988a8caf665549101cf9991122cd5de1198897768b1a"}, + {file = "poetry_core-2.1.2-py3-none-any.whl", hash = "sha256:ecb1e8f7d4f071a21cd0feb8c19bd1aec80de6fb0e82aa9d809a591e544431b4"}, + {file = "poetry_core-2.1.2.tar.gz", hash = "sha256:f9dbbbd0ebf9755476a1d57f04b30e9aecf71ca9dc2fcd4b17aba92c0002aa04"}, ] [[package]] name = "prompt-toolkit" -version = "3.0.50" +version = "3.0.51" description = "Library for building powerful interactive command lines in Python" optional = false -python-versions = ">=3.8.0" +python-versions = ">=3.8" groups = ["integration"] files = [ - {file = "prompt_toolkit-3.0.50-py3-none-any.whl", hash = "sha256:9b6427eb19e479d98acff65196a307c555eb567989e6d88ebbb1b509d9779198"}, - {file = "prompt_toolkit-3.0.50.tar.gz", hash = "sha256:544748f3860a2623ca5cd6d2795e7a14f3d0e1c3c9728359013f79877fc89bab"}, + {file = "prompt_toolkit-3.0.51-py3-none-any.whl", hash = "sha256:52742911fde84e2d423e2f9a4cf1de7d7ac4e51958f648d9540e0fb8db077b07"}, + {file = "prompt_toolkit-3.0.51.tar.gz", hash = "sha256:931a162e3b27fc90c86f1b48bb1fb2c528c2761475e57c9c06de13311c7b54ed"}, ] [package.dependencies] @@ -1674,18 +1763,18 @@ files = [ [[package]] name = "pyasn1-modules" -version = "0.4.1" +version = "0.4.2" description = "A collection of ASN.1-based protocols modules" optional = false python-versions = ">=3.8" groups = ["integration"] files = [ - {file = "pyasn1_modules-0.4.1-py3-none-any.whl", hash = "sha256:49bfa96b45a292b711e986f222502c1c9a5e1f4e568fc30e2574a6c7d07838fd"}, - {file = "pyasn1_modules-0.4.1.tar.gz", hash = "sha256:c28e2dbf9c06ad61c71a075c7e0f9fd0f1b0bb2d2ad4377f240d33ac2ab60a7c"}, + {file = "pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a"}, + {file = "pyasn1_modules-0.4.2.tar.gz", hash = "sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6"}, ] [package.dependencies] -pyasn1 = ">=0.4.6,<0.7.0" +pyasn1 = ">=0.6.1,<0.7.0" [[package]] name = "pycparser" @@ -1853,14 +1942,14 @@ files = [ [[package]] name = "pytest" -version = "8.3.4" +version = "8.3.5" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.8" groups = ["integration", "unit"] files = [ - {file = "pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6"}, - {file = "pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761"}, + {file = "pytest-8.3.5-py3-none-any.whl", hash = "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820"}, + {file = "pytest-8.3.5.tar.gz", hash = "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845"}, ] [package.dependencies] @@ -1895,14 +1984,14 @@ testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy [[package]] name = "pytest-operator" -version = "0.40.0" +version = "0.42.0" description = "Fixtures for Operators" optional = false python-versions = "*" groups = ["integration"] files = [ - {file = "pytest_operator-0.40.0-py3-none-any.whl", hash = "sha256:1cfa93ab61b11e8d7bf58dbb1a39e75fcbfcc084781bb571fde08fda7e236713"}, - {file = "pytest_operator-0.40.0.tar.gz", hash = "sha256:45394ade32b7765b6ba89871b676d1fb8aa7578589f74df26ff0fca4692d1c7b"}, + {file = "pytest_operator-0.42.0-py3-none-any.whl", hash = "sha256:29ee3df46b5a47b435f63f7efa2e1433807ba723ac3890f86b88033f79b3e48c"}, + {file = "pytest_operator-0.42.0.tar.gz", hash = "sha256:389afb648dab91eb8f0e224cbe58f05598e850aafc46e589fce1705577309c69"}, ] [package.dependencies] @@ -1930,14 +2019,14 @@ six = ">=1.5" [[package]] name = "pytz" -version = "2025.1" +version = "2025.2" description = "World timezone definitions, modern and historical" optional = false python-versions = "*" groups = ["integration"] files = [ - {file = "pytz-2025.1-py2.py3-none-any.whl", hash = "sha256:89dd22dca55b46eac6eda23b2d72721bf1bdfef212645d81513ef5d03038de57"}, - {file = "pytz-2025.1.tar.gz", hash = "sha256:c2db42be2a2518b28e65f9207c4d05e6ff547d1efa4086469ef855e4ab70178e"}, + {file = "pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00"}, + {file = "pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3"}, ] [[package]] @@ -2063,127 +2152,138 @@ rsa = ["oauthlib[signedtoken] (>=3.0.0)"] [[package]] name = "rpds-py" -version = "0.22.3" +version = "0.24.0" description = "Python bindings to Rust's persistent data structures (rpds)" optional = false python-versions = ">=3.9" groups = ["charm-libs", "unit"] files = [ - {file = "rpds_py-0.22.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:6c7b99ca52c2c1752b544e310101b98a659b720b21db00e65edca34483259967"}, - {file = "rpds_py-0.22.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:be2eb3f2495ba669d2a985f9b426c1797b7d48d6963899276d22f23e33d47e37"}, - {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70eb60b3ae9245ddea20f8a4190bd79c705a22f8028aaf8bbdebe4716c3fab24"}, - {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4041711832360a9b75cfb11b25a6a97c8fb49c07b8bd43d0d02b45d0b499a4ff"}, - {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:64607d4cbf1b7e3c3c8a14948b99345eda0e161b852e122c6bb71aab6d1d798c"}, - {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e69b0a0e2537f26d73b4e43ad7bc8c8efb39621639b4434b76a3de50c6966e"}, - {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc27863442d388870c1809a87507727b799c8460573cfbb6dc0eeaef5a11b5ec"}, - {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e79dd39f1e8c3504be0607e5fc6e86bb60fe3584bec8b782578c3b0fde8d932c"}, - {file = "rpds_py-0.22.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e0fa2d4ec53dc51cf7d3bb22e0aa0143966119f42a0c3e4998293a3dd2856b09"}, - {file = "rpds_py-0.22.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fda7cb070f442bf80b642cd56483b5548e43d366fe3f39b98e67cce780cded00"}, - {file = "rpds_py-0.22.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cff63a0272fcd259dcc3be1657b07c929c466b067ceb1c20060e8d10af56f5bf"}, - {file = "rpds_py-0.22.3-cp310-cp310-win32.whl", hash = "sha256:9bd7228827ec7bb817089e2eb301d907c0d9827a9e558f22f762bb690b131652"}, - {file = "rpds_py-0.22.3-cp310-cp310-win_amd64.whl", hash = "sha256:9beeb01d8c190d7581a4d59522cd3d4b6887040dcfc744af99aa59fef3e041a8"}, - {file = "rpds_py-0.22.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d20cfb4e099748ea39e6f7b16c91ab057989712d31761d3300d43134e26e165f"}, - {file = "rpds_py-0.22.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:68049202f67380ff9aa52f12e92b1c30115f32e6895cd7198fa2a7961621fc5a"}, - {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb4f868f712b2dd4bcc538b0a0c1f63a2b1d584c925e69a224d759e7070a12d5"}, - {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bc51abd01f08117283c5ebf64844a35144a0843ff7b2983e0648e4d3d9f10dbb"}, - {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0f3cec041684de9a4684b1572fe28c7267410e02450f4561700ca5a3bc6695a2"}, - {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7ef9d9da710be50ff6809fed8f1963fecdfecc8b86656cadfca3bc24289414b0"}, - {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59f4a79c19232a5774aee369a0c296712ad0e77f24e62cad53160312b1c1eaa1"}, - {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1a60bce91f81ddaac922a40bbb571a12c1070cb20ebd6d49c48e0b101d87300d"}, - {file = "rpds_py-0.22.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e89391e6d60251560f0a8f4bd32137b077a80d9b7dbe6d5cab1cd80d2746f648"}, - {file = "rpds_py-0.22.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e3fb866d9932a3d7d0c82da76d816996d1667c44891bd861a0f97ba27e84fc74"}, - {file = "rpds_py-0.22.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1352ae4f7c717ae8cba93421a63373e582d19d55d2ee2cbb184344c82d2ae55a"}, - {file = "rpds_py-0.22.3-cp311-cp311-win32.whl", hash = "sha256:b0b4136a252cadfa1adb705bb81524eee47d9f6aab4f2ee4fa1e9d3cd4581f64"}, - {file = "rpds_py-0.22.3-cp311-cp311-win_amd64.whl", hash = "sha256:8bd7c8cfc0b8247c8799080fbff54e0b9619e17cdfeb0478ba7295d43f635d7c"}, - {file = "rpds_py-0.22.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:27e98004595899949bd7a7b34e91fa7c44d7a97c40fcaf1d874168bb652ec67e"}, - {file = "rpds_py-0.22.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1978d0021e943aae58b9b0b196fb4895a25cc53d3956b8e35e0b7682eefb6d56"}, - {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:655ca44a831ecb238d124e0402d98f6212ac527a0ba6c55ca26f616604e60a45"}, - {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:feea821ee2a9273771bae61194004ee2fc33f8ec7db08117ef9147d4bbcbca8e"}, - {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:22bebe05a9ffc70ebfa127efbc429bc26ec9e9b4ee4d15a740033efda515cf3d"}, - {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3af6e48651c4e0d2d166dc1b033b7042ea3f871504b6805ba5f4fe31581d8d38"}, - {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e67ba3c290821343c192f7eae1d8fd5999ca2dc99994114643e2f2d3e6138b15"}, - {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:02fbb9c288ae08bcb34fb41d516d5eeb0455ac35b5512d03181d755d80810059"}, - {file = "rpds_py-0.22.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f56a6b404f74ab372da986d240e2e002769a7d7102cc73eb238a4f72eec5284e"}, - {file = "rpds_py-0.22.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0a0461200769ab3b9ab7e513f6013b7a97fdeee41c29b9db343f3c5a8e2b9e61"}, - {file = "rpds_py-0.22.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8633e471c6207a039eff6aa116e35f69f3156b3989ea3e2d755f7bc41754a4a7"}, - {file = "rpds_py-0.22.3-cp312-cp312-win32.whl", hash = "sha256:593eba61ba0c3baae5bc9be2f5232430453fb4432048de28399ca7376de9c627"}, - {file = "rpds_py-0.22.3-cp312-cp312-win_amd64.whl", hash = "sha256:d115bffdd417c6d806ea9069237a4ae02f513b778e3789a359bc5856e0404cc4"}, - {file = "rpds_py-0.22.3-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:ea7433ce7e4bfc3a85654aeb6747babe3f66eaf9a1d0c1e7a4435bbdf27fea84"}, - {file = "rpds_py-0.22.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6dd9412824c4ce1aca56c47b0991e65bebb7ac3f4edccfd3f156150c96a7bf25"}, - {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20070c65396f7373f5df4005862fa162db5d25d56150bddd0b3e8214e8ef45b4"}, - {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0b09865a9abc0ddff4e50b5ef65467cd94176bf1e0004184eb915cbc10fc05c5"}, - {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3453e8d41fe5f17d1f8e9c383a7473cd46a63661628ec58e07777c2fff7196dc"}, - {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f5d36399a1b96e1a5fdc91e0522544580dbebeb1f77f27b2b0ab25559e103b8b"}, - {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:009de23c9c9ee54bf11303a966edf4d9087cd43a6003672e6aa7def643d06518"}, - {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1aef18820ef3e4587ebe8b3bc9ba6e55892a6d7b93bac6d29d9f631a3b4befbd"}, - {file = "rpds_py-0.22.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f60bd8423be1d9d833f230fdbccf8f57af322d96bcad6599e5a771b151398eb2"}, - {file = "rpds_py-0.22.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:62d9cfcf4948683a18a9aff0ab7e1474d407b7bab2ca03116109f8464698ab16"}, - {file = "rpds_py-0.22.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9253fc214112405f0afa7db88739294295f0e08466987f1d70e29930262b4c8f"}, - {file = "rpds_py-0.22.3-cp313-cp313-win32.whl", hash = "sha256:fb0ba113b4983beac1a2eb16faffd76cb41e176bf58c4afe3e14b9c681f702de"}, - {file = "rpds_py-0.22.3-cp313-cp313-win_amd64.whl", hash = "sha256:c58e2339def52ef6b71b8f36d13c3688ea23fa093353f3a4fee2556e62086ec9"}, - {file = "rpds_py-0.22.3-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:f82a116a1d03628a8ace4859556fb39fd1424c933341a08ea3ed6de1edb0283b"}, - {file = "rpds_py-0.22.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3dfcbc95bd7992b16f3f7ba05af8a64ca694331bd24f9157b49dadeeb287493b"}, - {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59259dc58e57b10e7e18ce02c311804c10c5a793e6568f8af4dead03264584d1"}, - {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5725dd9cc02068996d4438d397e255dcb1df776b7ceea3b9cb972bdb11260a83"}, - {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99b37292234e61325e7a5bb9689e55e48c3f5f603af88b1642666277a81f1fbd"}, - {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:27b1d3b3915a99208fee9ab092b8184c420f2905b7d7feb4aeb5e4a9c509b8a1"}, - {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f612463ac081803f243ff13cccc648578e2279295048f2a8d5eb430af2bae6e3"}, - {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f73d3fef726b3243a811121de45193c0ca75f6407fe66f3f4e183c983573e130"}, - {file = "rpds_py-0.22.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:3f21f0495edea7fdbaaa87e633a8689cd285f8f4af5c869f27bc8074638ad69c"}, - {file = "rpds_py-0.22.3-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:1e9663daaf7a63ceccbbb8e3808fe90415b0757e2abddbfc2e06c857bf8c5e2b"}, - {file = "rpds_py-0.22.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a76e42402542b1fae59798fab64432b2d015ab9d0c8c47ba7addddbaf7952333"}, - {file = "rpds_py-0.22.3-cp313-cp313t-win32.whl", hash = "sha256:69803198097467ee7282750acb507fba35ca22cc3b85f16cf45fb01cb9097730"}, - {file = "rpds_py-0.22.3-cp313-cp313t-win_amd64.whl", hash = "sha256:f5cf2a0c2bdadf3791b5c205d55a37a54025c6e18a71c71f82bb536cf9a454bf"}, - {file = "rpds_py-0.22.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:378753b4a4de2a7b34063d6f95ae81bfa7b15f2c1a04a9518e8644e81807ebea"}, - {file = "rpds_py-0.22.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3445e07bf2e8ecfeef6ef67ac83de670358abf2996916039b16a218e3d95e97e"}, - {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b2513ba235829860b13faa931f3b6846548021846ac808455301c23a101689d"}, - {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eaf16ae9ae519a0e237a0f528fd9f0197b9bb70f40263ee57ae53c2b8d48aeb3"}, - {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:583f6a1993ca3369e0f80ba99d796d8e6b1a3a2a442dd4e1a79e652116413091"}, - {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4617e1915a539a0d9a9567795023de41a87106522ff83fbfaf1f6baf8e85437e"}, - {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c150c7a61ed4a4f4955a96626574e9baf1adf772c2fb61ef6a5027e52803543"}, - {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2fa4331c200c2521512595253f5bb70858b90f750d39b8cbfd67465f8d1b596d"}, - {file = "rpds_py-0.22.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:214b7a953d73b5e87f0ebece4a32a5bd83c60a3ecc9d4ec8f1dca968a2d91e99"}, - {file = "rpds_py-0.22.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:f47ad3d5f3258bd7058d2d506852217865afefe6153a36eb4b6928758041d831"}, - {file = "rpds_py-0.22.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:f276b245347e6e36526cbd4a266a417796fc531ddf391e43574cf6466c492520"}, - {file = "rpds_py-0.22.3-cp39-cp39-win32.whl", hash = "sha256:bbb232860e3d03d544bc03ac57855cd82ddf19c7a07651a7c0fdb95e9efea8b9"}, - {file = "rpds_py-0.22.3-cp39-cp39-win_amd64.whl", hash = "sha256:cfbc454a2880389dbb9b5b398e50d439e2e58669160f27b60e5eca11f68ae17c"}, - {file = "rpds_py-0.22.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:d48424e39c2611ee1b84ad0f44fb3b2b53d473e65de061e3f460fc0be5f1939d"}, - {file = "rpds_py-0.22.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:24e8abb5878e250f2eb0d7859a8e561846f98910326d06c0d51381fed59357bd"}, - {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4b232061ca880db21fa14defe219840ad9b74b6158adb52ddf0e87bead9e8493"}, - {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ac0a03221cdb5058ce0167ecc92a8c89e8d0decdc9e99a2ec23380793c4dcb96"}, - {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb0c341fa71df5a4595f9501df4ac5abfb5a09580081dffbd1ddd4654e6e9123"}, - {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bf9db5488121b596dbfc6718c76092fda77b703c1f7533a226a5a9f65248f8ad"}, - {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b8db6b5b2d4491ad5b6bdc2bc7c017eec108acbf4e6785f42a9eb0ba234f4c9"}, - {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b3d504047aba448d70cf6fa22e06cb09f7cbd761939fdd47604f5e007675c24e"}, - {file = "rpds_py-0.22.3-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:e61b02c3f7a1e0b75e20c3978f7135fd13cb6cf551bf4a6d29b999a88830a338"}, - {file = "rpds_py-0.22.3-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:e35ba67d65d49080e8e5a1dd40101fccdd9798adb9b050ff670b7d74fa41c566"}, - {file = "rpds_py-0.22.3-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:26fd7cac7dd51011a245f29a2cc6489c4608b5a8ce8d75661bb4a1066c52dfbe"}, - {file = "rpds_py-0.22.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:177c7c0fce2855833819c98e43c262007f42ce86651ffbb84f37883308cb0e7d"}, - {file = "rpds_py-0.22.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:bb47271f60660803ad11f4c61b42242b8c1312a31c98c578f79ef9387bbde21c"}, - {file = "rpds_py-0.22.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:70fb28128acbfd264eda9bf47015537ba3fe86e40d046eb2963d75024be4d055"}, - {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:44d61b4b7d0c2c9ac019c314e52d7cbda0ae31078aabd0f22e583af3e0d79723"}, - {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f0e260eaf54380380ac3808aa4ebe2d8ca28b9087cf411649f96bad6900c728"}, - {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b25bc607423935079e05619d7de556c91fb6adeae9d5f80868dde3468657994b"}, - {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fb6116dfb8d1925cbdb52595560584db42a7f664617a1f7d7f6e32f138cdf37d"}, - {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a63cbdd98acef6570c62b92a1e43266f9e8b21e699c363c0fef13bd530799c11"}, - {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2b8f60e1b739a74bab7e01fcbe3dddd4657ec685caa04681df9d562ef15b625f"}, - {file = "rpds_py-0.22.3-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:2e8b55d8517a2fda8d95cb45d62a5a8bbf9dd0ad39c5b25c8833efea07b880ca"}, - {file = "rpds_py-0.22.3-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:2de29005e11637e7a2361fa151f780ff8eb2543a0da1413bb951e9f14b699ef3"}, - {file = "rpds_py-0.22.3-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:666ecce376999bf619756a24ce15bb14c5bfaf04bf00abc7e663ce17c3f34fe7"}, - {file = "rpds_py-0.22.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:5246b14ca64a8675e0a7161f7af68fe3e910e6b90542b4bfb5439ba752191df6"}, - {file = "rpds_py-0.22.3.tar.gz", hash = "sha256:e32fee8ab45d3c2db6da19a5323bc3362237c8b653c70194414b892fd06a080d"}, + {file = "rpds_py-0.24.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:006f4342fe729a368c6df36578d7a348c7c716be1da0a1a0f86e3021f8e98724"}, + {file = "rpds_py-0.24.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2d53747da70a4e4b17f559569d5f9506420966083a31c5fbd84e764461c4444b"}, + {file = "rpds_py-0.24.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8acd55bd5b071156bae57b555f5d33697998752673b9de554dd82f5b5352727"}, + {file = "rpds_py-0.24.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7e80d375134ddb04231a53800503752093dbb65dad8dabacce2c84cccc78e964"}, + {file = "rpds_py-0.24.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:60748789e028d2a46fc1c70750454f83c6bdd0d05db50f5ae83e2db500b34da5"}, + {file = "rpds_py-0.24.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6e1daf5bf6c2be39654beae83ee6b9a12347cb5aced9a29eecf12a2d25fff664"}, + {file = "rpds_py-0.24.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1b221c2457d92a1fb3c97bee9095c874144d196f47c038462ae6e4a14436f7bc"}, + {file = "rpds_py-0.24.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:66420986c9afff67ef0c5d1e4cdc2d0e5262f53ad11e4f90e5e22448df485bf0"}, + {file = "rpds_py-0.24.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:43dba99f00f1d37b2a0265a259592d05fcc8e7c19d140fe51c6e6f16faabeb1f"}, + {file = "rpds_py-0.24.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:a88c0d17d039333a41d9bf4616bd062f0bd7aa0edeb6cafe00a2fc2a804e944f"}, + {file = "rpds_py-0.24.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cc31e13ce212e14a539d430428cd365e74f8b2d534f8bc22dd4c9c55b277b875"}, + {file = "rpds_py-0.24.0-cp310-cp310-win32.whl", hash = "sha256:fc2c1e1b00f88317d9de6b2c2b39b012ebbfe35fe5e7bef980fd2a91f6100a07"}, + {file = "rpds_py-0.24.0-cp310-cp310-win_amd64.whl", hash = "sha256:c0145295ca415668420ad142ee42189f78d27af806fcf1f32a18e51d47dd2052"}, + {file = "rpds_py-0.24.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:2d3ee4615df36ab8eb16c2507b11e764dcc11fd350bbf4da16d09cda11fcedef"}, + {file = "rpds_py-0.24.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e13ae74a8a3a0c2f22f450f773e35f893484fcfacb00bb4344a7e0f4f48e1f97"}, + {file = "rpds_py-0.24.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf86f72d705fc2ef776bb7dd9e5fbba79d7e1f3e258bf9377f8204ad0fc1c51e"}, + {file = "rpds_py-0.24.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c43583ea8517ed2e780a345dd9960896afc1327e8cf3ac8239c167530397440d"}, + {file = "rpds_py-0.24.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4cd031e63bc5f05bdcda120646a0d32f6d729486d0067f09d79c8db5368f4586"}, + {file = "rpds_py-0.24.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:34d90ad8c045df9a4259c47d2e16a3f21fdb396665c94520dbfe8766e62187a4"}, + {file = "rpds_py-0.24.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e838bf2bb0b91ee67bf2b889a1a841e5ecac06dd7a2b1ef4e6151e2ce155c7ae"}, + {file = "rpds_py-0.24.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04ecf5c1ff4d589987b4d9882872f80ba13da7d42427234fce8f22efb43133bc"}, + {file = "rpds_py-0.24.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:630d3d8ea77eabd6cbcd2ea712e1c5cecb5b558d39547ac988351195db433f6c"}, + {file = "rpds_py-0.24.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ebcb786b9ff30b994d5969213a8430cbb984cdd7ea9fd6df06663194bd3c450c"}, + {file = "rpds_py-0.24.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:174e46569968ddbbeb8a806d9922f17cd2b524aa753b468f35b97ff9c19cb718"}, + {file = "rpds_py-0.24.0-cp311-cp311-win32.whl", hash = "sha256:5ef877fa3bbfb40b388a5ae1cb00636a624690dcb9a29a65267054c9ea86d88a"}, + {file = "rpds_py-0.24.0-cp311-cp311-win_amd64.whl", hash = "sha256:e274f62cbd274359eff63e5c7e7274c913e8e09620f6a57aae66744b3df046d6"}, + {file = "rpds_py-0.24.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:d8551e733626afec514b5d15befabea0dd70a343a9f23322860c4f16a9430205"}, + {file = "rpds_py-0.24.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0e374c0ce0ca82e5b67cd61fb964077d40ec177dd2c4eda67dba130de09085c7"}, + {file = "rpds_py-0.24.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d69d003296df4840bd445a5d15fa5b6ff6ac40496f956a221c4d1f6f7b4bc4d9"}, + {file = "rpds_py-0.24.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8212ff58ac6dfde49946bea57474a386cca3f7706fc72c25b772b9ca4af6b79e"}, + {file = "rpds_py-0.24.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:528927e63a70b4d5f3f5ccc1fa988a35456eb5d15f804d276709c33fc2f19bda"}, + {file = "rpds_py-0.24.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a824d2c7a703ba6daaca848f9c3d5cb93af0505be505de70e7e66829affd676e"}, + {file = "rpds_py-0.24.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44d51febb7a114293ffd56c6cf4736cb31cd68c0fddd6aa303ed09ea5a48e029"}, + {file = "rpds_py-0.24.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3fab5f4a2c64a8fb64fc13b3d139848817a64d467dd6ed60dcdd6b479e7febc9"}, + {file = "rpds_py-0.24.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9be4f99bee42ac107870c61dfdb294d912bf81c3c6d45538aad7aecab468b6b7"}, + {file = "rpds_py-0.24.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:564c96b6076a98215af52f55efa90d8419cc2ef45d99e314fddefe816bc24f91"}, + {file = "rpds_py-0.24.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:75a810b7664c17f24bf2ffd7f92416c00ec84b49bb68e6a0d93e542406336b56"}, + {file = "rpds_py-0.24.0-cp312-cp312-win32.whl", hash = "sha256:f6016bd950be4dcd047b7475fdf55fb1e1f59fc7403f387be0e8123e4a576d30"}, + {file = "rpds_py-0.24.0-cp312-cp312-win_amd64.whl", hash = "sha256:998c01b8e71cf051c28f5d6f1187abbdf5cf45fc0efce5da6c06447cba997034"}, + {file = "rpds_py-0.24.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:3d2d8e4508e15fc05b31285c4b00ddf2e0eb94259c2dc896771966a163122a0c"}, + {file = "rpds_py-0.24.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0f00c16e089282ad68a3820fd0c831c35d3194b7cdc31d6e469511d9bffc535c"}, + {file = "rpds_py-0.24.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:951cc481c0c395c4a08639a469d53b7d4afa252529a085418b82a6b43c45c240"}, + {file = "rpds_py-0.24.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c9ca89938dff18828a328af41ffdf3902405a19f4131c88e22e776a8e228c5a8"}, + {file = "rpds_py-0.24.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ed0ef550042a8dbcd657dfb284a8ee00f0ba269d3f2286b0493b15a5694f9fe8"}, + {file = "rpds_py-0.24.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2b2356688e5d958c4d5cb964af865bea84db29971d3e563fb78e46e20fe1848b"}, + {file = "rpds_py-0.24.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78884d155fd15d9f64f5d6124b486f3d3f7fd7cd71a78e9670a0f6f6ca06fb2d"}, + {file = "rpds_py-0.24.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6a4a535013aeeef13c5532f802708cecae8d66c282babb5cd916379b72110cf7"}, + {file = "rpds_py-0.24.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:84e0566f15cf4d769dade9b366b7b87c959be472c92dffb70462dd0844d7cbad"}, + {file = "rpds_py-0.24.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:823e74ab6fbaa028ec89615ff6acb409e90ff45580c45920d4dfdddb069f2120"}, + {file = "rpds_py-0.24.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c61a2cb0085c8783906b2f8b1f16a7e65777823c7f4d0a6aaffe26dc0d358dd9"}, + {file = "rpds_py-0.24.0-cp313-cp313-win32.whl", hash = "sha256:60d9b630c8025b9458a9d114e3af579a2c54bd32df601c4581bd054e85258143"}, + {file = "rpds_py-0.24.0-cp313-cp313-win_amd64.whl", hash = "sha256:6eea559077d29486c68218178ea946263b87f1c41ae7f996b1f30a983c476a5a"}, + {file = "rpds_py-0.24.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:d09dc82af2d3c17e7dd17120b202a79b578d79f2b5424bda209d9966efeed114"}, + {file = "rpds_py-0.24.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5fc13b44de6419d1e7a7e592a4885b323fbc2f46e1f22151e3a8ed3b8b920405"}, + {file = "rpds_py-0.24.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c347a20d79cedc0a7bd51c4d4b7dbc613ca4e65a756b5c3e57ec84bd43505b47"}, + {file = "rpds_py-0.24.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:20f2712bd1cc26a3cc16c5a1bfee9ed1abc33d4cdf1aabd297fe0eb724df4272"}, + {file = "rpds_py-0.24.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aad911555286884be1e427ef0dc0ba3929e6821cbeca2194b13dc415a462c7fd"}, + {file = "rpds_py-0.24.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0aeb3329c1721c43c58cae274d7d2ca85c1690d89485d9c63a006cb79a85771a"}, + {file = "rpds_py-0.24.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2a0f156e9509cee987283abd2296ec816225145a13ed0391df8f71bf1d789e2d"}, + {file = "rpds_py-0.24.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:aa6800adc8204ce898c8a424303969b7aa6a5e4ad2789c13f8648739830323b7"}, + {file = "rpds_py-0.24.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a18fc371e900a21d7392517c6f60fe859e802547309e94313cd8181ad9db004d"}, + {file = "rpds_py-0.24.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:9168764133fd919f8dcca2ead66de0105f4ef5659cbb4fa044f7014bed9a1797"}, + {file = "rpds_py-0.24.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5f6e3cec44ba05ee5cbdebe92d052f69b63ae792e7d05f1020ac5e964394080c"}, + {file = "rpds_py-0.24.0-cp313-cp313t-win32.whl", hash = "sha256:8ebc7e65ca4b111d928b669713865f021b7773350eeac4a31d3e70144297baba"}, + {file = "rpds_py-0.24.0-cp313-cp313t-win_amd64.whl", hash = "sha256:675269d407a257b8c00a6b58205b72eec8231656506c56fd429d924ca00bb350"}, + {file = "rpds_py-0.24.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a36b452abbf29f68527cf52e181fced56685731c86b52e852053e38d8b60bc8d"}, + {file = "rpds_py-0.24.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8b3b397eefecec8e8e39fa65c630ef70a24b09141a6f9fc17b3c3a50bed6b50e"}, + {file = "rpds_py-0.24.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdabcd3beb2a6dca7027007473d8ef1c3b053347c76f685f5f060a00327b8b65"}, + {file = "rpds_py-0.24.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5db385bacd0c43f24be92b60c857cf760b7f10d8234f4bd4be67b5b20a7c0b6b"}, + {file = "rpds_py-0.24.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8097b3422d020ff1c44effc40ae58e67d93e60d540a65649d2cdaf9466030791"}, + {file = "rpds_py-0.24.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:493fe54318bed7d124ce272fc36adbf59d46729659b2c792e87c3b95649cdee9"}, + {file = "rpds_py-0.24.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8aa362811ccdc1f8dadcc916c6d47e554169ab79559319ae9fae7d7752d0d60c"}, + {file = "rpds_py-0.24.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d8f9a6e7fd5434817526815f09ea27f2746c4a51ee11bb3439065f5fc754db58"}, + {file = "rpds_py-0.24.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:8205ee14463248d3349131bb8099efe15cd3ce83b8ef3ace63c7e976998e7124"}, + {file = "rpds_py-0.24.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:921ae54f9ecba3b6325df425cf72c074cd469dea843fb5743a26ca7fb2ccb149"}, + {file = "rpds_py-0.24.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:32bab0a56eac685828e00cc2f5d1200c548f8bc11f2e44abf311d6b548ce2e45"}, + {file = "rpds_py-0.24.0-cp39-cp39-win32.whl", hash = "sha256:f5c0ed12926dec1dfe7d645333ea59cf93f4d07750986a586f511c0bc61fe103"}, + {file = "rpds_py-0.24.0-cp39-cp39-win_amd64.whl", hash = "sha256:afc6e35f344490faa8276b5f2f7cbf71f88bc2cda4328e00553bd451728c571f"}, + {file = "rpds_py-0.24.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:619ca56a5468f933d940e1bf431c6f4e13bef8e688698b067ae68eb4f9b30e3a"}, + {file = "rpds_py-0.24.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:4b28e5122829181de1898c2c97f81c0b3246d49f585f22743a1246420bb8d399"}, + {file = "rpds_py-0.24.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8e5ab32cf9eb3647450bc74eb201b27c185d3857276162c101c0f8c6374e098"}, + {file = "rpds_py-0.24.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:208b3a70a98cf3710e97cabdc308a51cd4f28aa6e7bb11de3d56cd8b74bab98d"}, + {file = "rpds_py-0.24.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bbc4362e06f950c62cad3d4abf1191021b2ffaf0b31ac230fbf0526453eee75e"}, + {file = "rpds_py-0.24.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ebea2821cdb5f9fef44933617be76185b80150632736f3d76e54829ab4a3b4d1"}, + {file = "rpds_py-0.24.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9a4df06c35465ef4d81799999bba810c68d29972bf1c31db61bfdb81dd9d5bb"}, + {file = "rpds_py-0.24.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d3aa13bdf38630da298f2e0d77aca967b200b8cc1473ea05248f6c5e9c9bdb44"}, + {file = "rpds_py-0.24.0-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:041f00419e1da7a03c46042453598479f45be3d787eb837af382bfc169c0db33"}, + {file = "rpds_py-0.24.0-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:d8754d872a5dfc3c5bf9c0e059e8107451364a30d9fd50f1f1a85c4fb9481164"}, + {file = "rpds_py-0.24.0-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:896c41007931217a343eff197c34513c154267636c8056fb409eafd494c3dcdc"}, + {file = "rpds_py-0.24.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:92558d37d872e808944c3c96d0423b8604879a3d1c86fdad508d7ed91ea547d5"}, + {file = "rpds_py-0.24.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f9e0057a509e096e47c87f753136c9b10d7a91842d8042c2ee6866899a717c0d"}, + {file = "rpds_py-0.24.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d6e109a454412ab82979c5b1b3aee0604eca4bbf9a02693bb9df027af2bfa91a"}, + {file = "rpds_py-0.24.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc1c892b1ec1f8cbd5da8de287577b455e388d9c328ad592eabbdcb6fc93bee5"}, + {file = "rpds_py-0.24.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9c39438c55983d48f4bb3487734d040e22dad200dab22c41e331cee145e7a50d"}, + {file = "rpds_py-0.24.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d7e8ce990ae17dda686f7e82fd41a055c668e13ddcf058e7fb5e9da20b57793"}, + {file = "rpds_py-0.24.0-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9ea7f4174d2e4194289cb0c4e172d83e79a6404297ff95f2875cf9ac9bced8ba"}, + {file = "rpds_py-0.24.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb2954155bb8f63bb19d56d80e5e5320b61d71084617ed89efedb861a684baea"}, + {file = "rpds_py-0.24.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04f2b712a2206e13800a8136b07aaedc23af3facab84918e7aa89e4be0260032"}, + {file = "rpds_py-0.24.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:eda5c1e2a715a4cbbca2d6d304988460942551e4e5e3b7457b50943cd741626d"}, + {file = "rpds_py-0.24.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:9abc80fe8c1f87218db116016de575a7998ab1629078c90840e8d11ab423ee25"}, + {file = "rpds_py-0.24.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:6a727fd083009bc83eb83d6950f0c32b3c94c8b80a9b667c87f4bd1274ca30ba"}, + {file = "rpds_py-0.24.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e0f3ef95795efcd3b2ec3fe0a5bcfb5dadf5e3996ea2117427e524d4fbf309c6"}, + {file = "rpds_py-0.24.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:2c13777ecdbbba2077670285dd1fe50828c8742f6a4119dbef6f83ea13ad10fb"}, + {file = "rpds_py-0.24.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79e8d804c2ccd618417e96720ad5cd076a86fa3f8cb310ea386a3e6229bae7d1"}, + {file = "rpds_py-0.24.0-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fd822f019ccccd75c832deb7aa040bb02d70a92eb15a2f16c7987b7ad4ee8d83"}, + {file = "rpds_py-0.24.0-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0047638c3aa0dbcd0ab99ed1e549bbf0e142c9ecc173b6492868432d8989a046"}, + {file = "rpds_py-0.24.0-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a5b66d1b201cc71bc3081bc2f1fc36b0c1f268b773e03bbc39066651b9e18391"}, + {file = "rpds_py-0.24.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dbcbb6db5582ea33ce46a5d20a5793134b5365110d84df4e30b9d37c6fd40ad3"}, + {file = "rpds_py-0.24.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:63981feca3f110ed132fd217bf7768ee8ed738a55549883628ee3da75bb9cb78"}, + {file = "rpds_py-0.24.0-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:3a55fc10fdcbf1a4bd3c018eea422c52cf08700cf99c28b5cb10fe97ab77a0d3"}, + {file = "rpds_py-0.24.0-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:c30ff468163a48535ee7e9bf21bd14c7a81147c0e58a36c1078289a8ca7af0bd"}, + {file = "rpds_py-0.24.0-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:369d9c6d4c714e36d4a03957b4783217a3ccd1e222cdd67d464a3a479fc17796"}, + {file = "rpds_py-0.24.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:24795c099453e3721fda5d8ddd45f5dfcc8e5a547ce7b8e9da06fecc3832e26f"}, + {file = "rpds_py-0.24.0.tar.gz", hash = "sha256:772cc1b2cd963e7e17e6cc55fe0371fb9c704d63e44cacec7b9b7f523b78919e"}, ] [[package]] name = "rsa" -version = "4.9" +version = "4.9.1" description = "Pure-Python RSA implementation" optional = false -python-versions = ">=3.6,<4" +python-versions = "<4,>=3.6" groups = ["integration"] files = [ - {file = "rsa-4.9-py3-none-any.whl", hash = "sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7"}, - {file = "rsa-4.9.tar.gz", hash = "sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21"}, + {file = "rsa-4.9.1-py3-none-any.whl", hash = "sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762"}, + {file = "rsa-4.9.1.tar.gz", hash = "sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75"}, ] [package.dependencies] @@ -2191,42 +2291,42 @@ pyasn1 = ">=0.1.3" [[package]] name = "ruff" -version = "0.9.6" +version = "0.11.6" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" groups = ["format"] files = [ - {file = "ruff-0.9.6-py3-none-linux_armv6l.whl", hash = "sha256:2f218f356dd2d995839f1941322ff021c72a492c470f0b26a34f844c29cdf5ba"}, - {file = "ruff-0.9.6-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b908ff4df65dad7b251c9968a2e4560836d8f5487c2f0cc238321ed951ea0504"}, - {file = "ruff-0.9.6-py3-none-macosx_11_0_arm64.whl", hash = "sha256:b109c0ad2ececf42e75fa99dc4043ff72a357436bb171900714a9ea581ddef83"}, - {file = "ruff-0.9.6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1de4367cca3dac99bcbd15c161404e849bb0bfd543664db39232648dc00112dc"}, - {file = "ruff-0.9.6-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ac3ee4d7c2c92ddfdaedf0bf31b2b176fa7aa8950efc454628d477394d35638b"}, - {file = "ruff-0.9.6-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5dc1edd1775270e6aa2386119aea692039781429f0be1e0949ea5884e011aa8e"}, - {file = "ruff-0.9.6-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:4a091729086dffa4bd070aa5dab7e39cc6b9d62eb2bef8f3d91172d30d599666"}, - {file = "ruff-0.9.6-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d1bbc6808bf7b15796cef0815e1dfb796fbd383e7dbd4334709642649625e7c5"}, - {file = "ruff-0.9.6-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:589d1d9f25b5754ff230dce914a174a7c951a85a4e9270613a2b74231fdac2f5"}, - {file = "ruff-0.9.6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc61dd5131742e21103fbbdcad683a8813be0e3c204472d520d9a5021ca8b217"}, - {file = "ruff-0.9.6-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:5e2d9126161d0357e5c8f30b0bd6168d2c3872372f14481136d13de9937f79b6"}, - {file = "ruff-0.9.6-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:68660eab1a8e65babb5229a1f97b46e3120923757a68b5413d8561f8a85d4897"}, - {file = "ruff-0.9.6-py3-none-musllinux_1_2_i686.whl", hash = "sha256:c4cae6c4cc7b9b4017c71114115db0445b00a16de3bcde0946273e8392856f08"}, - {file = "ruff-0.9.6-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:19f505b643228b417c1111a2a536424ddde0db4ef9023b9e04a46ed8a1cb4656"}, - {file = "ruff-0.9.6-py3-none-win32.whl", hash = "sha256:194d8402bceef1b31164909540a597e0d913c0e4952015a5b40e28c146121b5d"}, - {file = "ruff-0.9.6-py3-none-win_amd64.whl", hash = "sha256:03482d5c09d90d4ee3f40d97578423698ad895c87314c4de39ed2af945633caa"}, - {file = "ruff-0.9.6-py3-none-win_arm64.whl", hash = "sha256:0e2bb706a2be7ddfea4a4af918562fdc1bcb16df255e5fa595bbd800ce322a5a"}, - {file = "ruff-0.9.6.tar.gz", hash = "sha256:81761592f72b620ec8fa1068a6fd00e98a5ebee342a3642efd84454f3031dca9"}, + {file = "ruff-0.11.6-py3-none-linux_armv6l.whl", hash = "sha256:d84dcbe74cf9356d1bdb4a78cf74fd47c740bf7bdeb7529068f69b08272239a1"}, + {file = "ruff-0.11.6-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:9bc583628e1096148011a5d51ff3c836f51899e61112e03e5f2b1573a9b726de"}, + {file = "ruff-0.11.6-py3-none-macosx_11_0_arm64.whl", hash = "sha256:f2959049faeb5ba5e3b378709e9d1bf0cab06528b306b9dd6ebd2a312127964a"}, + {file = "ruff-0.11.6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63c5d4e30d9d0de7fedbfb3e9e20d134b73a30c1e74b596f40f0629d5c28a193"}, + {file = "ruff-0.11.6-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:26a4b9a4e1439f7d0a091c6763a100cef8fbdc10d68593df6f3cfa5abdd9246e"}, + {file = "ruff-0.11.6-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b5edf270223dd622218256569636dc3e708c2cb989242262fe378609eccf1308"}, + {file = "ruff-0.11.6-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:f55844e818206a9dd31ff27f91385afb538067e2dc0beb05f82c293ab84f7d55"}, + {file = "ruff-0.11.6-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d8f782286c5ff562e4e00344f954b9320026d8e3fae2ba9e6948443fafd9ffc"}, + {file = "ruff-0.11.6-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:01c63ba219514271cee955cd0adc26a4083df1956d57847978383b0e50ffd7d2"}, + {file = "ruff-0.11.6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15adac20ef2ca296dd3d8e2bedc6202ea6de81c091a74661c3666e5c4c223ff6"}, + {file = "ruff-0.11.6-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:4dd6b09e98144ad7aec026f5588e493c65057d1b387dd937d7787baa531d9bc2"}, + {file = "ruff-0.11.6-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:45b2e1d6c0eed89c248d024ea95074d0e09988d8e7b1dad8d3ab9a67017a5b03"}, + {file = "ruff-0.11.6-py3-none-musllinux_1_2_i686.whl", hash = "sha256:bd40de4115b2ec4850302f1a1d8067f42e70b4990b68838ccb9ccd9f110c5e8b"}, + {file = "ruff-0.11.6-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:77cda2dfbac1ab73aef5e514c4cbfc4ec1fbef4b84a44c736cc26f61b3814cd9"}, + {file = "ruff-0.11.6-py3-none-win32.whl", hash = "sha256:5151a871554be3036cd6e51d0ec6eef56334d74dfe1702de717a995ee3d5b287"}, + {file = "ruff-0.11.6-py3-none-win_amd64.whl", hash = "sha256:cce85721d09c51f3b782c331b0abd07e9d7d5f775840379c640606d3159cae0e"}, + {file = "ruff-0.11.6-py3-none-win_arm64.whl", hash = "sha256:3567ba0d07fb170b1b48d944715e3294b77f5b7679e8ba258199a250383ccb79"}, + {file = "ruff-0.11.6.tar.gz", hash = "sha256:bec8bcc3ac228a45ccc811e45f7eb61b950dbf4cf31a67fa89352574b01c7d79"}, ] [[package]] name = "s3transfer" -version = "0.11.4" +version = "0.12.0" description = "An Amazon S3 Transfer Manager" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main", "integration"] files = [ - {file = "s3transfer-0.11.4-py3-none-any.whl", hash = "sha256:ac265fa68318763a03bf2dc4f39d5cbd6a9e178d81cc9483ad27da33637e320d"}, - {file = "s3transfer-0.11.4.tar.gz", hash = "sha256:559f161658e1cf0a911f45940552c696735f5c74e64362e515f333ebed87d679"}, + {file = "s3transfer-0.12.0-py3-none-any.whl", hash = "sha256:35b314d7d82865756edab59f7baebc6b477189e6ab4c53050e28c1de4d9cce18"}, + {file = "s3transfer-0.12.0.tar.gz", hash = "sha256:8ac58bc1989a3fdb7c7f3ee0918a66b160d038a147c7b5db1500930a607e9a1c"}, ] [package.dependencies] @@ -2281,14 +2381,14 @@ tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"] [[package]] name = "tenacity" -version = "9.0.0" +version = "9.1.2" description = "Retry code until it succeeds" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main", "charm-libs", "integration"] files = [ - {file = "tenacity-9.0.0-py3-none-any.whl", hash = "sha256:93de0c98785b27fcf659856aa9f54bfbd399e29969b0621bc7f762bd441b4539"}, - {file = "tenacity-9.0.0.tar.gz", hash = "sha256:807f37ca97d62aa361264d497b0e31e92b8027044942bfa756160d908320d73b"}, + {file = "tenacity-9.1.2-py3-none-any.whl", hash = "sha256:f77bf36710d8b73a50b2dd155c97b870017ad21afe6ab300326b0371b3b05138"}, + {file = "tenacity-9.1.2.tar.gz", hash = "sha256:1169d376c297e7de388d18b4481760d478b0e99a777cad3a9c86e556f4b697cb"}, ] [package.extras] @@ -2368,14 +2468,14 @@ test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0, [[package]] name = "typing-extensions" -version = "4.12.2" +version = "4.13.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" groups = ["main", "charm-libs", "integration", "unit"] files = [ - {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, - {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, + {file = "typing_extensions-4.13.2-py3-none-any.whl", hash = "sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c"}, + {file = "typing_extensions-4.13.2.tar.gz", hash = "sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef"}, ] markers = {unit = "python_version < \"3.13\""} @@ -2397,14 +2497,14 @@ typing-extensions = ">=3.7.4" [[package]] name = "urllib3" -version = "2.3.0" +version = "2.4.0" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.9" groups = ["main", "charm-libs", "integration"] files = [ - {file = "urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df"}, - {file = "urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d"}, + {file = "urllib3-2.4.0-py3-none-any.whl", hash = "sha256:4e16665048960a0900c702d4a66415956a584919c03361cac9f1df5c5dd7e813"}, + {file = "urllib3-2.4.0.tar.gz", hash = "sha256:414bc6535b787febd7567804cc015fee39daab8ad86268f1310a9250697de466"}, ] [package.extras] @@ -2444,81 +2544,81 @@ test = ["websockets"] [[package]] name = "websockets" -version = "15.0" +version = "15.0.1" description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" optional = false python-versions = ">=3.9" groups = ["integration"] files = [ - {file = "websockets-15.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5e6ee18a53dd5743e6155b8ff7e8e477c25b29b440f87f65be8165275c87fef0"}, - {file = "websockets-15.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ee06405ea2e67366a661ed313e14cf2a86e84142a3462852eb96348f7219cee3"}, - {file = "websockets-15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8711682a629bbcaf492f5e0af72d378e976ea1d127a2d47584fa1c2c080b436b"}, - {file = "websockets-15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94c4a9b01eede952442c088d415861b0cf2053cbd696b863f6d5022d4e4e2453"}, - {file = "websockets-15.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:45535fead66e873f411c1d3cf0d3e175e66f4dd83c4f59d707d5b3e4c56541c4"}, - {file = "websockets-15.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e389efe46ccb25a1f93d08c7a74e8123a2517f7b7458f043bd7529d1a63ffeb"}, - {file = "websockets-15.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:67a04754d121ea5ca39ddedc3f77071651fb5b0bc6b973c71c515415b44ed9c5"}, - {file = "websockets-15.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:bd66b4865c8b853b8cca7379afb692fc7f52cf898786537dfb5e5e2d64f0a47f"}, - {file = "websockets-15.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:a4cc73a6ae0a6751b76e69cece9d0311f054da9b22df6a12f2c53111735657c8"}, - {file = "websockets-15.0-cp310-cp310-win32.whl", hash = "sha256:89da58e4005e153b03fe8b8794330e3f6a9774ee9e1c3bd5bc52eb098c3b0c4f"}, - {file = "websockets-15.0-cp310-cp310-win_amd64.whl", hash = "sha256:4ff380aabd7a74a42a760ee76c68826a8f417ceb6ea415bd574a035a111fd133"}, - {file = "websockets-15.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:dd24c4d256558429aeeb8d6c24ebad4e982ac52c50bc3670ae8646c181263965"}, - {file = "websockets-15.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f83eca8cbfd168e424dfa3b3b5c955d6c281e8fc09feb9d870886ff8d03683c7"}, - {file = "websockets-15.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4095a1f2093002c2208becf6f9a178b336b7572512ee0a1179731acb7788e8ad"}, - {file = "websockets-15.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb915101dfbf318486364ce85662bb7b020840f68138014972c08331458d41f3"}, - {file = "websockets-15.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:45d464622314973d78f364689d5dbb9144e559f93dca11b11af3f2480b5034e1"}, - {file = "websockets-15.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ace960769d60037ca9625b4c578a6f28a14301bd2a1ff13bb00e824ac9f73e55"}, - {file = "websockets-15.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c7cd4b1015d2f60dfe539ee6c95bc968d5d5fad92ab01bb5501a77393da4f596"}, - {file = "websockets-15.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4f7290295794b5dec470867c7baa4a14182b9732603fd0caf2a5bf1dc3ccabf3"}, - {file = "websockets-15.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3abd670ca7ce230d5a624fd3d55e055215d8d9b723adee0a348352f5d8d12ff4"}, - {file = "websockets-15.0-cp311-cp311-win32.whl", hash = "sha256:110a847085246ab8d4d119632145224d6b49e406c64f1bbeed45c6f05097b680"}, - {file = "websockets-15.0-cp311-cp311-win_amd64.whl", hash = "sha256:8d7bbbe2cd6ed80aceef2a14e9f1c1b61683194c216472ed5ff33b700e784e37"}, - {file = "websockets-15.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:cccc18077acd34c8072578394ec79563664b1c205f7a86a62e94fafc7b59001f"}, - {file = "websockets-15.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d4c22992e24f12de340ca5f824121a5b3e1a37ad4360b4e1aaf15e9d1c42582d"}, - {file = "websockets-15.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1206432cc6c644f6fc03374b264c5ff805d980311563202ed7fef91a38906276"}, - {file = "websockets-15.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d3cc75ef3e17490042c47e0523aee1bcc4eacd2482796107fd59dd1100a44bc"}, - {file = "websockets-15.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b89504227a5311610e4be16071465885a0a3d6b0e82e305ef46d9b064ce5fb72"}, - {file = "websockets-15.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56e3efe356416bc67a8e093607315951d76910f03d2b3ad49c4ade9207bf710d"}, - {file = "websockets-15.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0f2205cdb444a42a7919690238fb5979a05439b9dbb73dd47c863d39640d85ab"}, - {file = "websockets-15.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:aea01f40995fa0945c020228ab919b8dfc93fc8a9f2d3d705ab5b793f32d9e99"}, - {file = "websockets-15.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a9f8e33747b1332db11cf7fcf4a9512bef9748cb5eb4d3f7fbc8c30d75dc6ffc"}, - {file = "websockets-15.0-cp312-cp312-win32.whl", hash = "sha256:32e02a2d83f4954aa8c17e03fe8ec6962432c39aca4be7e8ee346b05a3476904"}, - {file = "websockets-15.0-cp312-cp312-win_amd64.whl", hash = "sha256:ffc02b159b65c05f2ed9ec176b715b66918a674bd4daed48a9a7a590dd4be1aa"}, - {file = "websockets-15.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:d2244d8ab24374bed366f9ff206e2619345f9cd7fe79aad5225f53faac28b6b1"}, - {file = "websockets-15.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:3a302241fbe825a3e4fe07666a2ab513edfdc6d43ce24b79691b45115273b5e7"}, - {file = "websockets-15.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:10552fed076757a70ba2c18edcbc601c7637b30cdfe8c24b65171e824c7d6081"}, - {file = "websockets-15.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c53f97032b87a406044a1c33d1e9290cc38b117a8062e8a8b285175d7e2f99c9"}, - {file = "websockets-15.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1caf951110ca757b8ad9c4974f5cac7b8413004d2f29707e4d03a65d54cedf2b"}, - {file = "websockets-15.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8bf1ab71f9f23b0a1d52ec1682a3907e0c208c12fef9c3e99d2b80166b17905f"}, - {file = "websockets-15.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bfcd3acc1a81f106abac6afd42327d2cf1e77ec905ae11dc1d9142a006a496b6"}, - {file = "websockets-15.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:c8c5c8e1bac05ef3c23722e591ef4f688f528235e2480f157a9cfe0a19081375"}, - {file = "websockets-15.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:86bfb52a9cfbcc09aba2b71388b0a20ea5c52b6517c0b2e316222435a8cdab72"}, - {file = "websockets-15.0-cp313-cp313-win32.whl", hash = "sha256:26ba70fed190708551c19a360f9d7eca8e8c0f615d19a574292b7229e0ae324c"}, - {file = "websockets-15.0-cp313-cp313-win_amd64.whl", hash = "sha256:ae721bcc8e69846af00b7a77a220614d9b2ec57d25017a6bbde3a99473e41ce8"}, - {file = "websockets-15.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c348abc5924caa02a62896300e32ea80a81521f91d6db2e853e6b1994017c9f6"}, - {file = "websockets-15.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5294fcb410ed0a45d5d1cdedc4e51a60aab5b2b3193999028ea94afc2f554b05"}, - {file = "websockets-15.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c24ba103ecf45861e2e1f933d40b2d93f5d52d8228870c3e7bf1299cd1cb8ff1"}, - {file = "websockets-15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc8821a03bcfb36e4e4705316f6b66af28450357af8a575dc8f4b09bf02a3dee"}, - {file = "websockets-15.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffc5ae23ada6515f31604f700009e2df90b091b67d463a8401c1d8a37f76c1d7"}, - {file = "websockets-15.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ac67b542505186b3bbdaffbc303292e1ee9c8729e5d5df243c1f20f4bb9057e"}, - {file = "websockets-15.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:c86dc2068f1c5ca2065aca34f257bbf4f78caf566eb230f692ad347da191f0a1"}, - {file = "websockets-15.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:30cff3ef329682b6182c01c568f551481774c476722020b8f7d0daacbed07a17"}, - {file = "websockets-15.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:98dcf978d4c6048965d1762abd534c9d53bae981a035bfe486690ba11f49bbbb"}, - {file = "websockets-15.0-cp39-cp39-win32.whl", hash = "sha256:37d66646f929ae7c22c79bc73ec4074d6db45e6384500ee3e0d476daf55482a9"}, - {file = "websockets-15.0-cp39-cp39-win_amd64.whl", hash = "sha256:24d5333a9b2343330f0f4eb88546e2c32a7f5c280f8dd7d3cc079beb0901781b"}, - {file = "websockets-15.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:b499caef4bca9cbd0bd23cd3386f5113ee7378094a3cb613a2fa543260fe9506"}, - {file = "websockets-15.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:17f2854c6bd9ee008c4b270f7010fe2da6c16eac5724a175e75010aacd905b31"}, - {file = "websockets-15.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89f72524033abbfde880ad338fd3c2c16e31ae232323ebdfbc745cbb1b3dcc03"}, - {file = "websockets-15.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1657a9eecb29d7838e3b415458cc494e6d1b194f7ac73a34aa55c6fb6c72d1f3"}, - {file = "websockets-15.0-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e413352a921f5ad5d66f9e2869b977e88d5103fc528b6deb8423028a2befd842"}, - {file = "websockets-15.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:8561c48b0090993e3b2a54db480cab1d23eb2c5735067213bb90f402806339f5"}, - {file = "websockets-15.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:190bc6ef8690cd88232a038d1b15714c258f79653abad62f7048249b09438af3"}, - {file = "websockets-15.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:327adab7671f3726b0ba69be9e865bba23b37a605b585e65895c428f6e47e766"}, - {file = "websockets-15.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2bd8ef197c87afe0a9009f7a28b5dc613bfc585d329f80b7af404e766aa9e8c7"}, - {file = "websockets-15.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:789c43bf4a10cd067c24c321238e800b8b2716c863ddb2294d2fed886fa5a689"}, - {file = "websockets-15.0-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7394c0b7d460569c9285fa089a429f58465db930012566c03046f9e3ab0ed181"}, - {file = "websockets-15.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2ea4f210422b912ebe58ef0ad33088bc8e5c5ff9655a8822500690abc3b1232d"}, - {file = "websockets-15.0-py3-none-any.whl", hash = "sha256:51ffd53c53c4442415b613497a34ba0aa7b99ac07f1e4a62db5dcd640ae6c3c3"}, - {file = "websockets-15.0.tar.gz", hash = "sha256:ca36151289a15b39d8d683fd8b7abbe26fc50be311066c5f8dcf3cb8cee107ab"}, + {file = "websockets-15.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d63efaa0cd96cf0c5fe4d581521d9fa87744540d4bc999ae6e08595a1014b45b"}, + {file = "websockets-15.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac60e3b188ec7574cb761b08d50fcedf9d77f1530352db4eef1707fe9dee7205"}, + {file = "websockets-15.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5756779642579d902eed757b21b0164cd6fe338506a8083eb58af5c372e39d9a"}, + {file = "websockets-15.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fdfe3e2a29e4db3659dbd5bbf04560cea53dd9610273917799f1cde46aa725e"}, + {file = "websockets-15.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c2529b320eb9e35af0fa3016c187dffb84a3ecc572bcee7c3ce302bfeba52bf"}, + {file = "websockets-15.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac1e5c9054fe23226fb11e05a6e630837f074174c4c2f0fe442996112a6de4fb"}, + {file = "websockets-15.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5df592cd503496351d6dc14f7cdad49f268d8e618f80dce0cd5a36b93c3fc08d"}, + {file = "websockets-15.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0a34631031a8f05657e8e90903e656959234f3a04552259458aac0b0f9ae6fd9"}, + {file = "websockets-15.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3d00075aa65772e7ce9e990cab3ff1de702aa09be3940d1dc88d5abf1ab8a09c"}, + {file = "websockets-15.0.1-cp310-cp310-win32.whl", hash = "sha256:1234d4ef35db82f5446dca8e35a7da7964d02c127b095e172e54397fb6a6c256"}, + {file = "websockets-15.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:39c1fec2c11dc8d89bba6b2bf1556af381611a173ac2b511cf7231622058af41"}, + {file = "websockets-15.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:823c248b690b2fd9303ba00c4f66cd5e2d8c3ba4aa968b2779be9532a4dad431"}, + {file = "websockets-15.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678999709e68425ae2593acf2e3ebcbcf2e69885a5ee78f9eb80e6e371f1bf57"}, + {file = "websockets-15.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d50fd1ee42388dcfb2b3676132c78116490976f1300da28eb629272d5d93e905"}, + {file = "websockets-15.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d99e5546bf73dbad5bf3547174cd6cb8ba7273062a23808ffea025ecb1cf8562"}, + {file = "websockets-15.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66dd88c918e3287efc22409d426c8f729688d89a0c587c88971a0faa2c2f3792"}, + {file = "websockets-15.0.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8dd8327c795b3e3f219760fa603dcae1dcc148172290a8ab15158cf85a953413"}, + {file = "websockets-15.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8fdc51055e6ff4adeb88d58a11042ec9a5eae317a0a53d12c062c8a8865909e8"}, + {file = "websockets-15.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:693f0192126df6c2327cce3baa7c06f2a117575e32ab2308f7f8216c29d9e2e3"}, + {file = "websockets-15.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:54479983bd5fb469c38f2f5c7e3a24f9a4e70594cd68cd1fa6b9340dadaff7cf"}, + {file = "websockets-15.0.1-cp311-cp311-win32.whl", hash = "sha256:16b6c1b3e57799b9d38427dda63edcbe4926352c47cf88588c0be4ace18dac85"}, + {file = "websockets-15.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:27ccee0071a0e75d22cb35849b1db43f2ecd3e161041ac1ee9d2352ddf72f065"}, + {file = "websockets-15.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3e90baa811a5d73f3ca0bcbf32064d663ed81318ab225ee4f427ad4e26e5aff3"}, + {file = "websockets-15.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:592f1a9fe869c778694f0aa806ba0374e97648ab57936f092fd9d87f8bc03665"}, + {file = "websockets-15.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0701bc3cfcb9164d04a14b149fd74be7347a530ad3bbf15ab2c678a2cd3dd9a2"}, + {file = "websockets-15.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8b56bdcdb4505c8078cb6c7157d9811a85790f2f2b3632c7d1462ab5783d215"}, + {file = "websockets-15.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0af68c55afbd5f07986df82831c7bff04846928ea8d1fd7f30052638788bc9b5"}, + {file = "websockets-15.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64dee438fed052b52e4f98f76c5790513235efaa1ef7f3f2192c392cd7c91b65"}, + {file = "websockets-15.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d5f6b181bb38171a8ad1d6aa58a67a6aa9d4b38d0f8c5f496b9e42561dfc62fe"}, + {file = "websockets-15.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5d54b09eba2bada6011aea5375542a157637b91029687eb4fdb2dab11059c1b4"}, + {file = "websockets-15.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3be571a8b5afed347da347bfcf27ba12b069d9d7f42cb8c7028b5e98bbb12597"}, + {file = "websockets-15.0.1-cp312-cp312-win32.whl", hash = "sha256:c338ffa0520bdb12fbc527265235639fb76e7bc7faafbb93f6ba80d9c06578a9"}, + {file = "websockets-15.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcd5cf9e305d7b8338754470cf69cf81f420459dbae8a3b40cee57417f4614a7"}, + {file = "websockets-15.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee443ef070bb3b6ed74514f5efaa37a252af57c90eb33b956d35c8e9c10a1931"}, + {file = "websockets-15.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5a939de6b7b4e18ca683218320fc67ea886038265fd1ed30173f5ce3f8e85675"}, + {file = "websockets-15.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:746ee8dba912cd6fc889a8147168991d50ed70447bf18bcda7039f7d2e3d9151"}, + {file = "websockets-15.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:595b6c3969023ecf9041b2936ac3827e4623bfa3ccf007575f04c5a6aa318c22"}, + {file = "websockets-15.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c714d2fc58b5ca3e285461a4cc0c9a66bd0e24c5da9911e30158286c9b5be7f"}, + {file = "websockets-15.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f3c1e2ab208db911594ae5b4f79addeb3501604a165019dd221c0bdcabe4db8"}, + {file = "websockets-15.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:229cf1d3ca6c1804400b0a9790dc66528e08a6a1feec0d5040e8b9eb14422375"}, + {file = "websockets-15.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:756c56e867a90fb00177d530dca4b097dd753cde348448a1012ed6c5131f8b7d"}, + {file = "websockets-15.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:558d023b3df0bffe50a04e710bc87742de35060580a293c2a984299ed83bc4e4"}, + {file = "websockets-15.0.1-cp313-cp313-win32.whl", hash = "sha256:ba9e56e8ceeeedb2e080147ba85ffcd5cd0711b89576b83784d8605a7df455fa"}, + {file = "websockets-15.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561"}, + {file = "websockets-15.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5f4c04ead5aed67c8a1a20491d54cdfba5884507a48dd798ecaf13c74c4489f5"}, + {file = "websockets-15.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:abdc0c6c8c648b4805c5eacd131910d2a7f6455dfd3becab248ef108e89ab16a"}, + {file = "websockets-15.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a625e06551975f4b7ea7102bc43895b90742746797e2e14b70ed61c43a90f09b"}, + {file = "websockets-15.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d591f8de75824cbb7acad4e05d2d710484f15f29d4a915092675ad3456f11770"}, + {file = "websockets-15.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:47819cea040f31d670cc8d324bb6435c6f133b8c7a19ec3d61634e62f8d8f9eb"}, + {file = "websockets-15.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac017dd64572e5c3bd01939121e4d16cf30e5d7e110a119399cf3133b63ad054"}, + {file = "websockets-15.0.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:4a9fac8e469d04ce6c25bb2610dc535235bd4aa14996b4e6dbebf5e007eba5ee"}, + {file = "websockets-15.0.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:363c6f671b761efcb30608d24925a382497c12c506b51661883c3e22337265ed"}, + {file = "websockets-15.0.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2034693ad3097d5355bfdacfffcbd3ef5694f9718ab7f29c29689a9eae841880"}, + {file = "websockets-15.0.1-cp39-cp39-win32.whl", hash = "sha256:3b1ac0d3e594bf121308112697cf4b32be538fb1444468fb0a6ae4feebc83411"}, + {file = "websockets-15.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:b7643a03db5c95c799b89b31c036d5f27eeb4d259c798e878d6937d71832b1e4"}, + {file = "websockets-15.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0c9e74d766f2818bb95f84c25be4dea09841ac0f734d1966f415e4edfc4ef1c3"}, + {file = "websockets-15.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1009ee0c7739c08a0cd59de430d6de452a55e42d6b522de7aa15e6f67db0b8e1"}, + {file = "websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76d1f20b1c7a2fa82367e04982e708723ba0e7b8d43aa643d3dcd404d74f1475"}, + {file = "websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f29d80eb9a9263b8d109135351caf568cc3f80b9928bccde535c235de55c22d9"}, + {file = "websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b359ed09954d7c18bbc1680f380c7301f92c60bf924171629c5db97febb12f04"}, + {file = "websockets-15.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:cad21560da69f4ce7658ca2cb83138fb4cf695a2ba3e475e0559e05991aa8122"}, + {file = "websockets-15.0.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7f493881579c90fc262d9cdbaa05a6b54b3811c2f300766748db79f098db9940"}, + {file = "websockets-15.0.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:47b099e1f4fbc95b701b6e85768e1fcdaf1630f3cbe4765fa216596f12310e2e"}, + {file = "websockets-15.0.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67f2b6de947f8c757db2db9c71527933ad0019737ec374a8a6be9a956786aaf9"}, + {file = "websockets-15.0.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d08eb4c2b7d6c41da6ca0600c077e93f5adcfd979cd777d747e9ee624556da4b"}, + {file = "websockets-15.0.1-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b826973a4a2ae47ba357e4e82fa44a463b8f168e1ca775ac64521442b19e87f"}, + {file = "websockets-15.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:21c1fa28a6a7e3cbdc171c694398b6df4744613ce9b36b1a498e816787e28123"}, + {file = "websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f"}, + {file = "websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee"}, ] [[package]] @@ -2633,4 +2733,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = "^3.10" -content-hash = "d6d1a9eb1d741b25733acdae41d5ad4c8f3a1948bb519a31b676c5f6b1f21550" +content-hash = "fb48e4bd5f30c14061469b28bacf1f284648934eac48e1eadfecdb29c563a896" diff --git a/pyproject.toml b/pyproject.toml index 1a7c1b7d51..755ccbbd9f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,14 +7,14 @@ requires-poetry = ">=2.0.0" [tool.poetry.dependencies] python = "^3.10" -ops = "^2.18.1" -boto3 = "^1.37.22" +ops = "^2.20.0" +boto3 = "^1.38.0" pgconnstr = "^1.0.1" requests = "^2.32.3" -tenacity = "^9.0.0" +tenacity = "^9.1.2" psycopg2 = "^2.9.10" pydantic = "^1.10.21" -jinja2 = "^3.1.5" +jinja2 = "^3.1.6" pysyncobj = "^0.3.14" psutil = "^7.0.0" @@ -40,7 +40,7 @@ opentelemetry-exporter-otlp-proto-http = "1.21.0" optional = true [tool.poetry.group.format.dependencies] -ruff = "^0.9.6" +ruff = "^0.11.6" [tool.poetry.group.lint] optional = true @@ -52,8 +52,8 @@ codespell = "^2.4.1" optional = true [tool.poetry.group.unit.dependencies] -coverage = {extras = ["toml"], version = "^7.6.12"} -pytest = "^8.3.4" +coverage = {extras = ["toml"], version = "^7.8.0"} +pytest = "^8.3.5" pytest-asyncio = "*" parameterized = "^0.9.0" jsonschema = "^4.23.0" @@ -62,16 +62,16 @@ jsonschema = "^4.23.0" optional = true [tool.poetry.group.integration.dependencies] -pytest = "^8.3.4" -pytest-operator = "^0.40.0" +pytest = "^8.3.5" +pytest-operator = "^0.42.0" # renovate caret doesn't work: https://github.com/renovatebot/renovate/issues/26940 -juju = "<=3.6.1.0" +juju = "<=3.6.1.1" boto3 = "*" tenacity = "*" landscape-api-py3 = "^0.9.0" mailmanclient = "^3.3.5" psycopg2-binary = "^2.9.10" -allure-pytest = "^2.13.5" +allure-pytest = "^2.14.0" allure-pytest-default-results = "^0.1.2" # Testing tools configuration diff --git a/src/charm.py b/src/charm.py index bc6fd78a3c..b4bd28d455 100755 --- a/src/charm.py +++ b/src/charm.py @@ -1078,9 +1078,9 @@ def _on_install(self, event: InstallEvent) -> None: # This is needed due to https://bugs.launchpad.net/snapd/+bug/2011581. try: # Input is hardcoded - subprocess.check_call("mkdir -p /home/snap_daemon".split()) # noqa: S603 - subprocess.check_call("chown snap_daemon:snap_daemon /home/snap_daemon".split()) # noqa: S603 - subprocess.check_call("usermod -d /home/snap_daemon snap_daemon".split()) # noqa: S603 + subprocess.check_call(["mkdir", "-p", "/home/snap_daemon"]) # noqa: S607 + subprocess.check_call(["chown", "snap_daemon:snap_daemon", "/home/snap_daemon"]) # noqa: S607 + subprocess.check_call(["usermod", "-d", "/home/snap_daemon", "snap_daemon"]) # noqa: S607 except subprocess.CalledProcessError: logger.exception("Unable to create snap_daemon home dir") @@ -1933,8 +1933,7 @@ def _reboot_on_detached_storage(self, event: EventBase) -> None: logger.error("Data directory not attached. Reboot unit.") self.unit.status = WaitingStatus("Data directory not attached") with contextlib.suppress(subprocess.CalledProcessError): - # Call is constant - subprocess.check_call(["/usr/bin/systemctl", "reboot"]) # noqa: S603 + subprocess.check_call(["/usr/bin/systemctl", "reboot"]) def _restart(self, event: RunWithLock) -> None: """Restart PostgreSQL.""" diff --git a/src/cluster.py b/src/cluster.py index 3ca1a46d4d..7d4c70c33a 100644 --- a/src/cluster.py +++ b/src/cluster.py @@ -1067,5 +1067,4 @@ def update_patroni_restart_condition(self, new_condition: str) -> None: logger.debug(f"new patroni service file: {new_patroni_service}") with open(PATRONI_SERVICE_DEFAULT_PATH, "w") as patroni_service_file: patroni_service_file.write(new_patroni_service) - # Input is hardcoded - subprocess.run(["/bin/systemctl", "daemon-reload"]) # noqa: S603 + subprocess.run(["/bin/systemctl", "daemon-reload"]) diff --git a/src/rotate_logs.py b/src/rotate_logs.py index 01d4ca88b4..17aa74aeb9 100644 --- a/src/rotate_logs.py +++ b/src/rotate_logs.py @@ -45,8 +45,7 @@ def start_log_rotation(self): logging.info("Starting rotate logs process") - # Input is generated by the charm - pid = subprocess.Popen( # noqa: S603 + pid = subprocess.Popen( ["/usr/bin/python3", "scripts/rotate_logs.py"], # File should not close stdout=open(LOG_FILE_PATH, "a"), # noqa: SIM115 diff --git a/tests/unit/test_backups.py b/tests/unit/test_backups.py index 1ca2d3a469..5cd5cac8c4 100644 --- a/tests/unit/test_backups.py +++ b/tests/unit/test_backups.py @@ -507,7 +507,7 @@ def test_execute_command(harness): patch("pwd.getpwnam") as _getpwnam, ): # Test when the command fails. - command = "rm -r /var/lib/postgresql/data/pgdata".split() + command = ["rm", "-r", "/var/lib/postgresql/data/pgdata"] _run.return_value = CompletedProcess(command, 1, b"", b"fake stderr") assert harness.charm.backup._execute_command(command) == (1, "", "fake stderr") _run.assert_called_once_with( diff --git a/tests/unit/test_charm.py b/tests/unit/test_charm.py index 3ff54bccce..bd18ab405f 100644 --- a/tests/unit/test_charm.py +++ b/tests/unit/test_charm.py @@ -92,9 +92,9 @@ def test_on_install(harness): pg_snap.alias.assert_any_call("patronictl") assert _check_call.call_count == 3 - _check_call.assert_any_call("mkdir -p /home/snap_daemon".split()) - _check_call.assert_any_call("chown snap_daemon:snap_daemon /home/snap_daemon".split()) - _check_call.assert_any_call("usermod -d /home/snap_daemon snap_daemon".split()) + _check_call.assert_any_call(["mkdir", "-p", "/home/snap_daemon"]) + _check_call.assert_any_call(["chown", "snap_daemon:snap_daemon", "/home/snap_daemon"]) + _check_call.assert_any_call(["usermod", "-d", "/home/snap_daemon", "snap_daemon"]) # Assert the status set by the event handler. assert isinstance(harness.model.unit.status, WaitingStatus) From 77d821003b49a1598f898db4214bf4d3754cf597 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 24 Apr 2025 04:13:34 +0300 Subject: [PATCH 022/112] Update dependency uv to v0.6.16 (#847) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- charmcraft.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charmcraft.yaml b/charmcraft.yaml index cd332e9ed5..d03da104cf 100644 --- a/charmcraft.yaml +++ b/charmcraft.yaml @@ -27,7 +27,7 @@ parts: PIP_BREAK_SYSTEM_PACKAGES=true python3 -m pip install --user --upgrade pip==25.0.1 # renovate: charmcraft-pip-latest # Use uv to install poetry so that a newer version of Python can be installed if needed by poetry - curl --proto '=https' --tlsv1.2 -LsSf https://github.com/astral-sh/uv/releases/download/0.6.14/uv-installer.sh | sh # renovate: charmcraft-uv-latest + curl --proto '=https' --tlsv1.2 -LsSf https://github.com/astral-sh/uv/releases/download/0.6.16/uv-installer.sh | sh # renovate: charmcraft-uv-latest # poetry 2.0.0 requires Python >=3.9 if ! "$HOME/.local/bin/uv" python find '>=3.9' then From 2ef8871262e0f0e662eb2619741320bfc69f6944 Mon Sep 17 00:00:00 2001 From: Dragomir Penev <6687393+dragomirp@users.noreply.github.com> Date: Fri, 25 Apr 2025 14:11:29 +0300 Subject: [PATCH 023/112] [DPE-6664] Make username mandatory in set-password (#846) * Make username mandatory * Second get password method * Default in get-password --- src/charm.py | 9 +++++---- tests/unit/test_charm.py | 16 +++++++++++----- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/charm.py b/src/charm.py index b4bd28d455..da921284c4 100755 --- a/src/charm.py +++ b/src/charm.py @@ -1507,13 +1507,14 @@ def _on_set_password(self, event: ActionEvent) -> None: event.fail("The action can be run only on leader unit") return - username = event.params.get("username", USER) - if username not in SYSTEM_USERS and self.is_ldap_enabled: - event.fail("The action can be run only for system users when LDAP is enabled") + if not (username := event.params.get("username")): + event.fail("The action requires a username") return if username not in SYSTEM_USERS: event.fail( - f"The action can be run only for system users:" + "The action can be run only for system users when LDAP is enabled" + if self.is_ldap_enabled + else "The action can be run only for system users:" f" {', '.join(SYSTEM_USERS)} not {username}" ) return diff --git a/tests/unit/test_charm.py b/tests/unit/test_charm.py index bd18ab405f..a81aa7eb35 100644 --- a/tests/unit/test_charm.py +++ b/tests/unit/test_charm.py @@ -854,14 +854,16 @@ def test_on_set_password(harness): patch("charm.PostgresqlOperatorCharm.postgresql") as _postgresql, patch("charm.Patroni.are_all_members_ready") as _are_all_members_ready, patch("charm.PostgresqlOperatorCharm._on_leader_elected"), + patch("charm.new_password", return_value="newpass"), ): # Create a mock event. mock_event = MagicMock(params={}) # Set some values for the other mocks. - _are_all_members_ready.side_effect = [False, True, True, True, True] - _postgresql.update_user_password = PropertyMock( - side_effect=[PostgreSQLUpdateUserPasswordError, None, None, None] + _are_all_members_ready.return_value = False + _postgresql.update_user_password = PropertyMock() + _postgresql.update_user_password.return_value.side_effect = ( + PostgreSQLUpdateUserPasswordError ) # Test trying to set a password through a non leader unit. @@ -878,6 +880,7 @@ def test_on_set_password(harness): _set_secret.assert_not_called() # Test without providing the username option but without all cluster members ready. + _are_all_members_ready.return_value = True mock_event.reset_mock() del mock_event.params["username"] harness.charm._on_set_password(mock_event) @@ -891,14 +894,17 @@ def test_on_set_password(harness): _set_secret.assert_not_called() # Test without providing the username option. + mock_event.reset_mock() + _postgresql.update_user_password.return_value.side_effect = None harness.charm._on_set_password(mock_event) - assert _set_secret.call_args_list[0][0][1] == "operator-password" + mock_event.fail.assert_called_once() + _set_secret.assert_not_called() # Also test providing the username option. _set_secret.reset_mock() mock_event.params["username"] = "replication" harness.charm._on_set_password(mock_event) - assert _set_secret.call_args_list[0][0][1] == "replication-password" + _set_secret.assert_called_once_with("app", "replication-password", "newpass") # And test providing both the username and password options. _set_secret.reset_mock() From eff10317b1bfd027c5b0b255dd3b9a3a631fb730 Mon Sep 17 00:00:00 2001 From: swetha1654 Date: Fri, 25 Apr 2025 20:58:12 +0530 Subject: [PATCH 024/112] Add conditional expose directive (#853) --- terraform/main.tf | 5 +++++ terraform/variables.tf | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/terraform/main.tf b/terraform/main.tf index e55420a960..e38c14628a 100644 --- a/terraform/main.tf +++ b/terraform/main.tf @@ -16,4 +16,9 @@ resource "juju_application" "machine_postgresql" { units = var.units constraints = var.constraints config = var.config + + dynamic "expose" { + for_each = var.enable_expose ? [1] : [] + content {} + } } diff --git a/terraform/variables.tf b/terraform/variables.tf index ede475f37a..987bb16ba0 100644 --- a/terraform/variables.tf +++ b/terraform/variables.tf @@ -50,3 +50,9 @@ variable "config" { type = map(string) default = {} } + +variable "enable_expose" { + type = bool + default = true + description = "Whether to expose the application" +} From 9fb223b5f4c478bd6c21ea0bc560ed639c3b3e6f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 25 Apr 2025 19:03:35 +0300 Subject: [PATCH 025/112] Lock file maintenance Python dependencies (#854) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- poetry.lock | 202 ++++++++++++++++++++++++------------------------- pyproject.toml | 6 +- 2 files changed, 104 insertions(+), 104 deletions(-) diff --git a/poetry.lock b/poetry.lock index 497df5734d..34e6fcc91c 100644 --- a/poetry.lock +++ b/poetry.lock @@ -256,18 +256,18 @@ typecheck = ["mypy"] [[package]] name = "boto3" -version = "1.38.0" +version = "1.38.2" description = "The AWS SDK for Python" optional = false python-versions = ">=3.9" groups = ["main", "integration"] files = [ - {file = "boto3-1.38.0-py3-none-any.whl", hash = "sha256:96898facb164b47859d40a4271007824a0a791c3811a7079ce52459d753d4474"}, - {file = "boto3-1.38.0.tar.gz", hash = "sha256:8b6544eca17e31d1bfd538e5d152b96a68d6c92950352a0cd9679f89d217d53a"}, + {file = "boto3-1.38.2-py3-none-any.whl", hash = "sha256:ef3237b169cd906a44a32c03b3229833d923c9e9733355b329ded2151f91ec0b"}, + {file = "boto3-1.38.2.tar.gz", hash = "sha256:53c8d44b231251fa9421dd13d968236d59fe2cf0421e077afedbf3821653fb3b"}, ] [package.dependencies] -botocore = ">=1.38.0,<1.39.0" +botocore = ">=1.38.2,<1.39.0" jmespath = ">=0.7.1,<2.0.0" s3transfer = ">=0.12.0,<0.13.0" @@ -276,14 +276,14 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.38.0" +version = "1.38.2" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">=3.9" groups = ["main", "integration"] files = [ - {file = "botocore-1.38.0-py3-none-any.whl", hash = "sha256:f9d58404796a44746d54c4a9318a8970fb4dbcbdc45aa0e75bf528af4213b6b5"}, - {file = "botocore-1.38.0.tar.gz", hash = "sha256:ac8997291bcfd28d329a779ceda429fbe9f8950ba051429a37ba93cbda025e94"}, + {file = "botocore-1.38.2-py3-none-any.whl", hash = "sha256:5d9cffedb1c759a058b43793d16647ed44ec87072f98a1bd6cd673ac0ae6b81d"}, + {file = "botocore-1.38.2.tar.gz", hash = "sha256:b688a9bd17211a1eaae3a6c965ba9f3973e5435efaaa4fa201f499d3467830e1"}, ] [package.dependencies] @@ -797,31 +797,31 @@ grpc = ["grpcio (>=1.44.0,<2.0.0)"] [[package]] name = "h11" -version = "0.14.0" +version = "0.16.0" description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" groups = ["charm-libs"] files = [ - {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, - {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, + {file = "h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86"}, + {file = "h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1"}, ] [[package]] name = "httpcore" -version = "1.0.8" +version = "1.0.9" description = "A minimal low-level HTTP client." optional = false python-versions = ">=3.8" groups = ["charm-libs"] files = [ - {file = "httpcore-1.0.8-py3-none-any.whl", hash = "sha256:5254cf149bcb5f75e9d1b2b9f729ea4a4b883d1ad7379fc632b727cec23674be"}, - {file = "httpcore-1.0.8.tar.gz", hash = "sha256:86e94505ed24ea06514883fd44d2bc02d90e77e7979c8eb71b90f41d364a1bad"}, + {file = "httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55"}, + {file = "httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8"}, ] [package.dependencies] certifi = "*" -h11 = ">=0.13,<0.15" +h11 = ">=0.16" [package.extras] asyncio = ["anyio (>=4.0,<5.0)"] @@ -1049,14 +1049,14 @@ format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339- [[package]] name = "jsonschema-specifications" -version = "2024.10.1" +version = "2025.4.1" description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry" optional = false python-versions = ">=3.9" groups = ["charm-libs", "unit"] files = [ - {file = "jsonschema_specifications-2024.10.1-py3-none-any.whl", hash = "sha256:a09a0680616357d9a0ecf05c12ad234479f549239d0f5b55f3deea67475da9bf"}, - {file = "jsonschema_specifications-2024.10.1.tar.gz", hash = "sha256:0f38b83639958ce1152d02a7f062902c41c8fd20d558b0c34344292d417ae272"}, + {file = "jsonschema_specifications-2025.4.1-py3-none-any.whl", hash = "sha256:4653bffbd6584f7de83a67e0d620ef16900b390ddc7939d56684d6c81e33f1af"}, + {file = "jsonschema_specifications-2025.4.1.tar.gz", hash = "sha256:630159c9f4dbea161a6a2205c3011cc4f18ff381b189fff48bb39b9bf26ae608"}, ] [package.dependencies] @@ -1580,23 +1580,23 @@ wcwidth = "*" [[package]] name = "protobuf" -version = "4.25.6" +version = "4.25.7" description = "" optional = false python-versions = ">=3.8" groups = ["charm-libs", "integration"] files = [ - {file = "protobuf-4.25.6-cp310-abi3-win32.whl", hash = "sha256:61df6b5786e2b49fc0055f636c1e8f0aff263808bb724b95b164685ac1bcc13a"}, - {file = "protobuf-4.25.6-cp310-abi3-win_amd64.whl", hash = "sha256:b8f837bfb77513fe0e2f263250f423217a173b6d85135be4d81e96a4653bcd3c"}, - {file = "protobuf-4.25.6-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:6d4381f2417606d7e01750e2729fe6fbcda3f9883aa0c32b51d23012bded6c91"}, - {file = "protobuf-4.25.6-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:5dd800da412ba7f6f26d2c08868a5023ce624e1fdb28bccca2dc957191e81fb5"}, - {file = "protobuf-4.25.6-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:4434ff8bb5576f9e0c78f47c41cdf3a152c0b44de475784cd3fd170aef16205a"}, - {file = "protobuf-4.25.6-cp38-cp38-win32.whl", hash = "sha256:8bad0f9e8f83c1fbfcc34e573352b17dfce7d0519512df8519994168dc015d7d"}, - {file = "protobuf-4.25.6-cp38-cp38-win_amd64.whl", hash = "sha256:b6905b68cde3b8243a198268bb46fbec42b3455c88b6b02fb2529d2c306d18fc"}, - {file = "protobuf-4.25.6-cp39-cp39-win32.whl", hash = "sha256:3f3b0b39db04b509859361ac9bca65a265fe9342e6b9406eda58029f5b1d10b2"}, - {file = "protobuf-4.25.6-cp39-cp39-win_amd64.whl", hash = "sha256:6ef2045f89d4ad8d95fd43cd84621487832a61d15b49500e4c1350e8a0ef96be"}, - {file = "protobuf-4.25.6-py3-none-any.whl", hash = "sha256:07972021c8e30b870cfc0863409d033af940213e0e7f64e27fe017b929d2c9f7"}, - {file = "protobuf-4.25.6.tar.gz", hash = "sha256:f8cfbae7c5afd0d0eaccbe73267339bff605a2315860bb1ba08eb66670a9a91f"}, + {file = "protobuf-4.25.7-cp310-abi3-win32.whl", hash = "sha256:dc582cf1a73a6b40aa8e7704389b8d8352da616bc8ed5c6cc614bdd0b5ce3f7a"}, + {file = "protobuf-4.25.7-cp310-abi3-win_amd64.whl", hash = "sha256:cd873dbddb28460d1706ff4da2e7fac175f62f2a0bebc7b33141f7523c5a2399"}, + {file = "protobuf-4.25.7-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:4c899f09b0502eb39174c717ccf005b844ea93e31137c167ddcacf3e09e49610"}, + {file = "protobuf-4.25.7-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:6d2f5dede3d112e573f0e5f9778c0c19d9f9e209727abecae1d39db789f522c6"}, + {file = "protobuf-4.25.7-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:d41fb7ae72a25fcb79b2d71e4247f0547a02e8185ed51587c22827a87e5736ed"}, + {file = "protobuf-4.25.7-cp38-cp38-win32.whl", hash = "sha256:237db80000865851eac3c6e9d5597c0dfb0b2700d642ec48ed80b6ffe7b8729c"}, + {file = "protobuf-4.25.7-cp38-cp38-win_amd64.whl", hash = "sha256:ea41b75edb0f1110050a60e653820d9acc70b6fb471013971535f412addbb0d0"}, + {file = "protobuf-4.25.7-cp39-cp39-win32.whl", hash = "sha256:2f738d4f341186e697c4cdd0e03143ee5cf6cf523790748e61273a51997494c3"}, + {file = "protobuf-4.25.7-cp39-cp39-win_amd64.whl", hash = "sha256:3629b34b65f6204b17adf4ffe21adc8e85f6c6c0bc2baf3fb001b0d343edaebb"}, + {file = "protobuf-4.25.7-py3-none-any.whl", hash = "sha256:e9d969f5154eaeab41404def5dcf04e62162178f4b9de98b2d3c1c70f5f84810"}, + {file = "protobuf-4.25.7.tar.gz", hash = "sha256:28f65ae8c14523cc2c76c1e91680958700d3eac69f45c96512c12c63d9a38807"}, ] [[package]] @@ -1791,62 +1791,62 @@ markers = {charm-libs = "platform_python_implementation != \"PyPy\""} [[package]] name = "pydantic" -version = "1.10.21" +version = "1.10.22" description = "Data validation and settings management using python type hints" optional = false python-versions = ">=3.7" groups = ["main", "charm-libs"] files = [ - {file = "pydantic-1.10.21-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:245e486e0fec53ec2366df9cf1cba36e0bbf066af7cd9c974bbbd9ba10e1e586"}, - {file = "pydantic-1.10.21-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6c54f8d4c151c1de784c5b93dfbb872067e3414619e10e21e695f7bb84d1d1fd"}, - {file = "pydantic-1.10.21-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b64708009cfabd9c2211295144ff455ec7ceb4c4fb45a07a804309598f36187"}, - {file = "pydantic-1.10.21-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8a148410fa0e971ba333358d11a6dea7b48e063de127c2b09ece9d1c1137dde4"}, - {file = "pydantic-1.10.21-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:36ceadef055af06e7756eb4b871cdc9e5a27bdc06a45c820cd94b443de019bbf"}, - {file = "pydantic-1.10.21-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c0501e1d12df6ab1211b8cad52d2f7b2cd81f8e8e776d39aa5e71e2998d0379f"}, - {file = "pydantic-1.10.21-cp310-cp310-win_amd64.whl", hash = "sha256:c261127c275d7bce50b26b26c7d8427dcb5c4803e840e913f8d9df3f99dca55f"}, - {file = "pydantic-1.10.21-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8b6350b68566bb6b164fb06a3772e878887f3c857c46c0c534788081cb48adf4"}, - {file = "pydantic-1.10.21-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:935b19fdcde236f4fbf691959fa5c3e2b6951fff132964e869e57c70f2ad1ba3"}, - {file = "pydantic-1.10.21-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b6a04efdcd25486b27f24c1648d5adc1633ad8b4506d0e96e5367f075ed2e0b"}, - {file = "pydantic-1.10.21-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c1ba253eb5af8d89864073e6ce8e6c8dec5f49920cff61f38f5c3383e38b1c9f"}, - {file = "pydantic-1.10.21-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:57f0101e6c97b411f287a0b7cf5ebc4e5d3b18254bf926f45a11615d29475793"}, - {file = "pydantic-1.10.21-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:90e85834f0370d737c77a386ce505c21b06bfe7086c1c568b70e15a568d9670d"}, - {file = "pydantic-1.10.21-cp311-cp311-win_amd64.whl", hash = "sha256:6a497bc66b3374b7d105763d1d3de76d949287bf28969bff4656206ab8a53aa9"}, - {file = "pydantic-1.10.21-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2ed4a5f13cf160d64aa331ab9017af81f3481cd9fd0e49f1d707b57fe1b9f3ae"}, - {file = "pydantic-1.10.21-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3b7693bb6ed3fbe250e222f9415abb73111bb09b73ab90d2d4d53f6390e0ccc1"}, - {file = "pydantic-1.10.21-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:185d5f1dff1fead51766da9b2de4f3dc3b8fca39e59383c273f34a6ae254e3e2"}, - {file = "pydantic-1.10.21-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:38e6d35cf7cd1727822c79e324fa0677e1a08c88a34f56695101f5ad4d5e20e5"}, - {file = "pydantic-1.10.21-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:1d7c332685eafacb64a1a7645b409a166eb7537f23142d26895746f628a3149b"}, - {file = "pydantic-1.10.21-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c9b782db6f993a36092480eeaab8ba0609f786041b01f39c7c52252bda6d85f"}, - {file = "pydantic-1.10.21-cp312-cp312-win_amd64.whl", hash = "sha256:7ce64d23d4e71d9698492479505674c5c5b92cda02b07c91dfc13633b2eef805"}, - {file = "pydantic-1.10.21-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0067935d35044950be781933ab91b9a708eaff124bf860fa2f70aeb1c4be7212"}, - {file = "pydantic-1.10.21-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5e8148c2ce4894ce7e5a4925d9d3fdce429fb0e821b5a8783573f3611933a251"}, - {file = "pydantic-1.10.21-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a4973232c98b9b44c78b1233693e5e1938add5af18042f031737e1214455f9b8"}, - {file = "pydantic-1.10.21-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:662bf5ce3c9b1cef32a32a2f4debe00d2f4839fefbebe1d6956e681122a9c839"}, - {file = "pydantic-1.10.21-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:98737c3ab5a2f8a85f2326eebcd214510f898881a290a7939a45ec294743c875"}, - {file = "pydantic-1.10.21-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0bb58bbe65a43483d49f66b6c8474424d551a3fbe8a7796c42da314bac712738"}, - {file = "pydantic-1.10.21-cp313-cp313-win_amd64.whl", hash = "sha256:e622314542fb48542c09c7bd1ac51d71c5632dd3c92dc82ede6da233f55f4848"}, - {file = "pydantic-1.10.21-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d356aa5b18ef5a24d8081f5c5beb67c0a2a6ff2a953ee38d65a2aa96526b274f"}, - {file = "pydantic-1.10.21-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:08caa8c0468172d27c669abfe9e7d96a8b1655ec0833753e117061febaaadef5"}, - {file = "pydantic-1.10.21-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c677aa39ec737fec932feb68e4a2abe142682f2885558402602cd9746a1c92e8"}, - {file = "pydantic-1.10.21-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:79577cc045d3442c4e845df53df9f9202546e2ba54954c057d253fc17cd16cb1"}, - {file = "pydantic-1.10.21-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:b6b73ab347284719f818acb14f7cd80696c6fdf1bd34feee1955d7a72d2e64ce"}, - {file = "pydantic-1.10.21-cp37-cp37m-win_amd64.whl", hash = "sha256:46cffa24891b06269e12f7e1ec50b73f0c9ab4ce71c2caa4ccf1fb36845e1ff7"}, - {file = "pydantic-1.10.21-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:298d6f765e3c9825dfa78f24c1efd29af91c3ab1b763e1fd26ae4d9e1749e5c8"}, - {file = "pydantic-1.10.21-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f2f4a2305f15eff68f874766d982114ac89468f1c2c0b97640e719cf1a078374"}, - {file = "pydantic-1.10.21-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35b263b60c519354afb3a60107d20470dd5250b3ce54c08753f6975c406d949b"}, - {file = "pydantic-1.10.21-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e23a97a6c2f2db88995496db9387cd1727acdacc85835ba8619dce826c0b11a6"}, - {file = "pydantic-1.10.21-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:3c96fed246ccc1acb2df032ff642459e4ae18b315ecbab4d95c95cfa292e8517"}, - {file = "pydantic-1.10.21-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:b92893ebefc0151474f682e7debb6ab38552ce56a90e39a8834734c81f37c8a9"}, - {file = "pydantic-1.10.21-cp38-cp38-win_amd64.whl", hash = "sha256:b8460bc256bf0de821839aea6794bb38a4c0fbd48f949ea51093f6edce0be459"}, - {file = "pydantic-1.10.21-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5d387940f0f1a0adb3c44481aa379122d06df8486cc8f652a7b3b0caf08435f7"}, - {file = "pydantic-1.10.21-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:266ecfc384861d7b0b9c214788ddff75a2ea123aa756bcca6b2a1175edeca0fe"}, - {file = "pydantic-1.10.21-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61da798c05a06a362a2f8c5e3ff0341743e2818d0f530eaac0d6898f1b187f1f"}, - {file = "pydantic-1.10.21-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a621742da75ce272d64ea57bd7651ee2a115fa67c0f11d66d9dcfc18c2f1b106"}, - {file = "pydantic-1.10.21-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:9e3e4000cd54ef455694b8be9111ea20f66a686fc155feda1ecacf2322b115da"}, - {file = "pydantic-1.10.21-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:f198c8206640f4c0ef5a76b779241efb1380a300d88b1bce9bfe95a6362e674d"}, - {file = "pydantic-1.10.21-cp39-cp39-win_amd64.whl", hash = "sha256:e7f0cda108b36a30c8fc882e4fc5b7eec8ef584aa43aa43694c6a7b274fb2b56"}, - {file = "pydantic-1.10.21-py3-none-any.whl", hash = "sha256:db70c920cba9d05c69ad4a9e7f8e9e83011abb2c6490e561de9ae24aee44925c"}, - {file = "pydantic-1.10.21.tar.gz", hash = "sha256:64b48e2b609a6c22178a56c408ee1215a7206077ecb8a193e2fda31858b2362a"}, + {file = "pydantic-1.10.22-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:57889565ccc1e5b7b73343329bbe6198ebc472e3ee874af2fa1865cfe7048228"}, + {file = "pydantic-1.10.22-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:90729e22426de79bc6a3526b4c45ec4400caf0d4f10d7181ba7f12c01bb3897d"}, + {file = "pydantic-1.10.22-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8684d347f351554ec94fdcb507983d3116dc4577fb8799fed63c65869a2d10"}, + {file = "pydantic-1.10.22-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c8dad498ceff2d9ef1d2e2bc6608f5b59b8e1ba2031759b22dfb8c16608e1802"}, + {file = "pydantic-1.10.22-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fac529cc654d4575cf8de191cce354b12ba705f528a0a5c654de6d01f76cd818"}, + {file = "pydantic-1.10.22-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:4148232aded8dd1dd13cf910a01b32a763c34bd79a0ab4d1ee66164fcb0b7b9d"}, + {file = "pydantic-1.10.22-cp310-cp310-win_amd64.whl", hash = "sha256:ece68105d9e436db45d8650dc375c760cc85a6793ae019c08769052902dca7db"}, + {file = "pydantic-1.10.22-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8e530a8da353f791ad89e701c35787418605d35085f4bdda51b416946070e938"}, + {file = "pydantic-1.10.22-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:654322b85642e9439d7de4c83cb4084ddd513df7ff8706005dada43b34544946"}, + {file = "pydantic-1.10.22-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8bece75bd1b9fc1c32b57a32831517943b1159ba18b4ba32c0d431d76a120ae"}, + {file = "pydantic-1.10.22-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eccb58767f13c6963dcf96d02cb8723ebb98b16692030803ac075d2439c07b0f"}, + {file = "pydantic-1.10.22-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7778e6200ff8ed5f7052c1516617423d22517ad36cc7a3aedd51428168e3e5e8"}, + {file = "pydantic-1.10.22-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bffe02767d27c39af9ca7dc7cd479c00dda6346bb62ffc89e306f665108317a2"}, + {file = "pydantic-1.10.22-cp311-cp311-win_amd64.whl", hash = "sha256:23bc19c55427091b8e589bc08f635ab90005f2dc99518f1233386f46462c550a"}, + {file = "pydantic-1.10.22-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:92d0f97828a075a71d9efc65cf75db5f149b4d79a38c89648a63d2932894d8c9"}, + {file = "pydantic-1.10.22-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6af5a2811b6b95b58b829aeac5996d465a5f0c7ed84bd871d603cf8646edf6ff"}, + {file = "pydantic-1.10.22-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6cf06d8d40993e79af0ab2102ef5da77b9ddba51248e4cb27f9f3f591fbb096e"}, + {file = "pydantic-1.10.22-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:184b7865b171a6057ad97f4a17fbac81cec29bd103e996e7add3d16b0d95f609"}, + {file = "pydantic-1.10.22-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:923ad861677ab09d89be35d36111156063a7ebb44322cdb7b49266e1adaba4bb"}, + {file = "pydantic-1.10.22-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:82d9a3da1686443fb854c8d2ab9a473251f8f4cdd11b125522efb4d7c646e7bc"}, + {file = "pydantic-1.10.22-cp312-cp312-win_amd64.whl", hash = "sha256:1612604929af4c602694a7f3338b18039d402eb5ddfbf0db44f1ebfaf07f93e7"}, + {file = "pydantic-1.10.22-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b259dc89c9abcd24bf42f31951fb46c62e904ccf4316393f317abeeecda39978"}, + {file = "pydantic-1.10.22-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9238aa0964d80c0908d2f385e981add58faead4412ca80ef0fa352094c24e46d"}, + {file = "pydantic-1.10.22-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f8029f05b04080e3f1a550575a1bca747c0ea4be48e2d551473d47fd768fc1b"}, + {file = "pydantic-1.10.22-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5c06918894f119e0431a36c9393bc7cceeb34d1feeb66670ef9b9ca48c073937"}, + {file = "pydantic-1.10.22-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:e205311649622ee8fc1ec9089bd2076823797f5cd2c1e3182dc0e12aab835b35"}, + {file = "pydantic-1.10.22-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:815f0a73d5688d6dd0796a7edb9eca7071bfef961a7b33f91e618822ae7345b7"}, + {file = "pydantic-1.10.22-cp313-cp313-win_amd64.whl", hash = "sha256:9dfce71d42a5cde10e78a469e3d986f656afc245ab1b97c7106036f088dd91f8"}, + {file = "pydantic-1.10.22-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3ecaf8177b06aac5d1f442db1288e3b46d9f05f34fd17fdca3ad34105328b61a"}, + {file = "pydantic-1.10.22-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb36c2de9ea74bd7f66b5481dea8032d399affd1cbfbb9bb7ce539437f1fce62"}, + {file = "pydantic-1.10.22-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e6b8d14a256be3b8fff9286d76c532f1a7573fbba5f189305b22471c6679854d"}, + {file = "pydantic-1.10.22-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:1c33269e815db4324e71577174c29c7aa30d1bba51340ce6be976f6f3053a4c6"}, + {file = "pydantic-1.10.22-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:8661b3ab2735b2a9ccca2634738534a795f4a10bae3ab28ec0a10c96baa20182"}, + {file = "pydantic-1.10.22-cp37-cp37m-win_amd64.whl", hash = "sha256:22bdd5fe70d4549995981c55b970f59de5c502d5656b2abdfcd0a25be6f3763e"}, + {file = "pydantic-1.10.22-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e3f33d1358aa4bc2795208cc29ff3118aeaad0ea36f0946788cf7cadeccc166b"}, + {file = "pydantic-1.10.22-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:813f079f9cd136cac621f3f9128a4406eb8abd2ad9fdf916a0731d91c6590017"}, + {file = "pydantic-1.10.22-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab618ab8dca6eac7f0755db25f6aba3c22c40e3463f85a1c08dc93092d917704"}, + {file = "pydantic-1.10.22-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d128e1aaa38db88caca920d5822c98fc06516a09a58b6d3d60fa5ea9099b32cc"}, + {file = "pydantic-1.10.22-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:cc97bbc25def7025e55fc9016080773167cda2aad7294e06a37dda04c7d69ece"}, + {file = "pydantic-1.10.22-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0dda5d7157d543b1fa565038cae6e952549d0f90071c839b3740fb77c820fab8"}, + {file = "pydantic-1.10.22-cp38-cp38-win_amd64.whl", hash = "sha256:a093fe44fe518cb445d23119511a71f756f8503139d02fcdd1173f7b76c95ffe"}, + {file = "pydantic-1.10.22-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ec54c89b2568b258bb30d7348ac4d82bec1b58b377fb56a00441e2ac66b24587"}, + {file = "pydantic-1.10.22-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d8f1d1a1532e4f3bcab4e34e8d2197a7def4b67072acd26cfa60e92d75803a48"}, + {file = "pydantic-1.10.22-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ad83ca35508c27eae1005b6b61f369f78aae6d27ead2135ec156a2599910121"}, + {file = "pydantic-1.10.22-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:53cdb44b78c420f570ff16b071ea8cd5a477635c6b0efc343c8a91e3029bbf1a"}, + {file = "pydantic-1.10.22-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:16d0a5ae9d98264186ce31acdd7686ec05fd331fab9d68ed777d5cb2d1514e5e"}, + {file = "pydantic-1.10.22-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:8aee040e25843f036192b1a1af62117504a209a043aa8db12e190bb86ad7e611"}, + {file = "pydantic-1.10.22-cp39-cp39-win_amd64.whl", hash = "sha256:7f691eec68dbbfca497d3c11b92a3e5987393174cbedf03ec7a4184c35c2def6"}, + {file = "pydantic-1.10.22-py3-none-any.whl", hash = "sha256:343037d608bcbd34df937ac259708bfc83664dadf88afe8516c4f282d7d471a9"}, + {file = "pydantic-1.10.22.tar.gz", hash = "sha256:ee1006cebd43a8e7158fb7190bb8f4e2da9649719bff65d0c287282ec38dec6d"}, ] [package.dependencies] @@ -2291,30 +2291,30 @@ pyasn1 = ">=0.1.3" [[package]] name = "ruff" -version = "0.11.6" +version = "0.11.7" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" groups = ["format"] files = [ - {file = "ruff-0.11.6-py3-none-linux_armv6l.whl", hash = "sha256:d84dcbe74cf9356d1bdb4a78cf74fd47c740bf7bdeb7529068f69b08272239a1"}, - {file = "ruff-0.11.6-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:9bc583628e1096148011a5d51ff3c836f51899e61112e03e5f2b1573a9b726de"}, - {file = "ruff-0.11.6-py3-none-macosx_11_0_arm64.whl", hash = "sha256:f2959049faeb5ba5e3b378709e9d1bf0cab06528b306b9dd6ebd2a312127964a"}, - {file = "ruff-0.11.6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63c5d4e30d9d0de7fedbfb3e9e20d134b73a30c1e74b596f40f0629d5c28a193"}, - {file = "ruff-0.11.6-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:26a4b9a4e1439f7d0a091c6763a100cef8fbdc10d68593df6f3cfa5abdd9246e"}, - {file = "ruff-0.11.6-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b5edf270223dd622218256569636dc3e708c2cb989242262fe378609eccf1308"}, - {file = "ruff-0.11.6-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:f55844e818206a9dd31ff27f91385afb538067e2dc0beb05f82c293ab84f7d55"}, - {file = "ruff-0.11.6-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d8f782286c5ff562e4e00344f954b9320026d8e3fae2ba9e6948443fafd9ffc"}, - {file = "ruff-0.11.6-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:01c63ba219514271cee955cd0adc26a4083df1956d57847978383b0e50ffd7d2"}, - {file = "ruff-0.11.6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15adac20ef2ca296dd3d8e2bedc6202ea6de81c091a74661c3666e5c4c223ff6"}, - {file = "ruff-0.11.6-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:4dd6b09e98144ad7aec026f5588e493c65057d1b387dd937d7787baa531d9bc2"}, - {file = "ruff-0.11.6-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:45b2e1d6c0eed89c248d024ea95074d0e09988d8e7b1dad8d3ab9a67017a5b03"}, - {file = "ruff-0.11.6-py3-none-musllinux_1_2_i686.whl", hash = "sha256:bd40de4115b2ec4850302f1a1d8067f42e70b4990b68838ccb9ccd9f110c5e8b"}, - {file = "ruff-0.11.6-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:77cda2dfbac1ab73aef5e514c4cbfc4ec1fbef4b84a44c736cc26f61b3814cd9"}, - {file = "ruff-0.11.6-py3-none-win32.whl", hash = "sha256:5151a871554be3036cd6e51d0ec6eef56334d74dfe1702de717a995ee3d5b287"}, - {file = "ruff-0.11.6-py3-none-win_amd64.whl", hash = "sha256:cce85721d09c51f3b782c331b0abd07e9d7d5f775840379c640606d3159cae0e"}, - {file = "ruff-0.11.6-py3-none-win_arm64.whl", hash = "sha256:3567ba0d07fb170b1b48d944715e3294b77f5b7679e8ba258199a250383ccb79"}, - {file = "ruff-0.11.6.tar.gz", hash = "sha256:bec8bcc3ac228a45ccc811e45f7eb61b950dbf4cf31a67fa89352574b01c7d79"}, + {file = "ruff-0.11.7-py3-none-linux_armv6l.whl", hash = "sha256:d29e909d9a8d02f928d72ab7837b5cbc450a5bdf578ab9ebee3263d0a525091c"}, + {file = "ruff-0.11.7-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:dd1fb86b168ae349fb01dd497d83537b2c5541fe0626e70c786427dd8363aaee"}, + {file = "ruff-0.11.7-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d3d7d2e140a6fbbc09033bce65bd7ea29d6a0adeb90b8430262fbacd58c38ada"}, + {file = "ruff-0.11.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4809df77de390a1c2077d9b7945d82f44b95d19ceccf0c287c56e4dc9b91ca64"}, + {file = "ruff-0.11.7-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f3a0c2e169e6b545f8e2dba185eabbd9db4f08880032e75aa0e285a6d3f48201"}, + {file = "ruff-0.11.7-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49b888200a320dd96a68e86736cf531d6afba03e4f6cf098401406a257fcf3d6"}, + {file = "ruff-0.11.7-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:2b19cdb9cf7dae00d5ee2e7c013540cdc3b31c4f281f1dacb5a799d610e90db4"}, + {file = "ruff-0.11.7-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:64e0ee994c9e326b43539d133a36a455dbaab477bc84fe7bfbd528abe2f05c1e"}, + {file = "ruff-0.11.7-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bad82052311479a5865f52c76ecee5d468a58ba44fb23ee15079f17dd4c8fd63"}, + {file = "ruff-0.11.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7940665e74e7b65d427b82bffc1e46710ec7f30d58b4b2d5016e3f0321436502"}, + {file = "ruff-0.11.7-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:169027e31c52c0e36c44ae9a9c7db35e505fee0b39f8d9fca7274a6305295a92"}, + {file = "ruff-0.11.7-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:305b93f9798aee582e91e34437810439acb28b5fc1fee6b8205c78c806845a94"}, + {file = "ruff-0.11.7-py3-none-musllinux_1_2_i686.whl", hash = "sha256:a681db041ef55550c371f9cd52a3cf17a0da4c75d6bd691092dfc38170ebc4b6"}, + {file = "ruff-0.11.7-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:07f1496ad00a4a139f4de220b0c97da6d4c85e0e4aa9b2624167b7d4d44fd6b6"}, + {file = "ruff-0.11.7-py3-none-win32.whl", hash = "sha256:f25dfb853ad217e6e5f1924ae8a5b3f6709051a13e9dad18690de6c8ff299e26"}, + {file = "ruff-0.11.7-py3-none-win_amd64.whl", hash = "sha256:0a931d85959ceb77e92aea4bbedfded0a31534ce191252721128f77e5ae1f98a"}, + {file = "ruff-0.11.7-py3-none-win_arm64.whl", hash = "sha256:778c1e5d6f9e91034142dfd06110534ca13220bfaad5c3735f6cb844654f6177"}, + {file = "ruff-0.11.7.tar.gz", hash = "sha256:655089ad3224070736dc32844fde783454f8558e71f501cb207485fe4eee23d4"}, ] [[package]] @@ -2733,4 +2733,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = "^3.10" -content-hash = "fb48e4bd5f30c14061469b28bacf1f284648934eac48e1eadfecdb29c563a896" +content-hash = "6dc6e4674b88f51d10915491d6adb84d6b93ffbd3b2013967f7c6df7de9174b0" diff --git a/pyproject.toml b/pyproject.toml index 755ccbbd9f..dc30816476 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,12 +8,12 @@ requires-poetry = ">=2.0.0" [tool.poetry.dependencies] python = "^3.10" ops = "^2.20.0" -boto3 = "^1.38.0" +boto3 = "^1.38.2" pgconnstr = "^1.0.1" requests = "^2.32.3" tenacity = "^9.1.2" psycopg2 = "^2.9.10" -pydantic = "^1.10.21" +pydantic = "^1.10.22" jinja2 = "^3.1.6" pysyncobj = "^0.3.14" psutil = "^7.0.0" @@ -40,7 +40,7 @@ opentelemetry-exporter-otlp-proto-http = "1.21.0" optional = true [tool.poetry.group.format.dependencies] -ruff = "^0.11.6" +ruff = "^0.11.7" [tool.poetry.group.lint] optional = true From 74cf17b3078e9f21229b52b365cb3fcb664c168a Mon Sep 17 00:00:00 2001 From: Dragomir Penev <6687393+dragomirp@users.noreply.github.com> Date: Tue, 29 Apr 2025 14:50:57 +0300 Subject: [PATCH 026/112] Mandatory scope for promote action (#856) --- actions.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/actions.yaml b/actions.yaml index 7069c4668e..fb94445f63 100644 --- a/actions.yaml +++ b/actions.yaml @@ -38,7 +38,6 @@ promote-to-primary: params: scope: type: string - default: cluster description: Whether to promote a unit or a cluster. Must be set to either unit or cluster. force: type: boolean From 38c79c73da074662b56efb16e4ec858d2113554c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 30 Apr 2025 13:11:07 +0300 Subject: [PATCH 027/112] Update charmcraft.yaml build tools (#860) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- charmcraft.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/charmcraft.yaml b/charmcraft.yaml index d03da104cf..4d1641575c 100644 --- a/charmcraft.yaml +++ b/charmcraft.yaml @@ -24,10 +24,10 @@ parts: # Use environment variable instead of `--break-system-packages` to avoid failing on older # versions of pip that do not recognize `--break-system-packages` # `--user` needed (in addition to `--break-system-packages`) for Ubuntu >=24.04 - PIP_BREAK_SYSTEM_PACKAGES=true python3 -m pip install --user --upgrade pip==25.0.1 # renovate: charmcraft-pip-latest + PIP_BREAK_SYSTEM_PACKAGES=true python3 -m pip install --user --upgrade pip==25.1 # renovate: charmcraft-pip-latest # Use uv to install poetry so that a newer version of Python can be installed if needed by poetry - curl --proto '=https' --tlsv1.2 -LsSf https://github.com/astral-sh/uv/releases/download/0.6.16/uv-installer.sh | sh # renovate: charmcraft-uv-latest + curl --proto '=https' --tlsv1.2 -LsSf https://github.com/astral-sh/uv/releases/download/0.6.17/uv-installer.sh | sh # renovate: charmcraft-uv-latest # poetry 2.0.0 requires Python >=3.9 if ! "$HOME/.local/bin/uv" python find '>=3.9' then From 573517b6274a6f013ef2228ee2d0759612eee4d5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 4 May 2025 03:43:16 +0300 Subject: [PATCH 028/112] Lock file maintenance Python dependencies (#861) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- poetry.lock | 42 +++++++++++++++++++++--------------------- pyproject.toml | 4 ++-- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/poetry.lock b/poetry.lock index 34e6fcc91c..b9df277227 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2,18 +2,18 @@ [[package]] name = "allure-pytest" -version = "2.14.0" +version = "2.14.1" description = "Allure pytest integration" optional = false python-versions = "*" groups = ["integration"] files = [ - {file = "allure_pytest-2.14.0-py3-none-any.whl", hash = "sha256:6ddb68ef42bd5a2dfbcc136a184bf3e78e631ede7b8c54750026ffd407bda9af"}, - {file = "allure_pytest-2.14.0.tar.gz", hash = "sha256:2b485dc307755f8f3207783a69558ca1cc72f1e2c97bedc65c93fdb77adf328f"}, + {file = "allure_pytest-2.14.1-py3-none-any.whl", hash = "sha256:2d35bee7118b6478acac264cf8e9b401ca9a8b1929cae2afa56c9c79193be3a2"}, + {file = "allure_pytest-2.14.1.tar.gz", hash = "sha256:f5a7469608044869243355ac1c1a97d373501a961076ac876ae29dbc6548920d"}, ] [package.dependencies] -allure-python-commons = "2.14.0" +allure-python-commons = "2.14.1" pytest = ">=4.5.0" [[package]] @@ -34,14 +34,14 @@ pytest = "*" [[package]] name = "allure-python-commons" -version = "2.14.0" +version = "2.14.1" description = "Contains the API for end users as well as helper functions and classes to build Allure adapters for Python test frameworks" optional = false python-versions = ">=3.6" groups = ["integration"] files = [ - {file = "allure_python_commons-2.14.0-py3-none-any.whl", hash = "sha256:9200f40abee697133e9ed9f68887cde996a24b9eb33fcf528da8fe50fae88e43"}, - {file = "allure_python_commons-2.14.0.tar.gz", hash = "sha256:9b217e2f6c74cdbd0e253f89059d4165346e95fcb28228fae333ff4dccea0bd5"}, + {file = "allure_python_commons-2.14.1-py3-none-any.whl", hash = "sha256:cf2bc5fef2c392b1782ee6956fce6641645517b453ff72a901acf20db3d37d36"}, + {file = "allure_python_commons-2.14.1.tar.gz", hash = "sha256:2a18f987c722810ff1cfc1509fad85fbdaabd695770804a1b4c93cf95d3cdd4e"}, ] [package.dependencies] @@ -256,18 +256,18 @@ typecheck = ["mypy"] [[package]] name = "boto3" -version = "1.38.2" +version = "1.38.4" description = "The AWS SDK for Python" optional = false python-versions = ">=3.9" groups = ["main", "integration"] files = [ - {file = "boto3-1.38.2-py3-none-any.whl", hash = "sha256:ef3237b169cd906a44a32c03b3229833d923c9e9733355b329ded2151f91ec0b"}, - {file = "boto3-1.38.2.tar.gz", hash = "sha256:53c8d44b231251fa9421dd13d968236d59fe2cf0421e077afedbf3821653fb3b"}, + {file = "boto3-1.38.4-py3-none-any.whl", hash = "sha256:ab315d38409f5b3262b653a10b0fac786bcff7e51e03dcb99ff38ba16bf85630"}, + {file = "boto3-1.38.4.tar.gz", hash = "sha256:4990df0087fe7be944ba06c2d1e6512b5a24f821af5a4881f24309e13ae29e68"}, ] [package.dependencies] -botocore = ">=1.38.2,<1.39.0" +botocore = ">=1.38.4,<1.39.0" jmespath = ">=0.7.1,<2.0.0" s3transfer = ">=0.12.0,<0.13.0" @@ -276,14 +276,14 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.38.2" +version = "1.38.4" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">=3.9" groups = ["main", "integration"] files = [ - {file = "botocore-1.38.2-py3-none-any.whl", hash = "sha256:5d9cffedb1c759a058b43793d16647ed44ec87072f98a1bd6cd673ac0ae6b81d"}, - {file = "botocore-1.38.2.tar.gz", hash = "sha256:b688a9bd17211a1eaae3a6c965ba9f3973e5435efaaa4fa201f499d3467830e1"}, + {file = "botocore-1.38.4-py3-none-any.whl", hash = "sha256:6206cf07be1069efaead2ddc858eb752dafef276ebbe88ac32b5c427b1d90570"}, + {file = "botocore-1.38.4.tar.gz", hash = "sha256:6143546bb56f1da4dff8d285cb6a3b8b0b6442451fe5937cb48a62bf7275386f"}, ] [package.dependencies] @@ -308,14 +308,14 @@ files = [ [[package]] name = "certifi" -version = "2025.1.31" +version = "2025.4.26" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" groups = ["main", "charm-libs", "integration"] files = [ - {file = "certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe"}, - {file = "certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651"}, + {file = "certifi-2025.4.26-py3-none-any.whl", hash = "sha256:30350364dfe371162649852c63336a15c70c6510c2ad5015b21c2345311805f3"}, + {file = "certifi-2025.4.26.tar.gz", hash = "sha256:0a816057ea3cdefcef70270d2c515e4506bbc954f417fa5ade2021213bb8f0c6"}, ] [[package]] @@ -938,14 +938,14 @@ tomli = {version = "*", markers = "python_version > \"3.6\" and python_version < [[package]] name = "ipython" -version = "8.35.0" +version = "8.36.0" description = "IPython: Productive Interactive Computing" optional = false python-versions = ">=3.10" groups = ["integration"] files = [ - {file = "ipython-8.35.0-py3-none-any.whl", hash = "sha256:e6b7470468ba6f1f0a7b116bb688a3ece2f13e2f94138e508201fad677a788ba"}, - {file = "ipython-8.35.0.tar.gz", hash = "sha256:d200b7d93c3f5883fc36ab9ce28a18249c7706e51347681f80a0aef9895f2520"}, + {file = "ipython-8.36.0-py3-none-any.whl", hash = "sha256:12b913914d010dcffa2711505ec8be4bf0180742d97f1e5175e51f22086428c1"}, + {file = "ipython-8.36.0.tar.gz", hash = "sha256:24658e9fe5c5c819455043235ba59cfffded4a35936eefceceab6b192f7092ff"}, ] [package.dependencies] @@ -2733,4 +2733,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = "^3.10" -content-hash = "6dc6e4674b88f51d10915491d6adb84d6b93ffbd3b2013967f7c6df7de9174b0" +content-hash = "2659005e108122ba58f3de8b027b362c57c7126bd4148ada883b5fa61ccf82ca" diff --git a/pyproject.toml b/pyproject.toml index dc30816476..3a84bbb377 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ requires-poetry = ">=2.0.0" [tool.poetry.dependencies] python = "^3.10" ops = "^2.20.0" -boto3 = "^1.38.2" +boto3 = "^1.38.4" pgconnstr = "^1.0.1" requests = "^2.32.3" tenacity = "^9.1.2" @@ -71,7 +71,7 @@ tenacity = "*" landscape-api-py3 = "^0.9.0" mailmanclient = "^3.3.5" psycopg2-binary = "^2.9.10" -allure-pytest = "^2.14.0" +allure-pytest = "^2.14.1" allure-pytest-default-results = "^0.1.2" # Testing tools configuration From 53608ba28cede00b08c1276b91a8ecf5ee98180d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 5 May 2025 22:53:38 +0200 Subject: [PATCH 029/112] Sync docs from Discourse (#850) Co-authored-by: GitHub Actions <41898282+github-actions[bot]@users.noreply.github.com> --- docs/explanation.md | 4 +- docs/explanation/e-units.md | 93 ++++++++ docs/explanation/e-users.md | 2 +- docs/how-to.md | 25 ++- docs/how-to/h-async-set-up.md | 2 +- docs/how-to/h-deploy-juju-spaces.md | 65 ++++++ docs/how-to/h-deploy-juju-storage.md | 284 ++++++++++++++++++++++++ docs/how-to/h-deploy.md | 22 +- docs/how-to/h-enable-ldap.md | 127 +++++++++++ docs/how-to/h-switchover-failover.md | 176 +++++++++++++++ docs/overview.md | 12 +- docs/reference/r-cli-helpers.md | 278 +++++++++++++++++++++++ docs/reference/r-plugins-timescaledb.md | 93 ++++++++ docs/reference/r-versions.md | 124 +++++++++++ 14 files changed, 1288 insertions(+), 19 deletions(-) create mode 100644 docs/explanation/e-units.md create mode 100644 docs/how-to/h-deploy-juju-spaces.md create mode 100644 docs/how-to/h-deploy-juju-storage.md create mode 100644 docs/how-to/h-enable-ldap.md create mode 100644 docs/how-to/h-switchover-failover.md create mode 100644 docs/reference/r-cli-helpers.md create mode 100644 docs/reference/r-plugins-timescaledb.md create mode 100644 docs/reference/r-versions.md diff --git a/docs/explanation.md b/docs/explanation.md index 05c2add64e..0883e615df 100644 --- a/docs/explanation.md +++ b/docs/explanation.md @@ -9,9 +9,10 @@ This section contains pages with more detailed explanations that provide additio * [Legacy charm] ## Operational concepts -* [Connection pooling] +* [Units] * [Users] * [Logs] +* [Connection pooling] ## Security and hardening * [Security hardening guide][Security] @@ -22,6 +23,7 @@ This section contains pages with more detailed explanations that provide additio [Architecture]: /t/11857 [Interfaces and endpoints]: /t/10251 +[Units]: /t/17525 [Users]: /t/10798 [Logs]: /t/12099 [Juju]: /t/11985 diff --git a/docs/explanation/e-units.md b/docs/explanation/e-units.md new file mode 100644 index 0000000000..762a5d0089 --- /dev/null +++ b/docs/explanation/e-units.md @@ -0,0 +1,93 @@ +# PostgreSQL units + +Each [HA](https://en.wikipedia.org/wiki/High_availability)/[DR](https://en.wikipedia.org/wiki/IT_disaster_recovery) implementation has a primary and secondary (standby) site(s). +Charmed PostgreSQL cluster size can be [easily scaled](/t/11863) from 0 to 10 units ([contact us](/t/11863) for 10+ units cluster). It is recommended to use 3+ units cluster size in production (due to [Raft consensus](https://en.wikipedia.org/wiki/Raft_(algorithm)) requirements). Those units type can be: + * **Primary**: unit which accepts all writes and guaranties [no split brain](https://en.wikipedia.org/wiki/Split-brain_(computing)). + * **Sync Standby** (synchronous copy) : designed for the fast automatic failover. Used for read-only queries and guaranties the latest transaction availability. + * **Replica** (asynchronous copy): designed for long-running and resource consuming queries without affecting Primary performance. Used for read-only queries without guaranties of the latest transaction availability. + +> **Warning**: all SQL transactions have to be confirmed by all Sync Standby unit(s) before Primary unit commit transaction to the client. Therefor the high-performance and high-availability is a trade-of balance between "Sync Standby" and "Replica" units count in the cluster. + +> **Note**: starting from revision 561 all Charmed PostgreSQL units are configured as Sync Standby members. It provides better guaranties for the data survival when two of three units gone simultaneously. Users can re-configure the necessary synchronous units count using Juju config option '[synchronous_node_count](https://charmhub.io/postgresql/configurations?channel=14/edge#synchronous_node_count)'. + +![PostgreSQL Units types|690x253, 100%](upload://pY5kzxO9ELJGEqEe1F1RQjOG6SS.png) + +## Primary + +The simplest way to find the Primary unit is to run `juju status`. Please be aware that the information here can be outdated as it is being updated only on [Juju event 'update-status'](https://documentation.ubuntu.com/juju/3.6/reference/hook/#update-status): +```shell +ubuntu@juju360:~$ juju status postgresql +Model Controller Cloud/Region Version SLA Timestamp +postgresql lxd localhost/localhost 3.6.5 unsupported 13:04:15+02:00 + +App Version Status Scale Charm Channel Rev Exposed Message +postgresql 14.15 active 3 postgresql 14/stable 553 no + +Unit Workload Agent Machine Public address Ports Message +postgresql/0* active idle 0 10.189.210.53 5432/tcp Primary <<<<<<<<<<<<<< +postgresql/1 active idle 1 10.189.210.166 5432/tcp +postgresql/2 active idle 2 10.189.210.188 5432/tcp + +Machine State Address Inst id Base AZ Message +0 started 10.189.210.53 juju-422c1a-0 ubuntu@22.04 Running +1 started 10.189.210.166 juju-422c1a-1 ubuntu@22.04 Running +2 started 10.189.210.188 juju-422c1a-2 ubuntu@22.04 Running +``` + +The up-to-date Primary unit number can be received using Juju action `get-primary`: +```shell +> juju run postgresql/leader get-primary +... +primary: postgresql/0 +``` + +Also it is possible to retrieve this information using [patronictl](/t/17406#p-37204-patronictl-3) and [Patroni REST API](/t/17406#p-37204-patroni-rest-api-8). + +## Standby / Replica + +At the moment it is possible to retrieve this information using [patronictl](/t/17406#p-37204-patronictl-3) and [Patroni REST API](/t/17406#p-37204-patroni-rest-api-8) only (check the linked documentation for the access details). Example: +```shell +> ... patronictl ... list ++ Cluster: postgresql (7499430436963402504) ---+-----------+----+-----------+ +| Member | Host | Role | State | TL | Lag in MB | ++--------------+----------------+--------------+-----------+----+-----------+ +| postgresql-0 | 10.189.210.53 | Leader | running | 1 | | +| postgresql-1 | 10.189.210.166 | Sync Standby | streaming | 1 | 0 | +| postgresql-2 | 10.189.210.188 | Replica | streaming | 1 | 0 | ++--------------+----------------+--------------+-----------+----+-----------+ +``` +On the example above: +* `postgresql-0` is a PostgreSQL Primary unit (Patroni Leader) which accepts all writes +* `postgresql-1` is a PostgreSQL/Patroni Sync Standby unit which can be promoted as new primary using manual switchover (safe). +* `postgresql-2` is a PostgreSQL/Patroni Replica unit which can NOT be directly promoted as a new Primary using manual switchover. The automatic promotion Replica=>Sync Standby is necessary to guaranties the latest SQL transactions availability on this unit to allow further promotion as a new Primary. Otherwise the manual failover can be performed to Replica unit accepting the risks of loosing the last transactions(s) which lagged behind Primary. + +## Replica lag distance + +At the moment it is possible to retrieve this information using [patronictl](/t/17406#p-37204-patronictl-3) and [Patroni REST API](/t/17406#p-37204-patroni-rest-api-8) only (check the linked documentation for the access details). Example: +```shell +> ... patronictl ... list ++ Cluster: postgresql (7499430436963402504) ---+-----------+----+-----------+ +| Member | Host | Role | State | TL | Lag in MB | ++--------------+----------------+--------------+-----------+----+-----------+ +| postgresql-0 | 10.189.210.53 | Leader | running | 1 | | +| ... +| postgresql-2 | 10.189.210.188 | Replica | streaming | 1 | 42 | <<<<< ++--------------+----------------+--------------+-----------+----+-----------+ + +> curl ... x.x.x.x:8008/cluster | jq + "members": [ + { + "name": "postgresql-0", + "role": "leader", + "state": "running", + ... + }, +... + { + "name": "postgresql-2", + "role": "replica", + "state": "streaming", + ... + "lag": 42 <<<<<<<<<<<< Lag in MB + } +``` \ No newline at end of file diff --git a/docs/explanation/e-users.md b/docs/explanation/e-users.md index f0f9ce86da..f5e233da94 100644 --- a/docs/explanation/e-users.md +++ b/docs/explanation/e-users.md @@ -1,4 +1,4 @@ -# Charm Users explanations +# Users There are three types of users in PostgreSQL: * Internal users (used by charm operator) diff --git a/docs/how-to.md b/docs/how-to.md index c21e3a5086..c4ecd48b71 100644 --- a/docs/how-to.md +++ b/docs/how-to.md @@ -13,10 +13,12 @@ Installation of different cloud services with Juju: * [Azure] * [Multi-availability zones (AZ)][Multi-AZ] -Specific deployment scenarios and architectures: -* [Terraform] -* [Air-gapped] +Other deployment scenarios and configurations: * [TLS VIP access] +* [Juju spaces] +* [Air-gapped] +* [Terraform] +* [Juju storage] ## Usage and maintenance @@ -25,6 +27,7 @@ Specific deployment scenarios and architectures: * [Scale replicas] * [Enable TLS] * [Enable plugins/extensions] +* [Switchover/failover] ## Backup and restore * [Configure S3 AWS] @@ -36,9 +39,10 @@ Specific deployment scenarios and architectures: ## Monitoring (COS) -* [Enable monitoring] -* [Enable alert rules] -* [Enable tracing] +* [Enable monitoring] with Grafana +* [Enable alert rules] with Prometheus +* [Enable tracing] with Tempo +* [Enable profiling] with Parca ## Minor upgrades * [Perform a minor upgrade] @@ -69,13 +73,17 @@ This section is for charm developers looking to support PostgreSQL integrations [GCE]: /t/15722 [Azure]: /t/15733 [Multi-AZ]: /t/15749 +[TLS VIP access]: /t/16576 +[Juju spaces]: /t/17416 [Terraform]: /t/14916 [Air-gapped]: /t/15746 -[TLS VIP access]: /t/16576 +[Juju storage]: /t/17529 + [Integrate with another application]: /t/9687 [External access]: /t/15802 [Scale replicas]: /t/9689 [Enable TLS]: /t/9685 +[Switchover/failover]: /t/17523 [Configure S3 AWS]: /t/9681 [Configure S3 RadosGW]: /t/10313 @@ -87,7 +95,8 @@ This section is for charm developers looking to support PostgreSQL integrations [Enable monitoring]: /t/10600 [Enable alert rules]: /t/13084 [Enable tracing]: /t/14521 - +[Enable profiling]: /t/17172 + [Perform a minor upgrade]: /t/12089 [Perform a minor rollback]: /t/12090 diff --git a/docs/how-to/h-async-set-up.md b/docs/how-to/h-async-set-up.md index 4c8e73b71a..e3a9518115 100644 --- a/docs/how-to/h-async-set-up.md +++ b/docs/how-to/h-async-set-up.md @@ -62,7 +62,7 @@ juju run -m rome db1/leader create-replication To switchover and use `lisbon` as the primary instead, run ```shell -juju run -m lisbon db2/leader promote-to-primary +juju run -m lisbon db2/leader promote-to-primary scope=cluster ``` ## Scale a cluster diff --git a/docs/how-to/h-deploy-juju-spaces.md b/docs/how-to/h-deploy-juju-spaces.md new file mode 100644 index 0000000000..b9cbe1e5d9 --- /dev/null +++ b/docs/how-to/h-deploy-juju-spaces.md @@ -0,0 +1,65 @@ +# Deploy on Juju spaces + +The Charmed PostgreSQL operator supports [Juju spaces](https://documentation.ubuntu.com/juju/latest/reference/space/index.html) to separate network traffic for: +- **Client** - PostgreSQL instance to client data +- **Instance-replication** - cluster instances replication data +- **Cluster-replication** - cluster to cluster replication data +- **Backup** - backup and restore data + +## Prerequisites + +* **Charmed PostgreSQL 16** +* Configured network spaces + * See [Juju | How to manage network spaces](https://documentation.ubuntu.com/juju/latest/reference/juju-cli/list-of-juju-cli-commands/add-space/) + +## Deploy + +On application deployment, constraints are required to ensure the unit(s) have address(es) on the specified network space(s), and endpoint binding(s) for the space(s). + +For example, with spaces configured for instance replication and client traffic: +```shell +❯ juju spaces +Name Space ID Subnets +alpha 0 10.163.154.0/24 +client 1 10.0.0.0/24 +peers 2 10.10.10.0/24 +``` + +The space `alpha` is default and cannot be removed. To deploy Charmed PostgreSQL Operator using the spaces: +```shell +juju deploy postgresql --channel 16/edge \ + --constraints spaces=client,peers \ + --bind "database-peers=peers database=client" +``` + +[note type=caution] +Currently there's no support for the juju `bind` command. Network space binding must be defined at deploy time only. +[/note] + +Consequently, a client application must use the `client` space on the model, or a space for the same subnet in another model, for example: +```shell +juju deploy client-app \ + --constraints spaces=client \ + --bind database=client +``` + +The two application can be then related using: +```shell +juju integrate postgresql:database client-app:database +``` + +The client application will receive network endpoints on the `10.0.0.0/24` subnet. + +The Charmed PostgreSQL operator endpoints are: + +| Endpoint | Traffic | +| ------------------------------ | -------------------- | +| database | Client | +| database-peers | Instance-replication | +| replication-offer, replication | Cluster-replication | +| s3-parameters | Backup | + + +[note] +If using a network space for the backup traffic, the user is responsible for ensuring that the target object storage URL traffic is routed via the specified network space. +[/note] \ No newline at end of file diff --git a/docs/how-to/h-deploy-juju-storage.md b/docs/how-to/h-deploy-juju-storage.md new file mode 100644 index 0000000000..43ea636938 --- /dev/null +++ b/docs/how-to/h-deploy-juju-storage.md @@ -0,0 +1,284 @@ +# Deploy on Juju storage + +Charmed PostgreSQL uses the [Juju storage](https://documentation.ubuntu.com/juju/3.6/reference/storage/) abstraction to utilize data volume provided by different [clouds](https://documentation.ubuntu.com/juju/3.6/reference/cloud/#cloud) while keeping the same UI/UX for end users. + +* **Charmed PostgreSQL** [**16**](https://charmhub.io/postgresql?channel=16/candidate) supports multiple storage: `archive`, `data`, `logs` and `temp`. +* **Charmed PostgreSQL** [**14**](https://charmhub.io/postgresql?channel=14/stable) supports single storage: `pgdata`. +* [Legacy PostgreSQL charm](/t/10690) in track "[latest](https://charmhub.io/postgresql?channel=14/stable)" does **not** support the Juju storage abstraction. + +## Charmed PostgreSQL 16 + +Check the [`metadata.yaml`](https://github.com/canonical/postgresql-operator/blob/16/edge/metadata.yaml) for find Juju storage name and tech details: + +[details="Charmed PostgreSQL 16 storage list"] +```shell +storage: + archive: + type: filesystem + location: /var/snap/charmed-postgresql/common/data/archive + data: + type: filesystem + location: /var/snap/charmed-postgresql/common/var/lib/postgresql + logs: + type: filesystem + location: /var/snap/charmed-postgresql/common/data/logs + temp: + type: filesystem + location: /var/snap/charmed-postgresql/common/data/temp +``` +[/details] + +Charmed PostgreSQL 16 supports multiple storage `archive` , `data` , `logs` and `temp` . See the deployment examples below. + +## Charmed PostgreSQL 14 + +Check the [metadata.yaml](https://github.com/canonical/postgresql-operator/blob/main/metadata.yaml) for find Juju storage name and tech details: +[details="Charmed PostgreSQL 14 storage list"] +```shell +storage: + pgdata: + type: filesystem + location: /var/snap/charmed-postgresql/common +``` +[/details] + +Charmed PostgreSQL 14 supports single storage `pgdata` attaching it on `juju deploy` and mounted inside the Snap common folder `/var/snap/charmed-postgresql/common`. + +[details="Example of 'Juju storage'"] +```shell +> juju deploy postgresql + +> juju storage +Unit Storage ID Type Size Status Message +postgresql/0 pgdata/0 filesystem pending + +> juju storage +Unit Storage ID Type Pool Size Status Message +postgresql/0 pgdata/0 filesystem rootfs 97 GiB attached + +> juju show-storage pgdata/0 +pgdata/0: + kind: filesystem + life: alive + status: + current: attached + since: 01 May 2025 18:47:04+02:00 + persistent: false + attachments: + units: + postgresql/0: + machine: "0" + location: /var/snap/charmed-postgresql/common + life: alive + +> juju ssh postgresql/0 mount | grep /var/snap/charmed-postgresql/common +/dev/sda1 on /var/snap/charmed-postgresql/common type ext4 (rw,relatime,discard,errors=remount-ro) +``` +[/details] + +## Deployment examples + +### Define the storage size + +```shell +> juju deploy postgresql --storage pgdata=10G + +> juju storage +Unit Storage ID Type Pool Size Status Message +postgresql/1 pgdata/1 filesystem lxd 10 GiB attached +``` + +### Define the storage location + +Juju supports wide list of different [storage pools](https://bobcares.com/blog/lxd-create-storage-pool/): + +```shell +> juju create-storage-pool mystoragepool lxd + +> juju storage-pools | grep mystoragepool +mystoragepool lxd + +> juju deploy postgresql --storage pgdata=5G,mystoragepool + +> juju storage +Unit Storage ID Type Pool Size Status Message +postgresql/2 pgdata/2 filesystem mystoragepool 5 GiB attached +``` + +### Re-deploy detached storage (track `14`) + +To re-deploy the application with the old Juju storage, it is necessary to provide all charm/database credentials to the new charm or app. + +**Charmed PostgreSQL 14 uses the Juju action `set-password` to handle credentials:** +```shell +# Note old passwords +> juju show-secret --reveal database-peers.postgresql.app + +# Find old storage id: +> juju storage + +# Re-deploy new app one unit only to set old passwords +> juju deploy postgresql --channel 14/stable -n 1 + +# Once deployed, set old passwords from old app Juju App secrets +juju run postgresql/leader set-password username=operator password=cpUJnNRJ6Qt2Hgli +juju run postgresql/leader set-password username=patroni password=0N7pKAutKCstPuvx +juju run postgresql/leader set-password username=raft password=8xSZvTLfyHpglGfI +juju run postgresql/leader set-password username=replication password=5xN9gj9uu5Um3PWB +juju run postgresql/leader set-password username=rewind password=wuEsPmsdpc6L8qhT +juju run postgresql/leader set-password username=monitoring password=AgOxXzcRD5iohE6C + +# Scale down to zero units byt removing all Juju units +> juju remove-unit postgresql/1 --destroy-storage=yes + +# Scale up to one unit and attach the old Juju storage +> juju add-unit postgresql --attach-storage pgdata/x + +# If no issues noticed, scale to HA (3 units total) +> juju add-unit postgresql -n 2 +``` + +### Re-deploy detached storage (track `16`) + +To re-deploy the application with the old Juju storage, it is necessary to provide all charm/database credentials as Juju user secrets. + +**Charmed PostgreSQL 16 uses Juju user secrets to handle credentials:** +```shell +# Note old passwords +> juju show-secret --reveal database-peers.postgresql.app + +# Add new Juju User secret with old password values +> juju add-secret mypgpass \ + monitoring-password=oQDLAVMV1AHFZq1L \ + operator-password=IXarOnndC9XKoytS \ + patroni-password=vWzJZIktqi0qGMCx \ + raft-password=2pALATzLJsrpAf5q \ + replication-password=2bcnAQhXLrX3ekVP \ + rewind-password=bBqQOXiC7whSqQbR + +# Find old storage id: +> juju storage + +# Re-deploy new app re-using old storage and old credentials +> juju deploy postgresql \ + --channel 16/candidate \ + --attach-storage pgdata/5 \ + --config system-users=newsecret54321id + +# Grant access to new secrets for re-deployed application +> juju grant-secret mypgpass postgresql +``` + +[details="Example: Complete old storage re-deployment (track 16)"] +Prepare the test data to restore later: +```shell +# Add a new model +> juju add-model teststorage + +# Deploy the new postgresql to dump storage with credentials +> juju deploy postgresql --channel 16/edge --storage pgdata=5Gcompleted +Deployed "postgresql" from charm-hub charm "postgresql", revision 613 in channel 16/edge on ubuntu@24.04/stable + +# Wait for deployment completed: +> juju status +... +Unit Workload Agent Machine Public address Ports Message +postgresql/0* active idle 0 10.189.210.99 5432/tcp Primary + +# Reveal the Juju secrets for the simpliest DB access: +> juju show-secret --reveal database-peers.postgresql.app +d09v83poie738j7af4n0: + revision: 2 + checksum: 9e28910800d4dd94cd655d5d5f49a9bb7e4b7fbf6dde232328e4f6734c7bdf84 + owner: postgresql + label: database-peers.postgresql.app + created: 2025-05-01T22:22:07Z + updated: 2025-05-01T22:22:10Z + content: + monitoring-password: 6inFApK8IyJuJ6LG + operator-password: I8mkza6vIhD2w1Rh + patroni-password: JAYSlB3mQXi9g4fc + raft-password: eFWUOCYb1lIOpGuM + replication-password: SFBx8OL9XxXiWwcC + rewind-password: 92xT4yTniiG7OEch + +# Create a test data +> PGPASSWORD=I8mkza6vIhD2w1Rh psql -h 10.189.210.99 -U operator -d postgres -c "create table a (id int);" +CREATE TABLE +> PGPASSWORD=I8mkza6vIhD2w1Rh psql -h 10.189.210.99 -U operator -d postgres -c "\d" + List of relations + Schema | Name | Type | Owner +--------+------+-------+---------- + public | a | table | operator +(1 row) + +# Check the storage status +> juju storage +Unit Storage ID Type Pool Size Status Message +postgresql/0 pgdata/0 filesystem lxd 5.0 GiB attached + +# Remove the old application keeping the storage: +> juju remove-application postgresql --destroy-storage=false +WARNING This command will perform the following actions: +will remove application postgresql +- will remove unit postgresql/0 +- will detach storage pgdata/0 +Continue [y/N]? y + +# Check the status (app and secrets are gone, but storage stays): +> juju status +Model Controller Cloud/Region Version SLA Timestamp +teststorage lxd localhost/localhost 3.6.5 unsupported 00:28:44+02:00 + +Model "admin/teststorage" is empty. + +> juju secrets +ID Name Owner Rotation Revision Last updated + +> juju storage +Unit Storage ID Type Pool Size Status Message + pgdata/0 filesystem lxd 5.0 GiB detached +``` + +Re-deploy the postgresql application reusing storage `pgdata/0 `: +```shell +# Create a new Juju User secret +> juju add-secret mypgpass \ + monitoring-password=6inFApK8IyJuJ6LG \ + operator-password=I8mkza6vIhD2w1Rh \ + patroni-password=JAYSlB3mQXi9g4fc \ + raft-password=eFWUOCYb1lIOpGuM \ + replication-password=SFBx8OL9XxXiWwcC \ + rewind-password=92xT4yTniiG7OEch +secret:d09vcn1oie738j7af4ng + +# Re-deploy app with old storage and old passwords +> juju deploy postgresql \ + --channel 16/edge \ + --attach-storage pgdata/0 \ + --config system-users=d09vcn1oie738j7af4ng +Deployed "postgresql" from charm-hub charm "postgresql", revision 613 in channel 16/edge on ubuntu@24.04/stable + +# Grant new application access to manually created Juju User secret +> juju grant-secret mypgpass postgresql + +# Wait for deployment +> juju status +... +Unit Workload Agent Machine Public address Ports Message +postgresql/1* active idle 1 10.189.210.179 5432/tcp Primary + +# Check the old data access once deployment completed (use new App IP!): +> PGPASSWORD=I8mkza6vIhD2w1Rh psql -h 10.189.210.179 -U operator -d postgres -c "\d" + List of relations + Schema | Name | Type | Owner +--------+------+-------+---------- + public | a | table | operator +(1 row) + +# Old storage re-used: +> juju storage +Unit Storage ID Type Pool Size Status Message +postgresql/1 pgdata/0 filesystem lxd 5.0 GiB attached +``` +[/details] \ No newline at end of file diff --git a/docs/how-to/h-deploy.md b/docs/how-to/h-deploy.md index f73fcb80ac..5e60f3879e 100644 --- a/docs/how-to/h-deploy.md +++ b/docs/how-to/h-deploy.md @@ -19,13 +19,13 @@ juju add-model Then, either continue with the `juju` client **or** use the `terraform juju` client to deploy the PostgreSQL charm. -To deploy with the `juju` client: +**To deploy with the `juju` client:** ```shell juju deploy postgresql -n ``` > See also: [`juju deploy` command](https://canonical-juju.readthedocs-hosted.com/en/latest/user/reference/juju-cli/list-of-juju-cli-commands/deploy/) -To deploy with `terraform juju`, follow the guide [How to deploy using Terraform]. +**To deploy with `terraform juju`**, follow the guide [How to deploy using Terraform]. > See also: [Terraform Provider for Juju documentation](https://canonical-terraform-provider-juju.readthedocs-hosted.com/en/latest/) If you are not sure where to start or would like a more guided walkthrough for setting up your environment, see the [Charmed PostgreSQL tutorial][Tutorial]. @@ -41,17 +41,20 @@ The guides below go through the steps to install different cloud services and bo [How to deploy on multiple availability zones (AZ)] demonstrates how to deploy a cluster on a cloud using different AZs for high availability. -## Special deployments +## Special deployment scenarios -These guides cover some specific deployment scenarios and architectures. +These guides cover some specific deployment scenarios and configurations. + +### Networking -### External TLS access [How to deploy for external TLS VIP access] goes over an example deployment of PostgreSQL, PgBouncer and HAcluster that require external TLS/SSL access via [Virtual IP (VIP)](https://en.wikipedia.org/wiki/Virtual_IP_address). See also: * [How to enable TLS] * [How to connect from outside the local network] +[How to deploy on juju spaces] goes over how to configure your deployment of PostgreSQL and client application to use juju spaces to separate network traffic. + ### Airgapped [How to deploy in an offline or air-gapped environment] goes over the special configuration steps for installing PostgreSQL in an airgapped environment via CharmHub and the Snap Store Proxy. @@ -60,6 +63,11 @@ Cluster-cluster, cross-regional, or multi-server asynchronous replication focuse The [Cross-regional async replication] guide goes through the steps to set up clusters for cluster-cluster replication, integrate with a client, and remove or recover a failed cluster. +### Juju storage +Charmed PostgreSQL uses the [Juju storage](https://documentation.ubuntu.com/juju/3.6/reference/storage/) abstraction to utilize data volume provided by different clouds while keeping the same UI/UX for end users. + +See: [How to deploy on juju storage] + --- @@ -78,6 +86,8 @@ The [Cross-regional async replication] guide goes through the steps to set up cl [How to deploy for external TLS VIP access]: /t/16576 [How to enable TLS]: /t/9685 [How to connect from outside the local network]: /t/15802 +[How to deploy on juju spaces]: /t/17416 [How to deploy in an offline or air-gapped environment]: /t/15746 -[Cross-regional async replication]: /t/15412 \ No newline at end of file +[Cross-regional async replication]: /t/15412 +[How to deploy on juju storage]: /t/17529 \ No newline at end of file diff --git a/docs/how-to/h-enable-ldap.md b/docs/how-to/h-enable-ldap.md new file mode 100644 index 0000000000..a37a00d526 --- /dev/null +++ b/docs/how-to/h-enable-ldap.md @@ -0,0 +1,127 @@ +[note] +**Note**: All commands are written for `juju >= v.3.0` + +If you are using an earlier version, check the [Juju 3.0 Release Notes](https://juju.is/docs/juju/roadmap#heading--juju-3-0-0---22-oct-2022). +[/note] + +[note] +LDAP is available on channels: `14/edge` and `16/edge`, from revision `600`. +[/note] + + +# How to enable LDAP authentication + +LDAP (*Lightweight Directory Access Protocol*) enables centralized authentication for PostgreSQL clusters, reducing the overhead of managing local credentials and access policies. + +This guide goes over the steps to integrate LDAP as an authentication method with the PostgreSQL charm, all within the Juju ecosystem. + +## Deploy an LDAP server in a K8s environment + +[note type="caution"] +**Disclaimer:** In this guide, we use [self-signed certificates](https://en.wikipedia.org/wiki/Self-signed_certificate) provided by the [`self-signed-certificates` operator](https://github.com/canonical/self-signed-certificates-operator). + +**This is not recommended for a production environment.** + +For production environments, check the collection of [Charmhub operators](https://charmhub.io/?q=tls-certificates) that implement the `tls-certificate` interface, and choose the most suitable for your use-case. +[/note] + +Switch to the Kubernetes controller: + +```shell +juju switch +``` + +Deploy the [GLAuth charm](https://charmhub.io/glauth-k8s): +```shell +juju add-model glauth +juju deploy self-signed-certificates +juju deploy postgresql-k8s --channel 14/stable --trust +juju deploy glauth-k8s --channel edge --trust +``` + +Integrate (formerly known as "relate") the three applications: +```shell +juju integrate glauth-k8s:certificates self-signed-certificates +juju integrate glauth-k8s:pg-database postgresql-k8s +``` + +Deploy the [GLAuth-utils charm](https://charmhub.io/glauth-utils), in order to manage LDAP users: + +```shell +juju deploy glauth-utils --channel edge --trust +``` + +Integrate (formerly known as "relate") the two applications: + +```shell +juju integrate glauth-k8s glauth-utils +``` + +## Expose cross-controller URLs + +Enable the required micro-k8s plugin: + +```shell +IPADDR=$(ip -4 -j route get 2.2.2.2 | jq -r '.[] | .prefsrc') +sudo microk8s enable metallb $IPADDR-$IPADDR +``` + +Deploy the [Traefik charm](https://charmhub.io/traefik-k8s), in order to expose endpoints from the K8s cluster: + +```shell +juju deploy traefik-k8s --trust +``` + +Integrate (formerly known as "relate") the two applications: + +```shell +juju integrate glauth-k8s:ingress traefik-k8s +``` + +## Expose cross-model relations + +To offer the GLAuth interfaces, run: + +```shell +juju offer glauth-k8s:ldap ldap +juju offer glauth-k8s:send-ca-cert send-ca-cert +``` + +## Enable LDAP + +Switch to the VM controller: + +```shell +juju switch :postgresql +``` + +To have LDAP offers consumed: + +```shell +juju consume :admin/glauth.ldap +juju consume :admin/glauth.send-ca-cert +``` + +To have LDAP authentication enabled, integrate the PostgreSQL charm with the GLAuth charm: + +```shell +juju integrate postgresql:ldap ldap +juju integrate postgresql:receive-ca-cert send-ca-cert +``` + +## Map LDAP users to PostgreSQL + +To have LDAP users available in PostgreSQL, provide a comma separated list of LDAP groups to already created PostgreSQL authorization groups. To create those groups before hand, refer to the Data Integrator charm [page](https://charmhub.io/data-integrator). + +```shell +juju config postgresql ldap_map="=" +``` + +## Disable LDAP + +You can disable LDAP removing the following relations: + +```shell +juju remove-relation postgresql.receive-ca-cert send-ca-cert +juju remove-relation postgresql.ldap ldap +``` \ No newline at end of file diff --git a/docs/how-to/h-switchover-failover.md b/docs/how-to/h-switchover-failover.md new file mode 100644 index 0000000000..a2e6c481a3 --- /dev/null +++ b/docs/how-to/h-switchover-failover.md @@ -0,0 +1,176 @@ +# PostgreSQL Switchover / Failover + +Charmed PostgreSQL constantly monitors the cluster status and performs **automated failover** in case of Primary unit gone. Sometimes **manual switchover** is necessary for hardware maintenance reasons. Check the difference between them [here](https://dbvisit.com/blog/difference-between-failover-vs-switchover). + +The [manual switchover](https://en.wikipedia.org/wiki/Switchover) is possible using Juju action [promote-to-primary](https://charmhub.io/postgresql/actions#promote-to-primary). + +> **Important**: Charmed PostgreSQL has been designed to provide maximum guaranties for the data survival in all corner cases, therefor allowed actions depends on the configured [Juju unit state](/t/17525). + +## Switchover + +To switchover the PostgreSQL Primary (write-endpoint) to new Juju unit, use Juju action `promote-to-primary` (on the unit `x`, which will be promoted as a new Primary): +```shell +juju run postgresql/x promote-to-primary scope=unit +``` +> **Note**: The manual switchover is possible on the healthy '[Sync Standby](/t/17525)' unit only. Otherwise it will be rejected by Patroni with the reason explanation. + +> **Note**: It is a normal situation when [Juju leader](https://documentation.ubuntu.com/juju/3.6/reference/unit/#leader-unit) unit and PostgreSQL Primary unit are pointing to different [Juju units](https://documentation.ubuntu.com/juju/3.6/reference/unit/). Juju Leader failover is fully automated and can be [enforced](https://github.com/canonical/jhack?tab=readme-ov-file#elect) for educational purpose only! Do NOT trigger Juju leader election for Primary moves. + +## Failover + +Charmed PostgreSQL doesn't provide manual failover due to lack of data safety guaranties. +Advanced users can still execute it using [patronictl](/t/17406#p-37204-patronictl-3) and [Patroni REST API](/t/17406#p-37204-patroni-rest-api-8). The same time Charmed PostgreSQL allows the cluster recovery using the full PostgreSQL/Patroni/Raft cluster re-initialization. + +## Raft re-initialization + +> **Warning**: this is the worst possible recovery case scenario when Primary and ALL Sync Standby units lost simultaneously and their data cannot be recovered from the disc. In this case Patroni cannot perform automatic failover for the only available Replica(s) units. Still Patroni provides the read-only access to the data. +> +> The manual failover procedure cannot guaranty the latest SQL transactions availability on the Replica unit(s) (due to the [lag distance](/t/17525#p-37314-replica-lag-disctance-4) to Primary)! Also Raft cluster consensus is not possible when one unit left in three units cluster. + +The command to re-init Raft cluster should be executed when charm is ready: +* the one/last Juju unit is available in Juju application +* the last unit was has detected Raft majority lost, status: `Raft majority loss, run: promote-to-primary` + +To re-initialize Raft and fix the Partition/PostgreSQL cluster (when requested): +```shell +juju run postgresql/x promote-to-primary scope=unit force=true +``` + +[details="Example of Raft re-initialization"] +Deploy PostgreSQL 3 units: +```shell +> juju deploy postgresql --config synchronous_node_count=1 + +> juju status +Model Controller Cloud/Region Version SLA Timestamp +postgresql lxd localhost/localhost 3.6.5 unsupported 14:50:19+02:00 + +App Version Status Scale Charm Channel Rev Exposed Message +postgresql 14.17 active 3 postgresql 14/edge 615 no + +Unit Workload Agent Machine Public address Ports Message +postgresql/0* active idle 0 10.189.210.53 5432/tcp +postgresql/1 active idle 1 10.189.210.166 5432/tcp +postgresql/2 active idle 2 10.189.210.188 5432/tcp Primary + +Machine State Address Inst id Base AZ Message +0 started 10.189.210.53 juju-422c1a-0 ubuntu@22.04 Running +1 started 10.189.210.166 juju-422c1a-1 ubuntu@22.04 Running +2 started 10.189.210.188 juju-422c1a-2 ubuntu@22.04 Running +``` +Find the current Primary/Standby/Replica: +```shell +> juju ssh postgresql/0 +ubuntu@juju-422c1a-0:~$ sudo -u snap_daemon patronictl -c /var/snap/charmed-postgresql/current/etc/patroni/patroni.yaml list ++ Cluster: postgresql (7499430436963402504) ---+-----------+----+-----------+ +| Member | Host | Role | State | TL | Lag in MB | ++--------------+----------------+--------------+-----------+----+-----------+ +| postgresql-0 | 10.189.210.53 | Sync Standby | streaming | 3 | 0 | +| postgresql-1 | 10.189.210.166 | Replica | streaming | 3 | 0 | +| postgresql-2 | 10.189.210.188 | Leader | running | 3 | | ++--------------+----------------+--------------+-----------+----+-----------+ +``` + +Kill the Leader and Sync Standby machines: +```shell +> lxc stop --force juju-422c1a-0 && lxc stop --force juju-422c1a-2 + +> juju status +Model Controller Cloud/Region Version SLA Timestamp +postgresql lxd localhost/localhost 3.6.5 unsupported 14:54:40+02:00 + +App Version Status Scale Charm Channel Rev Exposed Message +postgresql 14.17 active 1/3 postgresql 14/edge 615 no + +Unit Workload Agent Machine Public address Ports Message +postgresql/0 unknown lost 0 10.189.210.53 5432/tcp agent lost, see 'juju show-status-log postgresql/0' +postgresql/1* active idle 1 10.189.210.166 5432/tcp <<<<<<<<< Replica unit left only +postgresql/2 unknown lost 2 10.189.210.188 5432/tcp agent lost, see 'juju show-status-log postgresql/2' + +Machine State Address Inst id Base AZ Message +0 down 10.189.210.53 juju-422c1a-0 ubuntu@22.04 Running +1 started 10.189.210.166 juju-422c1a-1 ubuntu@22.04 Running +2 down 10.189.210.188 juju-422c1a-2 ubuntu@22.04 Running +``` +At this stage it is recommended to restore the lost nodes, they will rejoin the cluster automatically once Juju detects their availability. + +To start Raft re-initialization, remove DEAD machines as a signal to charm that they cannot be restored/started and no risks for split-brain: +```shell +> juju remove-machine --force 0 +WARNING This command will perform the following actions: +will remove machine 0 +- will remove unit postgresql/0 +- will remove storage pgdata/0 +Continue [y/N]? y + +> juju remove-machine --force 2 +WARNING This command will perform the following actions: +will remove machine 2 +- will remove unit postgresql/2 +- will remove storage pgdata/2 +Continue [y/N]? y +``` +Check the status to ensure `Raft majority loss`: +```shell +> juju status +... +Unit Workload Agent Machine Public address Ports Message +postgresql/1* blocked executing 1 10.189.210.166 5432/tcp Raft majority loss, run: promote-to-primary +... +``` + +Start Raft re-initialization: +```shell +> juju run postgresql/1 promote-to-primary scope=unit force=true +``` + +Wait for re-initiation to be completed: +``` +> juju status +... +Unit Workload Agent Machine Public address Ports Message +postgresql/1* maintenance executing 3 10.189.210.166 5432/tcp (promote-to-primary) Reinitialising raft +... +``` + +At the end, the Primary until is back: +```shell +> juju status +Model Controller Cloud/Region Version SLA Timestamp +postgresql lxd localhost/localhost 3.6.5 unsupported 15:03:12+02:00 + +App Version Status Scale Charm Channel Rev Exposed Message +postgresql 14.17 active 1 postgresql 14/edge 615 no + +Unit Workload Agent Machine Public address Ports Message +postgresql/1* active idle 1 10.189.210.166 5432/tcp Primary + +Machine State Address Inst id Base AZ Message +1 started 10.189.210.166 juju-422c1a-1 ubuntu@22.04 Running +``` + +Scale application to 3+ units to complete HA recovery: +```shell +> juju add-unit postgresql -n 2 +``` + +The healthy status: +```shell +> juju status +Model Controller Cloud/Region Version SLA Timestamp +postgresql lxd localhost/localhost 3.6.5 unsupported 15:09:56+02:00 + +App Version Status Scale Charm Channel Rev Exposed Message +postgresql 14.17 active 3 postgresql 14/edge 615 no + +Unit Workload Agent Machine Public address Ports Message +postgresql/1* active idle 1 10.189.210.166 5432/tcp Primary +postgresql/3 active idle 3 10.189.210.124 5432/tcp +postgresql/4 active idle 4 10.189.210.178 5432/tcp + +Machine State Address Inst id Base AZ Message +1 started 10.189.210.166 juju-422c1a-1 ubuntu@22.04 Running +3 started 10.189.210.124 juju-422c1a-3 ubuntu@22.04 Running +4 started 10.189.210.178 juju-422c1a-4 ubuntu@22.04 Running +``` +[/details] \ No newline at end of file diff --git a/docs/overview.md b/docs/overview.md index 958348ebd8..3d24b83d2a 100644 --- a/docs/overview.md +++ b/docs/overview.md @@ -59,12 +59,16 @@ PostgreSQL is a trademark or registered trademark of PostgreSQL Global Developme | 3 | h-deploy-azure | [Azure](/t/15733) | | 3 | h-deploy-multi-az | [Multi-AZ](/t/15749) | | 3 | h-deploy-terraform | [Terraform](/t/14916) | -| 3 | h-deploy-airgapped | [Air-gapped](/t/15746) | | 3 | h-deploy-tls-vip-access | [TLS VIP access](/t/16576) | +| 3 | h-deploy-juju-spaces | [Juju spaces](/t/17416) | +| 3 | h-deploy-airgapped | [Air-gapped](/t/15746) | +| 3 | h-deploy-juju-storage | [Juju storage](/t/17529) | | 2 | h-integrate | [Integrate with another application](/t/9687) | | 2 | h-external-access | [External network access](/t/15802) | | 2 | h-scale | [Scale replicas](/t/9689) | +| 2 | h-switchover-failover | [Switchover/failover](/t/17523) | | 2 | h-enable-tls | [Enable TLS](/t/9685) | +| 2 | h-enable-ldap | [Enable LDAP](/t/17361) | | 2 | h-enable-plugins-extensions | [Enable plugins/extensions](/t/10906) | | 2 | h-backup | [Back up and restore]() | | 3 | h-configure-s3-aws | [Configure S3 AWS](/t/9681) | @@ -91,12 +95,15 @@ PostgreSQL is a trademark or registered trademark of PostgreSQL Global Developme | 3 | h-migrate-backup-restore | [Migrate data via backup/restore](/t/12164) | | 1 | reference | [Reference](/t/13976) | | 2 | r-releases | [Releases](/t/11875) | +| 2 | r-versions | [Versions](/t/17405) | | 2 | r-system-requirements | [System requirements](/t/11743) | | 2 | r-software-testing | [Software testing](/t/11773) | | 2 | r-performance | [Performance and resources](/t/11974) | | 2 | r-troubleshooting | [Troubleshooting](/t/11864) | | 3 | r-sos-report | [SOS report](/t/17228) | +| 3 | r-cli-helpers | [CLI helpers](/t/17406) | | 2 | r-plugins-extensions | [Plugins/extensions](/t/10946) | +| 3 | r-plugins-timescaledb | [TimescaleDB](/t/17528) | | 2 | r-alert-rules | [Alert rules](/t/15841) | | 2 | r-statuses | [Statuses](/t/10844) | | 2 | r-contacts | [Contacts](/t/11863) | @@ -105,9 +112,10 @@ PostgreSQL is a trademark or registered trademark of PostgreSQL Global Developme | 2 | e-interfaces-endpoints | [Interfaces and endpoints](/t/10251) | | 2 | e-juju-details | [Juju](/t/11985) | | 2 | e-legacy-charm | [Legacy charm](/t/10690) | -| 2 | e-connection-pooling| [Connection pooling](/t/15777) | +| 2 | e-units | [Units](/t/17525) | | 2 | e-users | [Users](/t/10798) | | 2 | e-logs | [Logs](/t/12099) | +| 2 | e-connection-pooling| [Connection pooling](/t/15777) | | 2 | e-security | [Security](/t/16852) | | 3 | e-cryptography | [Cryptography](/t/16853) | | 1 | search | [Search](https://canonical.com/data/docs/postgresql/iaas) | diff --git a/docs/reference/r-cli-helpers.md b/docs/reference/r-cli-helpers.md new file mode 100644 index 0000000000..f5398e33e3 --- /dev/null +++ b/docs/reference/r-cli-helpers.md @@ -0,0 +1,278 @@ +# CLI helpers + +This page describes some useful low-level tools shipped withing Charmed PostgreSQL for advanced troubleshooting. + +[note type=caution] +**These tools can be dangerous in a production environment if they are not used correctly.** + +When in doubt, [contact us](/t/11863). +[/note] + +## Patroni + +Troubleshooting tools include: +* The command-line tool `patronictl` +* The Patroni REST API +* The Raft library + +Learn more about Patroni in the [Architecture](/t/11857) page. + +### `patronictl` + +The main Patroni tool is `patronictl`. + +**It should only be used under the snap context**, via the user `snap_daemon`. + +#### Cluster status + +`patronictl` checks the low-level Patroni status of the cluster. + +[details="Example: cluster status"] +```shell +> juju deploy postgresql -n 3 # and wait for deployment +> juju ssh postgresql/2 +... + +ubuntu@juju-b87344-2:~$ sudo -u snap_daemon patronictl -c /var/snap/charmed-postgresql/current/etc/patroni/patroni.yaml topology ++ Cluster: postgresql (7496847632512033809) ------+-----------+----+-----------+ +| Member | Host | Role | State | TL | Lag in MB | ++-----------------+----------------+--------------+-----------+----+-----------+ +| postgresql-1 | 10.189.210.201 | Leader | running | 1 | | +| + postgresql-2 | 10.189.210.55 | Sync Standby | streaming | 1 | 0 | +| + postgresql-3 | 10.189.210.26 | Sync Standby | streaming | 1 | 0 | ++-----------------+----------------+--------------+-----------+----+-----------+ +``` +[/details] + +#### Useful Patroni actions + +Use `--help` to find all the available Patroni actions. + +[details="Example: Patroni actions"] +```shell +> sudo -u snap_daemon patronictl -c /var/snap/charmed-postgresql/current/etc/patroni/patroni.yaml --help +... + failover Failover to a replica + history Show the history of failovers/switchovers + list List the Patroni members for a given Patroni + pause Disable auto failover + query Query a Patroni PostgreSQL member + reinit Reinitialize cluster member + reload Reload cluster member configuration + remove Remove cluster from DCS + restart Restart cluster member + resume Resume auto failover + switchover Switchover to a replica + topology Prints ASCII topology for given cluster +``` +[/details] + +#### Switchover/failover + +Patroni can perform a low-level [switchover/failover](https://patroni.readthedocs.io/en/latest/patronictl.html#patronictl-switchover) inside one cluster. + +[details="Example: switchover (healthy cluster only)"] +```shell +ubuntu@juju-b87344-2:~$ sudo -u snap_daemon patronictl -c /var/snap/charmed-postgresql/current/etc/patroni/patroni.yaml switchover postgresql --candidate postgresql-2 --force +Current cluster topology ++ Cluster: postgresql (7496847632512033809) ----+-----------+----+-----------+ +| Member | Host | Role | State | TL | Lag in MB | ++---------------+----------------+--------------+-----------+----+-----------+ +| postgresql-1 | 10.189.210.201 | Sync Standby | streaming | 2 | 0 | +| postgresql-2 | 10.189.210.55 | Sync Standby | streaming | 2 | 0 | +| postgresql-3 | 10.189.210.26 | Leader | running | 2 | | ++---------------+----------------+--------------+-----------+----+-----------+ +2025-04-25 04:59:10.87214 Successfully switched over to "postgresql-2" ++ Cluster: postgresql (7496847632512033809) -----------+----+-----------+ +| Member | Host | Role | State | TL | Lag in MB | ++---------------+----------------+---------+-----------+----+-----------+ +| postgresql-1 | 10.189.210.201 | Replica | running | 2 | 0 | +| postgresql-2 | 10.189.210.55 | Leader | running | 2 | | +| postgresql-3 | 10.189.210.26 | Replica | stopped | | unknown | ++---------------+----------------+---------+-----------+----+-----------+ + +ubuntu@juju-b87344-2:~$ sudo -u snap_daemon patronictl -c /var/snap/charmed-postgresql/current/etc/patroni/patroni.yaml list ++ Cluster: postgresql (7496847632512033809) ----+-----------+----+-----------+ +| Member | Host | Role | State | TL | Lag in MB | ++---------------+----------------+--------------+-----------+----+-----------+ +| postgresql-1 | 10.189.210.201 | Sync Standby | streaming | 3 | 0 | +| postgresql-2 | 10.189.210.55 | Leader | running | 3 | | +| postgresql-3 | 10.189.210.26 | Sync Standby | streaming | 3 | 0 | ++---------------+----------------+--------------+-----------+----+-----------+ +``` +[/details] + +[details="Example: failover"] +```shell +ubuntu@juju-b87344-2:~$ sudo -u snap_daemon patronictl -c /var/snap/charmed-postgresql/current/etc/patroni/patroni.yaml failover postgresql --candidate postgresql-3 +Current cluster list ++ Cluster: postgresql (7496847632512033809) ----+-----------+----+-----------+ +| Member | Host | Role | State | TL | Lag in MB | ++---------------+----------------+--------------+-----------+----+-----------+ +| postgresql-1 | 10.189.210.201 | Leader | running | 1 | | +| postgresql-2 | 10.189.210.55 | Sync Standby | streaming | 1 | 0 | +| postgresql-3 | 10.189.210.26 | Sync Standby | streaming | 1 | 0 | ++---------------+----------------+--------------+-----------+----+-----------+ +Are you sure you want to failover cluster postgresql, demoting current leader postgresql-1? [y/N]: y +2025-04-25 04:44:53.69748 Successfully failed over to "postgresql-3" ++ Cluster: postgresql (7496847632512033809) ---------+----+-----------+ +| Member | Host | Role | State | TL | Lag in MB | ++---------------+----------------+---------+---------+----+-----------+ +| postgresql-1 | 10.189.210.201 | Replica | stopped | | unknown | +| postgresql-2 | 10.189.210.55 | Replica | running | 1 | 0 | +| postgresql-3 | 10.189.210.26 | Leader | running | 1 | | ++---------------+----------------+---------+---------+----+-----------+ + +ubuntu@juju-b87344-2:~$ sudo -u snap_daemon patronictl -c /var/snap/charmed-postgresql/current/etc/patroni/patroni.yaml history ++----+-----------+------------------------------+----------------------------------+--------------+ +| TL | LSN | Reason | Timestamp | New Leader | ++----+-----------+------------------------------+----------------------------------+--------------+ +| 1 | 335544480 | no recovery target specified | 2025-04-25T04:44:53.137152+00:00 | postgresql-3 | ++----+-----------+------------------------------+----------------------------------+--------------+ + +ubuntu@juju-b87344-2:~$ sudo -u snap_daemon patronictl -c /var/snap/charmed-postgresql/current/etc/patroni/patroni.yaml list ++ Cluster: postgresql (7496847632512033809) ----+-----------+----+-----------+ +| Member | Host | Role | State | TL | Lag in MB | ++---------------+----------------+--------------+-----------+----+-----------+ +| postgresql-1 | 10.189.210.201 | Sync Standby | streaming | 2 | 0 | +| postgresql-2 | 10.189.210.55 | Sync Standby | streaming | 2 | 0 | +| postgresql-3 | 10.189.210.26 | Leader | running | 2 | | ++---------------+----------------+--------------+-----------+----+-----------+ +``` +[/details] + +#### Re-initialisation + +Sometimes the cluster member might stuck in the middle of nowhere, the easiest way to try is [reinit the Patroni cluster member](https://patroni.readthedocs.io/en/latest/patronictl.html#patronictl-reinit). +[details="Example: cluster member re-initialization"] +```shell +ubuntu@juju-b87344-2:~$ sudo -u snap_daemon patronictl -c /var/snap/charmed-postgresql/current/etc/patroni/patroni.yaml reinit postgresql postgresql-1 ++ Cluster: postgresql (7496847632512033809) ----+-----------+----+-----------+ +| Member | Host | Role | State | TL | Lag in MB | ++---------------+----------------+--------------+-----------+----+-----------+ +| postgresql-1 | 10.189.210.201 | Sync Standby | streaming | 3 | 0 | +| postgresql-2 | 10.189.210.55 | Leader | running | 3 | | +| postgresql-3 | 10.189.210.26 | Sync Standby | streaming | 3 | 0 | ++---------------+----------------+--------------+-----------+----+-----------+ +Are you sure you want to reinitialize members postgresql-1? [y/N]: y +Success: reinitialize for member postgresql-1 +``` + +[/details] + +### Patroni REST API + +Patroni provides most `patronictl` actions as a [REST API](https://patroni.readthedocs.io/en/latest/rest_api.html). Use port `8008` to access Patroni REST API on any member/unit of Charmed PostgreSQL. + +[details="Example: read-only access via Patroni REST API"] +```shell +ubuntu@juju360:~$ curl 10.189.210.55:8008/cluster | jq # where 10.189.210.55 is IP of Charmed PostgreSQL Juju unit +... +{ + "members": [ + { + "name": "postgresql-1", + "role": "sync_standby", + "state": "streaming", + "api_url": "http://10.189.210.201:8008/patroni", + "host": "10.189.210.201", + "port": 5432, + "timeline": 3, + "lag": 0 + }, + { + "name": "postgresql-2", + "role": "leader", + "state": "running", + "api_url": "http://10.189.210.55:8008/patroni", + "host": "10.189.210.55", + "port": 5432, + "timeline": 3 + }, + { + "name": "postgresql-3", + "role": "sync_standby", + "state": "streaming", + "api_url": "http://10.189.210.26:8008/patroni", + "host": "10.189.210.26", + "port": 5432, + "timeline": 3, + "lag": 0 + } + ], + "scope": "postgresql" +} +``` +[/details] + +> **Note**: Patroni REST API can be accessed anonymously in read-only mode only. The Juju secret `patroni-password` is mandatory to apply any chances via Patroni REST API. +Example of authenticated changes via Patroni REST API: +[details="Example: write access via Patroni REST API"] +```shell +> juju deploy postgresql -n 3 # and wait for deployment +> juju secrets | grep postgresql # find ID with 'patroni-password' +> juju show-secret --reveal ccccaaabbbbbbcgoi12345 | grep patroni-password # reveal password to access Patroni REST API + patroni-password: patr0n1sup3rs3cretpassw0rd +... +> curl -k -u patroni:patr0n1sup3rs3cretpassw0rd -X POST https://10.151.27.242:8008/switchover -d '{"leader": "postgresql-0", "candidate": "postgresql-1"}' +Successfully switched over to "postgresql-1" +``` +> **Hint**: use dedicated [promote-to-primary](/t/17523) action to switchover Primary. + +[/details] + +Pay attention to TLS relation with PostgreSQL and access Patroni REST API accordingly: +[details="Example: access Patroni REST API with(out) TLS"] +```shell +> curl http://x.x.x.x:8008/cluster # to access without TLS +> curl https://x.x.x.x:8008/cluster # to access with trusted certificate +> curl -k https://x.x.x.x:8008/cluster # to access with self-signed certificate +``` +[/details] + + +### Raft library + +Patroni relies on the Raft library for the consensus handling and Primary election. It is implemented using [pySyncObj](https://github.com/bakwc/PySyncObj) and available as a CLI tool. + +While **you should not interact with Raft library manually**, you can check its internal status: + +[details="Example: check Raft status"] +```shell +> juju deploy postgresql -n 3 # and wait for deployment +> juju secrets | grep postgresql # find ID with 'raft-password' +> juju show-secret --reveal cvia1ibjihbbbcgoi12300 | grep raft-password # reveal password to access Raft + raft-password: r@ftsup3rs3cretp@ssw0rd +> juju ssh postgresql/2 +... +ubuntu@juju-b87344-2:~$ charmed-postgresql.syncobj-admin -status -conn 10.151.27.242:2222 -pass r@ftsup3rs3cretp@ssw0rd # where IP is a PostgreSQL Juju unit IP +commit_idx: 1396297 +enabled_code_version: 0 +has_quorum: True <<<<<<<<<<<< Important Raft cluster health! +last_applied: 1396297 +leader: 10.151.27.205:2222 <<<<<<<<<<<< Shows you the Raft leader +leader_commit_idx: 1396297 +log_len: 69 +match_idx_count: 2 +match_idx_server_10.151.27.103:2222: 1310986 +match_idx_server_10.151.27.205:2222: 1310986 +next_node_idx_count: 2 +next_node_idx_server_10.151.27.103:2222: 1310987 +next_node_idx_server_10.151.27.205:2222: 1310987 +partner_node_status_server_10.151.27.103:2222: 2 +partner_node_status_server_10.151.27.205:2222: 2 +partner_nodes_count: 2 +raft_term: 92 +readonly_nodes_count: 0 <<<<<<<<<<<< Raft members health +revision: deprecated +self: 10.151.27.242:2222 +self_code_version: 0 +state: 0 <<<<<<<<<<<< Self health +uptime: 2482881 +version: 0.3.12 +``` + +> **Note**: password is mandatory to access Raft. + +> **Note**: pay attention to the CLI syntax (simple `-` used, avoid misstype with common `--` prefix for parametes) +[/details] \ No newline at end of file diff --git a/docs/reference/r-plugins-timescaledb.md b/docs/reference/r-plugins-timescaledb.md new file mode 100644 index 0000000000..9624a4b558 --- /dev/null +++ b/docs/reference/r-plugins-timescaledb.md @@ -0,0 +1,93 @@ +# TimescaleDB plugin/extension + +Charmed PostgreSQL separates TimescaleDB editions for different [CharmHub tracks](https://canonical-charmcraft.readthedocs-hosted.com/en/stable/howto/manage-channels/): + +* Charmed PostgreSQL [16](https://charmhub.io/postgresql?channel=16/candidate) ships [Timescale Community edition](https://docs.timescale.com/about/latest/timescaledb-editions/). +* Charmed PostgreSQL [14](https://charmhub.io/postgresql?channel=14/stable) ships [Timescale Apache 2 edition](https://docs.timescale.com/about/latest/timescaledb-editions/). + +## Enable TimescaleDB + +To enable TimescaleDB plugin/extension simply run: +```shell +juju config postgresql plugin_timescaledb_enable=true +``` +The plugin has been enabled on all units once the config-change event finished and all units reports idle: +```shell +> juju status +... +Unit Workload Agent Machine Public address Ports Message +postgresql/3* active executing 3 10.189.210.124 5432/tcp (config-changed) Primary +postgresql/5 active executing 5 10.189.210.166 5432/tcp (config-changed) +postgresql/6 active executing 6 10.189.210.150 5432/tcp (config-changed) +... +Unit Workload Agent Machine Public address Ports Message +postgresql/3* active idle 3 10.189.210.124 5432/tcp Primary +postgresql/5 active idle 5 10.189.210.166 5432/tcp +postgresql/6 active idle 6 10.189.210.150 5432/tcp +... +``` + +## Disable TimescaleDB + +To disable it explicitly, simply run: +```shell +juju config postgresql plugin_timescaledb_enable=false +``` +The plugin has been disabled on all units once the config-change event finished and all units reports idle (same example as above). + +> **Note**: the extension will NOT be disable when database objects uses/depends on plugin is being disabled (clean the database to disable the plugin): +```shell +> juju status +... +Unit Workload Agent Machine Public address Ports Message +postgresql/3* blocked idle 3 10.189.210.124 5432/tcp Cannot disable plugins: Existing objects depend on it. See logs +... +``` + +Another option is to reset the manually enabled config option (as it is disabled by default): +```shell +juju config postgresql --reset plugin_timescaledb_enable +``` + +## Test TimescaleDB status: + +Prepare the `user_defined_action` procedure: +```shell +postgres=# CREATE OR REPLACE PROCEDURE user_defined_action(job_id int, config jsonb) LANGUAGE PLPGSQL AS +$$ +BEGIN + RAISE NOTICE 'Executing action % with config %', job_id, config; +END +$$; +``` + +Run the following commands to test your TimescaleDB on Charmed PostgreSQL 14: +```shell +postgres=# SELECT add_job('user_defined_action','1h'); +ERROR: function "add_job" is not supported under the current "apache" license +HINT: Upgrade your license to 'timescale' to use this free community feature. + +postgres=# CREATE TABLE test_timescaledb (time TIMESTAMPTZ NOT NULL); SELECT create_hypertable('test_timescaledb', 'time'); +CREATE TABLE + create_hypertable +------------------------------- + (1,public,test_timescaledb,t) +(1 row) + +``` + +TimescaleDB status on Charmed PostgreSQL 16: +```shell +postgres=# SELECT add_job('user_defined_action','1h'); + add_job +--------- + 1000 +(1 row) + +postgres=# CREATE TABLE test_timescaledb (time TIMESTAMPTZ NOT NULL); SELECT create_hypertable('test_timescaledb', 'time'); +CREATE TABLE + create_hypertable +------------------------------- + (1,public,test_timescaledb,t) +(1 row) +``` \ No newline at end of file diff --git a/docs/reference/r-versions.md b/docs/reference/r-versions.md new file mode 100644 index 0000000000..36227851ee --- /dev/null +++ b/docs/reference/r-versions.md @@ -0,0 +1,124 @@ +# PostgreSQL major versions + +Charmed PostgreSQL is shipped in following [tracks](https://documentation.ubuntu.com/juju/3.6/reference/charm/#track): + +* [PostgreSQL 16] (channel `16/candidate`) +* [PostgreSQL 14] (channel `14/stable`) +* [Legacy PostgreSQL charm] (channel `latest/stable`) -> **deprecated** + +This includes two major PostgreSQL versions, `14` and `16`, matching [Ubuntu versioning](https://packages.ubuntu.com/postgresql) for PostgreSQL. + +## PostgreSQL 16 + +PostgreSQL 16 is shipped in track `16` and is available for testing in the channel `16/candidate`. + +>Released alongside [PgBouncer] and [Data Integrator](https://charmhub.io/data-integrator) for Ubuntu 24.04 + +**Base:** Noble (Ubuntu 24.04) + +**Supported architectures:** `arm64` and `amd64`. + +### Supported features + +* [LDAP integration] (also supported by PostgreSQL `14`) +* [SoS report integration] (also supported by PostgreSQL `14`) +* [Recovery improvements] (also supported by PostgreSQL `14`) + * All replicas are now [synchronous units] + * Switchover the primary unit via `promote-to-primary scope=unit` + * Raft re-init helper: `promote-to-primary scope=unit force=yes` +* [Juju user secrets](https://documentation.ubuntu.com/juju/latest/reference/secret/index.html#user) for internal charm password rotation +* [Timescale Community Edition] +* [Extended COS integration] + * [Profiling via Parca] + * [Tracing via Tempo] +* Improved [security hardening] +* (WIP) [Multiple Juju storage support] +* (WIP) [Juju Spaces support] +* (WIP) Refresh v3 lib support +* (WIP) Improved built-in roles + + + +Read more about Charmed PostgreSQL 16 features in the [release notes]. + +### Deprecated / removed + +* Legacy interface `psql` (endpoints `db` and `db-admin`). + * See more about supported interfaces in [Interfaces and endpoints]. +* Support for Juju < `v3.6` + * Charmed PostgreSQL 16 requires Juju `3.6+ LTS` due to [Juju secrets](https://documentation.ubuntu.com/juju/3.6/reference/secret/index.html) support. +* Juju actions `get-password` and `set-password`. + * For security reasons, these actions are replaced by [Juju secrets](https://documentation.ubuntu.com/juju/3.6/reference/secret/index.html). +* [Timescale Apache 2 edition](https://docs.timescale.com/about/latest/timescaledb-editions/) has been replaced by [Timescale Community edition](https://docs.timescale.com/about/latest/timescaledb-editions/). + + +## PostgreSQL 14 + +PostgreSQL 14 is shipped in track `14` and available for production in the channel `14/stable`. + +**Base:** Jammy (Ubuntu 22.04) + +**Supported architectures:** `arm64` and `amd64`. + +### Supported features + +* [Deployment] on multiple cloud services +* [Backup and restore] + * Including point-in-time recovery (PITR) +* [COS integration] +* [TLS integration] +* [LDAP integration] +* [`arm64` architecture] + +Read more about Charmed PostgreSQL 14 features in the [release notes]. + +### Deprecated + +* The track `14` is in bug-fixing/support mode. New Charmed PostgreSQL `16` features will NOT be backported to track `14`. +* Charmed PostgreSQL 14 ships [Timescale Apache 2 edition](https://docs.timescale.com/about/latest/timescaledb-editions/) only. + +## Legacy PostgreSQL charm + +The legacy charm in the track `latest` has been deprecated and is **not supported.** It is still available here for the historical and comparative reasons only. + +Please use the supported tracks of the modern charm: `14/` and `16/`. + +Learn more in the [legacy charm explanation page]. + + + +[PostgreSQL 16]: https://charmhub.io/postgresql?channel=16/beta +[PostgreSQL 14]: https://charmhub.io/postgresql?channel=14/stable +[Legacy PostgreSQL charm]: https://charmhub.io/postgresql?channel=latest/stable + +[PgBouncer]: https://charmhub.io/pgbouncer + +[LDAP integration]: /t/17361 +[SoS report integration]: /t/17228 +[Recovery improvements]: /t/17523 +[synchronous units]: https://charmhub.io/postgresql/configurations?channel=14/edge#synchronous_node_count +[internal charm passwords]: /t/10798 +[rotation]: /t/9703 +[Timescale Community Edition]: /t/17528 +[Extended COS integration]: /t/10600 +[Profiling via Parca]: /t/17172 +[Tracing via Tempo]: /t/14521 +[security hardening]: /t/16852 +[Multiple Juju storage support]: /t/17529 +[Juju Spaces support]: /t/17416 + +[release notes]: /t/11875 + +[Interfaces and endpoints]: /t/10251 + +[Deployment]: /t/16811 +[Backup and restore]: /t/9683 +[COS integration]: /t/10600 +[TLS integration]: /t/9685 +[LDAP integration]: /t/17361 +[`arm64` architecture]: /t/11743 + +[legacy charm explanation page]: /t/10690 \ No newline at end of file From d165940fab1e65fed6e3280d348f653b7c79124b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sinclert=20P=C3=A9rez?= Date: Tue, 6 May 2025 12:30:45 +0200 Subject: [PATCH 030/112] [MISC] Extend relation-user listing syntax (#868) --- lib/charms/postgresql_k8s/v0/postgresql.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/charms/postgresql_k8s/v0/postgresql.py b/lib/charms/postgresql_k8s/v0/postgresql.py index 7e6a9d7631..f2ceea76bb 100644 --- a/lib/charms/postgresql_k8s/v0/postgresql.py +++ b/lib/charms/postgresql_k8s/v0/postgresql.py @@ -35,7 +35,7 @@ # Increment this PATCH version before using `charmcraft publish-lib` or reset # to 0 if you are raising the major API version -LIBPATCH = 51 +LIBPATCH = 53 # Groups to distinguish HBA access ACCESS_GROUP_IDENTITY = "identity_access" @@ -672,7 +672,9 @@ def list_users_from_relation(self) -> Set[str]: try: with self._connect_to_database() as connection, connection.cursor() as cursor: cursor.execute( - "SELECT usename FROM pg_catalog.pg_user WHERE usename LIKE 'relation_id_%';" + "SELECT usename " + "FROM pg_catalog.pg_user " + "WHERE usename LIKE 'relation_id_%' OR usename LIKE 'relation-%';" ) usernames = cursor.fetchall() return {username[0] for username in usernames} From 66d5d743455e4446840f3f6fe0d12c6a4c59ff27 Mon Sep 17 00:00:00 2001 From: Dragomir Penev <6687393+dragomirp@users.noreply.github.com> Date: Tue, 20 May 2025 13:03:31 +0300 Subject: [PATCH 031/112] Sync libs (#884) --- lib/charms/postgresql_k8s/v0/postgresql.py | 21 +++++++++++++------ .../postgresql_k8s/v0/postgresql_tls.py | 15 +++++++++++-- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/lib/charms/postgresql_k8s/v0/postgresql.py b/lib/charms/postgresql_k8s/v0/postgresql.py index f2ceea76bb..f72a112a38 100644 --- a/lib/charms/postgresql_k8s/v0/postgresql.py +++ b/lib/charms/postgresql_k8s/v0/postgresql.py @@ -35,7 +35,7 @@ # Increment this PATCH version before using `charmcraft publish-lib` or reset # to 0 if you are raising the major API version -LIBPATCH = 53 +LIBPATCH = 52 # Groups to distinguish HBA access ACCESS_GROUP_IDENTITY = "identity_access" @@ -700,15 +700,22 @@ def list_valid_privileges_and_roles(self) -> Tuple[Set[str], Set[str]]: "superuser", }, {role[0] for role in cursor.fetchall() if role[0]} - def set_up_database(self) -> None: + def set_up_database(self, temp_location: Optional[str] = None) -> None: """Set up postgres database with the right permissions.""" connection = None + cursor = None try: - with self._connect_to_database() as connection, connection.cursor() as cursor: - cursor.execute("SELECT TRUE FROM pg_roles WHERE rolname='admin';") - if cursor.fetchone() is not None: - return + connection = self._connect_to_database() + cursor = connection.cursor() + if temp_location is not None: + cursor.execute("SELECT TRUE FROM pg_tablespace WHERE spcname='temp';") + if cursor.fetchone() is None: + cursor.execute(f"CREATE TABLESPACE temp LOCATION '{temp_location}';") + cursor.execute("GRANT CREATE ON TABLESPACE temp TO public;") + + cursor.execute("SELECT TRUE FROM pg_roles WHERE rolname='admin';") + if cursor.fetchone() is None: # Allow access to the postgres database only to the system users. cursor.execute("REVOKE ALL PRIVILEGES ON DATABASE postgres FROM PUBLIC;") cursor.execute("REVOKE CREATE ON SCHEMA public FROM PUBLIC;") @@ -727,6 +734,8 @@ def set_up_database(self) -> None: logger.error(f"Failed to set up databases: {e}") raise PostgreSQLDatabasesSetupError() from e finally: + if cursor is not None: + cursor.close() if connection is not None: connection.close() diff --git a/lib/charms/postgresql_k8s/v0/postgresql_tls.py b/lib/charms/postgresql_k8s/v0/postgresql_tls.py index 2aeaa52af6..9e79e881ef 100644 --- a/lib/charms/postgresql_k8s/v0/postgresql_tls.py +++ b/lib/charms/postgresql_k8s/v0/postgresql_tls.py @@ -23,7 +23,7 @@ import logging import re import socket -from typing import List, Optional +from typing import Iterator, List, Optional from charms.certificate_transfer_interface.v0.certificate_transfer import ( CertificateAvailableEvent as CertificateAddedEvent, @@ -55,7 +55,7 @@ # Increment this PATCH version before using `charmcraft publish-lib` or reset # to 0 if you are raising the major API version. -LIBPATCH = 14 +LIBPATCH = 15 logger = logging.getLogger(__name__) SCOPE = "unit" @@ -269,6 +269,17 @@ def is_ip_address(address: str) -> bool: "sans_dns": sans_dns, } + def get_ca_secret_names(self) -> Iterator[str]: + """Get a secret-name for each relation fulfilling the CA transfer interface. + + Returns: + Secret name for a CA transfer fulfilled interface. + """ + relations = self.charm.model.relations.get(TLS_TRANSFER_RELATION, []) + + for relation in relations: + yield f"ca-{relation.app.name}" + def get_tls_files(self) -> (Optional[str], Optional[str], Optional[str]): """Prepare TLS files in special PostgreSQL way. From 5c1976477c6ffbd6a06a6576b70a68aae5aef8ab Mon Sep 17 00:00:00 2001 From: Dragomir Penev <6687393+dragomirp@users.noreply.github.com> Date: Fri, 23 May 2025 15:10:51 +0300 Subject: [PATCH 032/112] Remove runner password (#913) --- spread.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spread.yaml b/spread.yaml index 2b435a5885..9a2c7ed1b6 100644 --- a/spread.yaml +++ b/spread.yaml @@ -79,6 +79,8 @@ backends: PermitEmptyPasswords yes EOF + sudo passwd -d runner + ADDRESS localhost # HACK: spread does not pass environment variables set on runner # Manually pass specific environment variables From f72c974817edb54857133ed6015f75951dca8a7c Mon Sep 17 00:00:00 2001 From: Marcelo Henrique Neppel Date: Mon, 26 May 2025 21:39:47 -0300 Subject: [PATCH 033/112] [DPE-6898] User->databases pg_hba rules (#885) * Restrict each user to their allowed databases Signed-off-by: Marcelo Henrique Neppel * Fix unit tests Signed-off-by: Marcelo Henrique Neppel * Fix sync users on replicas Signed-off-by: Marcelo Henrique Neppel * Fix unit test Signed-off-by: Marcelo Henrique Neppel * Add default landscape user permission Signed-off-by: Marcelo Henrique Neppel * Increase sleep time in pg_hba test, fix user->database mapping for upgrade from stable and skip event trigger function code when not a superuser Signed-off-by: Marcelo Henrique Neppel * Improve users list check Signed-off-by: Marcelo Henrique Neppel * Fix raft reinitialisation in tests Signed-off-by: Marcelo Henrique Neppel * Decrease the amount of API calls by one Signed-off-by: Marcelo Henrique Neppel * Check users list directly Signed-off-by: Marcelo Henrique Neppel * Tweak test fast interval Signed-off-by: Marcelo Henrique Neppel * Improvements to avoid replica restart while syncing from primary Signed-off-by: Marcelo Henrique Neppel * Fix linting Signed-off-by: Marcelo Henrique Neppel --------- Signed-off-by: Marcelo Henrique Neppel --- lib/charms/postgresql_k8s/v0/postgresql.py | 213 +++++++++++++++--- scripts/cluster_topology_observer.py | 69 +++++- src/charm.py | 35 +++ src/cluster.py | 10 +- src/cluster_topology_observer.py | 5 + src/relations/db.py | 14 +- src/relations/postgresql_provider.py | 27 +++ src/upgrade.py | 6 +- templates/patroni.yml.j2 | 11 +- .../ha_tests/test_scaling_three_units.py | 1 + .../test_scaling_three_units_async.py | 1 + tests/integration/helpers.py | 10 +- tests/integration/test_pg_hba.py | 178 +++++++++++++++ tests/spread/test_pg_hba.py/task.yaml | 7 + tests/unit/test_charm.py | 2 + tests/unit/test_cluster_topology_observer.py | 3 +- tests/unit/test_db.py | 6 +- tests/unit/test_postgresql_provider.py | 4 + 18 files changed, 544 insertions(+), 58 deletions(-) create mode 100644 tests/integration/test_pg_hba.py create mode 100644 tests/spread/test_pg_hba.py/task.yaml diff --git a/lib/charms/postgresql_k8s/v0/postgresql.py b/lib/charms/postgresql_k8s/v0/postgresql.py index f72a112a38..fbf7dec711 100644 --- a/lib/charms/postgresql_k8s/v0/postgresql.py +++ b/lib/charms/postgresql_k8s/v0/postgresql.py @@ -35,7 +35,7 @@ # Increment this PATCH version before using `charmcraft publish-lib` or reset # to 0 if you are raising the major API version -LIBPATCH = 52 +LIBPATCH = 54 # Groups to distinguish HBA access ACCESS_GROUP_IDENTITY = "identity_access" @@ -113,6 +113,10 @@ class PostgreSQLGetPostgreSQLVersionError(Exception): """Exception raised when retrieving PostgreSQL version fails.""" +class PostgreSQLListAccessibleDatabasesForUserError(Exception): + """Exception raised when retrieving the accessible databases for a user fails.""" + + class PostgreSQLListGroupsError(Exception): """Exception raised when retrieving PostgreSQL groups list fails.""" @@ -190,6 +194,11 @@ def create_access_groups(self) -> None: try: with self._connect_to_database() as connection, connection.cursor() as cursor: for group in ACCESS_GROUPS: + cursor.execute( + SQL("SELECT TRUE FROM pg_roles WHERE rolname={};").format(Literal(group)) + ) + if cursor.fetchone() is not None: + continue cursor.execute( SQL("CREATE ROLE {} NOLOGIN;").format( Identifier(group), @@ -622,15 +631,22 @@ def is_tls_enabled(self, check_current_host: bool = False) -> bool: # Connection errors happen when PostgreSQL has not started yet. return False - def list_access_groups(self) -> Set[str]: + def list_access_groups(self, current_host=False) -> Set[str]: """Returns the list of PostgreSQL database access groups. + Args: + current_host: whether to check the current host + instead of the primary host. + Returns: List of PostgreSQL database access groups. """ connection = None + host = self.current_host if current_host else None try: - with self._connect_to_database() as connection, connection.cursor() as cursor: + with self._connect_to_database( + database_host=host + ) as connection, connection.cursor() as cursor: cursor.execute( "SELECT groname FROM pg_catalog.pg_group WHERE groname LIKE '%_access';" ) @@ -643,16 +659,69 @@ def list_access_groups(self) -> Set[str]: if connection is not None: connection.close() - def list_users(self) -> Set[str]: + def list_accessible_databases_for_user(self, user: str, current_host=False) -> Set[str]: + """Returns the list of accessible databases for a specific user. + + Args: + user: the user to check. + current_host: whether to check the current host + instead of the primary host. + + Returns: + List of accessible database (the ones where + the user has the CONNECT privilege). + """ + connection = None + host = self.current_host if current_host else None + try: + with self._connect_to_database( + database_host=host + ) as connection, connection.cursor() as cursor: + cursor.execute( + SQL( + "SELECT TRUE FROM pg_catalog.pg_user WHERE usename = {} AND usesuper;" + ).format(Literal(user)) + ) + if cursor.fetchone() is not None: + return {"all"} + cursor.execute( + SQL( + "SELECT datname FROM pg_catalog.pg_database WHERE has_database_privilege({}, datname, 'CONNECT') AND NOT datistemplate;" + ).format(Literal(user)) + ) + databases = cursor.fetchall() + return {database[0] for database in databases} + except psycopg2.Error as e: + logger.error(f"Failed to list accessible databases for user {user}: {e}") + raise PostgreSQLListAccessibleDatabasesForUserError() from e + finally: + if connection is not None: + connection.close() + + def list_users(self, group: Optional[str] = None, current_host=False) -> Set[str]: """Returns the list of PostgreSQL database users. + Args: + group: optional group to filter the users. + current_host: whether to check the current host + instead of the primary host. + Returns: List of PostgreSQL database users. """ connection = None + host = self.current_host if current_host else None try: - with self._connect_to_database() as connection, connection.cursor() as cursor: - cursor.execute("SELECT usename FROM pg_catalog.pg_user;") + with self._connect_to_database( + database_host=host + ) as connection, connection.cursor() as cursor: + if group: + query = SQL( + "SELECT usename FROM (SELECT UNNEST(grolist) AS user_id FROM pg_catalog.pg_group WHERE groname = {}) AS g JOIN pg_catalog.pg_user AS u ON g.user_id = u.usesysid;" + ).format(Literal(group)) + else: + query = "SELECT usename FROM pg_catalog.pg_user;" + cursor.execute(query) usernames = cursor.fetchall() return {username[0] for username in usernames} except psycopg2.Error as e: @@ -662,19 +731,27 @@ def list_users(self) -> Set[str]: if connection is not None: connection.close() - def list_users_from_relation(self) -> Set[str]: + def list_users_from_relation(self, current_host=False) -> Set[str]: """Returns the list of PostgreSQL database users that were created by a relation. + Args: + current_host: whether to check the current host + instead of the primary host. + Returns: List of PostgreSQL database users. """ connection = None + host = self.current_host if current_host else None try: - with self._connect_to_database() as connection, connection.cursor() as cursor: + with self._connect_to_database( + database_host=host + ) as connection, connection.cursor() as cursor: cursor.execute( "SELECT usename " "FROM pg_catalog.pg_user " - "WHERE usename LIKE 'relation_id_%' OR usename LIKE 'relation-%';" + "WHERE usename LIKE 'relation_id_%' OR usename LIKE 'relation-%' " + "OR usename LIKE 'pgbouncer_auth_relation_id_%' OR usename LIKE '%_user_%_%';" ) usernames = cursor.fetchall() return {username[0] for username in usernames} @@ -700,42 +777,108 @@ def list_valid_privileges_and_roles(self) -> Tuple[Set[str], Set[str]]: "superuser", }, {role[0] for role in cursor.fetchall() if role[0]} - def set_up_database(self, temp_location: Optional[str] = None) -> None: + def set_up_database(self) -> None: """Set up postgres database with the right permissions.""" connection = None - cursor = None try: - connection = self._connect_to_database() - cursor = connection.cursor() - - if temp_location is not None: - cursor.execute("SELECT TRUE FROM pg_tablespace WHERE spcname='temp';") + with self._connect_to_database( + database="template1" + ) as connection, connection.cursor() as cursor: + # Create database function and event trigger to identify users created by PgBouncer. + cursor.execute( + "SELECT TRUE FROM pg_event_trigger WHERE evtname = 'update_pg_hba_on_create_schema';" + ) if cursor.fetchone() is None: - cursor.execute(f"CREATE TABLESPACE temp LOCATION '{temp_location}';") - cursor.execute("GRANT CREATE ON TABLESPACE temp TO public;") - - cursor.execute("SELECT TRUE FROM pg_roles WHERE rolname='admin';") - if cursor.fetchone() is None: - # Allow access to the postgres database only to the system users. - cursor.execute("REVOKE ALL PRIVILEGES ON DATABASE postgres FROM PUBLIC;") - cursor.execute("REVOKE CREATE ON SCHEMA public FROM PUBLIC;") - for user in self.system_users: - cursor.execute( - SQL("GRANT ALL PRIVILEGES ON DATABASE postgres TO {};").format( - Identifier(user) + cursor.execute(""" +CREATE OR REPLACE FUNCTION update_pg_hba() + RETURNS event_trigger + LANGUAGE plpgsql + AS $$ + DECLARE + hba_file TEXT; + copy_command TEXT; + connection_type TEXT; + rec record; + insert_value TEXT; + changes INTEGER = 0; + BEGIN + -- Don't execute on replicas. + IF NOT pg_is_in_recovery() THEN + -- Load the current authorisation rules. + DROP TABLE IF EXISTS pg_hba; + CREATE TEMPORARY TABLE pg_hba (lines TEXT); + SELECT setting INTO hba_file FROM pg_settings WHERE name = 'hba_file'; + IF hba_file IS NOT NULL THEN + copy_command='COPY pg_hba FROM ''' || hba_file || '''' ; + EXECUTE copy_command; + -- Build a list of the relation users and the databases they can access. + DROP TABLE IF EXISTS relation_users; + CREATE TEMPORARY TABLE relation_users AS + SELECT t.user, STRING_AGG(DISTINCT t.database, ',') AS databases FROM( SELECT u.usename AS user, CASE WHEN u.usesuper THEN 'all' ELSE d.datname END AS database FROM ( SELECT usename, usesuper FROM pg_catalog.pg_user WHERE usename NOT IN ('backup', 'monitoring', 'operator', 'postgres', 'replication', 'rewind')) AS u JOIN ( SELECT datname FROM pg_catalog.pg_database WHERE NOT datistemplate ) AS d ON has_database_privilege(u.usename, d.datname, 'CONNECT') ) AS t GROUP BY 1; + IF (SELECT COUNT(lines) FROM pg_hba WHERE lines LIKE 'hostssl %') > 0 THEN + connection_type := 'hostssl'; + ELSE + connection_type := 'host'; + END IF; + -- Add the new users to the pg_hba file. + FOR rec IN SELECT * FROM relation_users + LOOP + insert_value := connection_type || ' ' || rec.databases || ' ' || rec.user || ' 0.0.0.0/0 md5'; + IF (SELECT COUNT(lines) FROM pg_hba WHERE lines = insert_value) = 0 THEN + INSERT INTO pg_hba (lines) VALUES (insert_value); + changes := changes + 1; + END IF; + END LOOP; + -- Remove users that don't exist anymore from the pg_hba file. + FOR rec IN SELECT h.lines FROM pg_hba AS h LEFT JOIN relation_users AS r ON SPLIT_PART(h.lines, ' ', 3) = r.user WHERE r.user IS NULL AND (SPLIT_PART(h.lines, ' ', 3) LIKE 'relation_id_%' OR SPLIT_PART(h.lines, ' ', 3) LIKE 'pgbouncer_auth_relation_id_%' OR SPLIT_PART(h.lines, ' ', 3) LIKE '%_user_%_%') + LOOP + DELETE FROM pg_hba WHERE lines = rec.lines; + changes := changes + 1; + END LOOP; + -- Apply the changes to the pg_hba file. + IF changes > 0 THEN + copy_command='COPY pg_hba TO ''' || hba_file || '''' ; + EXECUTE copy_command; + PERFORM pg_reload_conf(); + END IF; + END IF; + END IF; + END; + $$; + """) + cursor.execute(""" +CREATE EVENT TRIGGER update_pg_hba_on_create_schema + ON ddl_command_end + WHEN TAG IN ('CREATE SCHEMA') + EXECUTE FUNCTION update_pg_hba(); + """) + cursor.execute(""" +CREATE EVENT TRIGGER update_pg_hba_on_drop_schema + ON ddl_command_end + WHEN TAG IN ('DROP SCHEMA') + EXECUTE FUNCTION update_pg_hba(); + """) + with self._connect_to_database() as connection, connection.cursor() as cursor: + cursor.execute("SELECT TRUE FROM pg_roles WHERE rolname='admin';") + if cursor.fetchone() is None: + # Allow access to the postgres database only to the system users. + cursor.execute("REVOKE ALL PRIVILEGES ON DATABASE postgres FROM PUBLIC;") + cursor.execute("REVOKE CREATE ON SCHEMA public FROM PUBLIC;") + for user in self.system_users: + cursor.execute( + SQL("GRANT ALL PRIVILEGES ON DATABASE postgres TO {};").format( + Identifier(user) + ) ) + self.create_user( + PERMISSIONS_GROUP_ADMIN, + extra_user_roles=["pg_read_all_data", "pg_write_all_data"], ) - self.create_user( - PERMISSIONS_GROUP_ADMIN, - extra_user_roles=["pg_read_all_data", "pg_write_all_data"], - ) - cursor.execute("GRANT CONNECT ON DATABASE postgres TO admin;") + cursor.execute("GRANT CONNECT ON DATABASE postgres TO admin;") except psycopg2.Error as e: logger.error(f"Failed to set up databases: {e}") raise PostgreSQLDatabasesSetupError() from e finally: - if cursor is not None: - cursor.close() if connection is not None: connection.close() diff --git a/scripts/cluster_topology_observer.py b/scripts/cluster_topology_observer.py index c41ee34207..c3b77f9d04 100644 --- a/scripts/cluster_topology_observer.py +++ b/scripts/cluster_topology_observer.py @@ -22,11 +22,51 @@ class UnreachableUnitsError(Exception): """Cannot reach any known cluster member.""" -def dispatch(run_cmd, unit, charm_dir): - """Use the input juju-run command to dispatch a :class:`ClusterTopologyChangeEvent`.""" - dispatch_sub_cmd = "JUJU_DISPATCH_PATH=hooks/cluster_topology_change {}/dispatch" +def check_for_authorisation_rules_changes(run_cmd, unit, charm_dir, previous_authorisation_rules): + """Check for changes in the authorisation rules. + + If changes are detected, dispatch an event to handle them. + """ + # Read contents from the pg_hba.conf file. + with open("/var/snap/charmed-postgresql/common/var/lib/postgresql/pg_hba.conf") as file: + current_authorisation_rules = file.read() + current_authorisation_rules = [ + line for line in current_authorisation_rules.splitlines() if not line.startswith("#") + ] + # If it's the first time the authorisation rules were retrieved, then store it and use + # it for subsequent checks. + if not previous_authorisation_rules: + previous_authorisation_rules = current_authorisation_rules + # If the authorisation rules changed, dispatch a charm event to handle this change. + elif current_authorisation_rules != previous_authorisation_rules: + previous_authorisation_rules = current_authorisation_rules + dispatch(run_cmd, unit, charm_dir, "authorisation_rules_change") + return previous_authorisation_rules + + +def check_for_cluster_topology_changes( + run_cmd, unit, charm_dir, previous_cluster_topology, current_cluster_topology +): + """Check for changes in the cluster topology. + + If changes are detected, dispatch an event to handle them. + """ + # If it's the first time the cluster topology was retrieved, then store it and use + # it for subsequent checks. + if not previous_cluster_topology: + previous_cluster_topology = current_cluster_topology + # If the cluster topology changed, dispatch a charm event to handle this change. + elif current_cluster_topology != previous_cluster_topology: + previous_cluster_topology = current_cluster_topology + dispatch(run_cmd, unit, charm_dir, "cluster_topology_change") + return previous_cluster_topology + + +def dispatch(run_cmd, unit, charm_dir, custom_event): + """Use the input juju-run command to dispatch a custom event.""" + dispatch_sub_cmd = "JUJU_DISPATCH_PATH=hooks/{} {}/dispatch" # Input is generated by the charm - subprocess.run([run_cmd, "-u", unit, dispatch_sub_cmd.format(charm_dir)]) # noqa: S603 + subprocess.run([run_cmd, "-u", unit, dispatch_sub_cmd.format(custom_event, charm_dir)]) # noqa: S603 def main(): @@ -37,6 +77,7 @@ def main(): patroni_urls, run_cmd, unit, charm_dir = sys.argv[1:] previous_cluster_topology = {} + previous_authorisation_rules = [] urls = [urljoin(url, PATRONI_CLUSTER_STATUS_ENDPOINT) for url in patroni_urls.split(",")] member_name = unit.replace("/", "-") while True: @@ -63,23 +104,27 @@ def main(): raise UnreachableUnitsError("Unable to reach cluster members") current_cluster_topology = {} urls = [] + is_primary = False for member in cluster_status["members"]: current_cluster_topology[member["name"]] = member["role"] member_url = urljoin(member["api_url"], PATRONI_CLUSTER_STATUS_ENDPOINT) # Call the current unit first if member["name"] == member_name: urls.insert(0, member_url) + # Check if the current member is the primary. + if member["role"] == "leader": + is_primary = True else: urls.append(member_url) - # If it's the first time the cluster topology was retrieved, then store it and use - # it for subsequent checks. - if not previous_cluster_topology: - previous_cluster_topology = current_cluster_topology - # If the cluster topology changed, dispatch a charm event to handle this change. - elif current_cluster_topology != previous_cluster_topology: - previous_cluster_topology = current_cluster_topology - dispatch(run_cmd, unit, charm_dir) + previous_cluster_topology = check_for_cluster_topology_changes( + run_cmd, unit, charm_dir, previous_cluster_topology, current_cluster_topology + ) + + if is_primary: + previous_authorisation_rules = check_for_authorisation_rules_changes( + run_cmd, unit, charm_dir, previous_authorisation_rules + ) # Wait some time before checking again for a cluster topology change. sleep(30) diff --git a/src/charm.py b/src/charm.py index da921284c4..0968e55394 100755 --- a/src/charm.py +++ b/src/charm.py @@ -87,7 +87,9 @@ POSTGRESQL_SNAP_NAME, RAFT_PASSWORD_KEY, REPLICATION_PASSWORD_KEY, + REPLICATION_USER, REWIND_PASSWORD_KEY, + REWIND_USER, SECRET_DELETED_LABEL, SECRET_INTERNAL_LABEL, SECRET_KEY_OVERRIDES, @@ -182,6 +184,9 @@ def __init__(self, *args): run_cmd = "/usr/bin/juju-exec" if juju_version.major > 2 else "/usr/bin/juju-run" self._observer = ClusterTopologyObserver(self, run_cmd) self._rotate_logs = RotateLogs(self) + self.framework.observe( + self.on.authorisation_rules_change, self._on_authorisation_rules_change + ) self.framework.observe(self.on.cluster_topology_change, self._on_cluster_topology_change) self.framework.observe(self.on.install, self._on_install) self.framework.observe(self.on.leader_elected, self._on_leader_elected) @@ -233,6 +238,12 @@ def __init__(self, *args): ) self._tracing_endpoint_config, _ = charm_tracing_config(self._grafana_agent, None) + def _on_authorisation_rules_change(self, _): + """Handle authorisation rules change event.""" + timestamp = datetime.now() + self._peers.data[self.unit].update({"pg_hba_needs_update_timestamp": str(timestamp)}) + logger.debug(f"authorisation rules changed at {timestamp}") + def patroni_scrape_config(self) -> list[dict]: """Generates scrape config for the Patroni metrics endpoint.""" return [ @@ -2011,6 +2022,7 @@ def update_config(self, is_creating_backup: bool = False, no_peers: bool = False restore_stanza=self.app_peer_data.get("restore-stanza"), parameters=pg_parameters, no_peers=no_peers, + user_databases_map=self.relations_user_databases_map, ) if no_peers: return True @@ -2138,6 +2150,29 @@ def client_relations(self) -> list[Relation]: relations.append(relation) return relations + @property + def relations_user_databases_map(self) -> dict: + """Returns a user->databases map for all relations.""" + if not self.is_cluster_initialised or not self._patroni.member_started: + return {USER: "all", REPLICATION_USER: "all", REWIND_USER: "all"} + user_database_map = {} + for user in self.postgresql.list_users_from_relation( + current_host=self.is_connectivity_enabled + ): + user_database_map[user] = ",".join( + self.postgresql.list_accessible_databases_for_user( + user, current_host=self.is_connectivity_enabled + ) + ) + # Add "landscape" superuser by default to the list when the "db-admin" relation is present. + if any(True for relation in self.client_relations if relation.name == "db-admin"): + user_database_map["landscape"] = "all" + if self.postgresql.list_access_groups(current_host=self.is_connectivity_enabled) != set( + ACCESS_GROUPS + ): + user_database_map.update({USER: "all", REPLICATION_USER: "all", REWIND_USER: "all"}) + return user_database_map + def override_patroni_restart_condition( self, new_condition: str, repeat_cause: str | None ) -> bool: diff --git a/src/cluster.py b/src/cluster.py index 7d4c70c33a..e46cb87860 100644 --- a/src/cluster.py +++ b/src/cluster.py @@ -516,7 +516,12 @@ def member_inactive(self) -> bool: except RetryError: return True - return response["state"] not in [*RUNNING_STATES, "starting", "restarting"] + return response["state"] not in [ + *RUNNING_STATES, + "creating replica", + "starting", + "restarting", + ] @property def member_replication_lag(self) -> str: @@ -632,6 +637,7 @@ def render_patroni_yml_file( restore_to_latest: bool = False, parameters: dict[str, str] | None = None, no_peers: bool = False, + user_databases_map: dict[str, str] | None = None, ) -> None: """Render the Patroni configuration file. @@ -649,6 +655,7 @@ def render_patroni_yml_file( restore_to_latest: restore all the WAL transaction logs from the stanza. parameters: PostgreSQL parameters to be added to the postgresql.conf file. no_peers: Don't include peers. + user_databases_map: map of databases to be accessible by each user. """ # Open the template patroni.yml file. with open("templates/patroni.yml.j2") as file: @@ -696,6 +703,7 @@ def render_patroni_yml_file( raft_password=self.raft_password, ldap_parameters=self._dict_to_hba_string(ldap_params), patroni_password=self.patroni_password, + user_databases_map=user_databases_map, ) self.render_file(f"{PATRONI_CONF_PATH}/patroni.yaml", rendered, 0o600) diff --git a/src/cluster_topology_observer.py b/src/cluster_topology_observer.py index aa85a0e48e..94f0e479d9 100644 --- a/src/cluster_topology_observer.py +++ b/src/cluster_topology_observer.py @@ -22,12 +22,17 @@ class ClusterTopologyChangeEvent(EventBase): """A custom event for cluster topology changes.""" +class AuthorisationRulesChangeEvent(EventBase): + """A custom event for authorisation rules changes.""" + + class ClusterTopologyChangeCharmEvents(CharmEvents): """A CharmEvents extension for cluster topology changes. Includes :class:`ClusterTopologyChangeEvent` in those that can be handled. """ + authorisation_rules_change = EventSource(AuthorisationRulesChangeEvent) cluster_topology_change = EventSource(ClusterTopologyChangeEvent) diff --git a/src/relations/db.py b/src/relations/db.py index a77070fc3b..d789d6d15b 100644 --- a/src/relations/db.py +++ b/src/relations/db.py @@ -111,6 +111,16 @@ def _on_relation_changed(self, event: RelationChangedEvent) -> None: """ # Check for some conditions before trying to access the PostgreSQL instance. if not self.charm.unit.is_leader(): + if ( + not self.charm._patroni.member_started + or f"relation-{event.relation.id}" + not in self.charm.postgresql.list_users(current_host=True) + ): + logger.debug("Deferring on_relation_changed: user was not created yet") + event.defer() + return + + self.charm.update_config() return if self._check_multiple_endpoints(): @@ -219,6 +229,8 @@ def set_up_relation(self, relation: Relation) -> bool: self._update_unit_status(relation) + self.charm.update_config() + return True def _on_relation_departed(self, event: RelationDepartedEvent) -> None: @@ -322,7 +334,7 @@ def update_endpoints(self, relation: Relation = None) -> None: postgresql_version = None try: - postgresql_version = self.charm.postgresql.get_postgresql_version() + postgresql_version = self.charm.postgresql.get_postgresql_version(current_host=False) except PostgreSQLGetPostgreSQLVersionError: logger.exception( f"Failed to retrieve the PostgreSQL version to initialise/update {self.relation_name} relation" diff --git a/src/relations/postgresql_provider.py b/src/relations/postgresql_provider.py index ef0dec90dc..1ff167d03d 100644 --- a/src/relations/postgresql_provider.py +++ b/src/relations/postgresql_provider.py @@ -66,6 +66,9 @@ def __init__(self, charm: CharmBase, relation_name: str = "database") -> None: self.framework.observe( self.database_provides.on.database_requested, self._on_database_requested ) + self.framework.observe( + charm.on[self.relation_name].relation_changed, self._on_relation_changed + ) @staticmethod def _sanitize_extra_roles(extra_roles: str | None) -> list[str]: @@ -128,6 +131,8 @@ def _on_database_requested(self, event: DatabaseRequestedEvent) -> None: self.update_endpoints(event) self._update_unit_status(event.relation) + + self.charm.update_config() except ( PostgreSQLCreateDatabaseError, PostgreSQLCreateUserError, @@ -140,6 +145,28 @@ def _on_database_requested(self, event: DatabaseRequestedEvent) -> None: else f"Failed to initialize {self.relation_name} relation" ) + def _on_relation_changed(self, event: RelationChangedEvent) -> None: + # Check for some conditions before trying to access the PostgreSQL instance. + if not self.charm.is_cluster_initialised: + logger.debug( + "Deferring on_relation_changed: Cluster must be initialized before configuration can be updated with relation users" + ) + event.defer() + return + + user = f"relation-{event.relation.id}" + try: + if user not in self.charm.postgresql.list_users(): + logger.debug("Deferring on_relation_changed: user was not created yet") + event.defer() + return + except PostgreSQLListUsersError: + logger.debug("Deferring on_relation_changed: failed to list users") + event.defer() + return + + self.charm.update_config() + def _on_relation_broken(self, event: RelationBrokenEvent) -> None: """Correctly update the status.""" self._update_unit_status(event.relation) diff --git a/src/upgrade.py b/src/upgrade.py index db4fb5f978..7728af28b0 100644 --- a/src/upgrade.py +++ b/src/upgrade.py @@ -186,6 +186,8 @@ def _on_upgrade_granted(self, event: UpgradeGrantedEvent) -> None: ) raise Exception() + self.charm.update_config() + self.set_unit_completed() # Ensures leader gets its own relation-changed when it upgrades @@ -253,7 +255,9 @@ def _prepare_upgrade_from_legacy(self) -> None: def _set_up_new_access_roles_for_legacy(self) -> None: """Create missing access groups and their memberships.""" access_groups = self.charm.postgresql.list_access_groups() - if access_groups == set(ACCESS_GROUPS): + if access_groups == set(ACCESS_GROUPS) and sorted( + self.charm.postgresql.list_users_from_relation() + ) == sorted(self.charm.postgresql.list_users(group="relation_access")): return self.charm.postgresql.create_access_groups() diff --git a/templates/patroni.yml.j2 b/templates/patroni.yml.j2 index 0ff720d698..75a37a5d8a 100644 --- a/templates/patroni.yml.j2 +++ b/templates/patroni.yml.j2 @@ -159,14 +159,19 @@ postgresql: - local all operator scram-sha-256 - local all monitoring password {%- if not connectivity %} - - {{ 'hostssl' if enable_tls else 'host' }} all all 0.0.0.0/0 reject - {{ 'hostssl' if enable_tls else 'host' }} all all {{ self_ip }} md5 + - {{ 'hostssl' if enable_tls else 'host' }} all all 0.0.0.0/0 reject {%- elif enable_ldap %} - {{ 'hostssl' if enable_tls else 'host' }} all +identity_access 0.0.0.0/0 ldap {{ ldap_parameters }} - {{ 'hostssl' if enable_tls else 'host' }} all +internal_access 0.0.0.0/0 md5 - - {{ 'hostssl' if enable_tls else 'host' }} all +relation_access 0.0.0.0/0 md5 + {%- for user, databases in user_databases_map.items() %} + - {{ 'hostssl' if enable_tls else 'host' }} {{ databases }} {{ user }} 0.0.0.0/0 md5 + {%- endfor %} {%- else %} - - {{ 'hostssl' if enable_tls else 'host' }} all all 0.0.0.0/0 md5 + - {{ 'hostssl' if enable_tls else 'host' }} all +internal_access 0.0.0.0/0 md5 + {%- for user, databases in user_databases_map.items() %} + - {{ 'hostssl' if enable_tls else 'host' }} {{ databases }} {{ user }} 0.0.0.0/0 md5 + {%- endfor %} {%- endif %} - {{ 'hostssl' if enable_tls else 'host' }} replication replication 127.0.0.1/32 md5 # Allow replications connections from other cluster members. diff --git a/tests/integration/ha_tests/test_scaling_three_units.py b/tests/integration/ha_tests/test_scaling_three_units.py index 7a44d0f5c2..3615a04df6 100644 --- a/tests/integration/ha_tests/test_scaling_three_units.py +++ b/tests/integration/ha_tests/test_scaling_three_units.py @@ -95,6 +95,7 @@ async def test_removing_unit(ops_test: OpsTest, roles: list[str], continuous_wri == "Raft majority loss, run: promote-to-primary", timeout=600, ) + await ops_test.model.wait_for_idle(timeout=600, idle_period=45) run_action = ( await ops_test.model.applications[DATABASE_APP_NAME] diff --git a/tests/integration/ha_tests/test_scaling_three_units_async.py b/tests/integration/ha_tests/test_scaling_three_units_async.py index 41fc03451d..a45e1484e2 100644 --- a/tests/integration/ha_tests/test_scaling_three_units_async.py +++ b/tests/integration/ha_tests/test_scaling_three_units_async.py @@ -96,6 +96,7 @@ async def test_removing_unit(ops_test: OpsTest, roles: list[str], continuous_wri == "Raft majority loss, run: promote-to-primary", timeout=600, ) + await ops_test.model.wait_for_idle(timeout=600, idle_period=45) run_action = ( await ops_test.model.applications[DATABASE_APP_NAME] diff --git a/tests/integration/helpers.py b/tests/integration/helpers.py index 9794364a4b..e707f4ddf3 100644 --- a/tests/integration/helpers.py +++ b/tests/integration/helpers.py @@ -272,18 +272,22 @@ def count_switchovers(ops_test: OpsTest, unit_name: str) -> int: return len(switchover_history_info.json()) -def db_connect(host: str, password: str) -> psycopg2.extensions.connection: +def db_connect( + host: str, password: str, user: str = "operator", database: str = "postgres" +) -> psycopg2.extensions.connection: """Returns psycopg2 connection object linked to postgres db in the given host. Args: host: the IP of the postgres host password: operator user password + user: postgres user (default: operator) + database: postgres database (default: postgres) Returns: psycopg2 connection object linked to postgres db, under "operator" user. """ return psycopg2.connect( - f"dbname='postgres' user='operator' host='{host}' password='{password}' connect_timeout=10" + f"dbname='{database}' user='{user}' host='{host}' password='{password}' connect_timeout=10" ) @@ -423,7 +427,7 @@ async def deploy_and_relate_bundle_with_postgresql( else: await ops_test.juju("deploy", patched.name) - async with ops_test.fast_forward(fast_interval="30s"): + async with ops_test.fast_forward(fast_interval="60s"): # Relate application to PostgreSQL. relation = await ops_test.model.relate( main_application_name, f"{DATABASE_APP_NAME}:{relation_name}" diff --git a/tests/integration/test_pg_hba.py b/tests/integration/test_pg_hba.py new file mode 100644 index 0000000000..62a261bf8b --- /dev/null +++ b/tests/integration/test_pg_hba.py @@ -0,0 +1,178 @@ +#!/usr/bin/env python3 +# Copyright 2025 Canonical Ltd. +# See LICENSE file for licensing details. +import logging +import re +from time import sleep + +import psycopg2 +import pytest +from pytest_operator.plugin import OpsTest + +from .helpers import ( + CHARM_BASE, + DATABASE_APP_NAME, + db_connect, + get_primary, + get_unit_address, +) + +logger = logging.getLogger(__name__) + +DATA_INTEGRATOR_APP_NAME = "data-integrator" +FIRST_DATABASE = "test_1" +SECOND_DATABASE = "test_2" +FIRST_RELATION_USER = "relation_id_0" +SECOND_RELATION_USER = "relation_id_1" +PASSWORD = "test-password" + + +@pytest.mark.abort_on_fail +async def test_pg_hba(ops_test: OpsTest, charm): + async with ops_test.fast_forward(): + logger.info("Deploying charms") + if DATABASE_APP_NAME not in ops_test.model.applications: + await ops_test.model.deploy( + charm, + num_units=2, + base=CHARM_BASE, + config={"profile": "testing"}, + ) + if DATA_INTEGRATOR_APP_NAME not in ops_test.model.applications: + await ops_test.model.deploy( + DATA_INTEGRATOR_APP_NAME, + config={"database-name": FIRST_DATABASE, "extra-user-roles": "SUPERUSER"}, + ) + + logger.info("Adding relation between charms") + relations = [ + relation + for relation in ops_test.model.applications[DATABASE_APP_NAME].relations + if not relation.is_peer + and f"{relation.requires.application_name}:{relation.requires.name}" + == f"{DATA_INTEGRATOR_APP_NAME}:postgresql" + ] + if not relations: + await ops_test.model.add_relation(DATA_INTEGRATOR_APP_NAME, DATABASE_APP_NAME) + + await ops_test.model.wait_for_idle( + apps=[DATA_INTEGRATOR_APP_NAME, DATABASE_APP_NAME], status="active", timeout=1000 + ) + + primary = await get_primary(ops_test, f"{DATABASE_APP_NAME}/0") + address = get_unit_address(ops_test, primary) + data_integrator_unit = ops_test.model.applications[DATA_INTEGRATOR_APP_NAME].units[0] + action = await data_integrator_unit.run_action(action_name="get-credentials") + result = await action.wait() + credentials = result.results + connection = None + try: + connection = db_connect( + host=address, + password=credentials["postgresql"]["password"], + user=credentials["postgresql"]["username"], + database=FIRST_DATABASE, + ) + connection.autocommit = True + with connection.cursor() as cursor: + logger.info("Dropping database objects from the previous test run (if any)") + cursor.execute(f"DROP USER IF EXISTS {FIRST_RELATION_USER};") + cursor.execute( + f"SELECT datname FROM pg_database WHERE datname='{SECOND_DATABASE}';" + ) + if cursor.fetchone() is not None: + cursor.execute( + f"REVOKE ALL ON DATABASE {SECOND_DATABASE} FROM {SECOND_RELATION_USER};" + ) + cursor.execute(f"DROP USER IF EXISTS {SECOND_RELATION_USER};") + cursor.execute(f"DROP DATABASE IF EXISTS {SECOND_DATABASE};") + cursor.execute("DROP SCHEMA IF EXISTS test;") + + logger.info("Creating database objects needed for the test") + cursor.execute( + f"CREATE USER {FIRST_RELATION_USER} WITH LOGIN SUPERUSER ENCRYPTED PASSWORD '{PASSWORD}';" + ) + cursor.execute( + f"CREATE USER {SECOND_RELATION_USER} WITH LOGIN ENCRYPTED PASSWORD '{PASSWORD}';" + ) + cursor.execute(f"CREATE DATABASE {SECOND_DATABASE};") + cursor.execute( + f"GRANT CONNECT ON DATABASE {SECOND_DATABASE} TO {SECOND_RELATION_USER};" + ) + cursor.execute("CREATE SCHEMA test;") + finally: + if connection: + connection.close() + + sleep(60) + + for unit in ops_test.model.applications[DATABASE_APP_NAME].units: + try: + address = get_unit_address(ops_test, unit.name) + + logger.info( + f"Checking that the user {FIRST_RELATION_USER} can connect to the database {FIRST_DATABASE} on {unit.name}" + ) + with ( + db_connect( + host=address, + password=PASSWORD, + user=FIRST_RELATION_USER, + database=FIRST_DATABASE, + ) as connection, + connection.cursor() as cursor, + ): + # Check the version that the application received is the same on the + # database server. + cursor.execute("SELECT version();") + data = cursor.fetchone()[0].split(" ")[1] + + # Get the version of the database and compare with the information that + # was retrieved directly from the database. + assert credentials["postgresql"]["version"] == data + connection.close() + + logger.info( + f"Checking that the user {SECOND_RELATION_USER} can connect to the database {SECOND_DATABASE} on {unit.name}" + ) + with ( + db_connect( + host=address, + password=PASSWORD, + user=SECOND_RELATION_USER, + database=SECOND_DATABASE, + ) as connection, + connection.cursor() as cursor, + ): + # Check the version that the application received is the same on the + # database server. + cursor.execute("SELECT VERSION();") + + # Get the version of the database and compare with the information that + # was retrieved directly from the database. + assert credentials["postgresql"]["version"] == data + + logger.info( + f"Checking that the user {SECOND_RELATION_USER} cannot connect to the database {FIRST_DATABASE} on {unit.name}" + ) + with db_connect( + host=address, + password=PASSWORD, + user=SECOND_RELATION_USER, + database=FIRST_DATABASE, + ) as connection: + assert False, ( + f"User {SECOND_RELATION_USER} should not be able to connect to the database {FIRST_DATABASE}" + ) + except psycopg2.OperationalError as e: + if ( + re.search( + f'^(connection to server at \\").*(\\", port 5432).*(failed: FATAL: no pg_hba.conf entry for host \\").*(\\", user \\"{SECOND_RELATION_USER}\\", database \\"{FIRST_DATABASE}\\", no encryption)$', + str(e), + ) + is None + ): + raise + finally: + if connection: + connection.close() diff --git a/tests/spread/test_pg_hba.py/task.yaml b/tests/spread/test_pg_hba.py/task.yaml new file mode 100644 index 0000000000..80f3d9e3e3 --- /dev/null +++ b/tests/spread/test_pg_hba.py/task.yaml @@ -0,0 +1,7 @@ +summary: test_pg_hba.py +environment: + TEST_MODULE: test_pg_hba.py +execute: | + tox run -e integration -- "tests/integration/$TEST_MODULE" --model testing --alluredir="$SPREAD_TASK/allure-results" +artifacts: + - allure-results diff --git a/tests/unit/test_charm.py b/tests/unit/test_charm.py index a81aa7eb35..b648b0ca82 100644 --- a/tests/unit/test_charm.py +++ b/tests/unit/test_charm.py @@ -1324,6 +1324,7 @@ def test_update_config(harness): restore_to_latest=False, parameters={"test": "test"}, no_peers=False, + user_databases_map={"operator": "all", "replication": "all", "rewind": "all"}, ) _handle_postgresql_restart_need.assert_called_once_with(False) _restart_ldap_sync_service.assert_called_once() @@ -1353,6 +1354,7 @@ def test_update_config(harness): restore_to_latest=False, parameters={"test": "test"}, no_peers=False, + user_databases_map={"operator": "all", "replication": "all", "rewind": "all"}, ) _handle_postgresql_restart_need.assert_called_once() _restart_ldap_sync_service.assert_called_once() diff --git a/tests/unit/test_cluster_topology_observer.py b/tests/unit/test_cluster_topology_observer.py index 3d0495b8eb..4047d2b13d 100644 --- a/tests/unit/test_cluster_topology_observer.py +++ b/tests/unit/test_cluster_topology_observer.py @@ -130,7 +130,7 @@ def test_dispatch(harness): with patch("subprocess.run") as _run: command = "test-command" charm_dir = "/path" - dispatch(command, harness.charm.unit.name, charm_dir) + dispatch(command, harness.charm.unit.name, charm_dir, "cluster_topology_change") _run.assert_called_once_with([ command, "-u", @@ -141,6 +141,7 @@ def test_dispatch(harness): def test_main(): with ( + patch("scripts.cluster_topology_observer.check_for_authorisation_rules_changes"), patch.object( sys, "argv", diff --git a/tests/unit/test_db.py b/tests/unit/test_db.py index a400ef708e..a811687f3a 100644 --- a/tests/unit/test_db.py +++ b/tests/unit/test_db.py @@ -83,6 +83,8 @@ def request_database(_harness): def test_on_relation_changed(harness): with ( + patch("charm.PostgresqlOperatorCharm.update_config"), + patch.object(PostgresqlOperatorCharm, "postgresql", Mock()) as postgresql_mock, patch("charm.DbProvides.set_up_relation") as _set_up_relation, patch.object(EventBase, "defer") as _defer, patch( @@ -92,7 +94,8 @@ def test_on_relation_changed(harness): patch("charm.Patroni.member_started", new_callable=PropertyMock) as _member_started, ): # Set some side effects to test multiple situations. - _member_started.side_effect = [False, True, True, True, True, True] + _member_started.side_effect = [True, False, True, True] + postgresql_mock.list_users.return_value = {"relation-0"} _primary_endpoint.side_effect = [ None, {"1.1.1.1"}, @@ -181,6 +184,7 @@ def test_get_extensions(harness): def test_set_up_relation(harness): with ( + patch("charm.PostgresqlOperatorCharm.update_config"), patch.object(PostgresqlOperatorCharm, "postgresql", Mock()) as postgresql_mock, patch("subprocess.check_output", return_value=b"C"), patch("relations.db.DbProvides._update_unit_status") as _update_unit_status, diff --git a/tests/unit/test_postgresql_provider.py b/tests/unit/test_postgresql_provider.py index 13b065d299..46a28570ba 100644 --- a/tests/unit/test_postgresql_provider.py +++ b/tests/unit/test_postgresql_provider.py @@ -75,6 +75,10 @@ def request_database(_harness): def test_on_database_requested(harness): with ( + patch("charm.PostgresqlOperatorCharm.update_config"), + patch( + "relations.postgresql_provider.PostgreSQLProvider._on_relation_changed" + ) as _on_relation_changed, patch.object(PostgresqlOperatorCharm, "postgresql", Mock()) as postgresql_mock, patch("subprocess.check_output", return_value=b"C"), patch("charm.PostgreSQLProvider.update_endpoints") as _update_endpoints, From 53a23149b53b5895e06a120f608e9d40e82e6ddd Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 4 Jun 2025 11:53:00 +0300 Subject: [PATCH 034/112] Update charmcraft.yaml build tools (#871) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- charmcraft.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/charmcraft.yaml b/charmcraft.yaml index 4d1641575c..f183aa2d69 100644 --- a/charmcraft.yaml +++ b/charmcraft.yaml @@ -24,10 +24,10 @@ parts: # Use environment variable instead of `--break-system-packages` to avoid failing on older # versions of pip that do not recognize `--break-system-packages` # `--user` needed (in addition to `--break-system-packages`) for Ubuntu >=24.04 - PIP_BREAK_SYSTEM_PACKAGES=true python3 -m pip install --user --upgrade pip==25.1 # renovate: charmcraft-pip-latest + PIP_BREAK_SYSTEM_PACKAGES=true python3 -m pip install --user --upgrade pip==25.1.1 # renovate: charmcraft-pip-latest # Use uv to install poetry so that a newer version of Python can be installed if needed by poetry - curl --proto '=https' --tlsv1.2 -LsSf https://github.com/astral-sh/uv/releases/download/0.6.17/uv-installer.sh | sh # renovate: charmcraft-uv-latest + curl --proto '=https' --tlsv1.2 -LsSf https://github.com/astral-sh/uv/releases/download/0.7.9/uv-installer.sh | sh # renovate: charmcraft-uv-latest # poetry 2.0.0 requires Python >=3.9 if ! "$HOME/.local/bin/uv" python find '>=3.9' then @@ -35,7 +35,7 @@ parts: # (to reduce the number of Python versions we use) "$HOME/.local/bin/uv" python install 3.10.12 # renovate: charmcraft-python-ubuntu-22.04 fi - "$HOME/.local/bin/uv" tool install --no-python-downloads --python '>=3.9' poetry==2.1.2 --with poetry-plugin-export==1.9.0 # renovate: charmcraft-poetry-latest + "$HOME/.local/bin/uv" tool install --no-python-downloads --python '>=3.9' poetry==2.1.3 --with poetry-plugin-export==1.9.0 # renovate: charmcraft-poetry-latest ln -sf "$HOME/.local/bin/poetry" /usr/local/bin/poetry # "charm-poetry" part name is arbitrary; use for consistency @@ -75,7 +75,7 @@ parts: # rpds-py (Python package) >=0.19.0 requires rustc >=1.76, which is not available in the # Ubuntu 22.04 archive. Install rustc and cargo using rustup instead of the Ubuntu archive rustup set profile minimal - rustup default 1.86.0 # renovate: charmcraft-rust-latest + rustup default 1.87.0 # renovate: charmcraft-rust-latest craftctl default # Include requirements.txt in *.charm artifact for easier debugging From 67d7c5f1485f9b5443af89dcf7fc42abb876e1d5 Mon Sep 17 00:00:00 2001 From: Dragomir Penev <6687393+dragomirp@users.noreply.github.com> Date: Thu, 5 Jun 2025 12:58:15 +0300 Subject: [PATCH 035/112] [MISC] Remove JujuVersion warning in 14/edge (#933) * Remove JujuVersion warning * Update libs --- lib/charms/operator_libs_linux/v2/snap.py | 5 ++++- .../tempo_coordinator_k8s/v0/charm_tracing.py | 13 ++++++++++--- .../v2/tls_certificates.py | 4 ++-- src/charm.py | 9 +++++---- tests/unit/conftest.py | 2 +- tests/unit/test_charm.py | 6 +++--- 6 files changed, 25 insertions(+), 14 deletions(-) diff --git a/lib/charms/operator_libs_linux/v2/snap.py b/lib/charms/operator_libs_linux/v2/snap.py index 5cd0ffd4b2..3623d1db2c 100644 --- a/lib/charms/operator_libs_linux/v2/snap.py +++ b/lib/charms/operator_libs_linux/v2/snap.py @@ -102,7 +102,7 @@ # Increment this PATCH version before using `charmcraft publish-lib` or reset # to 0 if you are raising the major API version -LIBPATCH = 10 +LIBPATCH = 11 # Regex to locate 7-bit C1 ANSI sequences @@ -577,6 +577,9 @@ def _refresh( if revision: args.append(f'--revision="{revision}"') + if self.confinement == 'classic': + args.append('--classic') + if devmode: args.append("--devmode") diff --git a/lib/charms/tempo_coordinator_k8s/v0/charm_tracing.py b/lib/charms/tempo_coordinator_k8s/v0/charm_tracing.py index e2208f756f..050e5b384b 100644 --- a/lib/charms/tempo_coordinator_k8s/v0/charm_tracing.py +++ b/lib/charms/tempo_coordinator_k8s/v0/charm_tracing.py @@ -314,7 +314,7 @@ def _remove_stale_otel_sdk_packages(): import opentelemetry import ops from opentelemetry.exporter.otlp.proto.common._internal.trace_encoder import ( - encode_spans, + encode_spans # type: ignore ) from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter from opentelemetry.sdk.resources import Resource @@ -348,7 +348,7 @@ def _remove_stale_otel_sdk_packages(): # Increment this PATCH version before using `charmcraft publish-lib` or reset # to 0 if you are raising the major API version -LIBPATCH = 7 +LIBPATCH = 8 PYDEPS = ["opentelemetry-exporter-otlp-proto-http==1.21.0"] @@ -704,7 +704,14 @@ def _get_server_cert( f"{charm_type}.{server_cert_attr} is None; sending traces over INSECURE connection." ) return - elif not Path(server_cert).is_absolute(): + if not isinstance(server_cert, (str, Path)): + logger.warning( + f"{charm_type}.{server_cert_attr} has unexpected type {type(server_cert)}; " + f"sending traces over INSECURE connection." + ) + return + path = Path(server_cert) + if not path.is_absolute() or not path.exists(): raise ValueError( f"{charm_type}.{server_cert_attr} should resolve to a valid tls cert absolute path (string | Path)); " f"got {server_cert} instead." diff --git a/lib/charms/tls_certificates_interface/v2/tls_certificates.py b/lib/charms/tls_certificates_interface/v2/tls_certificates.py index c232362feb..8023d85ddd 100644 --- a/lib/charms/tls_certificates_interface/v2/tls_certificates.py +++ b/lib/charms/tls_certificates_interface/v2/tls_certificates.py @@ -282,10 +282,10 @@ def _on_all_certificates_invalidated(self, event: AllCertificatesInvalidatedEven from typing import Any, Dict, List, Literal, Optional, Union from cryptography import x509 -from cryptography.hazmat._oid import ExtensionOID from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import rsa from cryptography.hazmat.primitives.serialization import pkcs12 +from cryptography.x509.oid import ExtensionOID from jsonschema import exceptions, validate from ops.charm import ( CharmBase, @@ -307,7 +307,7 @@ def _on_all_certificates_invalidated(self, event: AllCertificatesInvalidatedEven # Increment this PATCH version before using `charmcraft publish-lib` or reset # to 0 if you are raising the major API version -LIBPATCH = 29 +LIBPATCH = 30 PYDEPS = ["cryptography", "jsonschema"] diff --git a/src/charm.py b/src/charm.py index 0968e55394..a8303535b8 100755 --- a/src/charm.py +++ b/src/charm.py @@ -37,7 +37,7 @@ from charms.postgresql_k8s.v0.postgresql_tls import PostgreSQLTLS from charms.rolling_ops.v0.rollingops import RollingOpsManager, RunWithLock from charms.tempo_coordinator_k8s.v0.charm_tracing import trace_charm -from ops import JujuVersion, main +from ops import main from ops.charm import ( ActionEvent, HookEvent, @@ -180,8 +180,9 @@ def __init__(self, *args): deleted_label=SECRET_DELETED_LABEL, ) - juju_version = JujuVersion.from_environ() - run_cmd = "/usr/bin/juju-exec" if juju_version.major > 2 else "/usr/bin/juju-run" + run_cmd = ( + "/usr/bin/juju-exec" if self.model.juju_version.major > 2 else "/usr/bin/juju-run" + ) self._observer = ClusterTopologyObserver(self, run_cmd) self._rotate_logs = RotateLogs(self) self.framework.observe( @@ -316,7 +317,7 @@ def peer_relation_data(self, scope: Scopes) -> DataPeerData: def _translate_field_to_secret_key(self, key: str) -> str: """Change 'key' to secrets-compatible key field.""" - if not JujuVersion.from_environ().has_secrets: + if not self.model.juju_version.has_secrets: return key key = SECRET_KEY_OVERRIDES.get(key, key) new_key = key.replace("_", "-") diff --git a/tests/unit/conftest.py b/tests/unit/conftest.py index 03c68492e9..d8ae8bac70 100644 --- a/tests/unit/conftest.py +++ b/tests/unit/conftest.py @@ -11,7 +11,7 @@ # charm.JujuVersion.has_secrets set as True or as False @pytest.fixture(params=[True, False], autouse=True) def _has_secrets(request, monkeypatch): - monkeypatch.setattr("charm.JujuVersion.has_secrets", PropertyMock(return_value=request.param)) + monkeypatch.setattr("ops.JujuVersion.has_secrets", PropertyMock(return_value=request.param)) return request.param diff --git a/tests/unit/test_charm.py b/tests/unit/test_charm.py index b648b0ca82..0e39f1cd16 100644 --- a/tests/unit/test_charm.py +++ b/tests/unit/test_charm.py @@ -1879,17 +1879,17 @@ def test_get_available_memory(harness): def test_juju_run_exec_divergence(harness): with ( patch("charm.ClusterTopologyObserver") as _topology_observer, - patch("charm.JujuVersion") as _juju_version, + patch("ops.model.Model.juju_version", new_callable=PropertyMock) as _juju_version, ): # Juju 2 - _juju_version.from_environ.return_value.major = 2 + _juju_version.return_value.major = 2 harness = Harness(PostgresqlOperatorCharm) harness.begin() _topology_observer.assert_called_once_with(harness.charm, "/usr/bin/juju-run") _topology_observer.reset_mock() # Juju 3 - _juju_version.from_environ.return_value.major = 3 + _juju_version.return_value.major = 3 harness = Harness(PostgresqlOperatorCharm) harness.begin() _topology_observer.assert_called_once_with(harness.charm, "/usr/bin/juju-exec") From 3bd748ae0176a1c1c21bcc1fd54af030815c4234 Mon Sep 17 00:00:00 2001 From: Andreia Date: Fri, 6 Jun 2025 12:26:38 +0200 Subject: [PATCH 036/112] Refactor v14 documentation for Sphinx (#919) * initial starter pack transfer * update conf.py * import processed discourse pages * fix internal references and some broken URLs * fix some style errors * organize navigation * remove h1 heading anchors * add images to repository * edit home page * update .readthedocs.yaml * remove docs/requirements.txt from .gitignore scope * fix incorrect paths * remove shell syntax from code blocks * remove juju 2 banners * fix dropdown formatting * fix and polish admonitions, collapsible, and misc formatting * remove v16 docs * remove reference to nonexistant page * Join all tutorial pages * rename how-to-guides to how-to * polish cloud deployment guides and rename leftover how-to-guide references * polish and sync how-to guides with k8s * remove discourse sync workflow * specify channel on all deploy commands * misc polishing, add version to side nav * add pg 16 admonitions * ignore docs folder in charm workflows * sync misc. pages with k8s * Minor README update with new documentation link * add new section to CLI-helpers reference * pin commit for v16 tag on markdown lint workflow for added security * Update README.md * remove sphinx python dependency check workflow * Update index.md: add link to roles.md (#928) --------- Co-authored-by: Marcelo Henrique Neppel Co-authored-by: Alex Lutay <1928266+taurus-forever@users.noreply.github.com> --- .github/workflows/automatic-doc-checks.yml | 24 + .github/workflows/ci.yaml | 2 +- .github/workflows/lib-check.yaml | 1 + .github/workflows/markdown-style-checks.yml | 24 + .github/workflows/sync_docs.yaml | 18 - .gitignore | 2 +- .readthedocs.yaml | 39 + README.md | 13 +- docs/.custom_wordlist.txt | 40 ++ docs/.gitignore | 26 + docs/.sphinx/.markdownlint.json | 21 + docs/.sphinx/.pre-commit-config.yaml | 23 + docs/.sphinx/.wordlist.txt | 331 +++++++++ docs/.sphinx/get_vale_conf.py | 151 ++++ docs/.sphinx/metrics/build_metrics.sh | 15 + docs/.sphinx/metrics/source_metrics.sh | 66 ++ docs/.sphinx/pa11y.json | 9 + docs/.sphinx/spellingcheck.yaml | 30 + docs/.sphinx/update_sp.py | 268 +++++++ docs/.sphinx/version | 1 + docs/Makefile | 196 +++++ docs/conf.py | 336 +++++++++ docs/explanation.md | 33 - docs/explanation/architecture-diagram.png | Bin 0 -> 120226 bytes .../{e-architecture.md => architecture.md} | 66 +- ...ction-pooling.md => connection-pooling.md} | 8 +- docs/explanation/index.md | 53 ++ ...dpoints.md => interfaces-and-endpoints.md} | 20 +- .../{e-juju-details.md => juju.md} | 15 +- .../{e-legacy-charm.md => legacy-charm.md} | 55 +- docs/explanation/{e-logs.md => logs.md} | 25 +- docs/explanation/roles.md | 119 ++++ .../cryptography.md} | 3 +- .../{e-security.md => security/index.md} | 21 +- docs/explanation/unit-types.png | Bin 0 -> 126980 bytes docs/explanation/{e-units.md => units.md} | 43 +- docs/explanation/{e-users.md => users.md} | 66 +- docs/how-to.md | 111 --- .../configure-s3-aws.md} | 50 +- .../configure-s3-radosgw.md} | 50 +- .../create-a-backup.md} | 46 +- docs/how-to/back-up-and-restore/index.md | 13 + .../manage-backup-retention.md} | 46 +- .../migrate-a-cluster.md} | 36 +- .../restore-a-backup.md} | 38 +- .../cross-regional-async-replication/index.md | 41 ++ .../integrate-with-a-client-app.md} | 24 +- .../remove-or-recover-a-cluster.md} | 29 +- .../set-up-clusters.md} | 37 +- .../air-gapped.md} | 47 +- docs/how-to/deploy/aws-ec2-availability.png | Bin 0 -> 53477 bytes .../{h-deploy-ec2.md => deploy/aws-ec2.md} | 119 ++-- docs/how-to/deploy/azure-availability.png | Bin 0 -> 372861 bytes .../{h-deploy-azure.md => deploy/azure.md} | 147 ++-- docs/how-to/deploy/gce-availability.png | Bin 0 -> 77808 bytes .../how-to/{h-deploy-gce.md => deploy/gce.md} | 111 +-- docs/how-to/{h-deploy.md => deploy/index.md} | 90 +-- docs/how-to/deploy/juju-storage.md | 116 +++ docs/how-to/deploy/maas-create-tag.png | Bin 0 -> 95441 bytes docs/how-to/deploy/maas-dhcp-banner.png | Bin 0 -> 33261 bytes docs/how-to/deploy/maas-image-downloads.png | Bin 0 -> 67262 bytes .../{h-deploy-maas.md => deploy/maas.md} | 87 +-- .../multi-az.md} | 74 +- docs/how-to/deploy/sunbeam-dashboard.png | Bin 0 -> 162227 bytes .../sunbeam.md} | 44 +- .../terraform.md} | 49 +- .../tls-vip-access.md} | 78 +- docs/how-to/deploy/tls-vip-setup.png | Bin 0 -> 75135 bytes docs/how-to/development/index.md | 10 + .../integrate-with-your-charm.md} | 32 +- .../migrate-data-via-backup-restore.md | 47 ++ .../migrate-data-via-pg-dump.md} | 69 +- .../{h-enable-ldap.md => enable-ldap.md} | 61 +- .../enable-timescaledb.md} | 53 +- .../index.md} | 33 +- .../how-to/{h-enable-tls.md => enable-tls.md} | 52 +- ...l-access.md => external-network-access.md} | 5 +- docs/how-to/h-async.md | 30 - docs/how-to/h-deploy-juju-spaces.md | 65 -- docs/how-to/h-deploy-juju-storage.md | 284 -------- docs/how-to/h-migrate-backup-restore.md | 41 -- docs/how-to/h-upgrade.md | 12 - docs/how-to/index.md | 131 ++++ ... => integrate-with-another-application.md} | 69 +- docs/how-to/manage-passwords.md | 32 + .../monitoring-cos/alert-rules-grafana-ui.png | Bin 0 -> 274677 bytes .../enable-alert-rules.md} | 22 +- .../enable-monitoring.md} | 70 +- .../enable-profiling.md} | 100 ++- .../enable-tracing.md} | 74 +- docs/how-to/monitoring-cos/index.md | 11 + .../monitoring-cos/postgresql-grafana-ui.png | Bin 0 -> 354816 bytes .../profile-grafana-parca-plugin.png | Bin 0 -> 167635 bytes .../monitoring-cos/profile-parca-web-ui.png | Bin 0 -> 346229 bytes .../monitoring-cos/pushover-client.jpeg | Bin 0 -> 155021 bytes .../monitoring-cos/trace-grafana-tempo.jpeg | Bin 0 -> 114080 bytes docs/how-to/{h-scale.md => scale-replicas.md} | 39 +- ...ver-failover.md => switchover-failover.md} | 82 ++- docs/how-to/upgrade/index.md | 23 + .../perform-a-minor-rollback.md} | 28 +- .../perform-a-minor-upgrade.md} | 78 +- docs/index.md | 46 ++ docs/overview.md | 138 ---- docs/reference.md | 26 - .../{r-alert-rules.md => alert-rules.md} | 5 +- docs/reference/{r-contacts.md => contacts.md} | 8 +- docs/reference/index.md | 29 + ...rmance.md => performance-and-resources.md} | 35 +- ...ns-extensions.md => plugins-extensions.md} | 3 +- docs/reference/{r-releases.md => releases.md} | 78 +- ...oftware-testing.md => software-testing.md} | 39 +- docs/reference/{r-statuses.md => statuses.md} | 13 +- ...requirements.md => system-requirements.md} | 16 +- .../cli-helpers.md} | 144 ++-- .../index.md} | 104 +-- .../sos-report.md} | 26 +- docs/reference/{r-versions.md => versions.md} | 61 +- docs/requirements.txt | 3 + docs/reuse/links.txt | 43 ++ docs/reuse/substitutions.txt | 7 + docs/reuse/substitutions.yaml | 4 + docs/tutorial.md | 24 - docs/tutorial/index.md | 674 ++++++++++++++++++ docs/tutorial/t-access.md | 162 ----- docs/tutorial/t-clean-up.md | 37 - docs/tutorial/t-deploy.md | 39 - docs/tutorial/t-enable-tls.md | 89 --- docs/tutorial/t-integrate.md | 167 ----- docs/tutorial/t-manage-passwords.md | 91 --- docs/tutorial/t-scale.md | 81 --- docs/tutorial/t-set-up.md | 68 -- 131 files changed, 4538 insertions(+), 2921 deletions(-) create mode 100644 .github/workflows/automatic-doc-checks.yml create mode 100644 .github/workflows/markdown-style-checks.yml delete mode 100644 .github/workflows/sync_docs.yaml create mode 100644 .readthedocs.yaml create mode 100644 docs/.custom_wordlist.txt create mode 100644 docs/.gitignore create mode 100644 docs/.sphinx/.markdownlint.json create mode 100644 docs/.sphinx/.pre-commit-config.yaml create mode 100644 docs/.sphinx/.wordlist.txt create mode 100644 docs/.sphinx/get_vale_conf.py create mode 100755 docs/.sphinx/metrics/build_metrics.sh create mode 100755 docs/.sphinx/metrics/source_metrics.sh create mode 100644 docs/.sphinx/pa11y.json create mode 100644 docs/.sphinx/spellingcheck.yaml create mode 100755 docs/.sphinx/update_sp.py create mode 100644 docs/.sphinx/version create mode 100644 docs/Makefile create mode 100644 docs/conf.py delete mode 100644 docs/explanation.md create mode 100644 docs/explanation/architecture-diagram.png rename docs/explanation/{e-architecture.md => architecture.md} (74%) rename docs/explanation/{e-connection-pooling.md => connection-pooling.md} (80%) create mode 100644 docs/explanation/index.md rename docs/explanation/{e-interfaces-endpoints.md => interfaces-and-endpoints.md} (74%) rename docs/explanation/{e-juju-details.md => juju.md} (76%) rename docs/explanation/{e-legacy-charm.md => legacy-charm.md} (68%) rename docs/explanation/{e-logs.md => logs.md} (97%) create mode 100644 docs/explanation/roles.md rename docs/explanation/{e-cryptography.md => security/cryptography.md} (99%) rename docs/explanation/{e-security.md => security/index.md} (85%) create mode 100644 docs/explanation/unit-types.png rename docs/explanation/{e-units.md => units.md} (68%) rename docs/explanation/{e-users.md => users.md} (69%) delete mode 100644 docs/how-to.md rename docs/how-to/{h-configure-s3-aws.md => back-up-and-restore/configure-s3-aws.md} (80%) rename docs/how-to/{h-configure-s3-radosgw.md => back-up-and-restore/configure-s3-radosgw.md} (70%) rename docs/how-to/{h-create-backup.md => back-up-and-restore/create-a-backup.md} (61%) create mode 100644 docs/how-to/back-up-and-restore/index.md rename docs/how-to/{h-manage-backup-retention.md => back-up-and-restore/manage-backup-retention.md} (57%) rename docs/how-to/{h-migrate-cluster.md => back-up-and-restore/migrate-a-cluster.md} (64%) rename docs/how-to/{h-restore-backup.md => back-up-and-restore/restore-a-backup.md} (77%) create mode 100644 docs/how-to/cross-regional-async-replication/index.md rename docs/how-to/{h-async-integrate.md => cross-regional-async-replication/integrate-with-a-client-app.md} (81%) rename docs/how-to/{h-async-remove-recover.md => cross-regional-async-replication/remove-or-recover-a-cluster.md} (69%) rename docs/how-to/{h-async-set-up.md => cross-regional-async-replication/set-up-clusters.md} (75%) rename docs/how-to/{h-deploy-airgapped.md => deploy/air-gapped.md} (85%) create mode 100644 docs/how-to/deploy/aws-ec2-availability.png rename docs/how-to/{h-deploy-ec2.md => deploy/aws-ec2.md} (85%) create mode 100644 docs/how-to/deploy/azure-availability.png rename docs/how-to/{h-deploy-azure.md => deploy/azure.md} (85%) create mode 100644 docs/how-to/deploy/gce-availability.png rename docs/how-to/{h-deploy-gce.md => deploy/gce.md} (85%) rename docs/how-to/{h-deploy.md => deploy/index.md} (60%) create mode 100644 docs/how-to/deploy/juju-storage.md create mode 100644 docs/how-to/deploy/maas-create-tag.png create mode 100644 docs/how-to/deploy/maas-dhcp-banner.png create mode 100644 docs/how-to/deploy/maas-image-downloads.png rename docs/how-to/{h-deploy-maas.md => deploy/maas.md} (68%) rename docs/how-to/{h-deploy-multi-az.md => deploy/multi-az.md} (83%) create mode 100644 docs/how-to/deploy/sunbeam-dashboard.png rename docs/how-to/{h-deploy-sunbeam.md => deploy/sunbeam.md} (82%) rename docs/how-to/{h-deploy-terraform.md => deploy/terraform.md} (85%) rename docs/how-to/{h-deploy-tls-vip-access.md => deploy/tls-vip-access.md} (85%) create mode 100644 docs/how-to/deploy/tls-vip-setup.png create mode 100644 docs/how-to/development/index.md rename docs/how-to/{h-development-integrate.md => development/integrate-with-your-charm.md} (66%) create mode 100644 docs/how-to/development/migrate-data-via-backup-restore.md rename docs/how-to/{h-migrate-pgdump.md => development/migrate-data-via-pg-dump.md} (81%) rename docs/how-to/{h-enable-ldap.md => enable-ldap.md} (71%) rename docs/{reference/r-plugins-timescaledb.md => how-to/enable-plugins-extensions/enable-timescaledb.md} (64%) rename docs/how-to/{h-enable-plugins-extensions.md => enable-plugins-extensions/index.md} (63%) rename docs/how-to/{h-enable-tls.md => enable-tls.md} (79%) rename docs/how-to/{h-external-access.md => external-network-access.md} (89%) delete mode 100644 docs/how-to/h-async.md delete mode 100644 docs/how-to/h-deploy-juju-spaces.md delete mode 100644 docs/how-to/h-deploy-juju-storage.md delete mode 100644 docs/how-to/h-migrate-backup-restore.md delete mode 100644 docs/how-to/h-upgrade.md create mode 100644 docs/how-to/index.md rename docs/how-to/{h-integrate.md => integrate-with-another-application.md} (54%) create mode 100644 docs/how-to/manage-passwords.md create mode 100644 docs/how-to/monitoring-cos/alert-rules-grafana-ui.png rename docs/how-to/{h-enable-alert-rules.md => monitoring-cos/enable-alert-rules.md} (89%) rename docs/how-to/{h-enable-monitoring.md => monitoring-cos/enable-monitoring.md} (88%) rename docs/how-to/{h-enable-profiling.md => monitoring-cos/enable-profiling.md} (68%) rename docs/how-to/{h-enable-tracing.md => monitoring-cos/enable-tracing.md} (72%) create mode 100644 docs/how-to/monitoring-cos/index.md create mode 100644 docs/how-to/monitoring-cos/postgresql-grafana-ui.png create mode 100644 docs/how-to/monitoring-cos/profile-grafana-parca-plugin.png create mode 100644 docs/how-to/monitoring-cos/profile-parca-web-ui.png create mode 100644 docs/how-to/monitoring-cos/pushover-client.jpeg create mode 100644 docs/how-to/monitoring-cos/trace-grafana-tempo.jpeg rename docs/how-to/{h-scale.md => scale-replicas.md} (71%) rename docs/how-to/{h-switchover-failover.md => switchover-failover.md} (72%) create mode 100644 docs/how-to/upgrade/index.md rename docs/how-to/{h-rollback-minor.md => upgrade/perform-a-minor-rollback.md} (77%) rename docs/how-to/{h-upgrade-minor.md => upgrade/perform-a-minor-upgrade.md} (86%) create mode 100644 docs/index.md delete mode 100644 docs/overview.md delete mode 100644 docs/reference.md rename docs/reference/{r-alert-rules.md => alert-rules.md} (98%) rename docs/reference/{r-contacts.md => contacts.md} (97%) create mode 100644 docs/reference/index.md rename docs/reference/{r-performance.md => performance-and-resources.md} (74%) rename docs/reference/{r-plugins-extensions.md => plugins-extensions.md} (99%) rename docs/reference/{r-releases.md => releases.md} (58%) rename docs/reference/{r-software-testing.md => software-testing.md} (74%) rename docs/reference/{r-statuses.md => statuses.md} (82%) rename docs/reference/{r-system-requirements.md => system-requirements.md} (82%) rename docs/reference/{r-cli-helpers.md => troubleshooting/cli-helpers.md} (72%) rename docs/reference/{r-troubleshooting.md => troubleshooting/index.md} (78%) rename docs/reference/{r-sos-report.md => troubleshooting/sos-report.md} (96%) rename docs/reference/{r-versions.md => versions.md} (70%) create mode 100644 docs/requirements.txt create mode 100644 docs/reuse/links.txt create mode 100644 docs/reuse/substitutions.txt create mode 100644 docs/reuse/substitutions.yaml delete mode 100644 docs/tutorial.md create mode 100644 docs/tutorial/index.md delete mode 100644 docs/tutorial/t-access.md delete mode 100644 docs/tutorial/t-clean-up.md delete mode 100644 docs/tutorial/t-deploy.md delete mode 100644 docs/tutorial/t-enable-tls.md delete mode 100644 docs/tutorial/t-integrate.md delete mode 100644 docs/tutorial/t-manage-passwords.md delete mode 100644 docs/tutorial/t-scale.md delete mode 100644 docs/tutorial/t-set-up.md diff --git a/.github/workflows/automatic-doc-checks.yml b/.github/workflows/automatic-doc-checks.yml new file mode 100644 index 0000000000..479ebcbdc8 --- /dev/null +++ b/.github/workflows/automatic-doc-checks.yml @@ -0,0 +1,24 @@ +# +name: Automatic doc checks + +on: + push: + branches: [ main ] + pull_request: + paths: + - 'docs/**' # Only run on changes to the docs directory + + workflow_dispatch: + # Manual trigger + + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + documentation-checks: + uses: canonical/documentation-workflows/.github/workflows/documentation-checks.yaml@main + with: + working-directory: "docs" + fetch-depth: 0 diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index cdf5a0e2e6..cdaae9244d 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -14,7 +14,7 @@ on: - 'LICENSE' - '**.md' - .github/renovate.json5 - - '.github/workflows/sync_docs.yaml' + - 'docs/**' schedule: - cron: '53 0 * * *' # Daily at 00:53 UTC # Triggered on push to branch "main" by .github/workflows/release.yaml diff --git a/.github/workflows/lib-check.yaml b/.github/workflows/lib-check.yaml index bd6d351581..52b318a9f6 100644 --- a/.github/workflows/lib-check.yaml +++ b/.github/workflows/lib-check.yaml @@ -14,6 +14,7 @@ on: - 'LICENSE' - '**.md' - 'renovate.json' + - 'docs/**' jobs: lib-check: diff --git a/.github/workflows/markdown-style-checks.yml b/.github/workflows/markdown-style-checks.yml new file mode 100644 index 0000000000..bc75792104 --- /dev/null +++ b/.github/workflows/markdown-style-checks.yml @@ -0,0 +1,24 @@ +name: Markdown style checks + +on: + push: + branches: + - main + paths: + - 'docs/**' # Only run on changes to the docs directory + pull_request: + branches: + - '*' + paths: + - 'docs/**' # Only run on changes to the docs directory + +jobs: + markdown-lint: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: DavidAnson/markdownlint-cli2-action@b4c9feab76d8025d1e83c653fa3990936df0e6c8 + with: + config: "docs/.sphinx/.markdownlint.json" diff --git a/.github/workflows/sync_docs.yaml b/.github/workflows/sync_docs.yaml deleted file mode 100644 index 4b6e361979..0000000000 --- a/.github/workflows/sync_docs.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright 2024 Canonical Ltd. -# See LICENSE file for licensing details. -name: Sync docs from Discourse - -on: - workflow_dispatch: - schedule: - - cron: '53 0 * * *' # Daily at 00:53 UTC - -jobs: - sync-docs: - name: Sync docs from Discourse - uses: canonical/data-platform-workflows/.github/workflows/sync_docs.yaml@v31.0.1 - with: - reviewers: a-velasco,izmalk - permissions: - contents: write # Needed to push branch & tag - pull-requests: write # Needed to create PR diff --git a/.gitignore b/.gitignore index 34006fe231..173836107c 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,7 @@ build/ __pycache__/ *.py[cod] coverage.xml -requirements.txt +/requirements.txt requirements-last-build.txt # PyCharm project folder. diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 0000000000..01d6b9f5b4 --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,39 @@ +# .readthedocs.yaml +# Read the Docs configuration file +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +# Required +version: 2 + +# Set the version of Python and other tools you might need +build: + os: ubuntu-22.04 + tools: + python: "3.11" + jobs: + post_checkout: + - git fetch --unshallow || true + # Cancel building pull requests when there aren't changed in the docs directory. + # If there are no changes (git diff exits with 0) we force the command to return with 183. + # This is a special exit code on Read the Docs that will cancel the build immediately. + # https://docs.readthedocs.io/en/stable/build-customization.html#cancel-build-based-on-a-condition + - | + if [ "$READTHEDOCS_VERSION_TYPE" = "external" ] && git diff --quiet origin/14/docs -- 'docs/' '.readthedocs.yaml'; + then + exit 183; + fi + +# Build documentation in the docs/ directory with Sphinx +sphinx: + builder: dirhtml + configuration: docs/conf.py + fail_on_warning: true + +# If using Sphinx, optionally build your docs in additional formats such as PDF +# formats: +# - pdf + +# Optionally declare the Python requirements required to build your docs +python: + install: + - requirements: docs/requirements.txt diff --git a/README.md b/README.md index cbfdaf3a37..56198bf724 100644 --- a/README.md +++ b/README.md @@ -4,19 +4,14 @@ [![Tests](https://github.com/canonical/postgresql-operator/actions/workflows/ci.yaml/badge.svg?branch=main)](https://github.com/canonical/postgresql-operator/actions/workflows/ci.yaml?query=branch%3Amain) [![codecov](https://codecov.io/gh/canonical/postgresql-operator/graph/badge.svg?token=4V2mu7aWmu)](https://codecov.io/gh/canonical/postgresql-operator) -## Description -This repository contains a [Juju Charm](https://charmhub.io/postgresql) for deploying [PostgreSQL](https://www.postgresql.org/about/) on virtual machines ([LXD](https://ubuntu.com/lxd)). -To deploy on Kubernetes, please use [Charmed PostgreSQL K8s Operator](https://charmhub.io/postgresql-k8s). +This repository contains a charmed operator for deploying [PostgreSQL](https://www.postgresql.org/about/) on virtual machines via the [Juju orchestration engine](https://juju.is/). -This operator provides a PostgreSQL database with replication enabled: one primary instance and one (or more) hot standby replicas. The Operator in this repository is a Python script which wraps PostgreSQL versions distributed by Ubuntu Jammy series and adding [Patroni](https://github.com/zalando/patroni) on top of it, providing lifecycle management and handling events (install, configure, integrate, remove, etc). +To learn more about how to deploy and operate Charmed PostgreSQL, see the [official documentation](https://canonical-charmed-postgresql.readthedocs-hosted.com/). -## README contents +## Overview -* [Basic usage](#basic-usage): Deploy and scale Charmerd PostgreSQL -* [Integrations](#integrations-relations): Supported interfaces for integrations -* [Contributing](#contributing) -* [Licensing and trademark](#licensing-and-trademark) +This operator provides a PostgreSQL database with replication enabled: one primary instance and one (or more) hot standby replicas. The Operator in this repository is a Python script which wraps PostgreSQL versions distributed by Ubuntu Jammy series and adding [Patroni](https://github.com/zalando/patroni) on top of it, providing lifecycle management and handling events (install, configure, integrate, remove, etc). ## Basic usage diff --git a/docs/.custom_wordlist.txt b/docs/.custom_wordlist.txt new file mode 100644 index 0000000000..52d5f8c616 --- /dev/null +++ b/docs/.custom_wordlist.txt @@ -0,0 +1,40 @@ +# Leave a blank line at the end of this file to support concatenation +backend +backends +Charmcraft +cjk +cryptographically +dvipng +fonts +freefont +github +GPG +gyre +https +Intersphinx +lang +LaTeX +latexmk +Multipass +otf +plantuml +PNG +Pygments +QEMU +Rockcraft +rst +SVG +tex +texlive +TOC +toctree +txt +uncommenting +utils +VMs +WCAG +whitespace +whitespaces +wordlist +xetex +xindy diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 0000000000..aad78f1f7c --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,26 @@ +# Environment +*env*/ +.sphinx/venv/ + +# Sphinx +.sphinx/warnings.txt +.sphinx/.wordlist.dic +.sphinx/.doctrees/ +.sphinx/update/ +.sphinx/node_modules/ + +# Vale +.sphinx/styles/* +.sphinx/vale.ini + +# Build outputs +_build + +# Node.js +package*.json + +# Unrelated cache and config files +.DS_Store +__pycache__ +.idea/ +.vscode/ diff --git a/docs/.sphinx/.markdownlint.json b/docs/.sphinx/.markdownlint.json new file mode 100644 index 0000000000..536f9ea929 --- /dev/null +++ b/docs/.sphinx/.markdownlint.json @@ -0,0 +1,21 @@ +{ + "default": false, + "MD003": { + "style": "atx" + }, + "MD014": true, + "MD018": true, + "MD022": true, + "MD023": true, + "MD026": { + "punctuation": ".,;。,;" + }, + "MD031": { + "list_items": false + }, + "MD032": true, + "MD035": true, + "MD042": true, + "MD045": true, + "MD052": true +} \ No newline at end of file diff --git a/docs/.sphinx/.pre-commit-config.yaml b/docs/.sphinx/.pre-commit-config.yaml new file mode 100644 index 0000000000..07e0b48cbd --- /dev/null +++ b/docs/.sphinx/.pre-commit-config.yaml @@ -0,0 +1,23 @@ +repos: + - repo: local + hooks: + - id: make-spelling + name: Run make spelling + entry: make -C docs spelling + language: system + pass_filenames: false + files: ^docs/.*\.(rst|md|txt)$ + + - id: make-linkcheck + name: Run make linkcheck + entry: make -C docs linkcheck + language: system + pass_filenames: false + files: ^docs/.*\.(rst|md|txt)$ + + - id: make-woke + name: Run make woke + entry: make -C docs woke + language: system + pass_filenames: false + files: ^docs/.*\.(rst|md|txt)$ diff --git a/docs/.sphinx/.wordlist.txt b/docs/.sphinx/.wordlist.txt new file mode 100644 index 0000000000..fd1f10102e --- /dev/null +++ b/docs/.sphinx/.wordlist.txt @@ -0,0 +1,331 @@ +ACME +ACME's +addons +AGPLv +API +APIs +balancer +Charmhub +CLI +DCO +Diátaxis +Dqlite +dropdown +EBS +EKS +enablement +favicon +Furo +Git +GitHub +Grafana +IAM +installable +JSON +Juju +Kubeflow +Kubernetes +Launchpad +linter +LTS +LXD +Makefile +Makefiles +Matrix +Mattermost +MicroCeph +MicroCloud +MicroOVN +MyST +namespace +namespaces +NodePort +Numbat +observability +OEM +OLM +Permalink +pre +Quickstart +ReadMe +reST +reStructuredText +roadmap +RTD +subdirectories +subfolders +subtree +TODO +Ubuntu +UI +UUID +VM +webhook +YAML + +AAM +AAR +AArch +ABI +ADB +ADSys +AKS +AMC +AMS +ANAIS +APK +APM +ARMv +ARR +ASIC +AZ +BAU +BOM +BTS +BZR +CAC +CBR +CDK +CDN +CISC +CLA +CMP +CNI +COS +COTS +CPC +CPQ +CPT +CR +CRD +CRI +CSB +CSI +CTR +CVE +DBR +DEP +DHCP +DKMS +DMB +DNS +DPU +DSA +DSE +EE +EFI +EoL +EoS +EPMO +ESM +FCE +FFE +FIPS +FOSS +FPGA +FTBFS +FTI +FUSE +GKE +GPGPU +GPL +GSI +GTM +HA +HAP +HPC +HWE +IC +IHV +IOV +IPMI +IPU +IRCC +iSCSI +ISM +ISR +ISV +ITP +JAAS +KSPP +LTV +MAAS +MDF +MDL +MEC +MLflow +MOTU +MPA +MQL +MRE +MSRP +NATS +NFS +NIC +NIH +NIST +NOC +NOS +NPOASR +NPV +NRE +NUMA +NVIU +NVMe +OBSD +OCI +OCL +OCTO +ODM +OSD +OSS +OVA +OVAL +OVN +OVS +P4 +PCB +PCF +PCKN +PCRE +PKCS +PKS +PMO +POSIX +PPA +PS5 +PXE +RACI +RADOS +RAG +RBAC +RDMA +RTOS +SDK +SDR +SDS +SEG +SFDC +SIP +SKU +SLA +SOW +SQL +SR +SRU +TAM +TCS +TFTP +TLS +TPM +TUI +UCA +UCT +UDS +UIFe +URI +UX +VCS +VNFD +WSL +ZFS + +Anbox +Ansible +Appium +Backports +Ceph +Changelog +Charmcraft +CoC +CoF +Containerd +Coturn +Cryptographic +Devel +Endian +Endianness +Fluentd +GraphQL +HAProxy +HAcluster +Imagecraft +Infiniband +Influxdb +Istio +Kata +Keepalived +KernOS +KernelFactory +Keyring +Keyserver +Kibana +Knative +LXC +Laravel +Libvirt +Linkerd +LinuxONE +Livepatch +Mesos +Metallb +MicroK +MicroStack +Mojo +Multipass +Nagios +NetApp +Netplan +Nginx +OpenSSL +OpenSearch +OpenStack +Openshift +PgBouncer +QEMU +RabbitMQ +Rasterization +Rebase +RegEx +RoM +RoP +RoQA +RoSRM +RoST +Rockcraft +SQLair +Scrcpy +Snapcraft +Snapd +Splunk +Subnet +Superdistro +Superset +Telegraf +Terraform +Testflinger +Thruk +Tigera +TrilioVault +TripleO +Vue +WebRTC +WoU +amd +armhf +autopkgtest +cURL +containeragent +dqlite +dsc +init +jQuery +juju +jujuc +jujud +ppc +riscv +snapcrafting +subcluster +swrast +zSystems diff --git a/docs/.sphinx/get_vale_conf.py b/docs/.sphinx/get_vale_conf.py new file mode 100644 index 0000000000..46f57d8943 --- /dev/null +++ b/docs/.sphinx/get_vale_conf.py @@ -0,0 +1,151 @@ +#! /usr/bin/env python + +import os +import shutil +import subprocess +import tempfile +import sys +import logging +import argparse + +# Configure logging +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(levelname)s - %(message)s', + datefmt='%Y-%m-%d %H:%M:%S' +) + +SPHINX_DIR = os.path.join(os.getcwd(), ".sphinx") + +GITHUB_REPO = "canonical/praecepta" +GITHUB_CLONE_URL = f"https://github.com/{GITHUB_REPO}.git" + +# Source paths to copy from repo +VALE_FILE_LIST = [ + "styles/Canonical", + "styles/config/vocabularies/Canonical", + "styles/config/dictionaries", + "vale.ini" +] + +def clone_repo_and_copy_paths(file_source_dest, overwrite=False): + """ + Clone the repository to a temporary directory and copy required files + + Args: + file_source_dest: dictionary of file paths to copy from the repository, + and their destination paths + overwrite: boolean flag to overwrite existing files in the destination + + Returns: + bool: True if all files were copied successfully, False otherwise + """ + + if not file_source_dest: + logging.error("No files to copy") + return False + + # Create temporary directory on disk for cloning + temp_dir = tempfile.mkdtemp() + logging.info("Cloning repository <%s> to temporary directory: %s", GITHUB_REPO, temp_dir) + clone_cmd = ["git", "clone", "--depth", "1", GITHUB_CLONE_URL, temp_dir] + + try: + result = subprocess.run( + clone_cmd, + capture_output=True, + text=True, + check=True + ) + logging.debug("Git clone output: %s", result.stdout) + except subprocess.CalledProcessError as e: + logging.error("Git clone failed: %s", e.stderr) + return False + + # Copy files from the cloned repository to the destination paths + is_copy_success = True + for source, dest in file_source_dest.items(): + source_path = os.path.join(temp_dir, source) + + if not os.path.exists(source_path): + is_copy_success = False + logging.error("Source path not found: %s", source_path) + continue + + if not copy_files_to_path(source_path, dest, overwrite): + is_copy_success = False + logging.error("Failed to copy %s to %s", source_path, dest) + + # Clean up temporary directory + logging.info("Cleaning up temporary directory: %s", temp_dir) + shutil.rmtree(temp_dir) + + return is_copy_success + +def copy_files_to_path(source_path, dest_path, overwrite=False): + """ + Copy a file or directory from source to destination + + Args: + source_path: Path to the source file or directory + dest_path: Path to the destination + overwrite: Boolean flag to overwrite existing files in the destination + + Returns: + bool: True if copy was successful, False otherwise + """ + # Skip if source file doesn't exist + if not os.path.exists(source_path): + logging.warning("Source path not found: %s", source_path) + return False + + logging.info("Copying %s to %s", source_path, dest_path) + # Handle existing files + if os.path.exists(dest_path): + if overwrite: + logging.info(" Destination exists, overwriting: %s", dest_path) + if os.path.isdir(dest_path): + shutil.rmtree(dest_path) + else: + os.remove(dest_path) + else: + logging.info(" Destination exists, skip copying (use overwrite=True to replace): %s", + dest_path) + return True # Skip copying + + # Copy the source to destination + try: + if os.path.isdir(source_path): + # entire directory + shutil.copytree(source_path, dest_path) + else: + # individual files + shutil.copy2(source_path, dest_path) + return True + except (shutil.Error, OSError) as e: + logging.error("Copy failed: %s", e) + return False + +def parse_arguments(): + parser = argparse.ArgumentParser(description="Download Vale configuration files") + parser.add_argument("--no-overwrite", action="store_true", help="Don't overwrite existing files") + return parser.parse_args() + +def main(): + # Define local directory paths + vale_files_dict = {file: os.path.join(SPHINX_DIR, file) for file in VALE_FILE_LIST} + + # Parse command line arguments, default to overwrite_enabled = True + overwrite_enabled = not parse_arguments().no_overwrite + + # Download into /tmp through git clone + if not clone_repo_and_copy_paths(vale_files_dict, overwrite=overwrite_enabled): + logging.error("Failed to download files from repository") + return 1 + + logging.info("Download complete") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) # Keep return code diff --git a/docs/.sphinx/metrics/build_metrics.sh b/docs/.sphinx/metrics/build_metrics.sh new file mode 100755 index 0000000000..bd1ff1cb4c --- /dev/null +++ b/docs/.sphinx/metrics/build_metrics.sh @@ -0,0 +1,15 @@ +#!/bin/bash +# shellcheck disable=all + +links=0 +images=0 + +# count number of links +links=$(find . -type d -path './.sphinx' -prune -o -name '*.html' -exec cat {} + | grep -o " str: + """Get SHA of local files""" + logging.debug(f"Getting hash of {os.path.basename(file)}") + return subprocess.check_output(["git", "hash-object", file]).decode("ascii").strip() + + +# Examines local files +def get_local_files_and_paths(): + """Identify '.sphinx' local files and paths""" + logging.debug("Checking local files and paths") + try: + files = [] + paths = [] + patterns = [".*", "**.*", "metrics/**.*"] + files, paths = [], [] + + for pattern in patterns: + for file in glob.iglob(os.path.join(SPHINX_DIR, pattern), recursive=True): + files.append(os.path.basename(file)) + paths.append(file) + return files, paths + except Exception as e: + logging.debug(e) + raise RuntimeError("get_local_files_and_paths()") from e + + +# General API query with timeout and RequestException +def query_api(url): + """Query an API with a globally set timeout""" + logging.debug(f"Querying {url}") + try: + r = requests.get(url, timeout=TIMEOUT) + return r + except RequestException as e: + raise RuntimeError(f"Failed query_api(): {url}") from e + + +# General file download function +def download_file(url, output_path): + """Download a file to a specified path""" + logging.debug(f"Downloading {os.path.basename(output_path)}") + try: + os.makedirs(os.path.dirname(output_path), exist_ok=True) + with open(output_path, "wb") as file: + file.write(query_api(url).content) + except Exception as e: + logging.debug(e) + raise RuntimeError(f"Failed download_file(): {url}") from e + + +if __name__ == "__main__": + sys.exit(main()) # Keep return code diff --git a/docs/.sphinx/version b/docs/.sphinx/version new file mode 100644 index 0000000000..6d7de6e6ab --- /dev/null +++ b/docs/.sphinx/version @@ -0,0 +1 @@ +1.0.2 diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000000..18fb6a775c --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,196 @@ +# Minimal makefile for Sphinx documentation +# +# Add your customisation to `Makefile` instead. + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXDIR = .sphinx +SPHINXOPTS ?= -c . -d $(SPHINXDIR)/.doctrees -j auto +SPHINXBUILD ?= $(VENVDIR)/bin/sphinx-build +SOURCEDIR = . +BUILDDIR = _build +VENVDIR = $(SPHINXDIR)/venv +PA11Y = $(SPHINXDIR)/node_modules/pa11y/bin/pa11y.js --config $(SPHINXDIR)/pa11y.json +VENV = $(VENVDIR)/bin/activate +TARGET = * +ALLFILES = *.md **/*.md +METRICSDIR = $(SOURCEDIR)/.sphinx/metrics +REQPDFPACKS = latexmk fonts-freefont-otf texlive-latex-recommended texlive-latex-extra texlive-fonts-recommended texlive-font-utils texlive-lang-cjk texlive-xetex plantuml xindy tex-gyre dvipng +CONFIRM_SUDO ?= N +VALE_CONFIG = $(SPHINXDIR)/vale.ini +SPHINX_HOST ?= 127.0.0.1 +SPHINX_PORT ?= 8001 + +# Put it first so that "make" without argument is like "make help". +help: + @echo + @echo "-------------------------------------------------------------" + @echo "* watch, build and serve the documentation: make run" + @echo "* only build: make html" + @echo "* only serve: make serve" + @echo "* clean built doc files: make clean-doc" + @echo "* clean full environment: make clean" + @echo "* check links: make linkcheck" + @echo "* check spelling: make spelling" + @echo "* check spelling (without building again): make spellcheck" + @echo "* check inclusive language: make woke" + @echo "* check accessibility: make pa11y" + @echo "* check style guide compliance: make vale" + @echo "* check style guide compliance on target: make vale TARGET=*" + @echo "* check metrics for documentation: make allmetrics" + @echo "* other possible targets: make " + @echo "-------------------------------------------------------------" + @echo + +.PHONY: full-help spellcheck-install pa11y-install install run html \ + epub serve clean clean-doc spelling spellcheck linkcheck woke \ + allmetrics pa11y pdf-prep-force pdf-prep pdf vale-install vale \ + update + +full-help: $(VENVDIR) + @. $(VENV); $(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + @echo "\n\033[1;31mNOTE: This help texts shows unsupported targets!\033[0m" + @echo "Run 'make help' to see supported targets." + +# If requirements are updated, venv should be rebuilt and timestamped. +$(VENVDIR): + python3 -c "import venv" || \ + (echo "You must install python3-venv before you can build the documentation."; exit 1) + @echo "... setting up virtualenv" + python3 -m venv $(VENVDIR) + . $(VENV); pip install $(PIPOPTS) --require-virtualenv \ + --upgrade -r requirements.txt \ + --log $(VENVDIR)/pip_install.log + @test ! -f $(VENVDIR)/pip_list.txt || \ + mv $(VENVDIR)/pip_list.txt $(VENVDIR)/pip_list.txt.bak + @. $(VENV); pip list --local --format=freeze > $(VENVDIR)/pip_list.txt + @touch $(VENVDIR) + +spellcheck-install: + @type aspell >/dev/null 2>&1 || \ + { \ + echo "Installing system-wide \"aspell\" packages..."; \ + confirm_sudo=$(CONFIRM_SUDO); \ + if [ "$$confirm_sudo" != "y" ] && [ "$$confirm_sudo" != "Y" ]; then \ + read -p "This requires sudo privileges. Proceed? [y/N]: " confirm_sudo; \ + fi; \ + if [ "$$confirm_sudo" = "y" ] || [ "$$confirm_sudo" = "Y" ]; then \ + sudo apt-get install aspell aspell-en; \ + else \ + echo "Installation cancelled."; \ + fi \ + } + +pa11y-install: + @type $(PA11Y) >/dev/null 2>&1 || { \ + echo "Installing \"pa11y\" from npm..."; echo; \ + mkdir -p $(SPHINXDIR)/node_modules/ ; \ + npm install --prefix $(SPHINXDIR) pa11y; \ + } + +install: $(VENVDIR) + +run: install + . $(VENV); $(VENVDIR)/bin/sphinx-autobuild -b dirhtml --host $(SPHINX_HOST) --port $(SPHINX_PORT) "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) + +# Doesn't depend on $(BUILDDIR) to rebuild properly at every run. +html: install + . $(VENV); $(SPHINXBUILD) -W --keep-going -b dirhtml "$(SOURCEDIR)" "$(BUILDDIR)" -w $(SPHINXDIR)/warnings.txt $(SPHINXOPTS) + +epub: install + . $(VENV); $(SPHINXBUILD) -b epub "$(SOURCEDIR)" "$(BUILDDIR)" -w $(SPHINXDIR)/warnings.txt $(SPHINXOPTS) + +serve: html + cd "$(BUILDDIR)"; python3 -m http.server --bind 127.0.0.1 8000 + +clean: clean-doc + @test ! -e "$(VENVDIR)" -o -d "$(VENVDIR)" -a "$(abspath $(VENVDIR))" != "$(VENVDIR)" + rm -rf $(VENVDIR) + rm -rf $(SPHINXDIR)/node_modules/ + rm -rf $(SPHINXDIR)/styles + rm -rf $(VALE_CONFIG) + +clean-doc: + git clean -fx "$(BUILDDIR)" + rm -rf $(SPHINXDIR)/.doctrees + +spellcheck: spellcheck-install + . $(VENV) ; python3 -m pyspelling -c $(SPHINXDIR)/spellingcheck.yaml -j $(shell nproc) + +spelling: html spellcheck + +linkcheck: install + . $(VENV) ; $(SPHINXBUILD) -b linkcheck "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) || { grep --color -F "[broken]" "$(BUILDDIR)/output.txt"; exit 1; } + exit 0 + +pa11y: pa11y-install html + find $(BUILDDIR) -name *.html -print0 | xargs -n 1 -0 $(PA11Y) + +vale-install: install + @. $(VENV); test -d $(SPHINXDIR)/venv/lib/python*/site-packages/vale || pip install rst2html vale + @. $(VENV); test -f $(VALE_CONFIG) || python3 $(SPHINXDIR)/get_vale_conf.py + @echo '.Name=="Canonical.400-Enforce-inclusive-terms"' > $(SPHINXDIR)/styles/woke.filter + @echo '.Level=="error" and .Name!="Canonical.500-Repeated-words" and .Name!="Canonical.000-US-spellcheck"' > $(SPHINXDIR)/styles/error.filter + @echo '.Name=="Canonical.000-US-spellcheck"' > $(SPHINXDIR)/styles/spelling.filter + @. $(VENV); find $(SPHINXDIR)/venv/lib/python*/site-packages/vale/vale_bin -size 195c -exec vale --version \; + +woke: vale-install + @cat $(SPHINXDIR)/styles/config/vocabularies/Canonical/accept.txt > $(SPHINXDIR)/styles/config/vocabularies/Canonical/accept_backup.txt + @cat $(SPHINXDIR)/.wordlist.txt $(SOURCEDIR)/.custom_wordlist.txt >> $(SPHINXDIR)/styles/config/vocabularies/Canonical/accept.txt + @echo "Running Vale acceptable term check against $(TARGET). To change target set TARGET= with make command" + @. $(VENV); vale --config="$(VALE_CONFIG)" --filter='$(SPHINXDIR)/styles/woke.filter' --glob='*.{md,rst}' $(TARGET) + @cat $(SPHINXDIR)/styles/config/vocabularies/Canonical/accept_backup.txt > $(SPHINXDIR)/styles/config/vocabularies/Canonical/accept.txt && rm $(SPHINXDIR)/styles/config/vocabularies/Canonical/accept_backup.txt + +vale: vale-install + @cat $(SPHINXDIR)/styles/config/vocabularies/Canonical/accept.txt > $(SPHINXDIR)/styles/config/vocabularies/Canonical/accept_backup.txt + @cat $(SPHINXDIR)/.wordlist.txt $(SOURCEDIR)/.custom_wordlist.txt >> $(SPHINXDIR)/styles/config/vocabularies/Canonical/accept.txt + @echo "Running Vale against $(TARGET). To change target set TARGET= with make command" + @. $(VENV); vale --config="$(VALE_CONFIG)" --filter='$(SPHINXDIR)/styles/error.filter' --glob='*.{md,rst}' $(TARGET) + @cat $(SPHINXDIR)/styles/config/vocabularies/Canonical/accept_backup.txt > $(SPHINXDIR)/styles/config/vocabularies/Canonical/accept.txt && rm $(SPHINXDIR)/styles/config/vocabularies/Canonical/accept_backup.txt + +vale-spelling: vale-install + @cat $(SPHINXDIR)/styles/config/vocabularies/Canonical/accept.txt > $(SPHINXDIR)/styles/config/vocabularies/Canonical/accept_backup.txt + @cat $(SPHINXDIR)/.wordlist.txt $(SOURCEDIR)/.custom_wordlist.txt >> $(SPHINXDIR)/styles/config/vocabularies/Canonical/accept.txt + @echo "Running Vale against $(TARGET). To change target set TARGET= with make command" + @. $(VENV); vale --config="$(VALE_CONFIG)" --filter='$(SPHINXDIR)/styles/spelling.filter' --glob='*.{md,rst}' $(TARGET) + @cat $(SPHINXDIR)/styles/config/vocabularies/Canonical/accept_backup.txt > $(SPHINXDIR)/styles/config/vocabularies/Canonical/accept.txt && rm $(SPHINXDIR)/styles/config/vocabularies/Canonical/accept_backup.txt + +pdf-prep: install + @for packageName in $(REQPDFPACKS); do (dpkg-query -W -f='$${Status}' $$packageName 2>/dev/null | \ + grep -c "ok installed" >/dev/null && echo "Package $$packageName is installed") && continue || \ + (echo; echo "PDF generation requires the installation of the following packages: $(REQPDFPACKS)" && \ + echo "" && echo "Run 'sudo make pdf-prep-force' to install these packages" && echo "" && echo \ + "Please be aware these packages will be installed to your system") && exit 1 ; done + +pdf-prep-force: + apt-get update + apt-get upgrade -y + apt-get install --no-install-recommends -y $(REQPDFPACKS) \ + +pdf: pdf-prep + @. $(VENV); sphinx-build -M latexpdf "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) + @rm ./$(BUILDDIR)/latex/front-page-light.pdf || true + @rm ./$(BUILDDIR)/latex/normal-page-footer.pdf || true + @find ./$(BUILDDIR)/latex -name "*.pdf" -exec mv -t ./$(BUILDDIR) {} + + @rm -r $(BUILDDIR)/latex + @echo + @echo "Output can be found in ./$(BUILDDIR)" + @echo + +allmetrics: html + @echo "Recording documentation metrics..." + @echo "Checking for existence of vale..." + . $(VENV) + @. $(VENV); test -d $(SPHINXDIR)/venv/lib/python*/site-packages/vale || pip install vale + @. $(VENV); test -f $(VALE_CONFIG) || python3 $(SPHINXDIR)/get_vale_conf.py + @. $(VENV); find $(SPHINXDIR)/venv/lib/python*/site-packages/vale/vale_bin -size 195c -exec vale --config "$(VALE_CONFIG)" $(TARGET) > /dev/null \; + @eval '$(METRICSDIR)/source_metrics.sh $(PWD)' + @eval '$(METRICSDIR)/build_metrics.sh $(PWD) $(METRICSDIR)' + +update: install + @. $(VENV); .sphinx/update_sp.py + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: + . $(VENV); $(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000000..fb6c96f500 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,336 @@ +import datetime +import ast +import os +import yaml + +# Configuration for the Sphinx documentation builder. +# All configuration specific to your project should be done in this file. +# +# If you're new to Sphinx and don't want any advanced or custom features, +# just go through the items marked 'TODO'. +# +# A complete list of built-in Sphinx configuration values: +# https://www.sphinx-doc.org/en/master/usage/configuration.html +# +# Our starter pack uses the custom Canonical Sphinx extension +# to keep all documentation based on it consistent and on brand: +# https://github.com/canonical/canonical-sphinx + + +####################### +# Project information # +####################### + +# Project name + +project = "Charmed PostgreSQL" +author = "Canonical Ltd." + + +# Sidebar documentation title; best kept reasonably short +# +# TODO: To include a version number, add it here (hardcoded or automated). +# +# TODO: To disable the title, set to an empty string. + +html_title = project + " 14 documentation" + + +# Copyright string; shown at the bottom of the page +# +# Now, the starter pack uses CC-BY-SA as the license +# and the current year as the copyright year. +# +# TODO: If your docs need another license, specify it instead of 'CC-BY-SA'. +# +# TODO: If your documentation is a part of the code repository of your project, +# it inherits the code license instead; specify it instead of 'CC-BY-SA'. +# +# NOTE: For static works, it is common to provide the first publication year. +# Another option is to provide both the first year of publication +# and the current year, especially for docs that frequently change, +# e.g. 2022–2023 (note the en-dash). +# +# A way to check a repo's creation date is to get a classic GitHub token +# with 'repo' permissions; see https://github.com/settings/tokens +# Next, use 'curl' and 'jq' to extract the date from the API's output: +# +# curl -H 'Authorization: token ' \ +# -H 'Accept: application/vnd.github.v3.raw' \ +# https://api.github.com/repos/canonical/ | jq '.created_at' + +copyright = "%s CC-BY-SA, %s" % (datetime.date.today().year, author) + + +# Documentation website URL +# +# TODO: Update with the official URL of your docs or leave empty if unsure. +# +# NOTE: The Open Graph Protocol (OGP) enhances page display in a social graph +# and is used by social media platforms; see https://ogp.me/ + +ogp_site_url = "https://canonical-starter-pack.readthedocs-hosted.com/" + + +# Preview name of the documentation website +# +# TODO: To use a different name for the project in previews, update as needed. + +ogp_site_name = project + + +# Preview image URL +# +# TODO: To customise the preview image, update as needed. + +ogp_image = "https://assets.ubuntu.com/v1/253da317-image-document-ubuntudocs.svg" + + +# Product favicon; shown in bookmarks, browser tabs, etc. + +# TODO: To customise the favicon, uncomment and update as needed. + +# html_favicon = '.sphinx/_static/favicon.png' + + +# Dictionary of values to pass into the Sphinx context for all pages: +# https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-html_context + +html_context = { + # Product page URL; can be different from product docs URL + # + # TODO: Change to your product website URL, + # dropping the 'https://' prefix, e.g. 'ubuntu.com/lxd'. + # + # TODO: If there's no such website, + # remove the {{ product_page }} link from the page header template + # (usually .sphinx/_templates/header.html; also, see README.rst). + "product_page": "canonical.com/data/postgresql", + + # Product tag image; the orange part of your logo, shown in the page header + # + # TODO: To add a tag image, uncomment and update as needed. + # 'product_tag': '_static/tag.png', + + # Your Discourse instance URL + # + # TODO: Change to your Discourse instance URL or leave empty. + # + # NOTE: If set, adding ':discourse: 123' to an .rst file + # will add a link to Discourse topic 123 at the bottom of the page. + "discourse": "https://discourse.charmhub.io", + + # Your Mattermost channel URL + # + # TODO: Change to your Mattermost channel URL or leave empty. + "mattermost": "", + + # Your Matrix channel URL + # + "matrix": "https://matrix.to/#/#charmhub-data-platform:ubuntu.com", + + # Your documentation GitHub repository URL + # + # TODO: Change to your documentation GitHub repository URL or leave empty. + # + # NOTE: If set, links for viewing the documentation source files + # and creating GitHub issues are added at the bottom of each page. + "github_url": "https://github.com/canonical/postgresql-operator", + + # Docs branch in the repo; used in links for viewing the source files + # TODO: Update when default branch changes to 14 or 16 + 'repo_default_branch': 'main', + + # Docs location in the repo; used in links for viewing the source files + "repo_folder": "/docs/", + + # Enable or disable the Previous / Next buttons at the bottom of pages + # Valid options: none, prev, next, both + "sequential_nav": "none", + + # Enable listing contributors on individual pages, set to True + "display_contributors": True, + + # Required for feedback button + 'github_issues': 'enabled', +} + +# TODO: To enable the edit button on pages, uncomment and change the link to a +# public repository on GitHub or Launchpad. Any of the following link domains +# are accepted: +# - https://github.com/example-org/example" +# - https://launchpad.net/example +# - https://git.launchpad.net/example +# +html_theme_options = { +'source_edit_link': 'https://github.com/canonical/postgresql-operator/', +} + +# Project slug; see https://meta.discourse.org/t/what-is-category-slug/87897 +# +# TODO: If your documentation is hosted on https://docs.ubuntu.com/, +# uncomment and update as needed. + +# slug = '' + + +# Template and asset locations + +#html_static_path = ["_static"] +#templates_path = ["_templates"] + + +############# +# Redirects # +############# + +# To set up redirects: https://documatt.gitlab.io/sphinx-reredirects/usage.html +# For example: 'explanation/old-name.html': '../how-to/prettify.html', + +# To set up redirects in the Read the Docs project dashboard: +# https://docs.readthedocs.io/en/stable/guides/redirects.html + +# NOTE: If undefined, set to None, or empty, +# the sphinx_reredirects extension will be disabled. + +redirects = {} + + +########################### +# Link checker exceptions # +########################### + +# A regex list of URLs that are ignored by 'make linkcheck' +# +# TODO: Remove or adjust the ACME entry after you update the contributing guide + +linkcheck_ignore = [ + "http://127.0.0.1:8000", + "https://github.com/canonical/ACME/*", + "https://matrix.to/*" + ] + +# A regex list of URLs where anchors are ignored by 'make linkcheck' + +linkcheck_anchors_ignore_for_url = [ + r"https://github\.com/.*", + r"https://canonical-juju.readthedocs-hosted.com/en/latest/*" + ] + +# give linkcheck multiple tries on failure +# linkcheck_timeout = 30 +linkcheck_retries = 3 + +######################## +# Configuration extras # +######################## + +# Custom MyST syntax extensions; see +# https://myst-parser.readthedocs.io/en/latest/syntax/optional.html +# +# NOTE: By default, the following MyST extensions are enabled: +# substitution, deflist, linkify + +myst_enable_extensions = set() + +myst_heading_anchors = 3 + +# Custom Sphinx extensions; see +# https://www.sphinx-doc.org/en/master/usage/extensions/index.html + +# NOTE: The canonical_sphinx extension is required for the starter pack. +# It automatically enables the following extensions: +# - custom-rst-roles +# - myst_parser +# - notfound.extension +# - related-links +# - sphinx_copybutton +# - sphinx_design +# - sphinx_reredirects +# - sphinx_tabs.tabs +# - sphinxcontrib.jquery +# - sphinxext.opengraph +# - terminal-output +# - youtube-links + +extensions = [ + "canonical_sphinx", + "sphinxcontrib.cairosvgconverter", + "sphinx_last_updated_by_git", + "sphinx.ext.intersphinx", +] + +# Excludes files or directories from processing + +exclude_patterns = [ + "doc-cheat-sheet*", +] + +# Adds custom CSS files, located under 'html_static_path' + +# html_css_files = [] + + +# Adds custom JavaScript files, located under 'html_static_path' + +# html_js_files = [] + + +# Specifies a reST snippet to be appended to each .rst file + +rst_epilog = """ +.. include:: /reuse/links.txt +.. include:: /reuse/substitutions.txt +""" + +# Feedback button at the top; enabled by default +# +# TODO: To disable the button, uncomment this. + +# disable_feedback_button = True + + +# Your manpage URL +# +# TODO: To enable manpage links, uncomment and replace {codename} with required +# release, preferably an LTS release (e.g. noble). Do *not* substitute +# {section} or {page}; these will be replaced by sphinx at build time +# +# NOTE: If set, adding ':manpage:' to an .rst file +# adds a link to the corresponding man section at the bottom of the page. + +# manpages_url = 'https://manpages.ubuntu.com/manpages/{codename}/en/' + \ +# 'man{section}/{page}.{section}.html' + + +# Specifies a reST snippet to be prepended to each .rst file +# This defines a :center: role that centers table cell content. +# This defines a :h2: role that styles content for use with PDF generation. + +rst_prolog = """ +.. role:: center + :class: align-center +.. role:: h2 + :class: hclass2 +.. role:: woke-ignore + :class: woke-ignore +.. role:: vale-ignore + :class: vale-ignore +""" + +# Workaround for https://github.com/canonical/canonical-sphinx/issues/34 + +if "discourse_prefix" not in html_context and "discourse" in html_context: + html_context["discourse_prefix"] = html_context["discourse"] + "/t/" + +# Workaround for substitutions.yaml + +if os.path.exists('./reuse/substitutions.yaml'): + with open('./reuse/substitutions.yaml', 'r') as fd: + myst_substitutions = yaml.safe_load(fd.read()) + +# Add configuration for intersphinx mapping + +intersphinx_mapping = { + 'starter-pack': ('https://canonical-example-product-documentation.readthedocs-hosted.com/en/latest', None) +} diff --git a/docs/explanation.md b/docs/explanation.md deleted file mode 100644 index 0883e615df..0000000000 --- a/docs/explanation.md +++ /dev/null @@ -1,33 +0,0 @@ -# Explanation - -This section contains pages with more detailed explanations that provide additional context about key concepts behind the PostgreSQL charm. - -## Core concepts and design -* [Architecture] -* [Interfaces and endpoints] -* [Juju] -* [Legacy charm] - -## Operational concepts -* [Units] -* [Users] -* [Logs] -* [Connection pooling] - -## Security and hardening -* [Security hardening guide][Security] - * [Cryptography] - - - - -[Architecture]: /t/11857 -[Interfaces and endpoints]: /t/10251 -[Units]: /t/17525 -[Users]: /t/10798 -[Logs]: /t/12099 -[Juju]: /t/11985 -[Legacy charm]: /t/10690 -[Connection pooling]: /t/15777 -[Security]: /t/16852 -[Cryptography]: /t/16853 \ No newline at end of file diff --git a/docs/explanation/architecture-diagram.png b/docs/explanation/architecture-diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..eb4b586859b8992172c716486fe327635507f77c GIT binary patch literal 120226 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 z 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π2d0Xsenn3zFN02o3{0mNvz&r| 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

ofb(obA{_@TeC{+iAce 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 **Warning**: all SQL transactions have to be confirmed by all Sync Standby unit(s) before Primary unit commit transaction to the client. Therefor the high-performance and high-availability is a trade-of balance between "Sync Standby" and "Replica" units count in the cluster. +![PostgreSQL Units types|690x253, 100%](unit-types.png) -> **Note**: starting from revision 561 all Charmed PostgreSQL units are configured as Sync Standby members. It provides better guaranties for the data survival when two of three units gone simultaneously. Users can re-configure the necessary synchronous units count using Juju config option '[synchronous_node_count](https://charmhub.io/postgresql/configurations?channel=14/edge#synchronous_node_count)'. +All SQL transactions have to be confirmed by all Sync Standby unit(s) before Primary unit commit transaction to the client. Therefore, high-performance and high-availability is a trade-off between "sync standby" and "replica" unit count in the cluster. -![PostgreSQL Units types|690x253, 100%](upload://pY5kzxO9ELJGEqEe1F1RQjOG6SS.png) +Starting from revision 561, all Charmed PostgreSQL units are configured as Sync Standby members by default. It provides better guarantees for the data survival when two of three units gone simultaneously. Users can re-configure the necessary synchronous units count using Juju config option '[synchronous_node_count](https://charmhub.io/postgresql/configurations?channel=14/stable#synchronous_node_count)'. ## Primary -The simplest way to find the Primary unit is to run `juju status`. Please be aware that the information here can be outdated as it is being updated only on [Juju event 'update-status'](https://documentation.ubuntu.com/juju/3.6/reference/hook/#update-status): -```shell +The simplest way to find the Primary unit is to run `juju status`. Please be aware that the information here can be outdated as it is being updated only on [Juju event 'update-status'](https://documentation.ubuntu.com/juju/3.6/reference/hook/#update-status): + +```text ubuntu@juju360:~$ juju status postgresql Model Controller Cloud/Region Version SLA Timestamp postgresql lxd localhost/localhost 3.6.5 unsupported 13:04:15+02:00 @@ -35,18 +39,22 @@ Machine State Address Inst id Base AZ Message ``` The up-to-date Primary unit number can be received using Juju action `get-primary`: -```shell + +```text > juju run postgresql/leader get-primary ... primary: postgresql/0 ``` -Also it is possible to retrieve this information using [patronictl](/t/17406#p-37204-patronictl-3) and [Patroni REST API](/t/17406#p-37204-patroni-rest-api-8). +Also it is possible to retrieve this information using [patronictl](/reference/troubleshooting/cli-helpers) and [Patroni REST API](/reference/troubleshooting/cli-helpers). ## Standby / Replica -At the moment it is possible to retrieve this information using [patronictl](/t/17406#p-37204-patronictl-3) and [Patroni REST API](/t/17406#p-37204-patroni-rest-api-8) only (check the linked documentation for the access details). Example: -```shell +At the moment it is possible to retrieve this information using [patronictl](/reference/troubleshooting/cli-helpers) and [Patroni REST API](/reference/troubleshooting/cli-helpers) only (check the linked documentation for access details). + +Example: + +```text > ... patronictl ... list + Cluster: postgresql (7499430436963402504) ---+-----------+----+-----------+ | Member | Host | Role | State | TL | Lag in MB | @@ -56,15 +64,18 @@ At the moment it is possible to retrieve this information using [patronictl](/t/ | postgresql-2 | 10.189.210.188 | Replica | streaming | 1 | 0 | +--------------+----------------+--------------+-----------+----+-----------+ ``` -On the example above: + * `postgresql-0` is a PostgreSQL Primary unit (Patroni Leader) which accepts all writes * `postgresql-1` is a PostgreSQL/Patroni Sync Standby unit which can be promoted as new primary using manual switchover (safe). * `postgresql-2` is a PostgreSQL/Patroni Replica unit which can NOT be directly promoted as a new Primary using manual switchover. The automatic promotion Replica=>Sync Standby is necessary to guaranties the latest SQL transactions availability on this unit to allow further promotion as a new Primary. Otherwise the manual failover can be performed to Replica unit accepting the risks of loosing the last transactions(s) which lagged behind Primary. ## Replica lag distance -At the moment it is possible to retrieve this information using [patronictl](/t/17406#p-37204-patronictl-3) and [Patroni REST API](/t/17406#p-37204-patroni-rest-api-8) only (check the linked documentation for the access details). Example: -```shell +At the moment, it is only possible to retrieve this information using [patronictl](/reference/troubleshooting/cli-helpers) and [Patroni REST API](/reference/troubleshooting/cli-helpers). Check the linked documentation for access details. + +Example: + +```text > ... patronictl ... list + Cluster: postgresql (7499430436963402504) ---+-----------+----+-----------+ | Member | Host | Role | State | TL | Lag in MB | @@ -90,4 +101,4 @@ At the moment it is possible to retrieve this information using [patronictl](/t/ ... "lag": 42 <<<<<<<<<<<< Lag in MB } -``` \ No newline at end of file +``` diff --git a/docs/explanation/e-users.md b/docs/explanation/users.md similarity index 69% rename from docs/explanation/e-users.md rename to docs/explanation/users.md index f5e233da94..69e15a0c1b 100644 --- a/docs/explanation/e-users.md +++ b/docs/explanation/users.md @@ -1,26 +1,26 @@ # Users There are three types of users in PostgreSQL: -* Internal users (used by charm operator) + +* Internal users (used by the charmed operator) * Relation users (used by related applications) * Extra user roles (if default permissions are not enough) * Identity users (used when LDAP is enabled) - -## Internal users explanations: +## Internal users The operator uses the following internal DB users: -* `postgres` - the [initial/default](https://charmhub.io/postgresql/docs/t-manage-passwords) PostgreSQL user. Used for very initial bootstrap only. -* `operator` - the user that charm.py uses to manage database/cluster. +* `postgres` - the [initial/default](/how-to/manage-passwords) PostgreSQL user. Used for very initial bootstrap only. +* `operator` - the user that `charm.py` uses to manage database/cluster. * `replication` - the user performs replication between database PostgreSQL cluster members. * `rewind` - the internal user for synchronizing a PostgreSQL cluster with another copy of the same cluster. -* `monitoring` - the user for [COS integration](https://charmhub.io/postgresql/docs/h-enable-monitoring). -* `backups` - the user to [perform/list/restore backups](https://charmhub.io/postgresql/docs/h-create-and-list-backups). +* `monitoring` - the user for [COS integration](/how-to/monitoring-cos/enable-monitoring). +* `backups` - the user to [perform/list/restore backups](/how-to/back-up-and-restore/create-a-backup). The full list of internal users is available in charm [source code](https://github.com/canonical/postgresql-operator/blob/main/src/constants.py). The full dump of internal users (on the newly installed charm): -```shell +```text postgres=# \du List of roles Role name | Attributes | Member of @@ -32,10 +32,16 @@ postgres=# \du replication | Replication | {} rewind | | {} ``` -**Note**: it is forbidden to use/manage described above users! They are dedicated to the operators logic! Please use [data-integrator](https://charmhub.io/postgresql/docs/t-integrations) charm to generate/manage/remove an external credentials. -It is allowed to rotate passwords for *internal* users using action 'set-password': -```shell +```{caution} +It is forbidden to use/manage described above users, as they are dedicated to the operator's logic. + +Use the [data-integrator](https://charmhub.io/data-integrator) charm to generate, manage, and remove external credentials. +``` + +Passwords for *internal* users can be rotated using the action `set-password`: + +```text > juju show-action postgresql set-password Change the system user's password, which is used by charm. It is for internal charm users and SHOULD NOT be used by applications. @@ -47,9 +53,10 @@ username: type: string description: The username, the default value 'operator'. Possible values - operator, replication, rewind. ``` + For example, to generate a new random password for *internal* user: -```shell +```text > juju run-action --wait postgresql/leader set-password username=operator unit-postgresql-1: @@ -60,7 +67,7 @@ unit-postgresql-1: status: completed ``` To set a predefined password for the specific user, run: -```shell +```text > juju run-action --wait postgresql/leader set-password username=operator password=newpassword unit-postgresql-1: @@ -70,14 +77,14 @@ unit-postgresql-1: password: newpassword status: completed ``` -**Note**: the action `set-password` must be executed on juju leader unit (to update peer relation data with new value). - -## Relation users explanations: +The action `set-password` must be executed on juju leader unit (to update peer relation data with new value). + +## Relation users The operator created a dedicated user for every application related/integrated with database. Those users are removed on the juju relation/integration removal request. However, DB data stays in place and can be reused on re-created relations (using new user credentials): -```shell +```text postgres=# \du List of roles Role name | Attributes | Member of @@ -88,22 +95,27 @@ postgres=# \du ... ``` -**Note**: If password rotation is needed for users used in relations, it is needed to remove the relation and create it again: -```shell -> juju remove-relation postgresql myclientapp -> juju wait-for application postgresql -> juju relate postgresql myclientapp +If password rotation is required for users used in relations, the relation must be removed and created again: + +```text +juju remove-relation postgresql myclientapp +juju wait-for application postgresql +juju relate postgresql myclientapp ``` - ### Extra user roles When an application charm requests a new user through the relation/integration it can specify that the user should have the `admin` role in the `extra-user-roles` field. The `admin` role enables the new user to read and write to all databases (for the `postgres` system database it can only read data) and also to create and delete non-system databases. -**Note**: `extra-user-roles` is supported by modern interface `postgresql_client` only and missing for legacy `pgsql` interface. Read more about the supported charm interfaces [here](/t/10251). +```{note} +`extra-user-roles` is only supported by the modern interface `postgresql_client`. It is not supported for the legacy `pgsql` interface. R + +Read more about the supported charm interfaces in [](/explanation/interfaces-and-endpoints). +``` + +## Identity users - -## Identity users explanations: The operator considers Identity users all those that are automatically created when the LDAP integration is enabled, or in other words, the [GLAuth](https://charmhub.io/glauth-k8s) charm is related/integrated. -When synchronized from the LDAP server, these users do not have any permissions by default, so the LDAP group they belonged to must be mapped to a PostgreSQL pre-defined authorization role by using the `ldap_map` configuration option. \ No newline at end of file +When synchronized from the LDAP server, these users do not have any permissions by default, so the LDAP group they belonged to must be mapped to a PostgreSQL pre-defined authorization role by using the `ldap_map` configuration option. + diff --git a/docs/how-to.md b/docs/how-to.md deleted file mode 100644 index c4ecd48b71..0000000000 --- a/docs/how-to.md +++ /dev/null @@ -1,111 +0,0 @@ -# How-to guides - -The following guides cover key processes and common tasks for managing and using Charmed PostgreSQL on machines. - -## Deployment and setup - -Installation of different cloud services with Juju: -* [Sunbeam] -* [LXD] -* [MAAS] -* [AWS EC2] -* [GCE] -* [Azure] -* [Multi-availability zones (AZ)][Multi-AZ] - -Other deployment scenarios and configurations: -* [TLS VIP access] -* [Juju spaces] -* [Air-gapped] -* [Terraform] -* [Juju storage] - -## Usage and maintenance - -* [Integrate with another application] -* [External access] -* [Scale replicas] -* [Enable TLS] -* [Enable plugins/extensions] -* [Switchover/failover] - -## Backup and restore -* [Configure S3 AWS] -* [Configure S3 RadosGW] -* [Create a backup] -* [Restore a backup] -* [Manage backup retention] -* [Migrate a cluster] - -## Monitoring (COS) - -* [Enable monitoring] with Grafana -* [Enable alert rules] with Prometheus -* [Enable tracing] with Tempo -* [Enable profiling] with Parca - -## Minor upgrades -* [Perform a minor upgrade] -* [Perform a minor rollback] - -## Cross-regional (cluster-cluster) async replication - -* [Cross-regional async replication] - * [Set up clusters] - * [Integrate with a client app] - * [Remove or recover a cluster] - * [Enable plugins/extensions] - -## Development - -This section is for charm developers looking to support PostgreSQL integrations with their charm. - -* [Integrate with your charm] -* [Migrate data via pg_dump] -* [Migrate data via backup/restore] - - - -[Sunbeam]: /t/15972 -[LXD]: /t/11861 -[MAAS]: /t/14293 -[AWS EC2]: /t/15703 -[GCE]: /t/15722 -[Azure]: /t/15733 -[Multi-AZ]: /t/15749 -[TLS VIP access]: /t/16576 -[Juju spaces]: /t/17416 -[Terraform]: /t/14916 -[Air-gapped]: /t/15746 -[Juju storage]: /t/17529 - -[Integrate with another application]: /t/9687 -[External access]: /t/15802 -[Scale replicas]: /t/9689 -[Enable TLS]: /t/9685 -[Switchover/failover]: /t/17523 - -[Configure S3 AWS]: /t/9681 -[Configure S3 RadosGW]: /t/10313 -[Create a backup]: /t/9683 -[Restore a backup]: /t/9693 -[Manage backup retention]: /t/14249 -[Migrate a cluster]: /t/9691 - -[Enable monitoring]: /t/10600 -[Enable alert rules]: /t/13084 -[Enable tracing]: /t/14521 -[Enable profiling]: /t/17172 - -[Perform a minor upgrade]: /t/12089 -[Perform a minor rollback]: /t/12090 - -[Cross-regional async replication]: /t/15412 -[Set up clusters]: /t/13991 -[Integrate with a client app]: /t/13992 -[Remove or recover a cluster]: /t/13994 -[Enable plugins/extensions]: /t/10906 - -[Integrate with your charm]: /t/11865 -[Migrate data via pg_dump]: /t/12163 -[Migrate data via backup/restore]: /t/12164 \ No newline at end of file diff --git a/docs/how-to/h-configure-s3-aws.md b/docs/how-to/back-up-and-restore/configure-s3-aws.md similarity index 80% rename from docs/how-to/h-configure-s3-aws.md rename to docs/how-to/back-up-and-restore/configure-s3-aws.md index 5cc50899ce..be9bbdf026 100644 --- a/docs/how-to/h-configure-s3-aws.md +++ b/docs/how-to/back-up-and-restore/configure-s3-aws.md @@ -1,53 +1,63 @@ -[note] -**Note**: All commands are written for `juju >= v.3.0` - -If you are using an earlier version, check the [Juju 3.0 Release Notes](https://juju.is/docs/juju/roadmap#heading--juju-3-0-0---22-oct-2022). -[/note] - # Configure S3 for AWS + A Charmed PostgreSQL backup can be stored on any S3-compatible storage. S3 access and configurations are managed with the [s3-integrator charm](https://charmhub.io/s3-integrator). -This guide will teach you how to deploy and configure the s3-integrator charm for [AWS S3](https://aws.amazon.com/s3/), send the configurations to the Charmed PostgreSQL application, and update it. (To configure S3 for RadosGW, see [this guide](/t/10313)) +This guide will teach you how to deploy and configure the s3-integrator charm for [AWS S3](https://aws.amazon.com/s3/), send the configurations to the Charmed PostgreSQL application, and update it. + +```{seealso} +[](/how-to/back-up-and-restore/configure-s3-radosgw) +``` + +## Configure `s3-integrator` -## Configure s3-integrator First, deploy and run the charm: -```shell + +```text juju deploy s3-integrator juju run s3-integrator/leader sync-s3-credentials access-key= secret-key= ``` Then, use `juju config` to add your configuration parameters. For example: -```shell + +```text juju config s3-integrator \ endpoint="https://s3.us-west-2.amazonaws.com" \ bucket="postgresql-test-bucket-1" \ path="/postgresql-test" \ region="us-west-2" ``` -[note] -There is now an experimental configuration option that sets up a retention time (in days) for backups stored in S3: [`experimental-delete-older-than-days`](https://charmhub.io/s3-integrator/configuration?channel=latest/edge#experimental-delete-older-than-days). More info on [this guide](/t/14249) -[/note] -[note] +```{note} +There is now an experimental configuration option that sets up a retention time (in days) for backups stored in S3: [`experimental-delete-older-than-days`](https://charmhub.io/s3-integrator/configuration?channel=latest/edge#experimental-delete-older-than-days). More info on [this guide](/how-to/back-up-and-restore/manage-backup-retention) +``` + +```{note} The amazon S3 endpoint must be specified as `s3..amazonaws.com ` within the first 24 hours of creating the bucket. For older buckets, the endpoint `s3.amazonaws.com` can be used. See [this post](https://repost.aws/knowledge-center/s3-http-307-response) for more information. -[/note] +``` + +## Integrate with `postgresql` -## Integrate with Charmed PostgreSQL To pass these configurations to Charmed PostgreSQL, integrate the two applications: -```shell + +```text juju integrate s3-integrator postgresql ``` + You can create, list, and restore backups now: -```shell + +```text juju run postgresql/leader list-backups juju run postgresql/leader create-backup juju run postgresql/leader list-backups juju run postgresql/leader restore backup-id= ``` + You can also update your S3 configuration options after relating using: -```shell + +```text juju config s3-integrator

Save your current cluster credentials

For security reasons, charm credentials are not stored inside backups. So, if you plan to restore to a backup at any point in the future, **you will need the `operator`, `replication`, and `rewind` user passwords for your existing cluster**. You can retrieve them with: -```shell + +```text juju run postgresql/leader get-password username=operator juju run postgresql/leader get-password username=replication juju run postgresql/leader get-password username=rewind ``` -For more context about passwords during a restore, check [How to migrate a cluster > Manage cluster passwords](/t/9691#heading--manage-cluster-passwords). -

Create a backup

+For more context about passwords during a restore, check [How to migrate a cluster > Manage cluster passwords](/how-to/back-up-and-restore/migrate-a-cluster). + +## Create a backup + Once you have a three-node cluster with configurations set for S3 storage, check that Charmed PostgreSQL is `active` and `idle` with `juju status`. Once Charmed PostgreSQL is `active` and `idle`, you can create your first backup with the `create-backup` command: -```shell + +```text juju run postgresql/leader create-backup ``` + By default, backups created with the command above will be **full** backups: a copy of *all* your data will be stored in S3. There are 2 other supported types of backups (available in revision 416+): * Differential: Only modified files since the last full backup will be stored. * Incremental: Only modified files since the last successful backup (of any type) will be stored. To specify the desired backup type, use the [`type`](https://charmhub.io/postgresql/actions#create-backup) parameter: -```shell + +```text juju run postgresql/leader create-backup type={full|differential|incremental} ``` -**Tip**: To avoid unnecessary service downtime, always use non-primary units for the action `create-backup`. Keep in mind that: +To avoid unnecessary service downtime, always use non-primary units for the action `create-backup`. Keep in mind that: * When TLS is enabled, `create-backup` can only run on replicas (non-primary) * When TLS is **not** enabled, `create-backup` can only run in the primary unit -

List backups

+## List backups + You can list your available, failed, and in progress backups by running the `list-backups` command: -```shell + +```text juju run postgresql/leader list-backups -``` \ No newline at end of file +``` + diff --git a/docs/how-to/back-up-and-restore/index.md b/docs/how-to/back-up-and-restore/index.md new file mode 100644 index 0000000000..e6ef0f7020 --- /dev/null +++ b/docs/how-to/back-up-and-restore/index.md @@ -0,0 +1,13 @@ +# Back up and restore + +```{toctree} +:titlesonly: +:maxdepth: 2 +:glob: + +Configure S3 AWS +Configure S3 RadosGW +Create a backup +Restore a backup +Manage backup retention +Migrate a cluster diff --git a/docs/how-to/h-manage-backup-retention.md b/docs/how-to/back-up-and-restore/manage-backup-retention.md similarity index 57% rename from docs/how-to/h-manage-backup-retention.md rename to docs/how-to/back-up-and-restore/manage-backup-retention.md index c41a80c951..c73b30afbb 100644 --- a/docs/how-to/h-manage-backup-retention.md +++ b/docs/how-to/back-up-and-restore/manage-backup-retention.md @@ -1,45 +1,45 @@ -[note] -**Note**: All commands are written for `juju >= v.3.0` - -If you are using an earlier version, check the [Juju 3.0 Release Notes](https://juju.is/docs/juju/roadmap#heading--juju-3-0-0---22-oct-2022). -[/note] - # Manage backup retention Charmed PostgreSQL backups can be managed via a retention policy. This retention can be set by the user in the form of a configuration parameter in the charm [`s3-integrator`](https://charmhub.io/s3-integrator) via the config option [`experimental-delete-older-than-days`](https://charmhub.io/s3-integrator/configuration?channel=latest/edge#experimental-delete-older-than-days). This guide will teach you how to set this configuration and how it works in managing existing backups. -[note type="caution"] -**Note**: This is an **EXPERIMENTAL** parameter, use it with caution. -[/note] +```{caution} +This is an experimental parameter - use it with caution. +``` + +Deploy and run the `s3-integrator` charm: -## Configure S3-integrator charm -If not done already, deploy and run the charm: -```shell +```text juju deploy s3-integrator juju run s3-integrator/leader sync-s3-credentials access-key= secret-key= ``` + Then, use `juju config` to add the desired retention time in days: -```shell + +```text juju config s3-integrator experimental-delete-older-than-days= ``` + To pass these configurations to a Charmed PostgreSQL application, integrate the two applications: -```shell + +```text juju integrate s3-integrator postgresql ``` + If at any moment it is desired to remove this option, the user can erase this configuration from the charm: -```shell + +```text juju config s3-integrator --reset experimental-delete-older-than-days ``` -[note] -**Note**: This configuration will be enforced in **every** Charmed PostgreSQL application related to the configured S3-integrator charm -[/note] -[note] -**Note**: The retention is **not** enforced automatically once a backup is older than the set amount of days: Backups older than the set retention time will only get expired only once a newer backup is created. +This configuration will be enforced in **every** Charmed PostgreSQL application related to the configured S3-integrator charm + +```{caution} +The retention is **not** enforced automatically once a backup is older than the set amount of days. Backups older than the set retention time will only get expired only once a newer backup is created. + +This behavior avoids complete backup deletion if no newer backups have been created in the charm. +``` -This behavior avoids complete backup deletion if there has been no newer backups created in the charm. -[/note] +The s3-integrator charm accepts many [configurations](https://charmhub.io/s3-integrator/configure) - enter whichever are necessary for your S3 storage. -The s3-integrator charm accepts many [configurations](https://charmhub.io/s3-integrator/configure) - enter whichever are necessary for your S3 storage. \ No newline at end of file diff --git a/docs/how-to/h-migrate-cluster.md b/docs/how-to/back-up-and-restore/migrate-a-cluster.md similarity index 64% rename from docs/how-to/h-migrate-cluster.md rename to docs/how-to/back-up-and-restore/migrate-a-cluster.md index d8399962ec..4420774225 100644 --- a/docs/how-to/h-migrate-cluster.md +++ b/docs/how-to/back-up-and-restore/migrate-a-cluster.md @@ -1,48 +1,48 @@ -[note] -**Note**: All commands are written for `juju >= v.3.0` - -If you are using an earlier version, check the [Juju 3.0 Release Notes](https://juju.is/docs/juju/roadmap#heading--juju-3-0-0---22-oct-2022). -[/note] - # How to migrate a cluster This is a guide on how to restore a backup that was made from a different cluster, (i.e. cluster migration via restore). -To perform a basic restore (from a *local* backup), see [Charmed PostgreSQL VM | How to restore a local backup](/t/charmed-postgresql-how-to-restore-backup/9693?channel=14/stable). +To perform a basic restore (from a *local* backup), see [](/how-to/back-up-and-restore/restore-a-backup). ## Prerequisites + Restoring a backup from a previous cluster to a current cluster requires: - A single unit Charmed PostgreSQL deployed and running - Access to S3 storage -- [Configured settings for S3 storage](/t/charmed-postgresql-how-to-configure-s3/9681?channel=14/stable) + - [](/how-to/back-up-and-restore/configure-s3-aws) - Backups from the previous cluster in your S3 storage - Passwords from your previous cluster ---- +## Manage cluster passwords -

Manage cluster passwords

When you restore a backup from an old cluster, it will restore the password from the previous cluster to your current cluster. Set the password of your current cluster to the previous cluster’s password: -```shell + +```text juju run postgresql/leader set-password username=operator password= juju run postgresql/leader set-password username=replication password= juju run postgresql/leader set-password username=rewind password= ``` + ## List backups + To view the available backups to restore, use the command `list-backups`: -```shell + +```text juju run postgresql/leader list-backups ``` + This shows a list of the available backups (it is up to you to identify which `backup-id` corresponds to the previous-cluster): -```shell - backups: |- - backup-id | backup-type | backup-status - ---------------------------------------------------- - YYYY-MM-DDTHH:MM:SSZ | physical | finished +```text +backups: |- + backup-id | backup-type | backup-status + ---------------------------------------------------- + YYYY-MM-DDTHH:MM:SSZ | physical | finished ``` ## Restore backup To restore your current cluster to the state of the previous cluster, run the `restore` command and pass the correct `backup-id` to the command: - ```shell + + ```text juju run postgresql/leader restore backup-id=YYYY-MM-DDTHH:MM:SSZ ``` diff --git a/docs/how-to/h-restore-backup.md b/docs/how-to/back-up-and-restore/restore-a-backup.md similarity index 77% rename from docs/how-to/h-restore-backup.md rename to docs/how-to/back-up-and-restore/restore-a-backup.md index 788804a140..ff09bb747e 100644 --- a/docs/how-to/h-restore-backup.md +++ b/docs/how-to/back-up-and-restore/restore-a-backup.md @@ -1,40 +1,30 @@ -[note] -**Note**: All commands are written for `juju >= v.3.0` - -If you are using an earlier version, check the [Juju 3.0 Release Notes](https://juju.is/docs/juju/roadmap#heading--juju-3-0-0---22-oct-2022). -[/note] - # How to restore a local backup This is a guide on how to restore a locally made backup. -To restore a backup that was made from a *different* cluster, (i.e. cluster migration via restore), see [How to migrate cluster using backups](/t/charmed-postgresql-how-to-migrate-cluster-via-restore/9691?channel=14/stable): +To restore a backup that was made from a *different* cluster, (i.e. cluster migration via restore), see [](/how-to/back-up-and-restore/migrate-a-cluster). ## Prerequisites -- Deployments have been [scaled-down](/t/charmed-postgresql-how-to-manage-units/9689?channel=14/stable) to a single PostgreSQL unit (scale it up after the backup is restored) + +- Deployments have been [scaled-down](/how-to/scale-replicas) to a single PostgreSQL unit (scale it up after the backup is restored) - Access to S3 storage -- [Configured settings for S3 storage](/t/charmed-postgresql-how-to-configure-s3/9681?channel=14/stable) -- [Existing backups in your S3 storage](/t/charmed-postgresql-how-to-create-and-list-backups/9683?channel=14/stable) +- [Configured settings for S3 storage](/how-to/back-up-and-restore/configure-s3-aws) +- [Existing backups in your S3 storage](/how-to/back-up-and-restore/create-a-backup) - [Point-in-time recovery](#point-in-time-recovery) requires the following PostgreSQL charm revisions: - 467+ for `arm64` - 468+ for `amd64` -## Summary -* [List backups](#list-backups) -* [Point-in-time recovery](#point-in-time-recovery) -* [Restore backup](#restore-backup) - ---- - ## List backups + To view the available backups to restore, use the command `list-backups`: -```shell + +```text juju run postgresql/leader list-backups ``` This should show your available backups like in the sample output below: -```shell +```yaml list-backups: |- Storage bucket name: canonical-postgres Backups base path: /test/backup/ @@ -60,21 +50,25 @@ Below is a complete list of parameters shown for each backup/restore operation: * `backup-path`: path of the backup related files in the S3 repository. * `timeline`: number which identifies different branches in the database transactions history; every time a restore or PITR is made, this number is incremented by 1. + ## Point-in-time recovery + Point-in-time recovery (PITR) is a PostgreSQL feature that enables restorations to the database state at specific points in time. After performing a PITR in a PostgreSQL cluster, a new timeline is created to track from the point to where the database was restored. They can be tracked via the `timeline` parameter in the `list-backups` output. + ## Restore backup + To restore a backup from that list, run the `restore` command and pass the parameter corresponding to the backup type. When the user needs to restore a specific backup that was made, they can use the `backup-id` that is listed in the `list-backups` output. - ```shell + ```text juju run postgresql/leader restore backup-id=YYYY-MM-DDTHH:MM:SSZ ``` However, if the user needs to restore to a specific point in time between different backups (e.g. to restore only specific transactions made between those backups), they can use the `restore-to-time` parameter to pass a timestamp related to the moment they want to restore. - ```shell + ```text juju run postgresql/leader restore restore-to-time="YYYY-MM-DDTHH:MM:SSZ" ``` @@ -82,6 +76,6 @@ Your restore will then be in progress. It’s also possible to restore to the latest point from a specific timeline by passing the ID of a backup taken on that timeline and `restore-to-time=latest` when requesting a restore: - ```shell + ```text juju run postgresql/leader restore restore-to-time=latest ``` \ No newline at end of file diff --git a/docs/how-to/cross-regional-async-replication/index.md b/docs/how-to/cross-regional-async-replication/index.md new file mode 100644 index 0000000000..dcf32076f3 --- /dev/null +++ b/docs/how-to/cross-regional-async-replication/index.md @@ -0,0 +1,41 @@ +# Cross-regional async replication + +Cross-regional (or multi-server) asynchronous replication focuses on disaster recovery by distributing data across different servers. + +## Prerequisites +* Juju `v.3.4.2+` +* Make sure your machine(s) fulfill the [system requirements](/reference/system-requirements) + +### Substrate dependencies + +The following table shows the source and target controller/model combinations that are currently supported: + +| | AWS | GCP | Azure | +|---|---|:---:|:---:| +| AWS | | | | +| GCP | | ![ check ] | ![ check ] | +| Azure | | ![ check ] | ![ check ] | + +## Guides + +* [How to set up clusters for cross-regional async replication](/how-to/cross-regional-async-replication/set-up-clusters) +* [How to integrate with a client application](/how-to/cross-regional-async-replication/integrate-with-a-client-app) +* [How to remove or recover a cluster](/how-to/cross-regional-async-replication/remove-or-recover-a-cluster) + * [Switchover](/how-to/cross-regional-async-replication/remove-or-recover-a-cluster) + * [Detach](/how-to/cross-regional-async-replication/remove-or-recover-a-cluster) + * [Recover](/how-to/cross-regional-async-replication/remove-or-recover-a-cluster) + + +[check]: https://img.shields.io/badge/%E2%9C%93-brightgreen +[cross]: https://img.shields.io/badge/x-white + + +```{toctree} +:titlesonly: +:maxdepth: 2 +:glob: +:hidden: + +Set up clusters +Integrate with a client app +Remove or recover a cluster diff --git a/docs/how-to/h-async-integrate.md b/docs/how-to/cross-regional-async-replication/integrate-with-a-client-app.md similarity index 81% rename from docs/how-to/h-async-integrate.md rename to docs/how-to/cross-regional-async-replication/integrate-with-a-client-app.md index 99d6a347e5..13f2c761bb 100644 --- a/docs/how-to/h-async-integrate.md +++ b/docs/how-to/cross-regional-async-replication/integrate-with-a-client-app.md @@ -4,17 +4,10 @@ This guide will show you how to integrate a client application with a cross-regi ## Prerequisites * Juju `v.3.4.2+` -* Make sure your machine(s) fulfill the [system requirements](/t/11743) -* See [supported target/source model relationships](/t/15412#substrate-dependencies). +* Make sure your machine(s) fulfill the [system requirements](/reference/system-requirements) +* See [supported target/source model relationships](/how-to/cross-regional-async-replication/index). * A cross-regional async replication setup - * See [How to set up clusters](/t/13991) - -## Summary -* [Configure database endpoints](#configure-database-endpoints) -* [Internal client](#internal-client) -* [External client](#external-client) - ---- + * See [How to set up clusters](/how-to/cross-regional-async-replication/set-up-clusters) ## Configure database endpoints @@ -24,7 +17,7 @@ To make your database available to a client application, you must first offer an [Offer](https://juju.is/docs/juju/offer) the `database` endpoint on each of the `postgresql` applications. -```shell +```text juju switch rome juju offer db1:database db1database @@ -36,7 +29,7 @@ juju offer db2:database db2database It is good practice to use a separate model for the client application rather than using one of the database host models. -```shell +```text juju add-model app juju switch app juju consume rome.db1database @@ -49,7 +42,7 @@ If the client application is another charm, deploy them and connect them with `j -```shell +```text juju switch app juju deploy postgresql-test-app @@ -65,7 +58,7 @@ If the client application is external, they must be integrated via the [`data-in -```shell +```text juju switch app juju deploy data-integrator --config database-name=mydatabase @@ -75,4 +68,5 @@ juju relate data-integrator pgbouncer-external juju relate pgbouncer-external db1database juju run data-integrator/leader get-credentials -``` \ No newline at end of file +``` + diff --git a/docs/how-to/h-async-remove-recover.md b/docs/how-to/cross-regional-async-replication/remove-or-recover-a-cluster.md similarity index 69% rename from docs/how-to/h-async-remove-recover.md rename to docs/how-to/cross-regional-async-replication/remove-or-recover-a-cluster.md index 06621e33c4..aa4d400dc6 100644 --- a/docs/how-to/h-async-remove-recover.md +++ b/docs/how-to/cross-regional-async-replication/remove-or-recover-a-cluster.md @@ -4,20 +4,10 @@ This guide will cover how to manage clusters using an example PostgreSQL deploym ## Prerequisites * Juju `v.3.4.2+` -* Make sure your machine(s) fulfill the [system requirements](/t/11743) -* See [supported target/source model relationships](/t/15412#substrate-dependencies). +* Make sure your machine(s) fulfill the [system requirements](/reference/system-requirements) +* See [supported target/source model relationships](/how-to/cross-regional-async-replication/index). * A cross-regional async replication setup - * See [How to set up clusters](/t/13991) - -## Summary -* [Switchover](#switchover) -* [Detach a cluster](#detach-a-cluster) - * [Reuse a detached cluster](#reuse-a-detached-cluster) - * [Remove a detached cluster](#remove-a-detached-cluster) -* [Recover a cluster](#recover-a-cluster) - - ---- + * See [How to set up clusters](/how-to/cross-regional-async-replication/set-up-clusters) ## Switchover @@ -25,7 +15,7 @@ If the primary cluster fails or is removed, it is necessary to appoint a new clu To switchover and promote `lisbon` to primary, one would run the command: -```shell +```text juju run -m lisbon db2/leader promote-to-primary ``` @@ -35,7 +25,7 @@ Clusters in an async replica set can be detached. The detached cluster can then Assuming `lisbon` is the current primary, one would run the following command to detach `rome`: -```shell +```text juju remove-relation -m lisbon replication-offer db2:replication ``` @@ -45,14 +35,14 @@ The command above will move the `rome` cluster into a detached state (`blocked`) The following command creates a new cluster in the replica set from the detached `rome` cluster, keeping its existing data in use: -```shell -juju run -m rome db1/leader promote-to-primary +```text +juju run -m rome db1/leader promote-to-primary scope=cluster ``` ### Remove a detached cluster The following command removes the detached `rome` cluster and **destroys its stored data** with the optional `--destroy-storage` flag: -```shell +```text juju remove-application -m rome db1 --destroy-storage ``` @@ -60,4 +50,5 @@ juju remove-application -m rome db1 --destroy-storage **If the integration between clusters was removed** and one side went into a `blocked` state, integrate both clusters again and call the `promote-cluster` action to restore async replication - similar to the "Reuse a detached cluster" step above. -**If the cluster group lost a member entirely** (e.g. `rome` is suddenly no longer available to the cluster group originally consisting of `rome` and `lisbon`), deploy a new `postgresql` application and [set up async replication](/t/13991). The data will be copied automatically after the `promote-cluster` action is called, and the new cluster will join the cluster group. \ No newline at end of file +**If the cluster group lost a member entirely** (e.g. `rome` is suddenly no longer available to the cluster group originally consisting of `rome` and `lisbon`), deploy a new `postgresql` application and [set up async replication](/how-to/cross-regional-async-replication/set-up-clusters). The data will be copied automatically after the `promote-cluster` action is called, and the new cluster will join the cluster group. + diff --git a/docs/how-to/h-async-set-up.md b/docs/how-to/cross-regional-async-replication/set-up-clusters.md similarity index 75% rename from docs/how-to/h-async-set-up.md rename to docs/how-to/cross-regional-async-replication/set-up-clusters.md index e3a9518115..8328e7b49b 100644 --- a/docs/how-to/h-async-set-up.md +++ b/docs/how-to/cross-regional-async-replication/set-up-clusters.md @@ -6,38 +6,29 @@ This guide will show you the basics of initiating a cross-regional async setup u ## Prerequisites * Juju `v.3.4.2+` -* Make sure your machine(s) fulfill the [system requirements](/t/11743) -* See [supported target/source model relationships](/t/15412#substrate-dependencies). - -## Summary -* [Deploy](#deploy) -* [Offer](#offer) -* [Consume](#consume) -* [Promote or switchover a cluster](#promote-or-switchover-a-cluster) -* [Scale a cluster](#scale-a-cluster) - ---- +* Make sure your machine(s) fulfill the [system requirements](/reference/system-requirements) +* See [supported target/source model relationships](/how-to/cross-regional-async-replication/index). ## Deploy To deploy two clusters in different servers, create two juju models - one for the `rome` cluster, one for the `lisbon` cluster. In the example below, we use the config flag `profile=testing` to limit memory usage. -```shell +```text juju add-model rome juju add-model lisbon juju switch rome # active model must correspond to cluster -juju deploy postgresql db1 +juju deploy postgresql --channel 14/stable db1 juju switch lisbon -juju deploy postgresql db2 +juju deploy postgresql --channel 14/stable db2 ``` ## Offer [Offer](https://juju.is/docs/juju/offer) asynchronous replication in one of the clusters. -```shell +```text juju switch rome juju offer db1:replication-offer replication-offer ``` @@ -45,7 +36,7 @@ juju offer db1:replication-offer replication-offer ## Consume Consume asynchronous replication on planned `Standby` cluster (Lisbon): -```shell +```text juju switch lisbon juju consume rome.replication-offer juju integrate replication-offer db2:replication @@ -55,13 +46,13 @@ juju integrate replication-offer db2:replication To define the primary cluster, use the `create-replication` action. -```shell +```text juju run -m rome db1/leader create-replication ``` To switchover and use `lisbon` as the primary instead, run -```shell +```text juju run -m lisbon db2/leader promote-to-primary scope=cluster ``` @@ -71,10 +62,12 @@ The two clusters work independently, which means that it’s possible to scale e For example: -```shell +```text juju add-unit db1 -n 2 -m rome juju add-unit db2 -n 2 -m lisbon ``` -[note] -**Note:** Scaling is possible before and after the asynchronous replication is established/created. -[/note] \ No newline at end of file + +```{note} +Scaling is possible before and after the asynchronous replication is established/created. +``` + diff --git a/docs/how-to/h-deploy-airgapped.md b/docs/how-to/deploy/air-gapped.md similarity index 85% rename from docs/how-to/h-deploy-airgapped.md rename to docs/how-to/deploy/air-gapped.md index 510cf68b0b..1d3a98781a 100644 --- a/docs/how-to/h-deploy-airgapped.md +++ b/docs/how-to/deploy/air-gapped.md @@ -15,13 +15,6 @@ Canonical does not prescribe how you should set up your specific air-gapped envi * [Air-gapped Snap Store Proxy](https://documentation.ubuntu.com/snap-store-proxy/) is installed and running. * Local APT and LXD Images caches are reachable. -## Air-gapped setup summary - -[1\. Export snaps and charms](#1-export-snaps-and-charms)
-[2\. Transfer binary blobs](#2-transfer-binary-blobs)
-[3\. Import snaps and charms](3-import-snaps-and-charms)
-[4\. Deploy PostgreSQL](#4-deploy-postgresql) - ## Air-gapped day-to-day example ### 1. Export snaps and charms @@ -39,7 +32,7 @@ The bundle export example:
store-admin export bundle postgresql-bundle --channel=14/edge --series=jammy --arch=amd64 -``` +```text Downloading postgresql-bundle revision 140 (14/edge) [####################################] 100% Downloading data-integrator revision 71 (edge) @@ -75,7 +68,7 @@ Usually charms require SNAPs (and some manually pin them). For the manual SNAP e
store-admin export snaps --from-yaml snaps.yaml -```shell +```text Downloading grafana-agent revision 51 (latest/stable amd64) [####################################] 100% Downloading grafana-agent revision 82 (latest/stable amd64) @@ -98,37 +91,44 @@ canonical-livepatch: /home/ubuntu/snap/store-admin/common/export/canonical-livep Transfer the binary blobs using the way of your choice into the air-gapped environment. -```shell +```text cp /home/ubuntu/snap/store-admin/common/export/*.tar.gz /media/usb/ ... cp /media/usb/*.tar.gz /var/snap/snap-store-proxy/common/charms-to-push/ ``` -> **Note**: always check [checksum](https://en.wikipedia.org/wiki/Checksum) for the transferred blobs! + +```{tip} +Always check [checksum](https://en.wikipedia.org/wiki/Checksum) for the transferred blobs! +``` ### 3. Import snaps and charms Import the [snap](https://documentation.ubuntu.com/snap-store-proxy/en/airgap/#importing-pushing-snaps) and [charm](https://documentation.ubuntu.com/snap-store-proxy/en/airgap-charmhub/#import-packages) blobs into local air-gapped CharmHub: -> **Note**: when importing machine charms that depend on a snap for functionality, you must first manually import the required snap. -```shell +When importing machine charms that depend on a snap for functionality, you must first manually import the required snap. + +```text sudo snap-store-proxy push-snap /var/snap/snap-store-proxy/common/snaps-to-push/charmed-postgresql-20241008T082122.tar.gz sudo snap-store-proxy push-charm-bundle /var/snap/snap-store-proxy/common/charms-to-push/postgresql-bundle-20241003T104903.tar.gz ``` -> **Note**: when [re-importing](https://documentation.ubuntu.com/snap-store-proxy/en/airgap-charmhub/#import-packages) charms or importing other revisions, make sure to provide the `--push-channel-map`. + +When [re-importing](https://documentation.ubuntu.com/snap-store-proxy/en/airgap-charmhub/#import-packages) charms or importing other revisions, make sure to provide the `--push-channel-map`. ### 4. Deploy PostgreSQL Deploy and operate Juju charms normally: -```shell + +```text juju deploy postgresql ``` -[note] -**Note**: All the charms revisions and snap revisions deployed in the air-gapped environment must match the official CharmHub and SnapStore revisions. -Use [the official release notes](/t/11875) as a reference. -[/note] +```{note} +All the charms revisions and snap revisions deployed in the air-gapped environment must match the official Charmhub and snap store revisions. + +Use [the official release notes](/reference/releases) as a reference. +``` ## Additional resources @@ -136,9 +136,10 @@ Use [the official release notes](/t/11875) as a reference. * https://documentation.ubuntu.com/snap-store-proxy/ * https://documentation.ubuntu.com/snap-store-proxy/en/airgap-charmhub/ * https://ubuntu.com/kubernetes/docs/install-offline -* [Charmed Kubeflow > Install in an airgapped environment](https://charmed-kubeflow.io/docs/install-in-airgapped-environment) +* [Charmed Kubeflow > Install in an airgapped environment](https://charmed-kubeflow.io/docs/install-in-an-airgapped-environment) * [Wikipedia > Air gap (networking)](https://en.wikipedia.org/wiki/Air_gap_(networking)) -[note] -If you expect having several concurrent connections frequently, it is highly recommended to deploy [PgBouncer](https://charmhub.io/pgbouncer?channel=1/stable) alongside PostgreSQL. For more information, read our explanation about [Connection pooling](/t/15777). -[/note] \ No newline at end of file +```{note} +If you expect having several concurrent connections frequently, it is highly recommended to deploy [PgBouncer](https://charmhub.io/pgbouncer?channel=1/stable) alongside PostgreSQL. For more information, read our explanation about [Connection pooling](/explanation/connection-pooling). +``` + diff --git a/docs/how-to/deploy/aws-ec2-availability.png b/docs/how-to/deploy/aws-ec2-availability.png new file mode 100644 index 0000000000000000000000000000000000000000..a62fc37920079df71bcf9d35b1167a99f36f2727 GIT binary patch literal 53477 zcmd42WmH?+_bv>jKq*#=7b~Sead#_FTnmNb4#C}>Qna``En3_qSfDt;Def9HIKcvM zdd}~hzkImk{c^{+>qC;Ay>~L#nrqrKpBmI3 zkX|FneGvcTnRU4Ap*KBE)qhI7`GoT+-bdAsS!o-Z1w94M$K2nzWyDxMr=(*uF)@)@ zSai!*42N1|_*4<76Z8hXYkna`@F5f{2pqCX_0H;v{dZq6DqKq3>lhbNh%+h7Zw%%; zqNlI#!Vp+iW+R>{_2J(EW!RzB4-Efz$XZ!w&&6C{UvHF4{(I4ff=`UxvTW)l?oKn* zZ~h%>j8;~}c>j+0H}7Qs+abf3FRuTd!~5SSC4TUc5#I3q+|wpqz0+0gYgCj={qw_* z9K=&>wSKzn{cluKT^auRFSTC;1z=FdF`Pw9_}F8#FNSW!YNnMkguqIk<+ z@>^OF-*_;Y>Pl1pIbI?Jn2zq2^8F$c;GG|_O5GXC)`61T%-9I#Hbf2^r@H6%Tg>!`aa zP1xyP!|vwphSOsP^1Eakqf@ro46jx6#;{P3uMgnYupgNK-97^V2ad{tf_U zKg`w`@zLI^^}j?QU;}ULZk^P~>WEGTU!O2!D;e$CIhBr!o`!9~&hZns!7nws1;zXQLoy+~jy7_U+>$n?vllu}k!cEZ|D z;VD0MlMzi7Dt158;kH?cI%C}i#$^q!h}=EH7EzrvkN8IpSq61x@s>fe7RC?ga{=s6 z0vVxRbt8PXE1@ty1Mar5Zz4a8>n$h4DOzD_B_^mk+;%;`%*(7+3aC?3Qp)E^o^|eV z)m(FzeSo;zX*WPs6bpqFQzyHA{rcim)%GDQ=BRSM$!^hIG+Q|N9D*(If%&uJ$%bbCmaybzC^L4g5a&d9tLYjdC2?I4*GLXEuW`bddH2h{_BV;}(CxI$; zZKizNsC$W`@W|nEX3@tJJ9m4%A)%_6uIWNwC+xkVLtIP{O)mK8ZY>|SH(o;lFd1dv zT-0v6xz+W(xp9pl7Z`%W?#|Y?aI0$@S@$^qHOqpecPXTMxYyi}Vh2&$jRB`8!C&MQ zRM5Y7OWF+#4x+A&ujgk8kcFw#^_8zwlR})850~0;o8&8_UI_-Cjc!{`w_)6M|B4VH z#(jSsZ(48t_^!e)W2&%S47t5^qE%NWG}YA#s(<{}HU%PV z&?|qvhh+=~<*fq5%~s45Q0wx#ea>$N{OOJiw7P&olNP53cb-%_^|qrqaqUq7m)M+~ zoM$i=y%Tf?MUt`ZSmB;=z(fCMLq)bOd52VNr5vwpcVfuto{F(qs;j`8H_o_@y~j7} z*T5aPPr8#4W$q|;YtXr^CC4F)pgFv+;25@&4bmoZ+q?1(XsbZ36=+?z=~yN4;PZa@ zM``hoKTR+u!?67mmX`FqabGEW-%26b+JR5*>w-Db6>s`0;9PP2-mdEpL`rgs@;jDh z1ROO^Y0l0ku=7G=KQ_7mr^{%*DTJGGSAT88hk6EQ193gxv3a?VCl<2Gf)3iy&(>WU zFuY9p;k>!Xsn)-%(!9}y22Ac8ayh$pIzhZ2(0AubP>`lTw>zaT;I(W;ep0%R=zG6` zn-%DLMB6{%vc&fp(*+6nwDVRNJyaMb+xJIVJo=9pLcj7jH5j#DQjz4pK=_)-2-=hx zUNb7~0bFp5@vtn=+o1v)MY;2BWWCT=)Kp07AysWAwYZND(o<~s!c%F*E?8XyP&?KW z=RHj&pukwaJ4}Pi+d0*XtjJK1BQltyasEu$JIc+_U;ewf(n2g$$*Y@!wE8a-Tat`4 zw<2Z=CPX6I3Gm>1_Z=50CI;tbk=K4c)Q*%a2fCW7?;{!1_WfS92QL&C8U_Rk*s!r2 zJW*|^UDSa0^!1urScHaz^y-s=D|GJ9v0{$rf1QfxYTchl>8==%*Z_RU<+gvvbLkBX zZAc8`H69DNSn;+HHh8!F`ceq0F}*Z#XTD8~XF2RDWjJQmABJrj8h7nq9>TBjUWvgd z!u+Wu;9y+iWoqWT0~=}0raY@-;`D1R^>XAPKJ%@l_*1LNRuDzRJydSn^XUmDl;r60S(}xJ!p>{2qd*xBZcb_#v0hkR_BWtG1BL z&_vtd`znrtQrx#;$J5Y(R@4Xm5OWc*CsiB|Kdrcp9cd86A1}th>7V6=#>70jBF&KIYs0yV3iaNt5j(~SH$bGin%;Ht40}A7}NIG73-}5Hcro!Fu6eH9Wj*meBvo8nq!cXIpPJ7n11Jb+6mqfxoxWz=P1+SuU6u;Q`FRV0I}8Wo>ochkF?hg^ zVKI&FQf-dQkGdq=ut0;!qp>QS;bdI?DD>P+7x$2*>v0?Rgg$=FLDWK{>o^Ef=TsGi zU##6|K^&j@Fq19fc7}udcgg_OK%@(g9iFHR3?&!4OEG8$ZgcI&NZkg$C{=t_psbjmg-Vd8XO?$^UGq4<}E{2G^U*D4;yND z8csC_30=npWxCsJt=XWrMC5r5aBHLYTTfQZ5ARFs=Fjf*I~NUXYuG6%+$Z+$-5Vp+ zKQ^5RbN1r-y$L27S=jV&rtL!CXm&;>1zR7Hp17L6oE?XPybQRJQYLN9YYao-V5j?v*RM}`Ort%D`nn5ELkCfbV6 zNyXQ%Jz%{qBNA^gJss{2`_dI-4@P$B^)YgI6Fbl6%>WX~P*cyzeo}?b$;pI;u?_`H zd^4E}v)ibng3u${T0f8b-2IsCT=B1z5lky(U4Q9#ORPfci)-LC8E>6;_fA>k(L!CW zzR#6mgWW_V&uo^@wdLEeSZRYg_!#KR^?B8IA>Cd5S}|tf0E?Sshi6NNR|h~x?(keu z%#C6VNiAN;NAKT;J&J*8Zf$}_M8=;xzSmppyvM{SH^A$e!?QbuV=gS%113{Gb?y)0 z|EL~ZK)pmE_d8;^s<)O|t!%%!ZK@n5zj{(v$yIk~uhnFaf`Ts6`zP=UIkfwXJQ&mD z_O6VkBr|q4`X47CCkKR*yP<^Ti|z?ndZ$NwVV5yg+VwnW3bTFO zl^UUS0a9_+>bVB7ymY4E*H^^TlGWsJGJfXOR>e1e zOQEn9>>?*P;Rh(w+K9e7FKJ(!N?je-K!@w>MID(1$0nOXwdMOJVz_LE(6>%Y8WQ!h z1rbm-FqdvTuYyhKNlt#E)RTB>aa*0bY)k!U+P^A=rjofY7aMD~i3$`DJw+h!YgR*N zlI|oSyyEXHM?#}qMK_lD*ROnj0As8}CfcVF;qLo1=23IXwOyAZk_CIzs&Y}uqGYa1 zk=NyM7_-E@Y=BFbDt7C4)lP2$9$ZLM%28|=b9;M~V<%mg$t4oLmj@F&?Ap?--`%KKeX)V()v)P}8j`dhzXU&VI(0=J*>YQM7mE`>64w5V~R zBvTcaog$(3$|zleciv1doM!J{EJiNe=#C1{_OTnS_|A9lcbyQ*5_9^4#%nnbXT`sC z;5-H_6K`oiy(l#`nJ~uWJl-g57-8H#DXNMOtrWOfbawu6q(_#gJ`6SJFN{#9prpEc z+L2?Q)G)B2XZGxTHD^er=KUeL0lX*MBj+xreUqAtDI{M(G;g&jq&}JO*S(uI^Fi)V zlAJLrdEC$>1AYm7N4CR|1F3e@L2y5Y0z61)2I3GuEEjb$pd zskL!CQTW9CFWmx<)|s@DPGHQ!#ItSl5D4o?XMQ`l}!`+j$@bD`fe08sL$!@c=S_sX-*?MX%Ucvvo-dm}}I*-RH*}B98kA zsgT3rH;0I&x`8ii{b_-DWclPUB<@XLuB@iu0$#_RNx# z!ufukCFBv4YTz4kr@N{GCK_>aVo*_Y=Jb)gs`ZCU3%c)jGF3%yCeQXEFMUdbE|20W zOF6Mpqa^C1S~u9Mh=56+zLi@CQbbhxk=T`x0D8 z=N(Vqkn*pojS$}1z7~o34L&9Z9GgSSe5&?_YOPImKJmN^pbJSFwjFBb`R?ZOnN#`c z%L-7y-&;HrdOOK_j-y@8Hk#$I0N~7%)^{Kk+e571_>XR^02f->J64+$-Cw|RaEl^EZ-BFV z;fb}t4yV7%UQ6u$L-k2niZyWhNX=KXN~gOdvG^ILkk(`&!adyE%yCopTuaZJ9cT6z zyL7)JEGyOeT|E1h{wKgLqL4O=Y0vxbti-T*&Z6K^9e$h)dFBG;!^G zNd`c-Wrc&&vQw^M83(gJND)y2F`o4D)4+4DdJxJQeI6Lu2)x!D?JD!dp)_|XF-uj@ zxYNr5ZzUv{OCwYY;d=e1D@w$P=ups9+041?AeTyx8%2I>VfW83!6Ku!KG?J8vRWXj zqokRIzo)VK{Zo0s%S`*e4H_cHp1cBufAJYa>M)e8{kSEj2>u)A`@5c9{GX7XxOmHb znZ6=Ome!*wf%Ok|`4G$qY<1#*o5-d94O$kyFVUjW-_o>OB~l!tr_7JCOHW|^<5M3@ zS&IzK?i$zrzVX8cd1S87pJ$i8xX%G+S)e+9N%;4RJO#_qpGo{@s6G7?ME@O9s&TCU z9=!SAC##ulWu|W3BI|JeYi{vsgTvF)JWbyzYHDhF^}mHLQI}X*X^~>3rKczV2mk!@ zi;vzq3sPHR?{0^+Yn6)rkrN@)mKb8@0|BZj6SDU9LByGVEzX~p0VTEnlQ92BN&g=? zNxO9&kths1d#YLScwRJ`$>l)J7LzM$qIR~-p!kncD)SJqt^EKXH$ZCJx}ij`f|r`w z=UASqSXt_P4`6t*ec^B{e^)q?kZe;^*U-B<1}i;cD6wMJZ-_}<@r{KT1YvnRw{S__NPmFq3u5|4kv?Zajtr`|JlF;A~IZ) zQU$;H-S0i+QdMo;p`)48tL09?_jZHCYI7|#X*)`<&d$!eO9Bj+CB__P<}$Og$lZ^z z+YcHL*u-CB=>TB?19qoB*Z)jh8)S?xc7KhZ-Ex&@q3@8<=ovT$y1y+oMQM7F%I&}V z2r_orpK(y^XBD}*nf20Z^Ncs}dy;kuk44gJj!OVV4daSEJng(+eKhJ^`?0jTV{AQh zS@f|^6N^MRNpc;pNe{QvaPf<0-s&_Ii#niI&HkBc0b&pYrm~d@9qS4am$l)n4&2B}Z=eK|o5n@sQaHeU!lJfGER% zGzk^{V_P0Qbu`k6@$vDGZqm|dR7wv?bkSrRv$x3ZVTV5+JE_e800y| z8-P37F=H*fiLRqR1e4)&1ITzY_iG4+3Al)7Zhn6GlL!(xrOK?w#S{UY4vN{YKB)5A zE`4Z~q1;gQd@4femsMZSJv=YPN}*AbPNNOMH#^>e`KGTp{^4QffYz?bm%-c7a2?izwfEZS=*l^f)O>ufQulvmu{Amw<%$QS$pQ|GOc5r#}A(hRP(+CM=o^5B(H=3h_Nl0G1bXyy|Iu|ylAm=A($qb{i#taM& z7D1QvaA9}lgR_QAZ1#0@Qh^?aMvrv)tJ%_EbjnC;wzkYa&~a8=MMz0WqXNz;oSmH= znRQcC#BSom_{uGMCqpidrpN-D=#}5FutZxZWmb#54bNY{+k;!GAQc60owsZ5(8v+jRr%Ojr$j)-j=HTjEEoftlk*{L zE1DJmxVT4)=aW)fF_zm?2`jNz190(`u^1(Dnv8SPBrd z`FWyyNhqhet^Hva%hzb7m75Z)y{2hpab9u-qs#SkVI9yDE+4OTYlr4dzyH`$_`NQo zc?CqNt*i4o-Yoe*F5tdwN)toA2_KxQ)Oo%ID*C=Hm*bnqrcwH-&y4eQfy`l|+}uX= zdN;8w#fD+11ODUb1(o9RZ8UJKl{6McmIh*jMHXt?*XQ8V=bec;{2sr{fETOejvAhs zpFDM7nQ-F^dGOsK^&ZXoPKAJxnWS(b*Su)xY*%_BbLV`Bz0! z2o*sCx65W~JOW4@RBpcpuZLlZKoQ8{O3np_&s9jR^GK*kdG(e?`R>r|G?N_{L|q zkS0TU1=`OCz$%-BS;=f{kZNmd?QO8q)3rZ0crc9?S)3~2vKiPOiC+UJI2HN3#SN#h>PSQd zeZs)-sPQlg>FQS9n~U5QdWbufqJ&0O})_w>F8Gp2?_EDr{7Vb zGg&L;;(mx_aaKH4?NME9l_;H-neM`P%MIDs+?#Jdz>Yr1U19`2c|jcT(Af9F2P%w+ zGYIswy~5o-l=So13TV{K|DP!S_*IR(08(>KI#iEr@Y$Bb2!I9~~3b;f=kT!kZAid~4O=&!;@)0Atu<8_cB1=f@=-Pb zt-H{i*!I+RAqT=Fd06%>trdu}lC38z)cnQD1x0`|Q&EkMALupZH}JY;wiZ=gSZHTt zr+=hBoa>dNGc0fH1kcqKY_s6W`!!_sDISS;!knwFFx6o{I5=a&wZz7B@?(mBT|D-k za)PCE&p}s*@Z$&dEM}yr5B9go0$>k(%3PcnN^ZXbHpy0>?d)9gUspJm0~m3doVSPyVS}%o|O{W47>nP!WEJnWxgPS{F)hnnTqqldHIW zvQE>aH&rK@TVx{j*}_jO^W>yEEi+TSyG~GF(BtWMr~FW6!`i@-sgAdn{mQI*&4Dfg zfVQ^%@y9`Wdrv)7E7dC2phb_DZj2fGlo}2#SK&1M$Ul!YAUo*(n8M(B_Ty7D#W}~U zF3j$qYBQnQ?a=Po{J_<*f7JcRVNqFG2}C^#kB&yvIuFziCCSq~IgoxpTh%<7z@t)M zg`4S8D$Pj^Fla{+pmlxqAti;X=YrU`x^?|wL;LosY}oD9P!_T8YsREFZW&=F0TUTv zG7Cl1${MDr6zVJn$-b?7RwbpLF3TV-m$vBy4Z zu)uup!s}7r`?DONJ1qZ3u#o{JXJ5W-zp+57+-M={we4L8xIme;;3#eMd^M}br&IMw zhF}6wN9Z0`lgTbmkevR~>l+fGnD^V(tVwko&b~LUbaswrJ&>_YfS>teMTzbp-fUzH z`Qx6_3Wk$u=YW5GiP2kVr;f$Li)ZaC=FT2Xx{os$bm}l7s596m-a=$qtWNTr~SULo=~42^(O_>yl+YODg3 zXpBxy?qg4xHjrhN>tQ<^;AH3`dicO%}xNsv?S8G2I2$ZI_5*AvAt_2D7O20KR?UHA($#Cy$fRi)sL(c^C2Z`Rt;??S^j7Cr-H`c>?ZqHuJ%8xWjZaRNLfHENZR*;xPx^HifkD6xDwL_HkiX#KU;-$jUOZ+p zm15^=4GHLmROmHfV7j=pxcP3eYSRB>R;kIiuPJotOFy;o9#%LTiezaX)4h93L6!Rp z`Xpm?9d*hxATel#O-#jOOjm2?4e!_Q?@)4Jvpw&H6#)10-=`84AC_=G2geVfQnCBr zZ3km}HtzLb^TK7nt#oCL0XV&a(5LQ}eVgKxZ6yTJ=;?>F`8T%AUNccga5obakwpmQ zV#SySrm{PiPR!Li>xsY5$&N=t){K`||m`1em}7crGe+uk{v@I)rE%0&kz;Xl+JS#f#z zB&%6bVp5iGuZ*BHKFKRL>hE|@NAClzzM)`5@JpL*aY%R^y=H$yDobZJO5X+=d=Fa> zw%klpR+HeA!$8hQ41rbafv;&^!Pxy2N9HOZMlU(d2X__fzKU} zDXn3T#A$Hw!?8}!($U`UQ=5=t)Pf?z(qBvA9P4kX5g{c-{R04v?LI^3CD1}tfo4Na zUbK51P5pOZUNm;qgVq^PR{Y)HJRXn8(AzC63iyq*R~GD>qL1@6)?=_ zLlX`D zeN9I&4(-K-OiWF`wGzb#R8&jiwcSm8dd1UxobduKkMOmBQcXW}9M1J=;^PJHy*u0x z^|}mnO+GJ;um4nM;d%-Pkc;A_|Mj~Do0)gqA3(!qL+f*=vinQD^Sg)&=bz#mn)S!k z41hvDXY25}W`%^@=wna(dvYAXOxcc-!=5kPP+M>b3j2t__zeC~6Dw`@hTNja1;Y_x zUcQCk&ny_k>6N9=r-$d8$UFBRhbGtEL9qx21bg!bNSRGe$S5Kf`s0u!++rDv9v#Dhv@=|uUTW0@jb5WnGu=p(B zpsg*;!+EMcT+lFJfp67?nzo?;{MS_fOc%&d=qY_Gx6>gQA2RVcXS*%|;}bJ`&(fJR zyp9dlt`NN>*(7z3#Kqttki{(* za)8W!u)X)8-algOc80medVA$$Im_z9fxCx|(u>NBSS=-8T;q zuQqmHS&Yw&e^l}4u2DL>p50^s2?$0fx^6&h@qz45k--Nu%U*;}>{81g>YZq7HC;q127PV}{?YN<%CR>S1yB5GZ|nFD zsRI`8DYxBJ#*hIk?dQ@Z{6;iXNXYKx0mnuFO69`msk&D*VK`f5>0&Rv*|Uy>JT@0= zwJ|hwnx_vQ&1_WJkJ~va3ltdK<3AQ(@7C?L!TP|>No=1dx0m7&{5%8CBRk4~dLdZq zFNnGo9(ir7SW3l4bgHx|0H8a$eP4{I3r{A=jyZP+JGgCCs|vt)csD8;f=3DnYz3dL z?UXTJ8mpDbukB$+NKY2nNt~+$Tz6RzU5Ymz!&;B%zgtSqc-X6e(c`P8 z0=Ax$AcE5X$k>Y5MmLL`qUyT3*9e(hZ!}gY`uhHuw(s(?AJUQG={?ia3dB`f#ty_> zHuQ~#_}os^SEA=cFHH6KW1HFvJE5{BCJcuHZ6eAizcuw==9{{(372`TX@fCyd5=yR zTzOmK2b9FlM&~A;Vj+Nt-3Ud4SIU!OF%c`Ln281y3Y}}~SYCc~Wi-*LSH1Yx%k*vR z7Tn0eVJ}XG%c64I^W$DsSy+x|@Ujj*wa4yH15L{gT)o&>^7Z`5Y7|ND3Z{D!TV%M9 ztGsoa9!15K5g61>%72Bwb0|Mb_PDkF)R#ndp^#=%)AxPuLlq}vw-CF?v4c|JtCPZ* z9*7?ZIh^-E3RFH?Ao5m(Ts?U8LvdTT{r$6A1C31$TK7$R=4JJ^NR zZfY8|Wq-i|JoE9TB@LFZ^L_6@B&bo{VY6 z_T5=prn$Yna(hd|d;{Q-r3ulY2?39cY^MT26J;`d{;16Z01WaHZp1Q9ge=kp%!BqpBM>n#3YV!I6fl{t(euCHJFOh3IWLGJty0eRvBl5azglD?BCo7$*m}e%a*uimIxa(^i?DqdV9>-(d3qmRsDa z{;sa*LEch&#h@6Cf`r5ViD7_f$lzm{%w&-VAIb*Nq@?Mkf$%51?b0~(K>z> zbfdgra-8v-yqa$l5u-d7$4|RFB3SW%$~&Ak5=tPWbK}`HF|J@oi|9n61uJp>Kxd7n zbr$=vM_F$Tb>GB|TjEmA9`(s-{#^QLm!p#KtTHM*Qq&I&|BxM3Gy)g(JzF8Wp-No! zqp)FOvi8*6jBl)P03Ibya3Iv>_|E4IV+Mlt>sZ~?x_yPLoE<~WaPvfisdZIT$V2CM z$y5`$>}nL;ILy(bEIg!l6=dnK^G99eZu{J53JM4mWu-p36M+U@+dW9=Etj2NCwhI>?6|ts<#yPX z(HLu4nyn^1Zi68sEe5+!es{ur`SK-+$PVqFOK(yQQC_^PO@+4Ks^u&DWpKl`4;%p7 zu*d$5!g}w{T*m2x@wQ|tg%nm$$*l|yMN~+LfQ7{@l#2@m6VpXnIa_lh08sK&Y%}`sAzceHN-hc{2TD^R4W=t zdb=yLxzYH%HJ7{Z+sK;Nj?Q7VOv)pfYO{jjJ#T3o;awV5n_;ko8{21c{lyI|R(D^X zad>llcN13t7S#E;yyK=2&y{8+K~f12do`Rpw*JnuSx&tTa<44gj0d`l!F#za4y&xb zHR6{OS(aTQlQ&7$yiTsXSCLP*Rp*`2BJ>+)8KoN<9^O#2C8waW`qsWYEjF00tv#Fu z$L!Aae;x?LOo>a(RLIWADc5R^@9B99g;|Ym#=3*WAiJmd%my`~i4(b*|17Wqy`oI{F`%^?i0sn7K zdR#7qZDZ|6_l-gV|J)+i&GPK|qG7EwMZd}iV{>-Zb{&mdu^CL6{@Pgz1$%qe0Q=?9 z+@M7{S;f3O8&rdUJpn|6W{%1|JlTfNNpJ^?m335Ds97vok4cZK<7eW8=XA+nn^;OM zjVG=-#UUw&8Il~aTH5WjB3%qs=A-mLAIqXvgFSvCU0YO_Hnu_k+Z27&a_7TeM?V=v565%Eq&223qtD)`>{z!cH_fKRMR3Njf zsg7%^{5uvqzsq#L0njc{)`sW#i7K>4)@k}{YB^twx1uY(;xU4)z!9z1oX5+6tku-= zwVpvsVUbdH=iS%k6&26z&WBdfZFp@hwp*gjEG$l^%c;)&{S7H3fzHY|{pHKeA=6|J zTT?Llt=YS~jcsxf%3d3`n71q<*@aBAHGoHCPOiEW2NyAsR#&9Xm6aGo{|Yrm8^LNA z%gPNX3;-bwB{4{L;>Vs&je!s?#0On#n+4)20jD>Sphnxyg@p_R)|SMe9@?p7=TBvl8IQ>p7IEdLSQL{$@Sf%x&1o9i+S2bQ-rfo? zpfEAnn3!(vo_`QCAQ6eo_0N*Bv?NivAd}4xUGe1mIW_?4I~nXx+?}XkIz2r#Tiqgb znl95Q^oXq-el*?VxpQ{;f%yE1!5p6lkvKot$os|F&zikHM*j_t-7Y6T`$F!ci(*z3 zpMydmkUsuDkdn1on9*i5j7$zr#Q1 zhu-ta$FBJZ=Yqrxlc$py`nQ-aydn6h#+{>G?{$jeTTrt<8|jJ)Z?%W->3SsoZXx{< z5F(NIqu%LV!3qJ5l?;H>_hR)&+=LOhn>SEW(s%!1XbIlWt`qWdT`d;L5akCG3_oK- zX(Px}Sog-!#zkx!G@2hNgpMQif{a)tdY=-N5}z#916U$MUDr`Xk3jPg-r^J6>qAjO z3Itrus!_Jp9>`DXmx0iuR$Auy5?AmuocaC@LYv*+qq&F%`XR1RPq~20-UJY(I|n-U zfD(4S*CclG)A`^cp)C_Fp`r-F3; zc(yaFAK1`vi5PDoRJ6Zz`*(xN(tQ7v*j7LOI5~>IUJVBI&O5gst|7y$}-~*026bTQ)OM@DU|X z`A-7wGp)w+u~>Pk)+%4ZCaA42_$7WK3H;EAnVFeH?35-?IlD+RdjE6uC9Ice&f|5I zxXM+bgcrd7_6WD*&Wh5Z zT5BkM0JEXg?~>j7ei+yx0O4dts*7`f0kde-K^eV>G;&rLfZTY5^}{`SKgna%2g@D0 z0%kiWo~W}y55;=+nwE!<7yw8}U^_XjuPRY5L#t|IM?CsNPN$e5AuYXPuD&{wF0;JA z;{~1XGBY!CJ~dgnBJ=atZ#3)G8Kr-F20hrUu4aem`96vB-~j^+$MQUyl(8tT-<}h( zt|PeGmXkk`|16%IlKK4p<;Br-a#WOJk*`4TcVtE2g?Ri156_7NG=sagSW1iJ?(U9g5ttfV1uYZe^LSrg`c&R%xjF#V5tUck z{u)`-)jT-{25q9sa)oPPmmB3t73f6 zQRL#;#l5m>_8kTun_8|5CtYdeu~HrBTw0^};BhEHh*|C8+J!^2ZMzmJHBhw{o|qU^ z{`KwTnp&FuTc|H5e@fwaawvX+Y)|}93|bWR`Hh*eFz#Py*}TLM4qa@vzM}^!v2t1C z%Kde(W+VBC#hAG6y}<>m8EY$zG7ef+DfadO;JIL5yrw8mdV{YR8J0{9Xe^hJuxrr^ zo4Qp(HuCEGwBvI9r{^;ZO{fSrRBa8Xlg1&{TH|1vwSU?PYB*-O#B<|hQ@vlCsyb`B z+?~v6tnd>cr3emgr$DsP5R?(>+Y8bKk>8=v>;>e2Fjxu^k(q@#2LLM3;%437jVp@O zdDHV2L8DOb>)Xlj-`p5W^yfesQ{bA+SII>XLsA1pMNUiA@dM=v^#wdc*?PFr6%h=U z#Dt8WX=&59v8VO$1c4ZH$!if26hOcA+?>{`i{Yr0wA0A| zheaD#SN+R5@%)_(0~N;swl={HuYE7Cm+o}r6}*Xb(a#OrfbS9JV>nstHJYO=#Xu{JJ8lHDAMOhzIw-+G6i|V@4wGox0)+KNJi$r3=Ff@piqps z(@jvHnmg|or;G9FO)@&3t0ZLVc!)W)rAbL4>OnY&02TD{8vU}?7<_`a&c{o~3K*&L zwWfUd{p}`}htDPo!$N}On+}YP@kM85riQU{;d2d-|2&%bd30>! zznqYn`fdHzt+p^qK&z+wDP=RQjAQT9Mw+wMFsJRwLm9u|&9YBQ%T(=(LH3V2^Rzfk#Iz{7$6% z+IaUn?tJ_XEfK-V%T%IEYP&zmKjgDavfgv^8{)F-tJdR*1ME*#&@U5~%$K^!7^(Pj za!TD*Zs=3I?JJ#~$SNNTgI1V3$)-(_6UR`0Dc8w!xU^jTZGXo zcBjRz$i{tGdC}s|@h$cp1_}I4_HVTMJw6}R(vQo@OfChBajb{w#J|wb>#?9KL=Jqk zk-{japQ9bi+C!eOe{aw0-mNUMlQEp}114+uEI+$&d3$${GXuB!{?OUznV~s!@NBUu zmuNY2%{G33staA#-Kv|!VU3MuKJeF*s8DW`n6N}6?hH*oU2P<35uI#gQw{SP3}>mS z%KGVHi@Q`o&Qf=?G!Hp?tfYF&he>Km*eAv8kI3g3W5YHqRoqerB-CVvkwEI zlFxOb+))YYEq@x>58zxtc}0WyF(zWmQt5=A;)@2NatU6R1d!KgH(=Y}g;8 zJ_bIobbdwOJsO{ys^a;9Kg zZ5^&Q$;8`*#;>Y21N!LkX_Wc+DFu!%#zxEh4889h%#CxaRAM zb-6#Yo{f=T)5xe(x;qS%wbdAUQ}(;ca10UYUxxfj07ndxxH$hj(8x?6Xj(^UIa%fx)7-Qy3HQdDxrHkoeY)AYT1TJ&n{tk*g1rHy zo$k#tUOx}w2uxPBto*h|ukEXjUF<@~TA5N+49U>KC7GAQjxZYTu7VB7qHwfI31n-! z8q{6%(01U(VX?)Y<6p|R`gn~`^>D1-;X=uS@n)Ow=-+sH$aFu_D|4`(gpr+>J7JqDwLH)sN zXlxA9dOXW@u!*}neIPe=6&E++OI!~Pdb#&Jgf@|0*=Qrv;balo-gbRf<~e;@;M2tF z(IDb@qO$UMg5PMrB3qWi((JCJl3&E4aI}i}H$+K)@3-~72FB+wlSI{Fs9tewgu#gkNcje%kB&DR$a!f%pA<158#6XIo_+f_ThU27M>Dm##EI^}Yl zd-aPg%-`g6Oz`5}_@~S7y+&;JRiUR~DE|ep+J2N^hHyXcp&E5~-w7rquYn!L?h?vG z7O(=|sltgfVb4=7b#go{)FqDn^0v_j^IinE+Ur#2Waf!#B@;l2ni#(N{O;gxlrW~7ub)~^yYf}YhJ4w&P2@|oL6j{|FZ>fm zj}}k%&Z@4h4%`i{LE=6CA8BtHRmZlii{b?L;1HYu!QCymyGw9_1b2529^8UkaCdii z*NMC9t+n^s`>pfZY4^|lGoj|JQA7F|UBBL|58D%|!8B*r8i32r(p_0IzVTs1#l=q8(Cs;|u+b>aIp3h} zA;ZKuoOi$unu^6{&U&KRF2IPY`(P>`!_5tv%GSMkmA~l+=?NWxO*Nmrqv(&z%*iha z2)?t{Lgj4q38Rgy)bFsNX>l0Ypz1bX&Gznse|~@h{1iXzXddx-DaL}j;g$vuaH?%q zvy;S;uCA{o>Bh$aU?1%_IW1KQ1HEC~@A|pM`_N|}Yd32Y%DKsX`^fd;OI+Qf>uhd%U8CR?hj#E;wMWwo= zchauHWEZ5-0-;5n&?bqUVE)-k?U0uj&)Q}gE!OLNqn3G>j6cI8BRev#&Mau~)T5!ATmR|5-KI)Y0CoFIKcI~V7z zS2mYQ`bO-;LV+I22bQwmFzk9z-hX~8=t%LlpqQ!MZ%b=#@+FvTtiHJYV7jN}J-B@u zxS?tN@?-EcYt7^0Esn^A|A_u9K)_VQ?p6DN(SE2z7(Ze5oGDzB!nwF$Wp@u#4vsoC z`rDYxeaDf=%l+cY64P5xiWXgM5)viiMf{BF-6_3{4BC5hznjC zA%Pv5w$^rzoh?@auZ&Q`3DiZE}(%V+v$DK(u6u5v9aDl*?hDa@`rSQHd{&nH zH+y)17o4nK!xl~iV@r-=V@Jdrv2A0}E0@vO( zu)!iWPzWfGgz1zw@I0QmO1IQ@MMpBEQW5L`rDF0ZG_tufiLj*#u+7VxrMoW6zlo^G z(A^%*n%)z`a$SJ*XB`>5)3vF>0A<)_9D@otN^)5dopXIDMF@b{FOi}8NIEXA4A9`O z9{Z#(Zw|B+=qZ_xAn4_yi>y?Eh3E&I7680k36$KHLAZKZ-Jb9>G%?ZN5*e=yQw_-X z$thEUF0@o-Vqqa;U_b#1JpomH!XldmV=6LauCp&1sJ}7jcJJ)-C(nX194J_>X&xUR zfkVG9jI@4OAHs@D{&oQ}(U8W)6eZ`uw+#pn3 zCcL=xBeI_WD9EFVE>)G7uo^$ z(j|Ls;oNvFkl?-vsT#CK*kGJl*01C~M{wR$3FEPbG> zPMyV4I{TM2Y>$my4m~!C8PJzU{~_B}tpa2Bld-3RpyQ|w^sJu}dU`}`Yqp7}64ce< zw`yJ|S{w~^HdB!uZ~Q~)^2yuE9rRuv&O0wxmEm7J;?mNj0oT^)3Z`eq{d^EtR*Bp5 z_kQf1ZGb*KJ#8>RJ%_TD3znhcVht^==|;Z>i+m4}b9X=_ZRa&b6sy(%ek#tJ3XP}R zlm1-cDnJB2-5$xg2PZW}B;~27|?7MxS%+GhfdUd5b>zW;6=eAw=2k6J;(qp1crdx=O zzL(}E>MH}Iw2``UxwM@)^Md7ad!l=FcLuqueVofkmx|ge)?0ggY9aphcByl6YIRuw za$5K*29EbMTj-NTREF{xR8~fJtn`r5Z@{x3&td|=+PUWePn z0~{OB0l2fbWwL7(3`6En;2Lp3_~+Uor&(DDw@1t z*jy!=5#A1)CLHXEyS0wIIg@XtO4Fs!7!T`Zh5U^^`s}aO8Jj=90Hn$_TAAMkfv`s* zvCU>A{rtVr%{O%$X8Dci^=O#YOH`dY8*)&Dx=2(?k2)twAOY?`Hw}o^7W@_Om61Q4 zT}5*Zpi_kRd)B}7bK4Gqc);Uu@%<6!Uzew@Xv9rC`b%&7v|EqxRw;~aYNgKFOI!pu&J&lX_-ML&^_D2M4!}+G6_wy^*3}rO!9cdq+G1%TMrzt;Lor$B| zEMC2}De*S?T=Bw_1fsrwttQp|a5-3fdiv|;sTA19N^u8?8UWW}e{V(rEUN{5H^sOE ztOF%sQd3g{TQh0E((qnvOrd`}m6pkcthHJX1e`hKv2Uooefs+#eHUiC6WYH#6~HHJ$=oZHuZh+Po7En?8d)A_YSjGasQ7Mq^_Qe=cCoDi=J>b@-5^Gg&~oXYvvkpBH~xfnl9|G$jv@0tAH2LJzl z3mq*t7>Vd!10`#0F;AZ4jG4M4wXh0JG!3ok{l&M&tnW>CrETt5Q5m{TcaP700-EltwGY=Lkaz)VoJ%dmmioXbRW^pub?yrB*QyJV0{FW=4dheY5 z+6W>eWMLH=_-QLL!Wa9-SoX{mXc6D9+#q)vj{KDuN)h{83Y$+A`E<~~C$>!z3#?42 zht!OjG`eo+w}&|e0rrjA!O>P4$s3<4z@wzC*<; zgv_UH=L=!>_C=vVJjrBh4O|C{J+a4{e4eZfK|!>uu?e@4_ou9LHHa?g|6Q6}X7L5JBA~*-?oQK~WGv(9{W1 znCci|O;%t$Y-j64=0tmbK;M@!djJ6Kuv3qAMQEk@ZxX*&Fqs>Y0ocj-zHn4rZvSR z2s42`$bqdTA6|?r|D``KeDhmUEBqoj>kHy>0Oz>GS*kO_F6_=}$JjyXU5#=ljGQKD7 zx|r8Bi6y2Szf2b2@9Yz4v|!i>ku8Zd5+ie#UI{64#_OanMo}XW{SBTMyR85h6)zR9 z%uE;X$&9Cxullh?N-3KuvDU2jby@W5*Bam&NR*RJW6$x3p`xW;_6aK^8^vpjQ}D#? zaO8a(7Uyb=o^+zstm8<<%!2?$=V|b&bTy+SRh%OZ3+K=6ESWR=|eZ;d#K0n7DVhfs)y>H#8i%r?%*dG?SOLS6zXFIwFT{yht+=zs9g>+39wMvNY=1(lHU#Us_y#TNASF;!fcs;@omq*GRiv9I{1vdXr=L?+|IW z{)d<}m49t2A7ctK1Xc5{zqt#&!H&o|JAA=uuy1VpuleAX+s)I3sIpbmURZ6X1I6u= z{jZg={Fv_)Z#)_g(=Ayj5$p`6qk3%ZB9y4V8bT6za>EvI1rNh*V-yjS=MIENWGe*gZxs{S0lJ^*+DfDk0n6Q}&0D|&$5`{Y0qaYNjpw7_#Zun(Ag)**m>@Zpo> z4Xoh@vs3YiB?4QhAiR5Se$JInwsPcC)z18F;TbA@F$8M7d!rWxftkChEP69?=mo*g zmsQ2Z=0bAm|2fuRG)|;z0i9f>AL#0${GWRE{}?W=-J7T0nb^;?_wg63B&a&lwhncN z#7e7SopKnUk3hh4;7zn{H)9AV6e+enA$nLqfyhWDBpPL;l+Y)j_(u{fW`IbFS=VZl z)yt(gVC{)za64)IF=pyGUmv^5mj-vu6%hyXMuY=mZy}EkAT*~p-i1p2ft8iC7_*67 z!#uHj0)$U1=DQL3(vKF(ABH3)U1uxCma{(*WDq=B?1;5%TtZ(a({Cx3ewGT!ej*C z1w0uojwYu^b3krih+dlqi|4`h*X0gAJ5swUY|RckNGjnNmfgd`l&7;6tM^-VB_*Z7 z@%FA-T$Y2CO8u1R=gJN%5Y#-`?}N*^Eo41uhU=#XuN zI!n#Mb-p#J0tW5oNDKfPbnbKQ>mL!zZo8g7Wh5?*-WK_-9tw+mYV9S3-3y4Q@!%O_ zy>p%(mX|I4$(oF?Fs3EAv=I22tZyFB0(~HFYoa-5NJ?Lr!+|4oDzxH@jXSdj35|;J zLKM$&d_nw#SQ4+jM4V6g<4naJE0y$88+0us(ba$y=|gXHk(GVKnaP$HN$2f^`y8bg zsl%M8=hBZL3ggo|Y7I?0wZq}lyE&%db3kBv>l`?%Fz?k8v}U$5xldzfyBKT8fYMb- z^TQsg2Xrbv=S2;^6td(=hdhBM{Y!@2PUvru*ZW%B z8|FyT+tHODVKdlF?kqa z*imgDs%(E@?s%(@z_YPgR4En~b>+lZcaPA@tQ#B~G8x_-8cpGfsM~;Db0|wCBBIl5 z{7LNd;J0+WKb>tz7Kai4r%tuX<(_CggFDJZ-#bh{;$s;K{Pr!A(W1)*s`H)m*So#8 z;+c!POT)R;Ib#!Ds?SV7ZY+L{(LK?Nr`MzTJlzw@K}`2>s!T?-&;+9CQ{?@hs^adF zM15xKtCgFxnTB4k)+`M?j?29$4k}EKQEOG_J{tjtCq#M2(|(SPioT(xu!C#Gd(St( zFWKb%%Kg0qrF*$QxHx`e-zRI7m7@LJY4yCY17HPc)BRc9L#@HiY*|Rl8 zLgM6;L9eOu8CVN3JY zA`Sf(R=i2U-7{I8cNH2ote*R)sy7!ICOn^_Zke?8$A?iqEXJA#iGmfhxX&)d3lh?vtbS@4@ep! z2c-Vq6r%Z`{@N2Fa|OEE>FF6@=BvNqzz)@?t7>W}fT|6X9U{fLE$sYAc)y5@jEsglFChUb$Gil~+1;)=98_{YbgM6BMOLbk1(dq+-Ov6Z=M2PjOpOb&&<>{K z#+@^eKq(d#Wu-^Csw$?@mkYA-Os;^8a>6AsqhhvpgqTF9SMKFVM9ap7#!_9SZ=_62 z*axfa0TyW)ZG@^Ns~M4cf6UPk_Qy>oef?%DbkhJ{AK(L$>x<3;8fJMupgrH8_N;b8 z%#FPQu`vdw{pYZ~Fp1F{qbU78>8r4x1iMWr9qS0P5}aE$`T24$Ud1=#0)Glu);N!57AM$pcd^E3|wN2SauaeWEL_iQRk^3DDIJB5Mp@Nm-fc+v4y!v-%!F z{6@g0|2DlFR?YmHsdIVjY`oUT+U>ID&@L zk2+?PU72=s@Y+y?qlY!R{2Xhw&zvWFKkqEzX9b<6MBx<`OA0mL#0}H}l&dDMSO-7@ zQli%hUk(wf^cl@AwIhJj9Lvq{&;*co)_OOe8z%oYFok(_;v}$zRYC_ZegI*j&OEg* zC$p9bQWPKep`D6P=b%fqb1fo<45!hUIyf^Lr_?+gbLK_wN zRh0};p7^oe6d8Ewc%Ll)g9SJ{L6G4lJP zFa{2|@=2>PfWfpsp=}_Q8{_4bUQGG4xG<0scX$o@^3&KIclMm)C;Nb!J-IgnaXW6f znJx-JS)@)&ZcolLIi-tIt`b-?c_0EcIyWwSZegV|Ic03hYwILahKk>)m*;&u~7K?z8 z(CsR$BGUbmLRt1sJA7r}IV_)d_WEu=XshSZY6u+y7HNMlE97u}XDEbOO%o`IbFrsh zIyf?x?~~OogTsT&<0M4riZF7;b*`<2-u4N`p}(C!x?o;%f8>X{xfaTsM0*2$rpE=pZn67sLzQg(*NJzq3XHe=e;D=~= z5=zRKzQz-S8fys^gwnG?)RSFcsT6%`Y&0lW|BfpsmFXWB(Lz0G{^{)joZSl1P@8l1 zoHgMR{QX4q*Wbo@sQAd}(o)l+aQ)B_iqm5<>NW|t6Fott7Lmqh%zGOh7`5|Lp=Y}Z z`$Or_XS7ytJ_ob0{l((=d#h46+W|h1g{UhO0=B1Ao*2@(R4#T>TH3($1V3mrrA8+G zMy>dEn(h4b)ALTnedM{fd8OW0BXy~$1XxtgZ>;$3+Nu>^;lm~u*JPUaV^`tGB7bw! zx5VGI5rBa$wR6wsVdreuKQ$D)h*0I(WCaZgi$c@z*5=ika&t$1G+V6v4V}=YQYI!U ztV>#|F7iRqqPM@7@wz8QLZ(%QOZj>VI zFK_U_8~#fK+ACG6S82X3Vm(*-l)G9O-jnn>f3rTMtCEIk+19lwV;dVz69osbV ze4`SXt_lqB@ptz`nQ;icf4Oo0W2plF{r^3k7XS8iiYH>_z%>Ii50#=~6$;54F3Iho z#_;gq$))cF+_KvwVa=!!ZC;N_km!Fu%q~sGO67x{e2s@I)9#AG^v%*=ZqNMb)`p$f zXi!o0H)oVeaqj&9cu&($HTw*dEZ3G_Lr94rfM-Hv;c847{yoUvjwIkgp*}fR?TbbK z80ou-((>2;uH#>wQV0Fl{rB%Ngepk@-sykN@2^{kMQx}f#G{Ru<#fM_U!mf1T`ifz zOf1E;|JM`wuO^}J#+p;$s}Yy>)cC^AKX$DMh87|X%KO_6!6;*H2byvNob=JXqN|5!1=k1Ulg zu~79K@kT_UA|6LDm^}1Bx8}Vn>Pip#P`$#AQUk3K<$ZoT^iQJx<~ouSe!>uT^{^Tj ze26S!{|=8TKS4|C<8~y&`z6uZqD!mw7$ydnu9`;CCX$4`^YZ-|RMM7AGirWBnpiz50+*r6_AKC=`G4jfO&oQHN8bwu+i%zRgGQV@CgJKU7#N)rX8- z@z-ejlHeMEo*eA$YKkM|)WQJZS;}-8LMAy0sdX<;xe_iRJ>fY%Cq|{g3dySljljt) z6OK$GsdC;|!_JL7JSe4T&vcGu-npqxN}&I9w^ive}H8ycn z#{*fmTncD+lJ zX@82cS4Wt5n5S(k@ZJ6@yDsK>{aeFPSOg6=GemIq9JNf^Y zg(I3A9@OjD0V&w%x}KX-0%GIoQrT2R%Tb17C3|IQ2QlzuhR6Fg4?q1Y^347m&EQ5_ zd^dic?kkI8PVy|H4@5Im*jZ>cM}MvNxGxo`PHpO%YDCHG-G*lQH9Hn{(*2y;8sCTD zVqne_yr)lR_IT{Avr-*bmy_S?M3op`fu!TwEKQi{0CsBf#q9cO5wjMdCMBn}Wse$3 z;4LE-1m?w!;Q#h}Jd#kw?cQa%G6E><j4ZrZ=`iIqD; ze?p()Gs-56hjZZe{Uv>g%*xjc6SGA}=;(7!-=&1LNZw>vW9I7_!e3sl{<2GgS8gu_ zr`h8LD%Hd7>i=L*p*~H+X%ZX>?km3d!x? z4Zqpjve#66z22{YhBFPKU7y3kxpl7w4^j%-wj^arMlvYuUt57h5*#&j9w@yeW`+`Q zVZ*~Fc1Jpv^jb4?&Z48VBdE!G9jds&+m0#BfC!2wUen@^L&J)y4?MtPhyMdc2Ow54 zsWE+-()nPgFHX1uefulSOPaUuXHng`D6R(D(c`XsFH1i1NvYgXur;c8G(?-|i#cC) zYXVHfLY#Z9JtHYb!2Z_{CvgZ5x11`)Y>UN2xjIBqQHmr+bEd0Lv{We8o-{s3onpGs z3)(CfmM|U_%gnWHu<|@WW%vD^R($oKLx$R&NftTdps$RdXVY`M@mRUE?$Rgxc)xUH zPIUFJMS)hskrN#sFaz#z%{LmLL-Z~Sbj5g$TqtL0Y95^xK;hG)qenW87o;3Xm zxywy*aGSrmELYRRa`_)z3nH6I<+tOJ{=*);CJ3r^SoU0xTVpvBAVV3no$((ychM<)=szf1=BRKKRw-{@zyh zgviW%2LHW zLg`5kb2D&GKeo7zRgg0#$Y*~_Ch0n5-j%h2lK;7&F?xHlziHddb;P@tJ4C{KN*K;Q zy09zcO;HcZE#!jKKHHLgR(H&=aU#QQDA;3g`~dJC~*CJRIkVf|5!1>#!hcfdEoT$g`{orZhx6-SIZH z{(Mmv7vnB!oue*!y1El@*J<(k`Qs1d(Zgo>qWnSCk4U75&*%1)-io=^JJCj(2}*fl zTf03sOClGo$4%7u`1i|JNI$x|l>7>7;G-x6^@dLQS{GSrgAbc(i@zZy&9|-&rk<0< zJxXOrMmn+aTUa7}ML*=wR5dzm6mx9j8nLFsG9Mkooy~@4d6zOfY(ga9#b+6(jIY4n zepvq%P}sn7N_$@Vk7NHq5uE07T3g&5<V$wzfFN9N4#YK?iQ}Q5Bc+0 z`-a?C9?>`_5nj(sTHoj7?y@2&DJfG2<8w~j|JaMp4YUKXNU zh@YG?v!8ug*-r8Hts}|l{f$3)JRJ&fe&$F1%xN0ci|fhB)l)U}HmH4M$8u{)H67k8 z0%_36o(yt^w6VMtk%8R8JU#0q)%B1eUn&gSf%0AjviW(wP`p>rV+%T$BUk(+!Vr`$ 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%0AU30>dd@9G-`%d+ozM9MfrIRN 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 Bcvk=b literal 0 HcmV?d00001 diff --git a/docs/how-to/h-deploy-ec2.md b/docs/how-to/deploy/aws-ec2.md similarity index 85% rename from docs/how-to/h-deploy-ec2.md rename to docs/how-to/deploy/aws-ec2.md index 5eb0b9d975..24b88082ed 100644 --- a/docs/how-to/h-deploy-ec2.md +++ b/docs/how-to/deploy/aws-ec2.md @@ -2,38 +2,30 @@ [Amazon Web Services](https://aws.amazon.com/) is a popular subsidiary of Amazon that provides on-demand cloud computing platforms on a metered pay-as-you-go basis. Access the AWS web console at [console.aws.amazon.com](https://console.aws.amazon.com/). -## Summary -* [Install AWS and Juju tooling](#install-aws-and-juju-tooling) - * [Authenticate](#authenticate) -* [Bootstrap Juju controller on AWS EC2](#bootstrap-juju-controller-on-aws-ec2) -* [Deploy charms](#deploy-charms) -* [Expose database (optional)](#expose-database-optional) -* [Clean up](#clean-up) +## Prerequisites ---- +This guide assumes you have: -## Install AWS and Juju tooling +* A physical or virtual machine running Ubuntu 22.04+ +* Juju 3 (`3.6+` is recommended) + * See: [How to install Juju](https://documentation.ubuntu.com/juju/3.6/howto/manage-juju/#install-juju) -Install Juju via snap: -```shell -sudo snap install juju -``` - -Follow the installation guides for: -* [AWs CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) - the Amazon Web Services CLI +## Install AWS tooling -To check they are all correctly installed, you can run the commands demonstrated below with sample outputs: +Follow the installation guide for the [Amazon Web Services CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html). -```console -~$ juju version -3.5.4-genericlinux-amd64 +To check it is correctly installed, you can run the commands demonstrated below with sample outputs: +```text ~$ aws --version aws-cli/2.13.25 Python/3.11.5 Linux/6.2.0-33-generic exe/x86_64.ubuntu.23 prompt/off ``` + ### Authenticate + [Create an IAM account](https://docs.aws.amazon.com/eks/latest/userguide/getting-started-console.html) (or use legacy access keys) to operate AWS EC2: -```shell + +```text mkdir -p ~/.aws && cat <<- EOF > ~/.aws/credentials.yaml credentials: aws: @@ -45,7 +37,7 @@ EOF ``` -[Tutorial]: /t/9707 - -[How to deploy using Terraform]: /t/14916 - -[Sunbeam]: /t/15972 -[Canonical MAAS]: /t/14293 -[Amazon Web Services EC2]: /t/15703 -[Google Cloud Engine]: /t/15722 -[Azure]: /t/15733 -[How to deploy on multiple availability zones (AZ)]: /t/15749 - -[How to deploy for external TLS VIP access]: /t/16576 -[How to enable TLS]: /t/9685 -[How to connect from outside the local network]: /t/15802 -[How to deploy on juju spaces]: /t/17416 - -[How to deploy in an offline or air-gapped environment]: /t/15746 -[Cross-regional async replication]: /t/15412 -[How to deploy on juju storage]: /t/17529 \ No newline at end of file +[Tutorial]: /tutorial/index + +[How to deploy using Terraform]: /how-to/deploy/terraform + +[Sunbeam]: /how-to/deploy/sunbeam +[Canonical MAAS]: /how-to/deploy/maas +[Amazon Web Services EC2]: /how-to/deploy/aws-ec2 +[Google Cloud Engine]: /how-to/deploy/gce +[Azure]: /how-to/deploy/azure +[How to deploy on multiple availability zones (AZ)]: /how-to/deploy/multi-az + +[How to deploy for external TLS VIP access]: /how-to/deploy/tls-vip-access +[How to enable TLS]: /how-to/enable-tls +[How to connect from outside the local network]: /how-to/external-network-access +[How to deploy on juju spaces]: /how-to/deploy/juju-spaces + +[How to deploy in an offline or air-gapped environment]: /how-to/deploy/air-gapped +[Cross-regional async replication]: /how-to/cross-regional-async-replication/index +[How to deploy on juju storage]: /how-to/deploy/juju-storage + + +```{toctree} +:titlesonly: +:maxdepth: 2 +:glob: +:hidden: + +Sunbeam +MAAS +AWS EC2 +GCE +Azure +Multi-AZ +TLS VIP access +Terraform +Air-gapped +Juju storage \ No newline at end of file diff --git a/docs/how-to/deploy/juju-storage.md b/docs/how-to/deploy/juju-storage.md new file mode 100644 index 0000000000..7aa178ccb8 --- /dev/null +++ b/docs/how-to/deploy/juju-storage.md @@ -0,0 +1,116 @@ +# Deploy on Juju storage + +Charmed PostgreSQL uses the [Juju storage](https://documentation.ubuntu.com/juju/3.6/reference/storage/) abstraction to utilize data volume provided by different [clouds](https://documentation.ubuntu.com/juju/3.6/reference/cloud/#cloud) while keeping the same UI/UX for end users. + +Charmed PostgreSQL 14 supports a single storage: `pgdata`. + +The [legacy PostgreSQL charm](/explanation/legacy-charm) in track [`latest/`](https://charmhub.io/postgresql?channel=latest/stable)" does **not** support the Juju storage abstraction. + +## Check storage details + +Check the [metadata.yaml](https://github.com/canonical/postgresql-operator/blob/main/metadata.yaml) for find Juju storage name and tech details: + +```text +storage: + pgdata: + type: filesystem + location: /var/snap/charmed-postgresql/common +``` + +Charmed PostgreSQL 14 supports single storage `pgdata` attaching it on `juju deploy` and mounted inside the Snap common folder `/var/snap/charmed-postgresql/common`. + +
Example of 'Juju storage' + +```text +> juju deploy postgresql --channel 14/stable + +> juju storage +Unit Storage ID Type Size Status Message +postgresql/0 pgdata/0 filesystem pending + +> juju storage +Unit Storage ID Type Pool Size Status Message +postgresql/0 pgdata/0 filesystem rootfs 97 GiB attached + +> juju show-storage pgdata/0 +pgdata/0: + kind: filesystem + life: alive + status: + current: attached + since: 01 May 2025 18:47:04+02:00 + persistent: false + attachments: + units: + postgresql/0: + machine: "0" + location: /var/snap/charmed-postgresql/common + life: alive + +> juju ssh postgresql/0 mount | grep /var/snap/charmed-postgresql/common +/dev/sda1 on /var/snap/charmed-postgresql/common type ext4 (rw,relatime,discard,errors=remount-ro) +``` +
+ +## Deployment examples + +### Define the storage size + +```text +> juju deploy postgresql --channel 14/stable --storage pgdata=10G + +> juju storage +Unit Storage ID Type Pool Size Status Message +postgresql/1 pgdata/1 filesystem lxd 10 GiB attached +``` + +### Define the storage location + +Juju supports wide list of different [storage pools](https://bobcares.com/blog/lxd-create-storage-pool/): + +```text +> juju create-storage-pool mystoragepool lxd + +> juju storage-pools | grep mystoragepool +mystoragepool lxd + +> juju deploy postgresql --channel 14/stable --storage pgdata=5G,mystoragepool + +> juju storage +Unit Storage ID Type Pool Size Status Message +postgresql/2 pgdata/2 filesystem mystoragepool 5 GiB attached +``` + +### Re-deploy detached storage (track `14`) + +To re-deploy the application with the old Juju storage, it is necessary to provide all charm/database credentials to the new charm or app. + +Charmed PostgreSQL 14 uses the Juju action `set-password` to handle credentials: + +```text +# Note old passwords +> juju show-secret --reveal database-peers.postgresql.app + +# Find old storage id: +> juju storage + +# Re-deploy new app one unit only to set old passwords +> juju deploy postgresql --channel 14/stable -n 1 + +# Once deployed, set old passwords from old app Juju App secrets +juju run postgresql/leader set-password username=operator password=cpUJnNRJ6Qt2Hgli +juju run postgresql/leader set-password username=patroni password=0N7pKAutKCstPuvx +juju run postgresql/leader set-password username=raft password=8xSZvTLfyHpglGfI +juju run postgresql/leader set-password username=replication password=5xN9gj9uu5Um3PWB +juju run postgresql/leader set-password username=rewind password=wuEsPmsdpc6L8qhT +juju run postgresql/leader set-password username=monitoring password=AgOxXzcRD5iohE6C + +# Scale down to zero units byt removing all Juju units +> juju remove-unit postgresql/1 --destroy-storage=yes + +# Scale up to one unit and attach the old Juju storage +> juju add-unit postgresql --attach-storage pgdata/x + +# If no issues noticed, scale to HA (3 units total) +> juju add-unit postgresql -n 2 +``` diff --git a/docs/how-to/deploy/maas-create-tag.png b/docs/how-to/deploy/maas-create-tag.png new file mode 100644 index 0000000000000000000000000000000000000000..6f75cbd38a400144d2009ab1e8c5e3be0955ef5b GIT binary patch literal 95441 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 b)yc&rXotMv@G=Gkc?{tr(ykl9319pU$~jl# literal 0 HcmV?d00001 diff --git a/docs/how-to/deploy/maas-dhcp-banner.png b/docs/how-to/deploy/maas-dhcp-banner.png new file mode 100644 index 0000000000000000000000000000000000000000..b4538acfb080402c52cc7f31c1fa5c00ef16e7c6 GIT binary patch literal 33261 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

Bootstrap a Multipass VM

+## Bootstrap a Multipass VM Install Multipass and launch a VM: -```shell +```text sudo snap install multipass wget -qO- https://raw.githubusercontent.com/canonical/maas-multipass/main/maas.yml \ @@ -28,10 +17,10 @@ wget -qO- https://raw.githubusercontent.com/canonical/maas-multipass/main/maas.y ``` > The wget command provides a [cloud-init](https://github.com/canonical/maas-multipass/blob/main/maas.yml) file that will set up the VM's LXD and MAAS environment. -

Configure MAAS

+## Configure MAAS **1.** Find your MAAS IP with -```shell +```text multipass list ``` @@ -43,47 +32,47 @@ multipass list
4. Wait for image downloads to complete on http://:5240/MAAS/r/images -[![Screenshot from 2024-04-12 12-48-40](upload://kyNPhsHr7GHyFouEpp7sxPytb6g.png)](https://assets.ubuntu.com/v1/901aa34b-image_downloads.png) +![MAAS image downloads](maas-image-downloads.png)

-[note] +```{note} Make sure you are downloading 22.04 images as well (20.04 is the current default). -[/note] +``` The LXD machine will be up and running after the images downloading and sync is completed.
5. Navigate to http://:5240/MAAS/r/tags and create a tag with tag-name=juju. Assign it to the LXD machine. -[![Screenshot from 2024-04-12 12-51-30](upload://44dY32yFYSybmvypdEgDtj0lFid.png)](https://assets.ubuntu.com/v1/1c82f803-tags.png) +![MAAS interface - create tag](maas-create-tag.png)
-> **A note on DHCP** -> -> MAAS uses DHCP to boot and install new machines. You must enable DHCP manually if you see this banner on MAAS pages: -![image|690x46](upload://g458TLPPqGIISCFHKdfUwXRepeZ.png) -> -> **Make sure to enable DHCP service inside the MAAS VM only.** -> - >Use the internal VM network `fabric-1` on `10.10.10.0/24` and choose a range (e.g. `10.10.10.100-10.10.10.120`). Check the [official MAAS manual](https://maas.io/docs/enabling-dhcp) for more information about enabling DHCP. +```{note} +**A note on DHCP** +MAAS uses DHCP to boot and install new machines. You must enable DHCP manually if you see this banner on MAAS pages: +![DHCP banner|690x46](maas-dhcp-banner.png) + +**Make sure to enable DHCP service inside the MAAS VM only.** +Use the internal VM network `fabric-1` on `10.10.10.0/24` and choose a range (e.g. `10.10.10.100-10.10.10.120`). Check the [official MAAS manual](https://maas.io/docs/enabling-dhcp) for more information about enabling DHCP. +``` **6.** Finally, dump MAAS admin user API key to add as Juju credentials later: -```shell +```text multipass exec maas -- sudo maas apikey --username admin ``` -

Register MAAS with Juju

+## Register MAAS with Juju **1.** Enter the Multipass shell and install juju: -```shell +```text multipass shell maas sudo snap install juju ``` **2.** Add MAAS cloud and credentials into juju. These commands are interactive, so the following code block shows the commands followed by a sample output. **Make sure to enter your own information when prompted by juju.** -```shell +```text juju add-cloud > Since Juju 2 is being run for the first time, downloading latest cloud information. Fetching latest public cloud list... Your list of public clouds is up to date, see `juju clouds`. Cloud Types @@ -98,7 +87,7 @@ juju add-cloud > Enter the API endpoint url: http://:5240/MAAS > Cloud "maas-cloud" ``` -```shell +```text juju add-credential maas-cloud > ... @@ -116,18 +105,18 @@ juju add-credential maas-cloud **3.** Bootstrap Juju. Add the flags `--credential` if you registered several MAAS credentials, and `--debug` if you want to see bootstrap details: -```shell +```text juju bootstrap --constraints tags=juju maas-cloud maas-controller ``` -# Deploy Charmed PostgreSQL on MAAS -```shell +## Deploy Charmed PostgreSQL on MAAS +```text juju add-model postgresql maas-cloud juju deploy postgresql --channel 14/stable ``` Sample `juju status` output: -```shell +```text Model Controller Cloud/Region Version SLA Timestamp postgresql maas-controller maas-cloud/default 3.1.8 unsupported 12:50:26+02:00 @@ -141,28 +130,30 @@ Machine State Address Inst id Base AZ Message 0 started 10.10.10.5 wanted-dassie ubuntu@22.04 default Deployed ``` -# Test your Charmed PostgreSQL deployment +## Test your Charmed PostgreSQL deployment -Check the [Testing](/t/11773) reference to test your deployment. +Check the [Testing](/reference/software-testing) reference to test your deployment. + +## Clean up the environment -

Clean up the environment

To stop your VM, run: -```shell +```text multipass stop maas ``` If you're done with testing and would like to free up resources on your machine, you can remove the VM entirely. -[note type="caution"] -**Warning**: When you remove the VM as shown below, **you will lose all the data** in PostgreSQL and any other applications inside it! +```{warning} +When you remove the VM as shown below, **you will lose all the data** in PostgreSQL and any other applications inside it! For more information, see the docs for [`multipass delete`](https://multipass.run/docs/delete-command). -[/note] +``` To completely delete your VM and all its data, run: -```shell + +```text multipass delete --purge maas ``` -[note] -If you expect having several concurrent connections frequently, it is highly recommended to deploy [PgBouncer](https://charmhub.io/pgbouncer?channel=1/stable) alongside PostgreSQL. For more information, read our explanation about [Connection pooling](/t/15777). -[/note] \ No newline at end of file +If you expect having several concurrent connections frequently, it is highly recommended to deploy [PgBouncer](https://charmhub.io/pgbouncer?channel=1/stable) alongside PostgreSQL. For more information, read our explanation about [Connection pooling](/explanation/connection-pooling). + + diff --git a/docs/how-to/h-deploy-multi-az.md b/docs/how-to/deploy/multi-az.md similarity index 83% rename from docs/how-to/h-deploy-multi-az.md rename to docs/how-to/deploy/multi-az.md index 5cb4ffeda2..c25b050bef 100644 --- a/docs/how-to/h-deploy-multi-az.md +++ b/docs/how-to/deploy/multi-az.md @@ -6,29 +6,27 @@ or even better, to the different [availability zones](https://en.wikipedia.org/w This guide will take you through deploying a PostgreSQL cluster on GCE using 3 available zones. All Juju units will be set up to sit in their dedicated zones only, which effectively guarantees database copy survival across all available AZs. -[note] -This documentation assumes that your cloud supports and provides availability zones concepts. This is enabled by default on EC2/GCE and supported by LXD/MicroCloud. +## Prerequisites -See the [Additional resources](#additional-resources) section for more details about AZ on specific clouds. -[/note] +* A physical or virtual machine running Ubuntu 22.04+ +* Juju 3 (`3.6+` is recommended) + * See: [How to install Juju](https://documentation.ubuntu.com/juju/3.6/howto/manage-juju/#install-juju) +* A cloud service that supports and provides availability zones. -## Summary -* [Set up GCE on Google Cloud](#set-up-gce-on-google-cloud) -* [Deploy PostgreSQL with Juju zones constraints](#deploy-postgresql-with-juju-zones-constraints) - * [Simulation: A node gets drained](#simulation-a-node-gets-drained) -* [Additional resources](#additional-resources) ---- +```{note} +Multi-availability zones are enabled by default on EC2/GCE and supported by LXD and MicroCloud. +``` ## Set up GCE on Google Cloud -Let's deploy the [PostgreSQL Cluster on GKE (us-east4)](/t/11237) using all 3 zones there (`us-east4-a`, `us-east4-b`, `us-east4-c`) and make sure all pods always sits in the dedicated zones only. +Let's deploy a [PostgreSQL cluster on GKE (us-east4)](https://discourse.charmhub.io/t/charmed-postgresql-k8s-how-to-deploy-on-gke/11237) using all 3 zones there (`us-east4-a`, `us-east4-b`, `us-east4-c`) and make sure all pods always sits in the dedicated zones only. -[note type="caution"] -**Warning**: Creating the following GKE resources may cost you money - be sure to monitor your GCloud costs. -[/note] +```{caution} +Creating the following GKE resources may cost you money - be sure to monitor your GCloud costs. +``` -Log into Google Cloud and [bootstrap GCE on Google Cloud](/t/15722): -```shell +Log into Google Cloud and [bootstrap GCE on Google Cloud](/how-to/deploy/gce): +```text gcloud auth login gcloud iam service-accounts keys create sa-private-key.json --iam-account=juju-gce-account@[your-gcloud-project-12345].iam.gserviceaccount.com sudo mv sa-private-key.json /var/snap/juju/common/sa-private-key.json @@ -41,17 +39,18 @@ juju add-model mymodel ## Deploy PostgreSQL with Juju zones constraints -Juju provides the support for availability zones using **constraints**. Read more about zones in [Juju documentation](https://juju.is/docs/juju/constraint#heading--zones). +Juju provides support for availability zones using [**constraints**](https://juju.is/docs/juju/constraint#zones). -The command below demonstrates how Juju automatically deploys Charmed PostgreSQL VM using [Juju constraints](https://juju.is/docs/juju/constraint#heading--zones): +The command below demonstrates how Juju automatically deploys Charmed PostgreSQL VM using Juju constraints: -```shell -juju deploy postgresql -n 3 \ +```text +juju deploy postgresql --channel 14/stable -n 3 \ --constraints zones=us-east1-b,us-east1-c,us-east1-d ``` After a successful deployment, `juju status` will show an active application: -```shell + +```text Model Controller Cloud/Region Version SLA Timestamp mymodel gce google/us-east1 3.5.4 unsupported 00:16:52+02:00 @@ -70,7 +69,8 @@ Machine State Address Inst id Base AZ Messag ``` and each unit/vm will sit in the separate AZ out of the box: -```shell + +```text > gcloud compute instances list NAME ZONE MACHINE_TYPE PREEMPTIBLE INTERNAL_IP EXTERNAL_IP STATUS juju-a82dd9-0 us-east1-b n1-highcpu-4 10.142.0.30 34.23.252.144 RUNNING # Juju Controller @@ -80,8 +80,10 @@ juju-e7c0db-0 us-east1-d n2-highcpu-2 10.142.0.31 34.148.44.51 ``` ### Simulation: A node gets lost + Let's destroy a GCE node and recreate it using the same AZ: -```shell + +```text > gcloud compute instances delete juju-e7c0db-1 No zone specified. Using zone [us-east1-c] for instance: [juju-e7c0db-1]. The following instances will be deleted. Any attached disks configured to be auto-deleted will be deleted unless they are attached to any other instances or the `--keep-disks` flag is given and specifies them for keeping. Deleting a disk is @@ -93,7 +95,7 @@ Do you want to continue (Y/n)? Y Deleted [https://www.googleapis.com/compute/v1/projects/data-platform-testing-354909/zones/us-east1-c/instances/juju-e7c0db-1]. ``` -```shell +```text Model Controller Cloud/Region Version SLA Timestamp mymodel gce google/us-east1 3.5.4 unsupported 00:25:14+02:00 @@ -112,7 +114,8 @@ Machine State Address Inst id Base AZ Messag ``` Here we should remove the no-longer available `server/vm/GCE` node and add a new one. Juju will create it in the same AZ `us-east4-c`: -```shell + +```text > juju remove-unit postgresql/1 --force --no-wait WARNING This command will perform the following actions: will remove unit postgresql/1 @@ -121,7 +124,7 @@ Continue [y/N]? y ``` The command `juju status` shows the machines in a healthy state, but PostgreSQL HA recovery is necessary: -```shell +```text Model Controller Cloud/Region Version SLA Timestamp mymodel gce google/us-east1 3.5.4 unsupported 00:30:09+02:00 @@ -138,12 +141,12 @@ Machine State Address Inst id Base AZ Messag ``` Request Juju to add a new unit in the proper AZ: -```shell +```text juju add-unit postgresql -n 1 ``` Juju uses the right AZ where the node is missing. Run `juju status`: -```shell +```text Model Controller Cloud/Region Version SLA Timestamp mymodel gce google/us-east1 3.5.4 unsupported 00:30:42+02:00 @@ -163,12 +166,12 @@ Machine State Address Inst id Base AZ Messag ## Remove GCE setup -[note type="caution"] -**Warning**: Do not forget to remove your test setup - it can be costly! -[/note] +```{caution} +Do not forget to remove your test setup - it can be costly! +``` Check the list of currently running GCE instances: -```shell +```text > gcloud compute instances list NAME ZONE MACHINE_TYPE PREEMPTIBLE INTERNAL_IP EXTERNAL_IP STATUS juju-a82dd9-0 us-east1-b n1-highcpu-4 10.142.0.30 34.23.252.144 RUNNING @@ -178,11 +181,12 @@ juju-e7c0db-0 us-east1-d n2-highcpu-2 10.142.0.31 34.148.44.51 ``` Request Juju to clean all GCE resources: -```shell +```text juju destroy-controller gce --no-prompt --force --destroy-all-models ``` Re-check that there are no running GCE instances left (it should be empty): -```shell +```text gcloud compute instances list -``` \ No newline at end of file +``` + diff --git a/docs/how-to/deploy/sunbeam-dashboard.png b/docs/how-to/deploy/sunbeam-dashboard.png new file mode 100644 index 0000000000000000000000000000000000000000..9087cb1b47fb97f354901d50fb09f57d882b69a8 GIT binary patch literal 162227 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�-KbfGj+!45u6~u`bl(q^_^F($x=^dC7Ao3pIffj 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 To learn more about deploying and operating PostgreSQL, see the [Charmed PostgreSQL tutorial][Tutorial]. -[Tutorial]: /t/9707 +[Tutorial]: /tutorial/index [Single-node guided]: https://microstack.run/docs/single-node-guided [Accessing the OpenStack dashboard]: https://microstack.run/docs/dashboard [Images Sync]: https://microstack.run/docs/images -[Manage workloads with Juju]: https://microstack.run/docs/juju-workloads \ No newline at end of file +[Manage workloads with Juju]: https://microstack.run/docs/juju-workloads + diff --git a/docs/how-to/h-deploy-terraform.md b/docs/how-to/deploy/terraform.md similarity index 85% rename from docs/how-to/h-deploy-terraform.md rename to docs/how-to/deploy/terraform.md index 5384f21488..c3ba64c849 100644 --- a/docs/how-to/h-deploy-terraform.md +++ b/docs/how-to/deploy/terraform.md @@ -6,39 +6,36 @@ The easiest way is to start from [these examples of terraform modules](https://g For an in-depth introduction to the Juju Terraform Provider, read [this Discourse post](https://discourse.charmhub.io/t/6939). -[note] -**Note**: Storage support was added in [Juju Terraform Provider version 0.13+](https://github.com/juju/terraform-provider-juju/releases/tag/v0.13.0). -[/note] - -## Summary -* [Install Terraform tooling](#install-terraform-tooling) -* [Verify the deployment](#verify-the-deployment) -* [Apply the deployment](#apply-the-deployment) -* [Check deployment status](#check-deployment-status) -* [Clean up](#clean-up) ---- +```{note} +Storage support was added in [Juju Terraform Provider version 0.13+](https://github.com/juju/terraform-provider-juju/releases/tag/v0.13.0). +``` ## Install Terraform tooling -This guide assumes Juju is installed and you have an LXD controller already bootstrapped. For more information, check the [Set up the environment](/t/9709) tutorial page. +This guide assumes Juju is installed and you have an LXD controller already bootstrapped. For more information, check the [](/tutorial/index). First, install Terraform Provider and example modules: -```shell + +```text sudo snap install terraform --classic ``` + Switch to the LXD provider and create a new model: -```shell + +```text juju switch lxd juju add-model my-model ``` + Clone examples and navigate to the PostgreSQL machine module: -```shell + +```text git clone https://github.com/canonical/terraform-modules.git cd terraform-modules/modules/machine/postgresql ``` Initialise the Juju Terraform Provider: -```shell +```text terraform init ``` @@ -67,7 +64,7 @@ resource "juju_application" "machine_postgresql" { Run `terraform plan` to get a preview of the changes that will be made: -```shell +```text terraform plan -var "juju_model_name=my-model" ``` @@ -75,7 +72,7 @@ terraform plan -var "juju_model_name=my-model" If everything looks correct, deploy the resources (skip the approval): -```shell +```text terraform apply -auto-approve -var "juju_model_name=my-model" ``` @@ -83,13 +80,13 @@ terraform apply -auto-approve -var "juju_model_name=my-model" Check the deployment status with -```shell +```text juju status --model lxd:my-model --watch 1s ``` Sample output: -```shell +```text Model Controller Cloud/Region Version SLA Timestamp my-model lxd localhost/localhost 3.5.2 unsupported 14:04:26+02:00 @@ -108,12 +105,12 @@ Continue to operate the charm as usual from here or apply further Terraform chan ## Clean up To keep the house clean, remove the newly deployed Charmed PostgreSQL by running -```shell +```text terraform destroy -var "juju_model_name=my-model" ``` Sample output: -```shell +```text juju_application.machine_postgresql: Refreshing state... [id=my-model:postgresql] Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: @@ -169,11 +166,11 @@ juju_application.machine_postgresql: Destruction complete after 1s Destroy complete! Resources: 1 destroyed. ``` --- -[note] -If you expect having several concurrent connections frequently, it is highly recommended to deploy [PgBouncer](https://charmhub.io/pgbouncer?channel=1/stable) alongside PostgreSQL. For more information, read our explanation about [Connection pooling](/t/15777). +```{note} +If you expect having several concurrent connections frequently, it is highly recommended to deploy [PgBouncer](https://charmhub.io/pgbouncer?channel=1/stable) alongside PostgreSQL. For more information, read our explanation about [Connection pooling](/explanation/connection-pooling). For more examples of Terraform modules for VM, including PostgreSQL HA and PostgreSQL + PgBouncer, see the other directories in the [`terraform-modules` repository](https://github.com/canonical/terraform-modules/tree/main/modules/machine). -[/note] +``` +Feel free to [contact us](/reference/contacts) if you have any question and [collaborate with us on GitHub](https://github.com/canonical/terraform-modules)! -Feel free to [contact us](/t/11863) if you have any question and [collaborate with us on GitHub](https://github.com/canonical/terraform-modules)! \ No newline at end of file diff --git a/docs/how-to/h-deploy-tls-vip-access.md b/docs/how-to/deploy/tls-vip-access.md similarity index 85% rename from docs/how-to/h-deploy-tls-vip-access.md rename to docs/how-to/deploy/tls-vip-access.md index b7c8da8125..9621beca1e 100644 --- a/docs/how-to/h-deploy-tls-vip-access.md +++ b/docs/how-to/deploy/tls-vip-access.md @@ -3,83 +3,81 @@ This guide goes over an example deployment of PostgreSQL, PgBouncer and HAcluster that require external TLS/SSL access via [Virtual IP (VIP)](https://en.wikipedia.org/wiki/Virtual_IP_address). It combines the following guides, where you can find more detailed information: -* [PostgreSQL | Tutorial > Enable TLS](/t/9699) -* [PostgreSQL | How to connect from outside the local network](/t/15802) +* [](/how-to/external-network-access) * [PgBouncer | How to connect from outside the local network](https://charmhub.io/pgbouncer/docs/h-external-access?channel=1/stable) -## Summary -* [Requirements](#requirements) -* [Design](#design) -* [Deploy components](#deploy-components) -* [Check connectivity](#check-connectivity) -* [(Optional) Add monitoring](#optional-add-monitoring) -* [High availability](#high-availability) - ---- - ## Requirements -Although Canonical does not prescribe how you should set up your environment, we can provide recommendations. Consider [contacting us](/t/11863) for support with your use-case. +Although Canonical does not prescribe how you should set up your environment, we can provide recommendations. Consider [contacting us](/reference/contacts) for support with your use-case. The basic requirements to follow along with this example setup are the following: * A fully deployed and running Juju machine environment - * See the [PostgreSQL Tutorial](/t/9709) for a quick setup with Multipass + * See the [PostgreSQL Tutorial](/tutorial/index) for a quick setup with Multipass * See the official [Juju deployment guide](https://juju.is/docs/juju/tutorial#deploy) for more details -* A spare virtual IP address for [hacluster](/t/15741?channel=1/stable#using-a-virtual-ip-to-connect-to-pgbouncer) +* A spare virtual IP address for [hacluster](https://discourse.charmhub.io/t/pgbouncer-how-to-externally-access/15741#using-a-virtual-ip-to-connect-to-pgbouncer) * See the PgBouncer guide: [How to use a VIP to connect to PgBouncer](https://charmhub.io/pgbouncer/docs/h-external-access?channel=1/stable) * DNS record pointing to VIP above (`my-tls-example-db.local` is used as an example here) ## Design -[note type=caution] -This setup applicable for VM/machine charms only. **Do NOT use it for K8s deployments!** -[/note] +```{caution} +This setup is applicable for VM/machine charms only. Do **not** use it as a reference for K8s deployments. +``` -![PostgreSQL TLS VIP|631x562](upload://fIN24xhTTX1Hy1aszs7Os413Y0m.png) +![PostgreSQL TLS VIP|631x562](tls-vip-setup.png) This setup deploys the following components: * The [`postgresql`](https://charmhub.io/postgresql) charm (3 units, as a single cluster). * The [`self-signed-certificates`](https://charmhub.io/self-signed-certificates) charm as the TLS provider. * Note that this is not suitable for production deployments. See the guide: [Security with X.509 certificates](https://charmhub.io/topics/security-with-x-509-certificates). -* The [`data-integrator`](https://charmhub.io/data-integrator) charm as a [principal](https://juju.is/docs/sdk/charm-taxonomy#heading--principal-charms) charm for the [subordinated](https://juju.is/docs/sdk/charm-taxonomy#heading--subordinate-charms) charms below (3 units for high availability): +* The [`data-integrator`](https://charmhub.io/data-integrator) charm as a [principal](https://juju.is/docs/sdk/charm-taxonomy#principal-charms) charm for the [subordinated](https://juju.is/docs/sdk/charm-taxonomy#subordinate-charms) charms below (3 units for high availability): * The latest [`pgbouncer`](https://charmhub.io/pgbouncer?channel=1/stable) charm as a load-balancer and connection pooler (3 units). * The [`hacluster`](https://charmhub.io/hacluster) charm for VIP handling (3 units are the minimum for HA). - * (optional) The COS [`grafana-agent`](https://charmhub.io/grafana-agent) charm for `Monitoring` purposes. + * (optional) The COS [`grafana-agent`](https://charmhub.io/grafana-agent) charm for Monitoring purposes. ## Deploy components Create a Juju model if you haven't already: -```shell + +```text juju add-model my-external-tls-db ``` + Deploy `postgresql` and `self-signed-certificates`: -```shell -juju deploy postgresql -n 3 + +```text +juju deploy postgresql --channel 14/stable -n 3 juju deploy self-signed-certificates juju integrate postgresql self-signed-certificates ``` + Deploy `pgbouncer` from the `1/stable` channel and configure it with your VIP: -```shell + +```text juju deploy pgbouncer --channel 1/stable --config vip=10.20.30.40 juju integrate pgbouncer postgresql juju integrate pgbouncer self-signed-certificates ``` + Deploy `data-integrator` with 3 units and configure the database name of your choice. In this example, we use `mytestdb`: -```shell + +```text juju deploy data-integrator -n 3 --config database-name=mytestdb juju integrate data-integrator pgbouncer ``` + Deploy `hacluster`: -```shell + +```text juju deploy hacluster juju integrate hacluster pgbouncer juju integrate hacluster:juju-info data-integrator ``` Example `juju status` output: -```shell +```text Model Controller Cloud/Region Version SLA Timestamp my-external-tls-db lxd localhost/localhost 3.5.5 unsupported 12:53:35+01:00 @@ -118,10 +116,12 @@ Machine State Address Inst id Base AZ Message ## Check connectivity To test the connection to PostgreSQL via TLS, first get the credentials via `data-integrator`: -```shell + +```text juju run data-integrator/leader get-credentials ``` -```shell + +```text ... postgresql: data: '{"database": "mytestdb", "external-node-connectivity": "true", "requested-secrets": @@ -136,7 +136,8 @@ postgresql: ``` Now use the received credentials (`uris`) to connect PostgreSQL (via TLS/SSL): -```shell + +```text > psql postgresql://relation_id_9:V7kHqHyapIphkUS0cHoOtP3j@10.78.217.100:6432/mytestdb psql (14.15 (Ubuntu 14.15-0ubuntu0.22.04.1), server 14.12 (Ubuntu 14.12-0ubuntu0.22.04.1)) SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off) @@ -148,8 +149,10 @@ mytestdb=> select now(); 2025-01-14 11:51:04.646245+00 (1 row) ``` + Ensure your DNS records points to the virtual IP and that it is routable/reachable from outside of your network to connect using DNS: -```shell + +```text psql postgresql://relation_id_9:V7kHqHyapIphkUS0cHoOtP3j@my-tls-example-db.local:6432/mytestdb ``` @@ -157,14 +160,15 @@ psql postgresql://relation_id_9:V7kHqHyapIphkUS0cHoOtP3j@my-tls-example-db.local Consider adding the [Canonical Observability Stack (COS)](https://charmhub.io/topics/canonical-observability-stack) to your setup for monitoring, alert rules, logs, and tracing. ->See: [PostgreSQL | How to enable monitoring](/t/10600), [PgBouncer | How to enable monitoring](/t/12308). +>See: [](/how-to/monitoring-cos/enable-monitoring), [PgBouncer | How to enable monitoring](https://discourse.charmhub.io/t/pgbouncer-how-to-enable-monitoring/12308). ## High availability -[note type=caution] + +```{caution} In production environments, deploy different units into separate availability zones (AZ). -See: [How to deploy > Multi-AZ](/t/15749) -[/note] +See: [](/how-to/deploy/multi-az) +``` At this point, Juju is responsible for the health of the clusters/applications: * The PostgreSQL charm will restart the workload if PostgreSQL is not healthy. @@ -176,4 +180,4 @@ At this point, Juju is responsible for the health of the clusters/applications: ## Troubleshooting -[Contact us](/t/11863) if you have any issues with this setup or would like help with a different use-case. \ No newline at end of file +[Contact us](/reference/contacts) if you have any issues with this setup or would like help with a different use-case. \ No newline at end of file diff --git a/docs/how-to/deploy/tls-vip-setup.png b/docs/how-to/deploy/tls-vip-setup.png new file mode 100644 index 0000000000000000000000000000000000000000..dff6e3b6078fd3e844710488dfad2ce2c214f879 GIT binary patch literal 75135 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 literal 0 HcmV?d00001 diff --git a/docs/how-to/development/index.md b/docs/how-to/development/index.md new file mode 100644 index 0000000000..fd79237643 --- /dev/null +++ b/docs/how-to/development/index.md @@ -0,0 +1,10 @@ +# Development + +```{toctree} +:titlesonly: +:maxdepth: 2 +:glob: + +Integrate with your charm +Migrate data via pg_dump +Migrate data via backup/restore diff --git a/docs/how-to/h-development-integrate.md b/docs/how-to/development/integrate-with-your-charm.md similarity index 66% rename from docs/how-to/h-development-integrate.md rename to docs/how-to/development/integrate-with-your-charm.md index 86c88df3b7..94221b4a4f 100644 --- a/docs/how-to/h-development-integrate.md +++ b/docs/how-to/development/integrate-with-your-charm.md @@ -1,36 +1,31 @@ -# How to integrate a database with your charm +# How to integrate PostgreSQL with your charm Charmed PostgreSQL can be integrated with any charmed application that supports its interfaces. This page provides some guidance and resources for charm developers to develop, integrate, and troubleshoot their charm so that it may connect with PostgreSQL. -## Summary -* Check supported interfaces -* Integrate your charm with PostgreSQL -* Troubleshooting & testing -* FAQ - ---- - ## Check supported interfaces -First, we recommend that you check [the supported interfaces](/t/10251) of the current charm. You have the option to use modern (preferred) or legacy interfaces. + +First, we recommend that you check [the supported interfaces](/explanation/interfaces-and-endpoints) of the current charm. You have the option to use modern (preferred) or legacy interfaces. Most existing charms currently use [ops-lib-pgsql](https://github.com/canonical/ops-lib-pgsql) interface (legacy). For new charms, **Canonical recommends using [data-platform-libs](https://github.com/canonical/data-platform-libs).** -Legacy charm details are described [here](/t/10690). +Legacy charm details are described [here](/explanation/legacy-charm). ## Integrate your charm with PostgreSQL -> See also: [Juju documentation | Integration](https://juju.is/docs/juju/integration) + +**For an introduction** to the concepts of Juju integrations, see [Juju | Integration](https://juju.is/docs/juju/integration). **For a detailed tutorial** about integrating your charm with the PostgreSQL charm, refer to [Juju | Integrate your charm with PostgreSQL](https://juju.is/docs/sdk/integrate-your-charm-with-postgresql). **For some practical examples**, take a look at the following: * [postgresql-test-app](https://github.com/canonical/postgresql-test-app) GitHub repository -* [juju-sdk-tutorial-k8s](https://github.com/canonical/juju-sdk-tutorial-k8s/tree/04_integrate_with_psql) - the branch `04_integrate_with_psql` describes integration with Charmed PostgreSQL K8s -* [How to migrate Nextcloud to new PostgreSQL (vm-charms)](/t/10969) guide +* [juju-sdk-tutorial-k8s](https://github.com/canonical/juju-sdk-tutorial-k8s/tree/04_integrate_with_psql) - the branch `04_integrate_with_psql` describes integration with Charmed PostgreSQL K8s +* [How to migrate Nextcloud to new PostgreSQL (vm-charms)](https://discourse.charmhub.io/t/nextcloud-postgresql-how-to-migrate-nextcloud-to-new-postgresql-vm-charms/10969) guide ## Troubleshooting & testing + * To learn the basics of charm debugging, start with [Juju | How to debug a charm](https://juju.is/docs/sdk/debug-a-charm) -* To troubleshoot PostgreSQL, check the [Troubleshooting](/t/11864) reference -* To test PostgreSQL and other charms, check the [Testing](/t/11773) reference +* To troubleshoot PostgreSQL, check the [Troubleshooting](/reference/troubleshooting/index) reference +* To test PostgreSQL and other charms, check the [Testing](/reference/software-testing) reference ## FAQ **Does the requirer need to set anything in relation data?** @@ -62,6 +57,7 @@ Legacy charm details are described [here](/t/10690). ## Success stories -* [How to migrate Nextcloud to new PostgreSQL (vm-charms)](/t/10969). +* [How to migrate Nextcloud to new PostgreSQL (vm-charms)](https://discourse.charmhub.io/t/nextcloud-postgresql-how-to-migrate-nextcloud-to-new-postgresql-vm-charms/10969). + +[Contact us](/reference/contacts) if you have any questions, issues, or ideas! -[Contact us](/t/11863) if you have any questions, issues, or ideas! \ No newline at end of file diff --git a/docs/how-to/development/migrate-data-via-backup-restore.md b/docs/how-to/development/migrate-data-via-backup-restore.md new file mode 100644 index 0000000000..a72ee046d6 --- /dev/null +++ b/docs/how-to/development/migrate-data-via-backup-restore.md @@ -0,0 +1,47 @@ +# Migrate database data using ‘backup/restore’ + +This is a guide for migrating data from modern charms. To migrate [legacy charms](/explanation/legacy-charm) data, refer to the guide [Migrate data via pg_dump](/how-to/development/migrate-data-via-pg-dump). + +This Charmed PostgreSQL operator is able to restore its own [backups](/how-to/back-up-and-restore/restore-a-backup) stored on [S3-compatible storage](/how-to/back-up-and-restore/configure-s3-aws). The same restore approach is applicable to restore [foreign backups](/how-to/back-up-and-restore/migrate-a-cluster) made by different Charmed PostgreSQL installation or even another PostgreSQL charm. The backup have to be created manually using [pgBackRest](https://pgbackrest.org/)! + +```{caution} +The Canonical Data team describes here a general approach to data migration, but cannot guarantee restoration results. + +Always test a migration in a test environment before performing it in production! +``` + +## Prerequisites + +* **Check [your application compatibility](/explanation/legacy-charm)** with Charmed PostgreSQL VM before migrating production data from legacy charm +* Make sure **PostgreSQL versions are identical** before the migration + +## Migrate database data + +Below is the *general approach* to the migration (see warning above!): + +1. Retrieve root/admin level credentials from legacy charm. + + See examples in [](/how-to/development/migrate-data-via-pg-dump). + +2. Install [pgBackRest](https://pgbackrest.org/) inside the old charm OR nearby. + + Ensure the version is compatible with pgBackRest in the new `Charmed PostgreSQL` revision you are going to deploy! See examples [here](https://pgbackrest.org/user-guide.html#installation). + + ```{note} + You can use the `charmed-postgresql` [snap](https://snapcraft.io/charmed-postgresql)/[ROCK](https://github.com/canonical/charmed-postgresql-rock) directly. More details [here](/explanation/architecture) + ``` + +3. Configure storage for database backup (local or remote, S3-based is recommended). + +4. Create a first full logical backup during the off-peak + + See an example of backup command [here](https://github.com/canonical/postgresql-k8s-operator/commit/f39caaa4c5c85afdb157bd53df54a24a1b9687ac#diff-cc5993b9da2438ecff27897b3ab9d2f9bc445cbf5b4f6369a1a0c2f404fe6a4fR186-R212). + +5. [Restore the foreign backup](/how-to/back-up-and-restore/migrate-a-cluster) to the Charmed PostgreSQL installation in your test environment. +6. Perform all the necessary tests to make sure your application accepted the new database. +7. Schedule and perform the final production migration, re-using the last steps above. + +--- + +Do you have questions? [Contact us](/reference/contacts) if you are interested in such a data migration! + diff --git a/docs/how-to/h-migrate-pgdump.md b/docs/how-to/development/migrate-data-via-pg-dump.md similarity index 81% rename from docs/how-to/h-migrate-pgdump.md rename to docs/how-to/development/migrate-data-via-pg-dump.md index 50fa2da48b..b7858b93ae 100644 --- a/docs/how-to/h-migrate-pgdump.md +++ b/docs/how-to/development/migrate-data-via-pg-dump.md @@ -1,30 +1,22 @@ # Migrate database data using `pg_dump` / `pg_restore` -This guide describes database **data** migration only. To migrate charms on new juju interfaces, refer to the guide [How to integrate a database with my charm](/t/11865). - -[note] -**Note**: All commands are written for `juju >= v.3.0` - -If you are using an earlier version, be aware that: - - - `juju run` replaces `juju run-action --wait` in `juju v.2.9` - - `juju integrate` replaces `juju relate` and `juju add-relation` in `juju v.2.9` - -For more information, check the [Juju 3.0 Release Notes](https://juju.is/docs/juju/roadmap#heading--juju-3-0-0---22-oct-2022). -[/note] +This guide describes database **data** migration only. To migrate charms on new juju interfaces, refer to the guide [How to integrate a database with my charm](/how-to/development/integrate-with-your-charm). ## Do you need to migrate? + A database migration is only required if the output of the following command is `latest/stable`: -```shell +```text juju show-application postgresql | yq '.[] | .channel' ``` + Migration is **not** necessary if the output above is `14/stable`! -This guide can be used to copy data between different installations of the same (modern) charm `postgresql`, but the [backup/restore](/t/12164) is more recommended for migrations between modern charms. +This guide can be used to copy data between different installations of the same (modern) charm `postgresql`, but the [backup/restore](/how-to/development/migrate-data-via-backup-restore) is more recommended for migrations between modern charms. ## Summary -The legacy VM charm archived in the `latest/stable` channel, read more [here](/t/10690). + +The legacy VM charm archived in the `latest/stable` channel, read more [here](/explanation/legacy-charm). A minor difference in commands might be necessary for different revisions and/or Juju versions, but the general logic remains: * Deploy the modern charm nearby @@ -35,14 +27,15 @@ A minor difference in commands might be necessary for different revisions and/or * Add relation to modern charm * Validate results and remove legacy charm -[note] -**Note**: Always test migration in a safe environment before performing it in production! -[/note] +```{caution} +Always test migration in a safe environment before performing it in production! +``` ## Prerequisites -- **[Your application is compatible](/t/10690) with Charmed PostgreSQL VM** + +- **[Your application is compatible](/explanation/legacy-charm) with Charmed PostgreSQL VM** - A client machine with access to the deployed legacy charm -- `juju v.2.9` or later (check [Juju 3.0 Release Notes](https://juju.is/docs/juju/roadmap#heading--juju-3-0-0---22-oct-2022) for more information about key differences) +- `juju v.2.9` or later (check [Juju 3.0 Release Notes](https://juju.is/docs/juju/roadmap#juju-3-0-0---22-oct-2022) for more information about key differences) - Enough storage in the cluster to support backup/restore of the databases. ## Obtain existing database credentials @@ -50,14 +43,15 @@ A minor difference in commands might be necessary for different revisions and/or To obtain credentials for existing databases, execute the following commands for **each** database that will be migrated. Take note of these credentials for future steps. First, define and tune your application and db (database) names. For example: -```shell + +```text CLIENT_APP=< my-application/0 > OLD_DB_APP=< legacy-postgresql/leader | postgresql/0 > NEW_DB_APP=< new-postgresql/leader | postgresql/0 > DB_NAME=< your_db_name_to_migrate > ``` Then, obtain the username from the existing legacy database via its relation info: -```shell +```text OLD_DB_USER=$(juju show-unit ${CLIENT_APP} | yq '.[] | .relation-info | select(.[].endpoint == "db") | .[0].application-data.user') ``` @@ -65,11 +59,11 @@ OLD_DB_USER=$(juju show-unit ${CLIENT_APP} | yq '.[] | .relation-info | select(. Deploy new PostgreSQL database charm: -```shell +```text juju deploy postgresql ${NEW_DB_APP} --channel 14/stable ``` Obtain `operator` user password of new PostgreSQL database from PostgreSQL charm: -```shell +```text NEW_DB_USER=operator NEW_DB_PASS=$(juju run ${NEW_DB_APP} get-password | yq '.password') ``` @@ -77,53 +71,53 @@ NEW_DB_PASS=$(juju run ${NEW_DB_APP} get-password | yq '.password') ## Migrate database Use the credentials and information obtained in previous steps to perform the database migration with the following procedure. -[note] +```{note} Make sure no new connections were made and that the database has not been altered! -[/note] +``` ### Create dump from legacy charm Remove the relation between application charm and legacy charm: -```shell +```text juju remove-relation ${CLIENT_APP} ${OLD_DB_APP} ``` Connect to the database VM of a legacy charm: -```shell +```text juju ssh ${OLD_DB_APP} bash ``` Create a dump via Unix socket using credentials from the relation: -```shell +```text mkdir -p /srv/dump/ OLD_DB_DUMP="legacy-postgresql-${DB_NAME}.sql" pg_dump -Fc -h /var/run/postgresql/ -U ${OLD_DB_USER} -d ${DB_NAME} > "/srv/dump/${OLD_DB_DUMP}" ``` Exit the database VM: -```shell +```text exit ``` ### Upload dump to new charm Fetch dump locally and upload it to the new Charmed PostgreSQL charm: -```shell +```text juju scp ${OLD_DB_APP}:/srv/dump/${OLD_DB_DUMP} ./${OLD_DB_DUMP} juju scp ./${OLD_DB_DUMP} ${NEW_DB_APP}:. ``` ssh into new Charmed PostgreSQL charm and create a new database (using `${NEW_DB_PASS}`): -```shell +```text juju ssh ${NEW_DB_APP} bash createdb -h localhost -U ${NEW_DB_USER} --password ${DB_NAME} ``` Restore the dump (using `${NEW_DB_PASS}`): -```shell +```text pg_restore -h localhost -U ${NEW_DB_USER} --password -d ${DB_NAME} --no-owner --clean --if-exists ${OLD_DB_DUMP} ``` ## Integrate with modern charm Integrate (formerly "relate" in `juju v.2.9`) your application and new PostgreSQL database charm (using the modern `database` endpoint) -```shell +```text juju integrate ${CLIENT_APP} ${NEW_DB_APP}:database ``` If the `database` endpoint (from the `postgresql_client` interface) is not yet supported, use instead the `db` endpoint from the legacy `pgsql` interface: -```shell +```text juju integrate ${CLIENT_APP} ${NEW_DB_APP}:db ``` @@ -135,6 +129,7 @@ Test your application to make sure the data is available and in a good condition Test your application and if you are happy with a data migration, do not forget to remove legacy charms to keep the house clean: -```shell +```text juju remove-application --destroy-storage -``` \ No newline at end of file +``` + diff --git a/docs/how-to/h-enable-ldap.md b/docs/how-to/enable-ldap.md similarity index 71% rename from docs/how-to/h-enable-ldap.md rename to docs/how-to/enable-ldap.md index a37a00d526..bda04f3800 100644 --- a/docs/how-to/h-enable-ldap.md +++ b/docs/how-to/enable-ldap.md @@ -1,38 +1,33 @@ -[note] -**Note**: All commands are written for `juju >= v.3.0` - -If you are using an earlier version, check the [Juju 3.0 Release Notes](https://juju.is/docs/juju/roadmap#heading--juju-3-0-0---22-oct-2022). -[/note] - -[note] -LDAP is available on channels: `14/edge` and `16/edge`, from revision `600`. -[/note] - - # How to enable LDAP authentication -LDAP (*Lightweight Directory Access Protocol*) enables centralized authentication for PostgreSQL clusters, reducing the overhead of managing local credentials and access policies. +The Lightweight Directory Access Protocol (LDAP) enables centralized authentication for PostgreSQL clusters, reducing the overhead of managing local credentials and access policies. This guide goes over the steps to integrate LDAP as an authentication method with the PostgreSQL charm, all within the Juju ecosystem. +## Prerequisites + +* Charmed PostgreSQL revision `600+` +* Juju `3.6+` + ## Deploy an LDAP server in a K8s environment -[note type="caution"] -**Disclaimer:** In this guide, we use [self-signed certificates](https://en.wikipedia.org/wiki/Self-signed_certificate) provided by the [`self-signed-certificates` operator](https://github.com/canonical/self-signed-certificates-operator). +```{caution} +In this guide, we use [self-signed certificates](https://en.wikipedia.org/wiki/Self-signed_certificate) provided by the [`self-signed-certificates` operator](https://github.com/canonical/self-signed-certificates-operator). **This is not recommended for a production environment.** For production environments, check the collection of [Charmhub operators](https://charmhub.io/?q=tls-certificates) that implement the `tls-certificate` interface, and choose the most suitable for your use-case. -[/note] +``` -Switch to the Kubernetes controller: +Switch to a Kubernetes controller: -```shell +```text juju switch ``` Deploy the [GLAuth charm](https://charmhub.io/glauth-k8s): -```shell + +```text juju add-model glauth juju deploy self-signed-certificates juju deploy postgresql-k8s --channel 14/stable --trust @@ -40,20 +35,21 @@ juju deploy glauth-k8s --channel edge --trust ``` Integrate (formerly known as "relate") the three applications: -```shell + +```text juju integrate glauth-k8s:certificates self-signed-certificates juju integrate glauth-k8s:pg-database postgresql-k8s ``` Deploy the [GLAuth-utils charm](https://charmhub.io/glauth-utils), in order to manage LDAP users: -```shell +```text juju deploy glauth-utils --channel edge --trust ``` Integrate (formerly known as "relate") the two applications: -```shell +```text juju integrate glauth-k8s glauth-utils ``` @@ -61,20 +57,20 @@ juju integrate glauth-k8s glauth-utils Enable the required micro-k8s plugin: -```shell +```text IPADDR=$(ip -4 -j route get 2.2.2.2 | jq -r '.[] | .prefsrc') sudo microk8s enable metallb $IPADDR-$IPADDR ``` Deploy the [Traefik charm](https://charmhub.io/traefik-k8s), in order to expose endpoints from the K8s cluster: -```shell +```text juju deploy traefik-k8s --trust ``` Integrate (formerly known as "relate") the two applications: -```shell +```text juju integrate glauth-k8s:ingress traefik-k8s ``` @@ -82,7 +78,7 @@ juju integrate glauth-k8s:ingress traefik-k8s To offer the GLAuth interfaces, run: -```shell +```text juju offer glauth-k8s:ldap ldap juju offer glauth-k8s:send-ca-cert send-ca-cert ``` @@ -91,29 +87,29 @@ juju offer glauth-k8s:send-ca-cert send-ca-cert Switch to the VM controller: -```shell +```text juju switch :postgresql ``` To have LDAP offers consumed: -```shell +```text juju consume :admin/glauth.ldap juju consume :admin/glauth.send-ca-cert ``` To have LDAP authentication enabled, integrate the PostgreSQL charm with the GLAuth charm: -```shell +```text juju integrate postgresql:ldap ldap juju integrate postgresql:receive-ca-cert send-ca-cert ``` ## Map LDAP users to PostgreSQL -To have LDAP users available in PostgreSQL, provide a comma separated list of LDAP groups to already created PostgreSQL authorization groups. To create those groups before hand, refer to the Data Integrator charm [page](https://charmhub.io/data-integrator). +To have LDAP users available in PostgreSQL, provide a comma separated list of LDAP groups to already created PostgreSQL authorization groups. To create those groups before hand, refer to the [data integrator charm](https://charmhub.io/data-integrator). -```shell +```text juju config postgresql ldap_map="=" ``` @@ -121,7 +117,8 @@ juju config postgresql ldap_map="=" You can disable LDAP removing the following relations: -```shell +```text juju remove-relation postgresql.receive-ca-cert send-ca-cert juju remove-relation postgresql.ldap ldap -``` \ No newline at end of file +``` + diff --git a/docs/reference/r-plugins-timescaledb.md b/docs/how-to/enable-plugins-extensions/enable-timescaledb.md similarity index 64% rename from docs/reference/r-plugins-timescaledb.md rename to docs/how-to/enable-plugins-extensions/enable-timescaledb.md index 9624a4b558..7d3adada9b 100644 --- a/docs/reference/r-plugins-timescaledb.md +++ b/docs/how-to/enable-plugins-extensions/enable-timescaledb.md @@ -1,18 +1,18 @@ -# TimescaleDB plugin/extension +# How to enable TimescaleDB -Charmed PostgreSQL separates TimescaleDB editions for different [CharmHub tracks](https://canonical-charmcraft.readthedocs-hosted.com/en/stable/howto/manage-channels/): - -* Charmed PostgreSQL [16](https://charmhub.io/postgresql?channel=16/candidate) ships [Timescale Community edition](https://docs.timescale.com/about/latest/timescaledb-editions/). -* Charmed PostgreSQL [14](https://charmhub.io/postgresql?channel=14/stable) ships [Timescale Apache 2 edition](https://docs.timescale.com/about/latest/timescaledb-editions/). +[Charmed PostgreSQL 14](https://charmhub.io/postgresql?channel=14/stable) ships [Timescale Apache 2 edition](https://docs.timescale.com/about/latest/timescaledb-editions/). ## Enable TimescaleDB To enable TimescaleDB plugin/extension simply run: -```shell + +```text juju config postgresql plugin_timescaledb_enable=true ``` + The plugin has been enabled on all units once the config-change event finished and all units reports idle: -```shell + +```text > juju status ... Unit Workload Agent Machine Public address Ports Message @@ -30,13 +30,15 @@ postgresql/6 active idle 6 10.189.210.150 5432/tcp ## Disable TimescaleDB To disable it explicitly, simply run: -```shell + +```text juju config postgresql plugin_timescaledb_enable=false ``` The plugin has been disabled on all units once the config-change event finished and all units reports idle (same example as above). -> **Note**: the extension will NOT be disable when database objects uses/depends on plugin is being disabled (clean the database to disable the plugin): -```shell +The extension will NOT be disabled when database objects uses/depends on plugin is being disabled (clean the database to disable the plugin): + +```text > juju status ... Unit Workload Agent Machine Public address Ports Message @@ -45,14 +47,15 @@ postgresql/3* blocked idle 3 10.189.210.124 5432/tcp Cannot disabl ``` Another option is to reset the manually enabled config option (as it is disabled by default): -```shell +```text juju config postgresql --reset plugin_timescaledb_enable ``` -## Test TimescaleDB status: +## Test TimescaleDB status Prepare the `user_defined_action` procedure: -```shell + +```text postgres=# CREATE OR REPLACE PROCEDURE user_defined_action(job_id int, config jsonb) LANGUAGE PLPGSQL AS $$ BEGIN @@ -62,7 +65,8 @@ $$; ``` Run the following commands to test your TimescaleDB on Charmed PostgreSQL 14: -```shell + +```text postgres=# SELECT add_job('user_defined_action','1h'); ERROR: function "add_job" is not supported under the current "apache" license HINT: Upgrade your license to 'timescale' to use this free community feature. @@ -70,24 +74,3 @@ HINT: Upgrade your license to 'timescale' to use this free community feature. postgres=# CREATE TABLE test_timescaledb (time TIMESTAMPTZ NOT NULL); SELECT create_hypertable('test_timescaledb', 'time'); CREATE TABLE create_hypertable -------------------------------- - (1,public,test_timescaledb,t) -(1 row) - -``` - -TimescaleDB status on Charmed PostgreSQL 16: -```shell -postgres=# SELECT add_job('user_defined_action','1h'); - add_job ---------- - 1000 -(1 row) - -postgres=# CREATE TABLE test_timescaledb (time TIMESTAMPTZ NOT NULL); SELECT create_hypertable('test_timescaledb', 'time'); -CREATE TABLE - create_hypertable -------------------------------- - (1,public,test_timescaledb,t) -(1 row) -``` \ No newline at end of file diff --git a/docs/how-to/h-enable-plugins-extensions.md b/docs/how-to/enable-plugins-extensions/index.md similarity index 63% rename from docs/how-to/h-enable-plugins-extensions.md rename to docs/how-to/enable-plugins-extensions/index.md index 21f7148e87..9e3b372321 100644 --- a/docs/how-to/h-enable-plugins-extensions.md +++ b/docs/how-to/enable-plugins-extensions/index.md @@ -2,39 +2,44 @@ This guide outlines the steps for enabling an extension in a Charmed PostgreSQL deployment. -For a list of available extensions, see the page [Supported plugins/extensions](/t/10946). The words "plugin" and "extension" will be used interchangeably. - -## Prerequisites -* A deployed [Charmed PostgreSQL operator](/t/9697) from [a revision that supports the desired plugin](/t/10946) - +For a list of available extensions, see the page [Supported plugins/extensions](/reference/plugins-extensions). The words "plugin" and "extension" will be used interchangeably. ## Enable extension + Enable the extension by setting `True` as the value of its respective config option, like in the following example: -```shell +```text juju config postgresql plugin__enable=True ``` ## Integrate your application -Integrate (formerly known as "relate" in `juju v.2.9`) your application charm with the PostgreSQL charm: -```shell +```text juju integrate postgresql ``` If your application charm requests extensions through `db` or `db-admin` relation data, but the extension is not enabled yet, you'll see that the PostgreSQL application goes into a blocked state with the following message: -```shell +```text postgresql/0* blocked idle 10.1.123.30 extensions requested through relation ``` In the [Juju debug logs](https://juju.is/docs/juju/juju-debug-log) we can see the list of extensions that need to be enabled: -```shell +```text unit-postgresql-0: 18:04:51 ERROR unit.postgresql/0.juju-log db:5: ERROR - `extensions` (pg_trgm, unaccent) cannot be requested through relations - Please enable extensions through `juju config` and add the relation again. ``` After enabling the needed extensions through the config options, the charm will unblock. If you have removed the relation, you can add it back again. -If the application charm uses the new `postgresql_client` interface, it can use the [is_postgresql_plugin_enabled](https://charmhub.io/data-platform-libs/libraries/data_interfaces#databaserequires-is_postgresql_plugin_enabled) helper method from the data interfaces library to check whether the plugin/extension is already enabled in the database. +If the application charm uses the new `postgresql_client` interface, it can use the [is_postgresql_plugin_enabled](https://charmhub.io/data-platform-libs/libraries/data_interfaces) helper method from the data interfaces library to check whether the plugin/extension is already enabled in the database. + +```{note} +Not all PostgreSQL extensions are available. The list of supported extensions is available in [](/reference/plugins-extensions). +``` + + +```{toctree} +:titlesonly: +:maxdepth: 2 +:glob: +:hidden: -[note] -**Note:** Not all PostgreSQL extensions are available. The list of supported extensions is available at [ Supported plugins/extensions](/t/charmed-postgresql-k8s-reference-supported-plugins-extensions/10946). -[/note] \ No newline at end of file +Enable TimescaleDB \ No newline at end of file diff --git a/docs/how-to/h-enable-tls.md b/docs/how-to/enable-tls.md similarity index 79% rename from docs/how-to/h-enable-tls.md rename to docs/how-to/enable-tls.md index c5a872288d..2e529c9702 100644 --- a/docs/how-to/h-enable-tls.md +++ b/docs/how-to/enable-tls.md @@ -1,59 +1,54 @@ -[note] -**Note**: All commands are written for `juju >= v.3.1` - -If you're using `juju 2.9`, check the [`juju 3.0` Release Notes](https://juju.is/docs/juju/roadmap#heading--juju-3-0-0---22-oct-2022). -[/note] - # How to enable TLS encryption This guide will show how to enable TLS/SSL on a PostgreSQL cluster using the [`self-signed-certificates` operator](https://github.com/canonical/self-signed-certificates-operator) as an example. This guide assumes everything is deployed within the same network and Juju model. -> See also: [How to deploy for external TLS access](/t/16576) - -## Summary -* Enable TLS -* Disable TLS -* Check certificates in use -* Update keys ---- +> See also: [](/how-to/deploy/tls-vip-access) ## Enable TLS -[note type="caution"] +```{caution} **[Self-signed certificates](https://en.wikipedia.org/wiki/Self-signed_certificate) are not recommended for a production environment.** -Check [this guide about X.509 certificates](/t/11664) for an overview of all the TLS certificate charms available. -[/note] +Check [this guide about X.509 certificates](https://discourse.charmhub.io/t/security-with-x-509-certificates/11664) for an overview of all the TLS certificate charms available. +``` First, deploy the TLS charm: -```shell + +```text juju deploy self-signed-certificates ``` To enable TLS integrate (formerly known as “relate”) the two applications: -```shell + +```text juju integrate postgresql:certificates self-signed-certificates:certificates ``` ## Check certificates in use + To check the certificates in use by PostgreSQL, run -```shell + +```text openssl s_client -starttls postgres -connect : | grep issuer ``` -## Update keys +## Manage keys + Updates to private keys for certificate signing requests (CSR) can be made via the `set-tls-private-key` action. Note that passing keys to external/internal keys should *only be done with* `base64 -w0`, *not* `cat`. With three replicas, this schema should be followed: Generate a shared internal key: -```shell + +```text openssl genrsa -out internal-key.pem 3072 ``` + Generate external keys for each unit: -```shell + +```text openssl genrsa -out external-key-0.pem 3072 openssl genrsa -out external-key-1.pem 3072 openssl genrsa -out external-key-2.pem 3072 @@ -61,7 +56,7 @@ openssl genrsa -out external-key-2.pem 3072 Apply both private keys to each unit. The shared internal key will be applied only to the juju leader. -``` +```text juju run postgresql/0 set-tls-private-key "external-key=$(base64 -w0 external-key-0.pem)" "internal-key=$(base64 -w0 internal-key.pem)" --wait juju run postgresql/1 set-tls-private-key "external-key=$(base64 -w0 external-key-1.pem)" "internal-key=$(base64 -w0 internal-key.pem)" --wait juju run postgresql/2 set-tls-private-key "external-key=$(base64 -w0 external-key-2.pem)" "internal-key=$(base64 -w0 internal-key.pem)" --wait @@ -69,14 +64,17 @@ juju run postgresql/2 set-tls-private-key "external-key=$(base64 -w0 external-ke Updates can also be done with auto-generated keys: -``` +```text juju run postgresql/0 set-tls-private-key juju run postgresql/1 set-tls-private-key juju run postgresql/2 set-tls-private-key ``` ## Disable TLS + Disable TLS by removing the integration. -```shell + +```text juju remove-relation postgresql:certificates self-signed-certificates:certificates -``` \ No newline at end of file +``` + diff --git a/docs/how-to/h-external-access.md b/docs/how-to/external-network-access.md similarity index 89% rename from docs/how-to/h-external-access.md rename to docs/how-to/external-network-access.md index 023177692b..d11e2480f5 100644 --- a/docs/how-to/h-external-access.md +++ b/docs/how-to/external-network-access.md @@ -10,10 +10,11 @@ There are many possible ways to connect the Charmed PostgreSQL database from out One of the possible options is to use [virtual IP addresses (VIP)](https://en.wikipedia.org/wiki/Virtual_IP_address) which the charm PgBouncer provides with assistance from the charm/interface `hacluster`. Please follow the [PgBouncer documentation](https://charmhub.io/pgbouncer/docs/h-external-access) for such configuration. -> See also: [How to deploy for external TLS VIP access](/t/16576). +> See also: [](/how-to/deploy/tls-vip-access). ## External relation (Juju) **Use case**: The client application is a Juju application outside the database deployment (e.g. hybrid Juju deployment with different VM clouds/controllers). -In this case, a cross-controller relation is necessary. Please [contact](/t/11863) the Data team to discuss possible options for your use case. \ No newline at end of file +In this case, a cross-controller relation is necessary. Please [contact](/reference/contacts) the Data team to discuss possible options for your use case. + diff --git a/docs/how-to/h-async.md b/docs/how-to/h-async.md deleted file mode 100644 index 71da3b71da..0000000000 --- a/docs/how-to/h-async.md +++ /dev/null @@ -1,30 +0,0 @@ -# Cross-regional async replication - -Cross-regional (or multi-server) asynchronous replication focuses on disaster recovery by distributing data across different servers. - -## Prerequisites -* Juju `v.3.4.2+` -* Make sure your machine(s) fulfill the [system requirements](/t/11743) - -### Substrate dependencies - -The following table shows the source and target controller/model combinations that are currently supported: - -| | AWS | GCP | Azure | -|---|---|:---:|:---:| -| AWS | | | | -| GCP | | ![ check ] | ![ check ] | -| Azure | | ![ check ] | ![ check ] | - -## How-to guides - -* [How to set up clusters for cross-regional async replication](/t/13991) -* [How to integrate with a client application](/t/13992) -* [How to remove or recover a cluster](/t/13994) - * [Switchover](/t/13994#switchover) - * [Detach](/t/13994#detach-a-cluster) - * [Recover](/t/13994#recover-a-cluster) - - -[check]: https://img.shields.io/badge/%E2%9C%93-brightgreen -[cross]: https://img.shields.io/badge/x-white \ No newline at end of file diff --git a/docs/how-to/h-deploy-juju-spaces.md b/docs/how-to/h-deploy-juju-spaces.md deleted file mode 100644 index b9cbe1e5d9..0000000000 --- a/docs/how-to/h-deploy-juju-spaces.md +++ /dev/null @@ -1,65 +0,0 @@ -# Deploy on Juju spaces - -The Charmed PostgreSQL operator supports [Juju spaces](https://documentation.ubuntu.com/juju/latest/reference/space/index.html) to separate network traffic for: -- **Client** - PostgreSQL instance to client data -- **Instance-replication** - cluster instances replication data -- **Cluster-replication** - cluster to cluster replication data -- **Backup** - backup and restore data - -## Prerequisites - -* **Charmed PostgreSQL 16** -* Configured network spaces - * See [Juju | How to manage network spaces](https://documentation.ubuntu.com/juju/latest/reference/juju-cli/list-of-juju-cli-commands/add-space/) - -## Deploy - -On application deployment, constraints are required to ensure the unit(s) have address(es) on the specified network space(s), and endpoint binding(s) for the space(s). - -For example, with spaces configured for instance replication and client traffic: -```shell -❯ juju spaces -Name Space ID Subnets -alpha 0 10.163.154.0/24 -client 1 10.0.0.0/24 -peers 2 10.10.10.0/24 -``` - -The space `alpha` is default and cannot be removed. To deploy Charmed PostgreSQL Operator using the spaces: -```shell -juju deploy postgresql --channel 16/edge \ - --constraints spaces=client,peers \ - --bind "database-peers=peers database=client" -``` - -[note type=caution] -Currently there's no support for the juju `bind` command. Network space binding must be defined at deploy time only. -[/note] - -Consequently, a client application must use the `client` space on the model, or a space for the same subnet in another model, for example: -```shell -juju deploy client-app \ - --constraints spaces=client \ - --bind database=client -``` - -The two application can be then related using: -```shell -juju integrate postgresql:database client-app:database -``` - -The client application will receive network endpoints on the `10.0.0.0/24` subnet. - -The Charmed PostgreSQL operator endpoints are: - -| Endpoint | Traffic | -| ------------------------------ | -------------------- | -| database | Client | -| database-peers | Instance-replication | -| replication-offer, replication | Cluster-replication | -| s3-parameters | Backup | - - -[note] -If using a network space for the backup traffic, the user is responsible for ensuring that the target object storage URL traffic is routed via the specified network space. -[/note] \ No newline at end of file diff --git a/docs/how-to/h-deploy-juju-storage.md b/docs/how-to/h-deploy-juju-storage.md deleted file mode 100644 index 43ea636938..0000000000 --- a/docs/how-to/h-deploy-juju-storage.md +++ /dev/null @@ -1,284 +0,0 @@ -# Deploy on Juju storage - -Charmed PostgreSQL uses the [Juju storage](https://documentation.ubuntu.com/juju/3.6/reference/storage/) abstraction to utilize data volume provided by different [clouds](https://documentation.ubuntu.com/juju/3.6/reference/cloud/#cloud) while keeping the same UI/UX for end users. - -* **Charmed PostgreSQL** [**16**](https://charmhub.io/postgresql?channel=16/candidate) supports multiple storage: `archive`, `data`, `logs` and `temp`. -* **Charmed PostgreSQL** [**14**](https://charmhub.io/postgresql?channel=14/stable) supports single storage: `pgdata`. -* [Legacy PostgreSQL charm](/t/10690) in track "[latest](https://charmhub.io/postgresql?channel=14/stable)" does **not** support the Juju storage abstraction. - -## Charmed PostgreSQL 16 - -Check the [`metadata.yaml`](https://github.com/canonical/postgresql-operator/blob/16/edge/metadata.yaml) for find Juju storage name and tech details: - -[details="Charmed PostgreSQL 16 storage list"] -```shell -storage: - archive: - type: filesystem - location: /var/snap/charmed-postgresql/common/data/archive - data: - type: filesystem - location: /var/snap/charmed-postgresql/common/var/lib/postgresql - logs: - type: filesystem - location: /var/snap/charmed-postgresql/common/data/logs - temp: - type: filesystem - location: /var/snap/charmed-postgresql/common/data/temp -``` -[/details] - -Charmed PostgreSQL 16 supports multiple storage `archive` , `data` , `logs` and `temp` . See the deployment examples below. - -## Charmed PostgreSQL 14 - -Check the [metadata.yaml](https://github.com/canonical/postgresql-operator/blob/main/metadata.yaml) for find Juju storage name and tech details: -[details="Charmed PostgreSQL 14 storage list"] -```shell -storage: - pgdata: - type: filesystem - location: /var/snap/charmed-postgresql/common -``` -[/details] - -Charmed PostgreSQL 14 supports single storage `pgdata` attaching it on `juju deploy` and mounted inside the Snap common folder `/var/snap/charmed-postgresql/common`. - -[details="Example of 'Juju storage'"] -```shell -> juju deploy postgresql - -> juju storage -Unit Storage ID Type Size Status Message -postgresql/0 pgdata/0 filesystem pending - -> juju storage -Unit Storage ID Type Pool Size Status Message -postgresql/0 pgdata/0 filesystem rootfs 97 GiB attached - -> juju show-storage pgdata/0 -pgdata/0: - kind: filesystem - life: alive - status: - current: attached - since: 01 May 2025 18:47:04+02:00 - persistent: false - attachments: - units: - postgresql/0: - machine: "0" - location: /var/snap/charmed-postgresql/common - life: alive - -> juju ssh postgresql/0 mount | grep /var/snap/charmed-postgresql/common -/dev/sda1 on /var/snap/charmed-postgresql/common type ext4 (rw,relatime,discard,errors=remount-ro) -``` -[/details] - -## Deployment examples - -### Define the storage size - -```shell -> juju deploy postgresql --storage pgdata=10G - -> juju storage -Unit Storage ID Type Pool Size Status Message -postgresql/1 pgdata/1 filesystem lxd 10 GiB attached -``` - -### Define the storage location - -Juju supports wide list of different [storage pools](https://bobcares.com/blog/lxd-create-storage-pool/): - -```shell -> juju create-storage-pool mystoragepool lxd - -> juju storage-pools | grep mystoragepool -mystoragepool lxd - -> juju deploy postgresql --storage pgdata=5G,mystoragepool - -> juju storage -Unit Storage ID Type Pool Size Status Message -postgresql/2 pgdata/2 filesystem mystoragepool 5 GiB attached -``` - -### Re-deploy detached storage (track `14`) - -To re-deploy the application with the old Juju storage, it is necessary to provide all charm/database credentials to the new charm or app. - -**Charmed PostgreSQL 14 uses the Juju action `set-password` to handle credentials:** -```shell -# Note old passwords -> juju show-secret --reveal database-peers.postgresql.app - -# Find old storage id: -> juju storage - -# Re-deploy new app one unit only to set old passwords -> juju deploy postgresql --channel 14/stable -n 1 - -# Once deployed, set old passwords from old app Juju App secrets -juju run postgresql/leader set-password username=operator password=cpUJnNRJ6Qt2Hgli -juju run postgresql/leader set-password username=patroni password=0N7pKAutKCstPuvx -juju run postgresql/leader set-password username=raft password=8xSZvTLfyHpglGfI -juju run postgresql/leader set-password username=replication password=5xN9gj9uu5Um3PWB -juju run postgresql/leader set-password username=rewind password=wuEsPmsdpc6L8qhT -juju run postgresql/leader set-password username=monitoring password=AgOxXzcRD5iohE6C - -# Scale down to zero units byt removing all Juju units -> juju remove-unit postgresql/1 --destroy-storage=yes - -# Scale up to one unit and attach the old Juju storage -> juju add-unit postgresql --attach-storage pgdata/x - -# If no issues noticed, scale to HA (3 units total) -> juju add-unit postgresql -n 2 -``` - -### Re-deploy detached storage (track `16`) - -To re-deploy the application with the old Juju storage, it is necessary to provide all charm/database credentials as Juju user secrets. - -**Charmed PostgreSQL 16 uses Juju user secrets to handle credentials:** -```shell -# Note old passwords -> juju show-secret --reveal database-peers.postgresql.app - -# Add new Juju User secret with old password values -> juju add-secret mypgpass \ - monitoring-password=oQDLAVMV1AHFZq1L \ - operator-password=IXarOnndC9XKoytS \ - patroni-password=vWzJZIktqi0qGMCx \ - raft-password=2pALATzLJsrpAf5q \ - replication-password=2bcnAQhXLrX3ekVP \ - rewind-password=bBqQOXiC7whSqQbR - -# Find old storage id: -> juju storage - -# Re-deploy new app re-using old storage and old credentials -> juju deploy postgresql \ - --channel 16/candidate \ - --attach-storage pgdata/5 \ - --config system-users=newsecret54321id - -# Grant access to new secrets for re-deployed application -> juju grant-secret mypgpass postgresql -``` - -[details="Example: Complete old storage re-deployment (track 16)"] -Prepare the test data to restore later: -```shell -# Add a new model -> juju add-model teststorage - -# Deploy the new postgresql to dump storage with credentials -> juju deploy postgresql --channel 16/edge --storage pgdata=5Gcompleted -Deployed "postgresql" from charm-hub charm "postgresql", revision 613 in channel 16/edge on ubuntu@24.04/stable - -# Wait for deployment completed: -> juju status -... -Unit Workload Agent Machine Public address Ports Message -postgresql/0* active idle 0 10.189.210.99 5432/tcp Primary - -# Reveal the Juju secrets for the simpliest DB access: -> juju show-secret --reveal database-peers.postgresql.app -d09v83poie738j7af4n0: - revision: 2 - checksum: 9e28910800d4dd94cd655d5d5f49a9bb7e4b7fbf6dde232328e4f6734c7bdf84 - owner: postgresql - label: database-peers.postgresql.app - created: 2025-05-01T22:22:07Z - updated: 2025-05-01T22:22:10Z - content: - monitoring-password: 6inFApK8IyJuJ6LG - operator-password: I8mkza6vIhD2w1Rh - patroni-password: JAYSlB3mQXi9g4fc - raft-password: eFWUOCYb1lIOpGuM - replication-password: SFBx8OL9XxXiWwcC - rewind-password: 92xT4yTniiG7OEch - -# Create a test data -> PGPASSWORD=I8mkza6vIhD2w1Rh psql -h 10.189.210.99 -U operator -d postgres -c "create table a (id int);" -CREATE TABLE -> PGPASSWORD=I8mkza6vIhD2w1Rh psql -h 10.189.210.99 -U operator -d postgres -c "\d" - List of relations - Schema | Name | Type | Owner ---------+------+-------+---------- - public | a | table | operator -(1 row) - -# Check the storage status -> juju storage -Unit Storage ID Type Pool Size Status Message -postgresql/0 pgdata/0 filesystem lxd 5.0 GiB attached - -# Remove the old application keeping the storage: -> juju remove-application postgresql --destroy-storage=false -WARNING This command will perform the following actions: -will remove application postgresql -- will remove unit postgresql/0 -- will detach storage pgdata/0 -Continue [y/N]? y - -# Check the status (app and secrets are gone, but storage stays): -> juju status -Model Controller Cloud/Region Version SLA Timestamp -teststorage lxd localhost/localhost 3.6.5 unsupported 00:28:44+02:00 - -Model "admin/teststorage" is empty. - -> juju secrets -ID Name Owner Rotation Revision Last updated - -> juju storage -Unit Storage ID Type Pool Size Status Message - pgdata/0 filesystem lxd 5.0 GiB detached -``` - -Re-deploy the postgresql application reusing storage `pgdata/0 `: -```shell -# Create a new Juju User secret -> juju add-secret mypgpass \ - monitoring-password=6inFApK8IyJuJ6LG \ - operator-password=I8mkza6vIhD2w1Rh \ - patroni-password=JAYSlB3mQXi9g4fc \ - raft-password=eFWUOCYb1lIOpGuM \ - replication-password=SFBx8OL9XxXiWwcC \ - rewind-password=92xT4yTniiG7OEch -secret:d09vcn1oie738j7af4ng - -# Re-deploy app with old storage and old passwords -> juju deploy postgresql \ - --channel 16/edge \ - --attach-storage pgdata/0 \ - --config system-users=d09vcn1oie738j7af4ng -Deployed "postgresql" from charm-hub charm "postgresql", revision 613 in channel 16/edge on ubuntu@24.04/stable - -# Grant new application access to manually created Juju User secret -> juju grant-secret mypgpass postgresql - -# Wait for deployment -> juju status -... -Unit Workload Agent Machine Public address Ports Message -postgresql/1* active idle 1 10.189.210.179 5432/tcp Primary - -# Check the old data access once deployment completed (use new App IP!): -> PGPASSWORD=I8mkza6vIhD2w1Rh psql -h 10.189.210.179 -U operator -d postgres -c "\d" - List of relations - Schema | Name | Type | Owner ---------+------+-------+---------- - public | a | table | operator -(1 row) - -# Old storage re-used: -> juju storage -Unit Storage ID Type Pool Size Status Message -postgresql/1 pgdata/0 filesystem lxd 5.0 GiB attached -``` -[/details] \ No newline at end of file diff --git a/docs/how-to/h-migrate-backup-restore.md b/docs/how-to/h-migrate-backup-restore.md deleted file mode 100644 index b3885cc68b..0000000000 --- a/docs/how-to/h-migrate-backup-restore.md +++ /dev/null @@ -1,41 +0,0 @@ -# Migrate database data using ‘backup/restore’ - -This is a guide for migrating data from modern charms. To migrate [legacy charms](/t/11013) data, refer to the guide [Migrate data via pg_dump](/t/10690). - -This Charmed PostgreSQL operator is able to restore its own[backups](/t/9693) stored on [S3-compatible storage](/t/9681). The same restore approach is applicable to restore [foreign backups](/t/9691) made by different Charmed PostgreSQL installation or even another PostgreSQL charm. The backup have to be created manually using [pgBackRest](https://pgbackrest.org/)! - -[note type="caution"] -**Warning:** The Canonical Data Team describes here the general approach and does NOT support nor guarantee the restoration results. - -Always test a migration in a test environment before performing it in production! -[/note] - -## Prerequisites -* **Check [your application compatibility](/t/10690)** with Charmed PostgreSQL VM before migrating production data from legacy charm -* Make sure **PostgreSQL versions are identical** before the migration - -## Migrate database data -Below is the *general approach* to the migration (see warning above!): - -1. **Retrieve root/admin level credentials from legacy charm.** - - See examples [here](/t/12163). - -2. **Install [pgBackRest](https://pgbackrest.org/) inside the old charm OR nearby.** - - Ensure the version is compatible with pgBackRest in the new `Charmed PostgreSQL` revision you are going to deploy! See examples [here](https://pgbackrest.org/user-guide.html#installation). - - **Note**: You can use `charmed-postgresql` [SNAP](https://snapcraft.io/charmed-postgresql)/[ROCK](https://github.com/canonical/charmed-postgresql-rock) directly. More details [here](/t/11857#hld). - -3. **Configure storage for database backup (local or remote, S3-based is recommended).** - -4. **Create a first full logical backup during the off-peak** - - See an example of backup command [here](https://github.com/canonical/postgresql-k8s-operator/commit/f39caaa4c5c85afdb157bd53df54a24a1b9687ac#diff-cc5993b9da2438ecff27897b3ab9d2f9bc445cbf5b4f6369a1a0c2f404fe6a4fR186-R212). - -5. **[Restore the foreign backup](/t/9691) to the Charmed PostgreSQL installation in your test environment.** -6. **Perform all the necessary tests to make sure your application accepted the new database.** -7. **Schedule and perform the final production migration, re-using the last steps above.** - ---- -Do you have questions? [Contact us](/t/11863) if you are interested in such a data migration! \ No newline at end of file diff --git a/docs/how-to/h-upgrade.md b/docs/how-to/h-upgrade.md deleted file mode 100644 index 9a95915cac..0000000000 --- a/docs/how-to/h-upgrade.md +++ /dev/null @@ -1,12 +0,0 @@ -# Upgrade - -Currently, the charm supports PostgreSQL major version 14 only. Therefore, in-place upgrades/rollbacks are not possible for major versions. - -> **Note**: Canonical is not planning to support in-place upgrades for major version change. The new PostgreSQL charm will have to be installed nearby, and the data will be copied from the old to the new installation. After announcing the next PostgreSQL major version support, the appropriate documentation for data migration will be published. - -For instructions on carrying out **minor version upgrades**, see the following guides: - -* [Minor upgrade](/t/12089), e.g. PostgreSQL 14.8 -> PostgreSQL 14.9
-(including charm revision bump 42 -> 43). -* [Minor rollback](/t/12090), e.g. PostgreSQL 14.9 -> PostgreSQL 14.8
-(including charm revision return 43 -> 42). \ No newline at end of file diff --git a/docs/how-to/index.md b/docs/how-to/index.md new file mode 100644 index 0000000000..12c5525a4a --- /dev/null +++ b/docs/how-to/index.md @@ -0,0 +1,131 @@ +# How-to guides + +The following guides cover key processes and common tasks for managing and using Charmed PostgreSQL on machines. + +## Deployment and setup + +Installation of different cloud services with Juju: +* [Sunbeam] +* [MAAS] +* [AWS EC2] +* [GCE] +* [Azure] +* [Multi-availability zones (AZ)][Multi-AZ] + +Other deployment scenarios and configurations: +* [Terraform] +* [TLS VIP access] +* [Air-gapped] +* [Juju storage] + +## Usage and maintenance + +* [Integrate with another application] +* [External access] +* [Scale replicas] +* [Enable TLS] +* [Enable plugins/extensions] +* [Switchover/failover] + +## Backup and restore +* [Configure S3 AWS] +* [Configure S3 RadosGW] +* [Create a backup] +* [Restore a backup] +* [Manage backup retention] +* [Migrate a cluster] + +## Monitoring (COS) + +* [Enable monitoring] with Grafana +* [Enable alert rules] with Prometheus +* [Enable tracing] with Tempo +* [Enable profiling] with Parca + +## Minor upgrades +* [Perform a minor upgrade] +* [Perform a minor rollback] + +## Cross-regional (cluster-cluster) async replication + +* [Cross-regional async replication] + * [Set up clusters] + * [Integrate with a client app] + * [Remove or recover a cluster] + * [Enable plugins/extensions] + +## Development + +This section is for charm developers looking to support PostgreSQL integrations with their charm. + +* [Integrate with your charm] +* [Migrate data via pg_dump] +* [Migrate data via backup/restore] + + + +[Sunbeam]: /how-to/deploy/sunbeam +[MAAS]: /how-to/deploy/maas +[AWS EC2]: /how-to/deploy/aws-ec2 +[GCE]: /how-to/deploy/gce +[Azure]: /how-to/deploy/azure +[Multi-AZ]: /how-to/deploy/multi-az +[TLS VIP access]: /how-to/deploy/tls-vip-access +[Juju spaces]: /how-to/deploy/juju-spaces +[Terraform]: /how-to/deploy/terraform +[Air-gapped]: /how-to/deploy/air-gapped +[Juju storage]: /how-to/deploy/juju-storage + +[Integrate with another application]: /how-to/integrate-with-another-application +[External access]: /how-to/external-network-access +[Scale replicas]: /how-to/scale-replicas +[Enable TLS]: /how-to/enable-tls +[Switchover/failover]: /how-to/switchover-failover + +[Configure S3 AWS]: /how-to/back-up-and-restore/configure-s3-aws +[Configure S3 RadosGW]: /how-to/back-up-and-restore/configure-s3-radosgw +[Create a backup]: /how-to/back-up-and-restore/create-a-backup +[Restore a backup]: /how-to/back-up-and-restore/restore-a-backup +[Manage backup retention]: /how-to/back-up-and-restore/manage-backup-retention +[Migrate a cluster]: /how-to/back-up-and-restore/migrate-a-cluster + +[Enable monitoring]: /how-to/monitoring-cos/enable-monitoring +[Enable alert rules]: /how-to/monitoring-cos/enable-alert-rules +[Enable tracing]: /how-to/monitoring-cos/enable-tracing +[Enable profiling]: /how-to/monitoring-cos/enable-profiling + +[Perform a minor upgrade]: /how-to/upgrade/perform-a-minor-upgrade +[Perform a minor rollback]: /how-to/upgrade/perform-a-minor-rollback + +[Cross-regional async replication]: /how-to/cross-regional-async-replication/index +[Set up clusters]: /how-to/cross-regional-async-replication/set-up-clusters +[Integrate with a client app]: /how-to/cross-regional-async-replication/integrate-with-a-client-app +[Remove or recover a cluster]: /how-to/cross-regional-async-replication/remove-or-recover-a-cluster +[Enable plugins/extensions]: /how-to/enable-plugins-extensions/index + +[Integrate with your charm]: /how-to/development/integrate-with-your-charm +[Migrate data via pg_dump]: /how-to/development/migrate-data-via-pg-dump +[Migrate data via backup/restore]: /how-to/development/migrate-data-via-backup-restore + + +```{toctree} +:titlesonly: +:maxdepth: 2 +:glob: +:hidden: + +Deploy +Integrate +Manage passwords +External network access +Scale +Switchover/failover +Enable TLS +Enable LDAP +Enable plugins/extensions +Back up and restore +Monitoring (COS) +Upgrade +Cross-regional async replication +Development + diff --git a/docs/how-to/h-integrate.md b/docs/how-to/integrate-with-another-application.md similarity index 54% rename from docs/how-to/h-integrate.md rename to docs/how-to/integrate-with-another-application.md index fa8438764e..d14fef771a 100644 --- a/docs/how-to/h-integrate.md +++ b/docs/how-to/integrate-with-another-application.md @@ -1,58 +1,53 @@ -[note] -**Note**: All commands are written for `juju >= v.3.0` +--- +relatedlinks: https://documentation.ubuntu.com/juju/3.6/reference/relation/, [postgresql_client - GitHub](https://github.com/canonical/charm-relation-interfaces/tree/main/interfaces/postgresql_client/v0) -If you are using an earlier version, check the [Juju 3.0 Release Notes](https://juju.is/docs/juju/roadmap#heading--juju-3-0-0---22-oct-2022). -[/note] +--- # How to integrate with another application -[Integrations](https://juju.is/docs/juju/relation) (formerly “relations”) are connections between two applications with compatible endpoints. These connections simplify the creation and management of users, passwords, and other shared data. +[Integrations](https://juju.is/docs/juju/relation), also known as “relations” are connections between two applications with compatible endpoints. These connections simplify the creation and management of users, passwords, and other shared data. This guide shows how to integrate Charmed PostgreSQL with both charmed and non-charmed applications. -> For developer information about how to integrate your own charmed application with PostgreSQL, see [Development > How to integrate with your charm](/t/11865). - -## Summary -* [Integrate with a charmed application](#integrate-with-a-charmed-application) - * [Modern interface](#modern-interface) - * [Legacy interface](#legacy-interface) -* [Integrate with a non-charmed application](#integrate-with-a-non-charmed-application) -* [Rotate application passwords](#rotate-application-passwords) - ---- +For developer information about how to integrate your own charmed application with PostgreSQL, see [](/how-to/development/integrate-with-your-charm). ## Integrate with a charmed application Integrations with charmed applications are supported via the modern [`postgresql_client`](https://github.com/canonical/charm-relation-interfaces/blob/main/interfaces/postgresql_client/v0/README.md) interface, and the legacy `psql` interface from the [original version](https://launchpad.net/postgresql-charm) of the charm. -[note] -You can see which existing charms are compatible with PostgreSQL in the [Integrations](https://charmhub.io/postgresql/integrations) tab. -[/note] +```{note} +You can see which existing charms are compatible with PostgreSQL in the [Integrations](https://charmhub.io/postgresql/integrations) tab on Charmhub. +``` ### Modern `postgresql_client` interface + To integrate with a charmed application that supports the `postgresql_client` interface, run -```shell + +```text juju integrate postgresql:database ``` To remove the integration, run -```shell + +```text juju remove-relation postgresql ``` ### Legacy `pgsql` interface -[note type="caution"] -Note that this interface is **deprecated**. -See the [legacy charm explanation page](/t/10690). -[/note] + +```{caution} +Note that this interface is **deprecated**. See [](/explanation/legacy-charm). +``` To integrate via the legacy interface, run - ```shell + + ```text juju integrate postgresql:db ``` Extended permissions can be requested using the `db-admin` endpoint: -```shell + +```text juju integrate postgresql:db-admin ``` @@ -61,38 +56,28 @@ juju integrate postgresql:db-admin To integrate with an application outside of Juju, you must use the [`data-integrator` charm](https://charmhub.io/data-integrator) to create the required credentials and endpoints. Deploy `data-integrator`: -```shell +```text juju deploy data-integrator --config database-name= ``` Integrate with PostgreSQL: -```shell +```text juju integrate data-integrator postgresql ``` Use the `get-credentials` action to retrieve credentials from `data-integrator`: -```shell +```text juju run data-integrator/leader get-credentials ``` ## Rotate application passwords To rotate the passwords of users created for integrated applications, the integration should be removed and integrated again. This process will generate a new user and password for the application. -```shell +```text juju remove-relation postgresql juju integrate postgresql ``` ->`` can be `data-integrator` in the case of connecting with a non-charmed application. - -### Internal operator user -The operator user is used internally by the Charmed PostgreSQL application. The `set-password` action can be used to rotate its password. -To set a specific password for the operator user, run -```shell -juju run postgresql/leader set-password password= -``` +In the case of connecting with a non-charmed application, `` would be `data-integrator`. -To randomly generate a password for the `operator` user, run -```shell -juju run postgresql/leader set-password -``` \ No newline at end of file +See also: [](/how-to/manage-passwords) diff --git a/docs/how-to/manage-passwords.md b/docs/how-to/manage-passwords.md new file mode 100644 index 0000000000..b6317f1739 --- /dev/null +++ b/docs/how-to/manage-passwords.md @@ -0,0 +1,32 @@ +# How to manage passwords + +In Charmed PostgreSQL 14, user credentials are managed with Juju's `get-password` and `set-password` actions. + +## Get password + +To retrieve the operator's password: + +```text +juju run postgresql/leader get-password +``` + +## Set password + +To change the operator's password to a new, randomized password: + +```text +juju run postgresql/leader set-password +``` + +To set a manual password for the operator/admin user: + +```text +juju run postgresql/leader set-password password= +``` + +To set a manual password for another user: + +```text +juju run postgresql/leader set-password username= password= +``` + diff --git a/docs/how-to/monitoring-cos/alert-rules-grafana-ui.png b/docs/how-to/monitoring-cos/alert-rules-grafana-ui.png new file mode 100644 index 0000000000000000000000000000000000000000..9a64d01494882bd9c19f006e476e30006da1bdf3 GIT binary patch literal 274677 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 o9X!Z)%y3-N@Ir{oq7)Kon* z^B5VVNj@&W)ft=N4LGFQT27Tw3wv|-&HX{=3AW(xWQ=i({LJT_{mH>CeU>(#Rj$CE?rZQ1tgLLw zw|$HYhq2k_Vkf?BOas4L)`$pep7rzS57M7mbh~mAzw*Y)qExLHXEGlTDt`0=^|VHx z@VlC2#7`E=U>&4Mp5RwsIGNtfH8f*6s2CY8YCcv0gK=q9p_gM^&PO2|$GY7)>h)=A zM<~?_>zAl@_Fq_?Sky!wtN6A9d!m0=zXl`b_Mjr^PDG{IU~KzlEE_G68}wk(u<+$( z>o8z;%Wbs0ZQq`)h7q(xlzRRFCfF8GTuSOgpYCkB@T^4=!u0J4lpQPvlQ5Q?iMnHo z1J|}sv0kIX5KXQd=KlEUnT8&YGw8pljXY*V89z2SW;AhKZO^8rC2GSEAiciqza!b) zZWwIFI_GZ8{;)9n7F{{B%?4gA?JElK)R(O0k{Bx22kd78!CXl~;&fg?6v^Ym8#jK% zoz(h8)t+nkW&s4K;XjN1J=JGN-z!%tp8!PPS*e|)EbEgJYgdHhl#d7?qnaWPhf&4~ zI#0x=I$AA&SmdB~uf=-uclQqEW%_P&Eu5XM}ph5Jn>Ezd>4yfeXdtTY0d`>pl zMls^C zPwkkE;+rp`una1LvI2TbaCGqyHDEVJTqQ&i8ir+-K(Mq4q5p_~EL70x5wFsOd(I^} z=13FlZQ|$*%h5y7d(ks+cm#aDz}@?Tlj>qC8h=j%*j{EOu?YyD+%}-?9TK|>QGt5M zm*tfdDE=DP7aPNueMfNn4>VsAqr>suTkrovDI*6ofSY=iuiueU$qL`~;FuFP7wDZK zY&2PAOP0=}++*8+GHCI$=WQbZSm*=NsEL_!Y~zzW+cT@+*KYK}Eq{b|KZK#g_%C@g zIiTJ6N8#KJE)>M8Cg)8dt86SPi7+zQ|8csgW{nPU@fC{2_|1>m z=H!70=uH{4adw(Us=>es2S{Tg_B0uNEcCsy-|6P- z@pFPp5oxE1$bO~%DIywAt(nr?RcBj^V7&Vcg$|ETchqpgDFAu9@{KsuAyvOYS13|g zT5QZn%9Ts}>`oPo((!a<0 zt;64q%Xz0h^}$qUq|c%Y|6yz=r{Q2ZvY2ttdD!{dJ6LCP(d|oqtk~M5(g_1Oo$5K) z^;$-6L?H}-i}Vs}2Ep^+ACTy^YT<8)pp3)W+Iz`9Hm!HGUfMow(w|gsH28TeQege7 z;xXp#l-#WMO}U`v;ewdtaT<1J? z(0xO$O{!DDlx50C6Ss>|y|VgTi#@VIh*!c_(eza)HGMrPVz6rR_F$Ap*IlH1@YVYI z?PS%{=jYtZ+oeVd(lDl?7<|x2i4XGrYy_VX*5lRp<%9r1$X{ZVxOxe=qX}Uyd;zmYMKO*hD_z3wJ znx8rEt+{|(@3X+d7EFBsc}#X>vF(Yw+AM52{9PFVhY{ZcYQD>`VVk!V`_SvYevHj+ z)%Q}~sa;=phn>OUX5JZ;^2KwtZ~j`tgseiqCY>3M z+K^CtaNG97nMFd&JB2dBYQ!8>8RfXkiti>B;huke|MG+;00f{I|BybmBVA7RZ?qbpD^P;`?I89bYDsXg!__mwo5p{|0fTZ_q3=^g1}q zJ6=7On!o3N$7-;_J5=P^vZ_gGQC55bRAvZFlcS zLKU32?-(-tG?AlBeJLq608R|~^ePZxL=%SHZtaH%#Y~L&O3ObSW z%hf@8V0Yb7dZyXpdV4kJ2l8nv#dbQaaMxkTpzCeGTIL0FbUyc6wJ@ZWqdIQc!p?qD zt44otKa{dC;G14~)T1U`bAWsEI}=Ts$~F@13O_!N+Mk*sOyc{!0sBQXPHN!uTXRO<^!t$cDK=rF1-lh=gPb!ZcV#Uz0SN5bx+(mryA*nSro5G6CHnvg z9cWNpnZOA7Al)xGDWtmY@u*rNA>}7l=W=)P?i{tXa4$UU0&ef00l%XAm*hUebyS^A z7_4hKP6tZm9l}b(%V6v+_wT`zRaGmbvY;Muq=~~JT!U3o9ItjpT&j11!^{H&+a903 z>+6Y9?6maV-m6bE-0?P7niEb)-F+H5t7r@LG@&wqC(h@~Zm>l>^DGYRN*lMsODMUa zHV=zW!V6vDif0o-hWqu)x4pn#8#6Rm-9hyC9~BCod#o4umbFR7#q7C$Vx2#xuesjT z8PVg(xoUg>9wW&R?7htGyF6P;6ZMzShvE2z&s!+LxvWAEN*DmL8h)ZvpUW3%S`H4n zIlEzBy2XYjdtm6j2^76I>uE#?0%Js7GKFjsaJVvnm}JZr`!%0&kq0qU)ia8YS1?s2ripYne>?lw&ubl9@;LB;y9~MJB zZrUiVF{*|SC?MdWNbAi~%}cs<5FL38$+Tl%Z?sEsQ&_#?O!B>^KQ8{7K*E!?ST$Bd z!i(jt#0OvD1GV}K;Z9Te_Dx^}BP;zCu{)-)7e4Jk_)AWlT@|H2DgT(qCA7_#pa44@ z>Elq$doi|H#bSiCr_Fh8r*Y=(a%B##_hosgy-a9PJLP1KaoBmRKEWpCjW|*>FIgR$>e67cV7!HH2>@G@bPrK*jig=2j($rqaYG& z>MA6JiXvtk#}(0+4Eb2)FQu*OXy$%GBT+r^;J-<(=T}AeyT7Lw3H{?rF*(-Xn1R}M z{1E@Qjq`JAqw#D-9Z+&G=yWaHMU*;Q5N6QvG5OEcmcu&DHO}k=CHX*QJx#(dR<`PN zNp`;YGz!O)=cKRp4im|Cx{BIYE%lQ03u-Bof8iYnohgzR-r}_1I7J1UoCP1?v2i{& z@S%Fqrz_-8yT}K|GTJS|s2Q@IadN@n_*{E-Y(h8zIBXVIHmmueOTqz%racP;9<45tf4F+)%k=;pcqHK5mdv+ zNt5>uYwR85mltnGN=#!wv6{`19L}afl$`*;pXvc?E+YZ8?>m1IT^MqL#3c{*LBT7W zj9H^p6L!cvvH*eB5*p*SIt1b8(uKIyu%7V-17*s;J;Kq<7WCC6T*9o;P8YU*_w^o8 zW;z}=)60WqeVvUJ0uXWA5=S+>6#C5|S5Bjkw)*;osWz>aS)4H4WDJu6{}MT6>0PoS1obCCcc-ajz2Hr^y;OBHnWZWm?keB0(pE!rZSL4SJX| zSGQm3Z(DqQa$-uMs=zXrfTzttsftgv_Zuw!Py1muY{Hr5^GRAGPb<+_h> zf2Mdx4>T5>x=m%LudXUiurB?J_Ss5#4p!vF3qKQlX}oml zOXy?BA52<9y3%j4j&3?RCyY2O941VWWi_3>csWt>T-nV{HrS*0_M1g?H{G%txaBDr z-+gwZi5(bjKY^!+XYlPc2n;1%G)T_GQO-0OWdi8bF*=rv~MYdSdm8wHS7 z%MKgRLp!iPBu$SJ+S}G zfBMcW-v`waAaR}OK%l|vek#UAZ#}SoXejh-Rq1*6l=lIwVbhr_^}yx#!o=~=eZPe*YNslfFljlnY1ycoNwI60)neh_>vCuPlyn9h+jY8TjaiZO2Y}-XglNBvvLslYah~Hbbz83GeY(k>@sA^rXGw5IUO`78 zUuR!D(Q`<+qv;oF2VY{YPha}oji929b$TAf0%n()jn?bHt&|cE=keivYvZ`YyS@i% z@}2x!?Q(>Mux8w8Gjl@1zp|l3UJ@+%RSdjw=>0tU-@O3K&nt;*t1v_2&i4yoaLfyo z#5tz?l)!l@`H?=o@0=3w3^z{hjWOTbv2(UI(pIfHQjvZAs7Tg~v&YM~{|hDi^^Ecj^4K_mC8@3PeJB?EImW@`$U2*4dGBHvV-RXI|HhYDEh=z63S z|LLA(uxBGY%_=LnAzx65a9JJtyr^Ie zt9BJe2;S%l3%3d8*^?VwqC*_j*~I<-uz|#>|0V|n{=r=9_hUR+{7Ve9J-`JQU4~1A zgw8x2k=-D27+<*k8Kds(k&4L}J}{aNx<3mnv%wS}TrNCVZ)xl>TC!+fn8$s`glt(s z;R}gu6ajH-G;QuEgNt-9vvTJ>;r%?Q5&Xtx+&0$hwk$zS}Qe(er(%?Kn>1zU6?0?H_+vZ7sNcg#uQAkrTh(S~MWFg8s@% z6_B{x@KUVHex4Skdj5Gs$2X)#)Xf>si-j2^>f9vW{RMKO_Fsiva2iTX4JKn+Evr)Zttj5eAC#X9i56Y2_i^zdv^sT z*8>|y_UjOsUr3tUtZBx6yIysxzqn##zu~(iJp+)a&@vl#UBNhXPyV?P+51b; zkMZAd>S<59!J>`6^vTJK8OuNVz}e~>rOq}1)gn)d!1-ihLV%uwmoDjea*y5t9#K@+ z-1^-7OdDK}!QFq&%-Z!X9M7w&@9w-)3^^qwwCax65)?n|3khlTu>M2WItSnye=0Y@ zhcLu*@L*I(^=VT~z$j6`iykalUzEu6r6V^OM;(i3LsCkX{7z#wn!&lQErjvK@U>YT zN6@;3e=*kJ?xwPt+2MwaL@BP`NY>NNVeU6~`)zdv4MHyqJ>uPPLsh_Q9G!s5gNTCtPnXX7t zg{tffUPgNE1)DWG^kg%xH=4l`_@Hr-6pQ3-a&MwcQFJ3^_*pV2?+%34$q@+WEcTdF zA*2yzlYkH8d23&R$3AHj(%p_8!xslr2v`%N(Qb({VzF-uUJ;X#-E5 zuVD+Q=6*hjgn^v74Y>N9NTedgs<-;TjtHpM#QfBE|_HUuN`r8*7>esi?+I}gGRQM+0qQUtwt0rv^B}iEQTYKnY<#bWqR@)ASsP0Xu*Q? zTd88>vbH`k^NOY%IrCxk$H~z{Yo4c~wR*+o07Mvti03AI)FgJ2rnoS;fj7r&`t00- zq;#xtrHxN$7~jK>+)2dR+M3fzt?!eU;(zj)46)C2-6LA3w ztOvRxY%sWg2vh6~Es6%uVR)c+glBFC
Oo?y4;SNWl>Y6XRb;I3PN#rON$N3TFaq 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

PjwaR!Ht_|N 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 mNRVZ_pUnb!XGom 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 SOY*k8 literal 0 HcmV?d00001 diff --git a/docs/how-to/h-enable-alert-rules.md b/docs/how-to/monitoring-cos/enable-alert-rules.md similarity index 89% rename from docs/how-to/h-enable-alert-rules.md rename to docs/how-to/monitoring-cos/enable-alert-rules.md index 52638adcb8..dab0c5dbd4 100644 --- a/docs/how-to/h-enable-alert-rules.md +++ b/docs/how-to/monitoring-cos/enable-alert-rules.md @@ -1,4 +1,4 @@ -# How to enable COS Alert Rules +# How to enable COS alert rules This guide will show how to set up [Pushover](https://pushover.net/) to receive alert notifications from the COS Alert Manager with [Awesome Alert Rules](https://samber.github.io/awesome-prometheus-alerts/). @@ -6,23 +6,25 @@ Charmed PostgreSQL VM ships a pre-configured and pre-enabled [list of Awesome Al

Screenshot of alert rules in the Grafana web interface -![Screenshot from 2024-01-18 20-05-52|690x439](upload://j6WSPQ1BzoFzqIg2jm1mTq79SMo.png) +![Alert rules Grafana web UI|690x439](alert-rules-grafana-ui.png)
For information about accessing and managing COS Alert Rules, refer to the [COS documentation](https://charmhub.io/cos-lite). ## Prerequisites + * A deployed [Charmed PostgreSQL VM operator] * A deployed [`cos-lite` bundle in a Kubernetes environment](https://charmhub.io/topics/canonical-observability-stack/tutorials/install-microk8s) * Fully configured [COS Monitoring] ## Enable COS alerts for Pushover + The following section is an example of the [Pushover](https://pushover.net/) alerts aggregator. The first step is to create a new account on Pushover (or use an existing one). The goal is to have the 'user key' and 'token' to authorize alerts for the Pushover application. Follow this straightforward [Pushover guide](https://support.pushover.net/i175-how-to-get-a-pushover-api-or-pushover-application-token). Next, create a new [COS Alert Manager](https://charmhub.io/alertmanager-k8s) config (replace `user_key` and `token` with yours): -```shell +```text cat > myalert.yaml << EOF ``` ```yaml @@ -52,8 +54,10 @@ receivers: templates: [] EOF ``` + Upload and apply newly the created alert manager config: -``` + +```text juju switch : juju config alertmanager config_file=@myalert.yaml ``` @@ -62,7 +66,7 @@ At this stage, the COS Alert Manager will start sending alert notifications to P The image below shows an example of the Pushover web client: -![image|690x439](upload://vqUcKpZ5R4wQLmY2HYGV5fz5pNU.jpeg) +![Pushover web client|690x439](pushover-client.jpeg) ## Alert receivers @@ -71,7 +75,7 @@ The similar way as above, COS alerts can be send to the long [list of supported Do you have questions? [Contact us]! -[Contact us]: /t/11852 -[Charmed PostgreSQL VM operator]: /t/9697 -[COS Monitoring]: /t/10600 -[list of Awesome Alert Rules]: /t/15841 \ No newline at end of file +[Contact us]: /reference/contacts +[COS Monitoring]: /how-to/monitoring-cos/enable-monitoring +[list of Awesome Alert Rules]: /reference/alert-rules + diff --git a/docs/how-to/h-enable-monitoring.md b/docs/how-to/monitoring-cos/enable-monitoring.md similarity index 88% rename from docs/how-to/h-enable-monitoring.md rename to docs/how-to/monitoring-cos/enable-monitoring.md index 26eae39bc7..5c2386316b 100644 --- a/docs/how-to/h-enable-monitoring.md +++ b/docs/how-to/monitoring-cos/enable-monitoring.md @@ -1,42 +1,46 @@ -[note] -**Note**: All commands are written for `juju >= v.3.0` - -If you are using an earlier version, check the [Juju 3.0 Release Notes](https://juju.is/docs/juju/roadmap#heading--juju-3-0-0---22-oct-2022). -[/note] - -# How to enable monitoring (COS) +# How to enable monitoring ## Prerequisites -* Charmed PostgreSQL [Revision 336 or greater](/t/11875) + * [`cos-lite` bundle](https://charmhub.io/topics/canonical-observability-stack/tutorials/install-microk8s) deployed in a Kubernetes environment ---- +## Offer interfaces via the COS controller First, switch to the COS K8s environment and offer COS interfaces to be cross-model integrated with the Charmed PostgreSQL VM model. To switch to the Kubernetes controller for the COS model, run -```shell + +```text juju switch : ``` + To offer the COS interfaces, run -```shell + +```text juju offer grafana:grafana-dashboard grafana juju offer loki:logging loki juju offer prometheus:receive-remote-write prometheus ``` + ## Consume offers via the PostgreSQL model + Next, we will switch to the Charmed PostgreSQL VM model, find offers, and consume them. We are currently on the Kubernetes controller for the COS model. To switch to the PostgreSQL model, run -```shell + +```text juju switch : ``` + To find offers, run -```shell + +```text juju find-offers :admin/ ``` + The output should be similar to the sample below, where `k8s` is the k8s controller name and `cos` is the model where `cos-lite` has been deployed: -```shell + +```text Store URL Access Interfaces k8s admin/cos.grafana admin grafana_dashboard:grafana-dashboard k8s admin/cos.loki admin loki_push_api:logging @@ -45,31 +49,43 @@ k8s admin/cos.prometheus admin prometheus-receive-remote-write:receive-remo ``` To consume offers to be reachable in the current model, run -```shell + +```text juju consume :admin/cos.prometheus juju consume :admin/cos.loki juju consume :admin/cos.grafana ``` + ## Deploy and integrate Grafana + First, deploy the [`grafana-agent`](https://charmhub.io/grafana-agent) subordinate charm. -```shell + +```text juju deploy grafana-agent ``` + Then, integrate (previously known as "relate") it with PostgreSQL -```shell + +```text juju integrate postgresql:cos-agent grafana-agent ``` - Finally, integrate `grafana-agent` with consumed COS offers: -```shell + +Finally, integrate `grafana-agent` with consumed COS offers: + +```text juju integrate grafana-agent grafana juju integrate grafana-agent loki juju integrate grafana-agent prometheus ``` + After this is complete, Grafana will show the new dashboard `PostgreSQL Exporter` and will allow access to Charmed PostgreSQL logs on Loki. ### Sample outputs + Below is a sample output of `juju status` on the Charmed PostgreSQL VM model: -```console + + +```text ubuntu@localhost:~$ juju status Model Controller Cloud/Region Version SLA Timestamp vmmodel local localhost/localhost 2.9.42 unsupported 00:12:18+02:00 @@ -92,7 +108,8 @@ Machine State Address Inst id Series AZ Message ``` Example of `juju status` on a COS K8s model: -```console + +```text ubuntu@localhost:~$ juju status Model Controller Cloud/Region Version SLA Timestamp cos k8s microk8s/localhost 2.9.42 unsupported 00:15:31+02:00 @@ -120,11 +137,14 @@ prometheus prometheus prometheus-k8s 103 1/1 receive-remote-write ``` ### Connect Grafana web interface -To connect to the Grafana web interface, follow the [Browse dashboards](https://charmhub.io/topics/canonical-observability-stack/tutorials/install-microk8s?_ga=2.201254254.1948444620.1704703837-757109492.1701777558#heading--browse-dashboards) section of the MicroK8s "Getting started" guide. -```shell + +To connect to the Grafana web interface, follow the [Browse dashboards](https://charmhub.io/topics/canonical-observability-stack/tutorials/install-microk8s?_ga=2.201254254.1948444620.1704703837-757109492.1701777558#browse-dashboards) section of the MicroK8s "Getting started" guide. + +```text juju run grafana/leader get-admin-password --model : ``` -### Example of Charmed PostgreSQL on Grafana +Below is a sample screenshot of Charmed PostgreSQL on the Grafana web UI: + +![Charmed PostgreSQL Grafana web UI|690x353](postgresql-grafana-ui.png) -![image|690x353](upload://c7LEKHwQJ25t7BkkR5S9hhs9d4Q.png) \ No newline at end of file diff --git a/docs/how-to/h-enable-profiling.md b/docs/how-to/monitoring-cos/enable-profiling.md similarity index 68% rename from docs/how-to/h-enable-profiling.md rename to docs/how-to/monitoring-cos/enable-profiling.md index aabc52bc34..b1f2d3acca 100644 --- a/docs/how-to/h-enable-profiling.md +++ b/docs/how-to/monitoring-cos/enable-profiling.md @@ -1,73 +1,63 @@ -[note] -**Note**: All commands are written for `juju >= v3.1` - -If you're using `juju 2.9`, check the [`juju 3.0` Release Notes](https://juju.is/docs/juju/roadmap#heading--juju-3-0-0---22-oct-2022). -[/note] - # Enable profiling with Parca -This guide contains the steps to enable profiling with [Parca](https://www.parca.dev/docs/overview/) for your PostgreSQL application. +This guide contains the steps to enable profiling with [Parca](https://www.parca.dev/docs/overview/) for your PostgreSQL application. -## Summary -* [Prerequisites](#prerequisites) -* [Set up the Parca backend](#set-up-the-parca-backend) - * [Charmed Parca K8s](#charmed-parca-k8s) - * [Polar Signals Cloud](#polar-signals-cloud) -* [View profiles](#view-profiles) - ---- +```{important} +Read the [](#prerequisites) section carefully if you are deploying PostgreSQL in an **LXD model** or if your **base is `ubuntu@22.04`**. +``` ## Prerequisites -[note type=caution] -**Do not skip this section** if you are deploying PostgreSQL in an LXD model or if your base is `ubuntu@22.04`. -[/note] - - -This guide assumes you already have a juju model with Charmed PostgreSQL deployed. - -> See: [How to deploy PostgreSQL](/t/16811) - -In order for your Charmed PostgreSQL deployment to be correctly set up for integration with Parca, there are two important considerations: -* [LXD virtualization type](#lxd-virtualization-type) -* [Base (Ubuntu version)](#base-ubuntu-version) +* A juju model with [Charmed PostgreSQL deployed](/how-to/deploy/index). +* **If you are using an LXD model**, LXD's virtualization type must be set to `virtual-machine`. + * See [](#lxd-virtualization-type) for more details. +* **If your base is `ubuntu@22.4`**, you must use the `generic` flavor of Linux. + * See [](#base-ubuntu-version) for more details. ### LXD virtualization type -**If you are deploying Charmed PostgreSQL in a LXD model, you will need to ensure that LXD's virtualization type is set to `virtual-machine` for the Juju application.** +If you are deploying Charmed PostgreSQL in a LXD model, ensure that LXD's virtualization type is set to `virtual-machine` for the Juju application. This is because LXD does not allow `/sys/kernel/tracing` to be mounted in a system container (even in privileged mode) due to security isolation concerns. To ensure that a virtual machine is used instead of a system container, you would need to add constraints, for example: -``` -juju deploy postgresql --constraints="virt-type=virtual-machine"`. + +```text +juju deploy postgresql --channel 14/stable --constraints="virt-type=virtual-machine"`. ``` ### Base (Ubuntu version) -**If your base is `ubuntu@22.04`, you will need to ensure that your are using the `generic` flavor of Linux.** -> See the output of `uname -r` to confirm. +If your base is `ubuntu@22.04`, ensure that your are using the `generic` flavor of Linux. + +You can confirm this with +``` +uname -r +``` If you do not have the `generic` flavor, you can enable it on a unit to be profiled as follows: -``` +```text juju ssh postgresql/0 bash sudo apt-get update && sudo apt-get install linux-image-virtual sudo apt-get autopurge linux-image-kvm ``` If your application is deployed in an LXD model, run the following command: -``` + +```text rm /etc/default/grub.d/40-force-partuuid.cfg ``` Open the `/etc/default/grub` file with your editor of choice and replace the line that starts with `GRUB_DEFAULT=` with: -``` + +```text release=$(linux-version list | grep -e '-generic$' | sort -V | tail -n1) GRUB_DEFAULT="Advanced options for Ubuntu>Ubuntu, with Linux $release" ``` Exit out of the `/etc/default/grub file`, update GRUB, and reboot: -``` + +```text sudo update-grub sudo reboot ``` @@ -84,17 +74,19 @@ There are two potential backends: This section goes through the steps for enabling profiling with Charmed Parca K8s as the backend. +(deploy-cos-lite-and-parca-k8s)= #### 1. Deploy `cos-lite` and `parca-k8s` Refer to [Getting started on MicroK8s](https://charmhub.io/topics/canonical-observability-stack/tutorials/install-microk8s) and deploy the `cos-lite` bundle from the `latest/edge` track in a Kubernetes environment. Then, refer to [Deploy Charmed Parca on top of COS-lite](https://discourse.charmhub.io/t/how-to-deploy-charmed-parca-on-top-of-cos-lite/16579) to deploy Charmed Parca K8s in the same model as the `cos-lite` bundle. +(parca-offer-interfaces)= #### 2. Offer interfaces Offer interfaces for cross-model integrations: -``` +```text juju offer :parca-store-endpoint ``` @@ -102,7 +94,7 @@ juju offer :parca-store-endpoint Switch to the model containing the Charmed PostgreSQL deployment, deploy Charmed Parca Agent, and integrate it with Charmed PostgreSQL: -``` +```text juju switch : juju deploy parca-agent --channel latest/edge @@ -111,29 +103,32 @@ juju integrate postgresql parca-agent #### 4. Integrate `parca-agent` with `parca-k8s` -Consume the parca offer from [Step 2](#2-offer-interfaces) and integrate with them: +Consume the parca offer from [Step 2](#parca-offer-interfaces) and integrate with them: -``` +```text juju find-offers : ``` -> :exclamation: Do not miss the colon "`:`" in the command above. +```{tip} +Do not miss the colon "`:`" in the command above. +``` Below is a sample output where `k8s` is the K8s controller name and `cos` is the model where `cos-lite` and `parca-k8s` are deployed: -``` +```text Store URL Access Interfaces k8s admin/cos.parca admin parca_store:parca-store-endpoint ``` Next, consume this offer so that is reachable from the current machine model: -``` +```text juju consume k8s:admin/cos.parca ``` Finally, relate Charmed Parca Agent with the consumed offer endpoint: -``` + +```text juju integrate parca-agent parca ``` @@ -141,17 +136,19 @@ juju integrate parca-agent parca This section goes through the steps for enabling profiling with Polar Signals Cloud (PSC) as the backend. -[note] -With PSC, `cos-lite` and `parca-k8s` are not required. This section goes through the recommended setup, where `polar-signals-cloud-integrator` is deployed in the same model as `postgresql`, and `parca-agent` is used to relay traffic to PSC. +```{note} +With PSC, `cos-lite` and `parca-k8s` are not required. -If you would like to use `parca-k8s` to relay traffic to PSC instead, refer to [Steps 1 and 2](#1-deploy-cos-lite-and-parca-k8s) in the Charmed Parca K8s section. -[/note] +This section goes through the recommended setup, where `polar-signals-cloud-integrator` is deployed in the same model as `postgresql`, and `parca-agent` is used to relay traffic to PSC. + +If you would like to use `parca-k8s` to relay traffic to PSC instead, refer to [Steps 1 and 2](#deploy-cos-lite-and-parca-k8s) in the Charmed Parca K8s section. +``` #### 1. Deploy and integrate `parca-agent` with `postgresql` In the machine model where PostgreSQL is deployed, deploy `parca-agent` and integrate it with `postgresql`: -``` +```text juju deploy parca-agent --channel latest/edge juju integrate postgresql parca-agent ``` @@ -167,8 +164,9 @@ After the backend setup is complete, the profiles for the machines where the Pos If you are running Charmed Parca K8s, you can also access the link for Parca's web interface from COS catalogue (`juju run traefik/0 show-proxied-endpoints` in the K8s model where `cos-lite` is deployed). -![Example profile with Parca Web UI690x753](upload://zFOOKY8nokrg2Q4xUVTbD8UGjD3.png) +![Example profile with Parca Web UI690x753](profile-parca-web-ui.png) Furthermore, if you have `cos-lite` deployed, you can use Grafana to explore profiles under the `Explore` section with `parca-k8s` as the data source. -![Example profile with Grafana's Parca plugin|690x383](upload://w3G5STYOxMZHCpIA48gEJHUniLi.jpeg) \ No newline at end of file +![Example profile with Grafana's Parca plugin|690x383](profile-grafana-parca-plugin.png) + diff --git a/docs/how-to/h-enable-tracing.md b/docs/how-to/monitoring-cos/enable-tracing.md similarity index 72% rename from docs/how-to/h-enable-tracing.md rename to docs/how-to/monitoring-cos/enable-tracing.md index da7bdfb927..856bcd56bb 100644 --- a/docs/how-to/h-enable-tracing.md +++ b/docs/how-to/monitoring-cos/enable-tracing.md @@ -1,101 +1,92 @@ -[note] -**Note**: All commands are written for `juju >= v3.1` - -If you're using `juju 2.9`, check the [`juju 3.0` Release Notes](https://juju.is/docs/juju/roadmap#heading--juju-3-0-0---22-oct-2022). -[/note] - # Enable tracing This guide contains the steps to enable tracing with [Grafana Tempo](https://grafana.com/docs/tempo/latest/) for your PostgreSQL application. -To summarize: -* [Deploy the Tempo charm in a COS K8s environment](#heading--deploy) -* [Offer interfaces for cross-model integrations](#heading--offer) -* [Consume and integratre cross-model integrations](#heading--consume) -* [View PostgreSQL traces on Grafana](#heading--view) - -[note type="caution"] -**Warning:** This is feature is in development. It is **not recommended** for production environments. - -This feature is available for Charmed PostgreSQL revision 421+ only. -[/note] +```{caution} +This is feature is in development. It is **not recommended** for production environments. +``` ## Prerequisites + Enabling tracing with Tempo requires that you: -- Have deployed a Charmed PostgreSQL application - - See [How to scale units](https://discourse.charmhub.io/t/charmed-postgresql-how-to-scale-units/9689) -- Have deployed a 'cos-lite' bundle from the `latest/edge` track in a Kubernetes environment + +- Have deployed Charmed PostgreSQL revision 421+ + - See [](/how-to/deploy/index) +- Have deployed a `cos-lite` bundle from the `latest/edge` track in a Kubernetes environment - See [Getting started on MicroK8s](https://charmhub.io/topics/canonical-observability-stack/tutorials/install-microk8s) ---- -

Deploy Tempo

+## Deploy Tempo First, switch to the Kubernetes controller where the COS model is deployed: -```shell +```text juju switch : ``` + Then, deploy the dependencies of Tempo following [this tutorial](https://discourse.charmhub.io/t/tutorial-deploy-tempo-ha-on-top-of-cos-lite/15489). In particular, we would want to: - Deploy the minio charm - Deploy the s3 integrator charm - Add a bucket into minio using a python script - Configure s3 integrator with the minio credentials -Finally, deploy and integrate with Tempo HA in [a monolithic setup](https://discourse.charmhub.io/t/tutorial-deploy-tempo-ha-on-top-of-cos-lite/15489#heading--deploy-monolithic-setup). +Finally, deploy and integrate with Tempo HA in [a monolithic setup](https://discourse.charmhub.io/t/tutorial-deploy-tempo-ha-on-top-of-cos-lite/15489#deploy-monolithic-setup). -

Offer interfaces

+## Offer interfaces Next, offer interfaces for cross-model integrations from the model where Charmed PostgreSQL is deployed. To offer the Tempo integration, run -```shell +```text juju offer :tracing ``` Then, switch to the Charmed PostgreSQL model, find the offers, and integrate (relate) with them: -```shell +```text juju switch : juju find-offers : ``` -> :exclamation: Do not miss the "`:`" in the command above. +```{tip} +Don't miss the "`:`" in the command above. +``` Below is a sample output where `k8s` is the K8s controller name and `cos` is the model where `cos-lite` and `tempo-k8s` are deployed: -```shell +```text Store URL Access Interfaces k8s admin/cos.tempo admin tracing:tracing ``` Next, consume this offer so that it is reachable from the current model: -```shell +```text juju consume k8s:admin/cos.tempo ``` -

Consume interfaces

+## Consume interfaces First, deploy [Grafana Agent](https://charmhub.io/grafana-agent) from the `latest/edge` channel. -```shell + +```text juju deploy grafana-agent --channel latest/edge ``` Then, integrate Grafana Agent with Charmed PostgreSQL: -```shell +```text juju integrate postgresql:cos-agent grafana-agent:cos-agent ``` Finally, integrate Grafana Agent with the consumed interface from the previous section: -```shell +```text juju integrate grafana-agent:tracing tempo:tracing ``` Wait until the model settles. The following is an example of the `juju status --relations` on the Charmed PostgreSQL model: -```shell +```text Model Controller Cloud/Region Version SLA Timestamp database lxd localhost/localhost 3.5.4 unsupported 21:43:34Z @@ -122,16 +113,17 @@ postgresql:upgrade postgresql:upgrade upgrade pee tempo:tracing grafana-agent:tracing tracing regular ``` -[note] -**Note:** All traces are exported to Tempo using HTTP. Support for sending traces via HTTPS is an upcoming feature. -[/note] +```{note} +All traces are exported to Tempo using HTTP. Support for sending traces via HTTPS is an upcoming feature. +``` -

View traces

+## View traces After this is complete, the Tempo traces will be accessible from Grafana under the `Explore` section with `tempo-k8s` as the data source. You will be able to select `postgresql` as the `Service Name` under the `Search` tab to view traces belonging to Charmed PostgreSQL. Below is a screenshot demonstrating a Charmed PostgreSQL trace: -![Example PostgreSQL trace with Grafana Tempo|690x382](upload://2ts8eOnNODTJnFrfeGGD20Lj5lR.jpeg) +![Example PostgreSQL trace with Grafana Tempo|690x382](trace-grafana-tempo.jpeg) + +Feel free to read through the [Tempo HA documentation](https://discourse.charmhub.io/t/charmed-tempo-ha/15531) at your leisure to explore its deployment and its integrations. -Feel free to read through the [Tempo HA documentation](https://discourse.charmhub.io/t/charmed-tempo-ha/15531) at your leisure to explore its deployment and its integrations. \ No newline at end of file diff --git a/docs/how-to/monitoring-cos/index.md b/docs/how-to/monitoring-cos/index.md new file mode 100644 index 0000000000..706b34cdd9 --- /dev/null +++ b/docs/how-to/monitoring-cos/index.md @@ -0,0 +1,11 @@ +# Monitoring (COS) + +```{toctree} +:titlesonly: +:maxdepth: 2 +:glob: + +Enable monitoring +Enable alert rules +Enable tracing +Enable profiling diff --git a/docs/how-to/monitoring-cos/postgresql-grafana-ui.png b/docs/how-to/monitoring-cos/postgresql-grafana-ui.png new file mode 100644 index 0000000000000000000000000000000000000000..2bfe99b2a46485fc2b46d939d52afff6f6ed90f4 GIT binary patch literal 354816 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

{?z4n7yFCv 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%0A1H! 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 =E9)qjDdT>ypMrXr)RZ3fZ69MuZ$o5rm> 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 literal 0 HcmV?d00001 diff --git a/docs/how-to/monitoring-cos/profile-grafana-parca-plugin.png b/docs/how-to/monitoring-cos/profile-grafana-parca-plugin.png new file mode 100644 index 0000000000000000000000000000000000000000..273d0a8123e8c118fe8b2200da9fbc3959826b65 GIT binary patch literal 167635 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 (nJ(|Eoo5L=Gbuh{%C}fjq7yOvLWa1SB9U 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 oqM3ufi0b@B`umAu6 literal 0 HcmV?d00001 diff --git a/docs/how-to/monitoring-cos/profile-parca-web-ui.png b/docs/how-to/monitoring-cos/profile-parca-web-ui.png new file mode 100644 index 0000000000000000000000000000000000000000..d454ef58422c364261d12d55f049765d2e520c52 GIT binary patch literal 346229 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 z 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�sUgxbe1e5|u1gwk9oDAP#Ope#-M})FaRUH%! z?z@uj6BEDSmf839i)`zz!WyZ}s(u-^@FX}v;dgl7k+3qq9~ER5Y8lLK=Df3Da8Hi? z_%N%b$qd!N%g}1B`fc!Y4>7NBetxyB&ie;{rU+gA$1Vq8f3m}n=1!?XL+i4Am@lTQ zW`y4{PN^?<+6hD72EObcA3OutCijD!DcOoLR<0))Oad4%bm4Q-A`PvJ?m$g1Pp^)48!GoK*gk6fwHo1=pF@ z{HF;Ku`4i0+>m(X#dXv5hhsJQG(2lsmV+i4_2oz3J+mV$mDJC<5xxmY$sib7v^CYa zHq9U2K+L03Ft%^Ygj3B-w+g+JE$>Plj}QqRm?mUItuiQLy-N;Dm4?YXO{3XA@Myz^*#* z?o%hi%i%>fRb4sBho{#i?~_v&*hI8)`%}2u0($Ea8y_D&#O*{}(ZRt1`5P6zmU)?v z&*_`t)8E${WST-rG6qy?x; zguFm`v7hiELg2;;tP6j$ixcdA1DX%NDVGrgGyHzMYkS^@UE@)^3lL1SzJYtM4P>=m zwSM&LR0ZCBR()l&xjrQiXvV^WU*O*}MpcmHLa0tH3^}ns@-1SZooi@Ia48G{D^zp7 zwcK74QbxfnSz(UvOJ$W{&`++~i+?NviC3Qt!I-Q!LZT!66C()`54QVQ`O$a8J9m`@E4U zto|Nz-D3Qgm`}~yw}S$Op64HHs3iPc#w(rK<(|`SK5|w7*%AFQe||hZ zY;fDS0@QF02N7uD>#zmg&Mb+n0653I0HEu67W5M2WF)p1pk{hQ3at!#lR^r(1t>R3 z!~T#l0KKFeB<1Y9-QUvC0R5=RMowo0?0yJb${4>-4|dE%wx8na?3?p#L$69is{>&kqq}_L}sn7II$VK)IoM3qMOEdvN zZhu7nqZ}M^gV?CF_1^Vx~Hx}^BVCe+(=QV~i*eMIvHklH5UUR-AW!-YM=K8yf zE9yKI)$am0-?>vC!aBn>!B27@DMdb~Qw|JdS^8#RZnLB1NDvoB0`7fcMuue_yE;nN z$T*)$64373%W&>H67K<$9Y~0sHQ+{I<@*?*g)bAsmGd3B!9wR~$GkNX4g?x!6 zXVkllH$dose2-mS_1Dcr=%ip=y4}<{#@WIgw8zfaEznGMV|**yW00@a3kZZ{?1)2FQz-oBwAR~miui7Qsjdb=_M)Yp#pV? zb8v3{4zV>oEH%6F$uY2GWV;*B>=REU07Uu zG-QYvgbdSI^~r_3tkGEX%*7eNZQU7Q27}oyY}4e(27LN7byq zNL}Ejgvm)r2GX)l?)ndK-Z*=j|A?PJ4}{9@#vm$(&ejqjX*}kp7!5WLHgRmGb-#w{ z1Pfb4bI_XE_0a~bo`N}uAikN!AVhEPo;|qm_SKAfo4y*Q@fpl~ulbWQ#gS(dj5f&zZ|WBX^J88-Pb6642LMe635iNp#u((9!Y}Es4oabl2F~yNOgS zZOA(iiI|&~KtSG&FC7p`C zy2A7zm_o&LeGqnUaI864`b4fKF6K~c&iJEO-5&J#8&_~h&oM})@R2VK?i*hIOaR%I zlms^9ckBAbd;4qex|S=!^UMBUlK&(DzzUm#05yC5?_yo|J7+p0*9hiu52|=4*3C2%R{i_z@4#+jwIOBmMA7KCQzp{KntKUpenQUjh zeg3+FrysJ}(f`Qrv)AR|_!9cR?TXU#=g%h=UcKLtm-vs6pESa%olI$xSAvpK|0BJv zaz;4{Bg|8t*}l@%HSKHrSKFqb_ngV-`Kw!GgO?HC)Xz3TQ5294cVlhUfA`?5vPNGW t;s01YnlQ^ZS<3&9%HCfJ5MdW3D!3i>Hts#={5#K2O-W0!{E_*q{{x)|aQ*-Q literal 0 HcmV?d00001 diff --git a/docs/how-to/monitoring-cos/pushover-client.jpeg b/docs/how-to/monitoring-cos/pushover-client.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..1c34bae0cba3795acd454d0ac9ace1e7374ed534 GIT binary patch literal 155021 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%0A(Q<8JOrc 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

QrLfM*?|~5k#<8 zSFqKTd@FbL6%doJF`Njn3HS>w2#$+$S zKiDBz|NUvu7)0OeP>NDyKOB&U-zjRgww4 z!Ntpwj*^(LlZ-f*2f{y<5t?&T_n?9Ds2V-W7pmb)l%qGSbnvGO?wC>qXdA5i-W!v~ zhj4=I78`N#_y_XXcL~HM(_^yvhUqKhYM_O&OAPsET6wb{iOa=ukz^C~qu1II;6iXk zdmnU#%jVioS=OR+$=12caa3fhIx|(E>i$-cSJ5Cc`HJ>f7<4#Aw6C5x0>$3%$>UUE z!hH*FAh=<2t2TM1tqiUoV2HHQMpw;sIVkH_#Pv@Ue)F;wcH$RD7(5QV{{r5+Qy<|d z%^}s&S@__aLjEj=whur+i`{2bCQ>N4y6(h zHdZ6oBUL2AF&u)-R7F8fL^F?yt~XSpVn@7n%W);53|h+uY))G}zh67~Ftr##MriYZ zwjCy>-DM5D$hI>L@*g}Wx6yL65cBF$(YF?|1E^c2J1wTOnsPMq?8^#0wk328r0dzJ zhpl+3R9Li_$26jnsQAH-$u_Qs7Xed&gu(!EJG#9c_>>6|8ANpgd4-MVYV35h%AIXV z%heZlC=kNgZz~lkF!%H!F)%?v&b#FAZoXZ)kHLZCc=F{6U znxOv4ua)`hVyg228EkXpj215BdDo0xT7A09p9DB3zb-GDg>%q?7W&On-Kg%2M8t&? zg@h>S5Kc4q-RqhHAHOaWz{AC)#hmq^MD+0ezO##_jRqxl<+qBqYh6}6>P}978%p2` zoMF#5NMwV!snad$u)+%;gL|_+i6q6tYmeAGOiU@(+5ZkSK;u{mv)XOGuEe8piYDn~ zrk-MGVJOv{#yyWG!bT_9L09XBFk3O+NBez*wJbv$3W4xQpG&>BMWclW7@={+{l{z8 zj|G!9ey|e95-N`+h|(3d3#o+6m1L7P&fOJwViWWoc$nE!!B?oe(ZYA}SkGsh&^_qg zL*75XLHnVGNg%&LFth*~!0`NX`8K7*sBl?DZA(AMSV)5g|5dkoDrzAM#A7W1d)|$2 zi?&2aP_^#VFf#a?-^Z&#j*YAL;nWu&VL6J3wegLF)$LUsw~~VbF9~Nw3HL3eKfyhUYp4$ zQ-opb=RDR!a1V8@VYzFd8sb%-_KwrCWZFoGmxMUNHr@t^OP?%$-%yRyJd>+X!5$fG zQKUM)3%j9kJ74OVcc>bFRG!p~fB~&&!xxXON0#nKiRVr+R8B;G5R*gp4{J8IHe_(v z&N^#%Vd;=w;#*&Jl>v_(%_CI?jmSthS_w*ja~94ddyRDhdrsShBZkgZiam@YIUV;@ zt`mxku!~>?>LXln%m-IX6u1UrgSCOr63g7Neu<=%+E9z7mS*(7B^a)cyKcY z+$d;EnR3@u*twhn3O5JAhYhX}4SeJ$E9NgHT{!d(Vq&Fp-|wZP&gur)q(hOblvF~g zo=z6qsXIV=hxAoBm}Q_J2V_hr!44O5l@hFii&Ow9BV8SMi@l7)4qowuK_YsVTyZQd zku^~f1)<82Q!f)Sm)Q5`5UUr3AgLaEc+4S_UW{M^v4UGUKe;j5&8j720UJ?YMMuVDmh+(hSs{!3P%KhkYf!0QBXF`>vur9wA)T*!pOn zMCf>Nn<`{oNe+!niQ4fo72Be3ii-UudfK(*upMG!VsB((<(_8mQX^<78OH+^|l7Y)3s?xlZ( zBpT47sa;!;YY;%^PH=7i5=Rng5rAf>?g>r%TvU#EcwH?93TC-*szyq|DSju=zTXD# zwe>j%K@UtQ_~+@dx{ZlWw>Z(&9Mu*gLaFsHbtc(9vQg{BSF}%^?SCQfO4``0xm~As zl|pw$alCPy-82r7NH@mY>Qo{P!5ydZ&d;EDquEZGgh4RmcfKyg$g)z2I28ycmCSRk zvet9yC8Lr^%b#MA;J0FDDo=#iiJ2j7$JG0ym$?;f?JpVzu?Rpnzb-(tj|4`a1OzC= z*%GCcvct9e!JqL)PHYc}63IbLs0;n7;W_9kl0E$S@L(R-0Ij5Z^Vo>YwF}FaF5`4il5k&FdpcKpi$1<|iult$ za@2TT6Fiuie*&N)HLt1pI2uGUpxlHZ&^Y_v`xyN6Y^J-TCS~c?vUlqjcd0m`VZd z!KuS5nJ6R=&+N4WxRS1LX9-z3AV_a74L%Unlgl;u;4LF_%MZ-ZT5??vKJI?8J+C)x zD-ZBhy1r}|Lkp^l)B}a_hTH3?*%)^XfVHwI?%e192)b3-bCwgW7t*e0{lqy~ntb)W z&dG>en8c<&=)LPDxkD!!m?103sVw;yBm!Me$>BIv)1E>H!Mxi6Sa-1DZ$sH`RHrW6 zx!pCT;qG1yTYPXJ!`2_Iy_l*Rw=BFGpCbszfGv3@5E+7Jgis}euU%bz!)X`}dd=>xM_A+tOlCd~&y z2K24;LWGDX#P{KSfUT)zIqnTHHzvr--0e%sg18O?|2SC0#DR388bF)@;e;Dz1TOv% z_Grs6hoi`9wnb&Ku*7*F;6Q2H1sfgWMcq5-z_3y%60&B7(?(K)1-7EWD`#gEVW-7hs zm*CbhZ_{J6I&El9c7(Oa02t+6OMRS0K^dz1AOlpceTGkm9u)4Gk#@Vj))>u_0ZX5K z!cPomt9nO;j;OXVDij?&E%De3d8XT-LC=3VghV|z-JE=dq`o-F_DHZ5q1wH@Llqx( zsYR8Xvyh!%)n@*V5h7aaU@qg$O$Hvoyrr&F@ID;g1mR52!%YSEA&gG_vK3aLU#4XW z)PG;OBd^U(748xw1>F@L!IsYyUR=_mJA((x$DX!JLK@6JWl!L|I!zBCQeB;i>nf__ zYq(o(uLSa?Bir%$$IiY`K-o72Wd;@BO&PoTr3pWAPT&`&?*n3WE}v*^ikD5YuSBY? zbQLrzO5RqZv4!F6_eR^7KmbP`??`A{N7mFSI9TCPbZeBSU z&_>l5v&LvCGm1PuAr1A8IcpcwhlC&Rn>*h>c7rUCvwi&RUrnT~Z{2U)FKnNsBWw)- zAkaJaubT!IP@kb(j_YhR)l60gACltfq<*Mh_l@(Lc}?gX^UKRE ztvAC8L|~%Gw3zI^0N;`TH09UX5;`P+?QjSn?~SJbv@7o?O7z)qS3)7T1Wm2=tvOGU za=F7sE7J;o!-^XVrS#+JUc}x&pbsh_jKEh2qzmabV3*DDk+jvca6kQ7FFi^r8oO}_ zXHLtbN6%1-3uyB>;8MgHJWK210KB&v!IDB(z+Y$Gy&EfNSn>;M-)V2M^VsuWqW-B` z&3S*f`OneDECX6ZiUhC&i03T&a^;Tt0<2HJkVuVEZJqA`x77>`sV&I!Icm9KT$t3 z+06y@8t|6!E_#m7c)r#sllP53rDLfdZMO-UwWLnv7RXPLh2l>JRyMxNtmY9nPjZMjL9jEpI{~wx3$@l9qnhVV__Nvy0AFhc)vP98eZiaR4m7E8^;R1# zhWQmK8?q@OVI|)I&@&i3{NyfvL?;(7@wgWr(?CVaU1jo?)2 ze4*$TfT`LYyE#P?AZ~WBnfbCw*7P>zzN~SLF%{pb|D5;5`M^v3iby6IdPqM|x0Sum z@*G5oxj)9r4nKp0IJduuMVhH+KO-CA&XU>;%DXePW$8;VQdbR(-PNh1aJ_nks%ik= zq5MW!C7G<{`)QR4l8l}3`92cG_F*0*UEe*4KLl)E#_DW-8m20z;PFv~A35C*FgmPN zSirB8o68+RGJVY*v+Z!{BvQj2&RF_(m?mNCH7Nbhv7r!rTavDQ_mBH*Py&2~lj0pZJMd9G_qw@@J za{_UUb{-ZN7d`waOt;(P7tsWg2LBk7gp^#ap|Eqv()G4VhE`?)oVCreIq4nCRyGh; z@Mwn#HSq+6zsc2Llb)j1WU)i882)|}mOp2GDMFb`w;G;07kkt^asZ?e$el{s2XpHR z*wS#~1zkBT#H27Ed)o30SWMB~zW~!QH{P(fvo|c~C(b^+udHlmp;>0C>IwIMD*_-S zH}4uhTM$bQ0uNR-76dxaG~>s+2TXGGk$DX7V;w6X4MoBjPnynhIg(bk z@Tsw`6;GVm$u;o$P2y)}77!BT=(5C00sT;RK26{pvTM(}Emn}1g&?&hOOJRNEBZ9X z_Q}ZsAKzYEhF7F6C(J`;@}Ljqv^YzT(Iz^m(g2o0$)rux}&fD@uRe#Q8@IP2YjUgsOL~?gTTD zbg77YzJ4hixE}H2ocI{hsuznWGUrx>Kn)euy<=l9&YOf7AQ_|Ylk0R0+pSo2Hu6DW z(K%(`0av7H)9^_c2|vKHMH_E?1M;@HFg&4AHfwS zcr$?mHrHzjNOidH9_no2Ri3k(e4NN;^~|iqtL1)}RhM)Wcdhma2YjTLNBe9k6I8rtP=}vlIh(9 zORVX$n5pmBtUp#=VR4S_LBUDovswC62vyRhHc>#v(x$9kXZ#@*2&jxbO(lCTKd6^S z=kx_kVKbC_(7T1+r#bgXAU&L+Pj<{Qs}z{bM`ds$jX#!23A555@?EZNbKn`HAG>(= z>XjUW);fZcXQ2~%QC7Dn>k9ytmP)~r#+{%D3Y-^fWR~7dsW>efjBJ7|gK(rUhC0%| zJ~H;CS@8mp6;Yj+u`xHKH~J)<=6#`oezG+pjlPB&-fP)l41aWT z4a89nbtnPXd>sd=EP)eZ%k$1QFhWN1+RRvUKNr75ok;em! z_7%f!a;jj|*dT_euSg56n=28%i#oMytJ_sHsmmVbQ z3H0O9Fjb(MOoR+vXHRqW03ONE^)sVNlmQKW4_w4yNs4$&*I|W+W?b}Tz5k%_H!c>& z1&V;E7F55mdNsb_!M^pfdHvk1092rwO&DIN>7Bxzi1CC6iFY9|tWWDi&ykbn<`UYb zdT?M39v#2~7;Yx#aT4@-7xgZ&lik<$cqIntD2~ zQ)41yd`S1sM$iD{M~$ij-9%%jf&ST0DkP&c3$`DTCzes09s@moqVq9vkNn`3ID6F+ z#6yp*q`6d(fpdkMZ3zIOj4CVM08R03AyXypUB#Hl_7n6+2m$tK>Cz3DRF?>kg2dDI zaPL?cEdt|Kc~*g99O2$+8jlxD-~3QO7X2q=(GR=+L-ZlZvoJJqHQ#alXegRuD1(?3 z+d6AN1B|i3oZX-XO(T@B7Q-vKb&=4E67ZA3ceW)YE1iZ#QWBV^EaqAJNOtdPn6G-p z!y0f-DP-yI87HL^oqN~TEDeT6H>(NP8qDYHyqL@+XqXgdV`7iCIo_q3e+1u_juKn! z*0{LXknux#_b%C1Lk3VM))4(n^sylibacQ&6ZTKBOYMf9o2qLa&uBqp>Bl6cwb7ge zPHcZemJmW%@UHv#K^o=W5YB&c4JS?+@!6UeJX+yz=BE;D%~F$rnw7QKHCu?%M2MPw zRu)S90YJ&xhvbcw{&(?rysc+jbfYkorf%+X0I_SkL^)>sC3S-t*wTHj# zcld{a4B;jVL-s<}$62+?WPfxb_Yb^5p$dJlqqKKhd=Jw&4@55#dU{=n=;?A@{MgZ-0=BauytEtmPJl zH9YSI6u8n)#DoXEv0vs=jEv1wy=gbo`~qZONg?}|G%99od*VC5Qk&Pbx|t#tfY)Do0rns@ z9QW2k$5J|QyZ9WT=d3(!mq^kLoTQYYo;41RexV>bmFVzXC*StVWpo*2@S`K8N!Ef% zZ_hi>03+TSo_scIOyQLx5a4?RF2VHD1J}UQhdZ%`Jf-XeAp55PV@CM6+CW1x3CD9ox8Y%tO{U0bJmM7lbUeD zpb){G`a{gAZ()UcZ+*V(a@y|b_N>uB6YMevk0~o?iG{i|PnU{`K6z9LR64$>@9C!; zPhsy4F?+{N1Ph~qBUfH)zYjjc*>0Y$9(T%q2PDOuUJhXxgNX;u+R<)JlT%iIN2_e6 zlrIDmr1<4JO=wG^Cs+VJ`;MjxL zDh4KuD?mdF(IQg*^Zan%{s|MiskUqtN{Y0GY60pu!l{H0FNCQRhE_3gN?%nC1*@3{ z)oeb%SJBJIfi4|kvD{4hs^BSi0OJy4|^9nS`_eL?yd4d} zha~e@-t=GuboR-_PmWT1gZB@5sY-!!aa4^(?n)r&Nso8ex8vUskUY<;rkhk8-bQP_ z_00EtLvfySJ#+M6kHBEA{Iti!?&H#1C|abcT*0zRWZo&;xWbG3u`@ivMR|IeT6Xq@ zd%8batuKbZZae3O&V50?csn!?6X1qJB1v#t%IAu1RdE^!#tUXO1@nQn6VCS(It4j} z0(Mw1SUd}I4vQggQK!TTq;N&+XCYVaZBgP*4^YxFWfdfx2O(rb<(${(9`2}-w~Qmm z3yQt99agxgj6YU+8vpn%Yimo;JFA3Wm~k)d55I4kj*oYt^-cmOrLj8;$CgQb3p@vM zJ*+Dt9^zyGi459=-5=KbC>N>sLDqt9KAr&RCspJXQ+>mk#L4yrw}N{VNs=YLhgqUd zDD(mcyAVb`J)Q-C@l7DC72lJz@X_pYU$Mn4XJCm2@f7 z0>r=`kf$3!5gY?Uq;OCV8@j_W0p+!~U18h}9|u-0b|ZeW*59uDBp%IO#sY*sFIOBJ ztR6b;gP7^3F~Rb6V@ZIt*XQgV31rhBv{fL~eB zs27`Yo!=Pa=u=iBWaI78bo-h#1GF^fYetQi1GjnN4t7wPIS>4H`Hokr43E)7Jfl~T z|6~;_IMC<;YsZUoVidUVOQ^(R+X0uaGg!=NVJZUJzdv@k=@+~HYo0#{Quhm=8us%4 zFf4~cfB3*3O6cs6K8idTG~L^v??8agC_sR9HQ)Ih$CtmrWxV7*OjP!xV(8M0#svg~%rg*Ds&q@HN-J^tN*8TI09LnmbW8W7lo+NVM?;Muk@9HCQ z?{jW{E&#v=DJATg&cOg(+u@=alDuCeTu0tVO@w#B@*4_@1ea1~z(gcOs(vT1E={Tb z5q~wSh_3?yz$AS4$tR||aw6C-=JF00gRA?~QvUS^A(wC|g_eR|4;L7o#buniQEC^= zD_idB`3c__WR#Jk)J*g^;@b zooE9d9%0&OZZJof-S)?uwSaOI8R&0>`0S zUcO@Isa+D|olhN|SQkBtW4j*zLm!B2k*|)4f}_`#0^Lmn)6?GJ+p$vY1R)CDZB9$k2N&`AcfVeK%`;3c|E7<&(&7KbxqS!9!+ypZ4`!(g z68f3b^*htCCFa1z+xl^3wK<;^QH}#ma&wb0$zA&W*8*=F_)D#fLi}K;rdhc0hymo`7yn z^w&65NT3_YXS; z-U$FH#NHu>nENuca`+(PR37>O)?$f%3Yk3d;u)h8MnuUW8$1TYU22ftJawYOC-@AM z#p#nMJ$&wo3gBnmm}I%J4wmFFnaLB%SRS4;|wA4Yj zG0qfq96op4k`!~5UxmX@SY-(`Dskd^D`mBx0Ta_MzxyD6-inpJ;+!X{H>W(dHh#~b z`6WC*f@<+B!qLcyV3>e2jp=(wof$N;Fw&c06Rr@OjGVGCPGmx=@?r!&B_N*Ud4`?y%re?`Sx?k0Xn$tE+& zX$Bd9X`0W@Lts-QXxr{%qPBH5DqQzxZ3d|lcB#b_WFFid$q`%H8TC!w1!%FN{Ai{+}`fy^a*1_p&&E;4vyf%5Mdl2F8vDi;a`4 z5*6k{r}^`&L_FI~zUqu6jG>Q($iI^C?(RiJgQ%J;>vr?fAp!u+>G_<2HP8NIa7@Nx zMnFcjj`4^nws4E{*_YoVK!2W#cCY?z`kn%?B8Udu?Oqy-O5xu`_I|$W9mI;vi3gdV zQt}bbpAF@YzJc0eWz(}lIzVmR$Z>w7Be+@|5;wdFCf4%_u$c}}jM!bKWg4iS5la4n z98fQItcH6RoHI{B$x-fo#e9Nji12N&}=)p z#}xabPm)SLW7`#f5CWEVA5mF)SpbXoM|}U=v)Ne2Sn$r6GOnRBmprgujNo9l{qAs2#mtw}N>v z2m)(+!H>TDJLmCNt7S#k4N&NdkQm4DR?8J@TnM1*Ws50HtNuA{6m2@wXKd8O8G;-B z24b>OHI+o2Yql6iG-}{meT~B-eaN+DLDn||SwhYMNl7-pDFDLRu2K)b#sQZ;sN^wcldynr5>1n^U1J*uy0W2LM-Hbt8MEyux5z1@t;NrgZ|N6^JlTf`JiS zY9I9^U^d5Eer8H`{sR@lNNSe+*n&Mgw7EMHekPUa^bgqJ-8b@f8Lt59!Qirp9c!(&Ao_%Fxse0;|{yg{Tprc0j52%&GE5 zmPpM$3fT2?|GHjEB(_l2EU|n;U{%k1I_1VsqHar5A>Ci(%pTDiKMBV#Rr24P8jM5aumb6Cm*6P0b$A!;s!fH^J5?Mqv!Rw%n z2xjT=63swZgk5fF6T@lyP~^6HNvBgjZF%571_Ee>N($GkD2QM?S+zALr%TU-i|*28 zoS=txH*d*1$jWiu***HN5CpG*mm5Qf`SC8Ove8(cra4PR0O4sR~oj2!WB(* z4ZSlZUuVHIYrIjhIsi0;21l>a%V{aaac5l?d{j`_1{*8!gh*@THwL8zSDrJCFu*sx zM!fz34xGLFj-9c7tMN#HqDzO7NgJvJdR^@kp3rk+;IUb7@nLC;#lJdAr$Z=P)RL*% zf^FSQ(6iVrAU2j=WLBm%m>ki&&o6#yU<6!agA;FeHdfwd^z4U-2|gqqYe2Ao2E@xQ zjRe2WzmyBQ3@Efrx3TvVL7vGeJ1#w+s46cJX+bA#KFR=R2s^{abxj`%7>?T@l0bSy zv7S%jNIYCGqw%~dC8k(z-VO8I5ul6?zV?oesa5vh7@RCo=$(m4EkGEMH-W5^xM;Tp zM^m)Py5MNn<$Ul3=x3^J<^{1{3;Z?E(f`mzeg~re(`WzmO;L;4|9qT(7|RrW@OS6^ zHD1_AyKe6{EH>TwA$#|pK_>qNae9CC2tm!eodhEg9CG@AQO7jFFuHxn%#){vn#gF*nu^V7buBe&aW$eT-l#VPv58iLM=GSX+ME zpcK@q^Y|sPKUt7t3AmZTWA;eXjYVFbCTM}alxmBW>jwSbX1LS-eTKTD{NJX?AIrvyn|t76rMN!y|*+9N)4phU)SLgw5^Q>V?q>fM&8!z2V#`9 zT@lk_w(Z%f1;+9OV+bV}Oq(T&8A|>bU1K!c4GU?L?`59!5f~H6-j@J5X58E1$?UCt zU!8siyIqSr=Ac%tici&kX+&}pm*;`4I6FTtnUnHSvo|+-^BDytEB5w)j-%%JA#dgB z#wC^>P3`-X%@qg9`mE&n&;JSz{#D5d$~esS;wOa08-pk4&Z~0FeL!+d2#^yVpqVh; zGw1#-@|%VVQ-e;$mAoobc#bF6j+2+~LC{TVBIgV!lIuweG`pydfh4WKH^k~D@}6Rp z4!t^-5`vj`Zh=5BD)T~BT2PP<6;di{f>Z=?DnY_yAbi#oA+#IR$vVhmddZINw)Dq& zc9hI6uj)vw%dFhUft%u2IP2@jp<>D$BQIMg{Wg3{_W#v~=iDIplo;q$x8z^d@P3~! zt?)8@S6V6``$+NyQZH@yK`IhtwMVJuU@@1ae6mYiQK;OTc|Ut~8#pWt|0s4exm*;= z#h(WSCaFrYS^{x%^q8Q*E4@Jiavq68o*wdBRHLE?_ot<={i~IHXvRxv7}Pb_H<(U6 ztzjPg-nIbGpv(a?SZRQ8_9K?&8q1B=^j3UxTQrS$(Vvf^UG2goQ zkh`BQvU$d26b^d{=)Hdf3;QO*de6;l zRYPz2DD260i3`*m73ZYD`iIB zAZmUleww|PTbY7K{Pue{)=*GN4uajaM$nfP|EsBf=xdGJd)EO7s zzb*P!y9c@xbQLPZ5E+jp-{Yi7-6@V4SLI%oj(VTo ze}C5u_zf=IBmF^o{*{!gq>riVAwDT5l~ahBR=vSxJNZ$SHGs2%~=~#QLfspiI!4U>G8oaBR8Jy z@y)#tcmQ^JM>9PaPuzp?tPEU7^Ns#W`Tpk%1x6o<5^ZaE#j8J-f&%=*i>vJ9@dqbA z|CzY<%XcB?A#4x?Z@_NBdbGIX4psY!t|1ET6p}Oe5ktGUZhoR6Nl!< z$#sR8V%KFwtOGD$c+Kpy(F14}{pCP6EB>aJUlP=QF*6rA0F#$rVpM_CUq1awLK5UN zYe{a>`mpsoX#R%LGKw(1H*3zOIjK6b5m$6$L*0$Q1mQy9)sdx3gEHA$3~;=mkp)xN z*nSXylZZN0b%+~eF1~8L{DA2Pd1eblhRVeaW%VQ}> zD=Z=gO;Dm3C~2FAynex$HSWWTvfq*P>)>=lX)slI5GiA7m;ifrus}`Y!-(R4%XU&? zCYYg?TzT<9)c#;bsSCm0sf!m^QDaZ-b!0?)uR{GKSSYY=G|4(p--J%>FB)8KbzGr$jtstUXa6{u{4B=HLDSFjyDtycb*p<<*=3+7?pJyM zObqiZ>P%o|Y8Ghp`oE!nV@Mm(A1ZPmf$ce(_XK>i5F_)92nZQ%;B|2cZjcszit~D| z*67Gz)N%E1Wv4&@x$G1eMy@(V{sYK+^8kzja+a=`V8oS@?HzP<<0KNdi0Z=z{ZV!b zQTe{GH|c4<`Kn6Ri{p`h{ZGkn>XSVArEvS|*gNk~jr?chYiIwT?l6619w=qeAzD%k z=!wT6Xyy-J{U7^T-6Q8SK8b~D`3(Eyb=$hTsTE?Cc^NtyNLSKJY1CP3%1^N%6qO|PB4)rzgj5>)) z>()p;wuY9@*{06B`ZpbzmC9I~thFS|Y~%3j*Uh&#*^OypDq_o|(JF<0!u~V2NiD7Z ziZISQcCq@p;es5TuayUF(gI<6CMP5CDNw2AbbEtlP(zl~e3;UPU8ElJ@!VL+w1cvr z;5}W1(xApX$C71+WU-vSG45InC=r`TWA=Q@6~6#du;)Jb=N zl)JKag-$!jFZ@imWJ|}*rrS>JR{4k%dEpFwS&k0ja1r{|f-5EtrWUUq^kdZv79JWo zXE(4HcH~HaFq1A4*E5Y+uQGi~gg;bYrg2)W`#@7<7rDvmy6~E{CbDr1T?~F~RwU0p zD8Vwt^@W-VTpQmSmWcMicPR<$>^h*XwdW<>Ji$_3GUJ?eqzc);(NI3V$%PMcQM2+M z=V%ip2J6KivJ1k9% zp6)u9CR7xiXEjwDpiXnSORoZ)+u_UYD;_=at>W;OeYJWf#e03OXeN=kqM^IC_&Gn2 zw9d1zG=ZeSaE3K6YL(t9IrO8q=q#Zmp64?S264@qjtei%Ju6c!QQTIA*+T?;vvoVE zK@nkR8q~lWr(RfA5ho>ANwpv%t^95@Kv?!VsZ(&o%P+C0>Z#Fi>F{f}T|T;j)&K{f z1vL?_BPI9ZhUc+N=Tuv5vJ~4d)ZgWk*{WwC(dRp?V6Vd?H_3{M$yh(h8Tx+ORmV$ow zxucU@Si1|<`z>Y(idz-1@;-!Rh{uMwku|RS?u-q(x?Mj;SF$ND(uA66uyfqx_M`r( z#|al5`x?@QK3?009|7^yYTk-zR@ZRcph%{s+s$U?uwK;{S9+YPs4uQ26H3$cI@Pq= zN3dIxVBKR3V!L9)Kts)we`u=H_f%TO)lb@Om9gcj;2Rt52%F+WRg!Y#-KLIZlbqYh zxr3&qD{kIu6@|BM9(Yk*Cn~=p8LgW$@_$#)4*>99W~jFys!8?)8#3pGQqMY^oft5R7@H zTV%@tv<(f`ThHuGyR3f3b~LzSt~#lj>j{0^swH^ns=U*3)e9*`4p01DTNaDswAlc! zIa@}H6h^w+NJb5W^GmSNn^q`z50l|*czqeFSl*8^R2OgIJ*J!nde%NtkA3nrm{cT% zBglm1t7O##Jhq~tn}JFK*z|>lI=r^xshNcKu}TBi@VYzDcUrPUBknO=iCgmvDfQG_ zmYm1*;r3p2>Q-DQ>22Jq3TtZ>PVWc>hX{5$(d+hQEi3x~w?eX|dqYAi>?;y+*L&PVhEJC=w{{P~4%o z6)3c&#oJP-%a``ZbI$XebMCqCeeU<(_x--i{ASOrSu?Zu&Yu5XBYQ1`Q^r*O!uB^n zqEVDns(uQvrkOgVr7k^uho<__U|G1 z#J^f$P;sC|u2>6W^s9^ zZ6rNg4t^TmrJG)_O{+o(EhKCuB_>7a9-GibmlB-F%@kSL7c%8TE%f2`XyHn-2vQ?> z<>=jyNPuA}A&+*+j_}8K#aJE<7hU^#LUtUUwuU1K_ztxrY@rwN@Kp{8cA*9GLmlPb z9{xpUA2JzO5Y1Ai+FLVo?*6T~-JTu21Q7hO_B$YD`3v_qy1^lNGgj3y!a#_vij0UU zU^j-Ad)BXByD)m8V{K5bM}VWOT+YeW4eGjIl@J9bHb^0gWn6Wv*|ge?LGe_xXnlD! zvm6%6-Dy$Xm!E@Fj*Mc#t7`Lxxra}uq^p6s(J*7NID#2qry{-{mMOwB(6vh?SR$pf zmK;DBI|Ev};j8FoQj=#(P!kE5hB@M=l(Z7^6X+0D2P`7_W1ITop9K{w(A{W>A?2^C;xO)a z$D*n*YJH-!$~&)i-3A!}cvM--A;nm8gXnHTpetyFcx}9;q+~8%c%K&#c}GJK8t*@m zL+G^S4oc{yrVE11TX{1A-DsmHYjurJC6i}_7YoV6tr!IEREIMUwuV{wIvXs@SF1S~ z@XD>XjM7w7NjV5K^8caBV)WH&ngI!7!{m^EEx;or3-l%ASvu(>||V{+meIsb=5)}CvE86K@}=7 zlME{Y^!eRaA>~GFG@?*oL|r8E8vu;k5EN{K@1!bOo5IKvR_S+*S0Ltaop0&(98Onqrd1p*N> z@Asl6k@#(#oM;l`UZJ;R@v-!E)skg~rT9VfBJ~-Nxym%pqdEzGg@&BEDB~Srsi;{b zsn3$r4jd!%%CA6Pt~_ln<8ieK%?uNVmHf*R!i5|uUC_}4HFs#BMxwj4e`Z^PB8y6< zm@|1IMc%u>#GBM`6)c%-Bm^8?pND4PLkO7g@PHQEc#4j!b^@Pzr}OXhbz+G)@t+*L zFZDgumUO$oW^4iL$F?l?H&1bbl(mZ7NAiH}GvcYm-+dAAB=B6_?>VY_@f@w~_E~l^yuzphhLI{qZYJ}W- zA>+)~sRO6}YT6IO%PgsrhpGB-s@Tp+)9Js(wAjmj<}s(WpTO>K25u=HtJaY&@=o4I zbZvol$#?IqG7$m*p#H;96DEBlcyT%MF*aY&3Ro>KdXRD0(v7VwlfF1L^8dU4&3B-` zxs4rPC*n~eoJ;Vu{u=w{(tNuuXS+}}K3>eGSL$Wo&KpP3k5E$8+c32ffN?b~G)8iI z`->f?+BxARv5LNmth-+dQD)q~)5M{90d?RQdGEV>nu z;cNh%cg548m02OX+SF0T20l)Yp7xT^86Q3`z7OLStiLgcKH8ye ztTNU;=8e-q9%u`=NHEz6Aw}tX2UYvsRX0FtFko-wgmg#fz zy`#GE2)+I+3x@JyO0#tht?a7eq4C85H{FgfLs)Mc` zkhm5`Kf8FrBDCf87;73#XJ7nNuOjhEikd&oqmc{#v}xb7Ib=yj^_2gY66XTa-W1+0 ze0J#t#|sE)?yZWNYS~hf^BQH9CJ3)r1~YD=OH8R`y;O2sjNk=)Xf~ZzRZX=JYQm{u z)w9LozcenvGd=Z{D0%3-dpSOQLb8EmMNuNwLz+%jn65lIa|hF z-xm;7N9!93$&Yi)MYL-^&-!=*9(#n~Eg87yH+CEQ);t9HgY(-B79;zyO!EZx6nfwYi=>(7SWviOF_> zQ{oo?69CxWqUp4!nVt|Kvovw6b3VqF6=F{RG_;1)ty@JBG_O)CH=bp124FQ-Otp{4 zPo|=x$lcuvsbI*N-Mrto&4^Ua#1fCoedE&cFzC*K!qWG={x^kJWO0GW zFF{V<**|iR8#jK-{A*Io=EYCNf2I6yObWJ68!2gD$9VtyeF^^v&Y*!AiPekiSd%cT zosjI!?+5O6LGbj4Uz0ymaR*~EgJ0Q9YftJ;YhU+GN=RmFFI^x0#fj}ZtN7#QTVu2$ za`|h(ye9)U_ZuR0Yiv1LNwdc)c-d5G{U=sF|Iqa39}?@{Uf0yh zT~&T#2!zye5X3BzX^W8GV<%g__|DG!wsp((Lw?ce*fm~xor}#?Hnb&;%q#H6`h({S z{7TZm^7Ej|>zdMx5y%mi+R#(3%g|N;u>2k0Z1U7>u_K>DGNywbl2Si7U`E<+ao%ep zvxg&34=!3*ejR26b*(z(r9mP@$0kbL6=@_-Wjsh`TmANsFJuy`{KrXVJE5XG#Ll&g z$$i@%YP_EHDJ(9B{*Qx+G<@J1>wI;$1fr=FIz&6?jaiH%LR>7gkb2B_KYjx|KOo{) zM9&8DoV>nG<6CD+urI8;o6CRZP8oe=i~9rg1rf4T}{+W#U(-2 za3}mJB`2^`Re>V@A=WNy0JE}C~YJGVxfIasM(J3jx4d0~*ZPJoRfxxX+lAl%p8ROSVuG)7B@w}soWv2xlbkg_oPApnR>K5q8O+;!0x)=@ zeMp9ro9!C_Bd2ipJbc`>r^2J2O34WYHe+F?@Th?BO4vB#39tt^vp2=Wj;>%D0&R^^ zT%aA>W>-0Ke*}>JqLLzeqb}Rn?{TH>2>`mKc`r+r;O3H$<^#svl8#7bE>F7 z;FU@kiSw4cGZMIO$r-p!g2_S^L z&`Pm&Bhdv$5aDBR}KMy?LvuI-)W`+85i=u z5j{T>fm??9?T>=;Jpk_;;9e^9dEtD1fS%iw?7hE=!mMn*`p5;``-kVN2Fw=jP5+Dc zT7RJz_*?%xo|c>c{xfB&XtnApuUom7bXtTLbx3?a7+kW~O{gx$f6fQzt!-5{SP&D9 zk%#HDr&=UkdQT}0wgCqR#V>l*+OMklE{J3V!GH(HI$Z`2Tg=zeFU7Piik9te$BSz( zFjO!?sTPUg4s^cg6nEaZTL!3blVa7KxM8#FZN%H8Yg4`~Ax?@^iKm@J{;-hQFhyS9 zhsr#Jw~C`7RGYq|Y^K>{n`!X`9riIK@f=vGx6Ng&=*?Fbe> z%NbrFwDNxoNovif)$M}OH5WgxAuTyTwmo@Grp7(Ez{I(T&U7L_Ms$|rLz};JT z5VDw)q8r&JG4BZpBA1rwKy0t+1z-vO-bxYNAYKFZOfs?%?ZjdQ>R6{IWLl$$b=De? zWQ<*csayxm`xaI)(Z#HD35rOA*t+^jun3r_k4}%#9GRW95!6v(I=rY>4`ZOWedfs& zNnA1A^=^rv*cESlsFK&5peBQU zEBl@fpp)f1VdO9tr<2xezN>X{c6ZaaPt>^S@&VgE9e_{Q#jOk{R7nU50dk%X4iB|! z5hf^?(D(ROCK&C-h++A#k|Amf#q1j{NeEQiquWFdp*K53r!d5s5jD+(y|JY!oIo%H*{5&X>?l6Un0FQ>6r`H z|A@qtO>aB8G!S)T)G>+oONtHNnU}OqR7b^E5ZWwgWhHXCHiIr~{0{Wxl1lEwEYgT6{#6mId5)B45I~z9ljrlc}hRsM7B^9x8WUG z5(BV5#-N!AYh;M(S#10GvUc^GWWe04^brnH>oq0go=aKQxX-WirAhqk(iPDQXLN~* znE(fT;TV22d#UI>i$*b3qw(1gG~`e*Fz^MuMS{|5aRGjFvd@XEg$!+At@}JJlm?PO z7~0D@Rwo>BUoRR9E?MF8S`JGVubSIy761(i83{e3Xox%}+}(O`cEZCdK$jdv=ciT_ z%R2mQG|)Oiasi5rj1}QdKQQ0J$6I*U-_wUP-#b_zI`honbeWpCr=ve2WRonyu|o}K z7BfLG^(ufYtqNDbC%B-WH_Ci})?{okHWpBxKv>HxpAQ%6QUUC|5r=}bW695goHM@y zHZp32ZICyNeN1E4m!zkKDp{b(XNvH^Z-6IRjl|Zn;wFe_aP5g>7!^{n1EtnmS+QU> z+c8o$bSg6(W^^PRPaUM?+-kIas+|CbYFdmbiMZ)480(I-X9==W<&vm-#k+yxWT`DM4& zGPd-+BdiZ7DXFscCf~+=P}J|HpBCf?T<3kmYuG4}Y@5*Q@vU1$`fh%vOwR ze%9KNi^juy3_J4c9kwYS=D~U_C@{9Qaok>ccHO!GNx5|q*pso z6t49yZX$RyP6U5$%x{IiL8i%nh5sYl;!k5xhWYuz!lGQ9t=0AiM-$mHw}NH zz?n^=fhrwq^1T0Mxjl(#ew07QbrletKYTC#>WuC?_=%;6a=KgKd|u*(i5z8rhrvv$ zpqipuYc?!5zZEgQpqObPaiY32Nzp+?7UYwGevz?a=Lb+Gar6ujbP+V8ARDN$i?y5ziOE)y{>pBWThrrT4d1Y&s1OAy_*AxTO}VB zOWvvs61q9GL|SvswNFE7C>XT2MyYAAG@ydh^QYV#nUuAZv}X>w4ZqUZd}CAieq@Vu&=@dsbwdO*AsvU$ zVyeK5^5JX8Prm?IG;Jf%tl~o4`r7o{(apca!{1)FvH|mDMh`NDsN1SO<5G*D+i&UX z^ix7qea6tL1k~_R2Mz`(2NO=RfEdX;-MkF$)^KG-6x(a^H&)SR&yc>Ff2Yghbx~+; zPgCi@G#$N|Jf<94==e5KE&VZD3Ejpc{%5G$c>t9-geNz(iIlNYJEy*5v$poG_5FF{ zWhM7Ixfbc5g7X%9n%y34iNW6hdPLMOl@;RqQ zkgSMcdWko*+MU9qq`SbyUhQOexf-Z&ftUzLU~Le@ea|;cESI{>2~lCUBPfTq3*LRR z$DBb3X$q7t;h-r_mJGXPMD*i!xxv0aexJ0ZQ9eXW=A;1?g)~!R&ffq7S2ysjtY8%Y z(tLcA-X=qiYLUF_6VGj~tRk)VfbiP4k78gz!}rUqd+SAkn{>OF={CY_7m6q9LIcLIXiFE~8uq+}*(@y} zxwxOS{a~Upm4zYJZ+k3Ra$;3OzijH*Ha`7TrV)b*5#F4Bs9$*Ixq&XDdJ`FS-|Cr_ z-5c>A;xQY!jRv~ zWbv~Lyo*Y9c;h4qSGVsS=f206^mRwF+hP_P=z`sHEr5dKDK&Yw{pxnk<8LlYrCaBp+k=p+T=n=C%{4Up2N zV%&TAFnnvl`ECb$br(t(QIIp)8kTo`GUEg4rARL6{woWSTz(+fEZ%l@l0=Cu&->&< z&Sa0X(;E?7^q1ws`sI(dvUXn4q$y|B2dl&Y{(SGIp3b4*jYP63m|BgnnU2WY2Zl~B&qHN}hyoP~$ zh6zYh5e^jC`j$U)wrDH?_FD51Yj4acR*osMoWGBe$VwVn)$D1kRc1m*0n)u7IxV+Z z?-HXWOLP3eT%ckwkUVmnOe1{np3=jWY`pdX%Yo|?%=0Bw0J8b7!Vl*0XTP=-o5()q zoBp5|G9J)lScH3zX1%z6Pk!gmi8|~VKPKV7;QG^#m$8(S)c05N4~L686nW(xTfP&% zmZLCnXXl~+i}rx^_T%+`Cj1M>?+CZ%Rb~^{zuZ=W-|Ui5KDzlzgNgjk^R#UZ6ZwPm)#FJZj{rW_s%0D=Lg-q#KN+AVPt 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 v.3.0` - -If you are using an earlier version, check the [Juju 3.0 Release Notes](https://juju.is/docs/juju/roadmap#heading--juju-3-0-0---22-oct-2022). -[/note] - # How to scale units Replication in PostgreSQL is the process of creating copies of the stored data. This provides redundancy, which means the application can provide self-healing capabilities in case one replica fails. In this context, each replica is equivalent to one juju unit. @@ -13,10 +7,12 @@ This guide will show you how to establish and change the amount of juju units us ## Deploy PostgreSQL with replicas To deploy PostgreSQL with multiple replicas, specify the number of desired units with the `-n` option. -```shell + +```text juju deploy postgresql --channel 14/stable -n ``` -> It is recommended to use an odd number to prevent a [split-brain](https://en.wikipedia.org/wiki/Split-brain_(computing) scenario. + +It is recommended to use an odd number to prevent a [split-brain](https://en.wikipedia.org/wiki/Split-brain_(computing)) scenario. ### Primary vs. leader unit @@ -25,33 +21,40 @@ The [PostgreSQL primary server](https://www.postgresql.org/docs/current/runtime- The juju leader unit is the represented in `juju status` by an asterisk (*) next to its name. To retrieve the juju unit that corresponds to the PostgreSQL primary, use the action `get-primary` on any of the units running ` postgresql`: -```shell + +```text juju run postgresql/leader get-primary ``` Similarly, the primary replica is displayed as a status message in `juju status`. However, one should note that this hook gets called on regular time intervals and the primary may be outdated if the status hook has not been called recently. -[note] +````{note} **We highly suggest configuring the `update-status` hook to run frequently.** In addition to reporting the primary, secondaries, and other statuses, the [status hook](https://juju.is/docs/sdk/update-status-event) performs self-healing in the case of a network cut. To change the frequency of the `update-status` hook, run -```shell + +```text juju model-config update-status-hook-interval= ``` - -[/note] + +This hook executes a read query to PostgreSQL. On a production level server, this should be configured to occur at a frequency that doesn't overload the server with read requests. Similarly, the hook should not be configured at too quick of a frequency, as this can delay other hooks from running. +```` ## Scale replicas on an existing application To scale up the cluster, use `juju add-unit`: -```shell + +```text juju add-unit postgresql --num-units ``` To scale down the cluster, use `juju remove-unit`: -```shell + +```text juju remove-unit postgresql/ ``` -[note type=negative] -**Warning**: Do not remove the last unit, it will destroy your data! -[/note] \ No newline at end of file + +```{important} +Removing the last unit will destroy your data! +``` + diff --git a/docs/how-to/h-switchover-failover.md b/docs/how-to/switchover-failover.md similarity index 72% rename from docs/how-to/h-switchover-failover.md rename to docs/how-to/switchover-failover.md index a2e6c481a3..171c530808 100644 --- a/docs/how-to/h-switchover-failover.md +++ b/docs/how-to/switchover-failover.md @@ -1,45 +1,55 @@ -# PostgreSQL Switchover / Failover +# Switchover / failover Charmed PostgreSQL constantly monitors the cluster status and performs **automated failover** in case of Primary unit gone. Sometimes **manual switchover** is necessary for hardware maintenance reasons. Check the difference between them [here](https://dbvisit.com/blog/difference-between-failover-vs-switchover). -The [manual switchover](https://en.wikipedia.org/wiki/Switchover) is possible using Juju action [promote-to-primary](https://charmhub.io/postgresql/actions#promote-to-primary). +[Manual switchover](https://en.wikipedia.org/wiki/Switchover) is possible using Juju action [promote-to-primary](https://charmhub.io/postgresql/actions#promote-to-primary). -> **Important**: Charmed PostgreSQL has been designed to provide maximum guaranties for the data survival in all corner cases, therefor allowed actions depends on the configured [Juju unit state](/t/17525). +Charmed PostgreSQL has been designed for maximum guarantee of data survival in all corner cases. As such, allowed actions depend on the configured [Juju unit state](/explanation/units). ## Switchover -To switchover the PostgreSQL Primary (write-endpoint) to new Juju unit, use Juju action `promote-to-primary` (on the unit `x`, which will be promoted as a new Primary): -```shell +To switchover the PostgreSQL Primary (write-endpoint) to new Juju unit, use Juju action `promote-to-primary` (on the unit `x`, which will be promoted as a new primary): + +```text juju run postgresql/x promote-to-primary scope=unit ``` -> **Note**: The manual switchover is possible on the healthy '[Sync Standby](/t/17525)' unit only. Otherwise it will be rejected by Patroni with the reason explanation. -> **Note**: It is a normal situation when [Juju leader](https://documentation.ubuntu.com/juju/3.6/reference/unit/#leader-unit) unit and PostgreSQL Primary unit are pointing to different [Juju units](https://documentation.ubuntu.com/juju/3.6/reference/unit/). Juju Leader failover is fully automated and can be [enforced](https://github.com/canonical/jhack?tab=readme-ov-file#elect) for educational purpose only! Do NOT trigger Juju leader election for Primary moves. +Note that: +* a manual switchover is possible on the healthy '[Sync Standby](/explanation/units)' unit only. Otherwise it will be rejected by Patroni with the reason explanation. +* the [Juju leader](https://documentation.ubuntu.com/juju/3.6/reference/unit/#leader-unit) unit and PostgreSQL primary unit are normally pointing to different [Juju units](https://documentation.ubuntu.com/juju/3.6/reference/unit/). Juju leader failover is fully automated and can be [enforced](https://github.com/canonical/jhack?tab=readme-ov-file#elect) for educational purpose only! Do **not** trigger Juju leader election to move the primary. ## Failover -Charmed PostgreSQL doesn't provide manual failover due to lack of data safety guaranties. -Advanced users can still execute it using [patronictl](/t/17406#p-37204-patronictl-3) and [Patroni REST API](/t/17406#p-37204-patroni-rest-api-8). The same time Charmed PostgreSQL allows the cluster recovery using the full PostgreSQL/Patroni/Raft cluster re-initialization. +Charmed PostgreSQL doesn't provide manual failover due to lack of data safety guarantees. + +Advanced users can still execute it using [patronictl](/reference/troubleshooting/cli-helpers) and [Patroni REST API](/reference/troubleshooting/cli-helpers). The same time Charmed PostgreSQL allows the cluster recovery using the full PostgreSQL/Patroni/Raft cluster re-initialization. ## Raft re-initialization -> **Warning**: this is the worst possible recovery case scenario when Primary and ALL Sync Standby units lost simultaneously and their data cannot be recovered from the disc. In this case Patroni cannot perform automatic failover for the only available Replica(s) units. Still Patroni provides the read-only access to the data. -> -> The manual failover procedure cannot guaranty the latest SQL transactions availability on the Replica unit(s) (due to the [lag distance](/t/17525#p-37314-replica-lag-disctance-4) to Primary)! Also Raft cluster consensus is not possible when one unit left in three units cluster. +```{caution} +This is the worst possible recovery case scenario when Primary and ALL Sync Standby units lost simultaneously and their data cannot be recovered from the disc. + +In this case, Patroni cannot perform automatic failover for the only available Replica(s) units. Still Patroni provides the read-only access to the data. + +A manual failover procedure cannot guarantee the latest SQL transactions' availability on the replica unit(s) due to the [lag distance](/explanation/units) to the primary. Additionally, Raft cluster consensus is not possible when one unit is left in a three-unit cluster. +``` -The command to re-init Raft cluster should be executed when charm is ready: -* the one/last Juju unit is available in Juju application +The command to re-initialize the Raft cluster should be executed when charm is ready: +* the last Juju unit is available in Juju application * the last unit was has detected Raft majority lost, status: `Raft majority loss, run: promote-to-primary` To re-initialize Raft and fix the Partition/PostgreSQL cluster (when requested): -```shell + +```text juju run postgresql/x promote-to-primary scope=unit force=true ``` -[details="Example of Raft re-initialization"] +

Example of Raft re-initialization + Deploy PostgreSQL 3 units: -```shell -> juju deploy postgresql --config synchronous_node_count=1 + +```text +> juju deploy postgresql --channel 14/stable --config synchronous_node_count=1 > juju status Model Controller Cloud/Region Version SLA Timestamp @@ -58,8 +68,10 @@ Machine State Address Inst id Base AZ Message 1 started 10.189.210.166 juju-422c1a-1 ubuntu@22.04 Running 2 started 10.189.210.188 juju-422c1a-2 ubuntu@22.04 Running ``` -Find the current Primary/Standby/Replica: -```shell + +Find the current primary/standby/replica: + +```text > juju ssh postgresql/0 ubuntu@juju-422c1a-0:~$ sudo -u snap_daemon patronictl -c /var/snap/charmed-postgresql/current/etc/patroni/patroni.yaml list + Cluster: postgresql (7499430436963402504) ---+-----------+----+-----------+ @@ -71,8 +83,9 @@ ubuntu@juju-422c1a-0:~$ sudo -u snap_daemon patronictl -c /var/snap/charmed-post +--------------+----------------+--------------+-----------+----+-----------+ ``` -Kill the Leader and Sync Standby machines: -```shell +Kill the leader and sync standby machines: + +```text > lxc stop --force juju-422c1a-0 && lxc stop --force juju-422c1a-2 > juju status @@ -92,10 +105,12 @@ Machine State Address Inst id Base AZ Message 1 started 10.189.210.166 juju-422c1a-1 ubuntu@22.04 Running 2 down 10.189.210.188 juju-422c1a-2 ubuntu@22.04 Running ``` + At this stage it is recommended to restore the lost nodes, they will rejoin the cluster automatically once Juju detects their availability. To start Raft re-initialization, remove DEAD machines as a signal to charm that they cannot be restored/started and no risks for split-brain: -```shell + +```text > juju remove-machine --force 0 WARNING This command will perform the following actions: will remove machine 0 @@ -110,8 +125,10 @@ will remove machine 2 - will remove storage pgdata/2 Continue [y/N]? y ``` + Check the status to ensure `Raft majority loss`: -```shell + +```text > juju status ... Unit Workload Agent Machine Public address Ports Message @@ -120,11 +137,13 @@ postgresql/1* blocked executing 1 10.189.210.166 5432/tcp Raft majo ``` Start Raft re-initialization: -```shell + +```text > juju run postgresql/1 promote-to-primary scope=unit force=true ``` Wait for re-initiation to be completed: + ``` > juju status ... @@ -133,8 +152,9 @@ postgresql/1* maintenance executing 3 10.189.210.166 5432/tcp (promo ... ``` -At the end, the Primary until is back: -```shell +At the end, the primary until is back: + +```text > juju status Model Controller Cloud/Region Version SLA Timestamp postgresql lxd localhost/localhost 3.6.5 unsupported 15:03:12+02:00 @@ -150,12 +170,13 @@ Machine State Address Inst id Base AZ Message ``` Scale application to 3+ units to complete HA recovery: -```shell + +```text > juju add-unit postgresql -n 2 ``` The healthy status: -```shell +```text > juju status Model Controller Cloud/Region Version SLA Timestamp postgresql lxd localhost/localhost 3.6.5 unsupported 15:09:56+02:00 @@ -173,4 +194,5 @@ Machine State Address Inst id Base AZ Message 3 started 10.189.210.124 juju-422c1a-3 ubuntu@22.04 Running 4 started 10.189.210.178 juju-422c1a-4 ubuntu@22.04 Running ``` -[/details] \ No newline at end of file +
+ diff --git a/docs/how-to/upgrade/index.md b/docs/how-to/upgrade/index.md new file mode 100644 index 0000000000..4c95507927 --- /dev/null +++ b/docs/how-to/upgrade/index.md @@ -0,0 +1,23 @@ +# Upgrade + +For instructions on carrying out **minor version upgrades**, see the following guides: + +* [Minor upgrade](/how-to/upgrade/perform-a-minor-upgrade), e.g. PostgreSQL 14.8 -> PostgreSQL 14.9
+(including charm revision bump 42 -> 43). +* [Minor rollback](/how-to/upgrade/perform-a-minor-rollback), e.g. PostgreSQL 14.9 -> PostgreSQL 14.8
+(including charm revision return 43 -> 42). + +This charm does not support in-place upgrades for major version changes. + +```{note} +We will soon publish a migration guide with instructions on how to change from PostgreSQL 14 to 16. +``` + +```{toctree} +:titlesonly: +:maxdepth: 2 +:glob: +:hidden: + +Perform a minor upgrade +Perform a minor rollback diff --git a/docs/how-to/h-rollback-minor.md b/docs/how-to/upgrade/perform-a-minor-rollback.md similarity index 77% rename from docs/how-to/h-rollback-minor.md rename to docs/how-to/upgrade/perform-a-minor-rollback.md index e7d7754ff5..50ab8d7096 100644 --- a/docs/how-to/h-rollback-minor.md +++ b/docs/how-to/upgrade/perform-a-minor-rollback.md @@ -1,10 +1,5 @@ -[note] -**Note**: All commands are written for `juju >= v.3.0` - -If you are using an earlier version, check the [Juju 3.0 Release Notes](https://juju.is/docs/juju/roadmap#heading--juju-3-0-0---22-oct-2022). -[/note] - # Perform a minor rollback + **Example**: PostgreSQL 14.9 -> PostgreSQL 14.8
(including simple charm revision bump: from revision 43 to revision 42) @@ -12,11 +7,12 @@ After a `juju refresh`, if there are any version incompatibilities in charm revi Even if the underlying PostgreSQL cluster continues to work, it’s important to roll back the charm to a previous revision so that an update can be attempted after further inspection of the failure. -[note type="caution"] -**Warning:** Do NOT trigger `rollback` during the running `upgrade` action! It may cause an unpredictable PostgreSQL cluster state! -[/note] +```{caution} +Do NOT trigger `rollback` during the running `upgrade` action! It may cause an unpredictable PostgreSQL cluster state! +``` ## Summary of the rollback steps + 1. **Prepare** the Charmed PostgreSQL VM application for the in-place rollback. 2. **Rollback**. Once started, all units in a cluster will be executed sequentially. The rollback will be aborted (paused) if the unit rollback has failed. 3. **Check**. Make sure the charm and cluster are in a healthy state again. @@ -26,22 +22,25 @@ Even if the underlying PostgreSQL cluster continues to work, it’s important to To execute a rollback, we use a similar procedure to the upgrade. The difference is the charm revision to upgrade to. In this guide's example, we will refresh the charm back to revision `182`. It is necessary to re-run `pre-upgrade-check` action on the leader unit in order to enter the upgrade recovery state: -```shell + +```text juju run postgresql/leader pre-upgrade-check ``` ## Step 2: Rollback + When using a charm from charmhub: -```shell +```text juju refresh postgresql --revision=182 ``` When deploying from a local charm file, one must have the previous revision charm file and run the following command: -```shell + +```text juju refresh postgresql --path=./postgresql_ubuntu-22.04-amd64.charm ``` -> where `postgresql_ubuntu-22.04-amd64.charm` is the previous revision charm file. +where `postgresql_ubuntu-22.04-amd64.charm` is the previous revision charm file. The first unit will be rolled out and should rejoin the cluster after settling down. After the refresh command, the juju controller revision for the application will be back in sync with the running Charmed PostgreSQL revision. @@ -49,4 +48,5 @@ The first unit will be rolled out and should rejoin the cluster after settling d Future [improvements are planned](https://warthogs.atlassian.net/browse/DPE-2621) to check the state on pods/clusters on a low level. -For now, check `juju status` to make sure the cluster [state](/t/10844) is OK. \ No newline at end of file +For now, check `juju status` to make sure the cluster [state](/reference/statuses) is OK. + diff --git a/docs/how-to/h-upgrade-minor.md b/docs/how-to/upgrade/perform-a-minor-upgrade.md similarity index 86% rename from docs/how-to/h-upgrade-minor.md rename to docs/how-to/upgrade/perform-a-minor-upgrade.md index ec1ea6402d..47e5bfff80 100644 --- a/docs/how-to/h-upgrade-minor.md +++ b/docs/how-to/upgrade/perform-a-minor-upgrade.md @@ -1,32 +1,21 @@ -[note] -**Note**: All commands are written for `juju >= v.3.0` - -If you are using an earlier version, check the [Juju 3.0 Release Notes](https://juju.is/docs/juju/roadmap#heading--juju-3-0-0---22-oct-2022). -[/note] - # Perform a minor upgrade **Example**: PostgreSQL 14.8 -> PostgreSQL 14.9
(including charm revision bump: e.g. Revision 193 -> Revision 196) -This guide is part of [Charmed PostgreSQL Upgrades](/t/12086). Refer to this page for more information and an overview of the content. - ## Summary + - [**Pre-upgrade checks**](#pre-upgrade-checks): Important information to consider before starting an upgrade. - [**1. Collect**](#step-1-collect) all necessary pre-upgrade information. It will be necessary for a rollback, if needed. **Do not skip this step**; better to be safe than sorry! - [**2. Prepare**](#step-2-prepare) your Charmed PostgreSQL Juju application for the in-place upgrade. See the step details for all technical details executed by charm here. - [**3. Upgrade**](#step-3-upgrade). Once started, all units in a cluster will be executed sequentially. The upgrade will be aborted (paused) if the unit upgrade has failed. - [**4. (Optional) Consider a rollback**](#step-4-rollback-optional) in case of disaster. - - Please [inform us](/t/11863) about your case scenario troubleshooting to trace the source of the issue and prevent it in the future. -- [**Post-upgrade check**](#step-5-post-upgrade-check). Make sure all units are in the proper state and the cluster is healthy. - ---- + - Please [inform us](/reference/contacts) about your case scenario troubleshooting to trace the source of the issue and prevent it in the future. +- [**Post-upgrade check**](#post-upgrade-check). Make sure all units are in the proper state and the cluster is healthy. ## Pre-upgrade checks -Before performing a minor PostgreSQL upgrade, there are some important considerations to take into account: -* Concurrency with other operations during the upgrade -* Backing up your data -* Service disruption + +Key topics to take into consideration before upgrading. ### Concurrency with other operations **We strongly recommend to NOT perform any other extraordinary operations on Charmed PostgreSQL cluster while upgrading.** @@ -43,7 +32,7 @@ Concurrency with other operations is not supported, and it can lead the cluster ### Backups **Make sure to have a backup of your data when running any type of upgrade.** -Guides on how to configure backups with S3-compatible storage can be found [here](/t/9683). +Guides on how to configure backups with S3-compatible storage can be found [here](/how-to/back-up-and-restore/create-a-backup). ### Service disruption **It is recommended to deploy your application in conjunction with the [Charmed PgBouncer](https://charmhub.io/pgbouncer) operator.** @@ -52,15 +41,15 @@ This will ensure minimal service disruption, if any. ## Step 1: Collect -[note] +```{note} This step is only valid when deploying from [charmhub](https://charmhub.io/). If a [local charm](https://juju.is/docs/sdk/deploy-a-charm) is deployed (revision is small, e.g. 0-10), make sure the proper/current local revision of the `.charm` file is available BEFORE going further. You might need it for a rollback. -[/note] +``` The first step is to record the revision of the running application as a safety measure for a rollback action. To accomplish this, run the `juju status` command and look for the deployed Charmed PostgreSQL revision in the command output, e.g.: -```shell +```text Model Controller Cloud/Region Version SLA Timestamp welcome-lxd lxd localhost/localhost 3.1.6 unsupported 11:35:36+02:00 @@ -84,7 +73,7 @@ In this example, the current revision is `330`. Store it safely to use in case o Before running the [`juju refresh`](https://juju.is/docs/juju/juju-refresh) command, it’s necessary to run the `pre-upgrade-check` action against the leader unit: -```shell +```text juju run postgresql/leader pre-upgrade-check ``` Make sure there are no errors in the result output. @@ -93,32 +82,45 @@ This action will configure the charm to minimize the amount of primary switchove ## Step 3: Upgrade +```{important} +**Do NOT trigger `rollback` procedure during the running `upgrade` procedure.** +It is expected to have some status changes during the process: `waiting`, `maintenance`, `active`. + +Make sure the upgrade has failed/stopped and cannot be fixed/continued before triggering `rollback`! + +**Please be patient during huge installations.** +Each unit should recover shortly after the upgrade, but time can vary depending on the amount of data written to the cluster while the unit was not part of it. + +**Incompatible charm revisions or dependencies will halt the process.** +After a `juju refresh`, if there are any version incompatibilities in charm revisions, its dependencies, or any other unexpected failure in the upgrade process, the upgrade process will be halted and enter a failure state. +``` + Use the `juju refresh` command to trigger the charm upgrade process. Example with channel selection: -```shell +```text juju refresh postgresql --channel 14/edge ``` Example with specific revision selection: -```shell +```text juju refresh postgresql --revision=342 ``` Example with a local charm file: -```shell +```text juju refresh postgresql --path ./postgresql_ubuntu-22.04-amd64.charm ``` All units will be refreshed (i.e. receive new charm content), and the upgrade will execute one unit at a time. -[note] -**Note:** To reduce connection disruptions, the order in which the units are upgraded is based on roles: +```{note} +To reduce connection disruptions, the order in which the units are upgraded is based on roles: First the `replica` units, then the `sync-standby` units, and lastly, the `leader`(or `primary`) unit. -[/note] +``` `juju status` will look like similar to the output below: -```shell +```text Model Controller Cloud/Region Version SLA Timestamp welcome-lxd lxd localhost/localhost 3.1.6 unsupported 11:36:18+02:00 @@ -138,7 +140,7 @@ Machine State Address Inst id Base AZ Message After each unit completes the upgrade, the message will go blank, and a next unit will follow: -```shell +```text Model Controller Cloud/Region Version SLA Timestamp welcome-lxd lxd localhost/localhost 3.1.6 unsupported 11:36:31+02:00 @@ -155,17 +157,6 @@ Machine State Address Inst id Base AZ Message 4 started 10.3.217.95 juju-d483b7-4 ubuntu@22.04 Running 5 started 10.3.217.108 juju-d483b7-5 ubuntu@22.04 Running ``` -### Important Notes -**Do NOT trigger `rollback` procedure during the running `upgrade` procedure.** -It is expected to have some status changes during the process: `waiting`, `maintenance`, `active`. - -Make sure `upgrade` has failed/stopped and cannot be fixed/continued before triggering `rollback`! - -**Please be patient during huge installations.** -Each unit should recover shortly after the upgrade, but time can vary depending on the amount of data written to the cluster while the unit was not part of it. - -**Incompatible charm revisions or dependencies will halt the process.** -After a `juju refresh`, if there are any version incompatibilities in charm revisions, its dependencies, or any other unexpected failure in the upgrade process, the upgrade process will be halted and enter a failure state. ## Step 4: Rollback (optional) @@ -173,13 +164,13 @@ The step must be skipped if the upgrade went well! Although the underlying PostgreSQL Cluster continues to work, it’s important to roll back the charm to a previous revision so that an update can be attempted after further inspection of the failure. -> See: [How to perform a minor rollback](/t/12090) +> See: [](/how-to/upgrade/perform-a-minor-rollback) ## Post-upgrade check Future [improvements are planned](https://warthogs.atlassian.net/browse/DPE-2621) to check the state of a pod/cluster on a low level. -For now, use `juju status` to make sure the cluster [state](/t/10844) is OK. +For now, use `juju status` to make sure the cluster [state](/reference/statuses) is OK. \ No newline at end of file +---> + diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000000..3ebd1abf5e --- /dev/null +++ b/docs/index.md @@ -0,0 +1,46 @@ +# Charmed PostgreSQL documentation + +Charmed PostgreSQL is an open-source software operator designed to deploy and operate object-relational databases on IAAS/VM. It packages the powerful database management system [PostgreSQL](https://www.postgresql.org/) into a charmed operator for deployment with [Juju](https://juju.is/docs/juju). + +This charmed operator meets the need of simplifying deployment, scaling, configuration and management of relational databases in large-scale production environments reliably. It is equipped with several features to securely store and scale complicated data workloads, including easy integration with client applications. + +Charmed PostgreSQL is made for anyone looking for a comprehensive database management interface, whether for operating a complex production environment or simply as a playground to learn more about databases and charms. + +```{note} +This is a **IAAS/VM** operator. To deploy on Kubernetes, see [Charmed PostgreSQL K8s](https://canonical-charmed-postgresql-k8s.readthedocs-hosted.com/). +``` + +| | | +|--|--| +| [**Get started**](/tutorial/index) - [Deploy on a cloud](/how-to/deploy/index) \| [Scale](/how-to/scale-replicas) \| [Manage passwords](/how-to/manage-passwords) \| [Enable encryption](/how-to/enable-tls) \| [Back up](/how-to/back-up-and-restore/index) \| [Monitoring](/how-to/monitoring-cos/index)
| [**How-to guides**](/how-to/index) for key tasks, use-cases, and problems. These guides assume basic familiarity with Juju and PostgreSQL.
| +| [**Reference**](/reference/index) - Technical information for quick lookup, such as [requirements](/reference/system-requirements), [plugins](/reference/plugins-extensions), and [statuses](/reference/statuses). | [**Explanation**](/explanation/interfaces-and-endpoints) - Discussion and clarification of key topics such as [architecture](/explanation/architecture), [users](/explanation/users), and [legacy charms](/explanation/legacy-charm)| + + +## Project and community + +Charmed PostgreSQL is an official distribution of PostgreSQL. It’s an open-source project that welcomes community contributions, suggestions, fixes and constructive feedback. +- [Read our Code of Conduct](https://ubuntu.com/community/code-of-conduct) +- [Join the Discourse forum](https://discourse.charmhub.io/tag/postgresql) +- [Contribute](https://github.com/canonical/postgresql-operator/blob/main/CONTRIBUTING.md) to the code or report an [issue](https://github.com/canonical/postgresql-operator/issues/new/choose) +- Explore [Canonical Data solutions](https://canonical.com/data) +- [Contacts us](/reference/contacts) for all further questions + +## Licencing & Trademark + +The Charmed PostgreSQL Operator is distributed under the [Apache Software Licence version 2.0](https://github.com/canonical/postgresql-operator/blob/main/LICENSE). It depends on [PostgreSQL](https://www.postgresql.org/ftp/source/), which is licensed under the [PostgreSQL License](https://www.postgresql.org/about/licence/) - a liberal open-source licence similar to the BSD or MIT licences. + +PostgreSQL is a trademark or registered trademark of PostgreSQL Global Development Group. Other trademarks are the property of their respective owners. + + +```{toctree} +:titlesonly: +:maxdepth: 2 +:glob: +:hidden: + +Home +Tutorial +How-to guides +Reference +Explanation + diff --git a/docs/overview.md b/docs/overview.md deleted file mode 100644 index 3d24b83d2a..0000000000 --- a/docs/overview.md +++ /dev/null @@ -1,138 +0,0 @@ -> This is a **IAAS/VM** operator. To deploy on Kubernetes, see [Charmed PostgreSQL K8s](https://charmhub.io/postgresql-k8s). - -# Charmed PostgreSQL documentation - -Charmed PostgreSQL is an open-source software operator designed to deploy and operate object-relational databases on IAAS/VM. It packages the powerful database management system [PostgreSQL](https://www.postgresql.org/) into a charmed operator for deployment with [Juju](https://juju.is/docs/juju). - -This charm offers automated operations management from day 0 to day 2. It is equipped with several features to securely store and scale complicated data workloads, including TLS encryption, backups, monitoring, password rotation, and easy integration with client applications. - -Charmed PostgreSQL meets the need of deploying PostgreSQL in a structured and consistent manner while providing flexibility in configuration. It simplifies deployment, scaling, configuration and management of relational databases in large-scale production environments reliably. - -This charmed operator is made for anyone looking for a comprehensive database management interface, whether for operating a complex production environment or simply as a playground to learn more about databases and charms. - - - -## In this documentation - -| | | -|--|--| -| [**Tutorials**](/t/9707)
[Get started](/t/9707) - a hands-on introduction to using Charmed PostgreSQL operator for new users
| [**How-to guides**](/t/9689)
Step-by-step guides covering key operations such as [scaling](/t/9689), [encryption](/t/9685), and [restoring backups](/t/9693) | -| [**Reference**](/t/13976)
Technical information such as [requirements](/t/11743), [release notes](/t/11875), and [plugins](/t/10946) | [**Explanation**](/t/10251)
Concepts - discussion and clarification of key topics such as [architecture](/t/11857), [users](/t/10798), and [legacy charms](/t/10690)| -## Project and community - -Charmed PostgreSQL is an official distribution of PostgreSQL. It’s an open-source project that welcomes community contributions, suggestions, fixes and constructive feedback. -- [Read our Code of Conduct](https://ubuntu.com/community/code-of-conduct) -- [Join the Discourse forum](https://discourse.charmhub.io/tag/postgresql) -- [Contribute](https://github.com/canonical/postgresql-operator/blob/main/CONTRIBUTING.md) to the code or report an [issue](https://github.com/canonical/postgresql-operator/issues/new/choose) -- Explore [Canonical Data Fabric solutions](https://canonical.com/data) -- [Contacts us](/t/11863) for all further questions - -## Licencing & Trademark -The Charmed PostgreSQL Operator is distributed under the [Apache Software Licence version 2.0](https://github.com/canonical/postgresql-operator/blob/main/LICENSE). It depends on [PostgreSQL](https://www.postgresql.org/ftp/source/), which is licensed under the [PostgreSQL License](https://www.postgresql.org/about/licence/) - a liberal open-source licence similar to the BSD or MIT licences. - -PostgreSQL is a trademark or registered trademark of PostgreSQL Global Development Group. Other trademarks are the property of their respective owners. - - -# Navigation - -[details=Navigation] - -| Level | Path | Navlink | -|--------|--------|-------------| -| 1 | tutorial | [Tutorial](/t/9707) | -| 2 | t-set-up | [1. Set up environment](/t/9709) | -| 2 | t-deploy | [2. Deploy PostgreSQL](/t/9697) | -| 2 | t-access| [3. Access PostgreSQL](/t/15798) | -| 2 | t-scale | [4. Scale replicas](/t/9705) | -| 2 | t-manage-passwords | [5. Manage passwords](/t/9703) | -| 2 | t-integrate | [6. Integrate with other applications](/t/9701) | -| 2 | t-enable-tls | [7. Enable TLS encryption](/t/9699) | -| 2 | t-clean-up | [8. Clean up environment](/t/9695) | -| 1 | how-to | [How-to guides](/t/16766) | -| 2 | h-deploy | [Deploy](/t/16811) | -| 3 | h-deploy-sunbeam | [Sunbeam](/t/15972) | -| 3 | h-deploy-maas | [MAAS](/t/14293) | -| 3 | h-deploy-ec2 | [AWS EC2](/t/15703) | -| 3 | h-deploy-gce | [GCE](/t/15722) | -| 3 | h-deploy-azure | [Azure](/t/15733) | -| 3 | h-deploy-multi-az | [Multi-AZ](/t/15749) | -| 3 | h-deploy-terraform | [Terraform](/t/14916) | -| 3 | h-deploy-tls-vip-access | [TLS VIP access](/t/16576) | -| 3 | h-deploy-juju-spaces | [Juju spaces](/t/17416) | -| 3 | h-deploy-airgapped | [Air-gapped](/t/15746) | -| 3 | h-deploy-juju-storage | [Juju storage](/t/17529) | -| 2 | h-integrate | [Integrate with another application](/t/9687) | -| 2 | h-external-access | [External network access](/t/15802) | -| 2 | h-scale | [Scale replicas](/t/9689) | -| 2 | h-switchover-failover | [Switchover/failover](/t/17523) | -| 2 | h-enable-tls | [Enable TLS](/t/9685) | -| 2 | h-enable-ldap | [Enable LDAP](/t/17361) | -| 2 | h-enable-plugins-extensions | [Enable plugins/extensions](/t/10906) | -| 2 | h-backup | [Back up and restore]() | -| 3 | h-configure-s3-aws | [Configure S3 AWS](/t/9681) | -| 3 | h-configure-s3-radosgw | [Configure S3 RadosGW](/t/10313) | -| 3 | h-create-backup | [Create a backup](/t/9683) | -| 3 | h-restore-backup | [Restore a backup](/t/9693) | -| 3 | h-manage-backup-retention | [Manage backup retention](/t/14249) | -| 3 | h-migrate-cluster | [Migrate a cluster](/t/9691) | -| 2 | h-monitor | [Monitoring (COS)]() | -| 3 | h-enable-monitoring | [Enable monitoring](/t/10600) | -| 3 | h-enable-alert-rules | [Enable alert rules](/t/13084) | -| 3 | h-enable-tracing | [Enable tracing](/t/14521) | -| 3 | h-enable-profiling | [Enable profiling](/t/17172) | -| 2 | h-upgrade | [Upgrade](/t/12086) | -| 3 | h-upgrade-minor | [Perform a minor upgrade](/t/12089) | -| 3 | h-rollback-minor | [Perform a minor rollback](/t/12090) | -| 2 | h-async | [Cross-regional async replication](/t/15412) | -| 3 | h-async-set-up | [Set up clusters](/t/13991) | -| 3 | h-async-integrate | [Integrate with a client app](/t/13992) | -| 3 | h-async-remove-recover | [Remove or recover a cluster](/t/13994) | -| 2 | h-development| [Development]() | -| 3 | h-development-integrate | [Integrate with your charm](/t/11865) | -| 3 | h-migrate-pgdump | [Migrate data via pg_dump](/t/12163) | -| 3 | h-migrate-backup-restore | [Migrate data via backup/restore](/t/12164) | -| 1 | reference | [Reference](/t/13976) | -| 2 | r-releases | [Releases](/t/11875) | -| 2 | r-versions | [Versions](/t/17405) | -| 2 | r-system-requirements | [System requirements](/t/11743) | -| 2 | r-software-testing | [Software testing](/t/11773) | -| 2 | r-performance | [Performance and resources](/t/11974) | -| 2 | r-troubleshooting | [Troubleshooting](/t/11864) | -| 3 | r-sos-report | [SOS report](/t/17228) | -| 3 | r-cli-helpers | [CLI helpers](/t/17406) | -| 2 | r-plugins-extensions | [Plugins/extensions](/t/10946) | -| 3 | r-plugins-timescaledb | [TimescaleDB](/t/17528) | -| 2 | r-alert-rules | [Alert rules](/t/15841) | -| 2 | r-statuses | [Statuses](/t/10844) | -| 2 | r-contacts | [Contacts](/t/11863) | -| 1 | explanation | [Explanation](/t/16768) | -| 2 | e-architecture | [Architecture](/t/11857) | -| 2 | e-interfaces-endpoints | [Interfaces and endpoints](/t/10251) | -| 2 | e-juju-details | [Juju](/t/11985) | -| 2 | e-legacy-charm | [Legacy charm](/t/10690) | -| 2 | e-units | [Units](/t/17525) | -| 2 | e-users | [Users](/t/10798) | -| 2 | e-logs | [Logs](/t/12099) | -| 2 | e-connection-pooling| [Connection pooling](/t/15777) | -| 2 | e-security | [Security](/t/16852) | -| 3 | e-cryptography | [Cryptography](/t/16853) | -| 1 | search | [Search](https://canonical.com/data/docs/postgresql/iaas) | - -[/details] - - \ No newline at end of file diff --git a/docs/reference.md b/docs/reference.md deleted file mode 100644 index 2decbe04cb..0000000000 --- a/docs/reference.md +++ /dev/null @@ -1,26 +0,0 @@ -# Reference - -Technical specifications, APIs, release notes, and other reference material for fast lookup. - -**In the left sidebar navigation**, you will find the following references: -| Page | Description | -|---------------------------|---------------------------------------------------| -| [Release Notes](/t/11875) | Release notes for major revisions of this charm | -| [System requirements](/t/11743) | Software and hardware requirements | -| [Software testing](/t/11773) | Software tests (e.g. smoke, unit, performance...) | -| [Performance and resources](/t/11974) | Config profiles related to performance | -| [Troubleshooting](/t/11864) | Troubleshooting tips and tricks | -| [Plugins/extensions](/t/10946) | Plugins/extensions supported by each charm revision | -| [Alert rules](/t/15841) | Pre-configured Prometheus alert rules | -| [Charm statuses](/t/10844) | Juju application statuses | -| [Contacts](/t/11863) | Contact information | - - -**In the tabs at the top of the page**, you will find the following automatically generated API references: - -| Page | Description | -|----------------------------------------------------------------------------|---------------------------------------------------------| -| [Integrations](https://charmhub.io/postgresql/integrations) | Integration/relation interfaces supported by this charm | -| [Libraries](https://charmhub.io/postgresql/libraries) | VM charm library is empty as charm uses [K8s library](https://charmhub.io/postgresql-k8s/libraries/) (more info [here](/t/11857)) | -| [Configuration](https://charmhub.io/postgresql/configuration) | Application configuration parameters | -| [Actions](https://charmhub.io/postgresql/actions) | Juju actions supported by this charm | \ No newline at end of file diff --git a/docs/reference/r-alert-rules.md b/docs/reference/alert-rules.md similarity index 98% rename from docs/reference/r-alert-rules.md rename to docs/reference/alert-rules.md index 08bee1d7e5..a3c20c0a71 100644 --- a/docs/reference/r-alert-rules.md +++ b/docs/reference/alert-rules.md @@ -5,7 +5,7 @@ This page contains a markdown version of the alert rules described in the `postg * [`src/prometheus_alert_rules/pgbouncer_rules.yaml`](https://github.com/canonical/postgresql-operator/blob/main/src/prometheus_alert_rules/pgbouncer_rules.yaml) * [`src/prometheus_alert_rules/patroni_rules.yaml`](https://github.com/canonical/postgresql-operator/blob/main/src/prometheus_alert_rules/patroni_rules.yaml) -> This documentation describes the latest alert rule expressions. See the YAML file(s) on listed above if you require an older version. +> This documentation describes the latest alert rule expressions. See the YAML file(s) listed above if you require an older version. ## PostgresqlExporter @@ -51,4 +51,5 @@ This page contains a markdown version of the alert rules described in the `postg [info]: https://img.shields.io/badge/info-blue [warning]: https://img.shields.io/badge/warning-yellow -[critical]: https://img.shields.io/badge/critical-red \ No newline at end of file +[critical]: https://img.shields.io/badge/critical-red + diff --git a/docs/reference/r-contacts.md b/docs/reference/contacts.md similarity index 97% rename from docs/reference/r-contacts.md rename to docs/reference/contacts.md index ed3075fe4a..7bc6b284ae 100644 --- a/docs/reference/r-contacts.md +++ b/docs/reference/contacts.md @@ -6,10 +6,9 @@ Charmed PostgreSQL is an open source project that warmly welcomes community cont * [Report](https://github.com/canonical/postgresql-operator/security/advisories/new) security issues * Contact the Canonical Data Platform team directly through our [Matrix](https://matrix.to/#/#charmhub-data-platform:ubuntu.com) channel. -[note] +```{note} Our legacy [Mattermost](https://chat.charmhub.io/charmhub/channels/data-platform) channel is read-only until January 31, 2025. -[/note] - +``` Useful links: @@ -18,4 +17,5 @@ Useful links: * [Git sources for Charmed PostgreSQL](https://github.com/canonical/postgresql-operator) * [Canonical Data on Launchpad](https://launchpad.net/~data-platform) * [Canonical Data on Matrix](https://matrix.to/#/#charmhub-data-platform:ubuntu.com) -* [Mailing list on Launchpad](https://lists.launchpad.net/data-platform/) \ No newline at end of file +* [Mailing list on Launchpad](https://lists.launchpad.net/data-platform/) + diff --git a/docs/reference/index.md b/docs/reference/index.md new file mode 100644 index 0000000000..8bddca053b --- /dev/null +++ b/docs/reference/index.md @@ -0,0 +1,29 @@ +# Reference + +The following generated API references can be found on [Charmhub](https://charmhub.io/postgresql): + +| Page | Description | +|------|-------------| +| [Integrations](https://charmhub.io/postgresql/integrations) | Integration/relation interfaces supported by this charm | +| [Libraries](https://charmhub.io/postgresql/libraries) | VM charm library is empty as charm uses [K8s library](https://charmhub.io/postgresql-k8s/libraries/) (more info [here](/explanation/architecture)) | +| [Configuration](https://charmhub.io/postgresql/configuration) | Application configuration parameters | +| [Actions](https://charmhub.io/postgresql/actions) | Juju actions supported by this charm | + +The following guides contain technical specifications, APIs, release notes, and other reference material for fast lookup. + + +```{toctree} +:titlesonly: +:maxdepth: 2 +:glob: + +Releases +Versions +System requirements +Software testing +Performance and resources +Troubleshooting +Plugins/extensions +Alert rules +Statuses +Contacts diff --git a/docs/reference/r-performance.md b/docs/reference/performance-and-resources.md similarity index 74% rename from docs/reference/r-performance.md rename to docs/reference/performance-and-resources.md index 49f689d17a..784aee34a3 100644 --- a/docs/reference/r-performance.md +++ b/docs/reference/performance-and-resources.md @@ -2,43 +2,48 @@ This page covers topics related to measuring and configuring the performance of PostgreSQL ---- +## Performance testing -

Performance testing

For performance testing and benchmarking charms, we recommend using the [Charmed Sysbench](https://charmhub.io/sysbench) operator. This is a tool for benchmarking database applications that includes monitoring and CPU/RAM/IO performance measurement. -

Resource allocation

-Charmed PostgreSQL resource allocation can be controlled via the charm's `profile` config option. There are two profiles: `production` and `testing`. +## Resource allocation + +Charmed PostgreSQL resource allocation can be controlled via the charm's `profile` config option. |Value|Description|Details| | --- | --- | ----- | |`production`
(default)|[Maximum performance](https://github.com/canonical/postgresql-operator/blob/main/lib/charms/postgresql_k8s/v0/postgresql.py#L437-L446)| 25% of the available memory for `shared_buffers` and the remain as cache memory (defaults mimic legacy charm behaviour).
The `max_connections`=max(4 * os.cpu_count(), 100).
Use [pgbouncer](https://charmhub.io/pgbouncer?channel=1/stable) if max_connections are not enough ([reasoning](https://www.percona.com/blog/scaling-postgresql-with-pgbouncer-you-may-need-a-connection-pooler-sooner-than-you-expect/)).| |`testing`|[Minimal resource usage](https://github.com/canonical/postgresql-operator/blob/main/lib/charms/postgresql_k8s/v0/postgresql.py#L437-L446)| PostgreSQL 14 defaults. | -[note type="caution"] -**Note**: Pre-deployed application profile change is planned but currently is NOT supported. -[/note] +```{caution} +Pre-deployed application profile change is planned but currently is NOT supported. +``` You can set the profile during deployment using the `--config` flag. For example: -```shell -juju deploy postgresql --config profile=testing + +```text +juju deploy postgresql --channel 14/stable --config profile=testing ``` + You can change the profile using the `juju config` action. For example: -```shell + +```text juju config postgresql profile=production ``` + For a list of all of this charm's config options, see the [Configuration tab](https://charmhub.io/postgresql/configure#profile). ### Juju constraints The Juju [`--constraints`](https://juju.is/docs/juju/constraint) flag sets RAM and CPU limits for [Juju units](https://juju.is/docs/juju/unit): -```shell -juju deploy postgresql --constraints cores=8 mem=16G +```text +juju deploy postgresql --channel 14/stable --constraints cores=8 mem=16G ``` Juju constraints can be set together with the charm's profile: -```shell -juju deploy postgresql --constraints cores=8 mem=16G --config profile=testing -``` \ No newline at end of file +```text +juju deploy postgresql --channel 14/stable --constraints cores=8 mem=16G --config profile=testing +``` + diff --git a/docs/reference/r-plugins-extensions.md b/docs/reference/plugins-extensions.md similarity index 99% rename from docs/reference/r-plugins-extensions.md rename to docs/reference/plugins-extensions.md index 89c356eb35..9021921bcc 100644 --- a/docs/reference/r-plugins-extensions.md +++ b/docs/reference/plugins-extensions.md @@ -61,4 +61,5 @@ If you need support for other extensions, feel free to reach out to us on our [M | `unaccent` | [304+](https://github.com/canonical/postgresql-operator/releases/tag/rev304) | | `unaccent` | [347+](https://github.com/canonical/postgresql-operator/releases/tag/rev347) | | `unaccent` | [357+](https://github.com/canonical/postgresql-operator/releases/tag/rev357) | -| `uuid-ossp` | [347+](https://github.com/canonical/postgresql-operator/releases/tag/rev347) | \ No newline at end of file +| `uuid-ossp` | [347+](https://github.com/canonical/postgresql-operator/releases/tag/rev347) | + diff --git a/docs/reference/r-releases.md b/docs/reference/releases.md similarity index 58% rename from docs/reference/r-releases.md rename to docs/reference/releases.md index f67d6fc623..f440c8b4d9 100644 --- a/docs/reference/r-releases.md +++ b/docs/reference/releases.md @@ -2,19 +2,19 @@ This page provides high-level overviews of the dependencies and features that are supported by each revision in every stable release. -To learn more about the different release tracks and channels, see the [Juju documentation about channels](https://juju.is/docs/juju/channel#heading--risk). +To learn more about the different release tracks and channels, see the [Juju documentation about channels](https://juju.is/docs/juju/channel#risk). To see all releases and commits, check the [Charmed PostgreSQL Releases page on GitHub](https://github.com/canonical/postgresql-operator/releases). ## Dependencies and supported features For a given release, this table shows: -* The PostgreSQL version packaged inside. +* The PostgreSQL 14 version packaged inside. * The minimum Juju 3 version required to reliably operate **all** features of the release - > This charm still supports older versions of Juju down to 2.9. See the [Juju section of the system requirements](/t/11743) for more details. + > This charm still supports older versions of Juju down to 2.9. See the [Juju section of the system requirements](/reference/system-requirements) for more details. * Support for specific features -| Release | PostgreSQL version | Juju 3 version | [TLS encryption](/t/9685)* | [COS monitoring](/t/10600) | [Minor version upgrades](/t/12089) | [Cross-regional async replication](/t/15412) | [Point-in-time recovery](/t/9693) | +| Release | PostgreSQL version | Juju 3 version | [TLS encryption](/how-to/enable-tls)* | [COS monitoring](/how-to/monitoring-cos/enable-monitoring) | [Minor version upgrades](/how-to/upgrade/perform-a-minor-upgrade) | [Cross-regional async replication](/how-to/cross-regional-async-replication/index) | [Point-in-time recovery](/how-to/back-up-and-restore/restore-a-backup) | |:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:| | [552], [553] | 14.15 | `3.6.1+` | ![check] | ![check] | ![check] | ![check] | ![check] | | [467], [468] | 14.12 | `3.4.3+` | ![check] | ![check] | ![check] | ![check] | ![check] | @@ -26,15 +26,17 @@ For a given release, this table shows: \* **TLS encryption**: Support for **`v2` or higher** of the [`tls-certificates` interface](https://charmhub.io/tls-certificates-interface/libraries/tls_certificates). This means that you can integrate with [modern TLS charms](https://charmhub.io/topics/security-with-x-509-certificates). -For more details about a particular revision, refer to its dedicated Release Notes page. -For more details about each feature/interface, refer to the documentation linked in the column header. - ## Architecture and base + Several [revisions](https://juju.is/docs/sdk/revision) are released simultaneously for different [bases/series](https://juju.is/docs/juju/base) using the same charm code. In other words, one release contains multiple revisions. -> If you do not specify a revision on deploy time, Juju will automatically choose the revision that matches your base and architecture. +If you do not specify a revision on deploy time, Juju will automatically choose the revision that matches your base and architecture. -> If you deploy a specific revision, **you must make sure it matches your base and architecture** via the tables below or with [`juju info`](https://juju.is/docs/juju/juju-info) +```{caution} +If you deploy with the `--revision` flag, **you must make sure the revision matches your base and architecture**. + +Check the tables below, or use [`juju info`](https://juju.is/docs/juju/juju-info). +``` ### Release 552-553 @@ -43,56 +45,25 @@ Several [revisions](https://juju.is/docs/sdk/revision) are released simultaneous |[553] | ![check] | | ![check] | |[552] | | ![check] | ![check] | -[details=Older releases] - -### Release 467-468 - -| Revision | amd64 | arm64 | Ubuntu 22.04 LTS -|:--------:|:-----:|:-----:|:-----:| -|[468] |![check] | | ![check] | -|[467] | | ![check]| ![check] | - -### Release 429-430 +
+Older releases | Revision | amd64 | arm64 | Ubuntu 22.04 LTS |:--------:|:-----:|:-----:|:-----:| -|[430] |![check]| | ![check] | -|[429] | | ![check]| ![check] | +|[468] |![check] | | ![check] | +|[467] | | ![check] | ![check] | +|[430] |![check] | | ![check] | +|[429] | | ![check] | ![check] | +|[363] |![check] | | ![check] | +|[351] |![check] | | ![check] | +|[336] |![check] | | ![check] | +|[288] |![check] | | ![check] | -### Release 363 - -| Revision | amd64 | arm64 | Ubuntu 22.04 LTS -|:--------:|:-----:|:-----:|:-----:| -|[363] | ![check]| | ![check] | - - -### Release 351 - -| Revision | amd64 | arm64 | Ubuntu 22.04 LTS -|:--------:|:-----:|:-----:|:-----:| -|[351] |![check]| | ![check] | - - -### Release 336 - -| Revision | amd64 | arm64 | Ubuntu 22.04 LTS -|:--------:|:-----:|:-----:|:-----:| -|[336] |![check]| | ![check] | - - -### Release 288 - -| Revision | amd64 | arm64 | Ubuntu 22.04 LTS -|:--------:|:-----:|:-----:|:-----:| -|[288] |![check]| | ![check] | - -[/details] +
## Plugins/extensions -For a list of all plugins supported for each revision, see the reference page [Plugins/extensions](/t/10946). - -> **Note**: Our release notes are an ongoing work in progress. If there is any additional information about releases that you would like to see or suggestions for other improvements, don't hesitate to contact us on [Matrix ](https://matrix.to/#/#charmhub-data-platform:ubuntu.com) or [leave a comment](https://discourse.charmhub.io/t/charmed-postgresql-reference-release-notes/11875). +For a list of all plugins supported for each revision, see the reference page [Plugins/extensions](/reference/plugins-extensions). [553]: https://github.com/canonical/postgresql-operator/releases/tag/rev552 @@ -111,4 +82,5 @@ For a list of all plugins supported for each revision, see the reference page [P -[check]: https://img.icons8.com/color/20/checkmark--v1.png \ No newline at end of file +[check]: https://img.icons8.com/color/20/checkmark--v1.png + diff --git a/docs/reference/r-software-testing.md b/docs/reference/software-testing.md similarity index 74% rename from docs/reference/r-software-testing.md rename to docs/reference/software-testing.md index 5c3800c694..28464f1e77 100644 --- a/docs/reference/r-software-testing.md +++ b/docs/reference/software-testing.md @@ -1,31 +1,19 @@ -[note] -**Note**: All commands are written for `juju >= v.3.1` - -If you're using `juju 2.9`, check the [`juju 3.0` Release Notes](https://juju.is/docs/juju/roadmap#heading--juju-3-0-0---22-oct-2022). -[/note] - # Software testing for charms Most types of standard [software tests](https://en.wikipedia.org/wiki/Software_testing) are applicable to Charmed PostgreSQL. -This reference addresses the following types: +## Smoke test -* [Smoke test](#heading--smoke) -* [Unit tests](#heading--unit) -* [Integration tests](#heading--integration) -* [System test](#heading--system) - ---- -

Smoke test

This type of test ensures that basic functionality works over a short amount of time. + ### Steps -1. [Set up a `juju v.3.x` environment](/t/9297) -2. Deploy database with test application -3. Start "continuous write" test + +1. Deploy database with test application +2. Start "continuous write" test
Example -```shell +```text juju add-model smoke-test juju deploy postgresql --channel 14/edge @@ -57,25 +45,28 @@ watch -n1 -x juju ssh postgresql/leader "psql postgresql://${user}:${pass}@${ip}
### Expected results + * `postgresql-test-app` continuously inserts records into the database received through the integration (the table `continuous_writes`). * The counters (amount of records in table) are growing on all cluster members ### Tips + To stop the "continuous write" test, run -```shell +```text juju run postgresql-test-app/leader stop-continuous-writes ``` To truncate the "continuous write" table (i.e. delete all records from database), run -```shell +```text juju run postgresql-test-app/leader clear-continuous-writes ``` -

Unit test

+## Unit test Check the [Contributing guide](https://github.com/canonical/postgresql-operator/blob/main/CONTRIBUTING.md#testing) on GitHub and follow `tox run -e unit` examples there. -

Integration test

+## Integration test Check the [Contributing guide](https://github.com/canonical/postgresql-operator/blob/main/CONTRIBUTING.md#testing) on GitHub and follow `tox run -e integration` examples there. -

System test

+## System test To perform a system test, deploy [`postgresql-bundle`](https://charmhub.io/postgresql-bundle). -This charm bundle automatically deploys and tests all the necessary parts at once. \ No newline at end of file +This charm bundle automatically deploys and tests all the necessary parts at once. + diff --git a/docs/reference/r-statuses.md b/docs/reference/statuses.md similarity index 82% rename from docs/reference/r-statuses.md rename to docs/reference/statuses.md index 20dc754ba7..3ed8c2345a 100644 --- a/docs/reference/r-statuses.md +++ b/docs/reference/statuses.md @@ -1,8 +1,10 @@ # Charm statuses -> :warning: **WARNING** : This is an work-in-progress article. Do NOT use it in production! Contact [Canonical Data Platform team](https://chat.charmhub.io/charmhub/channels/data-platform) if you are interested in the topic. - -The charm follows [standard Juju applications statuses](https://juju.is/docs/olm/status-values#heading--application-status). Here you can find the expected end-users reaction on different statuses: +```{caution} +This reference is a work in progress and not fit for production. Contact [Canonical Data Platform team](https://chat.charmhub.io/charmhub/channels/data-platform) if you are interested in the topic. +``` + +The charm follows [standard Juju applications statuses](https://juju.is/docs/olm/status-values#application-status). Here you can find the expected end-users reaction on different statuses: | Juju Status | Message | Expectations | Actions | |-------|-------|-------|-------| @@ -17,7 +19,8 @@ The charm follows [standard Juju applications statuses](https://juju.is/docs/olm | **blocked** | failed to start Patroni | TODO: error/retry? | | | **blocked** | Failed to create postgres user | The charm couldn't create the default `postgres` database user due to connection problems | Connect to the database using the `operator` user and the password from the `get-password` action, then run `CREATE ROLE postgres WITH LOGIN SUPERUSER;` | | **blocked** | Failed to restore backup | The database couldn't start after the restore | The charm needs fix in the code to recover from this status and enable a new restore to be requested | -| **blocked** | Please choose one endpoint to use. No need to relate all of them simultaneously! | [The modern / legacy interfaces](https://charmhub.io/postgresql/docs/e-legacy-charm) should not be used simultaneously. | Remove modern or legacy relation. Choose one to use at a time. | +| **blocked** | Please choose one endpoint to use. No need to relate all of them simultaneously! | [The modern / legacy interfaces](/explanation/legacy-charm) should not be used simultaneously. | Remove modern or legacy relation. Choose one to use at a time. | | **error** | any | An unhanded internal error happened | Read the message hint. Execute `juju resolve ` after addressing the root of the error state | | **terminated** | any | The unit is gone and will be cleaned by Juju soon | No actions possible | -| **unknown** | any | Juju doesn't know the charm app/unit status. Possible reason: K8s charm termination in progress. | Manual investigation required if status is permanent | \ No newline at end of file +| **unknown** | any | Juju doesn't know the charm app/unit status. Possible reason: K8s charm termination in progress. | Manual investigation required if status is permanent | + diff --git a/docs/reference/r-system-requirements.md b/docs/reference/system-requirements.md similarity index 82% rename from docs/reference/r-system-requirements.md rename to docs/reference/system-requirements.md index 5d4c4a16b2..fe9a7db585 100644 --- a/docs/reference/r-system-requirements.md +++ b/docs/reference/system-requirements.md @@ -32,13 +32,14 @@ The charm is based on the [charmed-postgresql snap](https://snapcraft.io/charmed * `amd64` * `arm64` (from revision 396+) -[Contact us](/t/11863) if you are interested in a new architecture! +[Contact us](/reference/contacts) if you are interested in a new architecture! ## Networking + * Access to the internet is required for downloading required snaps and charms * Only IPv4 is supported at the moment * See more information about this limitation in [this Jira issue](https://warthogs.atlassian.net/browse/DPE-4695) - * [Contact us](/t/11863) if you are interested in IPv6! + * [Contact us](/reference/contacts) if you are interested in IPv6! @@ -52,8 +53,9 @@ The charm is based on the [charmed-postgresql snap](https://snapcraft.io/charmed [3.6 LTS]: https://img.shields.io/badge/3.6_LTS-%23E95420?label=Juju -[552]: /t/16007 -[288]: /t/11876 -[336]: /t/11877 -[363]: /t/13124 -[430]: /t/14067 \ No newline at end of file +[552]: https://github.com/canonical/postgresql-operator/releases/tag/rev552 +[288]: https://github.com/canonical/postgresql-operator/releases/tag/rev288 +[336]: https://github.com/canonical/postgresql-operator/releases/tag/rev336 +[363]: https://github.com/canonical/postgresql-operator/releases/tag/rev363 +[430]: https://github.com/canonical/postgresql-operator/releases/tag/rev429 + diff --git a/docs/reference/r-cli-helpers.md b/docs/reference/troubleshooting/cli-helpers.md similarity index 72% rename from docs/reference/r-cli-helpers.md rename to docs/reference/troubleshooting/cli-helpers.md index f5398e33e3..aa2fe3e443 100644 --- a/docs/reference/r-cli-helpers.md +++ b/docs/reference/troubleshooting/cli-helpers.md @@ -2,11 +2,11 @@ This page describes some useful low-level tools shipped withing Charmed PostgreSQL for advanced troubleshooting. -[note type=caution] +```{caution} **These tools can be dangerous in a production environment if they are not used correctly.** -When in doubt, [contact us](/t/11863). -[/note] +When in doubt, [contact us](/reference/contacts). +``` ## Patroni @@ -15,7 +15,7 @@ Troubleshooting tools include: * The Patroni REST API * The Raft library -Learn more about Patroni in the [Architecture](/t/11857) page. +Learn more about Patroni in the [Architecture](/explanation/architecture) page. ### `patronictl` @@ -27,9 +27,10 @@ The main Patroni tool is `patronictl`. `patronictl` checks the low-level Patroni status of the cluster. -[details="Example: cluster status"] -```shell -> juju deploy postgresql -n 3 # and wait for deployment +
Example: cluster status + +```text +> juju deploy postgresql --channel 14/stable -n 3 # and wait for deployment > juju ssh postgresql/2 ... @@ -42,14 +43,16 @@ ubuntu@juju-b87344-2:~$ sudo -u snap_daemon patronictl -c /var/snap/charmed-post | + postgresql-3 | 10.189.210.26 | Sync Standby | streaming | 1 | 0 | +-----------------+----------------+--------------+-----------+----+-----------+ ``` -[/details] +
+
#### Useful Patroni actions Use `--help` to find all the available Patroni actions. -[details="Example: Patroni actions"] -```shell +
Example: Patroni actions + +```text > sudo -u snap_daemon patronictl -c /var/snap/charmed-postgresql/current/etc/patroni/patroni.yaml --help ... failover Failover to a replica @@ -65,14 +68,16 @@ Use `--help` to find all the available Patroni actions. switchover Switchover to a replica topology Prints ASCII topology for given cluster ``` -[/details] +
+
#### Switchover/failover Patroni can perform a low-level [switchover/failover](https://patroni.readthedocs.io/en/latest/patronictl.html#patronictl-switchover) inside one cluster. -[details="Example: switchover (healthy cluster only)"] -```shell +
Example: switchover (healthy cluster only) + +```text ubuntu@juju-b87344-2:~$ sudo -u snap_daemon patronictl -c /var/snap/charmed-postgresql/current/etc/patroni/patroni.yaml switchover postgresql --candidate postgresql-2 --force Current cluster topology + Cluster: postgresql (7496847632512033809) ----+-----------+----+-----------+ @@ -100,10 +105,11 @@ ubuntu@juju-b87344-2:~$ sudo -u snap_daemon patronictl -c /var/snap/charmed-post | postgresql-3 | 10.189.210.26 | Sync Standby | streaming | 3 | 0 | +---------------+----------------+--------------+-----------+----+-----------+ ``` -[/details] +
-[details="Example: failover"] -```shell +
Example: failover + +```text ubuntu@juju-b87344-2:~$ sudo -u snap_daemon patronictl -c /var/snap/charmed-postgresql/current/etc/patroni/patroni.yaml failover postgresql --candidate postgresql-3 Current cluster list + Cluster: postgresql (7496847632512033809) ----+-----------+----+-----------+ @@ -139,13 +145,15 @@ ubuntu@juju-b87344-2:~$ sudo -u snap_daemon patronictl -c /var/snap/charmed-post | postgresql-3 | 10.189.210.26 | Leader | running | 2 | | +---------------+----------------+--------------+-----------+----+-----------+ ``` -[/details] +
+
#### Re-initialisation Sometimes the cluster member might stuck in the middle of nowhere, the easiest way to try is [reinit the Patroni cluster member](https://patroni.readthedocs.io/en/latest/patronictl.html#patronictl-reinit). -[details="Example: cluster member re-initialization"] -```shell +
Example: cluster member re-initialization + +```text ubuntu@juju-b87344-2:~$ sudo -u snap_daemon patronictl -c /var/snap/charmed-postgresql/current/etc/patroni/patroni.yaml reinit postgresql postgresql-1 + Cluster: postgresql (7496847632512033809) ----+-----------+----+-----------+ | Member | Host | Role | State | TL | Lag in MB | @@ -158,14 +166,16 @@ Are you sure you want to reinitialize members postgresql-1? [y/N]: y Success: reinitialize for member postgresql-1 ``` -[/details] +
+
### Patroni REST API Patroni provides most `patronictl` actions as a [REST API](https://patroni.readthedocs.io/en/latest/rest_api.html). Use port `8008` to access Patroni REST API on any member/unit of Charmed PostgreSQL. -[details="Example: read-only access via Patroni REST API"] -```shell +
Example: read-only access via Patroni REST API + +```text ubuntu@juju360:~$ curl 10.189.210.55:8008/cluster | jq # where 10.189.210.55 is IP of Charmed PostgreSQL Juju unit ... { @@ -203,13 +213,17 @@ ubuntu@juju360:~$ curl 10.189.210.55:8008/cluster | jq # where 10.189.210.55 is "scope": "postgresql" } ``` -[/details] +
+ +```{note} +The Patroni REST API can be accessed anonymously in read-only mode only. The Juju secret `patroni-password` is mandatory to apply any chances via Patroni REST API. +``` -> **Note**: Patroni REST API can be accessed anonymously in read-only mode only. The Juju secret `patroni-password` is mandatory to apply any chances via Patroni REST API. Example of authenticated changes via Patroni REST API: -[details="Example: write access via Patroni REST API"] -```shell -> juju deploy postgresql -n 3 # and wait for deployment +
Example: write access via Patroni REST API + +```text +> juju deploy postgresql --channel 14/stable -n 3 # and wait for deployment > juju secrets | grep postgresql # find ID with 'patroni-password' > juju show-secret --reveal ccccaaabbbbbbcgoi12345 | grep patroni-password # reveal password to access Patroni REST API patroni-password: patr0n1sup3rs3cretpassw0rd @@ -217,29 +231,31 @@ Example of authenticated changes via Patroni REST API: > curl -k -u patroni:patr0n1sup3rs3cretpassw0rd -X POST https://10.151.27.242:8008/switchover -d '{"leader": "postgresql-0", "candidate": "postgresql-1"}' Successfully switched over to "postgresql-1" ``` -> **Hint**: use dedicated [promote-to-primary](/t/17523) action to switchover Primary. +> **Hint**: use dedicated [promote-to-primary](/how-to/switchover-failover) action to switchover Primary. -[/details] +
Pay attention to TLS relation with PostgreSQL and access Patroni REST API accordingly: -[details="Example: access Patroni REST API with(out) TLS"] -```shell +
Example: access Patroni REST API with(out) TLS + +```text > curl http://x.x.x.x:8008/cluster # to access without TLS > curl https://x.x.x.x:8008/cluster # to access with trusted certificate > curl -k https://x.x.x.x:8008/cluster # to access with self-signed certificate ``` -[/details] - +
+
### Raft library Patroni relies on the Raft library for the consensus handling and Primary election. It is implemented using [pySyncObj](https://github.com/bakwc/PySyncObj) and available as a CLI tool. -While **you should not interact with Raft library manually**, you can check its internal status: +While **you should not interact with Raft library manually**, you can check its internal status. Note that a password is mandatory to access Raft. -[details="Example: check Raft status"] -```shell -> juju deploy postgresql -n 3 # and wait for deployment +
Example: check Raft status + +```text +> juju deploy postgresql --channel 14/stable -n 3 # and wait for deployment > juju secrets | grep postgresql # find ID with 'raft-password' > juju show-secret --reveal cvia1ibjihbbbcgoi12300 | grep raft-password # reveal password to access Raft raft-password: r@ftsup3rs3cretp@ssw0rd @@ -272,7 +288,55 @@ uptime: 2482881 version: 0.3.12 ``` -> **Note**: password is mandatory to access Raft. +```{tip} +Pay attention to the CLI syntax. Use the standard hyphen `-`, avoid typos with the common `--` prefix for parameters. +``` + +
+ +### PostgreSQL tools + +The Charmed PostgreSQL ships long list of standard `pg_*` tools, including `pg_dump`, `pg_dumpall` (and more). Due to the SNAP naming requirements they are available as `pg-dump` and `pg-dumpall` accordingly. + +The entire list can bu found on systems with snap charmed-postgresql installed, e.g.: +
Example: list of pg_* tools shipped by snap + +```text +> snap list charmed-postgresql +Name Version Rev Tracking Publisher Notes +charmed-postgresql 14.15 143 latest/stable canonical✓ held + +> charmed-postgresql.pg +charmed-postgresql.pg-archivecleanup charmed-postgresql.pg-conftool charmed-postgresql.pg-dump charmed-postgresql.pg-recvlogical charmed-postgresql.pg-upgradecluster charmed-postgresql.pgbouncer-server +charmed-postgresql.pg-backupcluster charmed-postgresql.pg-createcluster charmed-postgresql.pg-dumpall charmed-postgresql.pg-renamecluster charmed-postgresql.pg-virtualenv +charmed-postgresql.pg-basebackup charmed-postgresql.pg-ctl charmed-postgresql.pg-isready charmed-postgresql.pg-restore charmed-postgresql.pgbackrest +charmed-postgresql.pg-buildext charmed-postgresql.pg-ctlcluster charmed-postgresql.pg-lsclusters charmed-postgresql.pg-restorecluster charmed-postgresql.pgbench +charmed-postgresql.pg-config charmed-postgresql.pg-dropcluster charmed-postgresql.pg-receivewal charmed-postgresql.pg-updatedicts charmed-postgresql.pgbouncer +``` +
+ +#### pg_dump / pg_dumpall + +These tools are designed to dump the PostgreSQL content. Due to the strictly confined SNAP, the context is limited to SNAP itself (and not the POSIX user triggered the tool). Also, due to security reasons the default `postgres` user cannot access DB, use user `operator` (you can find it's credential in Juju Secrets). + +
Example: pg-dump/pg-dumpall usage + +```text +charmed-postgresql.pg-dump -c -C -U operator -W -h /tmp -d mydb | tee mydb.sql >/dev/null +``` + +Also you can pass password using env variable PGPASSWORD, however it is NOT recommended for productions as DB password will be stored in shell history: + +```text +PGPASSWORD=my$ecretp@ss charmed-postgresql.pg-dumpall -c -U operator -h /tmp | tee all_DBs.txt >/dev/null +``` + +Note, the local SNAP /tmp could be used as well: -> **Note**: pay attention to the CLI syntax (simple `-` used, avoid misstype with common `--` prefix for parametes) -[/details] \ No newline at end of file +```text +PGPASSWORD=my$ecretp@ss charmed-postgresql.pg-dumpall -c -U operator -h /tmp -f /tmp/test.sql + +> sudo ls -la /tmp/snap-private-tmp/snap.charmed-postgresql/tmp/test.sql +-rw-rw-r-- 1 ubuntu ubuntu 19416 Jun 4 08:24 /tmp/snap-private-tmp/snap.charmed-postgresql/tmp/test.sql +``` +
\ No newline at end of file diff --git a/docs/reference/r-troubleshooting.md b/docs/reference/troubleshooting/index.md similarity index 78% rename from docs/reference/r-troubleshooting.md rename to docs/reference/troubleshooting/index.md index 725399ec0c..9dc223c414 100644 --- a/docs/reference/r-troubleshooting.md +++ b/docs/reference/troubleshooting/index.md @@ -1,53 +1,48 @@ # Troubleshooting -[note type="caution"] -**Warning:** At the moment, there is **no** ability to [pause an operator](https://warthogs.atlassian.net/browse/DPE-2545). - -Make sure your activity will not interfere with the operator itself! -[/note] - -[note] -**Note**: All commands are written for `juju >= v.3.0` - -If you are using an earlier version, be aware that: +This page goes over some recommended tools and approaches to troubleshooting the charm. - - `juju run` replaces `juju run-action --wait` in `juju v.2.9` - - `juju integrate` replaces `juju relate` and `juju add-relation` in `juju v.2.9` +Before anything, always run `juju status` to check the [list of charm statuses](/reference/statuses) and the recommended fixes. This alone may already solve your issue. -For more information, check the [Juju 3.0 Release Notes](https://juju.is/docs/juju/roadmap#heading--juju-3-0-0---22-oct-2022). -[/note] +Otherwise, this reference goes over how to troubleshoot this charm via: +- [`juju` logs](#juju-logs) +- [`snap-based charm`](#snap-based-charm) +- [Installing extra software](#install-extra-software) -## Summary -This page goes over some recommended tools and approaches to troubleshooting the charm. -Before anything, always run `juju status` to check the [list of charm statuses](/t/10844) and the recommended fixes. This alone may already solve your issue. +```{caution} +At the moment, there is no support for [pausing an operator](https://warthogs.atlassian.net/browse/DPE-2545). -Otherwise, this reference goes over how to troubleshoot this charm via: -- [`juju` logs](#heading--logs) -- [`snap-based charm`](#heading--snap-based-charm) -- [Installing extra software](#heading--install-extra-software) +Make sure your activity will not interfere with the operator itself! +``` -

`juju` logs

+## Juju logs -Please be familiar with [Juju logs concepts](https://juju.is/docs/juju/log) and learn [how to manage Juju logs](https://juju.is/docs/juju/manage-logs). +See: +* [Juju | logs](https://juju.is/docs/juju/log) +* [Juju | How to manage logs](https://juju.is/docs/juju/manage-logs). Always check the Juju logs before troubleshooting further: -```shell + +```text juju debug-log --replay --tail ``` Focus on `ERRORS` (normally there should be none): -```shell + +```text juju debug-log --replay | grep -c ERROR ``` Consider enabling the `DEBUG` log level if you are troubleshooting unusual charm behaviour: -```shell + +```text juju model-config 'logging-config==INFO;unit=DEBUG' ``` -The Patroni/PostgreSQL logs are located inside SNAP: -```shell +The Patroni/PostgreSQL logs are located inside the snap: + +```text > ls -la /var/snap/charmed-postgresql/common/var/log/* /var/snap/charmed-postgresql/common/var/log/patroni: @@ -61,24 +56,27 @@ The Patroni/PostgreSQL logs are located inside SNAP: # The pgBouncer should be stopped on Charmed PostgreSQL deployments and produce no logs. ``` -

`snap`-based charm

+## Snap-based charm -First, check the [operator architecture](/t/11857) to become familiar with snap content, operator building blocks, and running Juju units. +First, check the [operator architecture](/explanation/architecture) to become familiar with snap content, operator building blocks, and running Juju units. To enter the unit, use: -```shell + +```text juju ssh postgresql/0 bash ``` Make sure the `charmed-postgresql` snap is installed and functional: -```shell + +```text ubuntu@juju-fd7874-0:~$ sudo snap list charmed-postgresql Name Version Rev Tracking Publisher Notes charmed-postgresql 14.9 70 latest/stable dataplatformbot held ``` -From here you can make sure all snap (systemd) services are running: -```shell +From here you can make sure all snap (systemd) services are running: + +```text ubuntu@juju-fd7874-0# sudo snap services Service Startup Current Notes charmed-postgresql.patroni enabled active - @@ -138,10 +136,11 @@ ubuntu 10234 0.0 0.0 17208 7944 ? R 21:47 0:00 sshd: ubuntu@ ubuntu@juju-fd7874-0:~$ ``` -The list of running snap/systemd services will depend on configured (enabled) [COS integration](/t/10600) and/or [backup](/t/9683) functionality. The snap service `charmed-postgresql.patroni` must always be active and currently running (the Linux processes `snapd`, `patroni` and `postgres`). +The list of running snap/systemd services will depend on configured (enabled) [COS integration](/how-to/monitoring-cos/enable-monitoring) and/or [backup](/how-to/back-up-and-restore/create-a-backup) functionality. The snap service `charmed-postgresql.patroni` must always be active and currently running (the Linux processes `snapd`, `patroni` and `postgres`). + +To access PostgreSQL, check the [charm users concept](/explanation/users) and request `operator` credentials to use `psql`: -To access PostgreSQL, check the [charm users concept](/t/10798) and request `operator` credentials to use `psql`: -```shell +```text > juju show-unit postgresql/0 | awk '/private-address:/{print $2;exit}' 10.47.228.200 @@ -160,28 +159,39 @@ password: rV0Xn4l65KtQsHSq ``` Continue troubleshooting your database/SQL related issues from here.
-[note type="caution"] -**Warning**: Do **NOT** manage users, credentials, databases, schema directly. This avoids a split brain situation with the operator and integrated applications. -[/note] +```{caution} +To avoid split-brain scenarios: -It is NOT recommended to restart services directly as it might create a split brain situation with operator internal state. If you see the problem with a unit, consider [removing the failing unit and adding a new unit](/t/9689) to recover the cluster state. - -As a last resort, [contact us](/t/11852) if you cannot determine the source of your issue. +* Do not manage users, credentials, databases, and schema directly. +* Avoid restarting services directly. If you see the problem with a unit, consider [removing the failing unit and adding a new unit](/how-to/scale-replicas) to recover the cluster state. +``` -Also, feel free to improve this document! +As a last resort, [contact us](/reference/contacts) if you cannot determine the source of your issue. -

Install extra software

+## Install extra software We recommend you do **not** install any additional software. This may affect stability and produce anomalies that are hard to troubleshoot. Sometimes, however, it is necessary to install some extra troubleshooting software. Use the common approach: -```shell + +```text ubuntu@juju-fd7874-0:~$ sudo apt update && sudo apt install gdb ... Setting up gdb (12.1-0ubuntu1~22.04) ... ubuntu@juju-fd7874-0:~$ ``` -**Always remove manually installed components at the end of troubleshooting.** Keep the house clean! \ No newline at end of file +```{tip} +Always remove manually installed components at the end of troubleshooting. Keep the house clean! +``` + +```{toctree} +:titlesonly: +:maxdepth: 2 +:glob: +:hidden: + +SOS report +CLI helpers diff --git a/docs/reference/r-sos-report.md b/docs/reference/troubleshooting/sos-report.md similarity index 96% rename from docs/reference/r-sos-report.md rename to docs/reference/troubleshooting/sos-report.md index 7c1a3a0441..4dfa658256 100644 --- a/docs/reference/r-sos-report.md +++ b/docs/reference/troubleshooting/sos-report.md @@ -4,11 +4,11 @@ SoS is an extensible, portable, support data collection tool primarily aimed at You can use the [built-in version of SoS](#use-built-in-sos-recommended), or [retrieve the latest version from GitHub](#use-the-latest-sos-plugins-from-git). -[note type=caution] +```{caution} Always review the collected data before sharing it! The generated archive may contain sensitive data. Its content should be reviewed by the originating organization before being passed to any third party. -[/note] +``` ## Use built-in SoS (recommended) @@ -17,12 +17,12 @@ Charmed PostgreSQL shipped with built-in [SoS](https://github.com/sosreport/sos) ### Collect logs on one unit To generate the troubleshooting report archiving all logs simply call `sos report` inside the relevant Juju unit: -```shell +```text juju ssh postgresql/0 > sudo sos report -o system,systemd,snap,charmed_postgresql --low-priority ``` As a result, the archive will all logs will be generated and can be shared with your support representative: -```shell +```text ... Your sos report has been generated and saved in: /tmp/sosreport-juju-d4c067-1-2025-04-07-chdmwlz.tar.xz @@ -34,12 +34,13 @@ Your sos report has been generated and saved in: ``` Use `juju scp` to copy logs from Juju unit to localhost: -```shell +```text juju scp postgresql/0:/tmp/sosreport-juju-d4c067-1-2025-04-07-chdmwlz.tar.xz . ``` -[details="Example output"] -```shell +
Example output + +```text juju ssh postgresql/0 ubuntu@juju-d4c067-1:~$ sudo sos report -o system,systemd,snap,charmed_postgresql --low-priority @@ -87,28 +88,29 @@ ubuntu@juju-d4c067-1:~$ exit juju scp postgresql/0:/tmp/sosreport-juju-d4c067-1-2025-04-07-qntyqpz.tar.xz . ``` -[/details] +
### Collect logs from several units The sos tool allows you to collect logs from several Juju units (replace labels with proper Juju unit like `postgresql/0`). Run the following command from outside the Juju units: -```shell +```text sos collect --cluster-type juju --no-local -c "juju.units=,,<...>" --batch -o system,systemd,snap,charmed_postgresql --low-priority ``` ## Use the latest sos plugins from Git The latest version of [sos plugins](https://github.com/sosreport/sos/tree/main/sos/report/plugins) can be retrieved from Git easily: -```shell +```text git clone https://github.com/sosreport/sos.git cd sos sudo ./bin/sos report -­a ``` The output will be the same to the example above providing archive with all logs as above: -```shell +```text Your sos report has been generated and saved in: /tmp/sosreport-juju-d4c067-1-2025-04-07-egosqmi.tar.xz -``` \ No newline at end of file +``` + diff --git a/docs/reference/r-versions.md b/docs/reference/versions.md similarity index 70% rename from docs/reference/r-versions.md rename to docs/reference/versions.md index 36227851ee..244507da6b 100644 --- a/docs/reference/r-versions.md +++ b/docs/reference/versions.md @@ -20,22 +20,22 @@ PostgreSQL 16 is shipped in track `16` and is available for testing in the chann ### Supported features +* Juju spaces support +* [Multiple Juju storage support] * [LDAP integration] (also supported by PostgreSQL `14`) * [SoS report integration] (also supported by PostgreSQL `14`) * [Recovery improvements] (also supported by PostgreSQL `14`) * All replicas are now [synchronous units] * Switchover the primary unit via `promote-to-primary scope=unit` * Raft re-init helper: `promote-to-primary scope=unit force=yes` -* [Juju user secrets](https://documentation.ubuntu.com/juju/latest/reference/secret/index.html#user) for internal charm password rotation +* [Juju user secrets](https://documentation.ubuntu.com/juju/latest/reference/secret/index.html#user) for charm [internal passwords](/how-to/manage-passwords) * [Timescale Community Edition] * [Extended COS integration] * [Profiling via Parca] * [Tracing via Tempo] * Improved [security hardening] -* (WIP) [Multiple Juju storage support] -* (WIP) [Juju Spaces support] -* (WIP) Refresh v3 lib support -* (WIP) Improved built-in roles +* (WIP) [Improved built-in roles](/explanation/roles) +* New "juju refresh" library (Refresh v3) + +[Charmhub PostgreSQL VM]: https://charmhub.io/postgresql?channel=14/stable \ No newline at end of file diff --git a/docs/tutorial/t-access.md b/docs/tutorial/t-access.md deleted file mode 100644 index 7e02a57e2b..0000000000 --- a/docs/tutorial/t-access.md +++ /dev/null @@ -1,162 +0,0 @@ -> [Charmed PostgreSQL Tutorial](/t/9707) > 3. Access PostgreSQL - -# Access PostgreSQL - -In this section, you will learn how to get the credentials of your deployment, connect to the PostgreSQL instance, view its default databases, and finally, create your own new database. -[note type="caution"] -This part of the tutorial accesses PostgreSQL via the `operator` user. - -**Do not directly interface with the `operator` user in a production environment.** - -In a later section about [Integrations,](https://charmhub.io/postgresql-k8s/docs/t-integrations) we will cover how to safely access PostgreSQL by creating a separate user via the [Data Integrator charm](https://charmhub.io/data-integrator) -[/note] - - -## Summary - -- [Retrieve credentials](#retrieve-credentials) -- [Access PostgreSQL via `psql`](#access-postgresql-via-psql) - - [ Create a new database](#heading--new-database) - ---- -## Retrieve credentials - -Connecting to the database requires that you know three pieces of information: The internal postgreSQL database's username and password, and the host machine's IP address. - -The IP addresses associated with each application unit can be found using the `juju status` command. Since we will use the leader unit to connect to PostgreSQL, we are interested in the IP address for the unit marked with `*`, like shown in the output below: -```shell -Unit Workload Agent Address Ports Message -postgresql/0* active idle 10.1.110.80 Primary -``` - -The user we will connect to in this tutorial will be 'operator'. To retrieve its associated password, run the Charmed PostgreSQL action get-password: -```shell -juju run postgresql/leader get-password -``` -The command above should output something like this: -```shell -Running operation 1 with 1 task - - task 2 on unit-postgresql-0 - -Waiting for task 2... -password: 66hDfCMm3ofT0yrG -``` -In order to retrieve the password of a user other than 'operator', use the option username: -```shell -juju run postgresql/leader get-password username=replication -``` - -At this point, we have all the information required to access PostgreSQL. Run the command below to enter the leader unit's shell as root: - -```shell -juju ssh --container postgresql postgresql/leader bash -``` -which should bring you to a prompt like this: - -```shell - root@postgresql-0:/# -``` -The following commands should be executed from this remote shell you just logged into. - ->If you’d like to leave the unit's shell and return to your local terminal, enter `Ctrl+D` or type `exit`. - -## Access PostgreSQL via `psql` - -The easiest way to interact with PostgreSQL is via [PostgreSQL interactive terminal `psql`](https://www.postgresql.org/docs/14/app-psql.html), which is already installed on the host you're connected to. - -For example, to list all databases currently available, run the command below. When requested, enter the password that you obtained earlier. -```shell -psql --host=10.1.110.80 --username=operator --password --list -``` - -You can see below the output for the list of databases. `postgres` is the default database we are connected to and is used for administrative tasks and for creating other databases. -```shell - Name | Owner | Encoding | Collate | Ctype | Access privileges ------------+----------+----------+-------------+-------------+----------------------- - postgres | operator | UTF8 | en_US.UTF-8 | en_US.UTF-8 | - template0 | operator | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/operator + - | | | | | operator=CTc/operator - template1 | operator | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/operator + - | | | | | operator=CTc/operator -(3 rows) -``` - -In order to execute queries, we should enter psql's interactive terminal by running the following command, again typing password when requested: -```shell - psql --host=10.1.110.80 --username=operator --password postgres -``` - -The output should be something like this: - -```shell -psql (14.10 (Ubuntu 14.10-0ubuntu0.22.04.1)) -Type "help" for help. - -postgres=# -``` -Now you are successfully logged in the interactive terminal. Here it is possible to execute commands to PostgreSQL directly using PostgreSQL SQL Queries. For example, to show which version of PostgreSQL is installed, run the following command: - -```shell -postgres=# SELECT version(); - version ---------------------------------------------------------------------------------------------------------------------------------- - PostgreSQL 14.10 (Ubuntu 14.10-0ubuntu0.22.04.1) on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0, 64-bit -(1 row) -``` - -We can see that PostgreSQL version 14.10 is installed. From this prompt, to print the list of available databases, we can simply run this command: - -```shell -postgres=# \l -``` - -The output should be the same as the one obtained before with `psql`, but this time we did not need to specify any parameters since we are already connected to the PostgreSQL application. - -### Create a new database -For creating and connecting to a new sample database, we can run the following commands: -```shell -postgres=# CREATE DATABASE mynewdatabase; -postgres=# \c mynewdatabase - -You are now connected to database "mynewdatabase" as user "operator". -``` - -We can now create a new table inside this database: - -```shell -postgres=# CREATE TABLE mytable ( - id SERIAL PRIMARY KEY, - name VARCHAR(50), - age INT -); -``` - -And insert an element into it: - -```shell -postgres=# INSERT INTO mytable (name, age) VALUES ('John', 30); -``` - -We can see our new table element by submitting a query: - -```shell -postgres=# SELECT * FROM mytable; - - id | name | age -----+------+----- - 1 | John | 30 -(1 row) -``` - -You can try multiple SQL commands inside this environment. Once you're ready, reconnect to the default postgres database and drop the sample database we created: - -```shell -postgres=# \c postgres - -You are now connected to database "postgres" as user "operator". -postgres=# DROP DATABASE mynewdatabase; -``` - -When you’re ready to leave the PostgreSQL shell, you can just type `exit`. This will take you back to the host of Charmed PostgreSQL (`postgresql/0`). Exit this host by once again typing exit. Now you will be in your original shell where you first started the tutorial. Here you can interact with Juju and LXD. - -**Next step**: [4. Scale replicas](/t/9705) \ No newline at end of file diff --git a/docs/tutorial/t-clean-up.md b/docs/tutorial/t-clean-up.md deleted file mode 100644 index 62de6ef958..0000000000 --- a/docs/tutorial/t-clean-up.md +++ /dev/null @@ -1,37 +0,0 @@ -> [Charmed PostgreSQL VM Tutorial](/t/9707) > 7. Clean up environment - -# Clean up your environment - -In this tutorial we've successfully deployed PostgreSQL on LXD, added and removed cluster members, added and removed database users, and enabled a layer of security with TLS. - -You may now keep your Charmed PostgreSQL VM deployment running and write to the database or remove it entirely using the steps in this page. - - -## Stop your virtual machine -If you'd like to keep your environment for later, simply stop your VM with -```shell -multipass stop my-vm -``` - -## Delete your virtual machine -If you're done with testing and would like to free up resources on your machine, you can remove the VM entirely. - -[note type="caution"] -**Warning**: When you remove VM as shown below, you will lose all the data in PostgreSQL and any other applications inside Multipass VM! - -For more information, see the docs for [`multipass delete`](https://multipass.run/docs/delete-command). -[/note] - -**Delete your VM and its data** by running -```shell -multipass delete --purge my-vm -``` - -## Next Steps - If you're looking for what to do next, you can: -- Run [Charmed PostgreSQL on Kubernetes](https://github.com/canonical/postgresql-k8s-operator). -- Check out our Charmed offerings of [MySQL](https://charmhub.io/mysql) and [Kafka](https://charmhub.io/kafka?channel=edge). -- Read about [High Availability Best Practices](https://canonical.com/blog/database-high-availability) -- [Report](https://github.com/canonical/postgresql-operator/issues) any problems you encountered. -- [Give us your feedback](https://chat.charmhub.io/charmhub/channels/data-platform). -- [Contribute to the code base](https://github.com/canonical/postgresql-operator) \ No newline at end of file diff --git a/docs/tutorial/t-deploy.md b/docs/tutorial/t-deploy.md deleted file mode 100644 index 7799f482bc..0000000000 --- a/docs/tutorial/t-deploy.md +++ /dev/null @@ -1,39 +0,0 @@ -> [Charmed PostgreSQL VM Tutorial](/t/9707) > 2. Deploy PostgreSQL - -# Deploy Charmed PostgreSQL VM - -In this section, you will deploy Charmed PostgreSQL VM, access a unit, and interact with the PostgreSQL databases that exist inside the application. - -## Deploy PostgreSQL - -To deploy Charmed PostgreSQL, run -```shell -juju deploy postgresql -``` - -Juju will now fetch Charmed PostgreSQL VM from [Charmhub](https://charmhub.io/postgresql?channel=14/stable) and deploy it to the LXD cloud. This process can take several minutes depending on how provisioned (RAM, CPU, etc) your machine is. - -You can track the progress by running: -```shell -juju status --watch 1s -``` - -This command is useful for checking the real-time information about the state of a charm and the machines hosting it. Check the [`juju status` documentation](https://juju.is/docs/juju/juju-status) for more information about its usage. - -When the application is ready, `juju status` will show something similar to the sample output below: -``` -Model Controller Cloud/Region Version SLA Timestamp -tutorial overlord localhost/localhost 3.1.7 unsupported 09:41:53+01:00 - -App Version Status Scale Charm Channel Rev Exposed Message -postgresql active 1 postgresql 14/stable 281 no - -Unit Workload Agent Machine Public address Ports Message -postgresql/0* active idle 0 10.89.49.129 - -Machine State Address Inst id Series AZ Message -0 started 10.89.49.129 juju-a8a31d-0 jammy Running -``` - -> You can also watch juju logs with the [`juju debug-log`](https://juju.is/docs/juju/juju-debug-log) command. -More info on logging in the [juju logs documentation](https://juju.is/docs/olm/juju-logs). \ No newline at end of file diff --git a/docs/tutorial/t-enable-tls.md b/docs/tutorial/t-enable-tls.md deleted file mode 100644 index 55f3b1b7e4..0000000000 --- a/docs/tutorial/t-enable-tls.md +++ /dev/null @@ -1,89 +0,0 @@ -> [Charmed PostgreSQL VM Tutorial](/t/9707) > 6. Enable encryption with TLS - -# Enable encryption with TLS - -[Transport Layer Security (TLS)](https://en.wikipedia.org/wiki/Transport_Layer_Security) is a protocol used to encrypt data exchanged between two applications. Essentially, it secures data transmitted over a network. - -Typically, enabling TLS internally within a highly available database or between a highly available database and client/server applications requires a high level of expertise. This has all been encoded into Charmed PostgreSQL so that configuring TLS requires minimal effort on your end. - -TLS is enabled by integrating Charmed PostgreSQL with the [Self Signed Certificates Charm](https://charmhub.io/self-signed-certificates). This charm centralises TLS certificate management consistently and handles operations like providing, requesting, and renewing TLS certificates. - -In this section, you will learn how to enable security in your PostgreSQL deployment using TLS encryption. - -[note type="caution"] -**[Self-signed certificates](https://en.wikipedia.org/wiki/Self-signed_certificate) are not recommended for a production environment.** - -Check [this guide](/t/11664) for an overview of the TLS certificates charms available. -[/note] - -## Summary -- [Deploy TLS charm](#heading--deploy-tls-charm) -- [Integrate with PostgreSQL](#heading--integrate-with-postgresql) - - Check the TLS certificates in use -- [Remove TLS certificate](#heading--remove-tls) - ---- - -

Deploy TLS charm

- -Before enabling TLS on Charmed PostgreSQL VM, we must deploy the `self-signed-certificates` charm: -```shell -juju deploy self-signed-certificates --config ca-common-name="Tutorial CA" -``` - -Wait until the `self-signed-certificates` is up and active, use `juju status --watch 1s` to monitor the progress: -``` -Model Controller Cloud/Region Version SLA Timestamp -tutorial overlord localhost/localhost 3.1.7 unsupported 10:31:40+01:00 - -App Version Status Scale Charm Channel Rev Exposed Message -postgresql active 2 postgresql 14/stable 281 no -self-signed-certificates active 1 self-signed-certificates stable 72 no - -Unit Workload Agent Machine Public address Ports Message -postgresql/0* active idle 0 10.89.49.129 Primary -postgresql/1 active idle 1 10.89.49.197 -self-signed-certificates/0* active idle 3 10.89.49.185 - -Machine State Address Inst id Series AZ Message -0 started 10.89.49.129 juju-a8a31d-0 jammy Running -1 started 10.89.49.197 juju-a8a31d-1 jammy Running -4 started 10.89.49.185 juju-a8a31d-3 jammy Running -``` - -

Integrate with PostgreSQL

- -To enable TLS on Charmed PostgreSQL VM, integrate the two applications: -```shell -juju integrate postgresql:certificates self-signed-certificates:certificates -``` -PostgreSQL is now using TLS certificate generated by the `self-signed-certificates` charm. - -### Check the TLS certificate in use -Use `openssl` to connect to the PostgreSQL and check the TLS certificate in use. Note that your leader unit's IP address will likely be different to the one shown below: -```shell -> openssl s_client -starttls postgres -connect 10.89.49.129:5432 | grep Issuer -... -depth=1 C = US, CN = Tutorial CA -verify error:num=19:self-signed certificate in certificate chain -... -``` - -

Remove TLS certificate

-To remove the external TLS, remove the integration: -```shell -juju remove-relation postgresql:certificates self-signed-certificates:certificates -``` - -If you once again check the TLS certificates in use via the OpenSSL client, you will see something similar to the output below: -```shell -> openssl s_client -starttls postgres -connect 10.89.49.129:5432 -... -no peer certificate available ---- -No client certificate CA names sent -... -``` -The Charmed PostgreSQL VM application is not using TLS anymore. - -**Next step:** [7. Clean up environment](/t/9695) \ No newline at end of file diff --git a/docs/tutorial/t-integrate.md b/docs/tutorial/t-integrate.md deleted file mode 100644 index 72db1dae01..0000000000 --- a/docs/tutorial/t-integrate.md +++ /dev/null @@ -1,167 +0,0 @@ ->[Charmed PostgreSQL VM Tutorial](https://discourse.charmhub.io/t/9707) > 5. Integrate with other applications - -# Integrate with other applications - -[Integrations](https://juju.is/docs/sdk/integration), known as "relations" in Juju 2.9, are the easiest way to create a user for PostgreSQL in Charmed PostgreSQL VM. - -Integrations automatically create a username, password, and database for the desired user/application. As mentioned earlier in [2. Deploy PostgreSQL](/t/9697) , it is a better practice to connect to PostgreSQL via a specific user rather than the admin user. - -In this section, you will integrate your Charmed PostgreSQL to another charmed application. - -## Summary -- [Deploy `data-integrator`](#heading--deploy-data-integrator) -- [Integrate with PostgreSQL](#heading--integrate-with-postgresq) -- [Access the related database](#heading--access-related-database) -- [Remove the user](#heading--remove-user) ---- - -

Deploy data-integrator

- -In this tutorial, we will relate to the [Data Integrator charm](https://charmhub.io/data-integrator). This is a bare-bones charm that allows for central management of database users. It automatically provides credentials and endpoints that are needed to connect with a charmed database application. - -To deploy `data-integrator`, run - -```shell -juju deploy data-integrator --config database-name=test-database -``` -Example output: -``` -Located charm "data-integrator" in charm-hub, revision 11 -Deploying "data-integrator" from charm-hub charm "data-integrator", revision 11 in channel stable on jammy -``` - -Running `juju status` will show you `data-integrator` in a `blocked` state. This state is expected due to not-yet established relation (integration) between applications. -``` -Model Controller Cloud/Region Version SLA Timestamp -tutorial overlord localhost/localhost 3.1.7 unsupported 10:22:13+01:00 - -App Version Status Scale Charm Channel Rev Exposed Message -data-integrator blocked 1 data-integrator stable 11 no Please relate the data-integrator with the desired product -postgresql active 2 postgresql 14/stable 281 no - -Unit Workload Agent Machine Public address Ports Message -data-integrator/0* blocked idle 3 10.89.49.179 Please relate the data-integrator with the desired product -postgresql/0* active idle 0 10.89.49.129 -postgresql/1 active idle 1 10.89.49.197 - -Machine State Address Inst id Series AZ Message -0 started 10.89.49.129 juju-a8a31d-0 jammy Running -1 started 10.89.49.197 juju-a8a31d-1 jammy Running -3 started 10.89.49.179 juju-a8a31d-3 jammy Running -``` - -

Integrate with PostgreSQL

- -Now that the `data-integrator` charm has been set up, we can relate it to PostgreSQL. This will automatically create a username, password, and database for `data-integrator`. - -Relate the two applications with: -```shell -juju integrate data-integrator postgresql -``` -Wait for `juju status --watch 1s` to show all applications/units as `active`: -``` -Model Controller Cloud/Region Version SLA Timestamp -tutorial overlord localhost/localhost 3.1.7 unsupported 10:22:31+01:00 - -App Version Status Scale Charm Channel Rev Exposed Message -data-integrator active 1 data-integrator stable 11 no -postgresql active 2 postgresql 14/stable 281 no - -Unit Workload Agent Machine Public address Ports Message -data-integrator/0* active idle 3 10.89.49.179 -postgresql/0* active idle 0 10.89.49.129 Primary -postgresql/1 active idle 1 10.89.49.197 - -Machine State Address Inst id Series AZ Message -0 started 10.89.49.129 juju-a8a31d-0 jammy Running -1 started 10.89.49.197 juju-a8a31d-1 jammy Running -3 started 10.89.49.179 juju-a8a31d-3 jammy Running -``` - -To retrieve the username, password and database name, run the command -```shell -juju run data-integrator/leader get-credentials -``` - -Example output: -```yaml -unit-data-integrator-0: - UnitId: data-integrator/0 - id: "20" - results: - ok: "True" - postgresql: - database: test-database - endpoints: 10.89.49.129:5432 - password: 136bvw0s7FjJ6mxZ - read-only-endpoints: 10.89.49.197:5432 - username: relation-3 - version: "14.7" - status: completed - timing: - completed: 2023-03-20 09:22:50 +0000 UTC - enqueued: 2023-03-20 09:22:46 +0000 UTC - started: 2023-03-20 09:22:50 +0000 UTC -``` -Note that your hostnames, usernames, and passwords will likely be different. - - - -Use `endpoints`, `username`, `password` from above to connect newly created database `test-database` on the PostgreSQL server: -```shell -> psql --host=10.89.49.129 --username=relation-3 --password test-database -... -test-database=> \l -... - test-database | operator | UTF8 | C.UTF-8 | C.UTF-8 | =Tc/operator + - | | | | | operator=CTc/operator + - | | | | | "relation-3"=CTc/operator -... -``` - -The newly created database `test-database` is also available on all other PostgreSQL cluster members: -```shell -> psql --host=10.89.49.197 --username=relation-3 --password --list -... - test-database | operator | UTF8 | C.UTF-8 | C.UTF-8 | =Tc/operator + - | | | | | operator=CTc/operator + - | | | | | "relation-3"=CTc/operator -... -``` - -When you relate two applications, Charmed PostgreSQL automatically sets up a new user and database for you. -Note the database name we specified when we first deployed the `data-integrator` charm: `--config database-name=test-database`. - -

Remove the user

- -Removing the integration automatically removes the user that was created when the integration was created. Enter the following to remove the integration: -```shell -juju remove-relation postgresql data-integrator -``` - -Now try again to connect to the same PostgreSQL you just used in the previous section: - -```shell -> psql --host=10.89.49.129 --username=relation-3 --password --list -``` - -This will output an error message like the one shown below: -``` -psql: error: connection to server at "10.89.49.129", port 5432 failed: FATAL: password authentication failed for user "relation-3" -``` -This is expected, since this user no longer exists after removing the integration. - -Data remains on the server at this stage. - -To create a user again, integrate the applications again: -```shell -juju integrate data-integrator postgresql -``` -Re-integrating generates a new user and password: -```shell -juju run data-integrator/leader get-credentials -``` -You can then connect to the database with these new credentials. -From here you will see all of your data is still present in the database. - -**Next step:** [6. Enable TLS](/t/9699) \ No newline at end of file diff --git a/docs/tutorial/t-manage-passwords.md b/docs/tutorial/t-manage-passwords.md deleted file mode 100644 index 85ba852744..0000000000 --- a/docs/tutorial/t-manage-passwords.md +++ /dev/null @@ -1,91 +0,0 @@ -> [Charmed PostgreSQL VM Tutorial](https://discourse.charmhub.io/t/9707) > 4. Manage passwords - -# Manage passwords - -When we accessed PostgreSQL earlier in this tutorial, we needed to use a password manually. Passwords help to secure our database and are essential for security. Over time, it is a good practice to change the password frequently. - -In this section, we will go through setting and changing the password for the admin user. - -## Summary -- [Retrieve the operator password](#heading--retrieve-password) -- [Rotate the operator password](#heading--rotate-password) -- [Set a new password](#heading--set-new-password) - - ...for the operator - - ...for another user - ---- - -

Retrieve the operator password

- -The operator's password can be retrieved by running the `get-password` action on the Charmed PostgreSQL VM application: -```shell -juju run postgresql/leader get-password -``` -Running the command should output: -```yaml -unit-postgresql-0: - UnitId: postgresql/0 - id: "14" - results: - operator-password: eItxBiOYeMf7seSv - status: completed - timing: - completed: 2023-03-20 09:17:51 +0000 UTC - enqueued: 2023-03-20 09:17:49 +0000 UTC - started: 2023-03-20 09:17:50 +0000 UTC -``` - -

Rotate the operator password

- -You can change the operator's password to a new random password by entering: -```shell -juju run postgresql/leader set-password -``` -Running the command should output: -```yaml -unit-postgresql-0: - UnitId: postgresql/0 - id: "16" - results: - operator-password: npGdNGNGVtu7SO50 - status: completed - timing: - completed: 2023-03-20 09:18:11 +0000 UTC - enqueued: 2023-03-20 09:18:08 +0000 UTC - started: 2023-03-20 09:18:10 +0000 UTC -``` -The `status: completed` element in the output above indicates that the password has been successfully updated. The new password should be different from the previous password. - -

Set a new password

- -You can set a specific password for any user by running the `set-password` juju action on the leader unit. - -### ...for the operator user -To set a manual password for the operator/admin user, run the following command: -```shell -juju run postgresql/leader set-password password= -``` -where `` is your password of choice. - -Example output: -```yaml -unit-postgresql-0: - UnitId: postgresql/0 - id: "18" - results: - operator-password: my-password - status: completed - timing: - completed: 2023-03-20 09:20:06 +0000 UTC - enqueued: 2023-03-20 09:20:04 +0000 UTC - started: 2023-03-20 09:20:05 +0000 UTC -``` - -### ...for another user -To set a manual password for another user, run the following command: -```shell -juju run postgresql/leader set-password username=my-user password=my-password -``` -Read more about internal operator users [here](/t/10798). - -**Next step:** [5. Integrate with other applications](/t/9701) \ No newline at end of file diff --git a/docs/tutorial/t-scale.md b/docs/tutorial/t-scale.md deleted file mode 100644 index 7a3a5427cb..0000000000 --- a/docs/tutorial/t-scale.md +++ /dev/null @@ -1,81 +0,0 @@ -> [Charmed PostgreSQL VM Tutorial](/t/9707) > 3. Scale replicas - -# Scale your replicas -In this section, you will learn to scale your Charmed PostgreSQL by adding or removing juju units. - -The Charmed PostgreSQL VM operator uses a [PostgreSQL Patroni-based cluster](https://patroni.readthedocs.io/en/latest/) for scaling. It provides features such as automatic membership management, fault tolerance, and automatic failover. The charm uses PostgreSQL’s [synchronous replication](https://patroni.readthedocs.io/en/latest/replication_modes.html#postgresql-k8s-synchronous-replication) with Patroni. - -[note type="caution"] -This tutorial hosts all replicas on the same machine. - -**This should not be done in a production environment.** - -To enable high availability in a production environment, replicas should be hosted on different servers to [maintain isolation](https://canonical.com/blog/database-high-availability). -[/note] - -## Summary - -- [Add units](#heading--add-units) -- [Remove units](#heading--remove-units) - ---- - -

Add units

- -Currently, your deployment has only one juju **unit**, known in juju as the **leader unit**. You can think of this as the database **primary instance**. For each **replica**, a new unit is created. All units are members of the same database cluster. - -To add two replicas to your deployed PostgreSQL application, run -```shell -juju add-unit postgresql -n 2 -``` - -You can now watch the scaling process in live using: `juju status --watch 1s`. It usually takes several minutes for new cluster members to be added. - -You’ll know that all three nodes are in sync when `juju status` reports `Workload=active` and `Agent=idle`: -``` -Model Controller Cloud/Region Version SLA Timestamp -tutorial overlord localhost/localhost 3.1.7 unsupported 10:16:44+01:00 - -App Version Status Scale Charm Channel Rev Exposed Message -postgresql active 3 postgresql 14/stable 281 no - -Unit Workload Agent Machine Public address Ports Message -postgresql/0* active idle 0 10.89.49.129 Primary -postgresql/1 active idle 1 10.89.49.197 -postgresql/2 active idle 2 10.89.49.175 - -Machine State Address Inst id Series AZ Message -0 started 10.89.49.129 juju-a8a31d-0 jammy Running -1 started 10.89.49.197 juju-a8a31d-1 jammy Running -2 started 10.89.49.175 juju-a8a31d-2 jammy Running -``` - -

Remove units

- -Removing a unit from the application scales down the replicas. - -Before we scale them down, list all the units with `juju status`. You will see three units: `postgresql/0`, `postgresql/1`, and `postgresql/2`. Each of these units hosts a PostgreSQL replica. - -To remove the replica hosted on the unit `postgresql/2` enter: -```shell -juju remove-unit postgresql/2 -``` - -You’ll know that the replica was successfully removed when `juju status --watch 1s` reports: -``` -Model Controller Cloud/Region Version SLA Timestamp -tutorial overlord localhost/localhost 3.1.7 unsupported 10:17:14+01:00 - -App Version Status Scale Charm Channel Rev Exposed Message -postgresql active 2 postgresql 14/stable 281 no - -Unit Workload Agent Machine Public address Ports Message -postgresql/0* active idle 0 10.89.49.129 -postgresql/1 active idle 1 10.89.49.197 - -Machine State Address Inst id Series AZ Message -0 started 10.89.49.129 juju-a8a31d-0 jammy Running -1 started 10.89.49.197 juju-a8a31d-1 jammy Running -``` - -**Next step:** [4. Manage passwords](/t/9703) \ No newline at end of file diff --git a/docs/tutorial/t-set-up.md b/docs/tutorial/t-set-up.md deleted file mode 100644 index 3223686f32..0000000000 --- a/docs/tutorial/t-set-up.md +++ /dev/null @@ -1,68 +0,0 @@ -> [Charmed PostgreSQL VM Tutorial](/t/9707) > 1. Set up the environment - -# Set up the environment - -In this step, we will set up a development environment with the required components for deploying Charmed PostgreSQL. - -[note] -Before you start, make sure your machine meets the [minimum system requirements](/t/11743). -[/note] - -## Summary - -- [Set up Multipass](#heading--multipass) -- [Set up Juju](#heading--juju) ---- - -

Set up Multipass

- -[Multipass](https://multipass.run/) is a quick and easy way to launch virtual machines running Ubuntu. It uses the [cloud-init](https://cloud-init.io/) standard to install and configure all the necessary parts automatically. - -Install Multipass from the [snap store](https://snapcraft.io/multipass): -```shell -sudo snap install multipass -``` - -Launch a new VM using the [charm-dev](https://github.com/canonical/multipass-blueprints/blob/main/v1/charm-dev.yaml) cloud-init config: -```shell -multipass launch --cpus 4 --memory 8G --disk 50G --name my-vm charm-dev -``` - -[note type=""] -**Note**: All 'multipass launch' parameters are [described here](https://multipass.run/docs/launch-command). -[/note] - -The Multipass [list of commands](https://multipass.run/docs/multipass-cli-commands) is short and self-explanatory. For example, to show all running VMs, just run the command `multipass list`. - -As soon as a new VM has started, access it using -```shell -multipass shell my-vm -``` - -[note] -**Note**: If at any point you'd like to leave a Multipass VM, enter `Ctrl+D` or type `exit`. -[/note] - -All necessary components have been pre-installed inside VM already, like LXD and Juju. The files `/var/log/cloud-init.log` and `/var/log/cloud-init-output.log` contain all low-level installation details. - -

Set up Juju

- -Let's bootstrap Juju to use the local LXD controller. We will call it “overlord”, but you can give it any name you’d like: -```shell -juju bootstrap localhost overlord -``` - -A controller can work with different [models](https://juju.is/docs/juju/model). Set up a specific model for Charmed PostgreSQL VM named ‘tutorial’: -```shell -juju add-model tutorial -``` - -You can now view the model you created above by running the command `juju status`. You should see something similar to the following example output: -``` -Model Controller Cloud/Region Version SLA Timestamp -tutorial overlord localhost/localhost 3.1.7 unsupported 09:38:32+01:00 - -Model "admin/tutorial" is empty. -``` - -**Next step:** [2. Deploy PostgreSQL](/t/9697) \ No newline at end of file From 2296dcad93e3f1267adeb9b7fa07687c13015a9f Mon Sep 17 00:00:00 2001 From: Marcelo Henrique Neppel Date: Sun, 8 Jun 2025 09:35:52 -0300 Subject: [PATCH 037/112] [DPE-7511] Fix the auth username pattern (#941) * Fix auth username pattern Signed-off-by: Marcelo Henrique Neppel * Fix another ocurrence of the pattern Signed-off-by: Marcelo Henrique Neppel --------- Signed-off-by: Marcelo Henrique Neppel --- lib/charms/postgresql_k8s/v0/postgresql.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/charms/postgresql_k8s/v0/postgresql.py b/lib/charms/postgresql_k8s/v0/postgresql.py index fbf7dec711..f839b5c004 100644 --- a/lib/charms/postgresql_k8s/v0/postgresql.py +++ b/lib/charms/postgresql_k8s/v0/postgresql.py @@ -35,7 +35,7 @@ # Increment this PATCH version before using `charmcraft publish-lib` or reset # to 0 if you are raising the major API version -LIBPATCH = 54 +LIBPATCH = 55 # Groups to distinguish HBA access ACCESS_GROUP_IDENTITY = "identity_access" @@ -751,7 +751,7 @@ def list_users_from_relation(self, current_host=False) -> Set[str]: "SELECT usename " "FROM pg_catalog.pg_user " "WHERE usename LIKE 'relation_id_%' OR usename LIKE 'relation-%' " - "OR usename LIKE 'pgbouncer_auth_relation_id_%' OR usename LIKE '%_user_%_%';" + "OR usename LIKE 'pgbouncer_auth_relation_%' OR usename LIKE '%_user_%_%';" ) usernames = cursor.fetchall() return {username[0] for username in usernames} @@ -830,7 +830,7 @@ def set_up_database(self) -> None: END IF; END LOOP; -- Remove users that don't exist anymore from the pg_hba file. - FOR rec IN SELECT h.lines FROM pg_hba AS h LEFT JOIN relation_users AS r ON SPLIT_PART(h.lines, ' ', 3) = r.user WHERE r.user IS NULL AND (SPLIT_PART(h.lines, ' ', 3) LIKE 'relation_id_%' OR SPLIT_PART(h.lines, ' ', 3) LIKE 'pgbouncer_auth_relation_id_%' OR SPLIT_PART(h.lines, ' ', 3) LIKE '%_user_%_%') + FOR rec IN SELECT h.lines FROM pg_hba AS h LEFT JOIN relation_users AS r ON SPLIT_PART(h.lines, ' ', 3) = r.user WHERE r.user IS NULL AND (SPLIT_PART(h.lines, ' ', 3) LIKE 'relation_id_%' OR SPLIT_PART(h.lines, ' ', 3) LIKE 'pgbouncer_auth_relation_%' OR SPLIT_PART(h.lines, ' ', 3) LIKE '%_user_%_%') LOOP DELETE FROM pg_hba WHERE lines = rec.lines; changes := changes + 1; From 394aec8927bf9353e5237d9d045cdd1102deec94 Mon Sep 17 00:00:00 2001 From: Dragomir Penev <6687393+dragomirp@users.noreply.github.com> Date: Tue, 10 Jun 2025 02:01:57 +0300 Subject: [PATCH 038/112] Update PG to 14.18 (#943) --- src/constants.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/constants.py b/src/constants.py index 7a431a1640..cc21e8f040 100644 --- a/src/constants.py +++ b/src/constants.py @@ -35,7 +35,7 @@ SNAP_PACKAGES = [ ( POSTGRESQL_SNAP_NAME, - {"revision": {"aarch64": "168", "x86_64": "167"}}, + {"revision": {"aarch64": "186", "x86_64": "184"}}, ) ] From ee3fb46c057efe73502506badc16c5f41995a1e5 Mon Sep 17 00:00:00 2001 From: Marcelo Henrique Neppel Date: Tue, 10 Jun 2025 09:30:02 -0300 Subject: [PATCH 039/112] [DPE-7521] Fix HBA rules for Landscape related through PgBouncer (#946) * Fix HBA rules for Landscape related through PgBouncer Signed-off-by: Marcelo Henrique Neppel * Update comment Signed-off-by: Marcelo Henrique Neppel * Order users and databases Signed-off-by: Marcelo Henrique Neppel * Add unit test for relations_user_databases_map property Signed-off-by: Marcelo Henrique Neppel * Fix typo Signed-off-by: Marcelo Henrique Neppel --------- Signed-off-by: Marcelo Henrique Neppel --- src/charm.py | 25 +++++++++++++----- tests/unit/test_charm.py | 56 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 6 deletions(-) diff --git a/src/charm.py b/src/charm.py index a8303535b8..6508225201 100755 --- a/src/charm.py +++ b/src/charm.py @@ -2157,16 +2157,29 @@ def relations_user_databases_map(self) -> dict: if not self.is_cluster_initialised or not self._patroni.member_started: return {USER: "all", REPLICATION_USER: "all", REWIND_USER: "all"} user_database_map = {} - for user in self.postgresql.list_users_from_relation( - current_host=self.is_connectivity_enabled + for user in sorted( + self.postgresql.list_users_from_relation(current_host=self.is_connectivity_enabled) ): user_database_map[user] = ",".join( - self.postgresql.list_accessible_databases_for_user( - user, current_host=self.is_connectivity_enabled + sorted( + self.postgresql.list_accessible_databases_for_user( + user, current_host=self.is_connectivity_enabled + ) ) ) - # Add "landscape" superuser by default to the list when the "db-admin" relation is present. - if any(True for relation in self.client_relations if relation.name == "db-admin"): + # Add "landscape" superuser by default to the list when the "db-admin" relation is present + # or when the "database" relation has "extra-user-roles" set to "SUPERUSER" (which may mean + # that PgBouncer is related to the database and there is the possibility that Landscape + # is related to it). + if any( + True + for relation in self.client_relations + if relation.name == "db-admin" # Possibly Landscape relation. + or ( + relation.name == "database" + and relation.data[relation.app].get("extra-user-roles") == "SUPERUSER" + ) # PgBouncer (which may be related to Landscape). + ): user_database_map["landscape"] = "all" if self.postgresql.list_access_groups(current_host=self.is_connectivity_enabled) != set( ACCESS_GROUPS diff --git a/tests/unit/test_charm.py b/tests/unit/test_charm.py index 0e39f1cd16..20417dfb91 100644 --- a/tests/unit/test_charm.py +++ b/tests/unit/test_charm.py @@ -2916,3 +2916,59 @@ def test_get_ldap_parameters(harness): harness.charm.get_ldap_parameters() _get_relation_data.assert_called_once() _get_relation_data.reset_mock() + + +def test_relations_user_databases_map(harness): + with ( + patch("charm.PostgresqlOperatorCharm.postgresql") as _postgresql, + patch("charm.Patroni.member_started", new_callable=PropertyMock) as _member_started, + patch( + "charm.PostgresqlOperatorCharm.is_cluster_initialised", new_callable=PropertyMock + ) as _is_cluster_initialised, + ): + # Initial empty results from the functions used in the property that's being tested. + _postgresql.list_users_from_relation.return_value = set() + _postgresql.list_accessible_databases_for_user.return_value = set() + _postgresql.list_access_groups.return_value = { + "identity_access", + "internal_access", + "relation_access", + } + + # Test when the cluster isn't initialised yet. + _is_cluster_initialised.return_value = False + _member_started.return_value = True + assert harness.charm.relations_user_databases_map == { + "operator": "all", + "replication": "all", + "rewind": "all", + } + + # Test when the cluster is initialised but the cluster member hasn't started yet. + _is_cluster_initialised.return_value = True + _member_started.return_value = False + assert harness.charm.relations_user_databases_map == { + "operator": "all", + "replication": "all", + "rewind": "all", + } + + # Test when there are no relation users in the database. + _member_started.return_value = True + assert harness.charm.relations_user_databases_map == {} + + # Test when there are relation users in the database. + _postgresql.list_users_from_relation.return_value = {"user1", "user2"} + _postgresql.list_accessible_databases_for_user.side_effect = [{"db1", "db2"}, {"db3"}] + assert harness.charm.relations_user_databases_map == {"user1": "db1,db2", "user2": "db3"} + + # Test when the access groups where not created yet. + _postgresql.list_accessible_databases_for_user.side_effect = [{"db1", "db2"}, {"db3"}] + _postgresql.list_access_groups.return_value = set() + assert harness.charm.relations_user_databases_map == { + "user1": "db1,db2", + "user2": "db3", + "operator": "all", + "replication": "all", + "rewind": "all", + } From 1d27ff58967cf683c25573aafc30ae0d371dd693 Mon Sep 17 00:00:00 2001 From: Alex Lutay <1928266+taurus-forever@users.noreply.github.com> Date: Wed, 11 Jun 2025 12:09:06 +0200 Subject: [PATCH 040/112] DPE-6662 Fix pgbackrest logs names on logs rotation (#939) (#949) The pgBackRest activity (backup creation, stanza initialisation, etc) could take minutes, as a result every minute logs rotation could move the current log A.log to A.log_$date.log and will be moved further as logrorate rule operates all *.log files in the folder: > /var/snap/charmed-postgresql/common/var/log/pgbackrest/*.log { ... It results in: -rw------- 1 postgres postgres 0 Feb 18 09:25 all-server.log -rw------- 1 postgres postgres 0 Feb 18 09:19 all-server.log-20250218_09:18.log -rw------- 1 postgres postgres 0 Feb 18 09:20 all-server.log-20250218_09:18.log-20250218_09:19.log -rw------- 1 postgres postgres 0 Feb 18 09:21 all-server.log-20250218_09:18.log-20250218_09:19.log-20250218_09:20.log -rw------- 1 postgres postgres 0 Feb 18 09:22 all-server.log-20250218_09:18.log-20250218_09:19.log-20250218_09:20.log-20250218_09:21.log -rw------- 1 postgres postgres 0 Feb 18 09:23 all-server.log-20250218_09:18.log-20250218_09:19.log-20250218_09:20.log-20250218_09:21.log-20250218_09:22.log -rw------- 1 postgres postgres 1793 Feb 18 09:24 all-server.log-20250218_09:18.log-20250218_09:19.log-20250218_09:20.log-20250218_09:21.log-20250218_09:22.log-20250218_09:23.log The poposed fix: * move the log file to the new name without .log suffix. * use datetime format matching MySQL charms Example: -rw------- 1 postgres postgres 12 Feb 18 09:28 all-server.log -rw------- 1 postgres postgres 322 Feb 18 09:29 all-server.log-20250218_0918 -rw------- 1 postgres postgres 7344 Feb 18 09:30 all-server.log-20250218_0918 (cherry picked from commit ffa77b299ff16b38f645164f1a39669949c277df) --- templates/pgbackrest.logrotate.j2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/pgbackrest.logrotate.j2 b/templates/pgbackrest.logrotate.j2 index f65878648b..9af8bffabf 100644 --- a/templates/pgbackrest.logrotate.j2 +++ b/templates/pgbackrest.logrotate.j2 @@ -6,5 +6,5 @@ daily create 0600 snap_daemon snap_daemon dateext - dateformat -%Y%m%d_%H:%M.log + dateformat -%Y%m%d_%H%M } From e619cdc653ada906c8270e01d68a5be06bb9a268 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 11 Jun 2025 08:29:32 -0300 Subject: [PATCH 041/112] Update Python dependencies (#904) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- poetry.lock | 219 +++++++++++----------------------------------------- 1 file changed, 47 insertions(+), 172 deletions(-) diff --git a/poetry.lock b/poetry.lock index b9df277227..c18232a471 100644 --- a/poetry.lock +++ b/poetry.lock @@ -48,29 +48,6 @@ files = [ attrs = ">=16.0.0" pluggy = ">=0.4.0" -[[package]] -name = "anyio" -version = "4.9.0" -description = "High level compatibility layer for multiple asynchronous event loop implementations" -optional = false -python-versions = ">=3.9" -groups = ["charm-libs"] -files = [ - {file = "anyio-4.9.0-py3-none-any.whl", hash = "sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c"}, - {file = "anyio-4.9.0.tar.gz", hash = "sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028"}, -] - -[package.dependencies] -exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""} -idna = ">=2.8" -sniffio = ">=1.1" -typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""} - -[package.extras] -doc = ["Sphinx (>=8.2,<9.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx_rtd_theme"] -test = ["anyio[trio]", "blockbuster (>=1.5.23)", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "trustme", "truststore (>=0.9.1) ; python_version >= \"3.10\"", "uvloop (>=0.21) ; platform_python_implementation == \"CPython\" and platform_system != \"Windows\" and python_version < \"3.14\""] -trio = ["trio (>=0.26.1)"] - [[package]] name = "asttokens" version = "3.0.0" @@ -534,18 +511,17 @@ files = [ [[package]] name = "cosl" -version = "0.0.57" +version = "1.0.0" description = "Utils for COS Lite charms" optional = false python-versions = ">=3.8" groups = ["charm-libs"] files = [ - {file = "cosl-0.0.57-py3-none-any.whl", hash = "sha256:0f2bac6dd84a636747e63acd6cb277f1cc642d3c5f80caa13cd9b51644b8ff67"}, - {file = "cosl-0.0.57.tar.gz", hash = "sha256:7ed489973e6e72a9b9533dddf0da1df3499a0aacdc513ad0b579cb04b4671b04"}, + {file = "cosl-1.0.0-py3-none-any.whl", hash = "sha256:4ed54e818a5614a5164011253c12441cd0bffacfd99c8bd6b5b9740a397e482d"}, + {file = "cosl-1.0.0.tar.gz", hash = "sha256:5cef884faac1313ae6d234fcd6f40db0cbdd44bcdacfd9a6e9ecf9cede219359"}, ] [package.dependencies] -lightkube = ">=v0.15.4" ops = "*" pydantic = "*" pyyaml = "*" @@ -633,60 +609,62 @@ toml = ["tomli ; python_full_version <= \"3.11.0a6\""] [[package]] name = "cryptography" -version = "44.0.2" +version = "45.0.4" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false python-versions = "!=3.9.0,!=3.9.1,>=3.7" groups = ["charm-libs", "integration"] files = [ - {file = "cryptography-44.0.2-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:efcfe97d1b3c79e486554efddeb8f6f53a4cdd4cf6086642784fa31fc384e1d7"}, - {file = "cryptography-44.0.2-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29ecec49f3ba3f3849362854b7253a9f59799e3763b0c9d0826259a88efa02f1"}, - {file = "cryptography-44.0.2-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc821e161ae88bfe8088d11bb39caf2916562e0a2dc7b6d56714a48b784ef0bb"}, - {file = "cryptography-44.0.2-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:3c00b6b757b32ce0f62c574b78b939afab9eecaf597c4d624caca4f9e71e7843"}, - {file = "cryptography-44.0.2-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7bdcd82189759aba3816d1f729ce42ffded1ac304c151d0a8e89b9996ab863d5"}, - {file = "cryptography-44.0.2-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:4973da6ca3db4405c54cd0b26d328be54c7747e89e284fcff166132eb7bccc9c"}, - {file = "cryptography-44.0.2-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:4e389622b6927d8133f314949a9812972711a111d577a5d1f4bee5e58736b80a"}, - {file = "cryptography-44.0.2-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:f514ef4cd14bb6fb484b4a60203e912cfcb64f2ab139e88c2274511514bf7308"}, - {file = "cryptography-44.0.2-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:1bc312dfb7a6e5d66082c87c34c8a62176e684b6fe3d90fcfe1568de675e6688"}, - {file = "cryptography-44.0.2-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:3b721b8b4d948b218c88cb8c45a01793483821e709afe5f622861fc6182b20a7"}, - {file = "cryptography-44.0.2-cp37-abi3-win32.whl", hash = "sha256:51e4de3af4ec3899d6d178a8c005226491c27c4ba84101bfb59c901e10ca9f79"}, - {file = "cryptography-44.0.2-cp37-abi3-win_amd64.whl", hash = "sha256:c505d61b6176aaf982c5717ce04e87da5abc9a36a5b39ac03905c4aafe8de7aa"}, - {file = "cryptography-44.0.2-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:8e0ddd63e6bf1161800592c71ac794d3fb8001f2caebe0966e77c5234fa9efc3"}, - {file = "cryptography-44.0.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81276f0ea79a208d961c433a947029e1a15948966658cf6710bbabb60fcc2639"}, - {file = "cryptography-44.0.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a1e657c0f4ea2a23304ee3f964db058c9e9e635cc7019c4aa21c330755ef6fd"}, - {file = "cryptography-44.0.2-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:6210c05941994290f3f7f175a4a57dbbb2afd9273657614c506d5976db061181"}, - {file = "cryptography-44.0.2-cp39-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d1c3572526997b36f245a96a2b1713bf79ce99b271bbcf084beb6b9b075f29ea"}, - {file = "cryptography-44.0.2-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:b042d2a275c8cee83a4b7ae30c45a15e6a4baa65a179a0ec2d78ebb90e4f6699"}, - {file = "cryptography-44.0.2-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:d03806036b4f89e3b13b6218fefea8d5312e450935b1a2d55f0524e2ed7c59d9"}, - {file = "cryptography-44.0.2-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:c7362add18b416b69d58c910caa217f980c5ef39b23a38a0880dfd87bdf8cd23"}, - {file = "cryptography-44.0.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:8cadc6e3b5a1f144a039ea08a0bdb03a2a92e19c46be3285123d32029f40a922"}, - {file = "cryptography-44.0.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6f101b1f780f7fc613d040ca4bdf835c6ef3b00e9bd7125a4255ec574c7916e4"}, - {file = "cryptography-44.0.2-cp39-abi3-win32.whl", hash = "sha256:3dc62975e31617badc19a906481deacdeb80b4bb454394b4098e3f2525a488c5"}, - {file = "cryptography-44.0.2-cp39-abi3-win_amd64.whl", hash = "sha256:5f6f90b72d8ccadb9c6e311c775c8305381db88374c65fa1a68250aa8a9cb3a6"}, - {file = "cryptography-44.0.2-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:af4ff3e388f2fa7bff9f7f2b31b87d5651c45731d3e8cfa0944be43dff5cfbdb"}, - {file = "cryptography-44.0.2-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:0529b1d5a0105dd3731fa65680b45ce49da4d8115ea76e9da77a875396727b41"}, - {file = "cryptography-44.0.2-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:7ca25849404be2f8e4b3c59483d9d3c51298a22c1c61a0e84415104dacaf5562"}, - {file = "cryptography-44.0.2-pp310-pypy310_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:268e4e9b177c76d569e8a145a6939eca9a5fec658c932348598818acf31ae9a5"}, - {file = "cryptography-44.0.2-pp310-pypy310_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:9eb9d22b0a5d8fd9925a7764a054dca914000607dff201a24c791ff5c799e1fa"}, - {file = "cryptography-44.0.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:2bf7bf75f7df9715f810d1b038870309342bff3069c5bd8c6b96128cb158668d"}, - {file = "cryptography-44.0.2-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:909c97ab43a9c0c0b0ada7a1281430e4e5ec0458e6d9244c0e821bbf152f061d"}, - {file = "cryptography-44.0.2-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:96e7a5e9d6e71f9f4fca8eebfd603f8e86c5225bb18eb621b2c1e50b290a9471"}, - {file = "cryptography-44.0.2-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:d1b3031093a366ac767b3feb8bcddb596671b3aaff82d4050f984da0c248b615"}, - {file = "cryptography-44.0.2-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:04abd71114848aa25edb28e225ab5f268096f44cf0127f3d36975bdf1bdf3390"}, - {file = "cryptography-44.0.2.tar.gz", hash = "sha256:c63454aa261a0cf0c5b4718349629793e9e634993538db841165b3df74f37ec0"}, + {file = "cryptography-45.0.4-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:425a9a6ac2823ee6e46a76a21a4e8342d8fa5c01e08b823c1f19a8b74f096069"}, + {file = "cryptography-45.0.4-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:680806cf63baa0039b920f4976f5f31b10e772de42f16310a6839d9f21a26b0d"}, + {file = "cryptography-45.0.4-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4ca0f52170e821bc8da6fc0cc565b7bb8ff8d90d36b5e9fdd68e8a86bdf72036"}, + {file = "cryptography-45.0.4-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:f3fe7a5ae34d5a414957cc7f457e2b92076e72938423ac64d215722f6cf49a9e"}, + {file = "cryptography-45.0.4-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:25eb4d4d3e54595dc8adebc6bbd5623588991d86591a78c2548ffb64797341e2"}, + {file = "cryptography-45.0.4-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:ce1678a2ccbe696cf3af15a75bb72ee008d7ff183c9228592ede9db467e64f1b"}, + {file = "cryptography-45.0.4-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:49fe9155ab32721b9122975e168a6760d8ce4cffe423bcd7ca269ba41b5dfac1"}, + {file = "cryptography-45.0.4-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:2882338b2a6e0bd337052e8b9007ced85c637da19ef9ecaf437744495c8c2999"}, + {file = "cryptography-45.0.4-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:23b9c3ea30c3ed4db59e7b9619272e94891f8a3a5591d0b656a7582631ccf750"}, + {file = "cryptography-45.0.4-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b0a97c927497e3bc36b33987abb99bf17a9a175a19af38a892dc4bbb844d7ee2"}, + {file = "cryptography-45.0.4-cp311-abi3-win32.whl", hash = "sha256:e00a6c10a5c53979d6242f123c0a97cff9f3abed7f064fc412c36dc521b5f257"}, + {file = "cryptography-45.0.4-cp311-abi3-win_amd64.whl", hash = "sha256:817ee05c6c9f7a69a16200f0c90ab26d23a87701e2a284bd15156783e46dbcc8"}, + {file = "cryptography-45.0.4-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:964bcc28d867e0f5491a564b7debb3ffdd8717928d315d12e0d7defa9e43b723"}, + {file = "cryptography-45.0.4-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6a5bf57554e80f75a7db3d4b1dacaa2764611ae166ab42ea9a72bcdb5d577637"}, + {file = "cryptography-45.0.4-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:46cf7088bf91bdc9b26f9c55636492c1cce3e7aaf8041bbf0243f5e5325cfb2d"}, + {file = "cryptography-45.0.4-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:7bedbe4cc930fa4b100fc845ea1ea5788fcd7ae9562e669989c11618ae8d76ee"}, + {file = "cryptography-45.0.4-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:eaa3e28ea2235b33220b949c5a0d6cf79baa80eab2eb5607ca8ab7525331b9ff"}, + {file = "cryptography-45.0.4-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:7ef2dde4fa9408475038fc9aadfc1fb2676b174e68356359632e980c661ec8f6"}, + {file = "cryptography-45.0.4-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:6a3511ae33f09094185d111160fd192c67aa0a2a8d19b54d36e4c78f651dc5ad"}, + {file = "cryptography-45.0.4-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:06509dc70dd71fa56eaa138336244e2fbaf2ac164fc9b5e66828fccfd2b680d6"}, + {file = "cryptography-45.0.4-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:5f31e6b0a5a253f6aa49be67279be4a7e5a4ef259a9f33c69f7d1b1191939872"}, + {file = "cryptography-45.0.4-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:944e9ccf67a9594137f942d5b52c8d238b1b4e46c7a0c2891b7ae6e01e7c80a4"}, + {file = "cryptography-45.0.4-cp37-abi3-win32.whl", hash = "sha256:c22fe01e53dc65edd1945a2e6f0015e887f84ced233acecb64b4daadb32f5c97"}, + {file = "cryptography-45.0.4-cp37-abi3-win_amd64.whl", hash = "sha256:627ba1bc94f6adf0b0a2e35d87020285ead22d9f648c7e75bb64f367375f3b22"}, + {file = "cryptography-45.0.4-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a77c6fb8d76e9c9f99f2f3437c1a4ac287b34eaf40997cfab1e9bd2be175ac39"}, + {file = "cryptography-45.0.4-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:7aad98a25ed8ac917fdd8a9c1e706e5a0956e06c498be1f713b61734333a4507"}, + {file = "cryptography-45.0.4-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:3530382a43a0e524bc931f187fc69ef4c42828cf7d7f592f7f249f602b5a4ab0"}, + {file = "cryptography-45.0.4-pp310-pypy310_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:6b613164cb8425e2f8db5849ffb84892e523bf6d26deb8f9bb76ae86181fa12b"}, + {file = "cryptography-45.0.4-pp310-pypy310_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:96d4819e25bf3b685199b304a0029ce4a3caf98947ce8a066c9137cc78ad2c58"}, + {file = "cryptography-45.0.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b97737a3ffbea79eebb062eb0d67d72307195035332501722a9ca86bab9e3ab2"}, + {file = "cryptography-45.0.4-pp311-pypy311_pp73-macosx_10_9_x86_64.whl", hash = "sha256:4828190fb6c4bcb6ebc6331f01fe66ae838bb3bd58e753b59d4b22eb444b996c"}, + {file = "cryptography-45.0.4-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:03dbff8411206713185b8cebe31bc5c0eb544799a50c09035733716b386e61a4"}, + {file = "cryptography-45.0.4-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:51dfbd4d26172d31150d84c19bbe06c68ea4b7f11bbc7b3a5e146b367c311349"}, + {file = "cryptography-45.0.4-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:0339a692de47084969500ee455e42c58e449461e0ec845a34a6a9b9bf7df7fb8"}, + {file = "cryptography-45.0.4-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:0cf13c77d710131d33e63626bd55ae7c0efb701ebdc2b3a7952b9b23a0412862"}, + {file = "cryptography-45.0.4-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:bbc505d1dc469ac12a0a064214879eac6294038d6b24ae9f71faae1448a9608d"}, + {file = "cryptography-45.0.4.tar.gz", hash = "sha256:7405ade85c83c37682c8fe65554759800a4a8c54b2d96e0f8ad114d31b808d57"}, ] [package.dependencies] -cffi = {version = ">=1.12", markers = "platform_python_implementation != \"PyPy\""} +cffi = {version = ">=1.14", markers = "platform_python_implementation != \"PyPy\""} [package.extras] -docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=3.0.0) ; python_version >= \"3.8\""] +docs = ["sphinx (>=5.3.0)", "sphinx-inline-tabs ; python_full_version >= \"3.8.0\"", "sphinx-rtd-theme (>=3.0.0) ; python_full_version >= \"3.8.0\""] docstest = ["pyenchant (>=3)", "readme-renderer (>=30.0)", "sphinxcontrib-spelling (>=7.3.1)"] -nox = ["nox (>=2024.4.15)", "nox[uv] (>=2024.3.2) ; python_version >= \"3.8\""] -pep8test = ["check-sdist ; python_version >= \"3.8\"", "click (>=8.0.1)", "mypy (>=1.4)", "ruff (>=0.3.6)"] +nox = ["nox (>=2024.4.15)", "nox[uv] (>=2024.3.2) ; python_full_version >= \"3.8.0\""] +pep8test = ["check-sdist ; python_full_version >= \"3.8.0\"", "click (>=8.0.1)", "mypy (>=1.4)", "ruff (>=0.3.6)"] sdist = ["build (>=1.0.0)"] ssh = ["bcrypt (>=3.1.5)"] -test = ["certifi (>=2024)", "cryptography-vectors (==44.0.2)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"] +test = ["certifi (>=2024)", "cryptography-vectors (==45.0.4)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"] test-randomorder = ["pytest-randomly"] [[package]] @@ -725,7 +703,7 @@ version = "1.2.2" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" -groups = ["charm-libs", "integration", "unit"] +groups = ["integration", "unit"] markers = "python_version < \"3.11\"" files = [ {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, @@ -795,65 +773,6 @@ protobuf = ">=3.20.2,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4 [package.extras] grpc = ["grpcio (>=1.44.0,<2.0.0)"] -[[package]] -name = "h11" -version = "0.16.0" -description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" -optional = false -python-versions = ">=3.8" -groups = ["charm-libs"] -files = [ - {file = "h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86"}, - {file = "h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1"}, -] - -[[package]] -name = "httpcore" -version = "1.0.9" -description = "A minimal low-level HTTP client." -optional = false -python-versions = ">=3.8" -groups = ["charm-libs"] -files = [ - {file = "httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55"}, - {file = "httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8"}, -] - -[package.dependencies] -certifi = "*" -h11 = ">=0.16" - -[package.extras] -asyncio = ["anyio (>=4.0,<5.0)"] -http2 = ["h2 (>=3,<5)"] -socks = ["socksio (==1.*)"] -trio = ["trio (>=0.22.0,<1.0)"] - -[[package]] -name = "httpx" -version = "0.28.1" -description = "The next generation HTTP client." -optional = false -python-versions = ">=3.8" -groups = ["charm-libs"] -files = [ - {file = "httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad"}, - {file = "httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc"}, -] - -[package.dependencies] -anyio = "*" -certifi = "*" -httpcore = "==1.*" -idna = "*" - -[package.extras] -brotli = ["brotli ; platform_python_implementation == \"CPython\"", "brotlicffi ; platform_python_implementation != \"CPython\""] -cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] -http2 = ["h2 (>=3,<5)"] -socks = ["socksio (==1.*)"] -zstd = ["zstandard (>=0.18.0)"] - [[package]] name = "hvac" version = "2.3.0" @@ -1135,38 +1054,6 @@ files = [ [package.dependencies] requests = "*" -[[package]] -name = "lightkube" -version = "0.17.1" -description = "Lightweight kubernetes client library" -optional = false -python-versions = "*" -groups = ["charm-libs"] -files = [ - {file = "lightkube-0.17.1-py3-none-any.whl", hash = "sha256:3d046c2c46191b3745471763710ef4ed2df4259a7405f798b577df2ae390358a"}, - {file = "lightkube-0.17.1.tar.gz", hash = "sha256:e0d6b71476a4fa7cbda7080da1f0943e43c7e747212db9f2ec7d87415bf8d23e"}, -] - -[package.dependencies] -httpx = ">=0.24.0,<1.0.0" -lightkube-models = ">=1.15.12.0" -PyYAML = "*" - -[package.extras] -dev = ["pytest", "pytest-asyncio", "respx"] - -[[package]] -name = "lightkube-models" -version = "1.32.0.8" -description = "Models and Resources for lightkube module" -optional = false -python-versions = "*" -groups = ["charm-libs"] -files = [ - {file = "lightkube-models-1.32.0.8.tar.gz", hash = "sha256:97f6c2ab554a23a69554dd56ffbd94173fb416af6490c3a21b1e0b8e13a2bafe"}, - {file = "lightkube_models-1.32.0.8-py3-none-any.whl", hash = "sha256:73786dac63085521f4c88aa69d86bfdc76a67da997c1770e5bdcef8482e4b2a0"}, -] - [[package]] name = "macaroonbakery" version = "1.3.4" @@ -2347,18 +2234,6 @@ files = [ {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, ] -[[package]] -name = "sniffio" -version = "1.3.1" -description = "Sniff out which async library your code is running under" -optional = false -python-versions = ">=3.7" -groups = ["charm-libs"] -files = [ - {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, - {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, -] - [[package]] name = "stack-data" version = "0.6.3" From cee4c6c79f8231753de9ec16396e0e5f656abb54 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 11 Jun 2025 10:14:56 -0300 Subject: [PATCH 042/112] Update canonical/data-platform-workflows action to v31.1.1 (#872) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/approve_renovate_pr.yaml | 2 +- .github/workflows/check_pr.yaml | 2 +- .github/workflows/ci.yaml | 4 ++-- .github/workflows/promote.yaml | 2 +- .github/workflows/release.yaml | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/approve_renovate_pr.yaml b/.github/workflows/approve_renovate_pr.yaml index 450111576b..88030ca0b0 100644 --- a/.github/workflows/approve_renovate_pr.yaml +++ b/.github/workflows/approve_renovate_pr.yaml @@ -10,6 +10,6 @@ on: jobs: approve-pr: name: Approve Renovate pull request - uses: canonical/data-platform-workflows/.github/workflows/approve_renovate_pr.yaml@v31.0.1 + uses: canonical/data-platform-workflows/.github/workflows/approve_renovate_pr.yaml@v31.1.1 permissions: pull-requests: write # Needed to approve PR diff --git a/.github/workflows/check_pr.yaml b/.github/workflows/check_pr.yaml index f613a6aed9..5ed03d4774 100644 --- a/.github/workflows/check_pr.yaml +++ b/.github/workflows/check_pr.yaml @@ -16,4 +16,4 @@ on: jobs: check-pr: name: Check pull request - uses: canonical/data-platform-workflows/.github/workflows/check_charm_pr.yaml@v31.0.1 + uses: canonical/data-platform-workflows/.github/workflows/check_charm_pr.yaml@v31.1.1 diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index cdaae9244d..4c2e86edcd 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -27,7 +27,7 @@ on: jobs: lint: name: Lint - uses: canonical/data-platform-workflows/.github/workflows/lint.yaml@v31.0.1 + uses: canonical/data-platform-workflows/.github/workflows/lint.yaml@v31.1.1 unit-test: name: Unit test charm @@ -49,7 +49,7 @@ jobs: build: name: Build charm - uses: canonical/data-platform-workflows/.github/workflows/build_charm.yaml@v31.0.1 + uses: canonical/data-platform-workflows/.github/workflows/build_charm.yaml@v31.1.1 integration-test: name: Integration test charm diff --git a/.github/workflows/promote.yaml b/.github/workflows/promote.yaml index 03e7bc7a29..ef229520fd 100644 --- a/.github/workflows/promote.yaml +++ b/.github/workflows/promote.yaml @@ -25,7 +25,7 @@ on: jobs: promote: name: Promote charm - uses: canonical/data-platform-workflows/.github/workflows/_promote_charm.yaml@v31.0.1 + uses: canonical/data-platform-workflows/.github/workflows/_promote_charm.yaml@v31.1.1 with: track: '14' from-risk: ${{ inputs.from-risk }} diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 28b9ddc5e1..04ecfeff0f 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -27,7 +27,7 @@ jobs: name: Release charm needs: - ci-tests - uses: canonical/data-platform-workflows/.github/workflows/release_charm.yaml@v31.0.1 + uses: canonical/data-platform-workflows/.github/workflows/release_charm.yaml@v31.1.1 with: channel: 14/edge artifact-prefix: ${{ needs.ci-tests.outputs.artifact-prefix }} From 1a243eee87131a689d101e6dbedd3bb0b389a83a Mon Sep 17 00:00:00 2001 From: Andreia Date: Thu, 12 Jun 2025 14:34:32 +0200 Subject: [PATCH 043/112] Add redirects for all charmhub pages (14) (#961) * feat: add rediraffe sphinx extension and discourse redirects for each page * convert tabs to single space * fix: minor style issues in README.md and CONTRIBUTING.md * comment out old redirect extension to avoid confusion --- CONTRIBUTING.md | 2 + README.md | 3 ++ docs/conf.py | 4 +- docs/redirects.txt | 105 ++++++++++++++++++++++++++++++++++++++++++ docs/requirements.txt | 1 + 5 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 docs/redirects.txt diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 388378cdff..873ce9606d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -40,6 +40,7 @@ tox # runs 'lint' and 'unit' environments ## Build charm The build environment assumes that there are preinstalled on the system: + * [tox](https://tox.wiki/) (version 4+ !!!) * [poetry](https://python-poetry.org/) * [charmcraft](https://snapcraft.io/charmcraft) @@ -69,6 +70,7 @@ pipx install charmcraftcache ``` Ensure local pip binaries are in your $PATH (otherwise re-login to your shell): + ```shell charmcraftcache --help ``` diff --git a/README.md b/README.md index 56198bf724..7e836a9759 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # Charmed PostgreSQL VM Operator + [![CharmHub Badge](https://charmhub.io/postgresql/badge.svg)](https://charmhub.io/postgresql) [![Release](https://github.com/canonical/postgresql-operator/actions/workflows/release.yaml/badge.svg)](https://github.com/canonical/postgresql-operator/actions/workflows/release.yaml) [![Tests](https://github.com/canonical/postgresql-operator/actions/workflows/ci.yaml/badge.svg?branch=main)](https://github.com/canonical/postgresql-operator/actions/workflows/ci.yaml?query=branch%3Amain) @@ -126,6 +127,7 @@ juju integrate postgresql ``` To remove a relation: + ```shell juju remove-relation postgresql ``` @@ -133,6 +135,7 @@ juju remove-relation postgresql #### Legacy `pgsql` interface We have also added support for the two database legacy relations from the [original version](https://launchpad.net/postgresql-charm) of the charm via the `pgsql` interface. Please note that these relations will be deprecated. + ```shell juju relate postgresql:db mailman3-core juju relate postgresql:db-admin landscape-server diff --git a/docs/conf.py b/docs/conf.py index fb6c96f500..8224800db0 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -193,8 +193,9 @@ # NOTE: If undefined, set to None, or empty, # the sphinx_reredirects extension will be disabled. -redirects = {} +# redirects = {} +rediraffe_redirects = "redirects.txt" ########################### # Link checker exceptions # @@ -258,6 +259,7 @@ "sphinxcontrib.cairosvgconverter", "sphinx_last_updated_by_git", "sphinx.ext.intersphinx", + "sphinxext.rediraffe" ] # Excludes files or directories from processing diff --git a/docs/redirects.txt b/docs/redirects.txt new file mode 100644 index 0000000000..edb7c5031f --- /dev/null +++ b/docs/redirects.txt @@ -0,0 +1,105 @@ +# The redirects.txt file stores all the redirects for the published docs +# If you change a filename, move or delete a file, you need a redirect here. +# - Comment lines start with a hash (#) and are ignored +# - Each redirect should appear on its own line + +# We are using the dirhtml builder, so files are treated as directories: +# - A file is built like `filename/index.html`, not `filename.html` +# - *Do* include a trailing slash at the end of the path +# - *Do not* include a file extension or you'll get errors +# - Paths don't need a slash in front of them + +# Example: +# redirect/from/file/ redirect/to/file/ + +# Tutorials +t-set-up tutorial/ +t-deploy tutorial/ +t-access tutorial/ +t-scale tutorial/ +t-manage-passwords tutorial/ +t-integrate tutorial/ +t-enable-tls tutorial/ +t-clean-up tutorial/ + +# How-to guides +h-deploy how-to/deploy +h-deploy-sunbeam how-to/deploy/sunbeam +h-deploy-maas how-to/deploy/maas +h-deploy-ec2 how-to/deploy/aws-ec2 +h-deploy-gce how-to/deploy/gce +h-deploy-azure how-to/deploy/azure +h-deploy-multi-az how-to/deploy/multi-az +h-deploy-tls-vip-access how-to/deploy/tls-vip-access +h-deploy-terraform how-to/deploy/terraform +h-deploy-airgapped how-to/deploy/air-gapped +h-deploy-juju-storage how-to/deploy/juju-storage + +h-integrate how-to/integrate-with-another-application +h-manage-passwords how-to/manage-passwords +h-external-access how-to/external-network-access +h-scale how-to/scale-replicas +h-switchover-failover how-to/switchover-failover +h-enable-tls how-to/enable-tls +h-enable-ldap how-to/enable-ldap + +h-enable-plugins-extensions how-to/enable-plugins-extensions +h-plugins-timescaledb how-to/enable-plugins-extensions/enable-timescaledb + +h-backup how-to/back-up-and-restore/ +h-configure-s3-aws how-to/back-up-and-restore/configure-s3-aws +h-configure-s3-radosgw how-to/back-up-and-restore/configure-s3-radosgw +h-create-backup how-to/back-up-and-restore/create-a-backup +h-restore-backup how-to/back-up-and-restore/restore-a-backup +h-manage-backup-retention how-to/back-up-and-restore/manage-backup-retention +h-migrate-cluster how-to/back-up-and-restore/migrate-a-cluster + +h-monitor how-to/monitoring-cos/ +h-enable-monitoring how-to/monitoring-cos/enable-monitoring +h-enable-alert-rules how-to/monitoring-cos/enable-alert-rules +h-enable-tracing how-to/monitoring-cos/enable-tracing +h-enable-profiling how-to/monitoring-cos/enable-profiling + +h-upgrade how-to/upgrade/ +h-upgrade-minor how-to/upgrade/perform-a-minor-upgrade +h-rollback-minor how-to/upgrade/perform-a-minor-rollback + +h-async how-to/cross-regional-async-replication/ +h-async-set-up how-to/cross-regional-async-replication/set-up-clusters +h-async-integrate how-to/cross-regional-async-replication/integrate-with-a-client-app +h-async-remove-recover how-to/cross-regional-async-replication/remove-or-recover-a-cluster + +h-development how-to/development/ +h-development-integrate how-to/development/integrate-with-your-charm +h-migrate-pgdump how-to/development/migrate-data-via-pg-dump +h-migrate-backup-restore how-to/development/migrate-data-via-backup-restore + +# Reference +r-releases reference/releases +r-versions reference/versions +r-system-requirements reference/system-requirements +r-software-testing reference/software-testing +r-performance reference/performance-and-resources + +r-troubleshooting reference/troubleshooting/ +r-sos-report reference/troubleshooting/sos-report +r-cli-helpers reference/troubleshooting/cli-helpers + +r-plugins-extensions reference/plugins-extensions +r-alert-rules reference/alert-rules +r-statuses reference/statuses +r-contacts reference/contacts + +# Explanation +e-architecture explanation/architecture +e-interfaces-endpoints explanation/interfaces-and-endpoints +e-juju-details explanation/juju +e-legacy-charm explanation/legacy-charm +e-units explanation/units +e-users explanation/users +e-roles explanation/roles +e-logs explanation/logs +e-connection-pooling explanation/connection-pooling + +e-security explanation/security/ +e-cryptography explanation/security/cryptography \ No newline at end of file diff --git a/docs/requirements.txt b/docs/requirements.txt index ffde202e3a..769442aef6 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,3 +1,4 @@ canonical-sphinx[full] sphinxcontrib-svg2pdfconverter[CairoSVG] sphinx-last-updated-by-git +sphinxext-rediraffe \ No newline at end of file From 6c47da6655047cab27996e4b6971a64840b41e02 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 13 Jun 2025 01:27:47 +0300 Subject: [PATCH 044/112] Update dependency requests to v2.32.4 [SECURITY] (#956) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- poetry.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/poetry.lock b/poetry.lock index c18232a471..fa68830f08 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1998,19 +1998,19 @@ typing-extensions = {version = ">=4.4.0", markers = "python_version < \"3.13\""} [[package]] name = "requests" -version = "2.32.3" +version = "2.32.4" description = "Python HTTP for Humans." optional = false python-versions = ">=3.8" groups = ["main", "charm-libs", "integration"] files = [ - {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, - {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, + {file = "requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c"}, + {file = "requests-2.32.4.tar.gz", hash = "sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422"}, ] [package.dependencies] certifi = ">=2017.4.17" -charset-normalizer = ">=2,<4" +charset_normalizer = ">=2,<4" idna = ">=2.5,<4" urllib3 = ">=1.21.1,<3" From 34b1b8446089cc8fc9ff6c869f30734625dd8acd Mon Sep 17 00:00:00 2001 From: Dragomir Penev <6687393+dragomirp@users.noreply.github.com> Date: Fri, 13 Jun 2025 12:45:26 +0300 Subject: [PATCH 045/112] Backport #959 to 14/edge (#963) --- lib/charms/postgresql_k8s/v0/postgresql.py | 20 ++++++- src/relations/postgresql_provider.py | 34 ++++------- .../ha_tests/test_async_replication.py | 56 +++++++++---------- tests/integration/helpers.py | 13 ++++- tests/unit/test_postgresql_provider.py | 3 - 5 files changed, 68 insertions(+), 58 deletions(-) diff --git a/lib/charms/postgresql_k8s/v0/postgresql.py b/lib/charms/postgresql_k8s/v0/postgresql.py index f839b5c004..1c73959a37 100644 --- a/lib/charms/postgresql_k8s/v0/postgresql.py +++ b/lib/charms/postgresql_k8s/v0/postgresql.py @@ -35,7 +35,7 @@ # Increment this PATCH version before using `charmcraft publish-lib` or reset # to 0 if you are raising the major API version -LIBPATCH = 55 +LIBPATCH = 56 # Groups to distinguish HBA access ACCESS_GROUP_IDENTITY = "identity_access" @@ -1078,3 +1078,21 @@ def validate_group_map(self, group_map: Optional[str]) -> bool: return False return True + + def is_user_in_hba(self, username: str) -> bool: + """Check if user was added in pg_hba.""" + connection = None + try: + with self._connect_to_database() as connection, connection.cursor() as cursor: + cursor.execute( + SQL( + "SELECT COUNT(*) FROM pg_hba_file_rules WHERE {} = ANY(user_name);" + ).format(Literal(username)) + ) + return cursor.fetchone()[0] > 0 + except psycopg2.Error as e: + logger.debug(f"Failed to check pg_hba: {e}") + return False + finally: + if connection: + connection.close() diff --git a/src/relations/postgresql_provider.py b/src/relations/postgresql_provider.py index 1ff167d03d..1734d4f047 100644 --- a/src/relations/postgresql_provider.py +++ b/src/relations/postgresql_provider.py @@ -4,6 +4,7 @@ """Postgres client relation hooks & helpers.""" import logging +from datetime import datetime from charms.data_platform_libs.v0.data_interfaces import ( DatabaseProvides, @@ -22,6 +23,7 @@ from ops.charm import CharmBase, RelationBrokenEvent, RelationChangedEvent from ops.framework import Object from ops.model import ActiveStatus, BlockedStatus, Relation +from tenacity import RetryError, Retrying, stop_after_attempt, wait_fixed from constants import ( ALL_CLIENT_RELATIONS, @@ -66,9 +68,6 @@ def __init__(self, charm: CharmBase, relation_name: str = "database") -> None: self.framework.observe( self.database_provides.on.database_requested, self._on_database_requested ) - self.framework.observe( - charm.on[self.relation_name].relation_changed, self._on_relation_changed - ) @staticmethod def _sanitize_extra_roles(extra_roles: str | None) -> list[str]: @@ -145,27 +144,16 @@ def _on_database_requested(self, event: DatabaseRequestedEvent) -> None: else f"Failed to initialize {self.relation_name} relation" ) - def _on_relation_changed(self, event: RelationChangedEvent) -> None: - # Check for some conditions before trying to access the PostgreSQL instance. - if not self.charm.is_cluster_initialised: - logger.debug( - "Deferring on_relation_changed: Cluster must be initialized before configuration can be updated with relation users" - ) - event.defer() - return - - user = f"relation-{event.relation.id}" + # Try to wait for pg_hba trigger try: - if user not in self.charm.postgresql.list_users(): - logger.debug("Deferring on_relation_changed: user was not created yet") - event.defer() - return - except PostgreSQLListUsersError: - logger.debug("Deferring on_relation_changed: failed to list users") - event.defer() - return - - self.charm.update_config() + for attempt in Retrying(stop=stop_after_attempt(3), wait=wait_fixed(1)): + with attempt: + self.charm.postgresql.is_user_in_hba(user) + self.charm.unit_peer_data.update({ + "pg_hba_needs_update_timestamp": str(datetime.now()) + }) + except RetryError: + logger.warning("database requested: Unable to check pg_hba rule update") def _on_relation_broken(self, event: RelationBrokenEvent) -> None: """Correctly update the status.""" diff --git a/tests/integration/ha_tests/test_async_replication.py b/tests/integration/ha_tests/test_async_replication.py index 7ac7ec4dbe..a879e5e63d 100644 --- a/tests/integration/ha_tests/test_async_replication.py +++ b/tests/integration/ha_tests/test_async_replication.py @@ -125,8 +125,12 @@ async def test_deploy_async_replication_setup( num_units=CLUSTER_SIZE, config={"profile": "testing"}, ) - await ops_test.model.deploy(APPLICATION_NAME, channel="latest/edge", num_units=1) - await second_model.deploy(APPLICATION_NAME, channel="latest/edge", num_units=1) + await ops_test.model.deploy( + APPLICATION_NAME, channel="latest/edge", num_units=1, config={"sleep_interval": 1000} + ) + await second_model.deploy( + APPLICATION_NAME, channel="latest/edge", num_units=1, config={"sleep_interval": 1000} + ) async with ops_test.fast_forward(), fast_forward(second_model): await gather( @@ -535,36 +539,32 @@ async def test_scaling( logger.info("checking whether writes are increasing") await are_writes_increasing(ops_test) - async with ops_test.fast_forward(FAST_INTERVAL), fast_forward(second_model, FAST_INTERVAL): - logger.info("scaling out the first cluster") - first_cluster_original_size = len(first_model.applications[DATABASE_APP_NAME].units) - await scale_application(ops_test, DATABASE_APP_NAME, first_cluster_original_size + 1) - - logger.info("checking whether writes are increasing") - await are_writes_increasing(ops_test, extra_model=second_model) - - logger.info("scaling out the second cluster") - second_cluster_original_size = len(second_model.applications[DATABASE_APP_NAME].units) - await scale_application( - ops_test, DATABASE_APP_NAME, second_cluster_original_size + 1, model=second_model - ) - - logger.info("checking whether writes are increasing") - await are_writes_increasing(ops_test, extra_model=second_model) - - logger.info("scaling in the first cluster") - await scale_application(ops_test, DATABASE_APP_NAME, first_cluster_original_size) + logger.info("scaling out the clusters") + first_cluster_original_size = len(first_model.applications[DATABASE_APP_NAME].units) + second_cluster_original_size = len(second_model.applications[DATABASE_APP_NAME].units) + await gather( + scale_application(ops_test, DATABASE_APP_NAME, first_cluster_original_size + 1), + scale_application( + ops_test, + DATABASE_APP_NAME, + second_cluster_original_size + 1, + model=second_model, + ), + ) - logger.info("checking whether writes are increasing") - await are_writes_increasing(ops_test, extra_model=second_model) + logger.info("checking whether writes are increasing") + await are_writes_increasing(ops_test, extra_model=second_model) - logger.info("scaling in the second cluster") - await scale_application( + logger.info("scaling in the clusters") + await gather( + scale_application(ops_test, DATABASE_APP_NAME, first_cluster_original_size), + scale_application( ops_test, DATABASE_APP_NAME, second_cluster_original_size, model=second_model - ) + ), + ) - logger.info("checking whether writes are increasing") - await are_writes_increasing(ops_test, extra_model=second_model) + logger.info("checking whether writes are increasing") + await are_writes_increasing(ops_test, extra_model=second_model) # Verify that no writes to the database were missed after stopping the writes # (check that all the units have all the writes). diff --git a/tests/integration/helpers.py b/tests/integration/helpers.py index e707f4ddf3..851ef58dac 100644 --- a/tests/integration/helpers.py +++ b/tests/integration/helpers.py @@ -950,7 +950,12 @@ async def run_command_on_unit(ops_test: OpsTest, unit_name: str, command: str) - async def scale_application( - ops_test: OpsTest, application_name: str, count: int, model: Model = None + ops_test: OpsTest, + application_name: str, + count: int, + model: Model = None, + timeout=2000, + idle_period: int = 30, ) -> None: """Scale a given application to a specific unit count. @@ -959,6 +964,8 @@ async def scale_application( application_name: The name of the application count: The desired number of units to scale to model: The model to scale the application in + timeout: timeout period + idle_period: idle period """ if model is None: model = ops_test.model @@ -971,8 +978,8 @@ async def scale_application( await model.wait_for_idle( apps=[application_name], status="active", - timeout=2000, - idle_period=30, + timeout=timeout, + idle_period=idle_period, wait_for_exact_units=count, ) diff --git a/tests/unit/test_postgresql_provider.py b/tests/unit/test_postgresql_provider.py index 46a28570ba..9c7947ca5d 100644 --- a/tests/unit/test_postgresql_provider.py +++ b/tests/unit/test_postgresql_provider.py @@ -76,9 +76,6 @@ def request_database(_harness): def test_on_database_requested(harness): with ( patch("charm.PostgresqlOperatorCharm.update_config"), - patch( - "relations.postgresql_provider.PostgreSQLProvider._on_relation_changed" - ) as _on_relation_changed, patch.object(PostgresqlOperatorCharm, "postgresql", Mock()) as postgresql_mock, patch("subprocess.check_output", return_value=b"C"), patch("charm.PostgreSQLProvider.update_endpoints") as _update_endpoints, From c778ce6b1d8ee64be167486362a7d0dccb175561 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 13 Jun 2025 12:50:50 +0300 Subject: [PATCH 046/112] Lock file maintenance Python dependencies (#874) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- poetry.lock | 767 +++++++++++++++++++++++++------------------------ pyproject.toml | 22 +- 2 files changed, 401 insertions(+), 388 deletions(-) diff --git a/poetry.lock b/poetry.lock index fa68830f08..fcf8535e03 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2,30 +2,30 @@ [[package]] name = "allure-pytest" -version = "2.14.1" +version = "2.14.3" description = "Allure pytest integration" optional = false python-versions = "*" groups = ["integration"] files = [ - {file = "allure_pytest-2.14.1-py3-none-any.whl", hash = "sha256:2d35bee7118b6478acac264cf8e9b401ca9a8b1929cae2afa56c9c79193be3a2"}, - {file = "allure_pytest-2.14.1.tar.gz", hash = "sha256:f5a7469608044869243355ac1c1a97d373501a961076ac876ae29dbc6548920d"}, + {file = "allure_pytest-2.14.3-py3-none-any.whl", hash = "sha256:9704dea12f98991bc9e13be4ce9f90fe703beaff90e4741d67ae64c9815336c5"}, + {file = "allure_pytest-2.14.3.tar.gz", hash = "sha256:6d02a129867c7ef8b6943721d2be3141e3d1c3551741aff17b6afee64cd92b60"}, ] [package.dependencies] -allure-python-commons = "2.14.1" +allure-python-commons = "2.14.3" pytest = ">=4.5.0" [[package]] name = "allure-pytest-default-results" -version = "0.1.2" +version = "0.1.3" description = "Generate default \"unknown\" results to show in Allure Report if test case does not run" optional = false python-versions = ">=3.8" groups = ["integration"] files = [ - {file = "allure_pytest_default_results-0.1.2-py3-none-any.whl", hash = "sha256:8dc6c5a5d548661c38111a2890509e794204586fa81cefbe61315fb63996e50c"}, - {file = "allure_pytest_default_results-0.1.2.tar.gz", hash = "sha256:eb6c16aa1c2ede69e653a0ee38094791685eaacb0ac6b2cae5c6da1379dbdbfd"}, + {file = "allure_pytest_default_results-0.1.3-py3-none-any.whl", hash = "sha256:750de894d3713a3f890e62dbda3993b522cb52c4072651e12662e7df26d7dd4c"}, + {file = "allure_pytest_default_results-0.1.3.tar.gz", hash = "sha256:e9031d19bd7e799da289ab53a56ec5b4ca974e21fef1533f6626249a3c856725"}, ] [package.dependencies] @@ -34,14 +34,14 @@ pytest = "*" [[package]] name = "allure-python-commons" -version = "2.14.1" +version = "2.14.3" description = "Contains the API for end users as well as helper functions and classes to build Allure adapters for Python test frameworks" optional = false python-versions = ">=3.6" groups = ["integration"] files = [ - {file = "allure_python_commons-2.14.1-py3-none-any.whl", hash = "sha256:cf2bc5fef2c392b1782ee6956fce6641645517b453ff72a901acf20db3d37d36"}, - {file = "allure_python_commons-2.14.1.tar.gz", hash = "sha256:2a18f987c722810ff1cfc1509fad85fbdaabd695770804a1b4c93cf95d3cdd4e"}, + {file = "allure_python_commons-2.14.3-py3-none-any.whl", hash = "sha256:7bcf6a2eff69e6f0eacd8681e923f0a9dfbdd86cb8e20d8f93288057f9fb7cb1"}, + {file = "allure_python_commons-2.14.3.tar.gz", hash = "sha256:2dcaa87dd6b0b41902f60fe17e2653d3762788f3998ca4cf721dabfa8342aa07"}, ] [package.dependencies] @@ -233,34 +233,34 @@ typecheck = ["mypy"] [[package]] name = "boto3" -version = "1.38.4" +version = "1.38.33" description = "The AWS SDK for Python" optional = false python-versions = ">=3.9" groups = ["main", "integration"] files = [ - {file = "boto3-1.38.4-py3-none-any.whl", hash = "sha256:ab315d38409f5b3262b653a10b0fac786bcff7e51e03dcb99ff38ba16bf85630"}, - {file = "boto3-1.38.4.tar.gz", hash = "sha256:4990df0087fe7be944ba06c2d1e6512b5a24f821af5a4881f24309e13ae29e68"}, + {file = "boto3-1.38.33-py3-none-any.whl", hash = "sha256:25d0717489c658f7ae6c3c7f0f7e1b4d611b30b2f08f0fcef6455ac6864a8768"}, + {file = "boto3-1.38.33.tar.gz", hash = "sha256:6467909c1ae01ff67981f021bb2568592211765ec8a9a1d2c4529191e46c3541"}, ] [package.dependencies] -botocore = ">=1.38.4,<1.39.0" +botocore = ">=1.38.33,<1.39.0" jmespath = ">=0.7.1,<2.0.0" -s3transfer = ">=0.12.0,<0.13.0" +s3transfer = ">=0.13.0,<0.14.0" [package.extras] crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.38.4" +version = "1.38.33" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">=3.9" groups = ["main", "integration"] files = [ - {file = "botocore-1.38.4-py3-none-any.whl", hash = "sha256:6206cf07be1069efaead2ddc858eb752dafef276ebbe88ac32b5c427b1d90570"}, - {file = "botocore-1.38.4.tar.gz", hash = "sha256:6143546bb56f1da4dff8d285cb6a3b8b0b6442451fe5937cb48a62bf7275386f"}, + {file = "botocore-1.38.33-py3-none-any.whl", hash = "sha256:ad25233e93dcebe95809b1f9393c1f11a639696327793d166295fb78dd7bc597"}, + {file = "botocore-1.38.33.tar.gz", hash = "sha256:dbe8fea9d0426c644c89ef2018ead886ccbcc22901a02b377b4e65ce1cb69a2b"}, ] [package.dependencies] @@ -378,104 +378,104 @@ pycparser = "*" [[package]] name = "charset-normalizer" -version = "3.4.1" +version = "3.4.2" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7" groups = ["main", "charm-libs", "integration"] files = [ - {file = "charset_normalizer-3.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e218488cd232553829be0664c2292d3af2eeeb94b32bea483cf79ac6a694e037"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:80ed5e856eb7f30115aaf94e4a08114ccc8813e6ed1b5efa74f9f82e8509858f"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b010a7a4fd316c3c484d482922d13044979e78d1861f0e0650423144c616a46a"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4532bff1b8421fd0a320463030c7520f56a79c9024a4e88f01c537316019005a"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d973f03c0cb71c5ed99037b870f2be986c3c05e63622c017ea9816881d2dd247"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3a3bd0dcd373514dcec91c411ddb9632c0d7d92aed7093b8c3bbb6d69ca74408"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:d9c3cdf5390dcd29aa8056d13e8e99526cda0305acc038b96b30352aff5ff2bb"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2bdfe3ac2e1bbe5b59a1a63721eb3b95fc9b6817ae4a46debbb4e11f6232428d"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:eab677309cdb30d047996b36d34caeda1dc91149e4fdca0b1a039b3f79d9a807"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-win32.whl", hash = "sha256:c0429126cf75e16c4f0ad00ee0eae4242dc652290f940152ca8c75c3a4b6ee8f"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:9f0b8b1c6d84c8034a44893aba5e767bf9c7a211e313a9605d9c617d7083829f"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8bfa33f4f2672964266e940dd22a195989ba31669bd84629f05fab3ef4e2d125"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-win32.whl", hash = "sha256:8417cb1f36cc0bc7eaba8ccb0e04d55f0ee52df06df3ad55259b9a323555fc8b"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:d7f50a1f8c450f3925cb367d011448c39239bb3eb4117c36a6d354794de4ce76"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-win32.whl", hash = "sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-win32.whl", hash = "sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f30bf9fd9be89ecb2360c7d94a711f00c09b976258846efe40db3d05828e8089"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:97f68b8d6831127e4787ad15e6757232e14e12060bec17091b85eb1486b91d8d"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7974a0b5ecd505609e3b19742b60cee7aa2aa2fb3151bc917e6e2646d7667dcf"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc54db6c8593ef7d4b2a331b58653356cf04f67c960f584edb7c3d8c97e8f39e"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:311f30128d7d333eebd7896965bfcfbd0065f1716ec92bd5638d7748eb6f936a"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:7d053096f67cd1241601111b698f5cad775f97ab25d81567d3f59219b5f1adbd"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:807f52c1f798eef6cf26beb819eeb8819b1622ddfeef9d0977a8502d4db6d534"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:dccbe65bd2f7f7ec22c4ff99ed56faa1e9f785482b9bbd7c717e26fd723a1d1e"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:2fb9bd477fdea8684f78791a6de97a953c51831ee2981f8e4f583ff3b9d9687e"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:01732659ba9b5b873fc117534143e4feefecf3b2078b0a6a2e925271bb6f4cfa"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-win32.whl", hash = "sha256:7a4f97a081603d2050bfaffdefa5b02a9ec823f8348a572e39032caa8404a487"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:7b1bef6280950ee6c177b326508f86cad7ad4dff12454483b51d8b7d673a2c5d"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ecddf25bee22fe4fe3737a399d0d177d72bc22be6913acfab364b40bce1ba83c"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c60ca7339acd497a55b0ea5d506b2a2612afb2826560416f6894e8b5770d4a9"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b7b2d86dd06bfc2ade3312a83a5c364c7ec2e3498f8734282c6c3d4b07b346b8"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dd78cfcda14a1ef52584dbb008f7ac81c1328c0f58184bf9a84c49c605002da6"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e27f48bcd0957c6d4cb9d6fa6b61d192d0b13d5ef563e5f2ae35feafc0d179c"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01ad647cdd609225c5350561d084b42ddf732f4eeefe6e678765636791e78b9a"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:619a609aa74ae43d90ed2e89bdd784765de0a25ca761b93e196d938b8fd1dbbd"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:89149166622f4db9b4b6a449256291dc87a99ee53151c74cbd82a53c8c2f6ccd"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:7709f51f5f7c853f0fb938bcd3bc59cdfdc5203635ffd18bf354f6967ea0f824"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:345b0426edd4e18138d6528aed636de7a9ed169b4aaf9d61a8c19e39d26838ca"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0907f11d019260cdc3f94fbdb23ff9125f6b5d1039b76003b5b0ac9d6a6c9d5b"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-win32.whl", hash = "sha256:ea0d8d539afa5eb2728aa1932a988a9a7af94f18582ffae4bc10b3fbdad0626e"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:329ce159e82018d646c7ac45b01a430369d526569ec08516081727a20e9e4af4"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b97e690a2118911e39b4042088092771b4ae3fc3aa86518f84b8cf6888dbdb41"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78baa6d91634dfb69ec52a463534bc0df05dbd546209b79a3880a34487f4b84f"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1a2bc9f351a75ef49d664206d51f8e5ede9da246602dc2d2726837620ea034b2"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75832c08354f595c760a804588b9357d34ec00ba1c940c15e31e96d902093770"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0af291f4fe114be0280cdd29d533696a77b5b49cfde5467176ecab32353395c4"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0167ddc8ab6508fe81860a57dd472b2ef4060e8d378f0cc555707126830f2537"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2a75d49014d118e4198bcee5ee0a6f25856b29b12dbf7cd012791f8a6cc5c496"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:363e2f92b0f0174b2f8238240a1a30142e3db7b957a5dd5689b0e75fb717cc78"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ab36c8eb7e454e34e60eb55ca5d241a5d18b2c6244f6827a30e451c42410b5f7"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:4c0907b1928a36d5a998d72d64d8eaa7244989f7aaaf947500d3a800c83a3fd6"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:04432ad9479fa40ec0f387795ddad4437a2b50417c69fa275e212933519ff294"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-win32.whl", hash = "sha256:3bed14e9c89dcb10e8f3a29f9ccac4955aebe93c71ae803af79265c9ca5644c5"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:49402233c892a461407c512a19435d1ce275543138294f7ef013f0b63d5d3765"}, - {file = "charset_normalizer-3.4.1-py3-none-any.whl", hash = "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85"}, - {file = "charset_normalizer-3.4.1.tar.gz", hash = "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c48ed483eb946e6c04ccbe02c6b4d1d48e51944b6db70f697e089c193404941"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2d318c11350e10662026ad0eb71bb51c7812fc8590825304ae0bdd4ac283acd"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9cbfacf36cb0ec2897ce0ebc5d08ca44213af24265bd56eca54bee7923c48fd6"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18dd2e350387c87dabe711b86f83c9c78af772c748904d372ade190b5c7c9d4d"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8075c35cd58273fee266c58c0c9b670947c19df5fb98e7b66710e04ad4e9ff86"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5bf4545e3b962767e5c06fe1738f951f77d27967cb2caa64c28be7c4563e162c"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7a6ab32f7210554a96cd9e33abe3ddd86732beeafc7a28e9955cdf22ffadbab0"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:b33de11b92e9f75a2b545d6e9b6f37e398d86c3e9e9653c4864eb7e89c5773ef"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8755483f3c00d6c9a77f490c17e6ab0c8729e39e6390328e42521ef175380ae6"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:68a328e5f55ec37c57f19ebb1fdc56a248db2e3e9ad769919a58672958e8f366"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:21b2899062867b0e1fde9b724f8aecb1af14f2778d69aacd1a5a1853a597a5db"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-win32.whl", hash = "sha256:e8082b26888e2f8b36a042a58307d5b917ef2b1cacab921ad3323ef91901c71a"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:f69a27e45c43520f5487f27627059b64aaf160415589230992cec34c5e18a509"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:be1e352acbe3c78727a16a455126d9ff83ea2dfdcbc83148d2982305a04714c2"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa88ca0b1932e93f2d961bf3addbb2db902198dca337d88c89e1559e066e7645"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d524ba3f1581b35c03cb42beebab4a13e6cdad7b36246bd22541fa585a56cccd"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28a1005facc94196e1fb3e82a3d442a9d9110b8434fc1ded7a24a2983c9888d8"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fdb20a30fe1175ecabed17cbf7812f7b804b8a315a25f24678bcdf120a90077f"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f5d9ed7f254402c9e7d35d2f5972c9bbea9040e99cd2861bd77dc68263277c7"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:efd387a49825780ff861998cd959767800d54f8308936b21025326de4b5a42b9"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f0aa37f3c979cf2546b73e8222bbfa3dc07a641585340179d768068e3455e544"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e70e990b2137b29dc5564715de1e12701815dacc1d056308e2b17e9095372a82"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0c8c57f84ccfc871a48a47321cfa49ae1df56cd1d965a09abe84066f6853b9c0"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6b66f92b17849b85cad91259efc341dce9c1af48e2173bf38a85c6329f1033e5"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-win32.whl", hash = "sha256:daac4765328a919a805fa5e2720f3e94767abd632ae410a9062dff5412bae65a"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:e53efc7c7cee4c1e70661e2e112ca46a575f90ed9ae3fef200f2a25e954f4b28"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0c29de6a1a95f24b9a1aa7aefd27d2487263f00dfd55a77719b530788f75cff7"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cddf7bd982eaa998934a91f69d182aec997c6c468898efe6679af88283b498d3"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcbe676a55d7445b22c10967bceaaf0ee69407fbe0ece4d032b6eb8d4565982a"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d41c4d287cfc69060fa91cae9683eacffad989f1a10811995fa309df656ec214"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e594135de17ab3866138f496755f302b72157d115086d100c3f19370839dd3a"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf713fe9a71ef6fd5adf7a79670135081cd4431c2943864757f0fa3a65b1fafd"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a370b3e078e418187da8c3674eddb9d983ec09445c99a3a263c2011993522981"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a955b438e62efdf7e0b7b52a64dc5c3396e2634baa62471768a64bc2adb73d5c"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7222ffd5e4de8e57e03ce2cef95a4c43c98fcb72ad86909abdfc2c17d227fc1b"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:bee093bf902e1d8fc0ac143c88902c3dfc8941f7ea1d6a8dd2bcb786d33db03d"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dedb8adb91d11846ee08bec4c8236c8549ac721c245678282dcb06b221aab59f"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-win32.whl", hash = "sha256:db4c7bf0e07fc3b7d89ac2a5880a6a8062056801b83ff56d8464b70f65482b6c"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:5a9979887252a82fefd3d3ed2a8e3b937a7a809f65dcb1e068b090e165bbe99e"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:926ca93accd5d36ccdabd803392ddc3e03e6d4cd1cf17deff3b989ab8e9dbcf0"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eba9904b0f38a143592d9fc0e19e2df0fa2e41c3c3745554761c5f6447eedabf"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3fddb7e2c84ac87ac3a947cb4e66d143ca5863ef48e4a5ecb83bd48619e4634e"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98f862da73774290f251b9df8d11161b6cf25b599a66baf087c1ffe340e9bfd1"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c9379d65defcab82d07b2a9dfbfc2e95bc8fe0ebb1b176a3190230a3ef0e07c"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e635b87f01ebc977342e2697d05b56632f5f879a4f15955dfe8cef2448b51691"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1c95a1e2902a8b722868587c0e1184ad5c55631de5afc0eb96bc4b0d738092c0"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ef8de666d6179b009dce7bcb2ad4c4a779f113f12caf8dc77f0162c29d20490b"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:32fc0341d72e0f73f80acb0a2c94216bd704f4f0bce10aedea38f30502b271ff"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:289200a18fa698949d2b39c671c2cc7a24d44096784e76614899a7ccf2574b7b"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a476b06fbcf359ad25d34a057b7219281286ae2477cc5ff5e3f70a246971148"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-win32.whl", hash = "sha256:aaeeb6a479c7667fbe1099af9617c83aaca22182d6cf8c53966491a0f1b7ffb7"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cad5f45b3146325bb38d6855642f6fd609c3f7cad4dbaf75549bf3b904d3184"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b2680962a4848b3c4f155dc2ee64505a9c57186d0d56b43123b17ca3de18f0fa"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:36b31da18b8890a76ec181c3cf44326bf2c48e36d393ca1b72b3f484113ea344"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f4074c5a429281bf056ddd4c5d3b740ebca4d43ffffe2ef4bf4d2d05114299da"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c9e36a97bee9b86ef9a1cf7bb96747eb7a15c2f22bdb5b516434b00f2a599f02"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:1b1bde144d98e446b056ef98e59c256e9294f6b74d7af6846bf5ffdafd687a7d"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:915f3849a011c1f593ab99092f3cecfcb4d65d8feb4a64cf1bf2d22074dc0ec4"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:fb707f3e15060adf5b7ada797624a6c6e0138e2a26baa089df64c68ee98e040f"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:25a23ea5c7edc53e0f29bae2c44fcb5a1aa10591aae107f2a2b2583a9c5cbc64"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:770cab594ecf99ae64c236bc9ee3439c3f46be49796e265ce0cc8bc17b10294f"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-win32.whl", hash = "sha256:6a0289e4589e8bdfef02a80478f1dfcb14f0ab696b5a00e1f4b8a14a307a3c58"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6fc1f5b51fa4cecaa18f2bd7a003f3dd039dd615cd69a2afd6d3b19aed6775f2"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:76af085e67e56c8816c3ccf256ebd136def2ed9654525348cfa744b6802b69eb"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e45ba65510e2647721e35323d6ef54c7974959f6081b58d4ef5d87c60c84919a"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:046595208aae0120559a67693ecc65dd75d46f7bf687f159127046628178dc45"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75d10d37a47afee94919c4fab4c22b9bc2a8bf7d4f46f87363bcf0573f3ff4f5"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6333b3aa5a12c26b2a4d4e7335a28f1475e0e5e17d69d55141ee3cab736f66d1"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e8323a9b031aa0393768b87f04b4164a40037fb2a3c11ac06a03ffecd3618027"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:24498ba8ed6c2e0b56d4acbf83f2d989720a93b41d712ebd4f4979660db4417b"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:844da2b5728b5ce0e32d863af26f32b5ce61bc4273a9c720a9f3aa9df73b1455"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:65c981bdbd3f57670af8b59777cbfae75364b483fa8a9f420f08094531d54a01"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:3c21d4fca343c805a52c0c78edc01e3477f6dd1ad7c47653241cf2a206d4fc58"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:dc7039885fa1baf9be153a0626e337aa7ec8bf96b0128605fb0d77788ddc1681"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-win32.whl", hash = "sha256:8272b73e1c5603666618805fe821edba66892e2870058c94c53147602eab29c7"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:70f7172939fdf8790425ba31915bfbe8335030f05b9913d7ae00a87d4395620a"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:005fa3432484527f9732ebd315da8da8001593e2cf46a3d817669f062c3d9ed4"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e92fca20c46e9f5e1bb485887d074918b13543b1c2a1185e69bb8d17ab6236a7"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:50bf98d5e563b83cc29471fa114366e6806bc06bc7a25fd59641e41445327836"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:721c76e84fe669be19c5791da68232ca2e05ba5185575086e384352e2c309597"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82d8fd25b7f4675d0c47cf95b594d4e7b158aca33b76aa63d07186e13c0e0ab7"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3daeac64d5b371dea99714f08ffc2c208522ec6b06fbc7866a450dd446f5c0f"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dccab8d5fa1ef9bfba0590ecf4d46df048d18ffe3eec01eeb73a42e0d9e7a8ba"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:aaf27faa992bfee0264dc1f03f4c75e9fcdda66a519db6b957a3f826e285cf12"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:eb30abc20df9ab0814b5a2524f23d75dcf83cde762c161917a2b4b7b55b1e518"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:c72fbbe68c6f32f251bdc08b8611c7b3060612236e960ef848e0a517ddbe76c5"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:982bb1e8b4ffda883b3d0a521e23abcd6fd17418f6d2c4118d257a10199c0ce3"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-win32.whl", hash = "sha256:43e0933a0eff183ee85833f341ec567c0980dae57c464d8a508e1b2ceb336471"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:d11b54acf878eef558599658b0ffca78138c8c3655cf4f3a4a673c437e67732e"}, + {file = "charset_normalizer-3.4.2-py3-none-any.whl", hash = "sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0"}, + {file = "charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63"}, ] [[package]] @@ -530,75 +530,79 @@ typing-extensions = "*" [[package]] name = "coverage" -version = "7.8.0" +version = "7.8.2" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.9" groups = ["unit"] files = [ - {file = "coverage-7.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2931f66991175369859b5fd58529cd4b73582461877ecfd859b6549869287ffe"}, - {file = "coverage-7.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:52a523153c568d2c0ef8826f6cc23031dc86cffb8c6aeab92c4ff776e7951b28"}, - {file = "coverage-7.8.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c8a5c139aae4c35cbd7cadca1df02ea8cf28a911534fc1b0456acb0b14234f3"}, - {file = "coverage-7.8.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5a26c0c795c3e0b63ec7da6efded5f0bc856d7c0b24b2ac84b4d1d7bc578d676"}, - {file = "coverage-7.8.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:821f7bcbaa84318287115d54becb1915eece6918136c6f91045bb84e2f88739d"}, - {file = "coverage-7.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a321c61477ff8ee705b8a5fed370b5710c56b3a52d17b983d9215861e37b642a"}, - {file = "coverage-7.8.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:ed2144b8a78f9d94d9515963ed273d620e07846acd5d4b0a642d4849e8d91a0c"}, - {file = "coverage-7.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:042e7841a26498fff7a37d6fda770d17519982f5b7d8bf5278d140b67b61095f"}, - {file = "coverage-7.8.0-cp310-cp310-win32.whl", hash = "sha256:f9983d01d7705b2d1f7a95e10bbe4091fabc03a46881a256c2787637b087003f"}, - {file = "coverage-7.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:5a570cd9bd20b85d1a0d7b009aaf6c110b52b5755c17be6962f8ccd65d1dbd23"}, - {file = "coverage-7.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e7ac22a0bb2c7c49f441f7a6d46c9c80d96e56f5a8bc6972529ed43c8b694e27"}, - {file = "coverage-7.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bf13d564d310c156d1c8e53877baf2993fb3073b2fc9f69790ca6a732eb4bfea"}, - {file = "coverage-7.8.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5761c70c017c1b0d21b0815a920ffb94a670c8d5d409d9b38857874c21f70d7"}, - {file = "coverage-7.8.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5ff52d790c7e1628241ffbcaeb33e07d14b007b6eb00a19320c7b8a7024c040"}, - {file = "coverage-7.8.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d39fc4817fd67b3915256af5dda75fd4ee10621a3d484524487e33416c6f3543"}, - {file = "coverage-7.8.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b44674870709017e4b4036e3d0d6c17f06a0e6d4436422e0ad29b882c40697d2"}, - {file = "coverage-7.8.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8f99eb72bf27cbb167b636eb1726f590c00e1ad375002230607a844d9e9a2318"}, - {file = "coverage-7.8.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b571bf5341ba8c6bc02e0baeaf3b061ab993bf372d982ae509807e7f112554e9"}, - {file = "coverage-7.8.0-cp311-cp311-win32.whl", hash = "sha256:e75a2ad7b647fd8046d58c3132d7eaf31b12d8a53c0e4b21fa9c4d23d6ee6d3c"}, - {file = "coverage-7.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:3043ba1c88b2139126fc72cb48574b90e2e0546d4c78b5299317f61b7f718b78"}, - {file = "coverage-7.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:bbb5cc845a0292e0c520656d19d7ce40e18d0e19b22cb3e0409135a575bf79fc"}, - {file = "coverage-7.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4dfd9a93db9e78666d178d4f08a5408aa3f2474ad4d0e0378ed5f2ef71640cb6"}, - {file = "coverage-7.8.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f017a61399f13aa6d1039f75cd467be388d157cd81f1a119b9d9a68ba6f2830d"}, - {file = "coverage-7.8.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0915742f4c82208ebf47a2b154a5334155ed9ef9fe6190674b8a46c2fb89cb05"}, - {file = "coverage-7.8.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a40fcf208e021eb14b0fac6bdb045c0e0cab53105f93ba0d03fd934c956143a"}, - {file = "coverage-7.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a1f406a8e0995d654b2ad87c62caf6befa767885301f3b8f6f73e6f3c31ec3a6"}, - {file = "coverage-7.8.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:77af0f6447a582fdc7de5e06fa3757a3ef87769fbb0fdbdeba78c23049140a47"}, - {file = "coverage-7.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f2d32f95922927186c6dbc8bc60df0d186b6edb828d299ab10898ef3f40052fe"}, - {file = "coverage-7.8.0-cp312-cp312-win32.whl", hash = "sha256:769773614e676f9d8e8a0980dd7740f09a6ea386d0f383db6821df07d0f08545"}, - {file = "coverage-7.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:e5d2b9be5b0693cf21eb4ce0ec8d211efb43966f6657807f6859aab3814f946b"}, - {file = "coverage-7.8.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5ac46d0c2dd5820ce93943a501ac5f6548ea81594777ca585bf002aa8854cacd"}, - {file = "coverage-7.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:771eb7587a0563ca5bb6f622b9ed7f9d07bd08900f7589b4febff05f469bea00"}, - {file = "coverage-7.8.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42421e04069fb2cbcbca5a696c4050b84a43b05392679d4068acbe65449b5c64"}, - {file = "coverage-7.8.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:554fec1199d93ab30adaa751db68acec2b41c5602ac944bb19187cb9a41a8067"}, - {file = "coverage-7.8.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5aaeb00761f985007b38cf463b1d160a14a22c34eb3f6a39d9ad6fc27cb73008"}, - {file = "coverage-7.8.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:581a40c7b94921fffd6457ffe532259813fc68eb2bdda60fa8cc343414ce3733"}, - {file = "coverage-7.8.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f319bae0321bc838e205bf9e5bc28f0a3165f30c203b610f17ab5552cff90323"}, - {file = "coverage-7.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:04bfec25a8ef1c5f41f5e7e5c842f6b615599ca8ba8391ec33a9290d9d2db3a3"}, - {file = "coverage-7.8.0-cp313-cp313-win32.whl", hash = "sha256:dd19608788b50eed889e13a5d71d832edc34fc9dfce606f66e8f9f917eef910d"}, - {file = "coverage-7.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:a9abbccd778d98e9c7e85038e35e91e67f5b520776781d9a1e2ee9d400869487"}, - {file = "coverage-7.8.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:18c5ae6d061ad5b3e7eef4363fb27a0576012a7447af48be6c75b88494c6cf25"}, - {file = "coverage-7.8.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:95aa6ae391a22bbbce1b77ddac846c98c5473de0372ba5c463480043a07bff42"}, - {file = "coverage-7.8.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e013b07ba1c748dacc2a80e69a46286ff145935f260eb8c72df7185bf048f502"}, - {file = "coverage-7.8.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d766a4f0e5aa1ba056ec3496243150698dc0481902e2b8559314368717be82b1"}, - {file = "coverage-7.8.0-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad80e6b4a0c3cb6f10f29ae4c60e991f424e6b14219d46f1e7d442b938ee68a4"}, - {file = "coverage-7.8.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b87eb6fc9e1bb8f98892a2458781348fa37e6925f35bb6ceb9d4afd54ba36c73"}, - {file = "coverage-7.8.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:d1ba00ae33be84066cfbe7361d4e04dec78445b2b88bdb734d0d1cbab916025a"}, - {file = "coverage-7.8.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f3c38e4e5ccbdc9198aecc766cedbb134b2d89bf64533973678dfcf07effd883"}, - {file = "coverage-7.8.0-cp313-cp313t-win32.whl", hash = "sha256:379fe315e206b14e21db5240f89dc0774bdd3e25c3c58c2c733c99eca96f1ada"}, - {file = "coverage-7.8.0-cp313-cp313t-win_amd64.whl", hash = "sha256:2e4b6b87bb0c846a9315e3ab4be2d52fac905100565f4b92f02c445c8799e257"}, - {file = "coverage-7.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fa260de59dfb143af06dcf30c2be0b200bed2a73737a8a59248fcb9fa601ef0f"}, - {file = "coverage-7.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:96121edfa4c2dfdda409877ea8608dd01de816a4dc4a0523356067b305e4e17a"}, - {file = "coverage-7.8.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b8af63b9afa1031c0ef05b217faa598f3069148eeee6bb24b79da9012423b82"}, - {file = "coverage-7.8.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:89b1f4af0d4afe495cd4787a68e00f30f1d15939f550e869de90a86efa7e0814"}, - {file = "coverage-7.8.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94ec0be97723ae72d63d3aa41961a0b9a6f5a53ff599813c324548d18e3b9e8c"}, - {file = "coverage-7.8.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:8a1d96e780bdb2d0cbb297325711701f7c0b6f89199a57f2049e90064c29f6bd"}, - {file = "coverage-7.8.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:f1d8a2a57b47142b10374902777e798784abf400a004b14f1b0b9eaf1e528ba4"}, - {file = "coverage-7.8.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:cf60dd2696b457b710dd40bf17ad269d5f5457b96442f7f85722bdb16fa6c899"}, - {file = "coverage-7.8.0-cp39-cp39-win32.whl", hash = "sha256:be945402e03de47ba1872cd5236395e0f4ad635526185a930735f66710e1bd3f"}, - {file = "coverage-7.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:90e7fbc6216ecaffa5a880cdc9c77b7418c1dcb166166b78dbc630d07f278cc3"}, - {file = "coverage-7.8.0-pp39.pp310.pp311-none-any.whl", hash = "sha256:b8194fb8e50d556d5849753de991d390c5a1edeeba50f68e3a9253fbd8bf8ccd"}, - {file = "coverage-7.8.0-py3-none-any.whl", hash = "sha256:dbf364b4c5e7bae9250528167dfe40219b62e2d573c854d74be213e1e52069f7"}, - {file = "coverage-7.8.0.tar.gz", hash = "sha256:7a3d62b3b03b4b6fd41a085f3574874cf946cb4604d2b4d3e8dca8cd570ca501"}, + {file = "coverage-7.8.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bd8ec21e1443fd7a447881332f7ce9d35b8fbd2849e761bb290b584535636b0a"}, + {file = "coverage-7.8.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4c26c2396674816deaeae7ded0e2b42c26537280f8fe313335858ffff35019be"}, + {file = "coverage-7.8.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1aec326ed237e5880bfe69ad41616d333712c7937bcefc1343145e972938f9b3"}, + {file = "coverage-7.8.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5e818796f71702d7a13e50c70de2a1924f729228580bcba1607cccf32eea46e6"}, + {file = "coverage-7.8.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:546e537d9e24efc765c9c891328f30f826e3e4808e31f5d0f87c4ba12bbd1622"}, + {file = "coverage-7.8.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ab9b09a2349f58e73f8ebc06fac546dd623e23b063e5398343c5270072e3201c"}, + {file = "coverage-7.8.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fd51355ab8a372d89fb0e6a31719e825cf8df8b6724bee942fb5b92c3f016ba3"}, + {file = "coverage-7.8.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0774df1e093acb6c9e4d58bce7f86656aeed6c132a16e2337692c12786b32404"}, + {file = "coverage-7.8.2-cp310-cp310-win32.whl", hash = "sha256:00f2e2f2e37f47e5f54423aeefd6c32a7dbcedc033fcd3928a4f4948e8b96af7"}, + {file = "coverage-7.8.2-cp310-cp310-win_amd64.whl", hash = "sha256:145b07bea229821d51811bf15eeab346c236d523838eda395ea969d120d13347"}, + {file = "coverage-7.8.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b99058eef42e6a8dcd135afb068b3d53aff3921ce699e127602efff9956457a9"}, + {file = "coverage-7.8.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5feb7f2c3e6ea94d3b877def0270dff0947b8d8c04cfa34a17be0a4dc1836879"}, + {file = "coverage-7.8.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:670a13249b957bb9050fab12d86acef7bf8f6a879b9d1a883799276e0d4c674a"}, + {file = "coverage-7.8.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0bdc8bf760459a4a4187b452213e04d039990211f98644c7292adf1e471162b5"}, + {file = "coverage-7.8.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07a989c867986c2a75f158f03fdb413128aad29aca9d4dbce5fc755672d96f11"}, + {file = "coverage-7.8.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2db10dedeb619a771ef0e2949ccba7b75e33905de959c2643a4607bef2f3fb3a"}, + {file = "coverage-7.8.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e6ea7dba4e92926b7b5f0990634b78ea02f208d04af520c73a7c876d5a8d36cb"}, + {file = "coverage-7.8.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ef2f22795a7aca99fc3c84393a55a53dd18ab8c93fb431004e4d8f0774150f54"}, + {file = "coverage-7.8.2-cp311-cp311-win32.whl", hash = "sha256:641988828bc18a6368fe72355df5f1703e44411adbe49bba5644b941ce6f2e3a"}, + {file = "coverage-7.8.2-cp311-cp311-win_amd64.whl", hash = "sha256:8ab4a51cb39dc1933ba627e0875046d150e88478dbe22ce145a68393e9652975"}, + {file = "coverage-7.8.2-cp311-cp311-win_arm64.whl", hash = "sha256:8966a821e2083c74d88cca5b7dcccc0a3a888a596a04c0b9668a891de3a0cc53"}, + {file = "coverage-7.8.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e2f6fe3654468d061942591aef56686131335b7a8325684eda85dacdf311356c"}, + {file = "coverage-7.8.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:76090fab50610798cc05241bf83b603477c40ee87acd358b66196ab0ca44ffa1"}, + {file = "coverage-7.8.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2bd0a0a5054be160777a7920b731a0570284db5142abaaf81bcbb282b8d99279"}, + {file = "coverage-7.8.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:da23ce9a3d356d0affe9c7036030b5c8f14556bd970c9b224f9c8205505e3b99"}, + {file = "coverage-7.8.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9392773cffeb8d7e042a7b15b82a414011e9d2b5fdbbd3f7e6a6b17d5e21b20"}, + {file = "coverage-7.8.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:876cbfd0b09ce09d81585d266c07a32657beb3eaec896f39484b631555be0fe2"}, + {file = "coverage-7.8.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3da9b771c98977a13fbc3830f6caa85cae6c9c83911d24cb2d218e9394259c57"}, + {file = "coverage-7.8.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9a990f6510b3292686713bfef26d0049cd63b9c7bb17e0864f133cbfd2e6167f"}, + {file = "coverage-7.8.2-cp312-cp312-win32.whl", hash = "sha256:bf8111cddd0f2b54d34e96613e7fbdd59a673f0cf5574b61134ae75b6f5a33b8"}, + {file = "coverage-7.8.2-cp312-cp312-win_amd64.whl", hash = "sha256:86a323a275e9e44cdf228af9b71c5030861d4d2610886ab920d9945672a81223"}, + {file = "coverage-7.8.2-cp312-cp312-win_arm64.whl", hash = "sha256:820157de3a589e992689ffcda8639fbabb313b323d26388d02e154164c57b07f"}, + {file = "coverage-7.8.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ea561010914ec1c26ab4188aef8b1567272ef6de096312716f90e5baa79ef8ca"}, + {file = "coverage-7.8.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cb86337a4fcdd0e598ff2caeb513ac604d2f3da6d53df2c8e368e07ee38e277d"}, + {file = "coverage-7.8.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26a4636ddb666971345541b59899e969f3b301143dd86b0ddbb570bd591f1e85"}, + {file = "coverage-7.8.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5040536cf9b13fb033f76bcb5e1e5cb3b57c4807fef37db9e0ed129c6a094257"}, + {file = "coverage-7.8.2-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc67994df9bcd7e0150a47ef41278b9e0a0ea187caba72414b71dc590b99a108"}, + {file = "coverage-7.8.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6e6c86888fd076d9e0fe848af0a2142bf606044dc5ceee0aa9eddb56e26895a0"}, + {file = "coverage-7.8.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:684ca9f58119b8e26bef860db33524ae0365601492e86ba0b71d513f525e7050"}, + {file = "coverage-7.8.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8165584ddedb49204c4e18da083913bdf6a982bfb558632a79bdaadcdafd0d48"}, + {file = "coverage-7.8.2-cp313-cp313-win32.whl", hash = "sha256:34759ee2c65362163699cc917bdb2a54114dd06d19bab860725f94ef45a3d9b7"}, + {file = "coverage-7.8.2-cp313-cp313-win_amd64.whl", hash = "sha256:2f9bc608fbafaee40eb60a9a53dbfb90f53cc66d3d32c2849dc27cf5638a21e3"}, + {file = "coverage-7.8.2-cp313-cp313-win_arm64.whl", hash = "sha256:9fe449ee461a3b0c7105690419d0b0aba1232f4ff6d120a9e241e58a556733f7"}, + {file = "coverage-7.8.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:8369a7c8ef66bded2b6484053749ff220dbf83cba84f3398c84c51a6f748a008"}, + {file = "coverage-7.8.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:159b81df53a5fcbc7d45dae3adad554fdbde9829a994e15227b3f9d816d00b36"}, + {file = "coverage-7.8.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e6fcbbd35a96192d042c691c9e0c49ef54bd7ed865846a3c9d624c30bb67ce46"}, + {file = "coverage-7.8.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:05364b9cc82f138cc86128dc4e2e1251c2981a2218bfcd556fe6b0fbaa3501be"}, + {file = "coverage-7.8.2-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46d532db4e5ff3979ce47d18e2fe8ecad283eeb7367726da0e5ef88e4fe64740"}, + {file = "coverage-7.8.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4000a31c34932e7e4fa0381a3d6deb43dc0c8f458e3e7ea6502e6238e10be625"}, + {file = "coverage-7.8.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:43ff5033d657cd51f83015c3b7a443287250dc14e69910577c3e03bd2e06f27b"}, + {file = "coverage-7.8.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:94316e13f0981cbbba132c1f9f365cac1d26716aaac130866ca812006f662199"}, + {file = "coverage-7.8.2-cp313-cp313t-win32.whl", hash = "sha256:3f5673888d3676d0a745c3d0e16da338c5eea300cb1f4ada9c872981265e76d8"}, + {file = "coverage-7.8.2-cp313-cp313t-win_amd64.whl", hash = "sha256:2c08b05ee8d7861e45dc5a2cc4195c8c66dca5ac613144eb6ebeaff2d502e73d"}, + {file = "coverage-7.8.2-cp313-cp313t-win_arm64.whl", hash = "sha256:1e1448bb72b387755e1ff3ef1268a06617afd94188164960dba8d0245a46004b"}, + {file = "coverage-7.8.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:496948261eaac5ac9cf43f5d0a9f6eb7a6d4cb3bedb2c5d294138142f5c18f2a"}, + {file = "coverage-7.8.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:eacd2de0d30871eff893bab0b67840a96445edcb3c8fd915e6b11ac4b2f3fa6d"}, + {file = "coverage-7.8.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b039ffddc99ad65d5078ef300e0c7eed08c270dc26570440e3ef18beb816c1ca"}, + {file = "coverage-7.8.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0e49824808d4375ede9dd84e9961a59c47f9113039f1a525e6be170aa4f5c34d"}, + {file = "coverage-7.8.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b069938961dfad881dc2f8d02b47645cd2f455d3809ba92a8a687bf513839787"}, + {file = "coverage-7.8.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:de77c3ba8bb686d1c411e78ee1b97e6e0b963fb98b1637658dd9ad2c875cf9d7"}, + {file = "coverage-7.8.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1676628065a498943bd3f64f099bb573e08cf1bc6088bbe33cf4424e0876f4b3"}, + {file = "coverage-7.8.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:8e1a26e7e50076e35f7afafde570ca2b4d7900a491174ca357d29dece5aacee7"}, + {file = "coverage-7.8.2-cp39-cp39-win32.whl", hash = "sha256:6782a12bf76fa61ad9350d5a6ef5f3f020b57f5e6305cbc663803f2ebd0f270a"}, + {file = "coverage-7.8.2-cp39-cp39-win_amd64.whl", hash = "sha256:1efa4166ba75ccefd647f2d78b64f53f14fb82622bc94c5a5cb0a622f50f1c9e"}, + {file = "coverage-7.8.2-pp39.pp310.pp311-none-any.whl", hash = "sha256:ec455eedf3ba0bbdf8f5a570012617eb305c63cb9f03428d39bf544cb2b94837"}, + {file = "coverage-7.8.2-py3-none-any.whl", hash = "sha256:726f32ee3713f7359696331a18daf0c3b3a70bb0ae71141b9d3c52be7c595e32"}, + {file = "coverage-7.8.2.tar.gz", hash = "sha256:a886d531373a1f6ff9fad2a2ba4a045b68467b779ae729ee0b3b10ac20033b27"}, ] [package.dependencies] @@ -685,7 +689,7 @@ version = "1.2.18" description = "Python @deprecated decorator to deprecate old python classes, functions or methods." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" -groups = ["charm-libs"] +groups = ["main", "charm-libs"] files = [ {file = "Deprecated-1.2.18-py2.py3-none-any.whl", hash = "sha256:bd5011788200372a32418f888e326a09ff80d0214bd961147cfed01b5c018eec"}, {file = "deprecated-1.2.18.tar.gz", hash = "sha256:422b6f6d859da6f2ef57857761bfb392480502a64c3028ca9bbe86085d72115d"}, @@ -699,17 +703,20 @@ dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "setuptools ; python_version [[package]] name = "exceptiongroup" -version = "1.2.2" +version = "1.3.0" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" groups = ["integration", "unit"] markers = "python_version < \"3.11\"" files = [ - {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, - {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, + {file = "exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10"}, + {file = "exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88"}, ] +[package.dependencies] +typing-extensions = {version = ">=4.6.0", markers = "python_version < \"3.13\""} + [package.extras] test = ["pytest (>=6)"] @@ -730,14 +737,14 @@ tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipyth [[package]] name = "google-auth" -version = "2.39.0" +version = "2.40.3" description = "Google Authentication Library" optional = false python-versions = ">=3.7" groups = ["integration"] files = [ - {file = "google_auth-2.39.0-py2.py3-none-any.whl", hash = "sha256:0150b6711e97fb9f52fe599f55648950cc4540015565d8fbb31be2ad6e1548a2"}, - {file = "google_auth-2.39.0.tar.gz", hash = "sha256:73222d43cdc35a3aeacbfdcaf73142a97839f10de930550d89ebfe1d0a00cde7"}, + {file = "google_auth-2.40.3-py2.py3-none-any.whl", hash = "sha256:1370d4593e86213563547f97a92752fc658456fe4514c809544f330fed45a7ca"}, + {file = "google_auth-2.40.3.tar.gz", hash = "sha256:500c3a29adedeb36ea9cf24b8d10858e152f2412e3ca37829b3fa18e33d63b77"}, ] [package.dependencies] @@ -812,7 +819,7 @@ version = "6.11.0" description = "Read metadata from Python packages" optional = false python-versions = ">=3.8" -groups = ["charm-libs"] +groups = ["main", "charm-libs"] files = [ {file = "importlib_metadata-6.11.0-py3-none-any.whl", hash = "sha256:f0afba6205ad8f8947c7d338b5342d5db2afbfd82f9cbef7879a9539cc12eb9b"}, {file = "importlib_metadata-6.11.0.tar.gz", hash = "sha256:1231cf92d825c9e03cfc4da076a16de6422c863558229ea0b22b675657463443"}, @@ -857,14 +864,14 @@ tomli = {version = "*", markers = "python_version > \"3.6\" and python_version < [[package]] name = "ipython" -version = "8.36.0" +version = "8.37.0" description = "IPython: Productive Interactive Computing" optional = false python-versions = ">=3.10" groups = ["integration"] files = [ - {file = "ipython-8.36.0-py3-none-any.whl", hash = "sha256:12b913914d010dcffa2711505ec8be4bf0180742d97f1e5175e51f22086428c1"}, - {file = "ipython-8.36.0.tar.gz", hash = "sha256:24658e9fe5c5c819455043235ba59cfffded4a35936eefceceab6b192f7092ff"}, + {file = "ipython-8.37.0-py3-none-any.whl", hash = "sha256:ed87326596b878932dbcb171e3e698845434d8c61b8d8cd474bf663041a9dcf2"}, + {file = "ipython-8.37.0.tar.gz", hash = "sha256:ca815841e1a41a1e6b73a0b08f3038af9b2252564d01fc405356d34033012216"}, ] [package.dependencies] @@ -946,14 +953,14 @@ files = [ [[package]] name = "jsonschema" -version = "4.23.0" +version = "4.24.0" description = "An implementation of JSON Schema validation for Python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["charm-libs", "unit"] files = [ - {file = "jsonschema-4.23.0-py3-none-any.whl", hash = "sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566"}, - {file = "jsonschema-4.23.0.tar.gz", hash = "sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4"}, + {file = "jsonschema-4.24.0-py3-none-any.whl", hash = "sha256:a462455f19f5faf404a7902952b6f0e3ce868f3ee09a359b05eca6673bd8412d"}, + {file = "jsonschema-4.24.0.tar.gz", hash = "sha256:0b4e8069eb12aedfa881333004bccaec24ecef5a8a6a4b6df142b2cc9599d196"}, ] [package.dependencies] @@ -983,14 +990,13 @@ referencing = ">=0.31.0" [[package]] name = "juju" -version = "3.6.1.1" +version = "3.6.1.2" description = "Python library for Juju" optional = false python-versions = ">=3.8.6" groups = ["integration"] files = [ - {file = "juju-3.6.1.1-py3-none-any.whl", hash = "sha256:19ede730130b03cd5a99850f812521c2eb93199771207b50e1edf86e5e47acb2"}, - {file = "juju-3.6.1.1.tar.gz", hash = "sha256:2289abd450515b7883f12f06d42f965d31939e711c496cb8713b4b058408e589"}, + {file = "juju-3.6.1.2.tar.gz", hash = "sha256:01ff58b8590b2ea19ace024c124a29d470c9e38431f5a9688ef990eef2b86889"}, ] [package.dependencies] @@ -1214,7 +1220,7 @@ version = "1.21.0" description = "OpenTelemetry Python API" optional = false python-versions = ">=3.7" -groups = ["charm-libs"] +groups = ["main", "charm-libs"] files = [ {file = "opentelemetry_api-1.21.0-py3-none-any.whl", hash = "sha256:4bb86b28627b7e41098f0e93280fe4892a1abed1b79a19aec6f928f39b17dffb"}, {file = "opentelemetry_api-1.21.0.tar.gz", hash = "sha256:d6185fd5043e000075d921822fd2d26b953eba8ca21b1e2fa360dd46a7686316"}, @@ -1311,23 +1317,26 @@ files = [ [[package]] name = "ops" -version = "2.20.0" +version = "2.22.0" description = "The Python library behind great charms" optional = false python-versions = ">=3.8" groups = ["main", "charm-libs"] files = [ - {file = "ops-2.20.0-py3-none-any.whl", hash = "sha256:94791a4b45f00c6902494a4934480c85947880b27f5ebf3a0ec32e8cc6279c99"}, - {file = "ops-2.20.0.tar.gz", hash = "sha256:be1dcfd0bb748839fbc200bbd073a6acf9648401c3729db22d8594ebb4301e05"}, + {file = "ops-2.22.0-py3-none-any.whl", hash = "sha256:ad44326bc065e33357b47e1cf4c73e811b2fdb3c89dd0c9bdf421a7a028bdcf7"}, + {file = "ops-2.22.0.tar.gz", hash = "sha256:bd1cd1229e83efb8ae2d97d8878c7db3deceb6819eb5a38fb6e235a959528ec2"}, ] [package.dependencies] +importlib-metadata = "*" +opentelemetry-api = ">=1.0,<2.0" PyYAML = "==6.*" websocket-client = "==1.*" [package.extras] docs = ["canonical-sphinx-extensions", "furo", "linkify-it-py", "myst-parser", "pyspelling", "sphinx (>=8.0.0,<8.1.0)", "sphinx-autobuild", "sphinx-copybutton", "sphinx-design", "sphinx-notfound-page", "sphinx-tabs", "sphinxcontrib-jquery", "sphinxext-opengraph"] -testing = ["ops-scenario (==7.20.0)"] +testing = ["ops-scenario (==7.22.0)"] +tracing = ["ops-tracing (==2.22.0)"] [[package]] name = "packaging" @@ -1424,30 +1433,30 @@ files = [ [[package]] name = "pluggy" -version = "1.5.0" +version = "1.6.0" description = "plugin and hook calling mechanisms for python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["integration", "unit"] files = [ - {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, - {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, + {file = "pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746"}, + {file = "pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3"}, ] [package.extras] dev = ["pre-commit", "tox"] -testing = ["pytest", "pytest-benchmark"] +testing = ["coverage", "pytest", "pytest-benchmark"] [[package]] name = "poetry-core" -version = "2.1.2" +version = "2.1.3" description = "Poetry PEP 517 Build Backend" optional = false python-versions = "<4.0,>=3.9" groups = ["charm-libs"] files = [ - {file = "poetry_core-2.1.2-py3-none-any.whl", hash = "sha256:ecb1e8f7d4f071a21cd0feb8c19bd1aec80de6fb0e82aa9d809a591e544431b4"}, - {file = "poetry_core-2.1.2.tar.gz", hash = "sha256:f9dbbbd0ebf9755476a1d57f04b30e9aecf71ca9dc2fcd4b17aba92c0002aa04"}, + {file = "poetry_core-2.1.3-py3-none-any.whl", hash = "sha256:2c704f05016698a54ca1d327f46ce2426d72eaca6ff614132c8477c292266771"}, + {file = "poetry_core-2.1.3.tar.gz", hash = "sha256:0522a015477ed622c89aad56a477a57813cace0c8e7ff2a2906b7ef4a2e296a4"}, ] [[package]] @@ -1467,23 +1476,23 @@ wcwidth = "*" [[package]] name = "protobuf" -version = "4.25.7" +version = "4.25.8" description = "" optional = false python-versions = ">=3.8" groups = ["charm-libs", "integration"] files = [ - {file = "protobuf-4.25.7-cp310-abi3-win32.whl", hash = "sha256:dc582cf1a73a6b40aa8e7704389b8d8352da616bc8ed5c6cc614bdd0b5ce3f7a"}, - {file = "protobuf-4.25.7-cp310-abi3-win_amd64.whl", hash = "sha256:cd873dbddb28460d1706ff4da2e7fac175f62f2a0bebc7b33141f7523c5a2399"}, - {file = "protobuf-4.25.7-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:4c899f09b0502eb39174c717ccf005b844ea93e31137c167ddcacf3e09e49610"}, - {file = "protobuf-4.25.7-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:6d2f5dede3d112e573f0e5f9778c0c19d9f9e209727abecae1d39db789f522c6"}, - {file = "protobuf-4.25.7-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:d41fb7ae72a25fcb79b2d71e4247f0547a02e8185ed51587c22827a87e5736ed"}, - {file = "protobuf-4.25.7-cp38-cp38-win32.whl", hash = "sha256:237db80000865851eac3c6e9d5597c0dfb0b2700d642ec48ed80b6ffe7b8729c"}, - {file = "protobuf-4.25.7-cp38-cp38-win_amd64.whl", hash = "sha256:ea41b75edb0f1110050a60e653820d9acc70b6fb471013971535f412addbb0d0"}, - {file = "protobuf-4.25.7-cp39-cp39-win32.whl", hash = "sha256:2f738d4f341186e697c4cdd0e03143ee5cf6cf523790748e61273a51997494c3"}, - {file = "protobuf-4.25.7-cp39-cp39-win_amd64.whl", hash = "sha256:3629b34b65f6204b17adf4ffe21adc8e85f6c6c0bc2baf3fb001b0d343edaebb"}, - {file = "protobuf-4.25.7-py3-none-any.whl", hash = "sha256:e9d969f5154eaeab41404def5dcf04e62162178f4b9de98b2d3c1c70f5f84810"}, - {file = "protobuf-4.25.7.tar.gz", hash = "sha256:28f65ae8c14523cc2c76c1e91680958700d3eac69f45c96512c12c63d9a38807"}, + {file = "protobuf-4.25.8-cp310-abi3-win32.whl", hash = "sha256:504435d831565f7cfac9f0714440028907f1975e4bed228e58e72ecfff58a1e0"}, + {file = "protobuf-4.25.8-cp310-abi3-win_amd64.whl", hash = "sha256:bd551eb1fe1d7e92c1af1d75bdfa572eff1ab0e5bf1736716814cdccdb2360f9"}, + {file = "protobuf-4.25.8-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:ca809b42f4444f144f2115c4c1a747b9a404d590f18f37e9402422033e464e0f"}, + {file = "protobuf-4.25.8-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:9ad7ef62d92baf5a8654fbb88dac7fa5594cfa70fd3440488a5ca3bfc6d795a7"}, + {file = "protobuf-4.25.8-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:83e6e54e93d2b696a92cad6e6efc924f3850f82b52e1563778dfab8b355101b0"}, + {file = "protobuf-4.25.8-cp38-cp38-win32.whl", hash = "sha256:27d498ffd1f21fb81d987a041c32d07857d1d107909f5134ba3350e1ce80a4af"}, + {file = "protobuf-4.25.8-cp38-cp38-win_amd64.whl", hash = "sha256:d552c53d0415449c8d17ced5c341caba0d89dbf433698e1436c8fa0aae7808a3"}, + {file = "protobuf-4.25.8-cp39-cp39-win32.whl", hash = "sha256:077ff8badf2acf8bc474406706ad890466274191a48d0abd3bd6987107c9cde5"}, + {file = "protobuf-4.25.8-cp39-cp39-win_amd64.whl", hash = "sha256:f4510b93a3bec6eba8fd8f1093e9d7fb0d4a24d1a81377c10c0e5bbfe9e4ed24"}, + {file = "protobuf-4.25.8-py3-none-any.whl", hash = "sha256:15a0af558aa3b13efef102ae6e4f3efac06f1eea11afb3a57db2901447d9fb59"}, + {file = "protobuf-4.25.8.tar.gz", hash = "sha256:6135cf8affe1fc6f76cced2641e4ea8d3e59518d1f24ae41ba97bcad82d397cd"}, ] [[package]] @@ -1749,7 +1758,7 @@ version = "2.19.1" description = "Pygments is a syntax highlighting package written in Python." optional = false python-versions = ">=3.8" -groups = ["integration"] +groups = ["integration", "unit"] files = [ {file = "pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c"}, {file = "pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f"}, @@ -1829,26 +1838,27 @@ files = [ [[package]] name = "pytest" -version = "8.3.5" +version = "8.4.0" description = "pytest: simple powerful testing with Python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["integration", "unit"] files = [ - {file = "pytest-8.3.5-py3-none-any.whl", hash = "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820"}, - {file = "pytest-8.3.5.tar.gz", hash = "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845"}, + {file = "pytest-8.4.0-py3-none-any.whl", hash = "sha256:f40f825768ad76c0977cbacdf1fd37c6f7a468e460ea6a0636078f8972d4517e"}, + {file = "pytest-8.4.0.tar.gz", hash = "sha256:14d920b48472ea0dbf68e45b96cd1ffda4705f33307dcc86c676c1b5104838a6"}, ] [package.dependencies] -colorama = {version = "*", markers = "sys_platform == \"win32\""} -exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} -iniconfig = "*" -packaging = "*" +colorama = {version = ">=0.4", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1", markers = "python_version < \"3.11\""} +iniconfig = ">=1" +packaging = ">=20" pluggy = ">=1.5,<2" +pygments = ">=2.7.2" tomli = {version = ">=1", markers = "python_version < \"3.11\""} [package.extras] -dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] +dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "requests", "setuptools", "xmlschema"] [[package]] name = "pytest-asyncio" @@ -2039,126 +2049,129 @@ rsa = ["oauthlib[signedtoken] (>=3.0.0)"] [[package]] name = "rpds-py" -version = "0.24.0" +version = "0.25.1" description = "Python bindings to Rust's persistent data structures (rpds)" optional = false python-versions = ">=3.9" groups = ["charm-libs", "unit"] files = [ - {file = "rpds_py-0.24.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:006f4342fe729a368c6df36578d7a348c7c716be1da0a1a0f86e3021f8e98724"}, - {file = "rpds_py-0.24.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2d53747da70a4e4b17f559569d5f9506420966083a31c5fbd84e764461c4444b"}, - {file = "rpds_py-0.24.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8acd55bd5b071156bae57b555f5d33697998752673b9de554dd82f5b5352727"}, - {file = "rpds_py-0.24.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7e80d375134ddb04231a53800503752093dbb65dad8dabacce2c84cccc78e964"}, - {file = "rpds_py-0.24.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:60748789e028d2a46fc1c70750454f83c6bdd0d05db50f5ae83e2db500b34da5"}, - {file = "rpds_py-0.24.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6e1daf5bf6c2be39654beae83ee6b9a12347cb5aced9a29eecf12a2d25fff664"}, - {file = "rpds_py-0.24.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1b221c2457d92a1fb3c97bee9095c874144d196f47c038462ae6e4a14436f7bc"}, - {file = "rpds_py-0.24.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:66420986c9afff67ef0c5d1e4cdc2d0e5262f53ad11e4f90e5e22448df485bf0"}, - {file = "rpds_py-0.24.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:43dba99f00f1d37b2a0265a259592d05fcc8e7c19d140fe51c6e6f16faabeb1f"}, - {file = "rpds_py-0.24.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:a88c0d17d039333a41d9bf4616bd062f0bd7aa0edeb6cafe00a2fc2a804e944f"}, - {file = "rpds_py-0.24.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cc31e13ce212e14a539d430428cd365e74f8b2d534f8bc22dd4c9c55b277b875"}, - {file = "rpds_py-0.24.0-cp310-cp310-win32.whl", hash = "sha256:fc2c1e1b00f88317d9de6b2c2b39b012ebbfe35fe5e7bef980fd2a91f6100a07"}, - {file = "rpds_py-0.24.0-cp310-cp310-win_amd64.whl", hash = "sha256:c0145295ca415668420ad142ee42189f78d27af806fcf1f32a18e51d47dd2052"}, - {file = "rpds_py-0.24.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:2d3ee4615df36ab8eb16c2507b11e764dcc11fd350bbf4da16d09cda11fcedef"}, - {file = "rpds_py-0.24.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e13ae74a8a3a0c2f22f450f773e35f893484fcfacb00bb4344a7e0f4f48e1f97"}, - {file = "rpds_py-0.24.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf86f72d705fc2ef776bb7dd9e5fbba79d7e1f3e258bf9377f8204ad0fc1c51e"}, - {file = "rpds_py-0.24.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c43583ea8517ed2e780a345dd9960896afc1327e8cf3ac8239c167530397440d"}, - {file = "rpds_py-0.24.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4cd031e63bc5f05bdcda120646a0d32f6d729486d0067f09d79c8db5368f4586"}, - {file = "rpds_py-0.24.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:34d90ad8c045df9a4259c47d2e16a3f21fdb396665c94520dbfe8766e62187a4"}, - {file = "rpds_py-0.24.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e838bf2bb0b91ee67bf2b889a1a841e5ecac06dd7a2b1ef4e6151e2ce155c7ae"}, - {file = "rpds_py-0.24.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04ecf5c1ff4d589987b4d9882872f80ba13da7d42427234fce8f22efb43133bc"}, - {file = "rpds_py-0.24.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:630d3d8ea77eabd6cbcd2ea712e1c5cecb5b558d39547ac988351195db433f6c"}, - {file = "rpds_py-0.24.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ebcb786b9ff30b994d5969213a8430cbb984cdd7ea9fd6df06663194bd3c450c"}, - {file = "rpds_py-0.24.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:174e46569968ddbbeb8a806d9922f17cd2b524aa753b468f35b97ff9c19cb718"}, - {file = "rpds_py-0.24.0-cp311-cp311-win32.whl", hash = "sha256:5ef877fa3bbfb40b388a5ae1cb00636a624690dcb9a29a65267054c9ea86d88a"}, - {file = "rpds_py-0.24.0-cp311-cp311-win_amd64.whl", hash = "sha256:e274f62cbd274359eff63e5c7e7274c913e8e09620f6a57aae66744b3df046d6"}, - {file = "rpds_py-0.24.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:d8551e733626afec514b5d15befabea0dd70a343a9f23322860c4f16a9430205"}, - {file = "rpds_py-0.24.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0e374c0ce0ca82e5b67cd61fb964077d40ec177dd2c4eda67dba130de09085c7"}, - {file = "rpds_py-0.24.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d69d003296df4840bd445a5d15fa5b6ff6ac40496f956a221c4d1f6f7b4bc4d9"}, - {file = "rpds_py-0.24.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8212ff58ac6dfde49946bea57474a386cca3f7706fc72c25b772b9ca4af6b79e"}, - {file = "rpds_py-0.24.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:528927e63a70b4d5f3f5ccc1fa988a35456eb5d15f804d276709c33fc2f19bda"}, - {file = "rpds_py-0.24.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a824d2c7a703ba6daaca848f9c3d5cb93af0505be505de70e7e66829affd676e"}, - {file = "rpds_py-0.24.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44d51febb7a114293ffd56c6cf4736cb31cd68c0fddd6aa303ed09ea5a48e029"}, - {file = "rpds_py-0.24.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3fab5f4a2c64a8fb64fc13b3d139848817a64d467dd6ed60dcdd6b479e7febc9"}, - {file = "rpds_py-0.24.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9be4f99bee42ac107870c61dfdb294d912bf81c3c6d45538aad7aecab468b6b7"}, - {file = "rpds_py-0.24.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:564c96b6076a98215af52f55efa90d8419cc2ef45d99e314fddefe816bc24f91"}, - {file = "rpds_py-0.24.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:75a810b7664c17f24bf2ffd7f92416c00ec84b49bb68e6a0d93e542406336b56"}, - {file = "rpds_py-0.24.0-cp312-cp312-win32.whl", hash = "sha256:f6016bd950be4dcd047b7475fdf55fb1e1f59fc7403f387be0e8123e4a576d30"}, - {file = "rpds_py-0.24.0-cp312-cp312-win_amd64.whl", hash = "sha256:998c01b8e71cf051c28f5d6f1187abbdf5cf45fc0efce5da6c06447cba997034"}, - {file = "rpds_py-0.24.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:3d2d8e4508e15fc05b31285c4b00ddf2e0eb94259c2dc896771966a163122a0c"}, - {file = "rpds_py-0.24.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0f00c16e089282ad68a3820fd0c831c35d3194b7cdc31d6e469511d9bffc535c"}, - {file = "rpds_py-0.24.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:951cc481c0c395c4a08639a469d53b7d4afa252529a085418b82a6b43c45c240"}, - {file = "rpds_py-0.24.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c9ca89938dff18828a328af41ffdf3902405a19f4131c88e22e776a8e228c5a8"}, - {file = "rpds_py-0.24.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ed0ef550042a8dbcd657dfb284a8ee00f0ba269d3f2286b0493b15a5694f9fe8"}, - {file = "rpds_py-0.24.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2b2356688e5d958c4d5cb964af865bea84db29971d3e563fb78e46e20fe1848b"}, - {file = "rpds_py-0.24.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78884d155fd15d9f64f5d6124b486f3d3f7fd7cd71a78e9670a0f6f6ca06fb2d"}, - {file = "rpds_py-0.24.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6a4a535013aeeef13c5532f802708cecae8d66c282babb5cd916379b72110cf7"}, - {file = "rpds_py-0.24.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:84e0566f15cf4d769dade9b366b7b87c959be472c92dffb70462dd0844d7cbad"}, - {file = "rpds_py-0.24.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:823e74ab6fbaa028ec89615ff6acb409e90ff45580c45920d4dfdddb069f2120"}, - {file = "rpds_py-0.24.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c61a2cb0085c8783906b2f8b1f16a7e65777823c7f4d0a6aaffe26dc0d358dd9"}, - {file = "rpds_py-0.24.0-cp313-cp313-win32.whl", hash = "sha256:60d9b630c8025b9458a9d114e3af579a2c54bd32df601c4581bd054e85258143"}, - {file = "rpds_py-0.24.0-cp313-cp313-win_amd64.whl", hash = "sha256:6eea559077d29486c68218178ea946263b87f1c41ae7f996b1f30a983c476a5a"}, - {file = "rpds_py-0.24.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:d09dc82af2d3c17e7dd17120b202a79b578d79f2b5424bda209d9966efeed114"}, - {file = "rpds_py-0.24.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5fc13b44de6419d1e7a7e592a4885b323fbc2f46e1f22151e3a8ed3b8b920405"}, - {file = "rpds_py-0.24.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c347a20d79cedc0a7bd51c4d4b7dbc613ca4e65a756b5c3e57ec84bd43505b47"}, - {file = "rpds_py-0.24.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:20f2712bd1cc26a3cc16c5a1bfee9ed1abc33d4cdf1aabd297fe0eb724df4272"}, - {file = "rpds_py-0.24.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aad911555286884be1e427ef0dc0ba3929e6821cbeca2194b13dc415a462c7fd"}, - {file = "rpds_py-0.24.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0aeb3329c1721c43c58cae274d7d2ca85c1690d89485d9c63a006cb79a85771a"}, - {file = "rpds_py-0.24.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2a0f156e9509cee987283abd2296ec816225145a13ed0391df8f71bf1d789e2d"}, - {file = "rpds_py-0.24.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:aa6800adc8204ce898c8a424303969b7aa6a5e4ad2789c13f8648739830323b7"}, - {file = "rpds_py-0.24.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a18fc371e900a21d7392517c6f60fe859e802547309e94313cd8181ad9db004d"}, - {file = "rpds_py-0.24.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:9168764133fd919f8dcca2ead66de0105f4ef5659cbb4fa044f7014bed9a1797"}, - {file = "rpds_py-0.24.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5f6e3cec44ba05ee5cbdebe92d052f69b63ae792e7d05f1020ac5e964394080c"}, - {file = "rpds_py-0.24.0-cp313-cp313t-win32.whl", hash = "sha256:8ebc7e65ca4b111d928b669713865f021b7773350eeac4a31d3e70144297baba"}, - {file = "rpds_py-0.24.0-cp313-cp313t-win_amd64.whl", hash = "sha256:675269d407a257b8c00a6b58205b72eec8231656506c56fd429d924ca00bb350"}, - {file = "rpds_py-0.24.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a36b452abbf29f68527cf52e181fced56685731c86b52e852053e38d8b60bc8d"}, - {file = "rpds_py-0.24.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8b3b397eefecec8e8e39fa65c630ef70a24b09141a6f9fc17b3c3a50bed6b50e"}, - {file = "rpds_py-0.24.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdabcd3beb2a6dca7027007473d8ef1c3b053347c76f685f5f060a00327b8b65"}, - {file = "rpds_py-0.24.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5db385bacd0c43f24be92b60c857cf760b7f10d8234f4bd4be67b5b20a7c0b6b"}, - {file = "rpds_py-0.24.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8097b3422d020ff1c44effc40ae58e67d93e60d540a65649d2cdaf9466030791"}, - {file = "rpds_py-0.24.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:493fe54318bed7d124ce272fc36adbf59d46729659b2c792e87c3b95649cdee9"}, - {file = "rpds_py-0.24.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8aa362811ccdc1f8dadcc916c6d47e554169ab79559319ae9fae7d7752d0d60c"}, - {file = "rpds_py-0.24.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d8f9a6e7fd5434817526815f09ea27f2746c4a51ee11bb3439065f5fc754db58"}, - {file = "rpds_py-0.24.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:8205ee14463248d3349131bb8099efe15cd3ce83b8ef3ace63c7e976998e7124"}, - {file = "rpds_py-0.24.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:921ae54f9ecba3b6325df425cf72c074cd469dea843fb5743a26ca7fb2ccb149"}, - {file = "rpds_py-0.24.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:32bab0a56eac685828e00cc2f5d1200c548f8bc11f2e44abf311d6b548ce2e45"}, - {file = "rpds_py-0.24.0-cp39-cp39-win32.whl", hash = "sha256:f5c0ed12926dec1dfe7d645333ea59cf93f4d07750986a586f511c0bc61fe103"}, - {file = "rpds_py-0.24.0-cp39-cp39-win_amd64.whl", hash = "sha256:afc6e35f344490faa8276b5f2f7cbf71f88bc2cda4328e00553bd451728c571f"}, - {file = "rpds_py-0.24.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:619ca56a5468f933d940e1bf431c6f4e13bef8e688698b067ae68eb4f9b30e3a"}, - {file = "rpds_py-0.24.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:4b28e5122829181de1898c2c97f81c0b3246d49f585f22743a1246420bb8d399"}, - {file = "rpds_py-0.24.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8e5ab32cf9eb3647450bc74eb201b27c185d3857276162c101c0f8c6374e098"}, - {file = "rpds_py-0.24.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:208b3a70a98cf3710e97cabdc308a51cd4f28aa6e7bb11de3d56cd8b74bab98d"}, - {file = "rpds_py-0.24.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bbc4362e06f950c62cad3d4abf1191021b2ffaf0b31ac230fbf0526453eee75e"}, - {file = "rpds_py-0.24.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ebea2821cdb5f9fef44933617be76185b80150632736f3d76e54829ab4a3b4d1"}, - {file = "rpds_py-0.24.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9a4df06c35465ef4d81799999bba810c68d29972bf1c31db61bfdb81dd9d5bb"}, - {file = "rpds_py-0.24.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d3aa13bdf38630da298f2e0d77aca967b200b8cc1473ea05248f6c5e9c9bdb44"}, - {file = "rpds_py-0.24.0-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:041f00419e1da7a03c46042453598479f45be3d787eb837af382bfc169c0db33"}, - {file = "rpds_py-0.24.0-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:d8754d872a5dfc3c5bf9c0e059e8107451364a30d9fd50f1f1a85c4fb9481164"}, - {file = "rpds_py-0.24.0-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:896c41007931217a343eff197c34513c154267636c8056fb409eafd494c3dcdc"}, - {file = "rpds_py-0.24.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:92558d37d872e808944c3c96d0423b8604879a3d1c86fdad508d7ed91ea547d5"}, - {file = "rpds_py-0.24.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f9e0057a509e096e47c87f753136c9b10d7a91842d8042c2ee6866899a717c0d"}, - {file = "rpds_py-0.24.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d6e109a454412ab82979c5b1b3aee0604eca4bbf9a02693bb9df027af2bfa91a"}, - {file = "rpds_py-0.24.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc1c892b1ec1f8cbd5da8de287577b455e388d9c328ad592eabbdcb6fc93bee5"}, - {file = "rpds_py-0.24.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9c39438c55983d48f4bb3487734d040e22dad200dab22c41e331cee145e7a50d"}, - {file = "rpds_py-0.24.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d7e8ce990ae17dda686f7e82fd41a055c668e13ddcf058e7fb5e9da20b57793"}, - {file = "rpds_py-0.24.0-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9ea7f4174d2e4194289cb0c4e172d83e79a6404297ff95f2875cf9ac9bced8ba"}, - {file = "rpds_py-0.24.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb2954155bb8f63bb19d56d80e5e5320b61d71084617ed89efedb861a684baea"}, - {file = "rpds_py-0.24.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04f2b712a2206e13800a8136b07aaedc23af3facab84918e7aa89e4be0260032"}, - {file = "rpds_py-0.24.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:eda5c1e2a715a4cbbca2d6d304988460942551e4e5e3b7457b50943cd741626d"}, - {file = "rpds_py-0.24.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:9abc80fe8c1f87218db116016de575a7998ab1629078c90840e8d11ab423ee25"}, - {file = "rpds_py-0.24.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:6a727fd083009bc83eb83d6950f0c32b3c94c8b80a9b667c87f4bd1274ca30ba"}, - {file = "rpds_py-0.24.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e0f3ef95795efcd3b2ec3fe0a5bcfb5dadf5e3996ea2117427e524d4fbf309c6"}, - {file = "rpds_py-0.24.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:2c13777ecdbbba2077670285dd1fe50828c8742f6a4119dbef6f83ea13ad10fb"}, - {file = "rpds_py-0.24.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79e8d804c2ccd618417e96720ad5cd076a86fa3f8cb310ea386a3e6229bae7d1"}, - {file = "rpds_py-0.24.0-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fd822f019ccccd75c832deb7aa040bb02d70a92eb15a2f16c7987b7ad4ee8d83"}, - {file = "rpds_py-0.24.0-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0047638c3aa0dbcd0ab99ed1e549bbf0e142c9ecc173b6492868432d8989a046"}, - {file = "rpds_py-0.24.0-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a5b66d1b201cc71bc3081bc2f1fc36b0c1f268b773e03bbc39066651b9e18391"}, - {file = "rpds_py-0.24.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dbcbb6db5582ea33ce46a5d20a5793134b5365110d84df4e30b9d37c6fd40ad3"}, - {file = "rpds_py-0.24.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:63981feca3f110ed132fd217bf7768ee8ed738a55549883628ee3da75bb9cb78"}, - {file = "rpds_py-0.24.0-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:3a55fc10fdcbf1a4bd3c018eea422c52cf08700cf99c28b5cb10fe97ab77a0d3"}, - {file = "rpds_py-0.24.0-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:c30ff468163a48535ee7e9bf21bd14c7a81147c0e58a36c1078289a8ca7af0bd"}, - {file = "rpds_py-0.24.0-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:369d9c6d4c714e36d4a03957b4783217a3ccd1e222cdd67d464a3a479fc17796"}, - {file = "rpds_py-0.24.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:24795c099453e3721fda5d8ddd45f5dfcc8e5a547ce7b8e9da06fecc3832e26f"}, - {file = "rpds_py-0.24.0.tar.gz", hash = "sha256:772cc1b2cd963e7e17e6cc55fe0371fb9c704d63e44cacec7b9b7f523b78919e"}, + {file = "rpds_py-0.25.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:f4ad628b5174d5315761b67f212774a32f5bad5e61396d38108bd801c0a8f5d9"}, + {file = "rpds_py-0.25.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8c742af695f7525e559c16f1562cf2323db0e3f0fbdcabdf6865b095256b2d40"}, + {file = "rpds_py-0.25.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:605ffe7769e24b1800b4d024d24034405d9404f0bc2f55b6db3362cd34145a6f"}, + {file = "rpds_py-0.25.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ccc6f3ddef93243538be76f8e47045b4aad7a66a212cd3a0f23e34469473d36b"}, + {file = "rpds_py-0.25.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f70316f760174ca04492b5ab01be631a8ae30cadab1d1081035136ba12738cfa"}, + {file = "rpds_py-0.25.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e1dafef8df605fdb46edcc0bf1573dea0d6d7b01ba87f85cd04dc855b2b4479e"}, + {file = "rpds_py-0.25.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0701942049095741a8aeb298a31b203e735d1c61f4423511d2b1a41dcd8a16da"}, + {file = "rpds_py-0.25.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e87798852ae0b37c88babb7f7bbbb3e3fecc562a1c340195b44c7e24d403e380"}, + {file = "rpds_py-0.25.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3bcce0edc1488906c2d4c75c94c70a0417e83920dd4c88fec1078c94843a6ce9"}, + {file = "rpds_py-0.25.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e2f6a2347d3440ae789505693a02836383426249d5293541cd712e07e7aecf54"}, + {file = "rpds_py-0.25.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:4fd52d3455a0aa997734f3835cbc4c9f32571345143960e7d7ebfe7b5fbfa3b2"}, + {file = "rpds_py-0.25.1-cp310-cp310-win32.whl", hash = "sha256:3f0b1798cae2bbbc9b9db44ee068c556d4737911ad53a4e5093d09d04b3bbc24"}, + {file = "rpds_py-0.25.1-cp310-cp310-win_amd64.whl", hash = "sha256:3ebd879ab996537fc510a2be58c59915b5dd63bccb06d1ef514fee787e05984a"}, + {file = "rpds_py-0.25.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:5f048bbf18b1f9120685c6d6bb70cc1a52c8cc11bdd04e643d28d3be0baf666d"}, + {file = "rpds_py-0.25.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4fbb0dbba559959fcb5d0735a0f87cdbca9e95dac87982e9b95c0f8f7ad10255"}, + {file = "rpds_py-0.25.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4ca54b9cf9d80b4016a67a0193ebe0bcf29f6b0a96f09db942087e294d3d4c2"}, + {file = "rpds_py-0.25.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1ee3e26eb83d39b886d2cb6e06ea701bba82ef30a0de044d34626ede51ec98b0"}, + {file = "rpds_py-0.25.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:89706d0683c73a26f76a5315d893c051324d771196ae8b13e6ffa1ffaf5e574f"}, + {file = "rpds_py-0.25.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c2013ee878c76269c7b557a9a9c042335d732e89d482606990b70a839635feb7"}, + {file = "rpds_py-0.25.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45e484db65e5380804afbec784522de84fa95e6bb92ef1bd3325d33d13efaebd"}, + {file = "rpds_py-0.25.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:48d64155d02127c249695abb87d39f0faf410733428d499867606be138161d65"}, + {file = "rpds_py-0.25.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:048893e902132fd6548a2e661fb38bf4896a89eea95ac5816cf443524a85556f"}, + {file = "rpds_py-0.25.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0317177b1e8691ab5879f4f33f4b6dc55ad3b344399e23df2e499de7b10a548d"}, + {file = "rpds_py-0.25.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bffcf57826d77a4151962bf1701374e0fc87f536e56ec46f1abdd6a903354042"}, + {file = "rpds_py-0.25.1-cp311-cp311-win32.whl", hash = "sha256:cda776f1967cb304816173b30994faaf2fd5bcb37e73118a47964a02c348e1bc"}, + {file = "rpds_py-0.25.1-cp311-cp311-win_amd64.whl", hash = "sha256:dc3c1ff0abc91444cd20ec643d0f805df9a3661fcacf9c95000329f3ddf268a4"}, + {file = "rpds_py-0.25.1-cp311-cp311-win_arm64.whl", hash = "sha256:5a3ddb74b0985c4387719fc536faced33cadf2172769540c62e2a94b7b9be1c4"}, + {file = "rpds_py-0.25.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:b5ffe453cde61f73fea9430223c81d29e2fbf412a6073951102146c84e19e34c"}, + {file = "rpds_py-0.25.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:115874ae5e2fdcfc16b2aedc95b5eef4aebe91b28e7e21951eda8a5dc0d3461b"}, + {file = "rpds_py-0.25.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a714bf6e5e81b0e570d01f56e0c89c6375101b8463999ead3a93a5d2a4af91fa"}, + {file = "rpds_py-0.25.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:35634369325906bcd01577da4c19e3b9541a15e99f31e91a02d010816b49bfda"}, + {file = "rpds_py-0.25.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d4cb2b3ddc16710548801c6fcc0cfcdeeff9dafbc983f77265877793f2660309"}, + {file = "rpds_py-0.25.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9ceca1cf097ed77e1a51f1dbc8d174d10cb5931c188a4505ff9f3e119dfe519b"}, + {file = "rpds_py-0.25.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c2cd1a4b0c2b8c5e31ffff50d09f39906fe351389ba143c195566056c13a7ea"}, + {file = "rpds_py-0.25.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1de336a4b164c9188cb23f3703adb74a7623ab32d20090d0e9bf499a2203ad65"}, + {file = "rpds_py-0.25.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9fca84a15333e925dd59ce01da0ffe2ffe0d6e5d29a9eeba2148916d1824948c"}, + {file = "rpds_py-0.25.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:88ec04afe0c59fa64e2f6ea0dd9657e04fc83e38de90f6de201954b4d4eb59bd"}, + {file = "rpds_py-0.25.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a8bd2f19e312ce3e1d2c635618e8a8d8132892bb746a7cf74780a489f0f6cdcb"}, + {file = "rpds_py-0.25.1-cp312-cp312-win32.whl", hash = "sha256:e5e2f7280d8d0d3ef06f3ec1b4fd598d386cc6f0721e54f09109a8132182fbfe"}, + {file = "rpds_py-0.25.1-cp312-cp312-win_amd64.whl", hash = "sha256:db58483f71c5db67d643857404da360dce3573031586034b7d59f245144cc192"}, + {file = "rpds_py-0.25.1-cp312-cp312-win_arm64.whl", hash = "sha256:6d50841c425d16faf3206ddbba44c21aa3310a0cebc3c1cdfc3e3f4f9f6f5728"}, + {file = "rpds_py-0.25.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:659d87430a8c8c704d52d094f5ba6fa72ef13b4d385b7e542a08fc240cb4a559"}, + {file = "rpds_py-0.25.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:68f6f060f0bbdfb0245267da014d3a6da9be127fe3e8cc4a68c6f833f8a23bb1"}, + {file = "rpds_py-0.25.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:083a9513a33e0b92cf6e7a6366036c6bb43ea595332c1ab5c8ae329e4bcc0a9c"}, + {file = "rpds_py-0.25.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:816568614ecb22b18a010c7a12559c19f6fe993526af88e95a76d5a60b8b75fb"}, + {file = "rpds_py-0.25.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3c6564c0947a7f52e4792983f8e6cf9bac140438ebf81f527a21d944f2fd0a40"}, + {file = "rpds_py-0.25.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c4a128527fe415d73cf1f70a9a688d06130d5810be69f3b553bf7b45e8acf79"}, + {file = "rpds_py-0.25.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a49e1d7a4978ed554f095430b89ecc23f42014a50ac385eb0c4d163ce213c325"}, + {file = "rpds_py-0.25.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d74ec9bc0e2feb81d3f16946b005748119c0f52a153f6db6a29e8cd68636f295"}, + {file = "rpds_py-0.25.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3af5b4cc10fa41e5bc64e5c198a1b2d2864337f8fcbb9a67e747e34002ce812b"}, + {file = "rpds_py-0.25.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:79dc317a5f1c51fd9c6a0c4f48209c6b8526d0524a6904fc1076476e79b00f98"}, + {file = "rpds_py-0.25.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1521031351865e0181bc585147624d66b3b00a84109b57fcb7a779c3ec3772cd"}, + {file = "rpds_py-0.25.1-cp313-cp313-win32.whl", hash = "sha256:5d473be2b13600b93a5675d78f59e63b51b1ba2d0476893415dfbb5477e65b31"}, + {file = "rpds_py-0.25.1-cp313-cp313-win_amd64.whl", hash = "sha256:a7b74e92a3b212390bdce1d93da9f6488c3878c1d434c5e751cbc202c5e09500"}, + {file = "rpds_py-0.25.1-cp313-cp313-win_arm64.whl", hash = "sha256:dd326a81afe332ede08eb39ab75b301d5676802cdffd3a8f287a5f0b694dc3f5"}, + {file = "rpds_py-0.25.1-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:a58d1ed49a94d4183483a3ce0af22f20318d4a1434acee255d683ad90bf78129"}, + {file = "rpds_py-0.25.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f251bf23deb8332823aef1da169d5d89fa84c89f67bdfb566c49dea1fccfd50d"}, + {file = "rpds_py-0.25.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8dbd586bfa270c1103ece2109314dd423df1fa3d9719928b5d09e4840cec0d72"}, + {file = "rpds_py-0.25.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6d273f136e912aa101a9274c3145dcbddbe4bac560e77e6d5b3c9f6e0ed06d34"}, + {file = "rpds_py-0.25.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:666fa7b1bd0a3810a7f18f6d3a25ccd8866291fbbc3c9b912b917a6715874bb9"}, + {file = "rpds_py-0.25.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:921954d7fbf3fccc7de8f717799304b14b6d9a45bbeec5a8d7408ccbf531faf5"}, + {file = "rpds_py-0.25.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3d86373ff19ca0441ebeb696ef64cb58b8b5cbacffcda5a0ec2f3911732a194"}, + {file = "rpds_py-0.25.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c8980cde3bb8575e7c956a530f2c217c1d6aac453474bf3ea0f9c89868b531b6"}, + {file = "rpds_py-0.25.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:8eb8c84ecea987a2523e057c0d950bcb3f789696c0499290b8d7b3107a719d78"}, + {file = "rpds_py-0.25.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:e43a005671a9ed5a650f3bc39e4dbccd6d4326b24fb5ea8be5f3a43a6f576c72"}, + {file = "rpds_py-0.25.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:58f77c60956501a4a627749a6dcb78dac522f249dd96b5c9f1c6af29bfacfb66"}, + {file = "rpds_py-0.25.1-cp313-cp313t-win32.whl", hash = "sha256:2cb9e5b5e26fc02c8a4345048cd9998c2aca7c2712bd1b36da0c72ee969a3523"}, + {file = "rpds_py-0.25.1-cp313-cp313t-win_amd64.whl", hash = "sha256:401ca1c4a20cc0510d3435d89c069fe0a9ae2ee6495135ac46bdd49ec0495763"}, + {file = "rpds_py-0.25.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:ce4c8e485a3c59593f1a6f683cf0ea5ab1c1dc94d11eea5619e4fb5228b40fbd"}, + {file = "rpds_py-0.25.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d8222acdb51a22929c3b2ddb236b69c59c72af4019d2cba961e2f9add9b6e634"}, + {file = "rpds_py-0.25.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4593c4eae9b27d22df41cde518b4b9e4464d139e4322e2127daa9b5b981b76be"}, + {file = "rpds_py-0.25.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bd035756830c712b64725a76327ce80e82ed12ebab361d3a1cdc0f51ea21acb0"}, + {file = "rpds_py-0.25.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:114a07e85f32b125404f28f2ed0ba431685151c037a26032b213c882f26eb908"}, + {file = "rpds_py-0.25.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dec21e02e6cc932538b5203d3a8bd6aa1480c98c4914cb88eea064ecdbc6396a"}, + {file = "rpds_py-0.25.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:09eab132f41bf792c7a0ea1578e55df3f3e7f61888e340779b06050a9a3f16e9"}, + {file = "rpds_py-0.25.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c98f126c4fc697b84c423e387337d5b07e4a61e9feac494362a59fd7a2d9ed80"}, + {file = "rpds_py-0.25.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0e6a327af8ebf6baba1c10fadd04964c1965d375d318f4435d5f3f9651550f4a"}, + {file = "rpds_py-0.25.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:bc120d1132cff853ff617754196d0ac0ae63befe7c8498bd67731ba368abe451"}, + {file = "rpds_py-0.25.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:140f61d9bed7839446bdd44852e30195c8e520f81329b4201ceead4d64eb3a9f"}, + {file = "rpds_py-0.25.1-cp39-cp39-win32.whl", hash = "sha256:9c006f3aadeda131b438c3092124bd196b66312f0caa5823ef09585a669cf449"}, + {file = "rpds_py-0.25.1-cp39-cp39-win_amd64.whl", hash = "sha256:a61d0b2c7c9a0ae45732a77844917b427ff16ad5464b4d4f5e4adb955f582890"}, + {file = "rpds_py-0.25.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b24bf3cd93d5b6ecfbedec73b15f143596c88ee249fa98cefa9a9dc9d92c6f28"}, + {file = "rpds_py-0.25.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:0eb90e94f43e5085623932b68840b6f379f26db7b5c2e6bcef3179bd83c9330f"}, + {file = "rpds_py-0.25.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d50e4864498a9ab639d6d8854b25e80642bd362ff104312d9770b05d66e5fb13"}, + {file = "rpds_py-0.25.1-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7c9409b47ba0650544b0bb3c188243b83654dfe55dcc173a86832314e1a6a35d"}, + {file = "rpds_py-0.25.1-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:796ad874c89127c91970652a4ee8b00d56368b7e00d3477f4415fe78164c8000"}, + {file = "rpds_py-0.25.1-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:85608eb70a659bf4c1142b2781083d4b7c0c4e2c90eff11856a9754e965b2540"}, + {file = "rpds_py-0.25.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4feb9211d15d9160bc85fa72fed46432cdc143eb9cf6d5ca377335a921ac37b"}, + {file = "rpds_py-0.25.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ccfa689b9246c48947d31dd9d8b16d89a0ecc8e0e26ea5253068efb6c542b76e"}, + {file = "rpds_py-0.25.1-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:3c5b317ecbd8226887994852e85de562f7177add602514d4ac40f87de3ae45a8"}, + {file = "rpds_py-0.25.1-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:454601988aab2c6e8fd49e7634c65476b2b919647626208e376afcd22019eeb8"}, + {file = "rpds_py-0.25.1-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:1c0c434a53714358532d13539272db75a5ed9df75a4a090a753ac7173ec14e11"}, + {file = "rpds_py-0.25.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:f73ce1512e04fbe2bc97836e89830d6b4314c171587a99688082d090f934d20a"}, + {file = "rpds_py-0.25.1-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ee86d81551ec68a5c25373c5643d343150cc54672b5e9a0cafc93c1870a53954"}, + {file = "rpds_py-0.25.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:89c24300cd4a8e4a51e55c31a8ff3918e6651b241ee8876a42cc2b2a078533ba"}, + {file = "rpds_py-0.25.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:771c16060ff4e79584dc48902a91ba79fd93eade3aa3a12d6d2a4aadaf7d542b"}, + {file = "rpds_py-0.25.1-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:785ffacd0ee61c3e60bdfde93baa6d7c10d86f15655bd706c89da08068dc5038"}, + {file = "rpds_py-0.25.1-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2a40046a529cc15cef88ac5ab589f83f739e2d332cb4d7399072242400ed68c9"}, + {file = "rpds_py-0.25.1-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:85fc223d9c76cabe5d0bff82214459189720dc135db45f9f66aa7cffbf9ff6c1"}, + {file = "rpds_py-0.25.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b0be9965f93c222fb9b4cc254235b3b2b215796c03ef5ee64f995b1b69af0762"}, + {file = "rpds_py-0.25.1-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8378fa4a940f3fb509c081e06cb7f7f2adae8cf46ef258b0e0ed7519facd573e"}, + {file = "rpds_py-0.25.1-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:33358883a4490287e67a2c391dfaea4d9359860281db3292b6886bf0be3d8692"}, + {file = "rpds_py-0.25.1-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:1d1fadd539298e70cac2f2cb36f5b8a65f742b9b9f1014dd4ea1f7785e2470bf"}, + {file = "rpds_py-0.25.1-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:9a46c2fb2545e21181445515960006e85d22025bd2fe6db23e76daec6eb689fe"}, + {file = "rpds_py-0.25.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:50f2c501a89c9a5f4e454b126193c5495b9fb441a75b298c60591d8a2eb92e1b"}, + {file = "rpds_py-0.25.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:7d779b325cc8238227c47fbc53964c8cc9a941d5dbae87aa007a1f08f2f77b23"}, + {file = "rpds_py-0.25.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:036ded36bedb727beeabc16dc1dad7cb154b3fa444e936a03b67a86dc6a5066e"}, + {file = "rpds_py-0.25.1-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:245550f5a1ac98504147cba96ffec8fabc22b610742e9150138e5d60774686d7"}, + {file = "rpds_py-0.25.1-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ff7c23ba0a88cb7b104281a99476cccadf29de2a0ef5ce864959a52675b1ca83"}, + {file = "rpds_py-0.25.1-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e37caa8cdb3b7cf24786451a0bdb853f6347b8b92005eeb64225ae1db54d1c2b"}, + {file = "rpds_py-0.25.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f2f48ab00181600ee266a095fe815134eb456163f7d6699f525dee471f312cf"}, + {file = "rpds_py-0.25.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9e5fc7484fa7dce57e25063b0ec9638ff02a908304f861d81ea49273e43838c1"}, + {file = "rpds_py-0.25.1-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:d3c10228d6cf6fe2b63d2e7985e94f6916fa46940df46b70449e9ff9297bd3d1"}, + {file = "rpds_py-0.25.1-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:5d9e40f32745db28c1ef7aad23f6fc458dc1e29945bd6781060f0d15628b8ddf"}, + {file = "rpds_py-0.25.1-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:35a8d1a24b5936b35c5003313bc177403d8bdef0f8b24f28b1c4a255f94ea992"}, + {file = "rpds_py-0.25.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:6099263f526efff9cf3883dfef505518730f7a7a93049b1d90d42e50a22b4793"}, + {file = "rpds_py-0.25.1.tar.gz", hash = "sha256:8960b6dac09b62dac26e75d7e2c4a22efb835d827a7278c34f72b2b84fa160e3"}, ] [[package]] @@ -2178,42 +2191,42 @@ pyasn1 = ">=0.1.3" [[package]] name = "ruff" -version = "0.11.7" +version = "0.11.13" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" groups = ["format"] files = [ - {file = "ruff-0.11.7-py3-none-linux_armv6l.whl", hash = "sha256:d29e909d9a8d02f928d72ab7837b5cbc450a5bdf578ab9ebee3263d0a525091c"}, - {file = "ruff-0.11.7-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:dd1fb86b168ae349fb01dd497d83537b2c5541fe0626e70c786427dd8363aaee"}, - {file = "ruff-0.11.7-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d3d7d2e140a6fbbc09033bce65bd7ea29d6a0adeb90b8430262fbacd58c38ada"}, - {file = "ruff-0.11.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4809df77de390a1c2077d9b7945d82f44b95d19ceccf0c287c56e4dc9b91ca64"}, - {file = "ruff-0.11.7-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f3a0c2e169e6b545f8e2dba185eabbd9db4f08880032e75aa0e285a6d3f48201"}, - {file = "ruff-0.11.7-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49b888200a320dd96a68e86736cf531d6afba03e4f6cf098401406a257fcf3d6"}, - {file = "ruff-0.11.7-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:2b19cdb9cf7dae00d5ee2e7c013540cdc3b31c4f281f1dacb5a799d610e90db4"}, - {file = "ruff-0.11.7-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:64e0ee994c9e326b43539d133a36a455dbaab477bc84fe7bfbd528abe2f05c1e"}, - {file = "ruff-0.11.7-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bad82052311479a5865f52c76ecee5d468a58ba44fb23ee15079f17dd4c8fd63"}, - {file = "ruff-0.11.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7940665e74e7b65d427b82bffc1e46710ec7f30d58b4b2d5016e3f0321436502"}, - {file = "ruff-0.11.7-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:169027e31c52c0e36c44ae9a9c7db35e505fee0b39f8d9fca7274a6305295a92"}, - {file = "ruff-0.11.7-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:305b93f9798aee582e91e34437810439acb28b5fc1fee6b8205c78c806845a94"}, - {file = "ruff-0.11.7-py3-none-musllinux_1_2_i686.whl", hash = "sha256:a681db041ef55550c371f9cd52a3cf17a0da4c75d6bd691092dfc38170ebc4b6"}, - {file = "ruff-0.11.7-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:07f1496ad00a4a139f4de220b0c97da6d4c85e0e4aa9b2624167b7d4d44fd6b6"}, - {file = "ruff-0.11.7-py3-none-win32.whl", hash = "sha256:f25dfb853ad217e6e5f1924ae8a5b3f6709051a13e9dad18690de6c8ff299e26"}, - {file = "ruff-0.11.7-py3-none-win_amd64.whl", hash = "sha256:0a931d85959ceb77e92aea4bbedfded0a31534ce191252721128f77e5ae1f98a"}, - {file = "ruff-0.11.7-py3-none-win_arm64.whl", hash = "sha256:778c1e5d6f9e91034142dfd06110534ca13220bfaad5c3735f6cb844654f6177"}, - {file = "ruff-0.11.7.tar.gz", hash = "sha256:655089ad3224070736dc32844fde783454f8558e71f501cb207485fe4eee23d4"}, + {file = "ruff-0.11.13-py3-none-linux_armv6l.whl", hash = "sha256:4bdfbf1240533f40042ec00c9e09a3aade6f8c10b6414cf11b519488d2635d46"}, + {file = "ruff-0.11.13-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:aef9c9ed1b5ca28bb15c7eac83b8670cf3b20b478195bd49c8d756ba0a36cf48"}, + {file = "ruff-0.11.13-py3-none-macosx_11_0_arm64.whl", hash = "sha256:53b15a9dfdce029c842e9a5aebc3855e9ab7771395979ff85b7c1dedb53ddc2b"}, + {file = "ruff-0.11.13-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ab153241400789138d13f362c43f7edecc0edfffce2afa6a68434000ecd8f69a"}, + {file = "ruff-0.11.13-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6c51f93029d54a910d3d24f7dd0bb909e31b6cd989a5e4ac513f4eb41629f0dc"}, + {file = "ruff-0.11.13-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1808b3ed53e1a777c2ef733aca9051dc9bf7c99b26ece15cb59a0320fbdbd629"}, + {file = "ruff-0.11.13-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:d28ce58b5ecf0f43c1b71edffabe6ed7f245d5336b17805803312ec9bc665933"}, + {file = "ruff-0.11.13-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:55e4bc3a77842da33c16d55b32c6cac1ec5fb0fbec9c8c513bdce76c4f922165"}, + {file = "ruff-0.11.13-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:633bf2c6f35678c56ec73189ba6fa19ff1c5e4807a78bf60ef487b9dd272cc71"}, + {file = "ruff-0.11.13-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ffbc82d70424b275b089166310448051afdc6e914fdab90e08df66c43bb5ca9"}, + {file = "ruff-0.11.13-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:4a9ddd3ec62a9a89578c85842b836e4ac832d4a2e0bfaad3b02243f930ceafcc"}, + {file = "ruff-0.11.13-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:d237a496e0778d719efb05058c64d28b757c77824e04ffe8796c7436e26712b7"}, + {file = "ruff-0.11.13-py3-none-musllinux_1_2_i686.whl", hash = "sha256:26816a218ca6ef02142343fd24c70f7cd8c5aa6c203bca284407adf675984432"}, + {file = "ruff-0.11.13-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:51c3f95abd9331dc5b87c47ac7f376db5616041173826dfd556cfe3d4977f492"}, + {file = "ruff-0.11.13-py3-none-win32.whl", hash = "sha256:96c27935418e4e8e77a26bb05962817f28b8ef3843a6c6cc49d8783b5507f250"}, + {file = "ruff-0.11.13-py3-none-win_amd64.whl", hash = "sha256:29c3189895a8a6a657b7af4e97d330c8a3afd2c9c8f46c81e2fc5a31866517e3"}, + {file = "ruff-0.11.13-py3-none-win_arm64.whl", hash = "sha256:b4385285e9179d608ff1d2fb9922062663c658605819a6876d8beef0c30b7f3b"}, + {file = "ruff-0.11.13.tar.gz", hash = "sha256:26fa247dc68d1d4e72c179e08889a25ac0c7ba4d78aecfc835d49cbfd60bf514"}, ] [[package]] name = "s3transfer" -version = "0.12.0" +version = "0.13.0" description = "An Amazon S3 Transfer Manager" optional = false python-versions = ">=3.9" groups = ["main", "integration"] files = [ - {file = "s3transfer-0.12.0-py3-none-any.whl", hash = "sha256:35b314d7d82865756edab59f7baebc6b477189e6ab4c53050e28c1de4d9cce18"}, - {file = "s3transfer-0.12.0.tar.gz", hash = "sha256:8ac58bc1989a3fdb7c7f3ee0918a66b160d038a147c7b5db1500930a607e9a1c"}, + {file = "s3transfer-0.13.0-py3-none-any.whl", hash = "sha256:0148ef34d6dd964d0d8cf4311b2b21c474693e57c2e069ec708ce043d2b527be"}, + {file = "s3transfer-0.13.0.tar.gz", hash = "sha256:f5e6db74eb7776a37208001113ea7aa97695368242b364d73e91c981ac522177"}, ] [package.dependencies] @@ -2343,14 +2356,14 @@ test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0, [[package]] name = "typing-extensions" -version = "4.13.2" -description = "Backported and Experimental Type Hints for Python 3.8+" +version = "4.14.0" +description = "Backported and Experimental Type Hints for Python 3.9+" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main", "charm-libs", "integration", "unit"] files = [ - {file = "typing_extensions-4.13.2-py3-none-any.whl", hash = "sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c"}, - {file = "typing_extensions-4.13.2.tar.gz", hash = "sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef"}, + {file = "typing_extensions-4.14.0-py3-none-any.whl", hash = "sha256:a1514509136dd0b477638fc68d6a91497af5076466ad0fa6c338e44e359944af"}, + {file = "typing_extensions-4.14.0.tar.gz", hash = "sha256:8676b788e32f02ab42d9e7c61324048ae4c6d844a399eebace3d4979d75ceef4"}, ] markers = {unit = "python_version < \"3.13\""} @@ -2502,7 +2515,7 @@ version = "1.17.2" description = "Module for decorators, wrappers and monkey patching." optional = false python-versions = ">=3.8" -groups = ["charm-libs"] +groups = ["main", "charm-libs"] files = [ {file = "wrapt-1.17.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3d57c572081fed831ad2d26fd430d565b76aa277ed1d30ff4d40670b1c0dd984"}, {file = "wrapt-1.17.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b5e251054542ae57ac7f3fba5d10bfff615b6c2fb09abeb37d2f1463f841ae22"}, @@ -2587,14 +2600,14 @@ files = [ [[package]] name = "zipp" -version = "3.21.0" +version = "3.23.0" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false python-versions = ">=3.9" -groups = ["charm-libs"] +groups = ["main", "charm-libs"] files = [ - {file = "zipp-3.21.0-py3-none-any.whl", hash = "sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931"}, - {file = "zipp-3.21.0.tar.gz", hash = "sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4"}, + {file = "zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e"}, + {file = "zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166"}, ] [package.extras] @@ -2602,10 +2615,10 @@ check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \" cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] enabler = ["pytest-enabler (>=2.2)"] -test = ["big-O", "importlib-resources ; python_version < \"3.9\"", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"] +test = ["big-O", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more_itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"] type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = "^3.10" -content-hash = "2659005e108122ba58f3de8b027b362c57c7126bd4148ada883b5fa61ccf82ca" +content-hash = "e290dc79dc14e6b1a1698a150a2637eeecc9ca3c4a9d2b6ed47ff2f110a63b79" diff --git a/pyproject.toml b/pyproject.toml index 3a84bbb377..29db516027 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,10 +7,10 @@ requires-poetry = ">=2.0.0" [tool.poetry.dependencies] python = "^3.10" -ops = "^2.20.0" -boto3 = "^1.38.4" +ops = "^2.22.0" +boto3 = "^1.38.33" pgconnstr = "^1.0.1" -requests = "^2.32.3" +requests = "^2.32.4" tenacity = "^9.1.2" psycopg2 = "^2.9.10" pydantic = "^1.10.22" @@ -40,7 +40,7 @@ opentelemetry-exporter-otlp-proto-http = "1.21.0" optional = true [tool.poetry.group.format.dependencies] -ruff = "^0.11.7" +ruff = "^0.11.13" [tool.poetry.group.lint] optional = true @@ -52,27 +52,27 @@ codespell = "^2.4.1" optional = true [tool.poetry.group.unit.dependencies] -coverage = {extras = ["toml"], version = "^7.8.0"} -pytest = "^8.3.5" +coverage = {extras = ["toml"], version = "^7.8.2"} +pytest = "^8.4.0" pytest-asyncio = "*" parameterized = "^0.9.0" -jsonschema = "^4.23.0" +jsonschema = "^4.24.0" [tool.poetry.group.integration] optional = true [tool.poetry.group.integration.dependencies] -pytest = "^8.3.5" +pytest = "^8.4.0" pytest-operator = "^0.42.0" # renovate caret doesn't work: https://github.com/renovatebot/renovate/issues/26940 -juju = "<=3.6.1.1" +juju = "<=3.6.1.2" boto3 = "*" tenacity = "*" landscape-api-py3 = "^0.9.0" mailmanclient = "^3.3.5" psycopg2-binary = "^2.9.10" -allure-pytest = "^2.14.1" -allure-pytest-default-results = "^0.1.2" +allure-pytest = "^2.14.3" +allure-pytest-default-results = "^0.1.3" # Testing tools configuration [tool.coverage.run] From fd4b65e0c82bac9bfaa06d3d642988ccfc414718 Mon Sep 17 00:00:00 2001 From: Andreia Date: Fri, 13 Jun 2025 13:47:24 +0200 Subject: [PATCH 047/112] fix: add forward slash to redirect paths (#964) --- docs/redirects.txt | 164 ++++++++++++++++++++++----------------------- 1 file changed, 82 insertions(+), 82 deletions(-) diff --git a/docs/redirects.txt b/docs/redirects.txt index edb7c5031f..72d254089f 100644 --- a/docs/redirects.txt +++ b/docs/redirects.txt @@ -13,93 +13,93 @@ # redirect/from/file/ redirect/to/file/ # Tutorials -t-set-up tutorial/ -t-deploy tutorial/ -t-access tutorial/ -t-scale tutorial/ -t-manage-passwords tutorial/ -t-integrate tutorial/ -t-enable-tls tutorial/ -t-clean-up tutorial/ +t-set-up/ tutorial/ +t-deploy/ tutorial/ +t-access/ tutorial/ +t-scale/ tutorial/ +t-manage-passwords/ tutorial/ +t-integrate/ tutorial/ +t-enable-tls/ tutorial/ +t-clean-up/ tutorial/ # How-to guides -h-deploy how-to/deploy -h-deploy-sunbeam how-to/deploy/sunbeam -h-deploy-maas how-to/deploy/maas -h-deploy-ec2 how-to/deploy/aws-ec2 -h-deploy-gce how-to/deploy/gce -h-deploy-azure how-to/deploy/azure -h-deploy-multi-az how-to/deploy/multi-az -h-deploy-tls-vip-access how-to/deploy/tls-vip-access -h-deploy-terraform how-to/deploy/terraform -h-deploy-airgapped how-to/deploy/air-gapped -h-deploy-juju-storage how-to/deploy/juju-storage - -h-integrate how-to/integrate-with-another-application -h-manage-passwords how-to/manage-passwords -h-external-access how-to/external-network-access -h-scale how-to/scale-replicas -h-switchover-failover how-to/switchover-failover -h-enable-tls how-to/enable-tls -h-enable-ldap how-to/enable-ldap - -h-enable-plugins-extensions how-to/enable-plugins-extensions -h-plugins-timescaledb how-to/enable-plugins-extensions/enable-timescaledb - -h-backup how-to/back-up-and-restore/ -h-configure-s3-aws how-to/back-up-and-restore/configure-s3-aws -h-configure-s3-radosgw how-to/back-up-and-restore/configure-s3-radosgw -h-create-backup how-to/back-up-and-restore/create-a-backup -h-restore-backup how-to/back-up-and-restore/restore-a-backup -h-manage-backup-retention how-to/back-up-and-restore/manage-backup-retention -h-migrate-cluster how-to/back-up-and-restore/migrate-a-cluster - -h-monitor how-to/monitoring-cos/ -h-enable-monitoring how-to/monitoring-cos/enable-monitoring -h-enable-alert-rules how-to/monitoring-cos/enable-alert-rules -h-enable-tracing how-to/monitoring-cos/enable-tracing -h-enable-profiling how-to/monitoring-cos/enable-profiling - -h-upgrade how-to/upgrade/ -h-upgrade-minor how-to/upgrade/perform-a-minor-upgrade -h-rollback-minor how-to/upgrade/perform-a-minor-rollback - -h-async how-to/cross-regional-async-replication/ -h-async-set-up how-to/cross-regional-async-replication/set-up-clusters -h-async-integrate how-to/cross-regional-async-replication/integrate-with-a-client-app -h-async-remove-recover how-to/cross-regional-async-replication/remove-or-recover-a-cluster - -h-development how-to/development/ -h-development-integrate how-to/development/integrate-with-your-charm -h-migrate-pgdump how-to/development/migrate-data-via-pg-dump -h-migrate-backup-restore how-to/development/migrate-data-via-backup-restore +h-deploy/ how-to/deploy +h-deploy-sunbeam/ how-to/deploy/sunbeam +h-deploy-maas/ how-to/deploy/maas +h-deploy-ec2/ how-to/deploy/aws-ec2 +h-deploy-gce/ how-to/deploy/gce +h-deploy-azure/ how-to/deploy/azure +h-deploy-multi-az/ how-to/deploy/multi-az +h-deploy-tls-vip-access/ how-to/deploy/tls-vip-access +h-deploy-terraform/ how-to/deploy/terraform +h-deploy-airgapped/ how-to/deploy/air-gapped +h-deploy-juju-storage/ how-to/deploy/juju-storage + +h-integrate/ how-to/integrate-with-another-application +h-manage-passwords/ how-to/manage-passwords +h-external-access/ how-to/external-network-access +h-scale/ how-to/scale-replicas +h-switchover-failover/ how-to/switchover-failover +h-enable-tls/ how-to/enable-tls +h-enable-ldap/ how-to/enable-ldap + +h-enable-plugins-extensions/ how-to/enable-plugins-extensions +h-plugins-timescaledb/ how-to/enable-plugins-extensions/enable-timescaledb + +h-backup/ how-to/back-up-and-restore/ +h-configure-s3-aws/ how-to/back-up-and-restore/configure-s3-aws +h-configure-s3-radosgw/ how-to/back-up-and-restore/configure-s3-radosgw +h-create-backup/ how-to/back-up-and-restore/create-a-backup +h-restore-backup/ how-to/back-up-and-restore/restore-a-backup +h-manage-backup-retention/ how-to/back-up-and-restore/manage-backup-retention +h-migrate-cluster/ how-to/back-up-and-restore/migrate-a-cluster + +h-monitor/ how-to/monitoring-cos/ +h-enable-monitoring/ how-to/monitoring-cos/enable-monitoring +h-enable-alert-rules/ how-to/monitoring-cos/enable-alert-rules +h-enable-tracing/ how-to/monitoring-cos/enable-tracing +h-enable-profiling/ how-to/monitoring-cos/enable-profiling + +h-upgrade/ how-to/upgrade/ +h-upgrade-minor/ how-to/upgrade/perform-a-minor-upgrade +h-rollback-minor/ how-to/upgrade/perform-a-minor-rollback + +h-async/ how-to/cross-regional-async-replication/ +h-async-set-up/ how-to/cross-regional-async-replication/set-up-clusters +h-async-integrate/ how-to/cross-regional-async-replication/integrate-with-a-client-app +h-async-remove-recover/ how-to/cross-regional-async-replication/remove-or-recover-a-cluster + +h-development/ how-to/development/ +h-development-integrate/ how-to/development/integrate-with-your-charm +h-migrate-pgdump/ how-to/development/migrate-data-via-pg-dump +h-migrate-backup-restore/ how-to/development/migrate-data-via-backup-restore # Reference -r-releases reference/releases -r-versions reference/versions -r-system-requirements reference/system-requirements -r-software-testing reference/software-testing -r-performance reference/performance-and-resources +r-releases/ reference/releases +r-versions/ reference/versions +r-system-requirements/ reference/system-requirements +r-software-testing/ reference/software-testing +r-performance/ reference/performance-and-resources -r-troubleshooting reference/troubleshooting/ -r-sos-report reference/troubleshooting/sos-report -r-cli-helpers reference/troubleshooting/cli-helpers +r-troubleshooting/ reference/troubleshooting/ +r-sos-report/ reference/troubleshooting/sos-report +r-cli-helpers/ reference/troubleshooting/cli-helpers -r-plugins-extensions reference/plugins-extensions -r-alert-rules reference/alert-rules -r-statuses reference/statuses -r-contacts reference/contacts +r-plugins-extensions/ reference/plugins-extensions +r-alert-rules/ reference/alert-rules +r-statuses/ reference/statuses +r-contacts/ reference/contacts # Explanation -e-architecture explanation/architecture -e-interfaces-endpoints explanation/interfaces-and-endpoints -e-juju-details explanation/juju -e-legacy-charm explanation/legacy-charm -e-units explanation/units -e-users explanation/users -e-roles explanation/roles -e-logs explanation/logs -e-connection-pooling explanation/connection-pooling - -e-security explanation/security/ -e-cryptography explanation/security/cryptography \ No newline at end of file +e-architecture/ explanation/architecture +e-interfaces-endpoints/ explanation/interfaces-and-endpoints +e-juju-details/ explanation/juju +e-legacy-charm/ explanation/legacy-charm +e-units/ explanation/units +e-users/ explanation/users +e-roles/ explanation/roles +e-logs/ explanation/logs +e-connection-pooling/ explanation/connection-pooling + +e-security/ explanation/security/ +e-cryptography/ explanation/security/cryptography \ No newline at end of file From e166a1187bd9b9e9409b98973933a3edd8f506f8 Mon Sep 17 00:00:00 2001 From: Mykola Marzhan <303592+delgod@users.noreply.github.com> Date: Fri, 13 Jun 2025 15:49:29 +0200 Subject: [PATCH 048/112] fix typo (#965) --- docs/explanation/users.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/explanation/users.md b/docs/explanation/users.md index 69e15a0c1b..890092aff3 100644 --- a/docs/explanation/users.md +++ b/docs/explanation/users.md @@ -108,7 +108,7 @@ juju relate postgresql myclientapp When an application charm requests a new user through the relation/integration it can specify that the user should have the `admin` role in the `extra-user-roles` field. The `admin` role enables the new user to read and write to all databases (for the `postgres` system database it can only read data) and also to create and delete non-system databases. ```{note} -`extra-user-roles` is only supported by the modern interface `postgresql_client`. It is not supported for the legacy `pgsql` interface. R +`extra-user-roles` is only supported by the modern interface `postgresql_client`. It is not supported for the legacy `pgsql` interface. Read more about the supported charm interfaces in [](/explanation/interfaces-and-endpoints). ``` From 526939f89cc291b27b9464a5664f965d6353a43a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 16 Jun 2025 01:51:53 +0300 Subject: [PATCH 049/112] Update dependency uv to v0.7.13 (#951) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- charmcraft.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charmcraft.yaml b/charmcraft.yaml index f183aa2d69..39b78b5174 100644 --- a/charmcraft.yaml +++ b/charmcraft.yaml @@ -27,7 +27,7 @@ parts: PIP_BREAK_SYSTEM_PACKAGES=true python3 -m pip install --user --upgrade pip==25.1.1 # renovate: charmcraft-pip-latest # Use uv to install poetry so that a newer version of Python can be installed if needed by poetry - curl --proto '=https' --tlsv1.2 -LsSf https://github.com/astral-sh/uv/releases/download/0.7.9/uv-installer.sh | sh # renovate: charmcraft-uv-latest + curl --proto '=https' --tlsv1.2 -LsSf https://github.com/astral-sh/uv/releases/download/0.7.13/uv-installer.sh | sh # renovate: charmcraft-uv-latest # poetry 2.0.0 requires Python >=3.9 if ! "$HOME/.local/bin/uv" python find '>=3.9' then From 26035442dc6a90927b41c20495e14b83747678b4 Mon Sep 17 00:00:00 2001 From: Dragomir Penev <6687393+dragomirp@users.noreply.github.com> Date: Tue, 17 Jun 2025 15:12:16 +0300 Subject: [PATCH 050/112] Rename team (#972) --- .github/renovate.json5 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/renovate.json5 b/.github/renovate.json5 index cd60ef68a5..c69f3357cb 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -4,7 +4,7 @@ 'github>canonical/data-platform//renovate_presets/charm.json5', ], reviewers: [ - 'team:data-platform-postgresql', + 'team:data-postgresql', ], "baseBranches": ["main", "/^*\\/edge$/"], packageRules: [ From 06228cb1a68d33a80d9831c227a96dc7b7d19134 Mon Sep 17 00:00:00 2001 From: Dragomir Penev <6687393+dragomirp@users.noreply.github.com> Date: Wed, 18 Jun 2025 16:53:00 +0300 Subject: [PATCH 051/112] [MISC] Check is_user_in_hba output (#973) * Check is_user_in_hba output * Drop extra parameter --- lib/charms/postgresql_k8s/v0/postgresql.py | 5 ++++- src/relations/postgresql_provider.py | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/charms/postgresql_k8s/v0/postgresql.py b/lib/charms/postgresql_k8s/v0/postgresql.py index 1c73959a37..54453a3623 100644 --- a/lib/charms/postgresql_k8s/v0/postgresql.py +++ b/lib/charms/postgresql_k8s/v0/postgresql.py @@ -35,7 +35,7 @@ # Increment this PATCH version before using `charmcraft publish-lib` or reset # to 0 if you are raising the major API version -LIBPATCH = 56 +LIBPATCH = 53 # Groups to distinguish HBA access ACCESS_GROUP_IDENTITY = "identity_access" @@ -780,6 +780,7 @@ def list_valid_privileges_and_roles(self) -> Tuple[Set[str], Set[str]]: def set_up_database(self) -> None: """Set up postgres database with the right permissions.""" connection = None + cursor = None try: with self._connect_to_database( database="template1" @@ -879,6 +880,8 @@ def set_up_database(self) -> None: logger.error(f"Failed to set up databases: {e}") raise PostgreSQLDatabasesSetupError() from e finally: + if cursor is not None: + cursor.close() if connection is not None: connection.close() diff --git a/src/relations/postgresql_provider.py b/src/relations/postgresql_provider.py index 1734d4f047..844da3b6f9 100644 --- a/src/relations/postgresql_provider.py +++ b/src/relations/postgresql_provider.py @@ -148,7 +148,8 @@ def _on_database_requested(self, event: DatabaseRequestedEvent) -> None: try: for attempt in Retrying(stop=stop_after_attempt(3), wait=wait_fixed(1)): with attempt: - self.charm.postgresql.is_user_in_hba(user) + if not self.charm.postgresql.is_user_in_hba(user): + raise Exception("pg_hba not ready") self.charm.unit_peer_data.update({ "pg_hba_needs_update_timestamp": str(datetime.now()) }) From 81e79b9080f3b359e1edc204b64755f02fde70ff Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 21 Jun 2025 05:26:49 +0300 Subject: [PATCH 052/112] Update canonical/data-platform-workflows action to v32 (main) (#873) * Update canonical/data-platform-workflows action to v32 * Update libs and release flow --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Dragomir Penev --- .github/workflows/approve_renovate_pr.yaml | 2 +- .github/workflows/check_pr.yaml | 2 +- .github/workflows/ci.yaml | 4 +- .github/workflows/promote.yaml | 2 +- .github/workflows/release.yaml | 4 +- lib/charms/data_platform_libs/v0/upgrade.py | 4 +- lib/charms/operator_libs_linux/v2/snap.py | 50 ++++++++++++++------- 7 files changed, 43 insertions(+), 25 deletions(-) diff --git a/.github/workflows/approve_renovate_pr.yaml b/.github/workflows/approve_renovate_pr.yaml index 88030ca0b0..102a832cc3 100644 --- a/.github/workflows/approve_renovate_pr.yaml +++ b/.github/workflows/approve_renovate_pr.yaml @@ -10,6 +10,6 @@ on: jobs: approve-pr: name: Approve Renovate pull request - uses: canonical/data-platform-workflows/.github/workflows/approve_renovate_pr.yaml@v31.1.1 + uses: canonical/data-platform-workflows/.github/workflows/approve_renovate_pr.yaml@v32.1.0 permissions: pull-requests: write # Needed to approve PR diff --git a/.github/workflows/check_pr.yaml b/.github/workflows/check_pr.yaml index 5ed03d4774..a12b5edbea 100644 --- a/.github/workflows/check_pr.yaml +++ b/.github/workflows/check_pr.yaml @@ -16,4 +16,4 @@ on: jobs: check-pr: name: Check pull request - uses: canonical/data-platform-workflows/.github/workflows/check_charm_pr.yaml@v31.1.1 + uses: canonical/data-platform-workflows/.github/workflows/check_charm_pr.yaml@v32.1.0 diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 4c2e86edcd..c51315e37d 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -27,7 +27,7 @@ on: jobs: lint: name: Lint - uses: canonical/data-platform-workflows/.github/workflows/lint.yaml@v31.1.1 + uses: canonical/data-platform-workflows/.github/workflows/lint.yaml@v32.1.0 unit-test: name: Unit test charm @@ -49,7 +49,7 @@ jobs: build: name: Build charm - uses: canonical/data-platform-workflows/.github/workflows/build_charm.yaml@v31.1.1 + uses: canonical/data-platform-workflows/.github/workflows/build_charm.yaml@v32.1.0 integration-test: name: Integration test charm diff --git a/.github/workflows/promote.yaml b/.github/workflows/promote.yaml index ef229520fd..9df0cbdebd 100644 --- a/.github/workflows/promote.yaml +++ b/.github/workflows/promote.yaml @@ -25,7 +25,7 @@ on: jobs: promote: name: Promote charm - uses: canonical/data-platform-workflows/.github/workflows/_promote_charm.yaml@v31.1.1 + uses: canonical/data-platform-workflows/.github/workflows/_promote_charm.yaml@v32.1.0 with: track: '14' from-risk: ${{ inputs.from-risk }} diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 04ecfeff0f..cf7c6d1727 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -27,9 +27,9 @@ jobs: name: Release charm needs: - ci-tests - uses: canonical/data-platform-workflows/.github/workflows/release_charm.yaml@v31.1.1 + uses: canonical/data-platform-workflows/.github/workflows/release_charm_edge.yaml@v32.1.0 with: - channel: 14/edge + track: 14 artifact-prefix: ${{ needs.ci-tests.outputs.artifact-prefix }} secrets: charmhub-token: ${{ secrets.CHARMHUB_TOKEN }} diff --git a/lib/charms/data_platform_libs/v0/upgrade.py b/lib/charms/data_platform_libs/v0/upgrade.py index 4d909d644d..5d051e9b5c 100644 --- a/lib/charms/data_platform_libs/v0/upgrade.py +++ b/lib/charms/data_platform_libs/v0/upgrade.py @@ -285,7 +285,7 @@ def restart(self, event) -> None: # Increment this PATCH version before using `charmcraft publish-lib` or reset # to 0 if you are raising the major API version -LIBPATCH = 18 +LIBPATCH = 19 PYDEPS = ["pydantic>=1.10,<2", "poetry-core"] @@ -929,7 +929,7 @@ def _on_upgrade_charm(self, event: UpgradeCharmEvent) -> None: # for k8s run version checks only on highest ordinal unit if ( self.charm.unit.name - == f"{self.charm.app.name}/{self.charm.app.planned_units() -1}" + == f"{self.charm.app.name}/{self.charm.app.planned_units() - 1}" ): try: self._upgrade_supported_check() diff --git a/lib/charms/operator_libs_linux/v2/snap.py b/lib/charms/operator_libs_linux/v2/snap.py index 3623d1db2c..b0d65017e8 100644 --- a/lib/charms/operator_libs_linux/v2/snap.py +++ b/lib/charms/operator_libs_linux/v2/snap.py @@ -87,7 +87,7 @@ if typing.TYPE_CHECKING: # avoid typing_extensions import at runtime - from typing_extensions import NotRequired, ParamSpec, Required, TypeAlias, Unpack + from typing_extensions import NotRequired, ParamSpec, Required, Self, TypeAlias, Unpack _P = ParamSpec("_P") _T = TypeVar("_T") @@ -102,7 +102,7 @@ # Increment this PATCH version before using `charmcraft publish-lib` or reset # to 0 if you are raising the major API version -LIBPATCH = 11 +LIBPATCH = 12 # Regex to locate 7-bit C1 ANSI sequences @@ -268,6 +268,22 @@ class SnapState(Enum): class SnapError(Error): """Raised when there's an error running snap control commands.""" + @classmethod + def _from_called_process_error(cls, msg: str, error: CalledProcessError) -> Self: + lines = [msg] + if error.stdout: + lines.extend(['Stdout:', error.stdout]) + if error.stderr: + lines.extend(['Stderr:', error.stderr]) + try: + cmd = ['journalctl', '--unit', 'snapd', '--lines', '20'] + logs = subprocess.check_output(cmd, text=True) + except Exception as e: + lines.extend(['Error fetching logs:', str(e)]) + else: + lines.extend(['Latest logs:', logs]) + return cls('\n'.join(lines)) + class SnapNotFoundError(Error): """Raised when a requested snap is not known to the system.""" @@ -340,11 +356,10 @@ def _snap(self, command: str, optargs: Iterable[str] | None = None) -> str: optargs = optargs or [] args = ["snap", command, self._name, *optargs] try: - return subprocess.check_output(args, text=True) + return subprocess.check_output(args, text=True, stderr=subprocess.PIPE) except CalledProcessError as e: - raise SnapError( - f"Snap: {self._name!r}; command {args!r} failed with output = {e.output!r}" - ) from e + msg = f'Snap: {self._name!r} -- command {args!r} failed!' + raise SnapError._from_called_process_error(msg=msg, error=e) from e def _snap_daemons( self, @@ -371,7 +386,8 @@ def _snap_daemons( try: return subprocess.run(args, text=True, check=True, capture_output=True) except CalledProcessError as e: - raise SnapError(f"Could not {args} for snap [{self._name}]: {e.stderr}") from e + msg = f'Snap: {self._name!r} -- command {args!r} failed!' + raise SnapError._from_called_process_error(msg=msg, error=e) from e @typing.overload def get(self, key: None | Literal[""], *, typed: Literal[False] = False) -> NoReturn: ... @@ -477,7 +493,8 @@ def connect(self, plug: str, service: str | None = None, slot: str | None = None try: subprocess.run(args, text=True, check=True, capture_output=True) except CalledProcessError as e: - raise SnapError(f"Could not {args} for snap [{self._name}]: {e.stderr}") from e + msg = f'Snap: {self._name!r} -- command {args!r} failed!' + raise SnapError._from_called_process_error(msg=msg, error=e) from e def hold(self, duration: timedelta | None = None) -> None: """Add a refresh hold to a snap. @@ -506,11 +523,10 @@ def alias(self, application: str, alias: str | None = None) -> None: alias = application args = ["snap", "alias", f"{self.name}.{application}", alias] try: - subprocess.check_output(args, text=True) + subprocess.run(args, text=True, check=True, capture_output=True) except CalledProcessError as e: - raise SnapError( - f"Snap: {self._name!r}; command {args!r} failed with output = {e.output!r}" - ) from e + msg = f'Snap: {self._name!r} -- command {args!r} failed!' + raise SnapError._from_called_process_error(msg=msg, error=e) from e def restart(self, services: list[str] | None = None, reload: bool = False) -> None: """Restarts a snap's services. @@ -1264,7 +1280,7 @@ def install_local( if dangerous: args.append("--dangerous") try: - result = subprocess.check_output(args, text=True).splitlines()[-1] + result = subprocess.check_output(args, text=True, stderr=subprocess.PIPE).splitlines()[-1] snap_name, _ = result.split(" ", 1) snap_name = ansi_filter.sub("", snap_name) @@ -1280,7 +1296,8 @@ def install_local( ) raise SnapError(f"Failed to find snap {snap_name} in Snap cache") from e except CalledProcessError as e: - raise SnapError(f"Could not install snap {filename}: {e.output}") from e + msg = f'Cound not install snap {filename}!' + raise SnapError._from_called_process_error(msg=msg, error=e) from e def _system_set(config_item: str, value: str) -> None: @@ -1292,9 +1309,10 @@ def _system_set(config_item: str, value: str) -> None: """ args = ["snap", "set", "system", f"{config_item}={value}"] try: - subprocess.check_call(args, text=True) + subprocess.run(args, text=True, check=True, capture_output=True) except CalledProcessError as e: - raise SnapError(f"Failed setting system config '{config_item}' to '{value}'") from e + msg = f"Failed setting system config '{config_item}' to '{value}'" + raise SnapError._from_called_process_error(msg=msg, error=e) from e def hold_refresh(days: int = 90, forever: bool = False) -> None: From 33ca7f308fa4289cdf45ceefcb335f373713431d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 22 Jun 2025 01:22:22 +0300 Subject: [PATCH 053/112] Lock file maintenance Python dependencies (#976) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- poetry.lock | 218 ++++++++++++++++++++++++------------------------- pyproject.toml | 10 +-- 2 files changed, 114 insertions(+), 114 deletions(-) diff --git a/poetry.lock b/poetry.lock index fcf8535e03..4f46e32e15 100644 --- a/poetry.lock +++ b/poetry.lock @@ -233,18 +233,18 @@ typecheck = ["mypy"] [[package]] name = "boto3" -version = "1.38.33" +version = "1.38.41" description = "The AWS SDK for Python" optional = false python-versions = ">=3.9" groups = ["main", "integration"] files = [ - {file = "boto3-1.38.33-py3-none-any.whl", hash = "sha256:25d0717489c658f7ae6c3c7f0f7e1b4d611b30b2f08f0fcef6455ac6864a8768"}, - {file = "boto3-1.38.33.tar.gz", hash = "sha256:6467909c1ae01ff67981f021bb2568592211765ec8a9a1d2c4529191e46c3541"}, + {file = "boto3-1.38.41-py3-none-any.whl", hash = "sha256:6119e9f272b9f004f052ca78ce94d3fe10198bc159ae808f75c0e1b9c07518bd"}, + {file = "boto3-1.38.41.tar.gz", hash = "sha256:c6710fc533c8e1f5d1f025c74ffe1222c3659094cd51c076ec50c201a54c8f22"}, ] [package.dependencies] -botocore = ">=1.38.33,<1.39.0" +botocore = ">=1.38.41,<1.39.0" jmespath = ">=0.7.1,<2.0.0" s3transfer = ">=0.13.0,<0.14.0" @@ -253,14 +253,14 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.38.33" +version = "1.38.41" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">=3.9" groups = ["main", "integration"] files = [ - {file = "botocore-1.38.33-py3-none-any.whl", hash = "sha256:ad25233e93dcebe95809b1f9393c1f11a639696327793d166295fb78dd7bc597"}, - {file = "botocore-1.38.33.tar.gz", hash = "sha256:dbe8fea9d0426c644c89ef2018ead886ccbcc22901a02b377b4e65ce1cb69a2b"}, + {file = "botocore-1.38.41-py3-none-any.whl", hash = "sha256:06069a06f1352accb1f6c9505d6e323753627112be80a9d2e057c6d9c9779ffd"}, + {file = "botocore-1.38.41.tar.gz", hash = "sha256:98e3fed636ebb519320c4b2d078db6fa6099b052b4bb9b5c66632a5a7fe72507"}, ] [package.dependencies] @@ -285,14 +285,14 @@ files = [ [[package]] name = "certifi" -version = "2025.4.26" +version = "2025.6.15" description = "Python package for providing Mozilla's CA Bundle." optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" groups = ["main", "charm-libs", "integration"] files = [ - {file = "certifi-2025.4.26-py3-none-any.whl", hash = "sha256:30350364dfe371162649852c63336a15c70c6510c2ad5015b21c2345311805f3"}, - {file = "certifi-2025.4.26.tar.gz", hash = "sha256:0a816057ea3cdefcef70270d2c515e4506bbc954f417fa5ade2021213bb8f0c6"}, + {file = "certifi-2025.6.15-py3-none-any.whl", hash = "sha256:2e0c7ce7cb5d8f8634ca55d2ba7e6ec2689a2fd6537d8dec1296a477a4910057"}, + {file = "certifi-2025.6.15.tar.gz", hash = "sha256:d747aa5a8b9bbbb1bb8c22bb13e22bd1f18e9796defa16bab421f7f7a317323b"}, ] [[package]] @@ -530,79 +530,79 @@ typing-extensions = "*" [[package]] name = "coverage" -version = "7.8.2" +version = "7.9.1" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.9" groups = ["unit"] files = [ - {file = "coverage-7.8.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bd8ec21e1443fd7a447881332f7ce9d35b8fbd2849e761bb290b584535636b0a"}, - {file = "coverage-7.8.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4c26c2396674816deaeae7ded0e2b42c26537280f8fe313335858ffff35019be"}, - {file = "coverage-7.8.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1aec326ed237e5880bfe69ad41616d333712c7937bcefc1343145e972938f9b3"}, - {file = "coverage-7.8.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5e818796f71702d7a13e50c70de2a1924f729228580bcba1607cccf32eea46e6"}, - {file = "coverage-7.8.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:546e537d9e24efc765c9c891328f30f826e3e4808e31f5d0f87c4ba12bbd1622"}, - {file = "coverage-7.8.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ab9b09a2349f58e73f8ebc06fac546dd623e23b063e5398343c5270072e3201c"}, - {file = "coverage-7.8.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fd51355ab8a372d89fb0e6a31719e825cf8df8b6724bee942fb5b92c3f016ba3"}, - {file = "coverage-7.8.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0774df1e093acb6c9e4d58bce7f86656aeed6c132a16e2337692c12786b32404"}, - {file = "coverage-7.8.2-cp310-cp310-win32.whl", hash = "sha256:00f2e2f2e37f47e5f54423aeefd6c32a7dbcedc033fcd3928a4f4948e8b96af7"}, - {file = "coverage-7.8.2-cp310-cp310-win_amd64.whl", hash = "sha256:145b07bea229821d51811bf15eeab346c236d523838eda395ea969d120d13347"}, - {file = "coverage-7.8.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b99058eef42e6a8dcd135afb068b3d53aff3921ce699e127602efff9956457a9"}, - {file = "coverage-7.8.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5feb7f2c3e6ea94d3b877def0270dff0947b8d8c04cfa34a17be0a4dc1836879"}, - {file = "coverage-7.8.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:670a13249b957bb9050fab12d86acef7bf8f6a879b9d1a883799276e0d4c674a"}, - {file = "coverage-7.8.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0bdc8bf760459a4a4187b452213e04d039990211f98644c7292adf1e471162b5"}, - {file = "coverage-7.8.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07a989c867986c2a75f158f03fdb413128aad29aca9d4dbce5fc755672d96f11"}, - {file = "coverage-7.8.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2db10dedeb619a771ef0e2949ccba7b75e33905de959c2643a4607bef2f3fb3a"}, - {file = "coverage-7.8.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e6ea7dba4e92926b7b5f0990634b78ea02f208d04af520c73a7c876d5a8d36cb"}, - {file = "coverage-7.8.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ef2f22795a7aca99fc3c84393a55a53dd18ab8c93fb431004e4d8f0774150f54"}, - {file = "coverage-7.8.2-cp311-cp311-win32.whl", hash = "sha256:641988828bc18a6368fe72355df5f1703e44411adbe49bba5644b941ce6f2e3a"}, - {file = "coverage-7.8.2-cp311-cp311-win_amd64.whl", hash = "sha256:8ab4a51cb39dc1933ba627e0875046d150e88478dbe22ce145a68393e9652975"}, - {file = "coverage-7.8.2-cp311-cp311-win_arm64.whl", hash = "sha256:8966a821e2083c74d88cca5b7dcccc0a3a888a596a04c0b9668a891de3a0cc53"}, - {file = "coverage-7.8.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e2f6fe3654468d061942591aef56686131335b7a8325684eda85dacdf311356c"}, - {file = "coverage-7.8.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:76090fab50610798cc05241bf83b603477c40ee87acd358b66196ab0ca44ffa1"}, - {file = "coverage-7.8.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2bd0a0a5054be160777a7920b731a0570284db5142abaaf81bcbb282b8d99279"}, - {file = "coverage-7.8.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:da23ce9a3d356d0affe9c7036030b5c8f14556bd970c9b224f9c8205505e3b99"}, - {file = "coverage-7.8.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9392773cffeb8d7e042a7b15b82a414011e9d2b5fdbbd3f7e6a6b17d5e21b20"}, - {file = "coverage-7.8.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:876cbfd0b09ce09d81585d266c07a32657beb3eaec896f39484b631555be0fe2"}, - {file = "coverage-7.8.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3da9b771c98977a13fbc3830f6caa85cae6c9c83911d24cb2d218e9394259c57"}, - {file = "coverage-7.8.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9a990f6510b3292686713bfef26d0049cd63b9c7bb17e0864f133cbfd2e6167f"}, - {file = "coverage-7.8.2-cp312-cp312-win32.whl", hash = "sha256:bf8111cddd0f2b54d34e96613e7fbdd59a673f0cf5574b61134ae75b6f5a33b8"}, - {file = "coverage-7.8.2-cp312-cp312-win_amd64.whl", hash = "sha256:86a323a275e9e44cdf228af9b71c5030861d4d2610886ab920d9945672a81223"}, - {file = "coverage-7.8.2-cp312-cp312-win_arm64.whl", hash = "sha256:820157de3a589e992689ffcda8639fbabb313b323d26388d02e154164c57b07f"}, - {file = "coverage-7.8.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ea561010914ec1c26ab4188aef8b1567272ef6de096312716f90e5baa79ef8ca"}, - {file = "coverage-7.8.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cb86337a4fcdd0e598ff2caeb513ac604d2f3da6d53df2c8e368e07ee38e277d"}, - {file = "coverage-7.8.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26a4636ddb666971345541b59899e969f3b301143dd86b0ddbb570bd591f1e85"}, - {file = "coverage-7.8.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5040536cf9b13fb033f76bcb5e1e5cb3b57c4807fef37db9e0ed129c6a094257"}, - {file = "coverage-7.8.2-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc67994df9bcd7e0150a47ef41278b9e0a0ea187caba72414b71dc590b99a108"}, - {file = "coverage-7.8.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6e6c86888fd076d9e0fe848af0a2142bf606044dc5ceee0aa9eddb56e26895a0"}, - {file = "coverage-7.8.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:684ca9f58119b8e26bef860db33524ae0365601492e86ba0b71d513f525e7050"}, - {file = "coverage-7.8.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8165584ddedb49204c4e18da083913bdf6a982bfb558632a79bdaadcdafd0d48"}, - {file = "coverage-7.8.2-cp313-cp313-win32.whl", hash = "sha256:34759ee2c65362163699cc917bdb2a54114dd06d19bab860725f94ef45a3d9b7"}, - {file = "coverage-7.8.2-cp313-cp313-win_amd64.whl", hash = "sha256:2f9bc608fbafaee40eb60a9a53dbfb90f53cc66d3d32c2849dc27cf5638a21e3"}, - {file = "coverage-7.8.2-cp313-cp313-win_arm64.whl", hash = "sha256:9fe449ee461a3b0c7105690419d0b0aba1232f4ff6d120a9e241e58a556733f7"}, - {file = "coverage-7.8.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:8369a7c8ef66bded2b6484053749ff220dbf83cba84f3398c84c51a6f748a008"}, - {file = "coverage-7.8.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:159b81df53a5fcbc7d45dae3adad554fdbde9829a994e15227b3f9d816d00b36"}, - {file = "coverage-7.8.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e6fcbbd35a96192d042c691c9e0c49ef54bd7ed865846a3c9d624c30bb67ce46"}, - {file = "coverage-7.8.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:05364b9cc82f138cc86128dc4e2e1251c2981a2218bfcd556fe6b0fbaa3501be"}, - {file = "coverage-7.8.2-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46d532db4e5ff3979ce47d18e2fe8ecad283eeb7367726da0e5ef88e4fe64740"}, - {file = "coverage-7.8.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4000a31c34932e7e4fa0381a3d6deb43dc0c8f458e3e7ea6502e6238e10be625"}, - {file = "coverage-7.8.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:43ff5033d657cd51f83015c3b7a443287250dc14e69910577c3e03bd2e06f27b"}, - {file = "coverage-7.8.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:94316e13f0981cbbba132c1f9f365cac1d26716aaac130866ca812006f662199"}, - {file = "coverage-7.8.2-cp313-cp313t-win32.whl", hash = "sha256:3f5673888d3676d0a745c3d0e16da338c5eea300cb1f4ada9c872981265e76d8"}, - {file = "coverage-7.8.2-cp313-cp313t-win_amd64.whl", hash = "sha256:2c08b05ee8d7861e45dc5a2cc4195c8c66dca5ac613144eb6ebeaff2d502e73d"}, - {file = "coverage-7.8.2-cp313-cp313t-win_arm64.whl", hash = "sha256:1e1448bb72b387755e1ff3ef1268a06617afd94188164960dba8d0245a46004b"}, - {file = "coverage-7.8.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:496948261eaac5ac9cf43f5d0a9f6eb7a6d4cb3bedb2c5d294138142f5c18f2a"}, - {file = "coverage-7.8.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:eacd2de0d30871eff893bab0b67840a96445edcb3c8fd915e6b11ac4b2f3fa6d"}, - {file = "coverage-7.8.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b039ffddc99ad65d5078ef300e0c7eed08c270dc26570440e3ef18beb816c1ca"}, - {file = "coverage-7.8.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0e49824808d4375ede9dd84e9961a59c47f9113039f1a525e6be170aa4f5c34d"}, - {file = "coverage-7.8.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b069938961dfad881dc2f8d02b47645cd2f455d3809ba92a8a687bf513839787"}, - {file = "coverage-7.8.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:de77c3ba8bb686d1c411e78ee1b97e6e0b963fb98b1637658dd9ad2c875cf9d7"}, - {file = "coverage-7.8.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1676628065a498943bd3f64f099bb573e08cf1bc6088bbe33cf4424e0876f4b3"}, - {file = "coverage-7.8.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:8e1a26e7e50076e35f7afafde570ca2b4d7900a491174ca357d29dece5aacee7"}, - {file = "coverage-7.8.2-cp39-cp39-win32.whl", hash = "sha256:6782a12bf76fa61ad9350d5a6ef5f3f020b57f5e6305cbc663803f2ebd0f270a"}, - {file = "coverage-7.8.2-cp39-cp39-win_amd64.whl", hash = "sha256:1efa4166ba75ccefd647f2d78b64f53f14fb82622bc94c5a5cb0a622f50f1c9e"}, - {file = "coverage-7.8.2-pp39.pp310.pp311-none-any.whl", hash = "sha256:ec455eedf3ba0bbdf8f5a570012617eb305c63cb9f03428d39bf544cb2b94837"}, - {file = "coverage-7.8.2-py3-none-any.whl", hash = "sha256:726f32ee3713f7359696331a18daf0c3b3a70bb0ae71141b9d3c52be7c595e32"}, - {file = "coverage-7.8.2.tar.gz", hash = "sha256:a886d531373a1f6ff9fad2a2ba4a045b68467b779ae729ee0b3b10ac20033b27"}, + {file = "coverage-7.9.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cc94d7c5e8423920787c33d811c0be67b7be83c705f001f7180c7b186dcf10ca"}, + {file = "coverage-7.9.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:16aa0830d0c08a2c40c264cef801db8bc4fc0e1892782e45bcacbd5889270509"}, + {file = "coverage-7.9.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf95981b126f23db63e9dbe4cf65bd71f9a6305696fa5e2262693bc4e2183f5b"}, + {file = "coverage-7.9.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f05031cf21699785cd47cb7485f67df619e7bcdae38e0fde40d23d3d0210d3c3"}, + {file = "coverage-7.9.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb4fbcab8764dc072cb651a4bcda4d11fb5658a1d8d68842a862a6610bd8cfa3"}, + {file = "coverage-7.9.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0f16649a7330ec307942ed27d06ee7e7a38417144620bb3d6e9a18ded8a2d3e5"}, + {file = "coverage-7.9.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:cea0a27a89e6432705fffc178064503508e3c0184b4f061700e771a09de58187"}, + {file = "coverage-7.9.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e980b53a959fa53b6f05343afbd1e6f44a23ed6c23c4b4c56c6662bbb40c82ce"}, + {file = "coverage-7.9.1-cp310-cp310-win32.whl", hash = "sha256:70760b4c5560be6ca70d11f8988ee6542b003f982b32f83d5ac0b72476607b70"}, + {file = "coverage-7.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:a66e8f628b71f78c0e0342003d53b53101ba4e00ea8dabb799d9dba0abbbcebe"}, + {file = "coverage-7.9.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:95c765060e65c692da2d2f51a9499c5e9f5cf5453aeaf1420e3fc847cc060582"}, + {file = "coverage-7.9.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ba383dc6afd5ec5b7a0d0c23d38895db0e15bcba7fb0fa8901f245267ac30d86"}, + {file = "coverage-7.9.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:37ae0383f13cbdcf1e5e7014489b0d71cc0106458878ccde52e8a12ced4298ed"}, + {file = "coverage-7.9.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:69aa417a030bf11ec46149636314c24c8d60fadb12fc0ee8f10fda0d918c879d"}, + {file = "coverage-7.9.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a4be2a28656afe279b34d4f91c3e26eccf2f85500d4a4ff0b1f8b54bf807338"}, + {file = "coverage-7.9.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:382e7ddd5289f140259b610e5f5c58f713d025cb2f66d0eb17e68d0a94278875"}, + {file = "coverage-7.9.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e5532482344186c543c37bfad0ee6069e8ae4fc38d073b8bc836fc8f03c9e250"}, + {file = "coverage-7.9.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a39d18b3f50cc121d0ce3838d32d58bd1d15dab89c910358ebefc3665712256c"}, + {file = "coverage-7.9.1-cp311-cp311-win32.whl", hash = "sha256:dd24bd8d77c98557880def750782df77ab2b6885a18483dc8588792247174b32"}, + {file = "coverage-7.9.1-cp311-cp311-win_amd64.whl", hash = "sha256:6b55ad10a35a21b8015eabddc9ba31eb590f54adc9cd39bcf09ff5349fd52125"}, + {file = "coverage-7.9.1-cp311-cp311-win_arm64.whl", hash = "sha256:6ad935f0016be24c0e97fc8c40c465f9c4b85cbbe6eac48934c0dc4d2568321e"}, + {file = "coverage-7.9.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a8de12b4b87c20de895f10567639c0797b621b22897b0af3ce4b4e204a743626"}, + {file = "coverage-7.9.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5add197315a054e92cee1b5f686a2bcba60c4c3e66ee3de77ace6c867bdee7cb"}, + {file = "coverage-7.9.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:600a1d4106fe66f41e5d0136dfbc68fe7200a5cbe85610ddf094f8f22e1b0300"}, + {file = "coverage-7.9.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2a876e4c3e5a2a1715a6608906aa5a2e0475b9c0f68343c2ada98110512ab1d8"}, + {file = "coverage-7.9.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81f34346dd63010453922c8e628a52ea2d2ccd73cb2487f7700ac531b247c8a5"}, + {file = "coverage-7.9.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:888f8eee13f2377ce86d44f338968eedec3291876b0b8a7289247ba52cb984cd"}, + {file = "coverage-7.9.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:9969ef1e69b8c8e1e70d591f91bbc37fc9a3621e447525d1602801a24ceda898"}, + {file = "coverage-7.9.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:60c458224331ee3f1a5b472773e4a085cc27a86a0b48205409d364272d67140d"}, + {file = "coverage-7.9.1-cp312-cp312-win32.whl", hash = "sha256:5f646a99a8c2b3ff4c6a6e081f78fad0dde275cd59f8f49dc4eab2e394332e74"}, + {file = "coverage-7.9.1-cp312-cp312-win_amd64.whl", hash = "sha256:30f445f85c353090b83e552dcbbdad3ec84c7967e108c3ae54556ca69955563e"}, + {file = "coverage-7.9.1-cp312-cp312-win_arm64.whl", hash = "sha256:af41da5dca398d3474129c58cb2b106a5d93bbb196be0d307ac82311ca234342"}, + {file = "coverage-7.9.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:31324f18d5969feef7344a932c32428a2d1a3e50b15a6404e97cba1cc9b2c631"}, + {file = "coverage-7.9.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0c804506d624e8a20fb3108764c52e0eef664e29d21692afa375e0dd98dc384f"}, + {file = "coverage-7.9.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef64c27bc40189f36fcc50c3fb8f16ccda73b6a0b80d9bd6e6ce4cffcd810bbd"}, + {file = "coverage-7.9.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d4fe2348cc6ec372e25adec0219ee2334a68d2f5222e0cba9c0d613394e12d86"}, + {file = "coverage-7.9.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:34ed2186fe52fcc24d4561041979a0dec69adae7bce2ae8d1c49eace13e55c43"}, + {file = "coverage-7.9.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:25308bd3d00d5eedd5ae7d4357161f4df743e3c0240fa773ee1b0f75e6c7c0f1"}, + {file = "coverage-7.9.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:73e9439310f65d55a5a1e0564b48e34f5369bee943d72c88378f2d576f5a5751"}, + {file = "coverage-7.9.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:37ab6be0859141b53aa89412a82454b482c81cf750de4f29223d52268a86de67"}, + {file = "coverage-7.9.1-cp313-cp313-win32.whl", hash = "sha256:64bdd969456e2d02a8b08aa047a92d269c7ac1f47e0c977675d550c9a0863643"}, + {file = "coverage-7.9.1-cp313-cp313-win_amd64.whl", hash = "sha256:be9e3f68ca9edb897c2184ad0eee815c635565dbe7a0e7e814dc1f7cbab92c0a"}, + {file = "coverage-7.9.1-cp313-cp313-win_arm64.whl", hash = "sha256:1c503289ffef1d5105d91bbb4d62cbe4b14bec4d13ca225f9c73cde9bb46207d"}, + {file = "coverage-7.9.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0b3496922cb5f4215bf5caaef4cf12364a26b0be82e9ed6d050f3352cf2d7ef0"}, + {file = "coverage-7.9.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:9565c3ab1c93310569ec0d86b017f128f027cab0b622b7af288696d7ed43a16d"}, + {file = "coverage-7.9.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2241ad5dbf79ae1d9c08fe52b36d03ca122fb9ac6bca0f34439e99f8327ac89f"}, + {file = "coverage-7.9.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3bb5838701ca68b10ebc0937dbd0eb81974bac54447c55cd58dea5bca8451029"}, + {file = "coverage-7.9.1-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b30a25f814591a8c0c5372c11ac8967f669b97444c47fd794926e175c4047ece"}, + {file = "coverage-7.9.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:2d04b16a6062516df97969f1ae7efd0de9c31eb6ebdceaa0d213b21c0ca1a683"}, + {file = "coverage-7.9.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:7931b9e249edefb07cd6ae10c702788546341d5fe44db5b6108a25da4dca513f"}, + {file = "coverage-7.9.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:52e92b01041151bf607ee858e5a56c62d4b70f4dac85b8c8cb7fb8a351ab2c10"}, + {file = "coverage-7.9.1-cp313-cp313t-win32.whl", hash = "sha256:684e2110ed84fd1ca5f40e89aa44adf1729dc85444004111aa01866507adf363"}, + {file = "coverage-7.9.1-cp313-cp313t-win_amd64.whl", hash = "sha256:437c576979e4db840539674e68c84b3cda82bc824dd138d56bead1435f1cb5d7"}, + {file = "coverage-7.9.1-cp313-cp313t-win_arm64.whl", hash = "sha256:18a0912944d70aaf5f399e350445738a1a20b50fbea788f640751c2ed9208b6c"}, + {file = "coverage-7.9.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6f424507f57878e424d9a95dc4ead3fbdd72fd201e404e861e465f28ea469951"}, + {file = "coverage-7.9.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:535fde4001b2783ac80865d90e7cc7798b6b126f4cd8a8c54acfe76804e54e58"}, + {file = "coverage-7.9.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:02532fd3290bb8fa6bec876520842428e2a6ed6c27014eca81b031c2d30e3f71"}, + {file = "coverage-7.9.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:56f5eb308b17bca3bbff810f55ee26d51926d9f89ba92707ee41d3c061257e55"}, + {file = "coverage-7.9.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfa447506c1a52271f1b0de3f42ea0fa14676052549095e378d5bff1c505ff7b"}, + {file = "coverage-7.9.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:9ca8e220006966b4a7b68e8984a6aee645a0384b0769e829ba60281fe61ec4f7"}, + {file = "coverage-7.9.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:49f1d0788ba5b7ba65933f3a18864117c6506619f5ca80326b478f72acf3f385"}, + {file = "coverage-7.9.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:68cd53aec6f45b8e4724c0950ce86eacb775c6be01ce6e3669fe4f3a21e768ed"}, + {file = "coverage-7.9.1-cp39-cp39-win32.whl", hash = "sha256:95335095b6c7b1cc14c3f3f17d5452ce677e8490d101698562b2ffcacc304c8d"}, + {file = "coverage-7.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:e1b5191d1648acc439b24721caab2fd0c86679d8549ed2c84d5a7ec1bedcc244"}, + {file = "coverage-7.9.1-pp39.pp310.pp311-none-any.whl", hash = "sha256:db0f04118d1db74db6c9e1cb1898532c7dcc220f1d2718f058601f7c3f499514"}, + {file = "coverage-7.9.1-py3-none-any.whl", hash = "sha256:66b974b145aa189516b6bf2d8423e888b742517d37872f6ee4c5be0073bd9a3c"}, + {file = "coverage-7.9.1.tar.gz", hash = "sha256:6cf43c78c4282708a28e466316935ec7489a9c487518a77fa68f716c67909cec"}, ] [package.dependencies] @@ -1199,14 +1199,14 @@ files = [ [[package]] name = "oauthlib" -version = "3.2.2" +version = "3.3.1" description = "A generic, spec-compliant, thorough implementation of the OAuth request-signing logic" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" groups = ["integration"] files = [ - {file = "oauthlib-3.2.2-py3-none-any.whl", hash = "sha256:8139f29aac13e25d502680e9e19963e83f16838d48a0d71c287fe40e7067fbca"}, - {file = "oauthlib-3.2.2.tar.gz", hash = "sha256:9859c40929662bec5d64f34d01c99e093149682a3f38915dc0655d5a633dd918"}, + {file = "oauthlib-3.3.1-py3-none-any.whl", hash = "sha256:88119c938d2b8fb88561af5f6ee0eec8cc8d552b7bb1f712743136eb7523b7a1"}, + {file = "oauthlib-3.3.1.tar.gz", hash = "sha256:0f0f8aa759826a193cf66c12ea1af1637f87b9b4622d46e866952bb022e538c9"}, ] [package.extras] @@ -1838,14 +1838,14 @@ files = [ [[package]] name = "pytest" -version = "8.4.0" +version = "8.4.1" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.9" groups = ["integration", "unit"] files = [ - {file = "pytest-8.4.0-py3-none-any.whl", hash = "sha256:f40f825768ad76c0977cbacdf1fd37c6f7a468e460ea6a0636078f8972d4517e"}, - {file = "pytest-8.4.0.tar.gz", hash = "sha256:14d920b48472ea0dbf68e45b96cd1ffda4705f33307dcc86c676c1b5104838a6"}, + {file = "pytest-8.4.1-py3-none-any.whl", hash = "sha256:539c70ba6fcead8e78eebbf1115e8b589e7565830d7d006a8723f19ac8a0afb7"}, + {file = "pytest-8.4.1.tar.gz", hash = "sha256:7c67fd69174877359ed9371ec3af8a3d2b04741818c51e5e99cc1742251fa93c"}, ] [package.dependencies] @@ -2191,30 +2191,30 @@ pyasn1 = ">=0.1.3" [[package]] name = "ruff" -version = "0.11.13" +version = "0.12.0" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" groups = ["format"] files = [ - {file = "ruff-0.11.13-py3-none-linux_armv6l.whl", hash = "sha256:4bdfbf1240533f40042ec00c9e09a3aade6f8c10b6414cf11b519488d2635d46"}, - {file = "ruff-0.11.13-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:aef9c9ed1b5ca28bb15c7eac83b8670cf3b20b478195bd49c8d756ba0a36cf48"}, - {file = "ruff-0.11.13-py3-none-macosx_11_0_arm64.whl", hash = "sha256:53b15a9dfdce029c842e9a5aebc3855e9ab7771395979ff85b7c1dedb53ddc2b"}, - {file = "ruff-0.11.13-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ab153241400789138d13f362c43f7edecc0edfffce2afa6a68434000ecd8f69a"}, - {file = "ruff-0.11.13-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6c51f93029d54a910d3d24f7dd0bb909e31b6cd989a5e4ac513f4eb41629f0dc"}, - {file = "ruff-0.11.13-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1808b3ed53e1a777c2ef733aca9051dc9bf7c99b26ece15cb59a0320fbdbd629"}, - {file = "ruff-0.11.13-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:d28ce58b5ecf0f43c1b71edffabe6ed7f245d5336b17805803312ec9bc665933"}, - {file = "ruff-0.11.13-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:55e4bc3a77842da33c16d55b32c6cac1ec5fb0fbec9c8c513bdce76c4f922165"}, - {file = "ruff-0.11.13-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:633bf2c6f35678c56ec73189ba6fa19ff1c5e4807a78bf60ef487b9dd272cc71"}, - {file = "ruff-0.11.13-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ffbc82d70424b275b089166310448051afdc6e914fdab90e08df66c43bb5ca9"}, - {file = "ruff-0.11.13-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:4a9ddd3ec62a9a89578c85842b836e4ac832d4a2e0bfaad3b02243f930ceafcc"}, - {file = "ruff-0.11.13-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:d237a496e0778d719efb05058c64d28b757c77824e04ffe8796c7436e26712b7"}, - {file = "ruff-0.11.13-py3-none-musllinux_1_2_i686.whl", hash = "sha256:26816a218ca6ef02142343fd24c70f7cd8c5aa6c203bca284407adf675984432"}, - {file = "ruff-0.11.13-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:51c3f95abd9331dc5b87c47ac7f376db5616041173826dfd556cfe3d4977f492"}, - {file = "ruff-0.11.13-py3-none-win32.whl", hash = "sha256:96c27935418e4e8e77a26bb05962817f28b8ef3843a6c6cc49d8783b5507f250"}, - {file = "ruff-0.11.13-py3-none-win_amd64.whl", hash = "sha256:29c3189895a8a6a657b7af4e97d330c8a3afd2c9c8f46c81e2fc5a31866517e3"}, - {file = "ruff-0.11.13-py3-none-win_arm64.whl", hash = "sha256:b4385285e9179d608ff1d2fb9922062663c658605819a6876d8beef0c30b7f3b"}, - {file = "ruff-0.11.13.tar.gz", hash = "sha256:26fa247dc68d1d4e72c179e08889a25ac0c7ba4d78aecfc835d49cbfd60bf514"}, + {file = "ruff-0.12.0-py3-none-linux_armv6l.whl", hash = "sha256:5652a9ecdb308a1754d96a68827755f28d5dfb416b06f60fd9e13f26191a8848"}, + {file = "ruff-0.12.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:05ed0c914fabc602fc1f3b42c53aa219e5736cb030cdd85640c32dbc73da74a6"}, + {file = "ruff-0.12.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:07a7aa9b69ac3fcfda3c507916d5d1bca10821fe3797d46bad10f2c6de1edda0"}, + {file = "ruff-0.12.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7731c3eec50af71597243bace7ec6104616ca56dda2b99c89935fe926bdcd48"}, + {file = "ruff-0.12.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:952d0630eae628250ab1c70a7fffb641b03e6b4a2d3f3ec6c1d19b4ab6c6c807"}, + {file = "ruff-0.12.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c021f04ea06966b02614d442e94071781c424ab8e02ec7af2f037b4c1e01cc82"}, + {file = "ruff-0.12.0-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:7d235618283718ee2fe14db07f954f9b2423700919dc688eacf3f8797a11315c"}, + {file = "ruff-0.12.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0c0758038f81beec8cc52ca22de9685b8ae7f7cc18c013ec2050012862cc9165"}, + {file = "ruff-0.12.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:139b3d28027987b78fc8d6cfb61165447bdf3740e650b7c480744873688808c2"}, + {file = "ruff-0.12.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68853e8517b17bba004152aebd9dd77d5213e503a5f2789395b25f26acac0da4"}, + {file = "ruff-0.12.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:3a9512af224b9ac4757f7010843771da6b2b0935a9e5e76bb407caa901a1a514"}, + {file = "ruff-0.12.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:b08df3d96db798e5beb488d4df03011874aff919a97dcc2dd8539bb2be5d6a88"}, + {file = "ruff-0.12.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:6a315992297a7435a66259073681bb0d8647a826b7a6de45c6934b2ca3a9ed51"}, + {file = "ruff-0.12.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:1e55e44e770e061f55a7dbc6e9aed47feea07731d809a3710feda2262d2d4d8a"}, + {file = "ruff-0.12.0-py3-none-win32.whl", hash = "sha256:7162a4c816f8d1555eb195c46ae0bd819834d2a3f18f98cc63819a7b46f474fb"}, + {file = "ruff-0.12.0-py3-none-win_amd64.whl", hash = "sha256:d00b7a157b8fb6d3827b49d3324da34a1e3f93492c1f97b08e222ad7e9b291e0"}, + {file = "ruff-0.12.0-py3-none-win_arm64.whl", hash = "sha256:8cd24580405ad8c1cc64d61725bca091d6b6da7eb3d36f72cc605467069d7e8b"}, + {file = "ruff-0.12.0.tar.gz", hash = "sha256:4d047db3662418d4a848a3fdbfaf17488b34b62f527ed6f10cb8afd78135bc5c"}, ] [[package]] @@ -2385,14 +2385,14 @@ typing-extensions = ">=3.7.4" [[package]] name = "urllib3" -version = "2.4.0" +version = "2.5.0" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.9" groups = ["main", "charm-libs", "integration"] files = [ - {file = "urllib3-2.4.0-py3-none-any.whl", hash = "sha256:4e16665048960a0900c702d4a66415956a584919c03361cac9f1df5c5dd7e813"}, - {file = "urllib3-2.4.0.tar.gz", hash = "sha256:414bc6535b787febd7567804cc015fee39daab8ad86268f1310a9250697de466"}, + {file = "urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc"}, + {file = "urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760"}, ] [package.extras] @@ -2621,4 +2621,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = "^3.10" -content-hash = "e290dc79dc14e6b1a1698a150a2637eeecc9ca3c4a9d2b6ed47ff2f110a63b79" +content-hash = "47f9ea14c625984013873b1d4be4aea61e11cface857df90ab23924549f19b5c" diff --git a/pyproject.toml b/pyproject.toml index 29db516027..35bc7c5f4b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ requires-poetry = ">=2.0.0" [tool.poetry.dependencies] python = "^3.10" ops = "^2.22.0" -boto3 = "^1.38.33" +boto3 = "^1.38.41" pgconnstr = "^1.0.1" requests = "^2.32.4" tenacity = "^9.1.2" @@ -40,7 +40,7 @@ opentelemetry-exporter-otlp-proto-http = "1.21.0" optional = true [tool.poetry.group.format.dependencies] -ruff = "^0.11.13" +ruff = "^0.12.0" [tool.poetry.group.lint] optional = true @@ -52,8 +52,8 @@ codespell = "^2.4.1" optional = true [tool.poetry.group.unit.dependencies] -coverage = {extras = ["toml"], version = "^7.8.2"} -pytest = "^8.4.0" +coverage = {extras = ["toml"], version = "^7.9.1"} +pytest = "^8.4.1" pytest-asyncio = "*" parameterized = "^0.9.0" jsonschema = "^4.24.0" @@ -62,7 +62,7 @@ jsonschema = "^4.24.0" optional = true [tool.poetry.group.integration.dependencies] -pytest = "^8.4.0" +pytest = "^8.4.1" pytest-operator = "^0.42.0" # renovate caret doesn't work: https://github.com/renovatebot/renovate/issues/26940 juju = "<=3.6.1.2" From 005dbf7d10ab47b6f6a19d6dc88be5723a15a324 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 25 Jun 2025 15:29:27 +0300 Subject: [PATCH 054/112] Update dependency uv to v0.7.14 (#995) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- charmcraft.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charmcraft.yaml b/charmcraft.yaml index 39b78b5174..60ea2be8ea 100644 --- a/charmcraft.yaml +++ b/charmcraft.yaml @@ -27,7 +27,7 @@ parts: PIP_BREAK_SYSTEM_PACKAGES=true python3 -m pip install --user --upgrade pip==25.1.1 # renovate: charmcraft-pip-latest # Use uv to install poetry so that a newer version of Python can be installed if needed by poetry - curl --proto '=https' --tlsv1.2 -LsSf https://github.com/astral-sh/uv/releases/download/0.7.13/uv-installer.sh | sh # renovate: charmcraft-uv-latest + curl --proto '=https' --tlsv1.2 -LsSf https://github.com/astral-sh/uv/releases/download/0.7.14/uv-installer.sh | sh # renovate: charmcraft-uv-latest # poetry 2.0.0 requires Python >=3.9 if ! "$HOME/.local/bin/uv" python find '>=3.9' then From bdb1f4ebb564c9d7e6ffe1379bda3faf38578df6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 26 Jun 2025 14:57:20 +0300 Subject: [PATCH 055/112] Lock file maintenance Python dependencies (#996) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- poetry.lock | 22 +++++++++++----------- pyproject.toml | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/poetry.lock b/poetry.lock index 4f46e32e15..31f7512ec4 100644 --- a/poetry.lock +++ b/poetry.lock @@ -233,18 +233,18 @@ typecheck = ["mypy"] [[package]] name = "boto3" -version = "1.38.41" +version = "1.38.42" description = "The AWS SDK for Python" optional = false python-versions = ">=3.9" groups = ["main", "integration"] files = [ - {file = "boto3-1.38.41-py3-none-any.whl", hash = "sha256:6119e9f272b9f004f052ca78ce94d3fe10198bc159ae808f75c0e1b9c07518bd"}, - {file = "boto3-1.38.41.tar.gz", hash = "sha256:c6710fc533c8e1f5d1f025c74ffe1222c3659094cd51c076ec50c201a54c8f22"}, + {file = "boto3-1.38.42-py3-none-any.whl", hash = "sha256:a9b4c7021bf5adee985523fc87db27a7200de161c094cb8f709b93a81797dc8a"}, + {file = "boto3-1.38.42.tar.gz", hash = "sha256:2cb783c668ae4f2a86b6497b47251b9baf9a16db8fff863b57eae683276b9e1f"}, ] [package.dependencies] -botocore = ">=1.38.41,<1.39.0" +botocore = ">=1.38.42,<1.39.0" jmespath = ">=0.7.1,<2.0.0" s3transfer = ">=0.13.0,<0.14.0" @@ -253,14 +253,14 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.38.41" +version = "1.38.42" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">=3.9" groups = ["main", "integration"] files = [ - {file = "botocore-1.38.41-py3-none-any.whl", hash = "sha256:06069a06f1352accb1f6c9505d6e323753627112be80a9d2e057c6d9c9779ffd"}, - {file = "botocore-1.38.41.tar.gz", hash = "sha256:98e3fed636ebb519320c4b2d078db6fa6099b052b4bb9b5c66632a5a7fe72507"}, + {file = "botocore-1.38.42-py3-none-any.whl", hash = "sha256:fbbeac30c045b5c19f1c3bb063ea2b6315ce2d6fcb3d898e87d1c1846297961c"}, + {file = "botocore-1.38.42.tar.gz", hash = "sha256:3a14188e48f6e26be561164373d34150fa9cb39f7ad32cc745dcd3ab05f43683"}, ] [package.dependencies] @@ -1754,14 +1754,14 @@ email = ["email-validator (>=1.0.3)"] [[package]] name = "pygments" -version = "2.19.1" +version = "2.19.2" description = "Pygments is a syntax highlighting package written in Python." optional = false python-versions = ">=3.8" groups = ["integration", "unit"] files = [ - {file = "pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c"}, - {file = "pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f"}, + {file = "pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b"}, + {file = "pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887"}, ] [package.extras] @@ -2621,4 +2621,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = "^3.10" -content-hash = "47f9ea14c625984013873b1d4be4aea61e11cface857df90ab23924549f19b5c" +content-hash = "a7259562b8d14c7e273c2904784c540cfb7947175998a551f853db3fa1820cbd" diff --git a/pyproject.toml b/pyproject.toml index 35bc7c5f4b..1ffbdecd56 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ requires-poetry = ">=2.0.0" [tool.poetry.dependencies] python = "^3.10" ops = "^2.22.0" -boto3 = "^1.38.41" +boto3 = "^1.38.42" pgconnstr = "^1.0.1" requests = "^2.32.4" tenacity = "^9.1.2" From 458e8c84376ab899455167e7b2dd30a915770d34 Mon Sep 17 00:00:00 2001 From: Dragomir Penev <6687393+dragomirp@users.noreply.github.com> Date: Mon, 30 Jun 2025 04:57:57 +0300 Subject: [PATCH 056/112] [MISC] Don't restart during initial sync (#1000) * Don't restart during initial sync * Catch relations map exceptions --- src/charm.py | 62 +++++++++++++++++++++----------------- src/cluster.py | 21 ++++++++++--- tests/unit/test_cluster.py | 3 ++ 3 files changed, 55 insertions(+), 31 deletions(-) diff --git a/src/charm.py b/src/charm.py index 6508225201..863eb92db7 100755 --- a/src/charm.py +++ b/src/charm.py @@ -2157,35 +2157,43 @@ def relations_user_databases_map(self) -> dict: if not self.is_cluster_initialised or not self._patroni.member_started: return {USER: "all", REPLICATION_USER: "all", REWIND_USER: "all"} user_database_map = {} - for user in sorted( - self.postgresql.list_users_from_relation(current_host=self.is_connectivity_enabled) - ): - user_database_map[user] = ",".join( - sorted( - self.postgresql.list_accessible_databases_for_user( - user, current_host=self.is_connectivity_enabled + try: + for user in sorted( + self.postgresql.list_users_from_relation(current_host=self.is_connectivity_enabled) + ): + user_database_map[user] = ",".join( + sorted( + self.postgresql.list_accessible_databases_for_user( + user, current_host=self.is_connectivity_enabled + ) ) ) - ) - # Add "landscape" superuser by default to the list when the "db-admin" relation is present - # or when the "database" relation has "extra-user-roles" set to "SUPERUSER" (which may mean - # that PgBouncer is related to the database and there is the possibility that Landscape - # is related to it). - if any( - True - for relation in self.client_relations - if relation.name == "db-admin" # Possibly Landscape relation. - or ( - relation.name == "database" - and relation.data[relation.app].get("extra-user-roles") == "SUPERUSER" - ) # PgBouncer (which may be related to Landscape). - ): - user_database_map["landscape"] = "all" - if self.postgresql.list_access_groups(current_host=self.is_connectivity_enabled) != set( - ACCESS_GROUPS - ): - user_database_map.update({USER: "all", REPLICATION_USER: "all", REWIND_USER: "all"}) - return user_database_map + # Add "landscape" superuser by default to the list when the "db-admin" relation is present + # or when the "database" relation has "extra-user-roles" set to "SUPERUSER" (which may mean + # that PgBouncer is related to the database and there is the possibility that Landscape + # is related to it). + if any( + True + for relation in self.client_relations + if relation.name == "db-admin" # Possibly Landscape relation. + or ( + relation.name == "database" + and relation.data[relation.app].get("extra-user-roles") == "SUPERUSER" + ) # PgBouncer (which may be related to Landscape). + ): + user_database_map["landscape"] = "all" + if self.postgresql.list_access_groups( + current_host=self.is_connectivity_enabled + ) != set(ACCESS_GROUPS): + user_database_map.update({ + USER: "all", + REPLICATION_USER: "all", + REWIND_USER: "all", + }) + return user_database_map + except PostgreSQLListUsersError: + logger.debug("relations_user_databases_map: Unable to get users") + return {USER: "all", REPLICATION_USER: "all", REWIND_USER: "all"} def override_patroni_restart_condition( self, new_condition: str, repeat_cause: str | None diff --git a/src/cluster.py b/src/cluster.py index e46cb87860..b3212b6b7e 100644 --- a/src/cluster.py +++ b/src/cluster.py @@ -53,7 +53,8 @@ PG_BASE_CONF_PATH = f"{POSTGRESQL_CONF_PATH}/postgresql.conf" -RUNNING_STATES = ["running", "streaming"] +STARTED_STATES = ["running", "streaming"] +RUNNING_STATES = [*STARTED_STATES, "starting"] PATRONI_TIMEOUT = 10 @@ -336,7 +337,7 @@ def get_standby_leader( ) for member in cluster_status.json()["members"]: if member["role"] == "standby_leader": - if check_whether_is_running and member["state"] not in RUNNING_STATES: + if check_whether_is_running and member["state"] not in STARTED_STATES: logger.warning(f"standby leader {member['name']} is not running") continue standby_leader = member["name"] @@ -416,7 +417,7 @@ def are_all_members_ready(self) -> bool: # a standby leader, because sometimes there may exist (for some period of time) # only replicas after a failed switchover. return all( - member["state"] in RUNNING_STATES for member in cluster_status.json()["members"] + member["state"] in STARTED_STATES for member in cluster_status.json()["members"] ) and any( member["role"] in ["leader", "standby_leader"] for member in cluster_status.json()["members"] @@ -496,6 +497,8 @@ def member_started(self) -> bool: True if services is ready False otherwise. Retries over a period of 60 seconds times to allow server time to start up. """ + if not self.is_patroni_running(): + return False try: response = self.get_patroni_health() except RetryError: @@ -517,7 +520,7 @@ def member_inactive(self) -> bool: return True return response["state"] not in [ - *RUNNING_STATES, + *STARTED_STATES, "creating replica", "starting", "restarting", @@ -965,6 +968,16 @@ def reload_patroni_configuration(self): timeout=PATRONI_TIMEOUT, ) + def is_patroni_running(self) -> bool: + """Check if the Patroni service is running.""" + try: + cache = snap.SnapCache() + selected_snap = cache["charmed-postgresql"] + return selected_snap.services["patroni"]["active"] + except snap.SnapError as e: + logger.debug(f"Failed to check Patroni service: {e}") + return False + def restart_patroni(self) -> bool: """Restart Patroni. diff --git a/tests/unit/test_cluster.py b/tests/unit/test_cluster.py index 4e02f37beb..3ee9ba4bf7 100644 --- a/tests/unit/test_cluster.py +++ b/tests/unit/test_cluster.py @@ -571,6 +571,7 @@ def test_member_started_true(peers_ips, patroni): patch("cluster.requests.get") as _get, patch("cluster.stop_after_delay", return_value=stop_after_delay(0)), patch("cluster.wait_fixed", return_value=wait_fixed(0)), + patch("charm.Patroni.is_patroni_running", return_value=True), ): _get.return_value.json.return_value = {"state": "running"} @@ -586,6 +587,7 @@ def test_member_started_false(peers_ips, patroni): patch("cluster.requests.get") as _get, patch("cluster.stop_after_delay", return_value=stop_after_delay(0)), patch("cluster.wait_fixed", return_value=wait_fixed(0)), + patch("charm.Patroni.is_patroni_running", return_value=True), ): _get.return_value.json.return_value = {"state": "stopped"} @@ -601,6 +603,7 @@ def test_member_started_error(peers_ips, patroni): patch("cluster.requests.get") as _get, patch("cluster.stop_after_delay", return_value=stop_after_delay(0)), patch("cluster.wait_fixed", return_value=wait_fixed(0)), + patch("charm.Patroni.is_patroni_running", return_value=True), ): _get.side_effect = Exception From d8e90beab7d5c7f41f0b89bf074f830ae0f120ec Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 1 Jul 2025 16:54:51 +0300 Subject: [PATCH 057/112] Lock file maintenance Python dependencies (#1011) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- poetry.lock | 65 +++++++++++++++++++++++++------------------------- pyproject.toml | 6 ++--- 2 files changed, 35 insertions(+), 36 deletions(-) diff --git a/poetry.lock b/poetry.lock index 31f7512ec4..414282cd2c 100644 --- a/poetry.lock +++ b/poetry.lock @@ -233,18 +233,18 @@ typecheck = ["mypy"] [[package]] name = "boto3" -version = "1.38.42" +version = "1.39.0" description = "The AWS SDK for Python" optional = false python-versions = ">=3.9" groups = ["main", "integration"] files = [ - {file = "boto3-1.38.42-py3-none-any.whl", hash = "sha256:a9b4c7021bf5adee985523fc87db27a7200de161c094cb8f709b93a81797dc8a"}, - {file = "boto3-1.38.42.tar.gz", hash = "sha256:2cb783c668ae4f2a86b6497b47251b9baf9a16db8fff863b57eae683276b9e1f"}, + {file = "boto3-1.39.0-py3-none-any.whl", hash = "sha256:6257f6f7bb87b66342564eab579ce1f0f63a4c1a6f701492f959e59bd7af68e5"}, + {file = "boto3-1.39.0.tar.gz", hash = "sha256:52a9f07fb9fa60ec6a2be07cd1586a97d8adae2be750121d4c032349cd113221"}, ] [package.dependencies] -botocore = ">=1.38.42,<1.39.0" +botocore = ">=1.39.0,<1.40.0" jmespath = ">=0.7.1,<2.0.0" s3transfer = ">=0.13.0,<0.14.0" @@ -253,14 +253,14 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.38.42" +version = "1.39.0" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">=3.9" groups = ["main", "integration"] files = [ - {file = "botocore-1.38.42-py3-none-any.whl", hash = "sha256:fbbeac30c045b5c19f1c3bb063ea2b6315ce2d6fcb3d898e87d1c1846297961c"}, - {file = "botocore-1.38.42.tar.gz", hash = "sha256:3a14188e48f6e26be561164373d34150fa9cb39f7ad32cc745dcd3ab05f43683"}, + {file = "botocore-1.39.0-py3-none-any.whl", hash = "sha256:d8e72850d3450aeca355b654efb32c8370bf824c1945a61cad2395dc2688581e"}, + {file = "botocore-1.39.0.tar.gz", hash = "sha256:2b8701e529a80241b989d83262a629d0d91fbd7a06ded63ecc1c9d529a383d57"}, ] [package.dependencies] @@ -1317,14 +1317,14 @@ files = [ [[package]] name = "ops" -version = "2.22.0" +version = "2.23.0" description = "The Python library behind great charms" optional = false python-versions = ">=3.8" groups = ["main", "charm-libs"] files = [ - {file = "ops-2.22.0-py3-none-any.whl", hash = "sha256:ad44326bc065e33357b47e1cf4c73e811b2fdb3c89dd0c9bdf421a7a028bdcf7"}, - {file = "ops-2.22.0.tar.gz", hash = "sha256:bd1cd1229e83efb8ae2d97d8878c7db3deceb6819eb5a38fb6e235a959528ec2"}, + {file = "ops-2.23.0-py3-none-any.whl", hash = "sha256:7a42840410e8570acc3a4b498973a5bcd3fd0b12dd06837f57b9379b3acdfac3"}, + {file = "ops-2.23.0.tar.gz", hash = "sha256:3e6c29a8f2119c7b8eaa88c82b5371de236dfcb7a7bf0012a6e2a829f0837fb7"}, ] [package.dependencies] @@ -1334,9 +1334,8 @@ PyYAML = "==6.*" websocket-client = "==1.*" [package.extras] -docs = ["canonical-sphinx-extensions", "furo", "linkify-it-py", "myst-parser", "pyspelling", "sphinx (>=8.0.0,<8.1.0)", "sphinx-autobuild", "sphinx-copybutton", "sphinx-design", "sphinx-notfound-page", "sphinx-tabs", "sphinxcontrib-jquery", "sphinxext-opengraph"] -testing = ["ops-scenario (==7.22.0)"] -tracing = ["ops-tracing (==2.22.0)"] +testing = ["ops-scenario (==7.23.0)"] +tracing = ["ops-tracing (==2.23.0)"] [[package]] name = "packaging" @@ -2191,30 +2190,30 @@ pyasn1 = ">=0.1.3" [[package]] name = "ruff" -version = "0.12.0" +version = "0.12.1" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" groups = ["format"] files = [ - {file = "ruff-0.12.0-py3-none-linux_armv6l.whl", hash = "sha256:5652a9ecdb308a1754d96a68827755f28d5dfb416b06f60fd9e13f26191a8848"}, - {file = "ruff-0.12.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:05ed0c914fabc602fc1f3b42c53aa219e5736cb030cdd85640c32dbc73da74a6"}, - {file = "ruff-0.12.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:07a7aa9b69ac3fcfda3c507916d5d1bca10821fe3797d46bad10f2c6de1edda0"}, - {file = "ruff-0.12.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7731c3eec50af71597243bace7ec6104616ca56dda2b99c89935fe926bdcd48"}, - {file = "ruff-0.12.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:952d0630eae628250ab1c70a7fffb641b03e6b4a2d3f3ec6c1d19b4ab6c6c807"}, - {file = "ruff-0.12.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c021f04ea06966b02614d442e94071781c424ab8e02ec7af2f037b4c1e01cc82"}, - {file = "ruff-0.12.0-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:7d235618283718ee2fe14db07f954f9b2423700919dc688eacf3f8797a11315c"}, - {file = "ruff-0.12.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0c0758038f81beec8cc52ca22de9685b8ae7f7cc18c013ec2050012862cc9165"}, - {file = "ruff-0.12.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:139b3d28027987b78fc8d6cfb61165447bdf3740e650b7c480744873688808c2"}, - {file = "ruff-0.12.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68853e8517b17bba004152aebd9dd77d5213e503a5f2789395b25f26acac0da4"}, - {file = "ruff-0.12.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:3a9512af224b9ac4757f7010843771da6b2b0935a9e5e76bb407caa901a1a514"}, - {file = "ruff-0.12.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:b08df3d96db798e5beb488d4df03011874aff919a97dcc2dd8539bb2be5d6a88"}, - {file = "ruff-0.12.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:6a315992297a7435a66259073681bb0d8647a826b7a6de45c6934b2ca3a9ed51"}, - {file = "ruff-0.12.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:1e55e44e770e061f55a7dbc6e9aed47feea07731d809a3710feda2262d2d4d8a"}, - {file = "ruff-0.12.0-py3-none-win32.whl", hash = "sha256:7162a4c816f8d1555eb195c46ae0bd819834d2a3f18f98cc63819a7b46f474fb"}, - {file = "ruff-0.12.0-py3-none-win_amd64.whl", hash = "sha256:d00b7a157b8fb6d3827b49d3324da34a1e3f93492c1f97b08e222ad7e9b291e0"}, - {file = "ruff-0.12.0-py3-none-win_arm64.whl", hash = "sha256:8cd24580405ad8c1cc64d61725bca091d6b6da7eb3d36f72cc605467069d7e8b"}, - {file = "ruff-0.12.0.tar.gz", hash = "sha256:4d047db3662418d4a848a3fdbfaf17488b34b62f527ed6f10cb8afd78135bc5c"}, + {file = "ruff-0.12.1-py3-none-linux_armv6l.whl", hash = "sha256:6013a46d865111e2edb71ad692fbb8262e6c172587a57c0669332a449384a36b"}, + {file = "ruff-0.12.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b3f75a19e03a4b0757d1412edb7f27cffb0c700365e9d6b60bc1b68d35bc89e0"}, + {file = "ruff-0.12.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:9a256522893cb7e92bb1e1153283927f842dea2e48619c803243dccc8437b8be"}, + {file = "ruff-0.12.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:069052605fe74c765a5b4272eb89880e0ff7a31e6c0dbf8767203c1fbd31c7ff"}, + {file = "ruff-0.12.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a684f125a4fec2d5a6501a466be3841113ba6847827be4573fddf8308b83477d"}, + {file = "ruff-0.12.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bdecdef753bf1e95797593007569d8e1697a54fca843d78f6862f7dc279e23bd"}, + {file = "ruff-0.12.1-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:70d52a058c0e7b88b602f575d23596e89bd7d8196437a4148381a3f73fcd5010"}, + {file = "ruff-0.12.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84d0a69d1e8d716dfeab22d8d5e7c786b73f2106429a933cee51d7b09f861d4e"}, + {file = "ruff-0.12.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6cc32e863adcf9e71690248607ccdf25252eeeab5193768e6873b901fd441fed"}, + {file = "ruff-0.12.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7fd49a4619f90d5afc65cf42e07b6ae98bb454fd5029d03b306bd9e2273d44cc"}, + {file = "ruff-0.12.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:ed5af6aaaea20710e77698e2055b9ff9b3494891e1b24d26c07055459bb717e9"}, + {file = "ruff-0.12.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:801d626de15e6bf988fbe7ce59b303a914ff9c616d5866f8c79eb5012720ae13"}, + {file = "ruff-0.12.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:2be9d32a147f98a1972c1e4df9a6956d612ca5f5578536814372113d09a27a6c"}, + {file = "ruff-0.12.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:49b7ce354eed2a322fbaea80168c902de9504e6e174fd501e9447cad0232f9e6"}, + {file = "ruff-0.12.1-py3-none-win32.whl", hash = "sha256:d973fa626d4c8267848755bd0414211a456e99e125dcab147f24daa9e991a245"}, + {file = "ruff-0.12.1-py3-none-win_amd64.whl", hash = "sha256:9e1123b1c033f77bd2590e4c1fe7e8ea72ef990a85d2484351d408224d603013"}, + {file = "ruff-0.12.1-py3-none-win_arm64.whl", hash = "sha256:78ad09a022c64c13cc6077707f036bab0fac8cd7088772dcd1e5be21c5002efc"}, + {file = "ruff-0.12.1.tar.gz", hash = "sha256:806bbc17f1104fd57451a98a58df35388ee3ab422e029e8f5cf30aa4af2c138c"}, ] [[package]] @@ -2621,4 +2620,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = "^3.10" -content-hash = "a7259562b8d14c7e273c2904784c540cfb7947175998a551f853db3fa1820cbd" +content-hash = "0b3f1bbe43e1ca66207dd2f4093f05657bda68ac5508be815e043130e1055370" diff --git a/pyproject.toml b/pyproject.toml index 1ffbdecd56..c63378b64e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,8 +7,8 @@ requires-poetry = ">=2.0.0" [tool.poetry.dependencies] python = "^3.10" -ops = "^2.22.0" -boto3 = "^1.38.42" +ops = "^2.23.0" +boto3 = "^1.39.0" pgconnstr = "^1.0.1" requests = "^2.32.4" tenacity = "^9.1.2" @@ -40,7 +40,7 @@ opentelemetry-exporter-otlp-proto-http = "1.21.0" optional = true [tool.poetry.group.format.dependencies] -ruff = "^0.12.0" +ruff = "^0.12.1" [tool.poetry.group.lint] optional = true From a016000fc7a418711e302dda5603590ee885cb70 Mon Sep 17 00:00:00 2001 From: Dragomir Penev <6687393+dragomirp@users.noreply.github.com> Date: Thu, 3 Jul 2025 15:57:48 +0300 Subject: [PATCH 058/112] [DPE-7549] Add compression and restore max-process (#1009) * Add compression and restore max-process * Update libs --- .../data_platform_libs/v0/data_interfaces.py | 101 ++++++++++++++++-- src/backups.py | 1 + templates/pgbackrest.conf.j2 | 4 + tests/unit/test_backups.py | 2 + 4 files changed, 102 insertions(+), 6 deletions(-) diff --git a/lib/charms/data_platform_libs/v0/data_interfaces.py b/lib/charms/data_platform_libs/v0/data_interfaces.py index c0ddec58c9..021de1dc89 100644 --- a/lib/charms/data_platform_libs/v0/data_interfaces.py +++ b/lib/charms/data_platform_libs/v0/data_interfaces.py @@ -331,7 +331,7 @@ def _on_topic_requested(self, event: TopicRequestedEvent): # Increment this PATCH version before using `charmcraft publish-lib` or reset # to 0 if you are raising the major API version -LIBPATCH = 46 +LIBPATCH = 48 PYDEPS = ["ops>=2.0.0"] @@ -2569,7 +2569,7 @@ def __init__( ################################################################################ -# Cross-charm Relatoins Data Handling and Evenets +# Cross-charm Relations Data Handling and Events ################################################################################ # Generic events @@ -3268,7 +3268,7 @@ def __init__( # Kafka Events -class KafkaProvidesEvent(RelationEvent): +class KafkaProvidesEvent(RelationEventWithSecret): """Base class for Kafka events.""" @property @@ -3287,6 +3287,40 @@ def consumer_group_prefix(self) -> Optional[str]: return self.relation.data[self.relation.app].get("consumer-group-prefix") + @property + def mtls_cert(self) -> Optional[str]: + """Returns TLS cert of the client.""" + if not self.relation.app: + return None + + if not self.secrets_enabled: + raise SecretsUnavailableError("Secrets unavailable on current Juju version") + + secret_field = f"{PROV_SECRET_PREFIX}{SECRET_GROUPS.MTLS}" + if secret_uri := self.relation.data[self.app].get(secret_field): + secret = self.framework.model.get_secret(id=secret_uri) + content = secret.get_content(refresh=True) + if content: + return content.get("mtls-cert") + + +class KafkaClientMtlsCertUpdatedEvent(KafkaProvidesEvent): + """Event emitted when the mtls relation is updated.""" + + def __init__(self, handle, relation, old_mtls_cert: Optional[str] = None, app=None, unit=None): + super().__init__(handle, relation, app, unit) + + self.old_mtls_cert = old_mtls_cert + + def snapshot(self): + """Return a snapshot of the event.""" + return super().snapshot() | {"old_mtls_cert": self.old_mtls_cert} + + def restore(self, snapshot): + """Restore the event from a snapshot.""" + super().restore(snapshot) + self.old_mtls_cert = snapshot["old_mtls_cert"] + class TopicRequestedEvent(KafkaProvidesEvent, ExtraRoleEvent): """Event emitted when a new topic is requested for use on this relation.""" @@ -3299,6 +3333,7 @@ class KafkaProvidesEvents(CharmEvents): """ topic_requested = EventSource(TopicRequestedEvent) + mtls_cert_updated = EventSource(KafkaClientMtlsCertUpdatedEvent) class KafkaRequiresEvent(RelationEvent): @@ -3416,6 +3451,13 @@ def __init__(self, charm: CharmBase, relation_data: KafkaProviderData) -> None: def _on_relation_changed_event(self, event: RelationChangedEvent) -> None: """Event emitted when the relation has changed.""" super()._on_relation_changed_event(event) + + new_data_keys = list(event.relation.data[event.app].keys()) + if any(newval for newval in new_data_keys if self.relation_data._is_secret_field(newval)): + self.relation_data._register_secrets_to_relation(event.relation, new_data_keys) + + getattr(self.on, "mtls_cert_updated").emit(event.relation, app=event.app, unit=event.unit) + # Leader only if not self.relation_data.local_unit.is_leader(): return @@ -3430,6 +3472,33 @@ def _on_relation_changed_event(self, event: RelationChangedEvent) -> None: event.relation, app=event.app, unit=event.unit ) + def _on_secret_changed_event(self, event: SecretChangedEvent): + """Event notifying about a new value of a secret.""" + if not event.secret.label: + return + + relation = self.relation_data._relation_from_secret_label(event.secret.label) + if not relation: + logging.info( + f"Received secret {event.secret.label} but couldn't parse, seems irrelevant" + ) + return + + if relation.app == self.charm.app: + logging.info("Secret changed event ignored for Secret Owner") + + remote_unit = None + for unit in relation.units: + if unit.app != self.charm.app: + remote_unit = unit + + old_mtls_cert = event.secret.get_content().get("mtls-cert") + # mtls-cert is the only secret that can be updated + logger.info("mtls-cert updated") + getattr(self.on, "mtls_cert_updated").emit( + relation, app=relation.app, unit=remote_unit, old_mtls_cert=old_mtls_cert + ) + class KafkaProvides(KafkaProviderData, KafkaProviderEventHandlers): """Provider-side of the Kafka relation.""" @@ -3450,11 +3519,13 @@ def __init__( extra_user_roles: Optional[str] = None, consumer_group_prefix: Optional[str] = None, additional_secret_fields: Optional[List[str]] = [], + mtls_cert: Optional[str] = None, ): """Manager of Kafka client relations.""" super().__init__(model, relation_name, extra_user_roles, additional_secret_fields) self.topic = topic self.consumer_group_prefix = consumer_group_prefix or "" + self.mtls_cert = mtls_cert @property def topic(self): @@ -3468,6 +3539,15 @@ def topic(self, value): raise ValueError(f"Error on topic '{value}', cannot be a wildcard.") self._topic = value + def set_mtls_cert(self, relation_id: int, mtls_cert: str) -> None: + """Set the mtls cert in the application relation databag / secret. + + Args: + relation_id: the identifier for a particular relation. + mtls_cert: mtls cert. + """ + self.update_relation_data(relation_id, {"mtls-cert": mtls_cert}) + class KafkaRequirerEventHandlers(RequirerEventHandlers): """Requires-side of the Kafka relation.""" @@ -3489,6 +3569,9 @@ def _on_relation_created_event(self, event: RelationCreatedEvent) -> None: # Sets topic, extra user roles, and "consumer-group-prefix" in the relation relation_data = {"topic": self.relation_data.topic} + if self.relation_data.mtls_cert: + relation_data["mtls-cert"] = self.relation_data.mtls_cert + if self.relation_data.extra_user_roles: relation_data["extra-user-roles"] = self.relation_data.extra_user_roles @@ -3547,15 +3630,17 @@ def __init__( extra_user_roles: Optional[str] = None, consumer_group_prefix: Optional[str] = None, additional_secret_fields: Optional[List[str]] = [], + mtls_cert: Optional[str] = None, ) -> None: KafkaRequirerData.__init__( self, charm.model, relation_name, topic, - extra_user_roles, - consumer_group_prefix, - additional_secret_fields, + extra_user_roles=extra_user_roles, + consumer_group_prefix=consumer_group_prefix, + additional_secret_fields=additional_secret_fields, + mtls_cert=mtls_cert, ) KafkaRequirerEventHandlers.__init__(self, charm, self) @@ -3675,6 +3760,10 @@ def _on_relation_changed_event(self, event: RelationChangedEvent) -> None: event.relation, app=event.app, unit=event.unit ) + def _on_secret_changed_event(self, event: SecretChangedEvent) -> None: + """Event emitted when the relation data has changed.""" + pass + class OpenSearchProvides(OpenSearchProvidesData, OpenSearchProvidesEventHandlers): """Provider-side of the OpenSearch relation.""" diff --git a/src/backups.py b/src/backups.py index 4c414d75e8..74f754b276 100644 --- a/src/backups.py +++ b/src/backups.py @@ -1262,6 +1262,7 @@ def _render_pgbackrest_conf_file(self) -> bool: storage_path=self.charm._storage_path, user=BACKUP_USER, retention_full=s3_parameters["delete-older-than-days"], + process_max=max(os.cpu_count() - 2, 1), ) # Render pgBackRest config file. self.charm._patroni.render_file(f"{PGBACKREST_CONF_PATH}/pgbackrest.conf", rendered, 0o644) diff --git a/templates/pgbackrest.conf.j2 b/templates/pgbackrest.conf.j2 index 46776c2e7c..bf43b83516 100644 --- a/templates/pgbackrest.conf.j2 +++ b/templates/pgbackrest.conf.j2 @@ -1,5 +1,6 @@ [global] backup-standby=y +compress-type=zst lock-path=/tmp log-path={{ log_path }} repo1-retention-full-type=time @@ -47,3 +48,6 @@ pg{{ ns.count }}-user={{ user }} {% set ns.count = ns.count + 1 %} {%- endfor %} {%- endif %} + +[global:restore] +process-max={{process_max}} diff --git a/tests/unit/test_backups.py b/tests/unit/test_backups.py index 5cd5cac8c4..2f93daa663 100644 --- a/tests/unit/test_backups.py +++ b/tests/unit/test_backups.py @@ -1,5 +1,6 @@ # Copyright 2023 Canonical Ltd. # See LICENSE file for licensing details. +from os import cpu_count from pathlib import PosixPath from subprocess import CompletedProcess, TimeoutExpired from unittest.mock import ANY, MagicMock, PropertyMock, call, mock_open, patch @@ -1754,6 +1755,7 @@ def test_render_pgbackrest_conf_file(harness, tls_ca_chain_filename): storage_path=harness.charm._storage_path, user="backup", retention_full=30, + process_max=max(cpu_count() - 2, 1), ) # Patch the `open` method with our mock. From 20d6e0e3db8713e93348b3d813d3b3b2f2d87ab8 Mon Sep 17 00:00:00 2001 From: Tushar <30565750+tushar5526@users.noreply.github.com> Date: Wed, 9 Jul 2025 21:37:07 +0530 Subject: [PATCH 059/112] typo: "chances" to "changes" (#1018) --- docs/reference/troubleshooting/cli-helpers.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/reference/troubleshooting/cli-helpers.md b/docs/reference/troubleshooting/cli-helpers.md index aa2fe3e443..ae55abf0ba 100644 --- a/docs/reference/troubleshooting/cli-helpers.md +++ b/docs/reference/troubleshooting/cli-helpers.md @@ -216,7 +216,7 @@ ubuntu@juju360:~$ curl 10.189.210.55:8008/cluster | jq # where 10.189.210.55 is

?Lp=GzSH`(Trq6^iQZHf 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 b@$URTdiJuiT;BJ;d literal 0 HcmV?d00001 diff --git a/docs/how-to/deploy/maas-image-downloads.png b/docs/how-to/deploy/maas-image-downloads.png new file mode 100644 index 0000000000000000000000000000000000000000..b3f9f39750469ffd920c15e1e8c1636551e4918d GIT binary patch literal 67262 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 literal 0 HcmV?d00001 diff --git a/docs/how-to/h-deploy-maas.md b/docs/how-to/deploy/maas.md similarity index 68% rename from docs/how-to/h-deploy-maas.md rename to docs/how-to/deploy/maas.md index d6c322cfc9..40650674d0 100644 --- a/docs/how-to/h-deploy-maas.md +++ b/docs/how-to/deploy/maas.md @@ -2,25 +2,14 @@ This guide aims to provide a quick start to deploying Charmed PostgreSQL on MAAS. It summarizes the instructions from the [Build a MAAS and LXD environment with Multipass Tutorial](https://discourse.maas.io/t/5360) to set up and tear down a **playground environment**. -If you want to deploy PostgreSQL on MAAS in a **production environment**, refer to the official [Bootstrap MAAS Tutorial](https://maas.io/docs/tutorial-bootstrapping-maas) followed by the [Charmed PostgreSQL Tutorial](/t/9707). - - - -## Summary - * [Bootstrap a Multipass VM](#heading--bootstrap-multipass-vm) - * [Configure MAAS](#heading--configure-maas) - * [Register MAAS with Juju](#heading--register-maas-juju) - * [Deploy Charmed PostgreSQL on MAAS](#heading--deploy-postgresql-maas) - * [Test Charmed PostgreSQL deployment](#heading--test-postgresql) - * [Clean up the environment](#heading--clean-up) +If you want to deploy PostgreSQL on MAAS in a **production environment**, refer to the official [Bootstrap MAAS Tutorial](https://maas.io/docs/tutorial-bootstrapping-maas) followed by the [Charmed PostgreSQL Tutorial](/tutorial/index). For further details and explanation about each step, remember you can refer to the [original tutorial](https://discourse.maas.io/t/5360). ---- -

```{note} -The Patroni REST API can be accessed anonymously in read-only mode only. The Juju secret `patroni-password` is mandatory to apply any chances via Patroni REST API. +The Patroni REST API can be accessed anonymously in read-only mode only. The Juju secret `patroni-password` is mandatory to apply any changes via Patroni REST API. ``` Example of authenticated changes via Patroni REST API: @@ -339,4 +339,4 @@ PGPASSWORD=my$ecretp@ss charmed-postgresql.pg-dumpall -c -U operator -h /tmp -f > sudo ls -la /tmp/snap-private-tmp/snap.charmed-postgresql/tmp/test.sql -rw-rw-r-- 1 ubuntu ubuntu 19416 Jun 4 08:24 /tmp/snap-private-tmp/snap.charmed-postgresql/tmp/test.sql ``` -
\ No newline at end of file + From fe2c9fbe64307a6391db0432e41a7e28fe801a62 Mon Sep 17 00:00:00 2001 From: Andreia Date: Wed, 9 Jul 2025 18:24:25 +0200 Subject: [PATCH 060/112] remove markdown linter action (#1028) --- .github/workflows/markdown-style-checks.yml | 24 --------------------- docs/.sphinx/.markdownlint.json | 21 ------------------ 2 files changed, 45 deletions(-) delete mode 100644 .github/workflows/markdown-style-checks.yml delete mode 100644 docs/.sphinx/.markdownlint.json diff --git a/.github/workflows/markdown-style-checks.yml b/.github/workflows/markdown-style-checks.yml deleted file mode 100644 index bc75792104..0000000000 --- a/.github/workflows/markdown-style-checks.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: Markdown style checks - -on: - push: - branches: - - main - paths: - - 'docs/**' # Only run on changes to the docs directory - pull_request: - branches: - - '*' - paths: - - 'docs/**' # Only run on changes to the docs directory - -jobs: - markdown-lint: - runs-on: ubuntu-22.04 - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - uses: DavidAnson/markdownlint-cli2-action@b4c9feab76d8025d1e83c653fa3990936df0e6c8 - with: - config: "docs/.sphinx/.markdownlint.json" diff --git a/docs/.sphinx/.markdownlint.json b/docs/.sphinx/.markdownlint.json deleted file mode 100644 index 536f9ea929..0000000000 --- a/docs/.sphinx/.markdownlint.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "default": false, - "MD003": { - "style": "atx" - }, - "MD014": true, - "MD018": true, - "MD022": true, - "MD023": true, - "MD026": { - "punctuation": ".,;。,;" - }, - "MD031": { - "list_items": false - }, - "MD032": true, - "MD035": true, - "MD042": true, - "MD045": true, - "MD052": true -} \ No newline at end of file From 69337866e1620013e045f6dc1de244d929fe5817 Mon Sep 17 00:00:00 2001 From: Andreia Date: Fri, 11 Jul 2025 14:06:28 +0200 Subject: [PATCH 061/112] Fix automatic doc checks (#1006) * Fix spellcheck * Fix some broken URLs * fix remaining broken urls * add missing backticks to toctrees * small spellcheck fix --- docs/.custom_wordlist.txt | 112 ++++++++++++++++++ docs/.sphinx/spellingcheck.yaml | 2 +- docs/conf.py | 3 +- docs/explanation/architecture.md | 22 ++-- docs/explanation/index.md | 49 +++----- docs/explanation/juju.md | 2 +- docs/explanation/legacy-charm.md | 12 +- docs/explanation/logs.md | 2 +- docs/explanation/security/cryptography.md | 2 +- docs/explanation/security/index.md | 16 +-- docs/explanation/units.md | 2 +- docs/explanation/users.md | 4 +- .../configure-s3-radosgw.md | 2 +- docs/how-to/back-up-and-restore/index.md | 1 + .../manage-backup-retention.md | 2 +- .../cross-regional-async-replication/index.md | 22 ++-- .../integrate-with-a-client-app.md | 2 +- .../remove-or-recover-a-cluster.md | 2 +- .../set-up-clusters.md | 2 +- docs/how-to/deploy/air-gapped.md | 32 ++--- docs/how-to/deploy/aws-ec2.md | 5 +- docs/how-to/deploy/azure.md | 4 +- docs/how-to/deploy/gce.md | 4 +- docs/how-to/deploy/index.md | 4 +- docs/how-to/deploy/juju-storage.md | 2 +- docs/how-to/deploy/maas.md | 4 +- docs/how-to/deploy/sunbeam.md | 4 +- docs/how-to/deploy/terraform.md | 2 +- docs/how-to/deploy/tls-vip-access.md | 6 +- docs/how-to/development/index.md | 1 + .../development/integrate-with-your-charm.md | 4 +- .../development/migrate-data-via-pg-dump.md | 2 +- docs/how-to/enable-ldap.md | 4 +- .../how-to/enable-plugins-extensions/index.md | 3 +- docs/how-to/external-network-access.md | 4 +- docs/how-to/index.md | 2 +- docs/how-to/manage-passwords.md | 2 +- .../monitoring-cos/enable-alert-rules.md | 2 +- .../monitoring-cos/enable-monitoring.md | 2 +- .../how-to/monitoring-cos/enable-profiling.md | 16 +-- docs/how-to/monitoring-cos/enable-tracing.md | 10 +- docs/how-to/monitoring-cos/index.md | 1 + docs/how-to/scale-replicas.md | 2 +- docs/how-to/switchover-failover.md | 14 +-- docs/how-to/upgrade/index.md | 1 + .../how-to/upgrade/perform-a-minor-upgrade.md | 2 +- docs/index.md | 4 +- docs/reference/alert-rules.md | 2 +- docs/reference/contacts.md | 4 - docs/reference/performance-and-resources.md | 2 +- docs/reference/releases.md | 4 +- docs/reference/statuses.md | 8 +- docs/reference/system-requirements.md | 14 +-- docs/reference/troubleshooting/cli-helpers.md | 14 +-- docs/reference/troubleshooting/index.md | 11 +- docs/reference/troubleshooting/sos-report.md | 12 +- docs/reference/versions.md | 2 +- docs/tutorial/index.md | 10 +- 58 files changed, 286 insertions(+), 201 deletions(-) diff --git a/docs/.custom_wordlist.txt b/docs/.custom_wordlist.txt index 52d5f8c616..842cb0ceea 100644 --- a/docs/.custom_wordlist.txt +++ b/docs/.custom_wordlist.txt @@ -1,40 +1,152 @@ # Leave a blank line at the end of this file to support concatenation +airgap +airgapped +analyze +artifact +Artifactory +artifacts +async +aws +AWS +AZ +AZs backend backends +backport +balancer +balancers +benchmark +benchmarking +CharmBase Charmcraft +charmhub +checksum +checksums +CIS cjk +codebase +config +configs cryptographically +CSR +CSRs +databag +databags +dev dvipng +eks +EKS +entrypoint +failover +filesystem +filesystems fonts freefont +gapped +gce +GCE +gcloud +GCloud +GCP github +GLAuth GPG gyre +HLD +hostname +hostnames https +IAAS +integration +integrations Intersphinx +io +IPs +IPv +Jira +jitter +Juju +Juju's lang LaTeX latexmk +LDAP +libs +lifecycle +LXD +LXD's +MicroK8s +MinIO Multipass +nameserver +nameservers +Nextcloud otf +Parca +Parca's +Patroni +patronictl +pgbackrest +pgBackRest +pgbouncer +pgsql +PITR plantuml PNG +pooler +postgres +postgresql +PPA +PPAs +pqsql +programmatically +PSC +PVCs +py Pygments QEMU +RadosGW +requirer +rockcraft Rockcraft +routable rst +scalable +sdk +SHA +snap +snapcraft +SoS +squashfs +SquashFS +src +SSL +stateful SVG +Sysbench +terraform tex texlive +TimescaleDB TOC toctree +Traefik txt +ubuntu uncommenting +uncordon utils +vm VMs +WAL +walkthrough WCAG +wget whitespace whitespaces +WIP wordlist xetex +XID xindy +yaml \ No newline at end of file diff --git a/docs/.sphinx/spellingcheck.yaml b/docs/.sphinx/spellingcheck.yaml index 9ee9ae7130..33aefd5e1b 100644 --- a/docs/.sphinx/spellingcheck.yaml +++ b/docs/.sphinx/spellingcheck.yaml @@ -9,7 +9,7 @@ matrix: - .custom_wordlist.txt output: .sphinx/.wordlist.dic sources: - - _build/**/*.html + - _build/**/*.html|!_build/reference/alert-rules/index.html pipeline: - pyspelling.filters.html: comments: false diff --git a/docs/conf.py b/docs/conf.py index 8224800db0..eba2ae7345 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -208,7 +208,8 @@ linkcheck_ignore = [ "http://127.0.0.1:8000", "https://github.com/canonical/ACME/*", - "https://matrix.to/*" + "https://matrix.to/*", + "https://portal.azure.com/#browse/Microsoft.Compute/VirtualMachines" ] # A regex list of URLs where anchors are ignored by 'make linkcheck' diff --git a/docs/explanation/architecture.md b/docs/explanation/architecture.md index 5a518f2569..0690ecc1d9 100644 --- a/docs/explanation/architecture.md +++ b/docs/explanation/architecture.md @@ -83,7 +83,7 @@ GLAuth is a secure, easy-to-use and open-sourced LDAP server which provides capa ### Grafana -Grafana is an open-source visualization tools that allows to query, visualize, alert on, and visualize metrics from mixed datasources in configurable dashboards for observability. This charms is shipped with its own Grafana dashboard and supports integration with the [Grafana Operator](https://charmhub.io/grafana-k8s) to simplify observability. Please follow [COS Monitoring](/how-to/monitoring-cos/enable-monitoring) setup. +Grafana is an open-source visualisation tools that allows to query, visualise, alert on, and visualise metrics from mixed data sources in configurable dashboards for observability. This charms is shipped with its own Grafana dashboard and supports integration with the [Grafana Operator](https://charmhub.io/grafana-k8s) to simplify observability. Please follow [COS Monitoring](/how-to/monitoring-cos/enable-monitoring) setup. ### Loki @@ -105,25 +105,25 @@ Accordingly to the [Juju SDK](https://juju.is/docs/sdk/event): “an event is a For this charm, the following events are observed: -1. [`on_install`](https://juju.is/docs/sdk/install-event): install the snap "charmed-postgresql" and perform basic preparations to bootstrap the cluster on the first leader (or join the already configured cluster). -2. [`leader-elected`](https://juju.is/docs/sdk/leader-elected-event): generate all the secrets to bootstrap the cluster. -3. [`leader-settings-changed`](https://juju.is/docs/sdk/leader-settings-changed-event): Handle the leader settings changed event. -4. [`start`](https://juju.is/docs/sdk/start-event): Init/setting up the cluster node. -5. [`config_changed`](https://juju.is/docs/sdk/config-changed-event): usually fired in response to a configuration change using the GUI or CLI. Create and set default cluster and cluster-set names in the peer relation databag (on the leader only). -6. [`update-status`](https://juju.is/docs/sdk/update-status-event): Takes care of workload health checks. +1. [`on_install`](https://documentation.ubuntu.com/juju/3.6/reference/hook/#install): install the snap "charmed-postgresql" and perform basic preparations to bootstrap the cluster on the first leader (or join the already configured cluster). +2. [`leader-elected`](https://documentation.ubuntu.com/juju/3.6/reference/hook/#leader-elected): generate all the secrets to bootstrap the cluster. +3. [`leader-settings-changed`](https://documentation.ubuntu.com/juju/3.6/reference/hook/#leader-settings-changed): Handle the leader settings changed event. +4. [`start`](https://documentation.ubuntu.com/juju/3.6/reference/hook/#start): Init/setting up the cluster node. +5. [`config_changed`](https://documentation.ubuntu.com/juju/3.6/reference/hook/#config-changed): usually fired in response to a configuration change using the GUI or CLI. Create and set default cluster and cluster-set names in the peer relation databag (on the leader only). +6. [`update-status`](https://documentation.ubuntu.com/juju/3.6/reference/hook/#update-status): Takes care of workload health checks. ### Charm code overview -[`src/charm.py`](https://github.com/canonical/postgresql-operator/blob/main/src/charm.py) is the default entry point for a charm and has the `PostgresqlOperatorCharm` Python class which inherits from CharmBase. +[`src/charm.py`](https://github.com/canonical/postgresql-operator/blob/main/src/charm.py) is the default entry point for a charm and has the `PostgresqlOperatorCharm` Python class which inherits from `CharmBase`. -CharmBase is the base class from which all Charms are formed, defined by [Ops](https://juju.is/docs/sdk/ops) (Python framework for developing charms). See more information in [Charm](https://juju.is/docs/sdk/constructs#charm). +`CharmBase` is the base class from which all Charms are formed, defined by [Ops](https://ops.readthedocs.io/en/latest/) (Python framework for developing charms). See more information in the [Ops documentation for `CharmBase`](https://ops.readthedocs.io/en/latest/reference/ops.html#ops.CharmBase). The `__init__` method guarantees that the charm observes all events relevant to its operation and handles them. -The VM and K8s charm flavors shares the codebase via [charm libraries](https://juju.is/docs/sdk/libraries) in [lib/charms/postgresql_k8s/v0/](https://github.com/canonical/postgresql-k8s-operator/blob/main/lib/charms/postgresql_k8s/v0/postgresql.py) (of K8s flavor of the charm!): +The VM and K8s charm flavours shares the codebase via charm libraries in [`lib/charms/postgresql_k8s/v0/`](https://github.com/canonical/postgresql-k8s-operator/blob/main/lib/charms/postgresql_k8s/v0/postgresql.py) (of K8s flavour of the charm!): ```text > charmcraft list-lib postgresql-k8s Library name API Patch diff --git a/docs/explanation/index.md b/docs/explanation/index.md index 3218d9baff..49990c65f1 100644 --- a/docs/explanation/index.md +++ b/docs/explanation/index.md @@ -3,51 +3,32 @@ Additional context about key concepts behind the PostgreSQL charm, including design and legacy information. ## Core concepts and design -* [Architecture] -* [Interfaces and endpoints] -* [Juju] -* [Legacy charm] - -## Operational concepts -* [Units] -* [Users] -* [Roles] -* [Logs] -* [Connection pooling] - -## Security and hardening -* [Security hardening guide][Security] - * [Cryptography] - - - - -[Architecture]: /explanation/architecture -[Interfaces and endpoints]: /explanation/interfaces-and-endpoints -[Units]: /explanation/units -[Users]: /explanation/users -[Roles]: /explanation/roles -[Logs]: /explanation/logs -[Juju]: /explanation/juju -[Legacy charm]: /explanation/legacy-charm -[Connection pooling]: /explanation/connection-pooling -[Security]: /explanation/security/index -[Cryptography]: /explanation/security/cryptography - ```{toctree} :titlesonly: -:maxdepth: 2 -:glob: -:hidden: Architecture Interfaces and endpoints Juju Legacy charm +``` + +## Operational concepts + +```{toctree} +:titlesonly: + Units Users Roles Logs Connection pooling +``` + +## Security and hardening + +```{toctree} +:titlesonly: + Security +``` \ No newline at end of file diff --git a/docs/explanation/juju.md b/docs/explanation/juju.md index 0a40ae0069..ce57b981cc 100644 --- a/docs/explanation/juju.md +++ b/docs/explanation/juju.md @@ -26,7 +26,7 @@ In the context of this documentation, the pertinent changes are as follows: |`run`|`exec`| |`run-action --wait`|`run`| -See the [Juju 3.0 release notes](https://juju.is/docs/juju/roadmap#juju-3-0-0---22-oct-2022) for the comprehensive list of changes. +See the [Juju 3.0 release notes](https://documentation.ubuntu.com/juju/3.6/reference/juju/juju-roadmap-and-releases/#juju-3-0-0-22-oct-2022) for the comprehensive list of changes. Example substitutions: diff --git a/docs/explanation/legacy-charm.md b/docs/explanation/legacy-charm.md index 6a1afbde03..edbbc3df7e 100644 --- a/docs/explanation/legacy-charm.md +++ b/docs/explanation/legacy-charm.md @@ -1,9 +1,9 @@ # Legacy charm -There are [two types of charms](https://juju.is/docs/sdk/charm-taxonomy#charm-types-by-generation) stored under the same charm name `postgresql`: +There are [two types of charms](https://documentation.ubuntu.com/juju/3.6/reference/charm/#by-generation) stored under the same charm name `postgresql`: -1. [Reactive](https://juju.is/docs/sdk/charm-taxonomy#reactive) charm in the channel `latest/stable` (called `legacy`) -2. [Ops-based](https://juju.is/docs/sdk/ops) charm in the channel `14/stable` (called `modern`) +1. [Reactive](https://documentation.ubuntu.com/juju/3.6/reference/charm/#reactive) charm in the channel `latest/stable` (called `legacy`) +2. [Ops-based](https://documentation.ubuntu.com/juju/3.6/reference/charm/#ops) charm in the channel `14/stable` (called `modern`) The legacy charm provided endpoints `db` and `db-admin` (for the interface `pgsql`). The modern charm provides old endpoints as well + new endpoint `database` (for the interface `postgresql_client`). Read more details about the available [endpoints/interfaces](/explanation/interfaces-and-endpoints). @@ -35,7 +35,7 @@ The "modern" charm provides temporary support for the legacy interfaces: Reactive charms cannot be upgraded to an operator-framework-based version. To move database data, the new DB application must be launched nearby, and data should be copied from "legacy" application to the "modern" one. -Please [contact us](https://chat.charmhub.io/charmhub/channels/data-platform) if you need migration instructions. +Please [contact us](/reference/contacts) if you need migration instructions. ``` ## How to deploy old "legacy" PostgreSQL charm @@ -60,7 +60,7 @@ A common error message is: `cannot deploy application "postgresql": unknown opti The legacy charm config options were not moved to the modern charm due to no need. The modern charm applies the best possible configuration automatically. -Feel free to [contact us](https://chat.charmhub.io/charmhub/channels/data-platform) about the DB tuning/config options. +Feel free to [contact us](/reference/contacts) about the DB tuning/config options. ## Extensions supported by modern charm @@ -80,7 +80,7 @@ For more information about migrating the new interface, see [this guide](/how-to At the moment, the modern charms support PostgreSQL 14 (based on Jammy/22.04 series) only. -Please [contact us](https://chat.charmhub.io/charmhub/channels/data-platform) if you need different versions/series. +Please [contact us](/reference/contacts) if you need different versions/series. ## Supported architectures diff --git a/docs/explanation/logs.md b/docs/explanation/logs.md index 3bf4b00997..ecf91c03fb 100644 --- a/docs/explanation/logs.md +++ b/docs/explanation/logs.md @@ -98,5 +98,5 @@ Charmed PostgreSQL is configured to rotate PostgreSQL text logs every minute and For PostgreSQL, logs will be truncated when the week turns and the same minute of the same hour of the same weekday comes to pass. E.g. at 12:01 UTC on Monday either a new log file will be created or last week's log will be overwritten. -Due to Patroni only supporting size based rotation, it has been configured to retain logs for a comparatively similar timeframe as PostgreSQL. The assumed size of a minute of Patroni logs is 600 bytes, but the estimation is bound to be imprecise. Patroni will retain 10,080 log files (for every minute of a week). The current log is `patroni.log`, when rotating Patroni will append a number to the name of the file and remove logs over the limit. +Due to Patroni only supporting size based rotation, it has been configured to retain logs for a comparatively similar time frame as PostgreSQL. The assumed size of a minute of Patroni logs is 600 bytes, but the estimation is bound to be imprecise. Patroni will retain 10,080 log files (for every minute of a week). The current log is `patroni.log`, when rotating Patroni will append a number to the name of the file and remove logs over the limit. diff --git a/docs/explanation/security/cryptography.md b/docs/explanation/security/cryptography.md index efc81e2f7e..ff4933a27c 100644 --- a/docs/explanation/security/cryptography.md +++ b/docs/explanation/security/cryptography.md @@ -30,7 +30,7 @@ Charmed PostgreSQL can be used to deploy a secure PostgreSQL cluster that provid * PgBouncer connections * External clients connections -To set up a secure connection Charmed PostgreSQL and Charmed PgBouncer need to be integrated with TLS Certificate Provider charms, e.g. self-signed-certificates operator. Certificate Signing Requests (CSRs) are generated for every unit using the tls_certificates_interface library that uses the cryptography Python library to create X.509 compatible certificates. The CSR is signed by the TLS Certificate Provider, returned to the units, and stored in Juju secret. The relation also provides the CA certificate, which is loaded into Juju secret. +To set up a secure connection Charmed PostgreSQL and Charmed PgBouncer need to be integrated with TLS Certificate Provider charms, e.g. self-signed-certificates operator. Certificate Signing Requests (CSRs) are generated for every unit using the `tls_certificates_interface` library that uses the cryptography Python library to create X.509 compatible certificates. The CSR is signed by the TLS Certificate Provider, returned to the units, and stored in Juju secret. The relation also provides the CA certificate, which is loaded into Juju secret. Encryption at rest is currently not supported, although it can be provided by the substrate (cloud or on-premises). diff --git a/docs/explanation/security/index.md b/docs/explanation/security/index.md index 8b82c56161..813cfcb0f9 100644 --- a/docs/explanation/security/index.md +++ b/docs/explanation/security/index.md @@ -11,22 +11,22 @@ The environment where Charmed PostgreSQL operates can be divided into two compon ### Cloud -Charmed PostgreSQL can be deployed on top of several clouds and virtualization layers: +Charmed PostgreSQL can be deployed on top of several clouds and virtualisation layers: |Cloud|Security guides| | --- | --- | |OpenStack|[OpenStack Security Guide](https://docs.openstack.org/security-guide/)| -|AWS|[Best Practices for Security, Identity and Compliance](https://aws.amazon.com/architecture/security-identity-compliance), [AWS security credentials](https://docs.aws.amazon.com/IAM/latest/UserGuide/security-creds.html#access-keys-and-secret-access-keys)| +|AWS|[Best Practices for Security, Identity and Compliance](https://aws.amazon.com/architecture/security-identity-compliance), [AWS security credentials](https://docs.aws.amazon.com/IAM/latest/UserGuide/security-creds.html)| |Azure|[Azure security best practices and patterns](https://learn.microsoft.com/en-us/azure/security/fundamentals/best-practices-and-patterns), [Managed identities for Azure resource](https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/)| |GCP|[Google security overview](https://cloud.google.com/docs/security)| ### Juju -Juju is the component responsible for orchestrating the entire lifecycle, from deployment to Day 2 operations. For more information on Juju security hardening, see the [Juju security page](https://canonical-juju.readthedocs-hosted.com/en/latest/user/explanation/juju-security/) and the [How to harden your deployment](https://juju.is/docs/juju/harden-your-deployment) guide. +Juju is the component responsible for orchestrating the entire lifecycle, from deployment to Day 2 operations. For more information on Juju security hardening, see the [Juju security page](https://canonical-juju.readthedocs-hosted.com/en/latest/user/explanation/juju-security/) and the [How to harden your deployment](https://documentation.ubuntu.com/juju/latest/howto/manage-your-deployment/#harden-your-deployment) guide. #### Cloud credentials -When configuring cloud credentials to be used with Juju, ensure that users have correct permissions to operate at the required level. Juju superusers responsible for bootstrapping and managing controllers require elevated permissions to manage several kinds of resources, such as virtual machines, networks, storages, etc. Please refer to the links below for more information on the policies required to be used depending on the cloud. +When configuring cloud credentials to be used with Juju, ensure that users have correct permissions to operate at the required level. Juju superusers responsible for bootstrapping and managing controllers require elevated permissions to manage several kinds of resources, such as virtual machines, networks, storage, etc. Please refer to the links below for more information on the policies required to be used depending on the cloud. |Cloud|Cloud user policies| | --- | --- | @@ -39,7 +39,7 @@ When configuring cloud credentials to be used with Juju, ensure that users have It is very important that Juju users are set up with minimal permissions depending on the scope of their operations. Please refer to the [User access levels](https://juju.is/docs/juju/user-permissions) documentation for more information on the access levels and corresponding abilities. -Juju user credentials must be stored securely and rotated regularly to limit the chances of unauthorized access due to credentials leakage. +Juju user credentials must be stored securely and rotated regularly to limit the chances of unauthorised access due to credentials leakage. ## Applications @@ -93,9 +93,5 @@ For details on the cryptography used by Charmed PostgreSQL, see the [Cryptograph ```{toctree} -:titlesonly: -:maxdepth: 2 -:glob: -:hidden: - Cryptography +``` \ No newline at end of file diff --git a/docs/explanation/units.md b/docs/explanation/units.md index f53728bc25..9a8890c0eb 100644 --- a/docs/explanation/units.md +++ b/docs/explanation/units.md @@ -13,7 +13,7 @@ It is recommended to use 3+ units cluster size in production (due to [Raft conse All SQL transactions have to be confirmed by all Sync Standby unit(s) before Primary unit commit transaction to the client. Therefore, high-performance and high-availability is a trade-off between "sync standby" and "replica" unit count in the cluster. -Starting from revision 561, all Charmed PostgreSQL units are configured as Sync Standby members by default. It provides better guarantees for the data survival when two of three units gone simultaneously. Users can re-configure the necessary synchronous units count using Juju config option '[synchronous_node_count](https://charmhub.io/postgresql/configurations?channel=14/stable#synchronous_node_count)'. +Starting from revision 561, all Charmed PostgreSQL units are configured as Sync Standby members by default. It provides better guarantees for the data survival when two of three units gone simultaneously. Users can re-configure the necessary synchronous units count using Juju config option '[synchronous_node_count](https://charmhub.io/postgresql/configurations?channel=14/stable)'. ## Primary diff --git a/docs/explanation/users.md b/docs/explanation/users.md index 890092aff3..cceffbd9ed 100644 --- a/docs/explanation/users.md +++ b/docs/explanation/users.md @@ -14,7 +14,7 @@ The operator uses the following internal DB users: * `postgres` - the [initial/default](/how-to/manage-passwords) PostgreSQL user. Used for very initial bootstrap only. * `operator` - the user that `charm.py` uses to manage database/cluster. * `replication` - the user performs replication between database PostgreSQL cluster members. -* `rewind` - the internal user for synchronizing a PostgreSQL cluster with another copy of the same cluster. +* `rewind` - the internal user for synchronising a PostgreSQL cluster with another copy of the same cluster. * `monitoring` - the user for [COS integration](/how-to/monitoring-cos/enable-monitoring). * `backups` - the user to [perform/list/restore backups](/how-to/back-up-and-restore/create-a-backup). @@ -117,5 +117,5 @@ Read more about the supported charm interfaces in [](/explanation/interfaces-and The operator considers Identity users all those that are automatically created when the LDAP integration is enabled, or in other words, the [GLAuth](https://charmhub.io/glauth-k8s) charm is related/integrated. -When synchronized from the LDAP server, these users do not have any permissions by default, so the LDAP group they belonged to must be mapped to a PostgreSQL pre-defined authorization role by using the `ldap_map` configuration option. +When synchronised from the LDAP server, these users do not have any permissions by default, so the LDAP group they belonged to must be mapped to a PostgreSQL pre-defined authorisation role by using the `ldap_map` configuration option. diff --git a/docs/how-to/back-up-and-restore/configure-s3-radosgw.md b/docs/how-to/back-up-and-restore/configure-s3-radosgw.md index d2fb5f3fe3..170819cd74 100644 --- a/docs/how-to/back-up-and-restore/configure-s3-radosgw.md +++ b/docs/how-to/back-up-and-restore/configure-s3-radosgw.md @@ -9,7 +9,7 @@ This guide will teach you how to deploy and configure the s3-integrator charm on ``` ```{caution} -The Charmed PostgreSQL backup tool [pgBackRest](https://pgbackrest.org/) can currently only interact with S3-compatible storages if they work with [SSL/TLS](https://github.com/pgbackrest/pgbackrest/issues/2340). +The Charmed PostgreSQL backup tool [pgBackRest](https://pgbackrest.org/) can currently only interact with S3-compatible storage if they work with [SSL/TLS](https://github.com/pgbackrest/pgbackrest/issues/2340). Backup via plain HTTP is currently not supported. ``` diff --git a/docs/how-to/back-up-and-restore/index.md b/docs/how-to/back-up-and-restore/index.md index e6ef0f7020..f3f342d0b0 100644 --- a/docs/how-to/back-up-and-restore/index.md +++ b/docs/how-to/back-up-and-restore/index.md @@ -11,3 +11,4 @@ Create a backup Restore a backup Manage backup retention Migrate a cluster +``` \ No newline at end of file diff --git a/docs/how-to/back-up-and-restore/manage-backup-retention.md b/docs/how-to/back-up-and-restore/manage-backup-retention.md index c73b30afbb..123d90f67f 100644 --- a/docs/how-to/back-up-and-restore/manage-backup-retention.md +++ b/docs/how-to/back-up-and-restore/manage-backup-retention.md @@ -38,7 +38,7 @@ This configuration will be enforced in **every** Charmed PostgreSQL application ```{caution} The retention is **not** enforced automatically once a backup is older than the set amount of days. Backups older than the set retention time will only get expired only once a newer backup is created. -This behavior avoids complete backup deletion if no newer backups have been created in the charm. +This behaviour avoids complete backup deletion if no newer backups have been created in the charm. ``` The s3-integrator charm accepts many [configurations](https://charmhub.io/s3-integrator/configure) - enter whichever are necessary for your S3 storage. diff --git a/docs/how-to/cross-regional-async-replication/index.md b/docs/how-to/cross-regional-async-replication/index.md index dcf32076f3..12dd247896 100644 --- a/docs/how-to/cross-regional-async-replication/index.md +++ b/docs/how-to/cross-regional-async-replication/index.md @@ -4,7 +4,7 @@ Cross-regional (or multi-server) asynchronous replication focuses on disaster re ## Prerequisites * Juju `v.3.4.2+` -* Make sure your machine(s) fulfill the [system requirements](/reference/system-requirements) +* Make sure your machine(s) fulfil the [system requirements](/reference/system-requirements) ### Substrate dependencies @@ -18,24 +18,16 @@ The following table shows the source and target controller/model combinations th ## Guides -* [How to set up clusters for cross-regional async replication](/how-to/cross-regional-async-replication/set-up-clusters) -* [How to integrate with a client application](/how-to/cross-regional-async-replication/integrate-with-a-client-app) -* [How to remove or recover a cluster](/how-to/cross-regional-async-replication/remove-or-recover-a-cluster) - * [Switchover](/how-to/cross-regional-async-replication/remove-or-recover-a-cluster) - * [Detach](/how-to/cross-regional-async-replication/remove-or-recover-a-cluster) - * [Recover](/how-to/cross-regional-async-replication/remove-or-recover-a-cluster) - - -[check]: https://img.shields.io/badge/%E2%9C%93-brightgreen -[cross]: https://img.shields.io/badge/x-white - - ```{toctree} :titlesonly: :maxdepth: 2 -:glob: -:hidden: Set up clusters Integrate with a client app Remove or recover a cluster +``` + +[check]: https://img.shields.io/badge/%E2%9C%93-brightgreen +[cross]: https://img.shields.io/badge/x-white + + diff --git a/docs/how-to/cross-regional-async-replication/integrate-with-a-client-app.md b/docs/how-to/cross-regional-async-replication/integrate-with-a-client-app.md index 13f2c761bb..f9f6f3f46c 100644 --- a/docs/how-to/cross-regional-async-replication/integrate-with-a-client-app.md +++ b/docs/how-to/cross-regional-async-replication/integrate-with-a-client-app.md @@ -4,7 +4,7 @@ This guide will show you how to integrate a client application with a cross-regi ## Prerequisites * Juju `v.3.4.2+` -* Make sure your machine(s) fulfill the [system requirements](/reference/system-requirements) +* Make sure your machine(s) fulfil the [system requirements](/reference/system-requirements) * See [supported target/source model relationships](/how-to/cross-regional-async-replication/index). * A cross-regional async replication setup * See [How to set up clusters](/how-to/cross-regional-async-replication/set-up-clusters) diff --git a/docs/how-to/cross-regional-async-replication/remove-or-recover-a-cluster.md b/docs/how-to/cross-regional-async-replication/remove-or-recover-a-cluster.md index aa4d400dc6..6cf08bbdc6 100644 --- a/docs/how-to/cross-regional-async-replication/remove-or-recover-a-cluster.md +++ b/docs/how-to/cross-regional-async-replication/remove-or-recover-a-cluster.md @@ -4,7 +4,7 @@ This guide will cover how to manage clusters using an example PostgreSQL deploym ## Prerequisites * Juju `v.3.4.2+` -* Make sure your machine(s) fulfill the [system requirements](/reference/system-requirements) +* Make sure your machine(s) fulfil the [system requirements](/reference/system-requirements) * See [supported target/source model relationships](/how-to/cross-regional-async-replication/index). * A cross-regional async replication setup * See [How to set up clusters](/how-to/cross-regional-async-replication/set-up-clusters) diff --git a/docs/how-to/cross-regional-async-replication/set-up-clusters.md b/docs/how-to/cross-regional-async-replication/set-up-clusters.md index 8328e7b49b..7535e93f43 100644 --- a/docs/how-to/cross-regional-async-replication/set-up-clusters.md +++ b/docs/how-to/cross-regional-async-replication/set-up-clusters.md @@ -6,7 +6,7 @@ This guide will show you the basics of initiating a cross-regional async setup u ## Prerequisites * Juju `v.3.4.2+` -* Make sure your machine(s) fulfill the [system requirements](/reference/system-requirements) +* Make sure your machine(s) fulfil the [system requirements](/reference/system-requirements) * See [supported target/source model relationships](/how-to/cross-regional-async-replication/index). ## Deploy diff --git a/docs/how-to/deploy/air-gapped.md b/docs/how-to/deploy/air-gapped.md index 1d3a98781a..4c8469840b 100644 --- a/docs/how-to/deploy/air-gapped.md +++ b/docs/how-to/deploy/air-gapped.md @@ -9,23 +9,23 @@ Canonical does not prescribe how you should set up your specific air-gapped envi * A VM/hardware resources available for Juju. * DNS is configured to the local nameservers. -* [Juju is configured](https://documentation.ubuntu.com/snap-store-proxy/en/airgap-charmhub/#configure-juju) to use local air-gapped services. +* DNS is configured to the local nameservers. +* [Juju is configured](https://documentation.ubuntu.com/enterprise-store/main/how-to/airgap-charmhub/#configure-juju) to use local air-gapped services. * The [`store-admin`](https://snapcraft.io/store-admin) tool is installed and configured. -* [Air-gapped CharmHub](https://documentation.ubuntu.com/snap-store-proxy/en/airgap-charmhub/) is installed and running. -* [Air-gapped Snap Store Proxy](https://documentation.ubuntu.com/snap-store-proxy/) is installed and running. +* [Air-gapped Charmhub](https://documentation.ubuntu.com/enterprise-store/main/how-to/airgap-charmhub/#offline-charmhub-configuration) is installed and running. * Local APT and LXD Images caches are reachable. ## Air-gapped day-to-day example ### 1. Export snaps and charms -Exporting VM SNAPs and Charms and are currently independent processes. The `store-admin` tool is designed to simplify the process. +Exporting VM snaps and charms are currently independent processes. The `store-admin` tool is designed to simplify the process. -Future improvements are planned to the `store-admin` tool so that it could potentially export all necessary SNAP resource(s) from the official SnapStore with Charms simultaneously. Other planned improvements include supporting the export of specific charm and resource by revisions ([PF-5369](https://warthogs.atlassian.net/browse/PF-5369), [PF-5185](https://warthogs.atlassian.net/browse/PF-5185)). +Future improvements are planned to the `store-admin` tool so that it could potentially export all necessary snap resource(s) from the official Snap Store with charms simultaneously. Other planned improvements include supporting the export of specific charm and resource by revisions ([PF-5369](https://warthogs.atlassian.net/browse/PF-5369), [PF-5185](https://warthogs.atlassian.net/browse/PF-5185)). #### Charms - The necessary charm(s) can be exported as bundle or independently (charm-by-charm). See the Snap Proxy documentation: -* [Offline Charmhub configuration > Export charm bundle](https://documentation.ubuntu.com/snap-store-proxy/en/airgap-charmhub/#export-charm-bundles) -* [Offline Charmhub configuration > Export charms](https://documentation.ubuntu.com/snap-store-proxy/en/airgap-charmhub/#export-charms) +The necessary charm(s) can be exported as bundle or independently (charm-by-charm). See the Snap Proxy documentation: +* [Offline Charmhub configuration > Export charm bundle](https://documentation.ubuntu.com/enterprise-store/main/how-to/airgap-charmhub/#export-charm-bundles) +* [Offline Charmhub configuration > Export charms](https://documentation.ubuntu.com/enterprise-store/main/how-to/airgap-charmhub/#export-charms) The bundle export example: @@ -60,8 +60,8 @@ Successfully exported charm bundle postgresql-bundle: /home/ubuntu/snap/store-ad ``` -#### SNAPs -Usually charms require SNAPs (and some manually pin them). For the manual SNAP exports, follow the official Snap Store Proxy documentation: [Offline Charmhub configuration > Export SNAP](https://documentation.ubuntu.com/snap-store-proxy/en/airgap-charmhub/#export-snap-resources). Data team is shipping the mapping [snap.yaml](https://github.com/canonical/postgresql-bundle/blob/main/releases/latest/) to the published [bundle.yaml](https://github.com/canonical/postgresql-bundle/blob/main/releases/latest/): +#### Snaps +Usually charms require snaps (and some manually pin them). For the manual snap exports, follow the official Snap Store Proxy documentation: [Offline Charmhub configuration > Export snap](https://documentation.ubuntu.com/enterprise-store/main/how-to/airgap-charmhub/#export-snap-resources). Data team is shipping the mapping [snap.yaml](https://github.com/canonical/postgresql-bundle/blob/main/releases/latest/) to the published [bundle.yaml](https://github.com/canonical/postgresql-bundle/blob/main/releases/latest/): > **Warning**: always use snap.yaml and bundle.yaml from the same Git commit (to match each other)! @@ -104,7 +104,7 @@ Always check [checksum](https://en.wikipedia.org/wiki/Checksum) for the transfer ### 3. Import snaps and charms - Import the [snap](https://documentation.ubuntu.com/snap-store-proxy/en/airgap/#importing-pushing-snaps) and [charm](https://documentation.ubuntu.com/snap-store-proxy/en/airgap-charmhub/#import-packages) blobs into local air-gapped CharmHub: +Import the [snap](https://documentation.ubuntu.com/enterprise-store/main/how-to/airgap/#importing-pushing-snaps) and [charm](https://documentation.ubuntu.com/enterprise-store/main/how-to/airgap-charmhub/#import-packages) blobs into local air-gapped Charmhub: When importing machine charms that depend on a snap for functionality, you must first manually import the required snap. @@ -114,7 +114,7 @@ sudo snap-store-proxy push-snap /var/snap/snap-store-proxy/common/snaps-to-push/ sudo snap-store-proxy push-charm-bundle /var/snap/snap-store-proxy/common/charms-to-push/postgresql-bundle-20241003T104903.tar.gz ``` -When [re-importing](https://documentation.ubuntu.com/snap-store-proxy/en/airgap-charmhub/#import-packages) charms or importing other revisions, make sure to provide the `--push-channel-map`. +When re-importing charms or importing other revisions, make sure to provide the `--push-channel-map`. ### 4. Deploy PostgreSQL @@ -132,10 +132,10 @@ Use [the official release notes](/reference/releases) as a reference. ## Additional resources -* https://docs.ubuntu.com/snap-store-proxy/en/airgap -* https://documentation.ubuntu.com/snap-store-proxy/ -* https://documentation.ubuntu.com/snap-store-proxy/en/airgap-charmhub/ -* https://ubuntu.com/kubernetes/docs/install-offline +* `https://docs.ubuntu.com/snap-store-proxy/en/airgap` +* `https://documentation.ubuntu.com/snap-store-proxy/` +* `https://documentation.ubuntu.com/snap-store-proxy/en/airgap-charmhub/` +* `https://ubuntu.com/kubernetes/docs/install-offline` * [Charmed Kubeflow > Install in an airgapped environment](https://charmed-kubeflow.io/docs/install-in-an-airgapped-environment) * [Wikipedia > Air gap (networking)](https://en.wikipedia.org/wiki/Air_gap_(networking)) diff --git a/docs/how-to/deploy/aws-ec2.md b/docs/how-to/deploy/aws-ec2.md index 24b88082ed..83f8d79e78 100644 --- a/docs/how-to/deploy/aws-ec2.md +++ b/docs/how-to/deploy/aws-ec2.md @@ -95,7 +95,8 @@ to create a new model to deploy workloads. ``` -You can check the [AWS EC2 instance availability](https://us-east-1.console.aws.amazon.com/ec2/home?region=us-east-1#Instances:instanceState=running) (ensure the right AWS region chosen!): + +You can check the AWS EC2 instance availability (ensure the right AWS region chosen!): ![image|690x118](aws-ec2-availability.png) Create a new Juju model: @@ -184,7 +185,7 @@ From here you can [use/scale/backup/restore/refresh](/tutorial/index) your newly ## Expose database (optional) -If necessary to access DB from outside of AWS (warning: [opening ports to public is risky](https://www.beyondtrust.com/blog/entry/what-is-an-open-port-what-are-the-security-implications)) open the AWS firewall using the simple [juju expose](https://juju.is/docs/juju/juju-expose) functionality: +If necessary to access DB from outside of AWS (warning: opening ports to public is risky) open the AWS firewall using the simple [juju expose](https://juju.is/docs/juju/juju-expose) functionality: ```text juju expose postgresql ``` diff --git a/docs/how-to/deploy/azure.md b/docs/how-to/deploy/azure.md index 9d3e1ef046..2439484116 100644 --- a/docs/how-to/deploy/azure.md +++ b/docs/how-to/deploy/azure.md @@ -142,7 +142,7 @@ Now you can run to create a new model to deploy workloads. ``` -You can check the [Azure instances availability](https://portal.azure.com/#browse/Microsoft.Compute%2FVirtualMachines): +You can check the [Azure instances availability](https://portal.azure.com/#browse/Microsoft.Compute/VirtualMachines): ![image|689x313](azure-availability.png) @@ -238,7 +238,7 @@ juju expose postgresql ``` ```{caution} -Be wary that [opening ports to the public is risky](https://www.beyondtrust.com/blog/entry/what-is-an-open-port-what-are-the-security-implications). +Be wary that opening ports to the public is risky. ``` Once exposed, you can connect your database using the same credentials as above. This time use the Azure VM public IP assigned to the PostgreSQL instance. You can see this with `juju status`: diff --git a/docs/how-to/deploy/gce.md b/docs/how-to/deploy/gce.md index 6f5618aafd..cd7839a950 100644 --- a/docs/how-to/deploy/gce.md +++ b/docs/how-to/deploy/gce.md @@ -56,7 +56,7 @@ created key [aaaaaaa....aaaaaaa] of type [json] as [sa-private-key.json] for [ju ## Bootstrap Juju controller on GCE -Move the newly exported GCloud json file into a snap-accessible folder due to a known Juju [issue](https://bugs.launchpad.net/juju/+bug/2007575). +Move the newly exported GCloud JSON file into a snap-accessible folder due to a known Juju [issue](https://bugs.launchpad.net/juju/+bug/2007575). ```text @@ -266,7 +266,7 @@ Remove GCloud credentials from Juju: > juju remove-credential google juju-gce-account ``` -Finally, remove GCloud jsonfile user credentials (to avoid forgetting and leaking): +Finally, remove GCloud JSON file user credentials (to avoid forgetting and leaking): ```text rm -f /var/snap/juju/common/sa-private-key.json ``` diff --git a/docs/how-to/deploy/index.md b/docs/how-to/deploy/index.md index a916ed60a4..d2108aa708 100644 --- a/docs/how-to/deploy/index.md +++ b/docs/how-to/deploy/index.md @@ -44,7 +44,7 @@ See also: * [How to connect from outside the local network] ## Airgapped -[How to deploy in an offline or air-gapped environment] goes over the special configuration steps for installing PostgreSQL in an airgapped environment via CharmHub and the Snap Store Proxy. +[How to deploy in an offline or air-gapped environment] goes over the special configuration steps for installing PostgreSQL in an airgapped environment via Charmhub and the Snap Store Proxy. ## Cluster-cluster replication @@ -53,7 +53,7 @@ Cluster-cluster, cross-regional, or multi-server asynchronous replication focuse The [Cross-regional async replication] guide goes through the steps to set up clusters for cluster-cluster replication, integrate with a client, and remove or recover a failed cluster. ## Juju storage -Charmed PostgreSQL uses the [Juju storage](https://documentation.ubuntu.com/juju/3.6/reference/storage/) abstraction to utilize data volume provided by different clouds while keeping the same UI/UX for end users. +Charmed PostgreSQL uses the [Juju storage](https://documentation.ubuntu.com/juju/3.6/reference/storage/) abstraction to use data volume provided by different clouds while keeping the same UI/UX for end users. See: [How to deploy on juju storage] diff --git a/docs/how-to/deploy/juju-storage.md b/docs/how-to/deploy/juju-storage.md index 7aa178ccb8..3573210fd4 100644 --- a/docs/how-to/deploy/juju-storage.md +++ b/docs/how-to/deploy/juju-storage.md @@ -1,6 +1,6 @@ # Deploy on Juju storage -Charmed PostgreSQL uses the [Juju storage](https://documentation.ubuntu.com/juju/3.6/reference/storage/) abstraction to utilize data volume provided by different [clouds](https://documentation.ubuntu.com/juju/3.6/reference/cloud/#cloud) while keeping the same UI/UX for end users. +Charmed PostgreSQL uses the [Juju storage](https://documentation.ubuntu.com/juju/3.6/reference/storage/) abstraction to utilise data volume provided by different [clouds](https://documentation.ubuntu.com/juju/3.6/reference/cloud/#cloud) while keeping the same UI/UX for end users. Charmed PostgreSQL 14 supports a single storage: `pgdata`. diff --git a/docs/how-to/deploy/maas.md b/docs/how-to/deploy/maas.md index 40650674d0..a904e6edb6 100644 --- a/docs/how-to/deploy/maas.md +++ b/docs/how-to/deploy/maas.md @@ -1,6 +1,6 @@ # How to deploy on MAAS -This guide aims to provide a quick start to deploying Charmed PostgreSQL on MAAS. It summarizes the instructions from the [Build a MAAS and LXD environment with Multipass Tutorial](https://discourse.maas.io/t/5360) to set up and tear down a **playground environment**. +This guide aims to provide a quick start to deploying Charmed PostgreSQL on MAAS. It summarises the instructions from the [Build a MAAS and LXD environment with Multipass Tutorial](https://discourse.maas.io/t/5360) to set up and tear down a **playground environment**. If you want to deploy PostgreSQL on MAAS in a **production environment**, refer to the official [Bootstrap MAAS Tutorial](https://maas.io/docs/tutorial-bootstrapping-maas) followed by the [Charmed PostgreSQL Tutorial](/tutorial/index). @@ -15,7 +15,7 @@ sudo snap install multipass wget -qO- https://raw.githubusercontent.com/canonical/maas-multipass/main/maas.yml \ | multipass launch --name maas -c8 -m12GB -d50GB --cloud-init - ``` -> The wget command provides a [cloud-init](https://github.com/canonical/maas-multipass/blob/main/maas.yml) file that will set up the VM's LXD and MAAS environment. +> The wget command provides a [cloud-init](https://github.com/canonical/maas-multipass/blob/main/maas.yml) file that will set up the LXD and MAAS environment. ## Configure MAAS diff --git a/docs/how-to/deploy/sunbeam.md b/docs/how-to/deploy/sunbeam.md index 8f55b35fe7..6d1b443a75 100644 --- a/docs/how-to/deploy/sunbeam.md +++ b/docs/how-to/deploy/sunbeam.md @@ -20,7 +20,7 @@ This guide assumes you have: Follow the official OpenStack guide: [Single-node deployment][Single-node guided]. -Pay attention to the `Caution` and `Note` sections - the `/etc/hosts` will require a [manual fqdn fix](https://github.com/canonical/multipass/issues/3277#issuecomment-2471434029). +Pay attention to the `Caution` and `Note` sections - the `/etc/hosts` will require a [manual {spellexception}`fqdn` fix](https://github.com/canonical/multipass/issues/3277#issuecomment-2471434029). ## Enable OpenStack images auto-sync @@ -30,7 +30,7 @@ Follow the official [Images Sync] guide to enable auto-sync and wait for the ima Follow the MicroStack guide [Manage workloads with Juju] from the beginning, and stop after the section "Create a Juju controller". -To summarize, the relevant sections are: +To summarise, the relevant sections are: * Set up the bastion * Install and configure the Juju client * Create a Juju controller diff --git a/docs/how-to/deploy/terraform.md b/docs/how-to/deploy/terraform.md index c3ba64c849..745fcfa211 100644 --- a/docs/how-to/deploy/terraform.md +++ b/docs/how-to/deploy/terraform.md @@ -1,6 +1,6 @@ # How to deploy using Terraform -[Terraform](https://www.terraform.io/) is an infrastructure automation tool to provision and manage resources in clouds or data centers. To deploy Charmed PostgreSQL using Terraform and Juju, you can use the [Juju Terraform Provider](https://registry.terraform.io/providers/juju/juju/latest). +[Terraform](https://www.terraform.io/) is an infrastructure automation tool to provision and manage resources in clouds or data centres. To deploy Charmed PostgreSQL using Terraform and Juju, you can use the [Juju Terraform Provider](https://registry.terraform.io/providers/juju/juju/latest). The easiest way is to start from [these examples of terraform modules](https://github.com/canonical/terraform-modules) prepared by Canonical. This page will guide you through a deployment using an example module for PostgreSQL on machines. diff --git a/docs/how-to/deploy/tls-vip-access.md b/docs/how-to/deploy/tls-vip-access.md index 9621beca1e..9e373110a2 100644 --- a/docs/how-to/deploy/tls-vip-access.md +++ b/docs/how-to/deploy/tls-vip-access.md @@ -15,7 +15,7 @@ The basic requirements to follow along with this example setup are the following * A fully deployed and running Juju machine environment * See the [PostgreSQL Tutorial](/tutorial/index) for a quick setup with Multipass * See the official [Juju deployment guide](https://juju.is/docs/juju/tutorial#deploy) for more details -* A spare virtual IP address for [hacluster](https://discourse.charmhub.io/t/pgbouncer-how-to-externally-access/15741#using-a-virtual-ip-to-connect-to-pgbouncer) +* A spare virtual IP address for [`hacluster`](https://discourse.charmhub.io/t/pgbouncer-how-to-externally-access/15741) * See the PgBouncer guide: [How to use a VIP to connect to PgBouncer](https://charmhub.io/pgbouncer/docs/h-external-access?channel=1/stable) * DNS record pointing to VIP above (`my-tls-example-db.local` is used as an example here) @@ -32,7 +32,7 @@ This setup deploys the following components: * The [`postgresql`](https://charmhub.io/postgresql) charm (3 units, as a single cluster). * The [`self-signed-certificates`](https://charmhub.io/self-signed-certificates) charm as the TLS provider. * Note that this is not suitable for production deployments. See the guide: [Security with X.509 certificates](https://charmhub.io/topics/security-with-x-509-certificates). -* The [`data-integrator`](https://charmhub.io/data-integrator) charm as a [principal](https://juju.is/docs/sdk/charm-taxonomy#principal-charms) charm for the [subordinated](https://juju.is/docs/sdk/charm-taxonomy#subordinate-charms) charms below (3 units for high availability): +* The [`data-integrator`](https://charmhub.io/data-integrator) charm as a [principal](https://documentation.ubuntu.com/juju/3.6/reference/charm/#principal) charm for the [subordinated](https://documentation.ubuntu.com/juju/3.6/reference/charm/#subordinate) charms below (3 units for high availability): * The latest [`pgbouncer`](https://charmhub.io/pgbouncer?channel=1/stable) charm as a load-balancer and connection pooler (3 units). * The [`hacluster`](https://charmhub.io/hacluster) charm for VIP handling (3 units are the minimum for HA). * (optional) The COS [`grafana-agent`](https://charmhub.io/grafana-agent) charm for Monitoring purposes. @@ -174,7 +174,7 @@ At this point, Juju is responsible for the health of the clusters/applications: * The PostgreSQL charm will restart the workload if PostgreSQL is not healthy. * The Juju agent will restart the unit/vm/container if it is no longer reachable/healthy (in the same AZ). * The Juju controller will make sure Juju agent is up and running and charm is healthy. -* The HACluster charm will make sure the VIP is always reachable and routes to a single PgBouncer. +* The HA Cluster charm will make sure the VIP is always reachable and routes to a single PgBouncer. * PgBouncer will balance incoming connections and makes sure write traffic goes to the primary PostgreSQL unit. * The TLS operator (in this example, the `self-signed-certificates` charm) is responsible for providing all components with signed ready-to-use TLS artifacts. diff --git a/docs/how-to/development/index.md b/docs/how-to/development/index.md index fd79237643..abbefea037 100644 --- a/docs/how-to/development/index.md +++ b/docs/how-to/development/index.md @@ -8,3 +8,4 @@ Integrate with your charm Migrate data via pg_dump Migrate data via backup/restore +``` \ No newline at end of file diff --git a/docs/how-to/development/integrate-with-your-charm.md b/docs/how-to/development/integrate-with-your-charm.md index 94221b4a4f..997480707d 100644 --- a/docs/how-to/development/integrate-with-your-charm.md +++ b/docs/how-to/development/integrate-with-your-charm.md @@ -12,7 +12,7 @@ Legacy charm details are described [here](/explanation/legacy-charm). ## Integrate your charm with PostgreSQL -**For an introduction** to the concepts of Juju integrations, see [Juju | Integration](https://juju.is/docs/juju/integration). +**For an introduction** to the concepts of Juju integrations, see [Juju | Integration](https://documentation.ubuntu.com/juju/3.6/reference/relation/). **For a detailed tutorial** about integrating your charm with the PostgreSQL charm, refer to [Juju | Integrate your charm with PostgreSQL](https://juju.is/docs/sdk/integrate-your-charm-with-postgresql). @@ -34,7 +34,7 @@ Legacy charm details are described [here](/explanation/legacy-charm). **Is there a charm library available, or does my charm need to compile the postgresql relation data on its own?** >Yes, a library is available: [data-platform-libs](https://github.com/canonical/data-platform-libs). The integration is trivial: [example](https://github.com/nextcloud-charmers/nextcloud-charms/pull/78). -**How do I obtain the database url/uri?** +**How do I obtain the database URL/URI?** >This feature is [planned](https://warthogs.atlassian.net/browse/DPE-2278) but currently missing. > >Meanwhile, use [this](https://github.com/nextcloud-charmers/nextcloud-charms/blob/91f9eebb4d40eaaff9c2f7513f66980df75c2a3b/operator-nextcloud/src/charm.py#L610-L631) example or refer to the function below. diff --git a/docs/how-to/development/migrate-data-via-pg-dump.md b/docs/how-to/development/migrate-data-via-pg-dump.md index b7858b93ae..46b2195adc 100644 --- a/docs/how-to/development/migrate-data-via-pg-dump.md +++ b/docs/how-to/development/migrate-data-via-pg-dump.md @@ -35,7 +35,7 @@ Always test migration in a safe environment before performing it in production! - **[Your application is compatible](/explanation/legacy-charm) with Charmed PostgreSQL VM** - A client machine with access to the deployed legacy charm -- `juju v.2.9` or later (check [Juju 3.0 Release Notes](https://juju.is/docs/juju/roadmap#juju-3-0-0---22-oct-2022) for more information about key differences) +- `juju v.2.9` or later (check [Juju 3.0 Release Notes](https://documentation.ubuntu.com/juju/3.6/reference/juju/juju-roadmap-and-releases/#juju-3-0-0-22-oct-2022) for more information about key differences) - Enough storage in the cluster to support backup/restore of the databases. ## Obtain existing database credentials diff --git a/docs/how-to/enable-ldap.md b/docs/how-to/enable-ldap.md index bda04f3800..5e407f81f1 100644 --- a/docs/how-to/enable-ldap.md +++ b/docs/how-to/enable-ldap.md @@ -1,6 +1,6 @@ # How to enable LDAP authentication -The Lightweight Directory Access Protocol (LDAP) enables centralized authentication for PostgreSQL clusters, reducing the overhead of managing local credentials and access policies. +The Lightweight Directory Access Protocol (LDAP) enables centralised authentication for PostgreSQL clusters, reducing the overhead of managing local credentials and access policies. This guide goes over the steps to integrate LDAP as an authentication method with the PostgreSQL charm, all within the Juju ecosystem. @@ -107,7 +107,7 @@ juju integrate postgresql:receive-ca-cert send-ca-cert ## Map LDAP users to PostgreSQL -To have LDAP users available in PostgreSQL, provide a comma separated list of LDAP groups to already created PostgreSQL authorization groups. To create those groups before hand, refer to the [data integrator charm](https://charmhub.io/data-integrator). +To have LDAP users available in PostgreSQL, provide a comma separated list of LDAP groups to already created PostgreSQL authorisation groups. To create those groups before hand, refer to the [data integrator charm](https://charmhub.io/data-integrator). ```text juju config postgresql ldap_map="=" diff --git a/docs/how-to/enable-plugins-extensions/index.md b/docs/how-to/enable-plugins-extensions/index.md index 9e3b372321..912fc38537 100644 --- a/docs/how-to/enable-plugins-extensions/index.md +++ b/docs/how-to/enable-plugins-extensions/index.md @@ -42,4 +42,5 @@ Not all PostgreSQL extensions are available. The list of supported extensions is :glob: :hidden: -Enable TimescaleDB \ No newline at end of file +Enable TimescaleDB +``` \ No newline at end of file diff --git a/docs/how-to/external-network-access.md b/docs/how-to/external-network-access.md index d11e2480f5..d3e6dc123d 100644 --- a/docs/how-to/external-network-access.md +++ b/docs/how-to/external-network-access.md @@ -1,12 +1,12 @@ # How to connect from outside the local network -This page summarizes resources for setting up deployments where an external application must connect to a PostgreSQL database from outside the local area network. +This page summarises resources for setting up deployments where an external application must connect to a PostgreSQL database from outside the local area network. ## External application (non-Juju) **Use case**: The client application is a non-Juju application outside of the local area network where Juju and the database are running. -There are many possible ways to connect the Charmed PostgreSQL database from outside of the LAN where the database cluster is located. The available options are heavily dependent on the cloud/hardware/virtualization in use. +There are many possible ways to connect the Charmed PostgreSQL database from outside of the LAN where the database cluster is located. The available options are heavily dependent on the cloud/hardware/virtualisation in use. One of the possible options is to use [virtual IP addresses (VIP)](https://en.wikipedia.org/wiki/Virtual_IP_address) which the charm PgBouncer provides with assistance from the charm/interface `hacluster`. Please follow the [PgBouncer documentation](https://charmhub.io/pgbouncer/docs/h-external-access) for such configuration. diff --git a/docs/how-to/index.md b/docs/how-to/index.md index 12c5525a4a..6253aa03a9 100644 --- a/docs/how-to/index.md +++ b/docs/how-to/index.md @@ -128,4 +128,4 @@ Monitoring (COS) Upgrade Cross-regional async replication Development - +``` diff --git a/docs/how-to/manage-passwords.md b/docs/how-to/manage-passwords.md index b6317f1739..41d81ca2ef 100644 --- a/docs/how-to/manage-passwords.md +++ b/docs/how-to/manage-passwords.md @@ -12,7 +12,7 @@ juju run postgresql/leader get-password ## Set password -To change the operator's password to a new, randomized password: +To change the operator's password to a new, randomised password: ```text juju run postgresql/leader set-password diff --git a/docs/how-to/monitoring-cos/enable-alert-rules.md b/docs/how-to/monitoring-cos/enable-alert-rules.md index dab0c5dbd4..b9708d8a6d 100644 --- a/docs/how-to/monitoring-cos/enable-alert-rules.md +++ b/docs/how-to/monitoring-cos/enable-alert-rules.md @@ -21,7 +21,7 @@ For information about accessing and managing COS Alert Rules, refer to the [COS The following section is an example of the [Pushover](https://pushover.net/) alerts aggregator. -The first step is to create a new account on Pushover (or use an existing one). The goal is to have the 'user key' and 'token' to authorize alerts for the Pushover application. Follow this straightforward [Pushover guide](https://support.pushover.net/i175-how-to-get-a-pushover-api-or-pushover-application-token). +The first step is to create a new account on Pushover (or use an existing one). The goal is to have the 'user key' and 'token' to authorise alerts for the Pushover application. Follow this straightforward [Pushover guide](https://support.pushover.net/i175-how-to-get-a-pushover-api-or-pushover-application-token). Next, create a new [COS Alert Manager](https://charmhub.io/alertmanager-k8s) config (replace `user_key` and `token` with yours): ```text diff --git a/docs/how-to/monitoring-cos/enable-monitoring.md b/docs/how-to/monitoring-cos/enable-monitoring.md index 5c2386316b..3c1c40f34c 100644 --- a/docs/how-to/monitoring-cos/enable-monitoring.md +++ b/docs/how-to/monitoring-cos/enable-monitoring.md @@ -138,7 +138,7 @@ prometheus prometheus prometheus-k8s 103 1/1 receive-remote-write ### Connect Grafana web interface -To connect to the Grafana web interface, follow the [Browse dashboards](https://charmhub.io/topics/canonical-observability-stack/tutorials/install-microk8s?_ga=2.201254254.1948444620.1704703837-757109492.1701777558#browse-dashboards) section of the MicroK8s "Getting started" guide. +To connect to the Grafana web interface, follow the [Browse dashboards](https://charmhub.io/topics/canonical-observability-stack/tutorials/install-microk8s) section of the MicroK8s "Getting started" guide. ```text juju run grafana/leader get-admin-password --model : diff --git a/docs/how-to/monitoring-cos/enable-profiling.md b/docs/how-to/monitoring-cos/enable-profiling.md index b1f2d3acca..6d861305d6 100644 --- a/docs/how-to/monitoring-cos/enable-profiling.md +++ b/docs/how-to/monitoring-cos/enable-profiling.md @@ -9,14 +9,14 @@ Read the [](#prerequisites) section carefully if you are deploying PostgreSQL in ## Prerequisites * A juju model with [Charmed PostgreSQL deployed](/how-to/deploy/index). -* **If you are using an LXD model**, LXD's virtualization type must be set to `virtual-machine`. - * See [](#lxd-virtualization-type) for more details. -* **If your base is `ubuntu@22.4`**, you must use the `generic` flavor of Linux. +* **If you are using an LXD model**, LXD's virtualisation type must be set to `virtual-machine`. + * See [](#lxd-virtualisation-type) for more details. +* **If your base is `ubuntu@22.4`**, you must use the `generic` flavour of Linux. * See [](#base-ubuntu-version) for more details. -### LXD virtualization type +### LXD virtualisation type -If you are deploying Charmed PostgreSQL in a LXD model, ensure that LXD's virtualization type is set to `virtual-machine` for the Juju application. +If you are deploying Charmed PostgreSQL in a LXD model, ensure that LXD's virtualisation type is set to `virtual-machine` for the Juju application. This is because LXD does not allow `/sys/kernel/tracing` to be mounted in a system container (even in privileged mode) due to security isolation concerns. @@ -27,14 +27,14 @@ juju deploy postgresql --channel 14/stable --constraints="virt-type=virtual-mach ``` ### Base (Ubuntu version) -If your base is `ubuntu@22.04`, ensure that your are using the `generic` flavor of Linux. +If your base is `ubuntu@22.04`, ensure that your are using the `generic` flavour of Linux. You can confirm this with ``` uname -r ``` -If you do not have the `generic` flavor, you can enable it on a unit to be profiled as follows: +If you do not have the `generic` flavour, you can enable it on a unit to be profiled as follows: ```text juju ssh postgresql/0 bash @@ -103,7 +103,7 @@ juju integrate postgresql parca-agent #### 4. Integrate `parca-agent` with `parca-k8s` -Consume the parca offer from [Step 2](#parca-offer-interfaces) and integrate with them: +Consume the Parca offer from [Step 2](#parca-offer-interfaces) and integrate with them: ```text juju find-offers : diff --git a/docs/how-to/monitoring-cos/enable-tracing.md b/docs/how-to/monitoring-cos/enable-tracing.md index 856bcd56bb..c79ce56932 100644 --- a/docs/how-to/monitoring-cos/enable-tracing.md +++ b/docs/how-to/monitoring-cos/enable-tracing.md @@ -25,12 +25,12 @@ juju switch : ``` Then, deploy the dependencies of Tempo following [this tutorial](https://discourse.charmhub.io/t/tutorial-deploy-tempo-ha-on-top-of-cos-lite/15489). In particular, we would want to: -- Deploy the minio charm -- Deploy the s3 integrator charm -- Add a bucket into minio using a python script -- Configure s3 integrator with the minio credentials +- Deploy the MinIO charm +- Deploy the S3 integrator charm +- Add a bucket into MinIO using a python script +- Configure S3 integrator with the MinIO credentials -Finally, deploy and integrate with Tempo HA in [a monolithic setup](https://discourse.charmhub.io/t/tutorial-deploy-tempo-ha-on-top-of-cos-lite/15489#deploy-monolithic-setup). +Finally, deploy and integrate with Tempo HA in [a monolithic setup](https://discourse.charmhub.io/t/tutorial-deploy-tempo-ha-on-top-of-cos-lite/15489). ## Offer interfaces diff --git a/docs/how-to/monitoring-cos/index.md b/docs/how-to/monitoring-cos/index.md index 706b34cdd9..2c0fad0301 100644 --- a/docs/how-to/monitoring-cos/index.md +++ b/docs/how-to/monitoring-cos/index.md @@ -9,3 +9,4 @@ Enable monitoring Enable alert rules Enable tracing Enable profiling +``` \ No newline at end of file diff --git a/docs/how-to/scale-replicas.md b/docs/how-to/scale-replicas.md index f583fdaa87..89f4b75ab6 100644 --- a/docs/how-to/scale-replicas.md +++ b/docs/how-to/scale-replicas.md @@ -29,7 +29,7 @@ juju run postgresql/leader get-primary Similarly, the primary replica is displayed as a status message in `juju status`. However, one should note that this hook gets called on regular time intervals and the primary may be outdated if the status hook has not been called recently. ````{note} -**We highly suggest configuring the `update-status` hook to run frequently.** In addition to reporting the primary, secondaries, and other statuses, the [status hook](https://juju.is/docs/sdk/update-status-event) performs self-healing in the case of a network cut. +**We highly suggest configuring the `update-status` hook to run frequently.** In addition to reporting the primary, secondaries, and other statuses, the [status hook](https://documentation.ubuntu.com/juju/3.6/reference/hook/#update-status) performs self-healing in the case of a network cut. To change the frequency of the `update-status` hook, run diff --git a/docs/how-to/switchover-failover.md b/docs/how-to/switchover-failover.md index 171c530808..21f3e4ad43 100644 --- a/docs/how-to/switchover-failover.md +++ b/docs/how-to/switchover-failover.md @@ -22,9 +22,9 @@ Note that: Charmed PostgreSQL doesn't provide manual failover due to lack of data safety guarantees. -Advanced users can still execute it using [patronictl](/reference/troubleshooting/cli-helpers) and [Patroni REST API](/reference/troubleshooting/cli-helpers). The same time Charmed PostgreSQL allows the cluster recovery using the full PostgreSQL/Patroni/Raft cluster re-initialization. +Advanced users can still execute it using [patronictl](/reference/troubleshooting/cli-helpers) and [Patroni REST API](/reference/troubleshooting/cli-helpers). The same time Charmed PostgreSQL allows the cluster recovery using the full PostgreSQL/Patroni/Raft cluster re-initialisation. -## Raft re-initialization +## Raft re-initialisation ```{caution} This is the worst possible recovery case scenario when Primary and ALL Sync Standby units lost simultaneously and their data cannot be recovered from the disc. @@ -34,17 +34,17 @@ In this case, Patroni cannot perform automatic failover for the only available R A manual failover procedure cannot guarantee the latest SQL transactions' availability on the replica unit(s) due to the [lag distance](/explanation/units) to the primary. Additionally, Raft cluster consensus is not possible when one unit is left in a three-unit cluster. ``` -The command to re-initialize the Raft cluster should be executed when charm is ready: +The command to re-initialise the Raft cluster should be executed when charm is ready: * the last Juju unit is available in Juju application * the last unit was has detected Raft majority lost, status: `Raft majority loss, run: promote-to-primary` -To re-initialize Raft and fix the Partition/PostgreSQL cluster (when requested): +To re-initialise Raft and fix the Partition/PostgreSQL cluster (when requested): ```text juju run postgresql/x promote-to-primary scope=unit force=true ``` -
Example of Raft re-initialization +
Example of Raft re-initialisation Deploy PostgreSQL 3 units: @@ -108,7 +108,7 @@ Machine State Address Inst id Base AZ Message At this stage it is recommended to restore the lost nodes, they will rejoin the cluster automatically once Juju detects their availability. -To start Raft re-initialization, remove DEAD machines as a signal to charm that they cannot be restored/started and no risks for split-brain: +To start Raft re-initialisation, remove DEAD machines as a signal to charm that they cannot be restored/started and no risks for split-brain: ```text > juju remove-machine --force 0 @@ -136,7 +136,7 @@ postgresql/1* blocked executing 1 10.189.210.166 5432/tcp Raft majo ... ``` -Start Raft re-initialization: +Start Raft re-initialisation: ```text > juju run postgresql/1 promote-to-primary scope=unit force=true diff --git a/docs/how-to/upgrade/index.md b/docs/how-to/upgrade/index.md index 4c95507927..b1e65a7b4a 100644 --- a/docs/how-to/upgrade/index.md +++ b/docs/how-to/upgrade/index.md @@ -21,3 +21,4 @@ We will soon publish a migration guide with instructions on how to change from P Perform a minor upgrade Perform a minor rollback +``` \ No newline at end of file diff --git a/docs/how-to/upgrade/perform-a-minor-upgrade.md b/docs/how-to/upgrade/perform-a-minor-upgrade.md index 47e5bfff80..3cedcebc74 100644 --- a/docs/how-to/upgrade/perform-a-minor-upgrade.md +++ b/docs/how-to/upgrade/perform-a-minor-upgrade.md @@ -78,7 +78,7 @@ juju run postgresql/leader pre-upgrade-check ``` Make sure there are no errors in the result output. -This action will configure the charm to minimize the amount of primary switchover, among other preparations for a safe upgrade process. After successful execution, the charm is ready to be upgraded. +This action will configure the charm to minimise the amount of primary switchover, among other preparations for a safe upgrade process. After successful execution, the charm is ready to be upgraded. ## Step 3: Upgrade diff --git a/docs/index.md b/docs/index.md index 3ebd1abf5e..317d2dc791 100644 --- a/docs/index.md +++ b/docs/index.md @@ -25,7 +25,7 @@ Charmed PostgreSQL is an official distribution of PostgreSQL. It’s an open-sou - Explore [Canonical Data solutions](https://canonical.com/data) - [Contacts us](/reference/contacts) for all further questions -## Licencing & Trademark +## Licensing & Trademark The Charmed PostgreSQL Operator is distributed under the [Apache Software Licence version 2.0](https://github.com/canonical/postgresql-operator/blob/main/LICENSE). It depends on [PostgreSQL](https://www.postgresql.org/ftp/source/), which is licensed under the [PostgreSQL License](https://www.postgresql.org/about/licence/) - a liberal open-source licence similar to the BSD or MIT licences. @@ -43,4 +43,4 @@ Tutorial How-to guides Reference Explanation - +``` diff --git a/docs/reference/alert-rules.md b/docs/reference/alert-rules.md index a3c20c0a71..fa97edc3a5 100644 --- a/docs/reference/alert-rules.md +++ b/docs/reference/alert-rules.md @@ -19,7 +19,7 @@ This page contains a markdown version of the alert rules described in the `postg | PostgresqlTooManyConnections | ![warning] | PostgresSQL instance is using > 80% of the maximum connections.
Consider checking how many connections the client application is opening, or using PgBouncer in front of the database. | | PostgresqlNotEnoughConnections | ![info] | PostgresSQL instance does not have enough connections.
PostgreSQL instance should have more connections (> 5).
Consider double-checking how many connections the client application is opening and/or using PgBouncer in front of the database. | | PostgresqlDeadLocks | ![warning] | PostgresSQL instance has dead locks.
See more details with the pg_locks view. | -| PostgresqlHighRollbackRate | ![warning] | PostgresSQL instance has a high rollback rate instance.
The ratio of transactions being aborted compared to committed is > 2 %.
This is probably happening due to unoptimized configurations related to commit delay, connections, memory, and WAL files. | +| PostgresqlHighRollbackRate | ![warning] | PostgresSQL instance has a high rollback rate instance.
The ratio of transactions being aborted compared to committed is > 2 %.
This is probably happening due to unoptimised configurations related to commit delay, connections, memory, and WAL files. | | PostgresqlCommitRateLow | ![info] | PostgresSQL instance has a low commit rate.
PostgresSQL seems to be processing very few transactions.
Check for long-running queries and configuration issues, like insufficient cache size. | | PostgresqlLowXidConsumption | ![info] | PostgresSQL instance shows low XID consumption.
PostgresSQL seems to be consuming transaction IDs very slowly.
Run ANALYZE to update the optimizer statistics, ensure that query plans are correct, and double-check your VACUUM settings. | | PostgresqlHighRateStatementTimeout | ![critical] | PostgresSQL instance shows a high rate of statement timeout.
Either tune `statement_timeout` when sending queries or use EXPLAIN ANALYZE to understand how the queries can be improved. | diff --git a/docs/reference/contacts.md b/docs/reference/contacts.md index 7bc6b284ae..dbbe12750e 100644 --- a/docs/reference/contacts.md +++ b/docs/reference/contacts.md @@ -6,10 +6,6 @@ Charmed PostgreSQL is an open source project that warmly welcomes community cont * [Report](https://github.com/canonical/postgresql-operator/security/advisories/new) security issues * Contact the Canonical Data Platform team directly through our [Matrix](https://matrix.to/#/#charmhub-data-platform:ubuntu.com) channel. -```{note} -Our legacy [Mattermost](https://chat.charmhub.io/charmhub/channels/data-platform) channel is read-only until January 31, 2025. -``` - Useful links: * [Canonical Data Fabric](https://ubuntu.com/data/) diff --git a/docs/reference/performance-and-resources.md b/docs/reference/performance-and-resources.md index 784aee34a3..247c983c03 100644 --- a/docs/reference/performance-and-resources.md +++ b/docs/reference/performance-and-resources.md @@ -12,7 +12,7 @@ Charmed PostgreSQL resource allocation can be controlled via the charm's `profil |Value|Description|Details| | --- | --- | ----- | -|`production`
(default)|[Maximum performance](https://github.com/canonical/postgresql-operator/blob/main/lib/charms/postgresql_k8s/v0/postgresql.py#L437-L446)| 25% of the available memory for `shared_buffers` and the remain as cache memory (defaults mimic legacy charm behaviour).
The `max_connections`=max(4 * os.cpu_count(), 100).
Use [pgbouncer](https://charmhub.io/pgbouncer?channel=1/stable) if max_connections are not enough ([reasoning](https://www.percona.com/blog/scaling-postgresql-with-pgbouncer-you-may-need-a-connection-pooler-sooner-than-you-expect/)).| +|`production`
(default)|[Maximum performance](https://github.com/canonical/postgresql-operator/blob/main/lib/charms/postgresql_k8s/v0/postgresql.py#L437-L446)| 25% of the available memory for `shared_buffers` and the remain as cache memory (defaults mimic legacy charm behaviour).
`max_connections = max(4 * os.cpu_count(), 100)`.
Use [pgbouncer](https://charmhub.io/pgbouncer?channel=1/stable) if max_connections are not enough ([reasoning](https://www.percona.com/blog/scaling-postgresql-with-pgbouncer-you-may-need-a-connection-pooler-sooner-than-you-expect/)).| |`testing`|[Minimal resource usage](https://github.com/canonical/postgresql-operator/blob/main/lib/charms/postgresql_k8s/v0/postgresql.py#L437-L446)| PostgreSQL 14 defaults. | ```{caution} diff --git a/docs/reference/releases.md b/docs/reference/releases.md index f440c8b4d9..20b998ef9d 100644 --- a/docs/reference/releases.md +++ b/docs/reference/releases.md @@ -2,7 +2,7 @@ This page provides high-level overviews of the dependencies and features that are supported by each revision in every stable release. -To learn more about the different release tracks and channels, see the [Juju documentation about channels](https://juju.is/docs/juju/channel#risk). +To learn more about the different release tracks and channels, see the [Juju documentation about channels](https://documentation.ubuntu.com/juju/3.6/reference/charm/#risk). To see all releases and commits, check the [Charmed PostgreSQL Releases page on GitHub](https://github.com/canonical/postgresql-operator/releases). @@ -28,7 +28,7 @@ For a given release, this table shows: ## Architecture and base -Several [revisions](https://juju.is/docs/sdk/revision) are released simultaneously for different [bases/series](https://juju.is/docs/juju/base) using the same charm code. In other words, one release contains multiple revisions. +Several [revisions](https://documentation.ubuntu.com/juju/3.6/reference/charm/#charm-revision) are released simultaneously for different [bases/series](https://juju.is/docs/juju/base) using the same charm code. In other words, one release contains multiple revisions. If you do not specify a revision on deploy time, Juju will automatically choose the revision that matches your base and architecture. diff --git a/docs/reference/statuses.md b/docs/reference/statuses.md index 3ed8c2345a..0bf6c86db2 100644 --- a/docs/reference/statuses.md +++ b/docs/reference/statuses.md @@ -1,10 +1,10 @@ # Charm statuses ```{caution} -This reference is a work in progress and not fit for production. Contact [Canonical Data Platform team](https://chat.charmhub.io/charmhub/channels/data-platform) if you are interested in the topic. +This reference is a work in progress and not fit for production. [Contact us](/reference/contacts) if you are interested in the topic. ``` -The charm follows [standard Juju applications statuses](https://juju.is/docs/olm/status-values#application-status). Here you can find the expected end-users reaction on different statuses: +The charm follows [standard Juju applications statuses](https://documentation.ubuntu.com/juju/3.6/reference/status/#application-status). Here you can find the expected end-users reaction on different statuses: | Juju Status | Message | Expectations | Actions | |-------|-------|-------|-------| @@ -13,8 +13,8 @@ The charm follows [standard Juju applications statuses](https://juju.is/docs/olm | **maintenance** | any | Charm is performing the internal maintenance (e.g. cluster re-configuration, upgrade, ...) | No actions required | | **blocked** | the S3 repository has backups from another cluster | The bucket contains foreign backup. To avoid accident DB corruption, use clean bucket. The cluster identified by Juju app name + DB UUID. | Choose/change the new S3 [bucket](https://charmhub.io/s3-integrator/configuration#bucket)/[path](https://charmhub.io/s3-integrator/configuration#path) OR clean the current one. | | **blocked** | failed to update cluster members on member | TODO: error/retry? | | -| **blocked** | failed to install snap packages | There are issues with the network connection and/or the Snap Store | Check your internet connection and https://status.snapcraft.io/. Remove the application and when everything is ok, deploy the charm again | -| **blocked** | failed to patch snap seccomp profile | The charm failed to patch one issue that happens when pgBackRest restores a backup (this blocked status should be removed when https://github.com/pgbackrest/pgbackrest/releases/tag/release%2F2.46 is added to the snap) | Remove the unit and add it back again | +| **blocked** | failed to install snap packages | There are issues with the network connection and/or the Snap Store | Check your internet connection and https://status.snapcraft.io/. Remove the application and when everything is OK, deploy the charm again | +| **blocked** | failed to patch snap `seccomp` profile | The charm failed to patch one issue that happens when pgBackRest restores a backup (this blocked status should be removed when https://github.com/pgbackrest/pgbackrest/releases/tag/release%2F2.46 is added to the snap) | Remove the unit and add it back again | | **blocked** | failed to set up postgresql_exporter options | The charm failed to set up the metrics exporter | Remove the unit and add it back again | | **blocked** | failed to start Patroni | TODO: error/retry? | | | **blocked** | Failed to create postgres user | The charm couldn't create the default `postgres` database user due to connection problems | Connect to the database using the `operator` user and the password from the `get-password` action, then run `CREATE ROLE postgres WITH LOGIN SUPERUSER;` | diff --git a/docs/reference/system-requirements.md b/docs/reference/system-requirements.md index fe9a7db585..421206e033 100644 --- a/docs/reference/system-requirements.md +++ b/docs/reference/system-requirements.md @@ -7,17 +7,17 @@ The following are the minimum software and hardware requirements to run Charmed ### Juju -The charm supports several Juju releases from [2.9 LTS](https://juju.is/docs/juju/roadmap#juju-juju-29) onwards. The table below shows which minor versions of each major Juju release are supported by the stable Charmhub releases of PostgreSQL. +The charm supports several Juju releases from [2.9 LTS](https://documentation.ubuntu.com/juju/3.6/reference/juju/juju-roadmap-and-releases/#juju-2-9) onwards. The table below shows which minor versions of each major Juju release are supported by the stable Charmhub releases of PostgreSQL. | Juju major release | Supported minor versions | Compatible charm revisions |Comment | |:--------|:-----|:-----|:-----| | ![3.6 LTS] | `3.6.1+` | [552]+ | `3.6.0` is not recommended, while `3.6.1+` works excellent. Recommended for production! | -| [![3.5]](https://juju.is/docs/juju/roadmap#juju-juju-35) | `3.5.1+` | [363]+ | [Known Juju issue](https://bugs.launchpad.net/juju/+bug/2066517) in `3.5.0` | -| [![3.4]](https://juju.is/docs/juju/roadmap#juju-juju-34) | `3.4.3+` | [363]+ | Know Juju issues with previous minor versions | -| [![3.3]](https://juju.is/docs/juju/roadmap#juju-juju-33) | `3.3.0+` | from [363] to [430] | No known issues | -| [![3.2]](https://juju.is/docs/juju/roadmap#juju-juju-32) | `3.2.0+` | from [363] to [430] | No known issues | -| [![3.1]](https://juju.is/docs/juju/roadmap#juju-juju-31) | `3.1.7+` | from [336] to [430] | Juju secrets were stabilized in `3.1.7` | -| [![2.9 LTS]](https://juju.is/docs/juju/roadmap#juju-juju-29) | `2.9.49+` | [288]+ | | +| [![3.5]](https://documentation.ubuntu.com/juju/3.6/reference/juju/juju-roadmap-and-releases/#juju-3-5) | `3.5.1+` | [363]+ | [Known Juju issue](https://bugs.launchpad.net/juju/+bug/2066517) in `3.5.0` | +| [![3.4]](https://documentation.ubuntu.com/juju/3.6/reference/juju/juju-roadmap-and-releases/#juju-3-4) | `3.4.3+` | [363]+ | Know Juju issues with previous minor versions | +| [![3.3]](https://documentation.ubuntu.com/juju/3.6/reference/juju/juju-roadmap-and-releases/#juju-3-3) | `3.3.0+` | from [363] to [430] | No known issues | +| [![3.2]](https://documentation.ubuntu.com/juju/3.6/reference/juju/juju-roadmap-and-releases/#juju-3-2) | `3.2.0+` | from [363] to [430] | No known issues | +| [![3.1]](https://documentation.ubuntu.com/juju/3.6/reference/juju/juju-roadmap-and-releases/#juju-3-1) | `3.1.7+` | from [336] to [430] | Juju secrets were stabilised in `3.1.7` | +| [![2.9 LTS]](https://documentation.ubuntu.com/juju/3.6/reference/juju/juju-roadmap-and-releases/#juju-2-9) | `2.9.49+` | [288]+ | | | | `2.9.32+` | from [288] to [430] | No tests for older Juju versions. | ## Hardware diff --git a/docs/reference/troubleshooting/cli-helpers.md b/docs/reference/troubleshooting/cli-helpers.md index ae55abf0ba..abd64e4f63 100644 --- a/docs/reference/troubleshooting/cli-helpers.md +++ b/docs/reference/troubleshooting/cli-helpers.md @@ -150,8 +150,8 @@ ubuntu@juju-b87344-2:~$ sudo -u snap_daemon patronictl -c /var/snap/charmed-post #### Re-initialisation -Sometimes the cluster member might stuck in the middle of nowhere, the easiest way to try is [reinit the Patroni cluster member](https://patroni.readthedocs.io/en/latest/patronictl.html#patronictl-reinit). -
Example: cluster member re-initialization +Sometimes the cluster member might stuck in the middle of nowhere, the easiest way to try is [`reinit` the Patroni cluster member](https://patroni.readthedocs.io/en/latest/patronictl.html#patronictl-reinit). +
Example: cluster member re-initialisation ```text ubuntu@juju-b87344-2:~$ sudo -u snap_daemon patronictl -c /var/snap/charmed-postgresql/current/etc/patroni/patroni.yaml reinit postgresql postgresql-1 @@ -248,7 +248,7 @@ Pay attention to TLS relation with PostgreSQL and access Patroni REST API accord ### Raft library -Patroni relies on the Raft library for the consensus handling and Primary election. It is implemented using [pySyncObj](https://github.com/bakwc/PySyncObj) and available as a CLI tool. +Patroni relies on the Raft library for the consensus handling and Primary election. It is implemented using [`pySyncObj`](https://github.com/bakwc/PySyncObj) and available as a CLI tool. While **you should not interact with Raft library manually**, you can check its internal status. Note that a password is mandatory to access Raft. @@ -315,23 +315,23 @@ charmed-postgresql.pg-config charmed-postgresql.pg-dropcluster char ```
-#### pg_dump / pg_dumpall +#### `pg_dump` / `pg_dumpall` These tools are designed to dump the PostgreSQL content. Due to the strictly confined SNAP, the context is limited to SNAP itself (and not the POSIX user triggered the tool). Also, due to security reasons the default `postgres` user cannot access DB, use user `operator` (you can find it's credential in Juju Secrets). -
Example: pg-dump/pg-dumpall usage +
Example: pg-dump/pg-dumpall usage ```text charmed-postgresql.pg-dump -c -C -U operator -W -h /tmp -d mydb | tee mydb.sql >/dev/null ``` -Also you can pass password using env variable PGPASSWORD, however it is NOT recommended for productions as DB password will be stored in shell history: +Also you can pass password using the environment variable `PGPASSWORD`, however it is NOT recommended for productions as the database password will be stored in the shell's history: ```text PGPASSWORD=my$ecretp@ss charmed-postgresql.pg-dumpall -c -U operator -h /tmp | tee all_DBs.txt >/dev/null ``` -Note, the local SNAP /tmp could be used as well: +Note, the local snap/`tmp` could be used as well: ```text PGPASSWORD=my$ecretp@ss charmed-postgresql.pg-dumpall -c -U operator -h /tmp -f /tmp/test.sql diff --git a/docs/reference/troubleshooting/index.md b/docs/reference/troubleshooting/index.md index 9dc223c414..8495ff0fa2 100644 --- a/docs/reference/troubleshooting/index.md +++ b/docs/reference/troubleshooting/index.md @@ -5,9 +5,10 @@ This page goes over some recommended tools and approaches to troubleshooting the Before anything, always run `juju status` to check the [list of charm statuses](/reference/statuses) and the recommended fixes. This alone may already solve your issue. Otherwise, this reference goes over how to troubleshoot this charm via: -- [`juju` logs](#juju-logs) -- [`snap-based charm`](#snap-based-charm) -- [Installing extra software](#install-extra-software) +- [Troubleshooting](#troubleshooting) + - [Juju logs](#juju-logs) + - [Snap-based charm](#snap-based-charm) + - [Install extra software](#install-extra-software) ```{caution} @@ -74,7 +75,7 @@ Name Version Rev Tracking Publisher Notes charmed-postgresql 14.9 70 latest/stable dataplatformbot held ``` -From here you can make sure all snap (systemd) services are running: +From here you can make sure all snap (`systemd`) services are running: ```text ubuntu@juju-fd7874-0# sudo snap services @@ -136,7 +137,7 @@ ubuntu 10234 0.0 0.0 17208 7944 ? R 21:47 0:00 sshd: ubuntu@ ubuntu@juju-fd7874-0:~$ ``` -The list of running snap/systemd services will depend on configured (enabled) [COS integration](/how-to/monitoring-cos/enable-monitoring) and/or [backup](/how-to/back-up-and-restore/create-a-backup) functionality. The snap service `charmed-postgresql.patroni` must always be active and currently running (the Linux processes `snapd`, `patroni` and `postgres`). +The list of running snap/`systemd` services will depend on configured (enabled) [COS integration](/how-to/monitoring-cos/enable-monitoring) and/or [backup](/how-to/back-up-and-restore/create-a-backup) functionality. The snap service `charmed-postgresql.patroni` must always be active and currently running (the Linux processes `snapd`, `patroni` and `postgres`). To access PostgreSQL, check the [charm users concept](/explanation/users) and request `operator` credentials to use `psql`: diff --git a/docs/reference/troubleshooting/sos-report.md b/docs/reference/troubleshooting/sos-report.md index 4dfa658256..31de46d1dd 100644 --- a/docs/reference/troubleshooting/sos-report.md +++ b/docs/reference/troubleshooting/sos-report.md @@ -7,7 +7,7 @@ You can use the [built-in version of SoS](#use-built-in-sos-recommended), or [re ```{caution} Always review the collected data before sharing it! -The generated archive may contain sensitive data. Its content should be reviewed by the originating organization before being passed to any third party. +The generated archive may contain sensitive data. Its content should be reviewed by the originating organisation before being passed to any third party. ``` ## Use built-in SoS (recommended) @@ -33,7 +33,7 @@ Your sos report has been generated and saved in: ... ``` -Use `juju scp` to copy logs from Juju unit to localhost: +Use `juju scp` to copy logs from Juju unit to `localhost`: ```text juju scp postgresql/0:/tmp/sosreport-juju-d4c067-1-2025-04-07-chdmwlz.tar.xz . ``` @@ -56,7 +56,7 @@ For more information on Canonical visit: Commercial Support : https://www.canonical.com The generated archive may contain data considered sensitive and its -content should be reviewed by the originating organization before being +content should be reviewed by the originating organisation before being passed to any third party. No changes will be made to system configuration. @@ -92,16 +92,16 @@ juju scp postgresql/0:/tmp/sosreport-juju-d4c067-1-2025-04-07-qntyqpz.tar.xz . ### Collect logs from several units -The sos tool allows you to collect logs from several Juju units (replace labels with proper Juju unit like `postgresql/0`). +The SoS tool allows you to collect logs from several Juju units (replace labels with proper Juju unit like `postgresql/0`). Run the following command from outside the Juju units: ```text sos collect --cluster-type juju --no-local -c "juju.units=,,<...>" --batch -o system,systemd,snap,charmed_postgresql --low-priority ``` -## Use the latest sos plugins from Git +## Use the latest SoS plugins from Git -The latest version of [sos plugins](https://github.com/sosreport/sos/tree/main/sos/report/plugins) can be retrieved from Git easily: +The latest version of [SoS plugins](https://github.com/sosreport/sos/tree/main/sos/report/plugins) can be retrieved from Git easily: ```text git clone https://github.com/sosreport/sos.git cd sos diff --git a/docs/reference/versions.md b/docs/reference/versions.md index 244507da6b..9787337944 100644 --- a/docs/reference/versions.md +++ b/docs/reference/versions.md @@ -79,7 +79,7 @@ Read more about Charmed PostgreSQL 14 features in the [release notes]. ### Deprecated -* The track `14` is in bug-fixing/support mode. New Charmed PostgreSQL `16` features will NOT be backported to track `14`. +* The track `14` is in bug-fixing/support mode. New Charmed PostgreSQL `16` features will NOT be back-ported to track `14`. * Charmed PostgreSQL 14 ships [Timescale Apache 2 edition](https://docs.timescale.com/about/latest/timescaledb-editions/) only. ## Legacy PostgreSQL charm diff --git a/docs/tutorial/index.md b/docs/tutorial/index.md index 41d35dbeb9..85c3b81109 100644 --- a/docs/tutorial/index.md +++ b/docs/tutorial/index.md @@ -188,10 +188,10 @@ You can see below the output for the list of databases. `postgres` is the defaul (3 rows) ``` -In order to execute queries, we should enter psql's interactive terminal by running the following command, again typing password when requested: +In order to execute queries, we should enter `psql`'s interactive terminal by running the following command, again typing password when requested: ```text - psql --host=10.1.110.80 --username=operator --password postgres +psql --host=10.1.110.80 --username=operator --password postgres ``` The output should be something like this: @@ -270,7 +270,7 @@ When you’re ready to leave the PostgreSQL shell, you can just type `exit`. Thi ## Scale your replicas -The Charmed PostgreSQL VM operator uses a [PostgreSQL Patroni-based cluster](https://patroni.readthedocs.io/en/latest/) for scaling. It provides features such as automatic membership management, fault tolerance, and automatic failover. The charm uses PostgreSQL’s [synchronous replication](https://patroni.readthedocs.io/en/latest/replication_modes.html#postgresql-k8s-synchronous-replication) with Patroni to handle replication. +The Charmed PostgreSQL VM operator uses a [PostgreSQL Patroni-based cluster](https://patroni.readthedocs.io/en/latest/) for scaling. It provides features such as automatic membership management, fault tolerance, and automatic failover. The charm uses PostgreSQL’s [synchronous replication](https://patroni.readthedocs.io/en/latest/replication_modes.html) with Patroni to handle replication. ```{caution} This tutorial hosts all replicas on the same machine. @@ -390,7 +390,7 @@ Learn more about managing user credentials in [](/how-to/manage-passwords) and [ ## Integrate with other applications -[Integrations](https://juju.is/docs/sdk/integration), known as "relations" in Juju 2.9, are the easiest way to create a user for PostgreSQL in Charmed PostgreSQL VM. +[Integrations](https://documentation.ubuntu.com/juju/3.6/reference/relation/), known as "relations" in Juju 2.9, are the easiest way to create a user for PostgreSQL in Charmed PostgreSQL VM. Integrations automatically create a username, password, and database for the desired user/application. The best practice is to connect to PostgreSQL via a specific user rather than the admin user. @@ -666,7 +666,7 @@ multipass delete --purge my-vm - Check out our other other charm offerings, like [MySQL](https://charmhub.io/mysql) and [Kafka](https://charmhub.io/kafka?channel=edge) - Read about [High Availability best practices](https://canonical.com/blog/database-high-availability) - [Report](https://github.com/canonical/postgresql-operator/issues) any problems you encountered -- [Give us your feedback](https://chat.charmhub.io/charmhub/channels/data-platform) +- [Give us your feedback](/reference/contacts) - [Contribute to the code base](https://github.com/canonical/postgresql-operator) From f502532c97f30780438e7becedef31ddb0e45d3a Mon Sep 17 00:00:00 2001 From: Alex Lutay <1928266+taurus-forever@users.noreply.github.com> Date: Tue, 15 Jul 2025 17:26:33 +0200 Subject: [PATCH 062/112] DPE-7723: Update releases.md: fix arch for revs 429/430 (#1046) ## Issue https://canonical-charmed-postgresql.readthedocs-hosted.com/14/reference/releases/ says rev 430 is amd64 rev 429 is arm64 This is wrong: ``` juju download postgresql --revision 429 unp ./postgresql_r429.charm -d ./r429 grep amd ./r429/manifest.yaml - amd64 ``` ## Solution Update docs with proper pinning. Fixes: https://github.com/canonical/postgresql-operator/issues/1045 --- docs/reference/releases.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/reference/releases.md b/docs/reference/releases.md index 20b998ef9d..91d819f4d3 100644 --- a/docs/reference/releases.md +++ b/docs/reference/releases.md @@ -42,7 +42,7 @@ Check the tables below, or use [`juju info`](https://juju.is/docs/juju/juju-info | Revision | amd64 | arm64 | Ubuntu 22.04 LTS |:--------:|:-----:|:-----:|:-----:| -|[553] | ![check] | | ![check] | +|[553] | ![check] | | ![check] | |[552] | | ![check] | ![check] |
@@ -52,8 +52,8 @@ Check the tables below, or use [`juju info`](https://juju.is/docs/juju/juju-info |:--------:|:-----:|:-----:|:-----:| |[468] |![check] | | ![check] | |[467] | | ![check] | ![check] | -|[430] |![check] | | ![check] | -|[429] | | ![check] | ![check] | +|[430] | | ![check] | ![check] | +|[429] |![check] | | ![check] | |[363] |![check] | | ![check] | |[351] |![check] | | ![check] | |[336] |![check] | | ![check] | From c3005d386c205181ac44cae8cf426347a4406a4f Mon Sep 17 00:00:00 2001 From: Dragomir Penev <6687393+dragomirp@users.noreply.github.com> Date: Thu, 17 Jul 2025 04:26:51 +0300 Subject: [PATCH 063/112] [DPE-6259] pgbackrest config perms (#1038) * Remove read access to pgbackrest conf file * Update libs * Set extra user roles config for the test app * Fix data-int base * Set channel and series in ne rel tests --- .../data_platform_libs/v0/data_interfaces.py | 12 ++++--- lib/charms/glauth_k8s/v0/ldap.py | 35 ++++++++++++------- .../tempo_coordinator_k8s/v0/charm_tracing.py | 6 ++-- src/backups.py | 2 +- .../new_relations/test_new_relations_1.py | 15 +++++--- .../new_relations/test_relations_coherence.py | 25 ++++++------- tests/unit/test_backups.py | 2 +- 7 files changed, 60 insertions(+), 37 deletions(-) diff --git a/lib/charms/data_platform_libs/v0/data_interfaces.py b/lib/charms/data_platform_libs/v0/data_interfaces.py index 021de1dc89..109603ad49 100644 --- a/lib/charms/data_platform_libs/v0/data_interfaces.py +++ b/lib/charms/data_platform_libs/v0/data_interfaces.py @@ -331,7 +331,7 @@ def _on_topic_requested(self, event: TopicRequestedEvent): # Increment this PATCH version before using `charmcraft publish-lib` or reset # to 0 if you are raising the major API version -LIBPATCH = 48 +LIBPATCH = 49 PYDEPS = ["ops>=2.0.0"] @@ -3527,6 +3527,11 @@ def __init__( self.consumer_group_prefix = consumer_group_prefix or "" self.mtls_cert = mtls_cert + @staticmethod + def is_topic_value_acceptable(topic_value: str) -> bool: + """Check whether the given Kafka topic value is acceptable.""" + return "*" not in topic_value[:3] + @property def topic(self): """Topic to use in Kafka.""" @@ -3534,9 +3539,8 @@ def topic(self): @topic.setter def topic(self, value): - # Avoid wildcards - if value == "*": - raise ValueError(f"Error on topic '{value}', cannot be a wildcard.") + if not self.is_topic_value_acceptable(value): + raise ValueError(f"Error on topic '{value}', unacceptable value.") self._topic = value def set_mtls_cert(self, relation_id: int, mtls_cert: str) -> None: diff --git a/lib/charms/glauth_k8s/v0/ldap.py b/lib/charms/glauth_k8s/v0/ldap.py index b68e1d2f30..1a15a303a6 100644 --- a/lib/charms/glauth_k8s/v0/ldap.py +++ b/lib/charms/glauth_k8s/v0/ldap.py @@ -147,7 +147,7 @@ def _on_ldap_requested(self, event: LdapRequestedEvent) -> None: # Increment this PATCH version before using `charmcraft publish-lib` or reset # to 0 if you are raising the major API version -LIBPATCH = 10 +LIBPATCH = 11 PYDEPS = ["pydantic"] @@ -256,13 +256,11 @@ def load( cls, charm: CharmBase, label: str, - *, - content: Optional[dict[str, str]] = None, - ) -> "Secret": + ) -> Optional["Secret"]: try: secret = charm.model.get_secret(label=label) except SecretNotFoundError: - secret = charm.app.add_secret(label=label, content=content) + return None return Secret(secret) @@ -411,7 +409,8 @@ def _on_relation_broken(self, event: RelationBrokenEvent) -> None: self.charm, label=BIND_ACCOUNT_SECRET_LABEL_TEMPLATE.substitute(relation_id=event.relation.id), ) - secret.remove() + if secret: + secret.remove() def get_bind_password(self, relation_id: int) -> Optional[str]: """Retrieve the bind account password for a given integration.""" @@ -490,15 +489,27 @@ def _on_ldap_relation_changed(self, event: RelationChangedEvent) -> None: """Handle the event emitted when the LDAP related information is ready.""" provider_app = event.relation.app - if not event.relation.data.get(provider_app): + if not (provider_data := event.relation.data.get(provider_app)): return - self.on.ldap_ready.emit(event.relation) + provider_data = dict(provider_data) + if self._load_provider_data(provider_data): + self.on.ldap_ready.emit(event.relation) def _on_ldap_relation_broken(self, event: RelationBrokenEvent) -> None: """Handle the event emitted when the LDAP integration is broken.""" self.on.ldap_unavailable.emit(event.relation) + def _load_provider_data(self, provider_data: dict) -> Optional[LdapProviderData]: + if secret_id := provider_data.get("bind_password_secret"): + secret = self.charm.model.get_secret(id=secret_id) + provider_data["bind_password"] = secret.get_content().get("password") + + try: + return LdapProviderData(**provider_data) + except ValidationError: + return None + def consume_ldap_relation_data( self, /, @@ -513,10 +524,10 @@ def consume_ldap_relation_data( return None provider_data = dict(relation.data.get(relation.app)) - if secret_id := provider_data.get("bind_password_secret"): - secret = self.charm.model.get_secret(id=secret_id) - provider_data["bind_password"] = secret.get_content().get("password") - return LdapProviderData(**provider_data) if provider_data else None + if not provider_data: + return None + + return self._load_provider_data(provider_data) def _is_relation_active(self, relation: Relation) -> bool: """Whether the relation is active based on contained data.""" diff --git a/lib/charms/tempo_coordinator_k8s/v0/charm_tracing.py b/lib/charms/tempo_coordinator_k8s/v0/charm_tracing.py index 050e5b384b..61fcf07716 100644 --- a/lib/charms/tempo_coordinator_k8s/v0/charm_tracing.py +++ b/lib/charms/tempo_coordinator_k8s/v0/charm_tracing.py @@ -313,10 +313,10 @@ def _remove_stale_otel_sdk_packages(): import opentelemetry import ops -from opentelemetry.exporter.otlp.proto.common._internal.trace_encoder import ( +from opentelemetry.exporter.otlp.proto.common._internal.trace_encoder import ( # type: ignore encode_spans # type: ignore ) -from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter +from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter # type: ignore from opentelemetry.sdk.resources import Resource from opentelemetry.sdk.trace import ReadableSpan, Span, TracerProvider from opentelemetry.sdk.trace.export import ( @@ -348,7 +348,7 @@ def _remove_stale_otel_sdk_packages(): # Increment this PATCH version before using `charmcraft publish-lib` or reset # to 0 if you are raising the major API version -LIBPATCH = 8 +LIBPATCH = 9 PYDEPS = ["opentelemetry-exporter-otlp-proto-http==1.21.0"] diff --git a/src/backups.py b/src/backups.py index 74f754b276..d4502c01c8 100644 --- a/src/backups.py +++ b/src/backups.py @@ -1265,7 +1265,7 @@ def _render_pgbackrest_conf_file(self) -> bool: process_max=max(os.cpu_count() - 2, 1), ) # Render pgBackRest config file. - self.charm._patroni.render_file(f"{PGBACKREST_CONF_PATH}/pgbackrest.conf", rendered, 0o644) + self.charm._patroni.render_file(f"{PGBACKREST_CONF_PATH}/pgbackrest.conf", rendered, 0o640) # Render the logrotate configuration file. with open("templates/pgbackrest.logrotate.j2") as file: diff --git a/tests/integration/new_relations/test_new_relations_1.py b/tests/integration/new_relations/test_new_relations_1.py index e430b7919b..88d5f030a9 100644 --- a/tests/integration/new_relations/test_new_relations_1.py +++ b/tests/integration/new_relations/test_new_relations_1.py @@ -58,7 +58,8 @@ async def test_deploy_charms(ops_test: OpsTest, charm): application_name=APPLICATION_APP_NAME, num_units=2, base=CHARM_BASE, - channel="edge", + channel="latest/edge", + config={"extra_user_roles": "CREATEDB,CREATEROLE"}, ), ops_test.model.deploy( charm, @@ -261,7 +262,7 @@ async def test_two_applications_doesnt_share_the_same_relation_data(ops_test: Op await ops_test.model.deploy( APPLICATION_APP_NAME, application_name=another_application_app_name, - channel="edge", + channel="latest/edge", base=CHARM_BASE, ) await ops_test.model.wait_for_idle(apps=all_app_names, status="active") @@ -490,7 +491,11 @@ async def test_admin_role(ops_test: OpsTest): all_app_names = [DATA_INTEGRATOR_APP_NAME] all_app_names.extend(APP_NAMES) async with ops_test.fast_forward(): - await ops_test.model.deploy(DATA_INTEGRATOR_APP_NAME, base=CHARM_BASE) + await ops_test.model.deploy( + DATA_INTEGRATOR_APP_NAME, + channel="latest/edge", + series="jammy", + ) await ops_test.model.wait_for_idle(apps=[DATA_INTEGRATOR_APP_NAME], status="blocked") await ops_test.model.applications[DATA_INTEGRATOR_APP_NAME].set_config({ "database-name": DATA_INTEGRATOR_APP_NAME.replace("-", "_"), @@ -579,10 +584,12 @@ async def test_invalid_extra_user_roles(ops_test: OpsTest): another_data_integrator_app_name = f"another-{DATA_INTEGRATOR_APP_NAME}" data_integrator_apps_names = [DATA_INTEGRATOR_APP_NAME, another_data_integrator_app_name] + # Base is ignored await ops_test.model.deploy( DATA_INTEGRATOR_APP_NAME, application_name=another_data_integrator_app_name, - base=CHARM_BASE, + channel="latest/edge", + series="jammy", ) await ops_test.model.wait_for_idle( apps=[another_data_integrator_app_name], status="blocked" diff --git a/tests/integration/new_relations/test_relations_coherence.py b/tests/integration/new_relations/test_relations_coherence.py index 74fd202fa6..faf5e5bebb 100644 --- a/tests/integration/new_relations/test_relations_coherence.py +++ b/tests/integration/new_relations/test_relations_coherence.py @@ -4,6 +4,7 @@ import logging import secrets import string +from asyncio import gather import psycopg2 import pytest @@ -26,23 +27,23 @@ async def test_relations(ops_test: OpsTest, charm): """Test that check relation data.""" async with ops_test.fast_forward(): - await ops_test.model.deploy( - charm, - application_name=DATABASE_APP_NAME, - num_units=1, - base=CHARM_BASE, - config={"profile": "testing"}, + await gather( + ops_test.model.deploy( + charm, + application_name=DATABASE_APP_NAME, + num_units=1, + base=CHARM_BASE, + config={"profile": "testing"}, + ), + # Creating first time relation with user role + # Base is ignored + ops_test.model.deploy(DATA_INTEGRATOR_APP_NAME, series="jammy"), ) - await ops_test.model.wait_for_idle(apps=[DATABASE_APP_NAME], status="active", timeout=3000) - - # Creating first time relation with user role - await ops_test.model.deploy(DATA_INTEGRATOR_APP_NAME, base=CHARM_BASE) await ops_test.model.applications[DATA_INTEGRATOR_APP_NAME].set_config({ "database-name": DATA_INTEGRATOR_APP_NAME.replace("-", "_"), }) - await ops_test.model.wait_for_idle(apps=[DATA_INTEGRATOR_APP_NAME], status="blocked") await ops_test.model.add_relation(DATA_INTEGRATOR_APP_NAME, DATABASE_APP_NAME) - await ops_test.model.wait_for_idle(apps=APP_NAMES, status="active") + await ops_test.model.wait_for_idle(apps=APP_NAMES, status="active", timeout=1500) connection_string = await build_connection_string( ops_test, diff --git a/tests/unit/test_backups.py b/tests/unit/test_backups.py index 2f93daa663..1942a20fdc 100644 --- a/tests/unit/test_backups.py +++ b/tests/unit/test_backups.py @@ -1776,7 +1776,7 @@ def test_render_pgbackrest_conf_file(harness, tls_ca_chain_filename): call( "/var/snap/charmed-postgresql/current/etc/pgbackrest/pgbackrest.conf", expected_content, - 0o644, + 0o640, ), call( "/etc/logrotate.d/pgbackrest.logrotate", From 94530a182bf7ce8ee5835d02a8fa75fcd7ef56c4 Mon Sep 17 00:00:00 2001 From: Andreia Date: Mon, 28 Jul 2025 15:42:22 +0200 Subject: [PATCH 064/112] Fix MicroStack links (#1063) --- docs/how-to/deploy/sunbeam.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/how-to/deploy/sunbeam.md b/docs/how-to/deploy/sunbeam.md index 6d1b443a75..58aa11659e 100644 --- a/docs/how-to/deploy/sunbeam.md +++ b/docs/how-to/deploy/sunbeam.md @@ -18,7 +18,7 @@ This guide assumes you have: ## Install and bootstrap Sunbeam -Follow the official OpenStack guide: [Single-node deployment][Single-node guided]. +Follow the [official OpenStack installation guide][Single-node guided]. Pay attention to the `Caution` and `Note` sections - the `/etc/hosts` will require a [manual {spellexception}`fqdn` fix](https://github.com/canonical/multipass/issues/3277#issuecomment-2471434029). @@ -28,7 +28,7 @@ Follow the official [Images Sync] guide to enable auto-sync and wait for the ima ## Set up Juju inside an OpenStack bastion -Follow the MicroStack guide [Manage workloads with Juju] from the beginning, and stop after the section "Create a Juju controller". +Follow the OpenStack guide [Manage workloads with Juju] from the beginning, and stop after the section "Create a Juju controller". To summarise, the relevant sections are: * Set up the bastion @@ -82,8 +82,8 @@ The image below is an example of the OpenStack dashboard view (bastion + juju co [Tutorial]: /tutorial/index -[Single-node guided]: https://microstack.run/docs/single-node-guided -[Accessing the OpenStack dashboard]: https://microstack.run/docs/dashboard -[Images Sync]: https://microstack.run/docs/images -[Manage workloads with Juju]: https://microstack.run/docs/juju-workloads +[Single-node guided]: https://canonical-openstack.readthedocs-hosted.com/en/latest/how-to/install/install-canonical-openstack-using-the-manual-bare-metal-provider/ +[Accessing the OpenStack dashboard]: https://canonical-openstack.readthedocs-hosted.com/en/latest/how-to/misc/using-the-openstack-dashboard/ +[Images Sync]: https://canonical-openstack.readthedocs-hosted.com/en/latest/how-to/features/images-sync/ +[Manage workloads with Juju]: https://canonical-openstack.readthedocs-hosted.com/en/latest/how-to/misc/manage-workloads-with-juju/ From 79a372e763bd44df482ff4a1b8f9cdf4377ddf13 Mon Sep 17 00:00:00 2001 From: Dragomir Penev <6687393+dragomirp@users.noreply.github.com> Date: Thu, 31 Jul 2025 15:04:37 +0300 Subject: [PATCH 065/112] [DPE-7594] Sync up pg_hba changes and remove trigger (#1070) * Port user hash * Blocking test app --- lib/charms/postgresql_k8s/v0/postgresql.py | 82 +------------------ scripts/cluster_topology_observer.py | 81 ++++++++++++------ src/charm.py | 37 +++++++-- src/cluster_topology_observer.py | 22 ++++- src/relations/postgresql_provider.py | 27 +++--- .../ha_tests/test_async_replication.py | 8 +- .../integration/ha_tests/test_replication.py | 9 +- tests/integration/ha_tests/test_scaling.py | 1 + .../ha_tests/test_scaling_three_units.py | 1 + .../test_scaling_three_units_async.py | 1 + .../integration/ha_tests/test_self_healing.py | 2 + tests/integration/ha_tests/test_upgrade.py | 1 + .../ha_tests/test_upgrade_from_stable.py | 1 + .../new_relations/test_new_relations_1.py | 5 +- tests/integration/relations/test_relations.py | 11 ++- tests/integration/test_db.py | 16 ++-- tests/integration/test_pg_hba.py | 2 +- tests/unit/test_cluster_topology_observer.py | 2 +- 18 files changed, 161 insertions(+), 148 deletions(-) diff --git a/lib/charms/postgresql_k8s/v0/postgresql.py b/lib/charms/postgresql_k8s/v0/postgresql.py index 54453a3623..480dac02ba 100644 --- a/lib/charms/postgresql_k8s/v0/postgresql.py +++ b/lib/charms/postgresql_k8s/v0/postgresql.py @@ -35,7 +35,7 @@ # Increment this PATCH version before using `charmcraft publish-lib` or reset # to 0 if you are raising the major API version -LIBPATCH = 53 +LIBPATCH = 55 # Groups to distinguish HBA access ACCESS_GROUP_IDENTITY = "identity_access" @@ -267,7 +267,8 @@ def create_database( raise PostgreSQLCreateDatabaseError() from e # Enable preset extensions - self.enable_disable_extensions(dict.fromkeys(plugins, True), database) + if plugins: + self.enable_disable_extensions(dict.fromkeys(plugins, True), database) def create_user( self, @@ -782,83 +783,6 @@ def set_up_database(self) -> None: connection = None cursor = None try: - with self._connect_to_database( - database="template1" - ) as connection, connection.cursor() as cursor: - # Create database function and event trigger to identify users created by PgBouncer. - cursor.execute( - "SELECT TRUE FROM pg_event_trigger WHERE evtname = 'update_pg_hba_on_create_schema';" - ) - if cursor.fetchone() is None: - cursor.execute(""" -CREATE OR REPLACE FUNCTION update_pg_hba() - RETURNS event_trigger - LANGUAGE plpgsql - AS $$ - DECLARE - hba_file TEXT; - copy_command TEXT; - connection_type TEXT; - rec record; - insert_value TEXT; - changes INTEGER = 0; - BEGIN - -- Don't execute on replicas. - IF NOT pg_is_in_recovery() THEN - -- Load the current authorisation rules. - DROP TABLE IF EXISTS pg_hba; - CREATE TEMPORARY TABLE pg_hba (lines TEXT); - SELECT setting INTO hba_file FROM pg_settings WHERE name = 'hba_file'; - IF hba_file IS NOT NULL THEN - copy_command='COPY pg_hba FROM ''' || hba_file || '''' ; - EXECUTE copy_command; - -- Build a list of the relation users and the databases they can access. - DROP TABLE IF EXISTS relation_users; - CREATE TEMPORARY TABLE relation_users AS - SELECT t.user, STRING_AGG(DISTINCT t.database, ',') AS databases FROM( SELECT u.usename AS user, CASE WHEN u.usesuper THEN 'all' ELSE d.datname END AS database FROM ( SELECT usename, usesuper FROM pg_catalog.pg_user WHERE usename NOT IN ('backup', 'monitoring', 'operator', 'postgres', 'replication', 'rewind')) AS u JOIN ( SELECT datname FROM pg_catalog.pg_database WHERE NOT datistemplate ) AS d ON has_database_privilege(u.usename, d.datname, 'CONNECT') ) AS t GROUP BY 1; - IF (SELECT COUNT(lines) FROM pg_hba WHERE lines LIKE 'hostssl %') > 0 THEN - connection_type := 'hostssl'; - ELSE - connection_type := 'host'; - END IF; - -- Add the new users to the pg_hba file. - FOR rec IN SELECT * FROM relation_users - LOOP - insert_value := connection_type || ' ' || rec.databases || ' ' || rec.user || ' 0.0.0.0/0 md5'; - IF (SELECT COUNT(lines) FROM pg_hba WHERE lines = insert_value) = 0 THEN - INSERT INTO pg_hba (lines) VALUES (insert_value); - changes := changes + 1; - END IF; - END LOOP; - -- Remove users that don't exist anymore from the pg_hba file. - FOR rec IN SELECT h.lines FROM pg_hba AS h LEFT JOIN relation_users AS r ON SPLIT_PART(h.lines, ' ', 3) = r.user WHERE r.user IS NULL AND (SPLIT_PART(h.lines, ' ', 3) LIKE 'relation_id_%' OR SPLIT_PART(h.lines, ' ', 3) LIKE 'pgbouncer_auth_relation_%' OR SPLIT_PART(h.lines, ' ', 3) LIKE '%_user_%_%') - LOOP - DELETE FROM pg_hba WHERE lines = rec.lines; - changes := changes + 1; - END LOOP; - -- Apply the changes to the pg_hba file. - IF changes > 0 THEN - copy_command='COPY pg_hba TO ''' || hba_file || '''' ; - EXECUTE copy_command; - PERFORM pg_reload_conf(); - END IF; - END IF; - END IF; - END; - $$; - """) - cursor.execute(""" -CREATE EVENT TRIGGER update_pg_hba_on_create_schema - ON ddl_command_end - WHEN TAG IN ('CREATE SCHEMA') - EXECUTE FUNCTION update_pg_hba(); - """) - cursor.execute(""" -CREATE EVENT TRIGGER update_pg_hba_on_drop_schema - ON ddl_command_end - WHEN TAG IN ('DROP SCHEMA') - EXECUTE FUNCTION update_pg_hba(); - """) with self._connect_to_database() as connection, connection.cursor() as cursor: cursor.execute("SELECT TRUE FROM pg_roles WHERE rolname='admin';") if cursor.fetchone() is None: diff --git a/scripts/cluster_topology_observer.py b/scripts/cluster_topology_observer.py index c3b77f9d04..8609f3e277 100644 --- a/scripts/cluster_topology_observer.py +++ b/scripts/cluster_topology_observer.py @@ -11,8 +11,15 @@ from urllib.parse import urljoin from urllib.request import urlopen +import psycopg2 +import yaml + API_REQUEST_TIMEOUT = 5 PATRONI_CLUSTER_STATUS_ENDPOINT = "cluster" +SNAP_CURRENT_PATH = "/var/snap/charmed-postgresql/current" +SNAP_CONF_PATH = f"{SNAP_CURRENT_PATH}/etc" +PATRONI_CONF_PATH = f"{SNAP_CONF_PATH}/patroni" +PATRONI_CONF_FILE_PATH = f"{PATRONI_CONF_PATH}/patroni.yaml" # File path for the spawned cluster topology observer process to write logs. LOG_FILE_PATH = "/var/log/cluster_topology_observer.log" @@ -22,28 +29,6 @@ class UnreachableUnitsError(Exception): """Cannot reach any known cluster member.""" -def check_for_authorisation_rules_changes(run_cmd, unit, charm_dir, previous_authorisation_rules): - """Check for changes in the authorisation rules. - - If changes are detected, dispatch an event to handle them. - """ - # Read contents from the pg_hba.conf file. - with open("/var/snap/charmed-postgresql/common/var/lib/postgresql/pg_hba.conf") as file: - current_authorisation_rules = file.read() - current_authorisation_rules = [ - line for line in current_authorisation_rules.splitlines() if not line.startswith("#") - ] - # If it's the first time the authorisation rules were retrieved, then store it and use - # it for subsequent checks. - if not previous_authorisation_rules: - previous_authorisation_rules = current_authorisation_rules - # If the authorisation rules changed, dispatch a charm event to handle this change. - elif current_authorisation_rules != previous_authorisation_rules: - previous_authorisation_rules = current_authorisation_rules - dispatch(run_cmd, unit, charm_dir, "authorisation_rules_change") - return previous_authorisation_rules - - def check_for_cluster_topology_changes( run_cmd, unit, charm_dir, previous_cluster_topology, current_cluster_topology ): @@ -62,6 +47,52 @@ def check_for_cluster_topology_changes( return previous_cluster_topology +def check_for_database_changes(run_cmd, unit, charm_dir, previous_databases): + """Check for changes in the databases. + + If changes are detected, dispatch an event to handle them. + """ + with open(PATRONI_CONF_FILE_PATH) as conf_file: + conf_file_contents = yaml.safe_load(conf_file) + password = conf_file_contents["postgresql"]["authentication"]["superuser"]["password"] + listen_addr = conf_file_contents["postgresql"]["listen"] + if not listen_addr or ":" not in listen_addr: + with open(LOG_FILE_PATH, "a") as log_file: + log_file.write("Failed to retrieve databases: Host not set yet.\n") + return previous_databases + host, _ = listen_addr.split(":") + + connection = None + try: + # Input is generated by the charm + with ( + psycopg2.connect( + f"dbname='postgres' user='operator' host='{host}' " + f"password='{password}' connect_timeout=1" + ) as connection, + connection.cursor() as cursor, + ): + cursor.execute("SELECT datname, datacl FROM pg_database;") + current_databases = cursor.fetchall() + except psycopg2.Error as e: + with open(LOG_FILE_PATH, "a") as log_file: + log_file.write(f"Failed to retrieve databases: {e}\n") + return previous_databases + else: + # If it's the first time the databases were retrieved, then store it and use + # it for subsequent checks. + if not previous_databases: + previous_databases = current_databases + # If the databases changed, dispatch a charm event to handle this change. + elif current_databases != previous_databases: + previous_databases = current_databases + dispatch(run_cmd, unit, charm_dir, "databases_change") + return previous_databases + finally: + if connection: + connection.close() + + def dispatch(run_cmd, unit, charm_dir, custom_event): """Use the input juju-run command to dispatch a custom event.""" dispatch_sub_cmd = "JUJU_DISPATCH_PATH=hooks/{} {}/dispatch" @@ -77,7 +108,7 @@ def main(): patroni_urls, run_cmd, unit, charm_dir = sys.argv[1:] previous_cluster_topology = {} - previous_authorisation_rules = [] + previous_databases = None urls = [urljoin(url, PATRONI_CLUSTER_STATUS_ENDPOINT) for url in patroni_urls.split(",")] member_name = unit.replace("/", "-") while True: @@ -122,8 +153,8 @@ def main(): ) if is_primary: - previous_authorisation_rules = check_for_authorisation_rules_changes( - run_cmd, unit, charm_dir, previous_authorisation_rules + previous_databases = check_for_database_changes( + run_cmd, unit, charm_dir, previous_databases ) # Wait some time before checking again for a cluster topology change. diff --git a/src/charm.py b/src/charm.py index 863eb92db7..f48c38d886 100755 --- a/src/charm.py +++ b/src/charm.py @@ -14,6 +14,7 @@ import sys import time from datetime import datetime +from hashlib import shake_128 from pathlib import Path from typing import Literal, get_args from urllib.parse import urlparse @@ -185,10 +186,8 @@ def __init__(self, *args): ) self._observer = ClusterTopologyObserver(self, run_cmd) self._rotate_logs = RotateLogs(self) - self.framework.observe( - self.on.authorisation_rules_change, self._on_authorisation_rules_change - ) self.framework.observe(self.on.cluster_topology_change, self._on_cluster_topology_change) + self.framework.observe(self.on.databases_change, self._on_databases_change) self.framework.observe(self.on.install, self._on_install) self.framework.observe(self.on.leader_elected, self._on_leader_elected) self.framework.observe(self.on.config_changed, self._on_config_changed) @@ -239,8 +238,10 @@ def __init__(self, *args): ) self._tracing_endpoint_config, _ = charm_tracing_config(self._grafana_agent, None) - def _on_authorisation_rules_change(self, _): - """Handle authorisation rules change event.""" + def _on_databases_change(self, _): + """Handle databases change event.""" + self.update_config() + logger.debug("databases changed") timestamp = datetime.now() self._peers.data[self.unit].update({"pg_hba_needs_update_timestamp": str(timestamp)}) logger.debug(f"authorisation rules changed at {timestamp}") @@ -2072,6 +2073,9 @@ def update_config(self, is_creating_backup: bool = False, no_peers: bool = False self._restart_metrics_service(postgres_snap) self._restart_ldap_sync_service(postgres_snap) + self.unit_peer_data.update({"user_hash": self.generate_user_hash}) + if self.unit.is_leader(): + self.app_peer_data.update({"user_hash": self.generate_user_hash}) return True def _validate_config_options(self) -> None: @@ -2190,11 +2194,34 @@ def relations_user_databases_map(self) -> dict: REPLICATION_USER: "all", REWIND_USER: "all", }) + + # Copy relations users directly instead of waiting for them to be created + for relation in self.model.relations[self.postgresql_client_relation.relation_name]: + user = f"relation-{relation.id}" + if user not in user_database_map and ( + database + := self.postgresql_client_relation.database_provides.fetch_relation_field( + relation.id, "database" + ) + ): + user_database_map[user] = database return user_database_map except PostgreSQLListUsersError: logger.debug("relations_user_databases_map: Unable to get users") return {USER: "all", REPLICATION_USER: "all", REWIND_USER: "all"} + @property + def generate_user_hash(self) -> str: + """Generate expected user and database hash.""" + user_db_pairs = {} + for relation in self.model.relations[self.postgresql_client_relation.relation_name]: + if database := self.postgresql_client_relation.database_provides.fetch_relation_field( + relation.id, "database" + ): + user = f"relation_id_{relation.id}" + user_db_pairs[user] = database + return shake_128(str(user_db_pairs).encode()).hexdigest(16) + def override_patroni_restart_condition( self, new_condition: str, repeat_cause: str | None ) -> bool: diff --git a/src/cluster_topology_observer.py b/src/cluster_topology_observer.py index 94f0e479d9..2206bc8af7 100644 --- a/src/cluster_topology_observer.py +++ b/src/cluster_topology_observer.py @@ -7,6 +7,8 @@ import os import signal import subprocess +from pathlib import Path +from sys import version_info from ops.charm import CharmBase, CharmEvents from ops.framework import EventBase, EventSource, Object @@ -22,8 +24,8 @@ class ClusterTopologyChangeEvent(EventBase): """A custom event for cluster topology changes.""" -class AuthorisationRulesChangeEvent(EventBase): - """A custom event for authorisation rules changes.""" +class DatabasesChangeEvent(EventBase): + """A custom event for databases changes.""" class ClusterTopologyChangeCharmEvents(CharmEvents): @@ -32,8 +34,8 @@ class ClusterTopologyChangeCharmEvents(CharmEvents): Includes :class:`ClusterTopologyChangeEvent` in those that can be handled. """ - authorisation_rules_change = EventSource(AuthorisationRulesChangeEvent) cluster_topology_change = EventSource(ClusterTopologyChangeEvent) + databases_change = EventSource(DatabasesChangeEvent) class ClusterTopologyObserver(Object): @@ -74,6 +76,20 @@ def start_observer(self): new_env = os.environ.copy() if "JUJU_CONTEXT_ID" in new_env: new_env.pop("JUJU_CONTEXT_ID") + # Generate the venv path based on the existing lib path + for loc in new_env["PYTHONPATH"].split(":"): + path = Path(loc) + venv_path = ( + path + / ".." + / "venv" + / "lib" + / f"python{version_info.major}.{version_info.minor}" + / "site-packages" + ) + if path.stem == "lib": + new_env["PYTHONPATH"] = f"{venv_path.resolve()}:{new_env['PYTHONPATH']}" + break urls = [self._charm._patroni._patroni_url] + [ self._charm._patroni._patroni_url.replace(self._charm._patroni.unit_ip, peer) diff --git a/src/relations/postgresql_provider.py b/src/relations/postgresql_provider.py index 844da3b6f9..e303b41143 100644 --- a/src/relations/postgresql_provider.py +++ b/src/relations/postgresql_provider.py @@ -4,7 +4,6 @@ """Postgres client relation hooks & helpers.""" import logging -from datetime import datetime from charms.data_platform_libs.v0.data_interfaces import ( DatabaseProvides, @@ -23,7 +22,6 @@ from ops.charm import CharmBase, RelationBrokenEvent, RelationChangedEvent from ops.framework import Object from ops.model import ActiveStatus, BlockedStatus, Relation -from tenacity import RetryError, Retrying, stop_after_attempt, wait_fixed from constants import ( ALL_CLIENT_RELATIONS, @@ -97,6 +95,19 @@ def _on_database_requested(self, event: DatabaseRequestedEvent) -> None: ) return + self.charm.update_config() + for key in self.charm._peers.data: + # We skip the leader so we don't have to wait on the defer + if ( + key != self.charm.app + and key != self.charm.unit + and self.charm._peers.data[key].get("user_hash", "") + != self.charm.generate_user_hash + ): + logger.debug("Not all units have synced configuration") + event.defer() + return + # Retrieve the database name and extra user roles using the charm library. database = event.database @@ -144,18 +155,6 @@ def _on_database_requested(self, event: DatabaseRequestedEvent) -> None: else f"Failed to initialize {self.relation_name} relation" ) - # Try to wait for pg_hba trigger - try: - for attempt in Retrying(stop=stop_after_attempt(3), wait=wait_fixed(1)): - with attempt: - if not self.charm.postgresql.is_user_in_hba(user): - raise Exception("pg_hba not ready") - self.charm.unit_peer_data.update({ - "pg_hba_needs_update_timestamp": str(datetime.now()) - }) - except RetryError: - logger.warning("database requested: Unable to check pg_hba rule update") - def _on_relation_broken(self, event: RelationBrokenEvent) -> None: """Correctly update the status.""" self._update_unit_status(event.relation) diff --git a/tests/integration/ha_tests/test_async_replication.py b/tests/integration/ha_tests/test_async_replication.py index a879e5e63d..43e3b8bf7c 100644 --- a/tests/integration/ha_tests/test_async_replication.py +++ b/tests/integration/ha_tests/test_async_replication.py @@ -133,14 +133,18 @@ async def test_deploy_async_replication_setup( ) async with ops_test.fast_forward(), fast_forward(second_model): + await gather( + first_model.wait_for_idle(apps=[APPLICATION_NAME], status="blocked"), + second_model.wait_for_idle(apps=[APPLICATION_NAME], status="blocked"), + ) await gather( first_model.wait_for_idle( - apps=[DATABASE_APP_NAME, APPLICATION_NAME, DATA_INTEGRATOR_APP_NAME], + apps=[DATABASE_APP_NAME, DATA_INTEGRATOR_APP_NAME], status="active", timeout=TIMEOUT, ), second_model.wait_for_idle( - apps=[DATABASE_APP_NAME, APPLICATION_NAME], + apps=[DATABASE_APP_NAME], status="active", timeout=TIMEOUT, ), diff --git a/tests/integration/ha_tests/test_replication.py b/tests/integration/ha_tests/test_replication.py index fed67a8019..c97a37115b 100644 --- a/tests/integration/ha_tests/test_replication.py +++ b/tests/integration/ha_tests/test_replication.py @@ -6,7 +6,13 @@ from pytest_operator.plugin import OpsTest from tenacity import Retrying, stop_after_delay, wait_fixed -from ..helpers import APPLICATION_NAME, CHARM_BASE, db_connect, scale_application +from ..helpers import ( + APPLICATION_NAME, + CHARM_BASE, + DATABASE_APP_NAME, + db_connect, + scale_application, +) from .helpers import ( app_name, are_writes_increasing, @@ -46,6 +52,7 @@ async def test_build_and_deploy(ops_test: OpsTest, charm) -> None: if wait_for_apps: async with ops_test.fast_forward(): + await ops_test.model.relate(DATABASE_APP_NAME, f"{APPLICATION_NAME}:database") await ops_test.model.wait_for_idle(status="active", timeout=1500) diff --git a/tests/integration/ha_tests/test_scaling.py b/tests/integration/ha_tests/test_scaling.py index 8c85dd931e..7ea2f6c90f 100644 --- a/tests/integration/ha_tests/test_scaling.py +++ b/tests/integration/ha_tests/test_scaling.py @@ -50,6 +50,7 @@ async def test_build_and_deploy(ops_test: OpsTest, charm) -> None: ), ) + await ops_test.model.relate(DATABASE_APP_NAME, f"{APPLICATION_NAME}:database") await ops_test.model.wait_for_idle(status="active", timeout=1500) diff --git a/tests/integration/ha_tests/test_scaling_three_units.py b/tests/integration/ha_tests/test_scaling_three_units.py index 3615a04df6..e0407d2a2f 100644 --- a/tests/integration/ha_tests/test_scaling_three_units.py +++ b/tests/integration/ha_tests/test_scaling_three_units.py @@ -52,6 +52,7 @@ async def test_build_and_deploy(ops_test: OpsTest, charm) -> None: ), ) + await ops_test.model.relate(DATABASE_APP_NAME, f"{APPLICATION_NAME}:database") await ops_test.model.wait_for_idle(status="active", timeout=1500) diff --git a/tests/integration/ha_tests/test_scaling_three_units_async.py b/tests/integration/ha_tests/test_scaling_three_units_async.py index a45e1484e2..07fa956af8 100644 --- a/tests/integration/ha_tests/test_scaling_three_units_async.py +++ b/tests/integration/ha_tests/test_scaling_three_units_async.py @@ -52,6 +52,7 @@ async def test_build_and_deploy(ops_test: OpsTest, charm) -> None: ), ) + await ops_test.model.relate(DATABASE_APP_NAME, f"{APPLICATION_NAME}:database") await ops_test.model.wait_for_idle(status="active", timeout=1500) diff --git a/tests/integration/ha_tests/test_self_healing.py b/tests/integration/ha_tests/test_self_healing.py index a5b4faddac..1ec6141366 100644 --- a/tests/integration/ha_tests/test_self_healing.py +++ b/tests/integration/ha_tests/test_self_healing.py @@ -12,6 +12,7 @@ from .. import markers from ..helpers import ( CHARM_BASE, + DATABASE_APP_NAME, db_connect, get_machine_from_unit, get_password, @@ -91,6 +92,7 @@ async def test_build_and_deploy(ops_test: OpsTest, charm) -> None: ) if wait_for_apps: + await ops_test.model.relate(DATABASE_APP_NAME, f"{APPLICATION_NAME}:database") async with ops_test.fast_forward(): await ops_test.model.wait_for_idle(status="active", timeout=1500) diff --git a/tests/integration/ha_tests/test_upgrade.py b/tests/integration/ha_tests/test_upgrade.py index 06b98bcceb..a8ef5ba38c 100644 --- a/tests/integration/ha_tests/test_upgrade.py +++ b/tests/integration/ha_tests/test_upgrade.py @@ -43,6 +43,7 @@ async def test_deploy_latest(ops_test: OpsTest) -> None: num_units=1, channel="latest/edge", ) + await ops_test.model.relate(DATABASE_APP_NAME, f"{APPLICATION_NAME}:database") logger.info("Wait for applications to become active") async with ops_test.fast_forward(): await ops_test.model.wait_for_idle( diff --git a/tests/integration/ha_tests/test_upgrade_from_stable.py b/tests/integration/ha_tests/test_upgrade_from_stable.py index db0586a2ab..49feed0063 100644 --- a/tests/integration/ha_tests/test_upgrade_from_stable.py +++ b/tests/integration/ha_tests/test_upgrade_from_stable.py @@ -67,6 +67,7 @@ async def test_deploy_stable(ops_test: OpsTest) -> None: num_units=1, channel="latest/edge", ) + await ops_test.model.relate(DATABASE_APP_NAME, f"{APPLICATION_NAME}:database") logger.info("Wait for applications to become active") async with ops_test.fast_forward(): await ops_test.model.wait_for_idle( diff --git a/tests/integration/new_relations/test_new_relations_1.py b/tests/integration/new_relations/test_new_relations_1.py index 88d5f030a9..5190d1f1d8 100644 --- a/tests/integration/new_relations/test_new_relations_1.py +++ b/tests/integration/new_relations/test_new_relations_1.py @@ -77,7 +77,9 @@ async def test_deploy_charms(ops_test: OpsTest, charm): ), ) - await ops_test.model.wait_for_idle(apps=APP_NAMES, status="active", timeout=3000) + await ops_test.model.wait_for_idle( + apps=[DATABASE_APP_NAME, ANOTHER_DATABASE_APP_NAME], status="active", timeout=3000 + ) async def test_primary_read_only_endpoint_in_standalone_cluster(ops_test: OpsTest): @@ -265,7 +267,6 @@ async def test_two_applications_doesnt_share_the_same_relation_data(ops_test: Op channel="latest/edge", base=CHARM_BASE, ) - await ops_test.model.wait_for_idle(apps=all_app_names, status="active") # Relate the new application with the database # and wait for them exchanging some connection data. diff --git a/tests/integration/relations/test_relations.py b/tests/integration/relations/test_relations.py index 0037b5c140..2f56784c26 100644 --- a/tests/integration/relations/test_relations.py +++ b/tests/integration/relations/test_relations.py @@ -37,7 +37,7 @@ async def test_deploy_charms(ops_test: OpsTest, charm): application_name=DATABASE_APP_NAME, num_units=1, base=CHARM_BASE, - channel="edge", + channel="latest/edge", ), ops_test.model.deploy( charm, @@ -55,11 +55,11 @@ async def test_deploy_charms(ops_test: OpsTest, charm): application_name=DB_APP_NAME, num_units=1, base=CHARM_BASE, - channel="edge", + channel="latest/edge", ), ) - await ops_test.model.wait_for_idle(apps=APP_NAMES, status="active", timeout=3000) + await ops_test.model.wait_for_idle(apps=[APP_NAME], status="active", timeout=3000) async def test_legacy_endpoint_with_multiple_related_endpoints(ops_test: OpsTest): @@ -78,6 +78,7 @@ async def test_legacy_endpoint_with_multiple_related_endpoints(ops_test: OpsTest ) async with ops_test.fast_forward(): await ops_test.model.wait_for_idle( + apps=[APP_NAME], status="active", timeout=1500, raise_on_error=False, @@ -117,7 +118,9 @@ async def test_modern_endpoint_with_multiple_related_endpoints(ops_test: OpsTest f"{DB_APP_NAME}:{DB_RELATION}", f"{APP_NAME}:{DB_RELATION}" ) async with ops_test.fast_forward(): - await ops_test.model.wait_for_idle(status="active", timeout=3000, raise_on_error=False) + await ops_test.model.wait_for_idle( + apps=[APP_NAME], status="active", timeout=3000, raise_on_error=False + ) modern_interface_connect = await build_connection_string( ops_test, DATABASE_APP_NAME, FIRST_DATABASE_RELATION diff --git a/tests/integration/test_db.py b/tests/integration/test_db.py index a24ea28475..3b643be254 100644 --- a/tests/integration/test_db.py +++ b/tests/integration/test_db.py @@ -209,9 +209,7 @@ async def test_roles_blocking(ops_test: OpsTest, charm: str) -> None: ) await ops_test.model.wait_for_idle( - apps=[DATABASE_APP_NAME, APPLICATION_NAME, f"{APPLICATION_NAME}2"], - status="active", - timeout=1000, + apps=[APPLICATION_NAME, f"{APPLICATION_NAME}2"], status="blocked", timeout=1000 ) await asyncio.gather( @@ -242,11 +240,7 @@ async def test_roles_blocking(ops_test: OpsTest, charm: str) -> None: f"{DATABASE_APP_NAME}:db", f"{APPLICATION_NAME}2:db" ) - await ops_test.model.wait_for_idle( - apps=[DATABASE_APP_NAME], - status="active", - timeout=1000, - ) + await ops_test.model.wait_for_idle(apps=[DATABASE_APP_NAME], status="active", timeout=1000) async def test_extensions_blocking(ops_test: OpsTest, charm: str) -> None: @@ -255,9 +249,7 @@ async def test_extensions_blocking(ops_test: OpsTest, charm: str) -> None: ops_test.model.applications[f"{APPLICATION_NAME}2"].set_config({"legacy_roles": "False"}), ) await ops_test.model.wait_for_idle( - apps=[APPLICATION_NAME, f"{APPLICATION_NAME}2"], - status="active", - timeout=1000, + apps=[APPLICATION_NAME, f"{APPLICATION_NAME}2"], status="blocked", timeout=1000 ) await asyncio.gather( @@ -288,6 +280,8 @@ async def test_extensions_blocking(ops_test: OpsTest, charm: str) -> None: f"{DATABASE_APP_NAME}:db", f"{APPLICATION_NAME}2:db" ) + await ops_test.model.wait_for_idle(apps=[DATABASE_APP_NAME], status="active", timeout=1000) + @markers.juju2 @pytest.mark.skip(reason="Unstable") diff --git a/tests/integration/test_pg_hba.py b/tests/integration/test_pg_hba.py index 62a261bf8b..308f1decea 100644 --- a/tests/integration/test_pg_hba.py +++ b/tests/integration/test_pg_hba.py @@ -104,7 +104,7 @@ async def test_pg_hba(ops_test: OpsTest, charm): if connection: connection.close() - sleep(60) + sleep(90) for unit in ops_test.model.applications[DATABASE_APP_NAME].units: try: diff --git a/tests/unit/test_cluster_topology_observer.py b/tests/unit/test_cluster_topology_observer.py index 4047d2b13d..f620defb9f 100644 --- a/tests/unit/test_cluster_topology_observer.py +++ b/tests/unit/test_cluster_topology_observer.py @@ -141,7 +141,7 @@ def test_dispatch(harness): def test_main(): with ( - patch("scripts.cluster_topology_observer.check_for_authorisation_rules_changes"), + patch("scripts.cluster_topology_observer.check_for_database_changes"), patch.object( sys, "argv", From 33f0ca5858c4b76c49525f84620314e74b599a3a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 31 Jul 2025 21:53:43 +0300 Subject: [PATCH 066/112] Update canonical/data-platform-workflows action to v32.2.1 (#1065) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/approve_renovate_pr.yaml | 2 +- .github/workflows/check_pr.yaml | 2 +- .github/workflows/ci.yaml | 4 ++-- .github/workflows/promote.yaml | 2 +- .github/workflows/release.yaml | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/approve_renovate_pr.yaml b/.github/workflows/approve_renovate_pr.yaml index 102a832cc3..be0c1ee058 100644 --- a/.github/workflows/approve_renovate_pr.yaml +++ b/.github/workflows/approve_renovate_pr.yaml @@ -10,6 +10,6 @@ on: jobs: approve-pr: name: Approve Renovate pull request - uses: canonical/data-platform-workflows/.github/workflows/approve_renovate_pr.yaml@v32.1.0 + uses: canonical/data-platform-workflows/.github/workflows/approve_renovate_pr.yaml@v32.2.1 permissions: pull-requests: write # Needed to approve PR diff --git a/.github/workflows/check_pr.yaml b/.github/workflows/check_pr.yaml index a12b5edbea..e5bf04489a 100644 --- a/.github/workflows/check_pr.yaml +++ b/.github/workflows/check_pr.yaml @@ -16,4 +16,4 @@ on: jobs: check-pr: name: Check pull request - uses: canonical/data-platform-workflows/.github/workflows/check_charm_pr.yaml@v32.1.0 + uses: canonical/data-platform-workflows/.github/workflows/check_charm_pr.yaml@v32.2.1 diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index c51315e37d..4d3259ee7a 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -27,7 +27,7 @@ on: jobs: lint: name: Lint - uses: canonical/data-platform-workflows/.github/workflows/lint.yaml@v32.1.0 + uses: canonical/data-platform-workflows/.github/workflows/lint.yaml@v32.2.1 unit-test: name: Unit test charm @@ -49,7 +49,7 @@ jobs: build: name: Build charm - uses: canonical/data-platform-workflows/.github/workflows/build_charm.yaml@v32.1.0 + uses: canonical/data-platform-workflows/.github/workflows/build_charm.yaml@v32.2.1 integration-test: name: Integration test charm diff --git a/.github/workflows/promote.yaml b/.github/workflows/promote.yaml index 9df0cbdebd..dcd9d19863 100644 --- a/.github/workflows/promote.yaml +++ b/.github/workflows/promote.yaml @@ -25,7 +25,7 @@ on: jobs: promote: name: Promote charm - uses: canonical/data-platform-workflows/.github/workflows/_promote_charm.yaml@v32.1.0 + uses: canonical/data-platform-workflows/.github/workflows/_promote_charm.yaml@v32.2.1 with: track: '14' from-risk: ${{ inputs.from-risk }} diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index cf7c6d1727..f21f08e3ca 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -27,7 +27,7 @@ jobs: name: Release charm needs: - ci-tests - uses: canonical/data-platform-workflows/.github/workflows/release_charm_edge.yaml@v32.1.0 + uses: canonical/data-platform-workflows/.github/workflows/release_charm_edge.yaml@v32.2.1 with: track: 14 artifact-prefix: ${{ needs.ci-tests.outputs.artifact-prefix }} From a54e10e61565a81e8a18ae48794c68c488c0fc6b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 31 Jul 2025 22:49:28 +0300 Subject: [PATCH 067/112] Lock file maintenance Python dependencies (#1020) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- poetry.lock | 617 ++++++++++++++++++++++++++----------------------- pyproject.toml | 16 +- 2 files changed, 341 insertions(+), 292 deletions(-) diff --git a/poetry.lock b/poetry.lock index 414282cd2c..3b4b3a4ae3 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2,18 +2,18 @@ [[package]] name = "allure-pytest" -version = "2.14.3" +version = "2.15.0" description = "Allure pytest integration" optional = false python-versions = "*" groups = ["integration"] files = [ - {file = "allure_pytest-2.14.3-py3-none-any.whl", hash = "sha256:9704dea12f98991bc9e13be4ce9f90fe703beaff90e4741d67ae64c9815336c5"}, - {file = "allure_pytest-2.14.3.tar.gz", hash = "sha256:6d02a129867c7ef8b6943721d2be3141e3d1c3551741aff17b6afee64cd92b60"}, + {file = "allure_pytest-2.15.0-py3-none-any.whl", hash = "sha256:f33c6ad242995bd27d2b467ee685772904d6941a6a6c9877657e0b8fe97a0ede"}, + {file = "allure_pytest-2.15.0.tar.gz", hash = "sha256:b8f464d3bfeb6cb5e6a77e70eacd1aa3762133677cabece57a07c9f3bcd4b1e8"}, ] [package.dependencies] -allure-python-commons = "2.14.3" +allure-python-commons = "2.15.0" pytest = ">=4.5.0" [[package]] @@ -34,14 +34,14 @@ pytest = "*" [[package]] name = "allure-python-commons" -version = "2.14.3" +version = "2.15.0" description = "Contains the API for end users as well as helper functions and classes to build Allure adapters for Python test frameworks" optional = false python-versions = ">=3.6" groups = ["integration"] files = [ - {file = "allure_python_commons-2.14.3-py3-none-any.whl", hash = "sha256:7bcf6a2eff69e6f0eacd8681e923f0a9dfbdd86cb8e20d8f93288057f9fb7cb1"}, - {file = "allure_python_commons-2.14.3.tar.gz", hash = "sha256:2dcaa87dd6b0b41902f60fe17e2653d3762788f3998ca4cf721dabfa8342aa07"}, + {file = "allure_python_commons-2.15.0-py3-none-any.whl", hash = "sha256:84ebbbca2e4c147ed151e615f995eb2e0dd688818d06c55df9e8e3ce4de6eeeb"}, + {file = "allure_python_commons-2.15.0.tar.gz", hash = "sha256:4f639c8bb4b79df0d94f1baa88782c9399be3f45fd839ae583a314a5d451b978"}, ] [package.dependencies] @@ -233,18 +233,18 @@ typecheck = ["mypy"] [[package]] name = "boto3" -version = "1.39.0" +version = "1.39.17" description = "The AWS SDK for Python" optional = false python-versions = ">=3.9" groups = ["main", "integration"] files = [ - {file = "boto3-1.39.0-py3-none-any.whl", hash = "sha256:6257f6f7bb87b66342564eab579ce1f0f63a4c1a6f701492f959e59bd7af68e5"}, - {file = "boto3-1.39.0.tar.gz", hash = "sha256:52a9f07fb9fa60ec6a2be07cd1586a97d8adae2be750121d4c032349cd113221"}, + {file = "boto3-1.39.17-py3-none-any.whl", hash = "sha256:6af9f7d6db7b5e72d6869ae22ebad1b0c6602591af2ef5d914b331a055953df5"}, + {file = "boto3-1.39.17.tar.gz", hash = "sha256:a6904a40b1c61f6a1766574b3155ec75a6020399fb570be2b51bf93a2c0a2b3d"}, ] [package.dependencies] -botocore = ">=1.39.0,<1.40.0" +botocore = ">=1.39.17,<1.40.0" jmespath = ">=0.7.1,<2.0.0" s3transfer = ">=0.13.0,<0.14.0" @@ -253,14 +253,14 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.39.0" +version = "1.39.17" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">=3.9" groups = ["main", "integration"] files = [ - {file = "botocore-1.39.0-py3-none-any.whl", hash = "sha256:d8e72850d3450aeca355b654efb32c8370bf824c1945a61cad2395dc2688581e"}, - {file = "botocore-1.39.0.tar.gz", hash = "sha256:2b8701e529a80241b989d83262a629d0d91fbd7a06ded63ecc1c9d529a383d57"}, + {file = "botocore-1.39.17-py3-none-any.whl", hash = "sha256:41db169e919f821b3ef684794c5e67dd7bb1f5ab905d33729b1d8c27fafe8004"}, + {file = "botocore-1.39.17.tar.gz", hash = "sha256:1a1f0b29dab5d1b10d16f14423c16ac0a3043272f579e9ab0d757753ee9a7d2b"}, ] [package.dependencies] @@ -285,14 +285,14 @@ files = [ [[package]] name = "certifi" -version = "2025.6.15" +version = "2025.7.14" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.7" groups = ["main", "charm-libs", "integration"] files = [ - {file = "certifi-2025.6.15-py3-none-any.whl", hash = "sha256:2e0c7ce7cb5d8f8634ca55d2ba7e6ec2689a2fd6537d8dec1296a477a4910057"}, - {file = "certifi-2025.6.15.tar.gz", hash = "sha256:d747aa5a8b9bbbb1bb8c22bb13e22bd1f18e9796defa16bab421f7f7a317323b"}, + {file = "certifi-2025.7.14-py3-none-any.whl", hash = "sha256:6b31f564a415d79ee77df69d757bb49a5bb53bd9f756cbbe24394ffd6fc1f4b2"}, + {file = "certifi-2025.7.14.tar.gz", hash = "sha256:8ea99dbdfaaf2ba2f9bac77b9249ef62ec5218e7c2b2e903378ed5fccf765995"}, ] [[package]] @@ -530,79 +530,100 @@ typing-extensions = "*" [[package]] name = "coverage" -version = "7.9.1" +version = "7.10.1" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.9" groups = ["unit"] files = [ - {file = "coverage-7.9.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cc94d7c5e8423920787c33d811c0be67b7be83c705f001f7180c7b186dcf10ca"}, - {file = "coverage-7.9.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:16aa0830d0c08a2c40c264cef801db8bc4fc0e1892782e45bcacbd5889270509"}, - {file = "coverage-7.9.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf95981b126f23db63e9dbe4cf65bd71f9a6305696fa5e2262693bc4e2183f5b"}, - {file = "coverage-7.9.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f05031cf21699785cd47cb7485f67df619e7bcdae38e0fde40d23d3d0210d3c3"}, - {file = "coverage-7.9.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb4fbcab8764dc072cb651a4bcda4d11fb5658a1d8d68842a862a6610bd8cfa3"}, - {file = "coverage-7.9.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0f16649a7330ec307942ed27d06ee7e7a38417144620bb3d6e9a18ded8a2d3e5"}, - {file = "coverage-7.9.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:cea0a27a89e6432705fffc178064503508e3c0184b4f061700e771a09de58187"}, - {file = "coverage-7.9.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e980b53a959fa53b6f05343afbd1e6f44a23ed6c23c4b4c56c6662bbb40c82ce"}, - {file = "coverage-7.9.1-cp310-cp310-win32.whl", hash = "sha256:70760b4c5560be6ca70d11f8988ee6542b003f982b32f83d5ac0b72476607b70"}, - {file = "coverage-7.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:a66e8f628b71f78c0e0342003d53b53101ba4e00ea8dabb799d9dba0abbbcebe"}, - {file = "coverage-7.9.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:95c765060e65c692da2d2f51a9499c5e9f5cf5453aeaf1420e3fc847cc060582"}, - {file = "coverage-7.9.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ba383dc6afd5ec5b7a0d0c23d38895db0e15bcba7fb0fa8901f245267ac30d86"}, - {file = "coverage-7.9.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:37ae0383f13cbdcf1e5e7014489b0d71cc0106458878ccde52e8a12ced4298ed"}, - {file = "coverage-7.9.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:69aa417a030bf11ec46149636314c24c8d60fadb12fc0ee8f10fda0d918c879d"}, - {file = "coverage-7.9.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a4be2a28656afe279b34d4f91c3e26eccf2f85500d4a4ff0b1f8b54bf807338"}, - {file = "coverage-7.9.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:382e7ddd5289f140259b610e5f5c58f713d025cb2f66d0eb17e68d0a94278875"}, - {file = "coverage-7.9.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e5532482344186c543c37bfad0ee6069e8ae4fc38d073b8bc836fc8f03c9e250"}, - {file = "coverage-7.9.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a39d18b3f50cc121d0ce3838d32d58bd1d15dab89c910358ebefc3665712256c"}, - {file = "coverage-7.9.1-cp311-cp311-win32.whl", hash = "sha256:dd24bd8d77c98557880def750782df77ab2b6885a18483dc8588792247174b32"}, - {file = "coverage-7.9.1-cp311-cp311-win_amd64.whl", hash = "sha256:6b55ad10a35a21b8015eabddc9ba31eb590f54adc9cd39bcf09ff5349fd52125"}, - {file = "coverage-7.9.1-cp311-cp311-win_arm64.whl", hash = "sha256:6ad935f0016be24c0e97fc8c40c465f9c4b85cbbe6eac48934c0dc4d2568321e"}, - {file = "coverage-7.9.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a8de12b4b87c20de895f10567639c0797b621b22897b0af3ce4b4e204a743626"}, - {file = "coverage-7.9.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5add197315a054e92cee1b5f686a2bcba60c4c3e66ee3de77ace6c867bdee7cb"}, - {file = "coverage-7.9.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:600a1d4106fe66f41e5d0136dfbc68fe7200a5cbe85610ddf094f8f22e1b0300"}, - {file = "coverage-7.9.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2a876e4c3e5a2a1715a6608906aa5a2e0475b9c0f68343c2ada98110512ab1d8"}, - {file = "coverage-7.9.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81f34346dd63010453922c8e628a52ea2d2ccd73cb2487f7700ac531b247c8a5"}, - {file = "coverage-7.9.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:888f8eee13f2377ce86d44f338968eedec3291876b0b8a7289247ba52cb984cd"}, - {file = "coverage-7.9.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:9969ef1e69b8c8e1e70d591f91bbc37fc9a3621e447525d1602801a24ceda898"}, - {file = "coverage-7.9.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:60c458224331ee3f1a5b472773e4a085cc27a86a0b48205409d364272d67140d"}, - {file = "coverage-7.9.1-cp312-cp312-win32.whl", hash = "sha256:5f646a99a8c2b3ff4c6a6e081f78fad0dde275cd59f8f49dc4eab2e394332e74"}, - {file = "coverage-7.9.1-cp312-cp312-win_amd64.whl", hash = "sha256:30f445f85c353090b83e552dcbbdad3ec84c7967e108c3ae54556ca69955563e"}, - {file = "coverage-7.9.1-cp312-cp312-win_arm64.whl", hash = "sha256:af41da5dca398d3474129c58cb2b106a5d93bbb196be0d307ac82311ca234342"}, - {file = "coverage-7.9.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:31324f18d5969feef7344a932c32428a2d1a3e50b15a6404e97cba1cc9b2c631"}, - {file = "coverage-7.9.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0c804506d624e8a20fb3108764c52e0eef664e29d21692afa375e0dd98dc384f"}, - {file = "coverage-7.9.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef64c27bc40189f36fcc50c3fb8f16ccda73b6a0b80d9bd6e6ce4cffcd810bbd"}, - {file = "coverage-7.9.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d4fe2348cc6ec372e25adec0219ee2334a68d2f5222e0cba9c0d613394e12d86"}, - {file = "coverage-7.9.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:34ed2186fe52fcc24d4561041979a0dec69adae7bce2ae8d1c49eace13e55c43"}, - {file = "coverage-7.9.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:25308bd3d00d5eedd5ae7d4357161f4df743e3c0240fa773ee1b0f75e6c7c0f1"}, - {file = "coverage-7.9.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:73e9439310f65d55a5a1e0564b48e34f5369bee943d72c88378f2d576f5a5751"}, - {file = "coverage-7.9.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:37ab6be0859141b53aa89412a82454b482c81cf750de4f29223d52268a86de67"}, - {file = "coverage-7.9.1-cp313-cp313-win32.whl", hash = "sha256:64bdd969456e2d02a8b08aa047a92d269c7ac1f47e0c977675d550c9a0863643"}, - {file = "coverage-7.9.1-cp313-cp313-win_amd64.whl", hash = "sha256:be9e3f68ca9edb897c2184ad0eee815c635565dbe7a0e7e814dc1f7cbab92c0a"}, - {file = "coverage-7.9.1-cp313-cp313-win_arm64.whl", hash = "sha256:1c503289ffef1d5105d91bbb4d62cbe4b14bec4d13ca225f9c73cde9bb46207d"}, - {file = "coverage-7.9.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0b3496922cb5f4215bf5caaef4cf12364a26b0be82e9ed6d050f3352cf2d7ef0"}, - {file = "coverage-7.9.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:9565c3ab1c93310569ec0d86b017f128f027cab0b622b7af288696d7ed43a16d"}, - {file = "coverage-7.9.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2241ad5dbf79ae1d9c08fe52b36d03ca122fb9ac6bca0f34439e99f8327ac89f"}, - {file = "coverage-7.9.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3bb5838701ca68b10ebc0937dbd0eb81974bac54447c55cd58dea5bca8451029"}, - {file = "coverage-7.9.1-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b30a25f814591a8c0c5372c11ac8967f669b97444c47fd794926e175c4047ece"}, - {file = "coverage-7.9.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:2d04b16a6062516df97969f1ae7efd0de9c31eb6ebdceaa0d213b21c0ca1a683"}, - {file = "coverage-7.9.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:7931b9e249edefb07cd6ae10c702788546341d5fe44db5b6108a25da4dca513f"}, - {file = "coverage-7.9.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:52e92b01041151bf607ee858e5a56c62d4b70f4dac85b8c8cb7fb8a351ab2c10"}, - {file = "coverage-7.9.1-cp313-cp313t-win32.whl", hash = "sha256:684e2110ed84fd1ca5f40e89aa44adf1729dc85444004111aa01866507adf363"}, - {file = "coverage-7.9.1-cp313-cp313t-win_amd64.whl", hash = "sha256:437c576979e4db840539674e68c84b3cda82bc824dd138d56bead1435f1cb5d7"}, - {file = "coverage-7.9.1-cp313-cp313t-win_arm64.whl", hash = "sha256:18a0912944d70aaf5f399e350445738a1a20b50fbea788f640751c2ed9208b6c"}, - {file = "coverage-7.9.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6f424507f57878e424d9a95dc4ead3fbdd72fd201e404e861e465f28ea469951"}, - {file = "coverage-7.9.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:535fde4001b2783ac80865d90e7cc7798b6b126f4cd8a8c54acfe76804e54e58"}, - {file = "coverage-7.9.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:02532fd3290bb8fa6bec876520842428e2a6ed6c27014eca81b031c2d30e3f71"}, - {file = "coverage-7.9.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:56f5eb308b17bca3bbff810f55ee26d51926d9f89ba92707ee41d3c061257e55"}, - {file = "coverage-7.9.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfa447506c1a52271f1b0de3f42ea0fa14676052549095e378d5bff1c505ff7b"}, - {file = "coverage-7.9.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:9ca8e220006966b4a7b68e8984a6aee645a0384b0769e829ba60281fe61ec4f7"}, - {file = "coverage-7.9.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:49f1d0788ba5b7ba65933f3a18864117c6506619f5ca80326b478f72acf3f385"}, - {file = "coverage-7.9.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:68cd53aec6f45b8e4724c0950ce86eacb775c6be01ce6e3669fe4f3a21e768ed"}, - {file = "coverage-7.9.1-cp39-cp39-win32.whl", hash = "sha256:95335095b6c7b1cc14c3f3f17d5452ce677e8490d101698562b2ffcacc304c8d"}, - {file = "coverage-7.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:e1b5191d1648acc439b24721caab2fd0c86679d8549ed2c84d5a7ec1bedcc244"}, - {file = "coverage-7.9.1-pp39.pp310.pp311-none-any.whl", hash = "sha256:db0f04118d1db74db6c9e1cb1898532c7dcc220f1d2718f058601f7c3f499514"}, - {file = "coverage-7.9.1-py3-none-any.whl", hash = "sha256:66b974b145aa189516b6bf2d8423e888b742517d37872f6ee4c5be0073bd9a3c"}, - {file = "coverage-7.9.1.tar.gz", hash = "sha256:6cf43c78c4282708a28e466316935ec7489a9c487518a77fa68f716c67909cec"}, + {file = "coverage-7.10.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1c86eb388bbd609d15560e7cc0eb936c102b6f43f31cf3e58b4fd9afe28e1372"}, + {file = "coverage-7.10.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6b4ba0f488c1bdb6bd9ba81da50715a372119785458831c73428a8566253b86b"}, + {file = "coverage-7.10.1-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:083442ecf97d434f0cb3b3e3676584443182653da08b42e965326ba12d6b5f2a"}, + {file = "coverage-7.10.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c1a40c486041006b135759f59189385da7c66d239bad897c994e18fd1d0c128f"}, + {file = "coverage-7.10.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3beb76e20b28046989300c4ea81bf690df84ee98ade4dc0bbbf774a28eb98440"}, + {file = "coverage-7.10.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:bc265a7945e8d08da28999ad02b544963f813a00f3ed0a7a0ce4165fd77629f8"}, + {file = "coverage-7.10.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:47c91f32ba4ac46f1e224a7ebf3f98b4b24335bad16137737fe71a5961a0665c"}, + {file = "coverage-7.10.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:1a108dd78ed185020f66f131c60078f3fae3f61646c28c8bb4edd3fa121fc7fc"}, + {file = "coverage-7.10.1-cp310-cp310-win32.whl", hash = "sha256:7092cc82382e634075cc0255b0b69cb7cada7c1f249070ace6a95cb0f13548ef"}, + {file = "coverage-7.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:ac0c5bba938879c2fc0bc6c1b47311b5ad1212a9dcb8b40fe2c8110239b7faed"}, + {file = "coverage-7.10.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b45e2f9d5b0b5c1977cb4feb5f594be60eb121106f8900348e29331f553a726f"}, + {file = "coverage-7.10.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3a7a4d74cb0f5e3334f9aa26af7016ddb94fb4bfa11b4a573d8e98ecba8c34f1"}, + {file = "coverage-7.10.1-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d4b0aab55ad60ead26159ff12b538c85fbab731a5e3411c642b46c3525863437"}, + {file = "coverage-7.10.1-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:dcc93488c9ebd229be6ee1f0d9aad90da97b33ad7e2912f5495804d78a3cd6b7"}, + {file = "coverage-7.10.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:aa309df995d020f3438407081b51ff527171cca6772b33cf8f85344b8b4b8770"}, + {file = "coverage-7.10.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cfb8b9d8855c8608f9747602a48ab525b1d320ecf0113994f6df23160af68262"}, + {file = "coverage-7.10.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:320d86da829b012982b414c7cdda65f5d358d63f764e0e4e54b33097646f39a3"}, + {file = "coverage-7.10.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:dc60ddd483c556590da1d9482a4518292eec36dd0e1e8496966759a1f282bcd0"}, + {file = "coverage-7.10.1-cp311-cp311-win32.whl", hash = "sha256:4fcfe294f95b44e4754da5b58be750396f2b1caca8f9a0e78588e3ef85f8b8be"}, + {file = "coverage-7.10.1-cp311-cp311-win_amd64.whl", hash = "sha256:efa23166da3fe2915f8ab452dde40319ac84dc357f635737174a08dbd912980c"}, + {file = "coverage-7.10.1-cp311-cp311-win_arm64.whl", hash = "sha256:d12b15a8c3759e2bb580ffa423ae54be4f184cf23beffcbd641f4fe6e1584293"}, + {file = "coverage-7.10.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6b7dc7f0a75a7eaa4584e5843c873c561b12602439d2351ee28c7478186c4da4"}, + {file = "coverage-7.10.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:607f82389f0ecafc565813aa201a5cade04f897603750028dd660fb01797265e"}, + {file = "coverage-7.10.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:f7da31a1ba31f1c1d4d5044b7c5813878adae1f3af8f4052d679cc493c7328f4"}, + {file = "coverage-7.10.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:51fe93f3fe4f5d8483d51072fddc65e717a175490804e1942c975a68e04bf97a"}, + {file = "coverage-7.10.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3e59d00830da411a1feef6ac828b90bbf74c9b6a8e87b8ca37964925bba76dbe"}, + {file = "coverage-7.10.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:924563481c27941229cb4e16eefacc35da28563e80791b3ddc5597b062a5c386"}, + {file = "coverage-7.10.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:ca79146ee421b259f8131f153102220b84d1a5e6fb9c8aed13b3badfd1796de6"}, + {file = "coverage-7.10.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2b225a06d227f23f386fdc0eab471506d9e644be699424814acc7d114595495f"}, + {file = "coverage-7.10.1-cp312-cp312-win32.whl", hash = "sha256:5ba9a8770effec5baaaab1567be916c87d8eea0c9ad11253722d86874d885eca"}, + {file = "coverage-7.10.1-cp312-cp312-win_amd64.whl", hash = "sha256:9eb245a8d8dd0ad73b4062135a251ec55086fbc2c42e0eb9725a9b553fba18a3"}, + {file = "coverage-7.10.1-cp312-cp312-win_arm64.whl", hash = "sha256:7718060dd4434cc719803a5e526838a5d66e4efa5dc46d2b25c21965a9c6fcc4"}, + {file = "coverage-7.10.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ebb08d0867c5a25dffa4823377292a0ffd7aaafb218b5d4e2e106378b1061e39"}, + {file = "coverage-7.10.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f32a95a83c2e17422f67af922a89422cd24c6fa94041f083dd0bb4f6057d0bc7"}, + {file = "coverage-7.10.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:c4c746d11c8aba4b9f58ca8bfc6fbfd0da4efe7960ae5540d1a1b13655ee8892"}, + {file = "coverage-7.10.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7f39edd52c23e5c7ed94e0e4bf088928029edf86ef10b95413e5ea670c5e92d7"}, + {file = "coverage-7.10.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ab6e19b684981d0cd968906e293d5628e89faacb27977c92f3600b201926b994"}, + {file = "coverage-7.10.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5121d8cf0eacb16133501455d216bb5f99899ae2f52d394fe45d59229e6611d0"}, + {file = "coverage-7.10.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:df1c742ca6f46a6f6cbcaef9ac694dc2cb1260d30a6a2f5c68c5f5bcfee1cfd7"}, + {file = "coverage-7.10.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:40f9a38676f9c073bf4b9194707aa1eb97dca0e22cc3766d83879d72500132c7"}, + {file = "coverage-7.10.1-cp313-cp313-win32.whl", hash = "sha256:2348631f049e884839553b9974f0821d39241c6ffb01a418efce434f7eba0fe7"}, + {file = "coverage-7.10.1-cp313-cp313-win_amd64.whl", hash = "sha256:4072b31361b0d6d23f750c524f694e1a417c1220a30d3ef02741eed28520c48e"}, + {file = "coverage-7.10.1-cp313-cp313-win_arm64.whl", hash = "sha256:3e31dfb8271937cab9425f19259b1b1d1f556790e98eb266009e7a61d337b6d4"}, + {file = "coverage-7.10.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:1c4f679c6b573a5257af6012f167a45be4c749c9925fd44d5178fd641ad8bf72"}, + {file = "coverage-7.10.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:871ebe8143da284bd77b84a9136200bd638be253618765d21a1fce71006d94af"}, + {file = "coverage-7.10.1-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:998c4751dabf7d29b30594af416e4bf5091f11f92a8d88eb1512c7ba136d1ed7"}, + {file = "coverage-7.10.1-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:780f750a25e7749d0af6b3631759c2c14f45de209f3faaa2398312d1c7a22759"}, + {file = "coverage-7.10.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:590bdba9445df4763bdbebc928d8182f094c1f3947a8dc0fc82ef014dbdd8324"}, + {file = "coverage-7.10.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b2df80cb6a2af86d300e70acb82e9b79dab2c1e6971e44b78dbfc1a1e736b53"}, + {file = "coverage-7.10.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:d6a558c2725bfb6337bf57c1cd366c13798bfd3bfc9e3dd1f4a6f6fc95a4605f"}, + {file = "coverage-7.10.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e6150d167f32f2a54690e572e0a4c90296fb000a18e9b26ab81a6489e24e78dd"}, + {file = "coverage-7.10.1-cp313-cp313t-win32.whl", hash = "sha256:d946a0c067aa88be4a593aad1236493313bafaa27e2a2080bfe88db827972f3c"}, + {file = "coverage-7.10.1-cp313-cp313t-win_amd64.whl", hash = "sha256:e37c72eaccdd5ed1130c67a92ad38f5b2af66eeff7b0abe29534225db2ef7b18"}, + {file = "coverage-7.10.1-cp313-cp313t-win_arm64.whl", hash = "sha256:89ec0ffc215c590c732918c95cd02b55c7d0f569d76b90bb1a5e78aa340618e4"}, + {file = "coverage-7.10.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:166d89c57e877e93d8827dac32cedae6b0277ca684c6511497311249f35a280c"}, + {file = "coverage-7.10.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:bed4a2341b33cd1a7d9ffc47df4a78ee61d3416d43b4adc9e18b7d266650b83e"}, + {file = "coverage-7.10.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:ddca1e4f5f4c67980533df01430184c19b5359900e080248bbf4ed6789584d8b"}, + {file = "coverage-7.10.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:37b69226001d8b7de7126cad7366b0778d36777e4d788c66991455ba817c5b41"}, + {file = "coverage-7.10.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b2f22102197bcb1722691296f9e589f02b616f874e54a209284dd7b9294b0b7f"}, + {file = "coverage-7.10.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:1e0c768b0f9ac5839dac5cf88992a4bb459e488ee8a1f8489af4cb33b1af00f1"}, + {file = "coverage-7.10.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:991196702d5e0b120a8fef2664e1b9c333a81d36d5f6bcf6b225c0cf8b0451a2"}, + {file = "coverage-7.10.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ae8e59e5f4fd85d6ad34c2bb9d74037b5b11be072b8b7e9986beb11f957573d4"}, + {file = "coverage-7.10.1-cp314-cp314-win32.whl", hash = "sha256:042125c89cf74a074984002e165d61fe0e31c7bd40ebb4bbebf07939b5924613"}, + {file = "coverage-7.10.1-cp314-cp314-win_amd64.whl", hash = "sha256:a22c3bfe09f7a530e2c94c87ff7af867259c91bef87ed2089cd69b783af7b84e"}, + {file = "coverage-7.10.1-cp314-cp314-win_arm64.whl", hash = "sha256:ee6be07af68d9c4fca4027c70cea0c31a0f1bc9cb464ff3c84a1f916bf82e652"}, + {file = "coverage-7.10.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:d24fb3c0c8ff0d517c5ca5de7cf3994a4cd559cde0315201511dbfa7ab528894"}, + {file = "coverage-7.10.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1217a54cfd79be20512a67ca81c7da3f2163f51bbfd188aab91054df012154f5"}, + {file = "coverage-7.10.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:51f30da7a52c009667e02f125737229d7d8044ad84b79db454308033a7808ab2"}, + {file = "coverage-7.10.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:ed3718c757c82d920f1c94089066225ca2ad7f00bb904cb72b1c39ebdd906ccb"}, + {file = "coverage-7.10.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cc452481e124a819ced0c25412ea2e144269ef2f2534b862d9f6a9dae4bda17b"}, + {file = "coverage-7.10.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:9d6f494c307e5cb9b1e052ec1a471060f1dea092c8116e642e7a23e79d9388ea"}, + {file = "coverage-7.10.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:fc0e46d86905ddd16b85991f1f4919028092b4e511689bbdaff0876bd8aab3dd"}, + {file = "coverage-7.10.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:80b9ccd82e30038b61fc9a692a8dc4801504689651b281ed9109f10cc9fe8b4d"}, + {file = "coverage-7.10.1-cp314-cp314t-win32.whl", hash = "sha256:e58991a2b213417285ec866d3cd32db17a6a88061a985dbb7e8e8f13af429c47"}, + {file = "coverage-7.10.1-cp314-cp314t-win_amd64.whl", hash = "sha256:e88dd71e4ecbc49d9d57d064117462c43f40a21a1383507811cf834a4a620651"}, + {file = "coverage-7.10.1-cp314-cp314t-win_arm64.whl", hash = "sha256:1aadfb06a30c62c2eb82322171fe1f7c288c80ca4156d46af0ca039052814bab"}, + {file = "coverage-7.10.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:57b6e8789cbefdef0667e4a94f8ffa40f9402cee5fc3b8e4274c894737890145"}, + {file = "coverage-7.10.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:85b22a9cce00cb03156334da67eb86e29f22b5e93876d0dd6a98646bb8a74e53"}, + {file = "coverage-7.10.1-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:97b6983a2f9c76d345ca395e843a049390b39652984e4a3b45b2442fa733992d"}, + {file = "coverage-7.10.1-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:ddf2a63b91399a1c2f88f40bc1705d5a7777e31c7e9eb27c602280f477b582ba"}, + {file = "coverage-7.10.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:47ab6dbbc31a14c5486420c2c1077fcae692097f673cf5be9ddbec8cdaa4cdbc"}, + {file = "coverage-7.10.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:21eb7d8b45d3700e7c2936a736f732794c47615a20f739f4133d5230a6512a88"}, + {file = "coverage-7.10.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:283005bb4d98ae33e45f2861cd2cde6a21878661c9ad49697f6951b358a0379b"}, + {file = "coverage-7.10.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:fefe31d61d02a8b2c419700b1fade9784a43d726de26495f243b663cd9fe1513"}, + {file = "coverage-7.10.1-cp39-cp39-win32.whl", hash = "sha256:e8ab8e4c7ec7f8a55ac05b5b715a051d74eac62511c6d96d5bb79aaafa3b04cf"}, + {file = "coverage-7.10.1-cp39-cp39-win_amd64.whl", hash = "sha256:c36baa0ecde742784aa76c2b816466d3ea888d5297fda0edbac1bf48fa94688a"}, + {file = "coverage-7.10.1-py3-none-any.whl", hash = "sha256:fa2a258aa6bf188eb9a8948f7102a83da7c430a0dce918dbd8b60ef8fcb772d7"}, + {file = "coverage-7.10.1.tar.gz", hash = "sha256:ae2b4856f29ddfe827106794f3589949a57da6f0d38ab01e24ec35107979ba57"}, ] [package.dependencies] @@ -613,49 +634,49 @@ toml = ["tomli ; python_full_version <= \"3.11.0a6\""] [[package]] name = "cryptography" -version = "45.0.4" +version = "45.0.5" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false python-versions = "!=3.9.0,!=3.9.1,>=3.7" groups = ["charm-libs", "integration"] files = [ - {file = "cryptography-45.0.4-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:425a9a6ac2823ee6e46a76a21a4e8342d8fa5c01e08b823c1f19a8b74f096069"}, - {file = "cryptography-45.0.4-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:680806cf63baa0039b920f4976f5f31b10e772de42f16310a6839d9f21a26b0d"}, - {file = "cryptography-45.0.4-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4ca0f52170e821bc8da6fc0cc565b7bb8ff8d90d36b5e9fdd68e8a86bdf72036"}, - {file = "cryptography-45.0.4-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:f3fe7a5ae34d5a414957cc7f457e2b92076e72938423ac64d215722f6cf49a9e"}, - {file = "cryptography-45.0.4-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:25eb4d4d3e54595dc8adebc6bbd5623588991d86591a78c2548ffb64797341e2"}, - {file = "cryptography-45.0.4-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:ce1678a2ccbe696cf3af15a75bb72ee008d7ff183c9228592ede9db467e64f1b"}, - {file = "cryptography-45.0.4-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:49fe9155ab32721b9122975e168a6760d8ce4cffe423bcd7ca269ba41b5dfac1"}, - {file = "cryptography-45.0.4-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:2882338b2a6e0bd337052e8b9007ced85c637da19ef9ecaf437744495c8c2999"}, - {file = "cryptography-45.0.4-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:23b9c3ea30c3ed4db59e7b9619272e94891f8a3a5591d0b656a7582631ccf750"}, - {file = "cryptography-45.0.4-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b0a97c927497e3bc36b33987abb99bf17a9a175a19af38a892dc4bbb844d7ee2"}, - {file = "cryptography-45.0.4-cp311-abi3-win32.whl", hash = "sha256:e00a6c10a5c53979d6242f123c0a97cff9f3abed7f064fc412c36dc521b5f257"}, - {file = "cryptography-45.0.4-cp311-abi3-win_amd64.whl", hash = "sha256:817ee05c6c9f7a69a16200f0c90ab26d23a87701e2a284bd15156783e46dbcc8"}, - {file = "cryptography-45.0.4-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:964bcc28d867e0f5491a564b7debb3ffdd8717928d315d12e0d7defa9e43b723"}, - {file = "cryptography-45.0.4-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6a5bf57554e80f75a7db3d4b1dacaa2764611ae166ab42ea9a72bcdb5d577637"}, - {file = "cryptography-45.0.4-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:46cf7088bf91bdc9b26f9c55636492c1cce3e7aaf8041bbf0243f5e5325cfb2d"}, - {file = "cryptography-45.0.4-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:7bedbe4cc930fa4b100fc845ea1ea5788fcd7ae9562e669989c11618ae8d76ee"}, - {file = "cryptography-45.0.4-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:eaa3e28ea2235b33220b949c5a0d6cf79baa80eab2eb5607ca8ab7525331b9ff"}, - {file = "cryptography-45.0.4-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:7ef2dde4fa9408475038fc9aadfc1fb2676b174e68356359632e980c661ec8f6"}, - {file = "cryptography-45.0.4-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:6a3511ae33f09094185d111160fd192c67aa0a2a8d19b54d36e4c78f651dc5ad"}, - {file = "cryptography-45.0.4-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:06509dc70dd71fa56eaa138336244e2fbaf2ac164fc9b5e66828fccfd2b680d6"}, - {file = "cryptography-45.0.4-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:5f31e6b0a5a253f6aa49be67279be4a7e5a4ef259a9f33c69f7d1b1191939872"}, - {file = "cryptography-45.0.4-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:944e9ccf67a9594137f942d5b52c8d238b1b4e46c7a0c2891b7ae6e01e7c80a4"}, - {file = "cryptography-45.0.4-cp37-abi3-win32.whl", hash = "sha256:c22fe01e53dc65edd1945a2e6f0015e887f84ced233acecb64b4daadb32f5c97"}, - {file = "cryptography-45.0.4-cp37-abi3-win_amd64.whl", hash = "sha256:627ba1bc94f6adf0b0a2e35d87020285ead22d9f648c7e75bb64f367375f3b22"}, - {file = "cryptography-45.0.4-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a77c6fb8d76e9c9f99f2f3437c1a4ac287b34eaf40997cfab1e9bd2be175ac39"}, - {file = "cryptography-45.0.4-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:7aad98a25ed8ac917fdd8a9c1e706e5a0956e06c498be1f713b61734333a4507"}, - {file = "cryptography-45.0.4-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:3530382a43a0e524bc931f187fc69ef4c42828cf7d7f592f7f249f602b5a4ab0"}, - {file = "cryptography-45.0.4-pp310-pypy310_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:6b613164cb8425e2f8db5849ffb84892e523bf6d26deb8f9bb76ae86181fa12b"}, - {file = "cryptography-45.0.4-pp310-pypy310_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:96d4819e25bf3b685199b304a0029ce4a3caf98947ce8a066c9137cc78ad2c58"}, - {file = "cryptography-45.0.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b97737a3ffbea79eebb062eb0d67d72307195035332501722a9ca86bab9e3ab2"}, - {file = "cryptography-45.0.4-pp311-pypy311_pp73-macosx_10_9_x86_64.whl", hash = "sha256:4828190fb6c4bcb6ebc6331f01fe66ae838bb3bd58e753b59d4b22eb444b996c"}, - {file = "cryptography-45.0.4-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:03dbff8411206713185b8cebe31bc5c0eb544799a50c09035733716b386e61a4"}, - {file = "cryptography-45.0.4-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:51dfbd4d26172d31150d84c19bbe06c68ea4b7f11bbc7b3a5e146b367c311349"}, - {file = "cryptography-45.0.4-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:0339a692de47084969500ee455e42c58e449461e0ec845a34a6a9b9bf7df7fb8"}, - {file = "cryptography-45.0.4-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:0cf13c77d710131d33e63626bd55ae7c0efb701ebdc2b3a7952b9b23a0412862"}, - {file = "cryptography-45.0.4-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:bbc505d1dc469ac12a0a064214879eac6294038d6b24ae9f71faae1448a9608d"}, - {file = "cryptography-45.0.4.tar.gz", hash = "sha256:7405ade85c83c37682c8fe65554759800a4a8c54b2d96e0f8ad114d31b808d57"}, + {file = "cryptography-45.0.5-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:101ee65078f6dd3e5a028d4f19c07ffa4dd22cce6a20eaa160f8b5219911e7d8"}, + {file = "cryptography-45.0.5-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3a264aae5f7fbb089dbc01e0242d3b67dffe3e6292e1f5182122bdf58e65215d"}, + {file = "cryptography-45.0.5-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e74d30ec9c7cb2f404af331d5b4099a9b322a8a6b25c4632755c8757345baac5"}, + {file = "cryptography-45.0.5-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:3af26738f2db354aafe492fb3869e955b12b2ef2e16908c8b9cb928128d42c57"}, + {file = "cryptography-45.0.5-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e6c00130ed423201c5bc5544c23359141660b07999ad82e34e7bb8f882bb78e0"}, + {file = "cryptography-45.0.5-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:dd420e577921c8c2d31289536c386aaa30140b473835e97f83bc71ea9d2baf2d"}, + {file = "cryptography-45.0.5-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:d05a38884db2ba215218745f0781775806bde4f32e07b135348355fe8e4991d9"}, + {file = "cryptography-45.0.5-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:ad0caded895a00261a5b4aa9af828baede54638754b51955a0ac75576b831b27"}, + {file = "cryptography-45.0.5-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9024beb59aca9d31d36fcdc1604dd9bbeed0a55bface9f1908df19178e2f116e"}, + {file = "cryptography-45.0.5-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:91098f02ca81579c85f66df8a588c78f331ca19089763d733e34ad359f474174"}, + {file = "cryptography-45.0.5-cp311-abi3-win32.whl", hash = "sha256:926c3ea71a6043921050eaa639137e13dbe7b4ab25800932a8498364fc1abec9"}, + {file = "cryptography-45.0.5-cp311-abi3-win_amd64.whl", hash = "sha256:b85980d1e345fe769cfc57c57db2b59cff5464ee0c045d52c0df087e926fbe63"}, + {file = "cryptography-45.0.5-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:f3562c2f23c612f2e4a6964a61d942f891d29ee320edb62ff48ffb99f3de9ae8"}, + {file = "cryptography-45.0.5-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3fcfbefc4a7f332dece7272a88e410f611e79458fab97b5efe14e54fe476f4fd"}, + {file = "cryptography-45.0.5-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:460f8c39ba66af7db0545a8c6f2eabcbc5a5528fc1cf6c3fa9a1e44cec33385e"}, + {file = "cryptography-45.0.5-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:9b4cf6318915dccfe218e69bbec417fdd7c7185aa7aab139a2c0beb7468c89f0"}, + {file = "cryptography-45.0.5-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2089cc8f70a6e454601525e5bf2779e665d7865af002a5dec8d14e561002e135"}, + {file = "cryptography-45.0.5-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:0027d566d65a38497bc37e0dd7c2f8ceda73597d2ac9ba93810204f56f52ebc7"}, + {file = "cryptography-45.0.5-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:be97d3a19c16a9be00edf79dca949c8fa7eff621763666a145f9f9535a5d7f42"}, + {file = "cryptography-45.0.5-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:7760c1c2e1a7084153a0f68fab76e754083b126a47d0117c9ed15e69e2103492"}, + {file = "cryptography-45.0.5-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:6ff8728d8d890b3dda5765276d1bc6fb099252915a2cd3aff960c4c195745dd0"}, + {file = "cryptography-45.0.5-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:7259038202a47fdecee7e62e0fd0b0738b6daa335354396c6ddebdbe1206af2a"}, + {file = "cryptography-45.0.5-cp37-abi3-win32.whl", hash = "sha256:1e1da5accc0c750056c556a93c3e9cb828970206c68867712ca5805e46dc806f"}, + {file = "cryptography-45.0.5-cp37-abi3-win_amd64.whl", hash = "sha256:90cb0a7bb35959f37e23303b7eed0a32280510030daba3f7fdfbb65defde6a97"}, + {file = "cryptography-45.0.5-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:206210d03c1193f4e1ff681d22885181d47efa1ab3018766a7b32a7b3d6e6afd"}, + {file = "cryptography-45.0.5-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c648025b6840fe62e57107e0a25f604db740e728bd67da4f6f060f03017d5097"}, + {file = "cryptography-45.0.5-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:b8fa8b0a35a9982a3c60ec79905ba5bb090fc0b9addcfd3dc2dd04267e45f25e"}, + {file = "cryptography-45.0.5-pp310-pypy310_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:14d96584701a887763384f3c47f0ca7c1cce322aa1c31172680eb596b890ec30"}, + {file = "cryptography-45.0.5-pp310-pypy310_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:57c816dfbd1659a367831baca4b775b2a5b43c003daf52e9d57e1d30bc2e1b0e"}, + {file = "cryptography-45.0.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b9e38e0a83cd51e07f5a48ff9691cae95a79bea28fe4ded168a8e5c6c77e819d"}, + {file = "cryptography-45.0.5-pp311-pypy311_pp73-macosx_10_9_x86_64.whl", hash = "sha256:8c4a6ff8a30e9e3d38ac0539e9a9e02540ab3f827a3394f8852432f6b0ea152e"}, + {file = "cryptography-45.0.5-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:bd4c45986472694e5121084c6ebbd112aa919a25e783b87eb95953c9573906d6"}, + {file = "cryptography-45.0.5-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:982518cd64c54fcada9d7e5cf28eabd3ee76bd03ab18e08a48cad7e8b6f31b18"}, + {file = "cryptography-45.0.5-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:12e55281d993a793b0e883066f590c1ae1e802e3acb67f8b442e721e475e6463"}, + {file = "cryptography-45.0.5-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:5aa1e32983d4443e310f726ee4b071ab7569f58eedfdd65e9675484a4eb67bd1"}, + {file = "cryptography-45.0.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:e357286c1b76403dd384d938f93c46b2b058ed4dfcdce64a770f0537ed3feb6f"}, + {file = "cryptography-45.0.5.tar.gz", hash = "sha256:72e76caa004ab63accdf26023fccd1d087f6d90ec6048ff33ad0445abf7f605a"}, ] [package.dependencies] @@ -668,7 +689,7 @@ nox = ["nox (>=2024.4.15)", "nox[uv] (>=2024.3.2) ; python_full_version >= \"3.8 pep8test = ["check-sdist ; python_full_version >= \"3.8.0\"", "click (>=8.0.1)", "mypy (>=1.4)", "ruff (>=0.3.6)"] sdist = ["build (>=1.0.0)"] ssh = ["bcrypt (>=3.1.5)"] -test = ["certifi (>=2024)", "cryptography-vectors (==45.0.4)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"] +test = ["certifi (>=2024)", "cryptography-vectors (==45.0.5)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"] test-randomorder = ["pytest-randomly"] [[package]] @@ -953,14 +974,14 @@ files = [ [[package]] name = "jsonschema" -version = "4.24.0" +version = "4.25.0" description = "An implementation of JSON Schema validation for Python" optional = false python-versions = ">=3.9" groups = ["charm-libs", "unit"] files = [ - {file = "jsonschema-4.24.0-py3-none-any.whl", hash = "sha256:a462455f19f5faf404a7902952b6f0e3ce868f3ee09a359b05eca6673bd8412d"}, - {file = "jsonschema-4.24.0.tar.gz", hash = "sha256:0b4e8069eb12aedfa881333004bccaec24ecef5a8a6a4b6df142b2cc9599d196"}, + {file = "jsonschema-4.25.0-py3-none-any.whl", hash = "sha256:24c2e8da302de79c8b9382fee3e76b355e44d2a4364bb207159ce10b517bd716"}, + {file = "jsonschema-4.25.0.tar.gz", hash = "sha256:e63acf5c11762c0e6672ffb61482bdf57f0876684d8d249c0fe2d730d48bc55f"}, ] [package.dependencies] @@ -971,7 +992,7 @@ rpds-py = ">=0.7.1" [package.extras] format = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3987", "uri-template", "webcolors (>=1.11)"] -format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=24.6.0)"] +format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "rfc3987-syntax (>=1.1.0)", "uri-template", "webcolors (>=24.6.0)"] [[package]] name = "jsonschema-specifications" @@ -990,13 +1011,14 @@ referencing = ">=0.31.0" [[package]] name = "juju" -version = "3.6.1.2" +version = "3.6.1.3" description = "Python library for Juju" optional = false python-versions = ">=3.8.6" groups = ["integration"] files = [ - {file = "juju-3.6.1.2.tar.gz", hash = "sha256:01ff58b8590b2ea19ace024c124a29d470c9e38431f5a9688ef990eef2b86889"}, + {file = "juju-3.6.1.3-py3-none-any.whl", hash = "sha256:87469500a0a4e6a3976ddf0595e316379868d5cea96e15af2d2d4b94188f76e5"}, + {file = "juju-3.6.1.3.tar.gz", hash = "sha256:2fcf510fa35b387abb382da3a8b2227f38852ae7e9dc1058afb228588e1aec51"}, ] [package.dependencies] @@ -1317,14 +1339,14 @@ files = [ [[package]] name = "ops" -version = "2.23.0" +version = "2.23.1" description = "The Python library behind great charms" optional = false python-versions = ">=3.8" groups = ["main", "charm-libs"] files = [ - {file = "ops-2.23.0-py3-none-any.whl", hash = "sha256:7a42840410e8570acc3a4b498973a5bcd3fd0b12dd06837f57b9379b3acdfac3"}, - {file = "ops-2.23.0.tar.gz", hash = "sha256:3e6c29a8f2119c7b8eaa88c82b5371de236dfcb7a7bf0012a6e2a829f0837fb7"}, + {file = "ops-2.23.1-py3-none-any.whl", hash = "sha256:fdf58163beafd25180c12a4c7efaf1e76e5f8710508a97840c07055bb78b0c77"}, + {file = "ops-2.23.1.tar.gz", hash = "sha256:aecacd67ef7ca913f63f397e0330bfa93d70529a3ef71ed2d99e2bc232564ae3"}, ] [package.dependencies] @@ -1334,8 +1356,8 @@ PyYAML = "==6.*" websocket-client = "==1.*" [package.extras] -testing = ["ops-scenario (==7.23.0)"] -tracing = ["ops-tracing (==2.23.0)"] +testing = ["ops-scenario (==7.23.1)"] +tracing = ["ops-tracing (==2.23.1)"] [[package]] name = "packaging" @@ -1880,14 +1902,14 @@ testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy [[package]] name = "pytest-operator" -version = "0.42.0" -description = "Fixtures for Operators" +version = "0.43.1" +description = "Fixtures for Charmed Operators" optional = false -python-versions = "*" +python-versions = ">=3.8" groups = ["integration"] files = [ - {file = "pytest_operator-0.42.0-py3-none-any.whl", hash = "sha256:29ee3df46b5a47b435f63f7efa2e1433807ba723ac3890f86b88033f79b3e48c"}, - {file = "pytest_operator-0.42.0.tar.gz", hash = "sha256:389afb648dab91eb8f0e224cbe58f05598e850aafc46e589fce1705577309c69"}, + {file = "pytest_operator-0.43.1-py3-none-any.whl", hash = "sha256:092e010fef884ea6166c3f71ec4ca717ed9158cf09de67f28e23cfdd780c46fa"}, + {file = "pytest_operator-0.43.1.tar.gz", hash = "sha256:fd76c7e34c56624176405b47f981de3fe0c3efb71d7875109483cc01f221be99"}, ] [package.dependencies] @@ -2048,129 +2070,156 @@ rsa = ["oauthlib[signedtoken] (>=3.0.0)"] [[package]] name = "rpds-py" -version = "0.25.1" +version = "0.26.0" description = "Python bindings to Rust's persistent data structures (rpds)" optional = false python-versions = ">=3.9" groups = ["charm-libs", "unit"] files = [ - {file = "rpds_py-0.25.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:f4ad628b5174d5315761b67f212774a32f5bad5e61396d38108bd801c0a8f5d9"}, - {file = "rpds_py-0.25.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8c742af695f7525e559c16f1562cf2323db0e3f0fbdcabdf6865b095256b2d40"}, - {file = "rpds_py-0.25.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:605ffe7769e24b1800b4d024d24034405d9404f0bc2f55b6db3362cd34145a6f"}, - {file = "rpds_py-0.25.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ccc6f3ddef93243538be76f8e47045b4aad7a66a212cd3a0f23e34469473d36b"}, - {file = "rpds_py-0.25.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f70316f760174ca04492b5ab01be631a8ae30cadab1d1081035136ba12738cfa"}, - {file = "rpds_py-0.25.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e1dafef8df605fdb46edcc0bf1573dea0d6d7b01ba87f85cd04dc855b2b4479e"}, - {file = "rpds_py-0.25.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0701942049095741a8aeb298a31b203e735d1c61f4423511d2b1a41dcd8a16da"}, - {file = "rpds_py-0.25.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e87798852ae0b37c88babb7f7bbbb3e3fecc562a1c340195b44c7e24d403e380"}, - {file = "rpds_py-0.25.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3bcce0edc1488906c2d4c75c94c70a0417e83920dd4c88fec1078c94843a6ce9"}, - {file = "rpds_py-0.25.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e2f6a2347d3440ae789505693a02836383426249d5293541cd712e07e7aecf54"}, - {file = "rpds_py-0.25.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:4fd52d3455a0aa997734f3835cbc4c9f32571345143960e7d7ebfe7b5fbfa3b2"}, - {file = "rpds_py-0.25.1-cp310-cp310-win32.whl", hash = "sha256:3f0b1798cae2bbbc9b9db44ee068c556d4737911ad53a4e5093d09d04b3bbc24"}, - {file = "rpds_py-0.25.1-cp310-cp310-win_amd64.whl", hash = "sha256:3ebd879ab996537fc510a2be58c59915b5dd63bccb06d1ef514fee787e05984a"}, - {file = "rpds_py-0.25.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:5f048bbf18b1f9120685c6d6bb70cc1a52c8cc11bdd04e643d28d3be0baf666d"}, - {file = "rpds_py-0.25.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4fbb0dbba559959fcb5d0735a0f87cdbca9e95dac87982e9b95c0f8f7ad10255"}, - {file = "rpds_py-0.25.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4ca54b9cf9d80b4016a67a0193ebe0bcf29f6b0a96f09db942087e294d3d4c2"}, - {file = "rpds_py-0.25.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1ee3e26eb83d39b886d2cb6e06ea701bba82ef30a0de044d34626ede51ec98b0"}, - {file = "rpds_py-0.25.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:89706d0683c73a26f76a5315d893c051324d771196ae8b13e6ffa1ffaf5e574f"}, - {file = "rpds_py-0.25.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c2013ee878c76269c7b557a9a9c042335d732e89d482606990b70a839635feb7"}, - {file = "rpds_py-0.25.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45e484db65e5380804afbec784522de84fa95e6bb92ef1bd3325d33d13efaebd"}, - {file = "rpds_py-0.25.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:48d64155d02127c249695abb87d39f0faf410733428d499867606be138161d65"}, - {file = "rpds_py-0.25.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:048893e902132fd6548a2e661fb38bf4896a89eea95ac5816cf443524a85556f"}, - {file = "rpds_py-0.25.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0317177b1e8691ab5879f4f33f4b6dc55ad3b344399e23df2e499de7b10a548d"}, - {file = "rpds_py-0.25.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bffcf57826d77a4151962bf1701374e0fc87f536e56ec46f1abdd6a903354042"}, - {file = "rpds_py-0.25.1-cp311-cp311-win32.whl", hash = "sha256:cda776f1967cb304816173b30994faaf2fd5bcb37e73118a47964a02c348e1bc"}, - {file = "rpds_py-0.25.1-cp311-cp311-win_amd64.whl", hash = "sha256:dc3c1ff0abc91444cd20ec643d0f805df9a3661fcacf9c95000329f3ddf268a4"}, - {file = "rpds_py-0.25.1-cp311-cp311-win_arm64.whl", hash = "sha256:5a3ddb74b0985c4387719fc536faced33cadf2172769540c62e2a94b7b9be1c4"}, - {file = "rpds_py-0.25.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:b5ffe453cde61f73fea9430223c81d29e2fbf412a6073951102146c84e19e34c"}, - {file = "rpds_py-0.25.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:115874ae5e2fdcfc16b2aedc95b5eef4aebe91b28e7e21951eda8a5dc0d3461b"}, - {file = "rpds_py-0.25.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a714bf6e5e81b0e570d01f56e0c89c6375101b8463999ead3a93a5d2a4af91fa"}, - {file = "rpds_py-0.25.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:35634369325906bcd01577da4c19e3b9541a15e99f31e91a02d010816b49bfda"}, - {file = "rpds_py-0.25.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d4cb2b3ddc16710548801c6fcc0cfcdeeff9dafbc983f77265877793f2660309"}, - {file = "rpds_py-0.25.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9ceca1cf097ed77e1a51f1dbc8d174d10cb5931c188a4505ff9f3e119dfe519b"}, - {file = "rpds_py-0.25.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c2cd1a4b0c2b8c5e31ffff50d09f39906fe351389ba143c195566056c13a7ea"}, - {file = "rpds_py-0.25.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1de336a4b164c9188cb23f3703adb74a7623ab32d20090d0e9bf499a2203ad65"}, - {file = "rpds_py-0.25.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9fca84a15333e925dd59ce01da0ffe2ffe0d6e5d29a9eeba2148916d1824948c"}, - {file = "rpds_py-0.25.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:88ec04afe0c59fa64e2f6ea0dd9657e04fc83e38de90f6de201954b4d4eb59bd"}, - {file = "rpds_py-0.25.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a8bd2f19e312ce3e1d2c635618e8a8d8132892bb746a7cf74780a489f0f6cdcb"}, - {file = "rpds_py-0.25.1-cp312-cp312-win32.whl", hash = "sha256:e5e2f7280d8d0d3ef06f3ec1b4fd598d386cc6f0721e54f09109a8132182fbfe"}, - {file = "rpds_py-0.25.1-cp312-cp312-win_amd64.whl", hash = "sha256:db58483f71c5db67d643857404da360dce3573031586034b7d59f245144cc192"}, - {file = "rpds_py-0.25.1-cp312-cp312-win_arm64.whl", hash = "sha256:6d50841c425d16faf3206ddbba44c21aa3310a0cebc3c1cdfc3e3f4f9f6f5728"}, - {file = "rpds_py-0.25.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:659d87430a8c8c704d52d094f5ba6fa72ef13b4d385b7e542a08fc240cb4a559"}, - {file = "rpds_py-0.25.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:68f6f060f0bbdfb0245267da014d3a6da9be127fe3e8cc4a68c6f833f8a23bb1"}, - {file = "rpds_py-0.25.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:083a9513a33e0b92cf6e7a6366036c6bb43ea595332c1ab5c8ae329e4bcc0a9c"}, - {file = "rpds_py-0.25.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:816568614ecb22b18a010c7a12559c19f6fe993526af88e95a76d5a60b8b75fb"}, - {file = "rpds_py-0.25.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3c6564c0947a7f52e4792983f8e6cf9bac140438ebf81f527a21d944f2fd0a40"}, - {file = "rpds_py-0.25.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c4a128527fe415d73cf1f70a9a688d06130d5810be69f3b553bf7b45e8acf79"}, - {file = "rpds_py-0.25.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a49e1d7a4978ed554f095430b89ecc23f42014a50ac385eb0c4d163ce213c325"}, - {file = "rpds_py-0.25.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d74ec9bc0e2feb81d3f16946b005748119c0f52a153f6db6a29e8cd68636f295"}, - {file = "rpds_py-0.25.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3af5b4cc10fa41e5bc64e5c198a1b2d2864337f8fcbb9a67e747e34002ce812b"}, - {file = "rpds_py-0.25.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:79dc317a5f1c51fd9c6a0c4f48209c6b8526d0524a6904fc1076476e79b00f98"}, - {file = "rpds_py-0.25.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1521031351865e0181bc585147624d66b3b00a84109b57fcb7a779c3ec3772cd"}, - {file = "rpds_py-0.25.1-cp313-cp313-win32.whl", hash = "sha256:5d473be2b13600b93a5675d78f59e63b51b1ba2d0476893415dfbb5477e65b31"}, - {file = "rpds_py-0.25.1-cp313-cp313-win_amd64.whl", hash = "sha256:a7b74e92a3b212390bdce1d93da9f6488c3878c1d434c5e751cbc202c5e09500"}, - {file = "rpds_py-0.25.1-cp313-cp313-win_arm64.whl", hash = "sha256:dd326a81afe332ede08eb39ab75b301d5676802cdffd3a8f287a5f0b694dc3f5"}, - {file = "rpds_py-0.25.1-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:a58d1ed49a94d4183483a3ce0af22f20318d4a1434acee255d683ad90bf78129"}, - {file = "rpds_py-0.25.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f251bf23deb8332823aef1da169d5d89fa84c89f67bdfb566c49dea1fccfd50d"}, - {file = "rpds_py-0.25.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8dbd586bfa270c1103ece2109314dd423df1fa3d9719928b5d09e4840cec0d72"}, - {file = "rpds_py-0.25.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6d273f136e912aa101a9274c3145dcbddbe4bac560e77e6d5b3c9f6e0ed06d34"}, - {file = "rpds_py-0.25.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:666fa7b1bd0a3810a7f18f6d3a25ccd8866291fbbc3c9b912b917a6715874bb9"}, - {file = "rpds_py-0.25.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:921954d7fbf3fccc7de8f717799304b14b6d9a45bbeec5a8d7408ccbf531faf5"}, - {file = "rpds_py-0.25.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3d86373ff19ca0441ebeb696ef64cb58b8b5cbacffcda5a0ec2f3911732a194"}, - {file = "rpds_py-0.25.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c8980cde3bb8575e7c956a530f2c217c1d6aac453474bf3ea0f9c89868b531b6"}, - {file = "rpds_py-0.25.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:8eb8c84ecea987a2523e057c0d950bcb3f789696c0499290b8d7b3107a719d78"}, - {file = "rpds_py-0.25.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:e43a005671a9ed5a650f3bc39e4dbccd6d4326b24fb5ea8be5f3a43a6f576c72"}, - {file = "rpds_py-0.25.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:58f77c60956501a4a627749a6dcb78dac522f249dd96b5c9f1c6af29bfacfb66"}, - {file = "rpds_py-0.25.1-cp313-cp313t-win32.whl", hash = "sha256:2cb9e5b5e26fc02c8a4345048cd9998c2aca7c2712bd1b36da0c72ee969a3523"}, - {file = "rpds_py-0.25.1-cp313-cp313t-win_amd64.whl", hash = "sha256:401ca1c4a20cc0510d3435d89c069fe0a9ae2ee6495135ac46bdd49ec0495763"}, - {file = "rpds_py-0.25.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:ce4c8e485a3c59593f1a6f683cf0ea5ab1c1dc94d11eea5619e4fb5228b40fbd"}, - {file = "rpds_py-0.25.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d8222acdb51a22929c3b2ddb236b69c59c72af4019d2cba961e2f9add9b6e634"}, - {file = "rpds_py-0.25.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4593c4eae9b27d22df41cde518b4b9e4464d139e4322e2127daa9b5b981b76be"}, - {file = "rpds_py-0.25.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bd035756830c712b64725a76327ce80e82ed12ebab361d3a1cdc0f51ea21acb0"}, - {file = "rpds_py-0.25.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:114a07e85f32b125404f28f2ed0ba431685151c037a26032b213c882f26eb908"}, - {file = "rpds_py-0.25.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dec21e02e6cc932538b5203d3a8bd6aa1480c98c4914cb88eea064ecdbc6396a"}, - {file = "rpds_py-0.25.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:09eab132f41bf792c7a0ea1578e55df3f3e7f61888e340779b06050a9a3f16e9"}, - {file = "rpds_py-0.25.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c98f126c4fc697b84c423e387337d5b07e4a61e9feac494362a59fd7a2d9ed80"}, - {file = "rpds_py-0.25.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0e6a327af8ebf6baba1c10fadd04964c1965d375d318f4435d5f3f9651550f4a"}, - {file = "rpds_py-0.25.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:bc120d1132cff853ff617754196d0ac0ae63befe7c8498bd67731ba368abe451"}, - {file = "rpds_py-0.25.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:140f61d9bed7839446bdd44852e30195c8e520f81329b4201ceead4d64eb3a9f"}, - {file = "rpds_py-0.25.1-cp39-cp39-win32.whl", hash = "sha256:9c006f3aadeda131b438c3092124bd196b66312f0caa5823ef09585a669cf449"}, - {file = "rpds_py-0.25.1-cp39-cp39-win_amd64.whl", hash = "sha256:a61d0b2c7c9a0ae45732a77844917b427ff16ad5464b4d4f5e4adb955f582890"}, - {file = "rpds_py-0.25.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b24bf3cd93d5b6ecfbedec73b15f143596c88ee249fa98cefa9a9dc9d92c6f28"}, - {file = "rpds_py-0.25.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:0eb90e94f43e5085623932b68840b6f379f26db7b5c2e6bcef3179bd83c9330f"}, - {file = "rpds_py-0.25.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d50e4864498a9ab639d6d8854b25e80642bd362ff104312d9770b05d66e5fb13"}, - {file = "rpds_py-0.25.1-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7c9409b47ba0650544b0bb3c188243b83654dfe55dcc173a86832314e1a6a35d"}, - {file = "rpds_py-0.25.1-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:796ad874c89127c91970652a4ee8b00d56368b7e00d3477f4415fe78164c8000"}, - {file = "rpds_py-0.25.1-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:85608eb70a659bf4c1142b2781083d4b7c0c4e2c90eff11856a9754e965b2540"}, - {file = "rpds_py-0.25.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4feb9211d15d9160bc85fa72fed46432cdc143eb9cf6d5ca377335a921ac37b"}, - {file = "rpds_py-0.25.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ccfa689b9246c48947d31dd9d8b16d89a0ecc8e0e26ea5253068efb6c542b76e"}, - {file = "rpds_py-0.25.1-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:3c5b317ecbd8226887994852e85de562f7177add602514d4ac40f87de3ae45a8"}, - {file = "rpds_py-0.25.1-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:454601988aab2c6e8fd49e7634c65476b2b919647626208e376afcd22019eeb8"}, - {file = "rpds_py-0.25.1-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:1c0c434a53714358532d13539272db75a5ed9df75a4a090a753ac7173ec14e11"}, - {file = "rpds_py-0.25.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:f73ce1512e04fbe2bc97836e89830d6b4314c171587a99688082d090f934d20a"}, - {file = "rpds_py-0.25.1-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ee86d81551ec68a5c25373c5643d343150cc54672b5e9a0cafc93c1870a53954"}, - {file = "rpds_py-0.25.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:89c24300cd4a8e4a51e55c31a8ff3918e6651b241ee8876a42cc2b2a078533ba"}, - {file = "rpds_py-0.25.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:771c16060ff4e79584dc48902a91ba79fd93eade3aa3a12d6d2a4aadaf7d542b"}, - {file = "rpds_py-0.25.1-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:785ffacd0ee61c3e60bdfde93baa6d7c10d86f15655bd706c89da08068dc5038"}, - {file = "rpds_py-0.25.1-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2a40046a529cc15cef88ac5ab589f83f739e2d332cb4d7399072242400ed68c9"}, - {file = "rpds_py-0.25.1-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:85fc223d9c76cabe5d0bff82214459189720dc135db45f9f66aa7cffbf9ff6c1"}, - {file = "rpds_py-0.25.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b0be9965f93c222fb9b4cc254235b3b2b215796c03ef5ee64f995b1b69af0762"}, - {file = "rpds_py-0.25.1-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8378fa4a940f3fb509c081e06cb7f7f2adae8cf46ef258b0e0ed7519facd573e"}, - {file = "rpds_py-0.25.1-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:33358883a4490287e67a2c391dfaea4d9359860281db3292b6886bf0be3d8692"}, - {file = "rpds_py-0.25.1-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:1d1fadd539298e70cac2f2cb36f5b8a65f742b9b9f1014dd4ea1f7785e2470bf"}, - {file = "rpds_py-0.25.1-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:9a46c2fb2545e21181445515960006e85d22025bd2fe6db23e76daec6eb689fe"}, - {file = "rpds_py-0.25.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:50f2c501a89c9a5f4e454b126193c5495b9fb441a75b298c60591d8a2eb92e1b"}, - {file = "rpds_py-0.25.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:7d779b325cc8238227c47fbc53964c8cc9a941d5dbae87aa007a1f08f2f77b23"}, - {file = "rpds_py-0.25.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:036ded36bedb727beeabc16dc1dad7cb154b3fa444e936a03b67a86dc6a5066e"}, - {file = "rpds_py-0.25.1-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:245550f5a1ac98504147cba96ffec8fabc22b610742e9150138e5d60774686d7"}, - {file = "rpds_py-0.25.1-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ff7c23ba0a88cb7b104281a99476cccadf29de2a0ef5ce864959a52675b1ca83"}, - {file = "rpds_py-0.25.1-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e37caa8cdb3b7cf24786451a0bdb853f6347b8b92005eeb64225ae1db54d1c2b"}, - {file = "rpds_py-0.25.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f2f48ab00181600ee266a095fe815134eb456163f7d6699f525dee471f312cf"}, - {file = "rpds_py-0.25.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9e5fc7484fa7dce57e25063b0ec9638ff02a908304f861d81ea49273e43838c1"}, - {file = "rpds_py-0.25.1-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:d3c10228d6cf6fe2b63d2e7985e94f6916fa46940df46b70449e9ff9297bd3d1"}, - {file = "rpds_py-0.25.1-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:5d9e40f32745db28c1ef7aad23f6fc458dc1e29945bd6781060f0d15628b8ddf"}, - {file = "rpds_py-0.25.1-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:35a8d1a24b5936b35c5003313bc177403d8bdef0f8b24f28b1c4a255f94ea992"}, - {file = "rpds_py-0.25.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:6099263f526efff9cf3883dfef505518730f7a7a93049b1d90d42e50a22b4793"}, - {file = "rpds_py-0.25.1.tar.gz", hash = "sha256:8960b6dac09b62dac26e75d7e2c4a22efb835d827a7278c34f72b2b84fa160e3"}, + {file = "rpds_py-0.26.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:4c70c70f9169692b36307a95f3d8c0a9fcd79f7b4a383aad5eaa0e9718b79b37"}, + {file = "rpds_py-0.26.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:777c62479d12395bfb932944e61e915741e364c843afc3196b694db3d669fcd0"}, + {file = "rpds_py-0.26.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec671691e72dff75817386aa02d81e708b5a7ec0dec6669ec05213ff6b77e1bd"}, + {file = "rpds_py-0.26.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6a1cb5d6ce81379401bbb7f6dbe3d56de537fb8235979843f0d53bc2e9815a79"}, + {file = "rpds_py-0.26.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4f789e32fa1fb6a7bf890e0124e7b42d1e60d28ebff57fe806719abb75f0e9a3"}, + {file = "rpds_py-0.26.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c55b0a669976cf258afd718de3d9ad1b7d1fe0a91cd1ab36f38b03d4d4aeaaf"}, + {file = "rpds_py-0.26.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c70d9ec912802ecfd6cd390dadb34a9578b04f9bcb8e863d0a7598ba5e9e7ccc"}, + {file = "rpds_py-0.26.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3021933c2cb7def39d927b9862292e0f4c75a13d7de70eb0ab06efed4c508c19"}, + {file = "rpds_py-0.26.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8a7898b6ca3b7d6659e55cdac825a2e58c638cbf335cde41f4619e290dd0ad11"}, + {file = "rpds_py-0.26.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:12bff2ad9447188377f1b2794772f91fe68bb4bbfa5a39d7941fbebdbf8c500f"}, + {file = "rpds_py-0.26.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:191aa858f7d4902e975d4cf2f2d9243816c91e9605070aeb09c0a800d187e323"}, + {file = "rpds_py-0.26.0-cp310-cp310-win32.whl", hash = "sha256:b37a04d9f52cb76b6b78f35109b513f6519efb481d8ca4c321f6a3b9580b3f45"}, + {file = "rpds_py-0.26.0-cp310-cp310-win_amd64.whl", hash = "sha256:38721d4c9edd3eb6670437d8d5e2070063f305bfa2d5aa4278c51cedcd508a84"}, + {file = "rpds_py-0.26.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:9e8cb77286025bdb21be2941d64ac6ca016130bfdcd228739e8ab137eb4406ed"}, + {file = "rpds_py-0.26.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5e09330b21d98adc8ccb2dbb9fc6cb434e8908d4c119aeaa772cb1caab5440a0"}, + {file = "rpds_py-0.26.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c9c1b92b774b2e68d11193dc39620d62fd8ab33f0a3c77ecdabe19c179cdbc1"}, + {file = "rpds_py-0.26.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:824e6d3503ab990d7090768e4dfd9e840837bae057f212ff9f4f05ec6d1975e7"}, + {file = "rpds_py-0.26.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8ad7fd2258228bf288f2331f0a6148ad0186b2e3643055ed0db30990e59817a6"}, + {file = "rpds_py-0.26.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0dc23bbb3e06ec1ea72d515fb572c1fea59695aefbffb106501138762e1e915e"}, + {file = "rpds_py-0.26.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d80bf832ac7b1920ee29a426cdca335f96a2b5caa839811803e999b41ba9030d"}, + {file = "rpds_py-0.26.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0919f38f5542c0a87e7b4afcafab6fd2c15386632d249e9a087498571250abe3"}, + {file = "rpds_py-0.26.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d422b945683e409000c888e384546dbab9009bb92f7c0b456e217988cf316107"}, + {file = "rpds_py-0.26.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:77a7711fa562ba2da1aa757e11024ad6d93bad6ad7ede5afb9af144623e5f76a"}, + {file = "rpds_py-0.26.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:238e8c8610cb7c29460e37184f6799547f7e09e6a9bdbdab4e8edb90986a2318"}, + {file = "rpds_py-0.26.0-cp311-cp311-win32.whl", hash = "sha256:893b022bfbdf26d7bedb083efeea624e8550ca6eb98bf7fea30211ce95b9201a"}, + {file = "rpds_py-0.26.0-cp311-cp311-win_amd64.whl", hash = "sha256:87a5531de9f71aceb8af041d72fc4cab4943648d91875ed56d2e629bef6d4c03"}, + {file = "rpds_py-0.26.0-cp311-cp311-win_arm64.whl", hash = "sha256:de2713f48c1ad57f89ac25b3cb7daed2156d8e822cf0eca9b96a6f990718cc41"}, + {file = "rpds_py-0.26.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:894514d47e012e794f1350f076c427d2347ebf82f9b958d554d12819849a369d"}, + {file = "rpds_py-0.26.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc921b96fa95a097add244da36a1d9e4f3039160d1d30f1b35837bf108c21136"}, + {file = "rpds_py-0.26.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e1157659470aa42a75448b6e943c895be8c70531c43cb78b9ba990778955582"}, + {file = "rpds_py-0.26.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:521ccf56f45bb3a791182dc6b88ae5f8fa079dd705ee42138c76deb1238e554e"}, + {file = "rpds_py-0.26.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9def736773fd56b305c0eef698be5192c77bfa30d55a0e5885f80126c4831a15"}, + {file = "rpds_py-0.26.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cdad4ea3b4513b475e027be79e5a0ceac8ee1c113a1a11e5edc3c30c29f964d8"}, + {file = "rpds_py-0.26.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82b165b07f416bdccf5c84546a484cc8f15137ca38325403864bfdf2b5b72f6a"}, + {file = "rpds_py-0.26.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d04cab0a54b9dba4d278fe955a1390da3cf71f57feb78ddc7cb67cbe0bd30323"}, + {file = "rpds_py-0.26.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:79061ba1a11b6a12743a2b0f72a46aa2758613d454aa6ba4f5a265cc48850158"}, + {file = "rpds_py-0.26.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:f405c93675d8d4c5ac87364bb38d06c988e11028a64b52a47158a355079661f3"}, + {file = "rpds_py-0.26.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dafd4c44b74aa4bed4b250f1aed165b8ef5de743bcca3b88fc9619b6087093d2"}, + {file = "rpds_py-0.26.0-cp312-cp312-win32.whl", hash = "sha256:3da5852aad63fa0c6f836f3359647870e21ea96cf433eb393ffa45263a170d44"}, + {file = "rpds_py-0.26.0-cp312-cp312-win_amd64.whl", hash = "sha256:cf47cfdabc2194a669dcf7a8dbba62e37a04c5041d2125fae0233b720da6f05c"}, + {file = "rpds_py-0.26.0-cp312-cp312-win_arm64.whl", hash = "sha256:20ab1ae4fa534f73647aad289003f1104092890849e0266271351922ed5574f8"}, + {file = "rpds_py-0.26.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:696764a5be111b036256c0b18cd29783fab22154690fc698062fc1b0084b511d"}, + {file = "rpds_py-0.26.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1e6c15d2080a63aaed876e228efe4f814bc7889c63b1e112ad46fdc8b368b9e1"}, + {file = "rpds_py-0.26.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:390e3170babf42462739a93321e657444f0862c6d722a291accc46f9d21ed04e"}, + {file = "rpds_py-0.26.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7da84c2c74c0f5bc97d853d9e17bb83e2dcafcff0dc48286916001cc114379a1"}, + {file = "rpds_py-0.26.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c5fe114a6dd480a510b6d3661d09d67d1622c4bf20660a474507aaee7eeeee9"}, + {file = "rpds_py-0.26.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3100b3090269f3a7ea727b06a6080d4eb7439dca4c0e91a07c5d133bb1727ea7"}, + {file = "rpds_py-0.26.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c03c9b0c64afd0320ae57de4c982801271c0c211aa2d37f3003ff5feb75bb04"}, + {file = "rpds_py-0.26.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5963b72ccd199ade6ee493723d18a3f21ba7d5b957017607f815788cef50eaf1"}, + {file = "rpds_py-0.26.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9da4e873860ad5bab3291438525cae80169daecbfafe5657f7f5fb4d6b3f96b9"}, + {file = "rpds_py-0.26.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:5afaddaa8e8c7f1f7b4c5c725c0070b6eed0228f705b90a1732a48e84350f4e9"}, + {file = "rpds_py-0.26.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4916dc96489616a6f9667e7526af8fa693c0fdb4f3acb0e5d9f4400eb06a47ba"}, + {file = "rpds_py-0.26.0-cp313-cp313-win32.whl", hash = "sha256:2a343f91b17097c546b93f7999976fd6c9d5900617aa848c81d794e062ab302b"}, + {file = "rpds_py-0.26.0-cp313-cp313-win_amd64.whl", hash = "sha256:0a0b60701f2300c81b2ac88a5fb893ccfa408e1c4a555a77f908a2596eb875a5"}, + {file = "rpds_py-0.26.0-cp313-cp313-win_arm64.whl", hash = "sha256:257d011919f133a4746958257f2c75238e3ff54255acd5e3e11f3ff41fd14256"}, + {file = "rpds_py-0.26.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:529c8156d7506fba5740e05da8795688f87119cce330c244519cf706a4a3d618"}, + {file = "rpds_py-0.26.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f53ec51f9d24e9638a40cabb95078ade8c99251945dad8d57bf4aabe86ecee35"}, + {file = "rpds_py-0.26.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab504c4d654e4a29558eaa5bb8cea5fdc1703ea60a8099ffd9c758472cf913f"}, + {file = "rpds_py-0.26.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fd0641abca296bc1a00183fe44f7fced8807ed49d501f188faa642d0e4975b83"}, + {file = "rpds_py-0.26.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:69b312fecc1d017b5327afa81d4da1480f51c68810963a7336d92203dbb3d4f1"}, + {file = "rpds_py-0.26.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c741107203954f6fc34d3066d213d0a0c40f7bb5aafd698fb39888af277c70d8"}, + {file = "rpds_py-0.26.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc3e55a7db08dc9a6ed5fb7103019d2c1a38a349ac41901f9f66d7f95750942f"}, + {file = "rpds_py-0.26.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9e851920caab2dbcae311fd28f4313c6953993893eb5c1bb367ec69d9a39e7ed"}, + {file = "rpds_py-0.26.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:dfbf280da5f876d0b00c81f26bedce274e72a678c28845453885a9b3c22ae632"}, + {file = "rpds_py-0.26.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:1cc81d14ddfa53d7f3906694d35d54d9d3f850ef8e4e99ee68bc0d1e5fed9a9c"}, + {file = "rpds_py-0.26.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dca83c498b4650a91efcf7b88d669b170256bf8017a5db6f3e06c2bf031f57e0"}, + {file = "rpds_py-0.26.0-cp313-cp313t-win32.whl", hash = "sha256:4d11382bcaf12f80b51d790dee295c56a159633a8e81e6323b16e55d81ae37e9"}, + {file = "rpds_py-0.26.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ff110acded3c22c033e637dd8896e411c7d3a11289b2edf041f86663dbc791e9"}, + {file = "rpds_py-0.26.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:da619979df60a940cd434084355c514c25cf8eb4cf9a508510682f6c851a4f7a"}, + {file = "rpds_py-0.26.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ea89a2458a1a75f87caabefe789c87539ea4e43b40f18cff526052e35bbb4fdf"}, + {file = "rpds_py-0.26.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:feac1045b3327a45944e7dcbeb57530339f6b17baff154df51ef8b0da34c8c12"}, + {file = "rpds_py-0.26.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b818a592bd69bfe437ee8368603d4a2d928c34cffcdf77c2e761a759ffd17d20"}, + {file = "rpds_py-0.26.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1a8b0dd8648709b62d9372fc00a57466f5fdeefed666afe3fea5a6c9539a0331"}, + {file = "rpds_py-0.26.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6d3498ad0df07d81112aa6ec6c95a7e7b1ae00929fb73e7ebee0f3faaeabad2f"}, + {file = "rpds_py-0.26.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24a4146ccb15be237fdef10f331c568e1b0e505f8c8c9ed5d67759dac58ac246"}, + {file = "rpds_py-0.26.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a9a63785467b2d73635957d32a4f6e73d5e4df497a16a6392fa066b753e87387"}, + {file = "rpds_py-0.26.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:de4ed93a8c91debfd5a047be327b7cc8b0cc6afe32a716bbbc4aedca9e2a83af"}, + {file = "rpds_py-0.26.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:caf51943715b12af827696ec395bfa68f090a4c1a1d2509eb4e2cb69abbbdb33"}, + {file = "rpds_py-0.26.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:4a59e5bc386de021f56337f757301b337d7ab58baa40174fb150accd480bc953"}, + {file = "rpds_py-0.26.0-cp314-cp314-win32.whl", hash = "sha256:92c8db839367ef16a662478f0a2fe13e15f2227da3c1430a782ad0f6ee009ec9"}, + {file = "rpds_py-0.26.0-cp314-cp314-win_amd64.whl", hash = "sha256:b0afb8cdd034150d4d9f53926226ed27ad15b7f465e93d7468caaf5eafae0d37"}, + {file = "rpds_py-0.26.0-cp314-cp314-win_arm64.whl", hash = "sha256:ca3f059f4ba485d90c8dc75cb5ca897e15325e4e609812ce57f896607c1c0867"}, + {file = "rpds_py-0.26.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:5afea17ab3a126006dc2f293b14ffc7ef3c85336cf451564a0515ed7648033da"}, + {file = "rpds_py-0.26.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:69f0c0a3df7fd3a7eec50a00396104bb9a843ea6d45fcc31c2d5243446ffd7a7"}, + {file = "rpds_py-0.26.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:801a71f70f9813e82d2513c9a96532551fce1e278ec0c64610992c49c04c2dad"}, + {file = "rpds_py-0.26.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:df52098cde6d5e02fa75c1f6244f07971773adb4a26625edd5c18fee906fa84d"}, + {file = "rpds_py-0.26.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9bc596b30f86dc6f0929499c9e574601679d0341a0108c25b9b358a042f51bca"}, + {file = "rpds_py-0.26.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9dfbe56b299cf5875b68eb6f0ebaadc9cac520a1989cac0db0765abfb3709c19"}, + {file = "rpds_py-0.26.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac64f4b2bdb4ea622175c9ab7cf09444e412e22c0e02e906978b3b488af5fde8"}, + {file = "rpds_py-0.26.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:181ef9b6bbf9845a264f9aa45c31836e9f3c1f13be565d0d010e964c661d1e2b"}, + {file = "rpds_py-0.26.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:49028aa684c144ea502a8e847d23aed5e4c2ef7cadfa7d5eaafcb40864844b7a"}, + {file = "rpds_py-0.26.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:e5d524d68a474a9688336045bbf76cb0def88549c1b2ad9dbfec1fb7cfbe9170"}, + {file = "rpds_py-0.26.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c1851f429b822831bd2edcbe0cfd12ee9ea77868f8d3daf267b189371671c80e"}, + {file = "rpds_py-0.26.0-cp314-cp314t-win32.whl", hash = "sha256:7bdb17009696214c3b66bb3590c6d62e14ac5935e53e929bcdbc5a495987a84f"}, + {file = "rpds_py-0.26.0-cp314-cp314t-win_amd64.whl", hash = "sha256:f14440b9573a6f76b4ee4770c13f0b5921f71dde3b6fcb8dabbefd13b7fe05d7"}, + {file = "rpds_py-0.26.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:7a48af25d9b3c15684059d0d1fc0bc30e8eee5ca521030e2bffddcab5be40226"}, + {file = "rpds_py-0.26.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0c71c2f6bf36e61ee5c47b2b9b5d47e4d1baad6426bfed9eea3e858fc6ee8806"}, + {file = "rpds_py-0.26.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d815d48b1804ed7867b539236b6dd62997850ca1c91cad187f2ddb1b7bbef19"}, + {file = "rpds_py-0.26.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:84cfbd4d4d2cdeb2be61a057a258d26b22877266dd905809e94172dff01a42ae"}, + {file = "rpds_py-0.26.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fbaa70553ca116c77717f513e08815aec458e6b69a028d4028d403b3bc84ff37"}, + {file = "rpds_py-0.26.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:39bfea47c375f379d8e87ab4bb9eb2c836e4f2069f0f65731d85e55d74666387"}, + {file = "rpds_py-0.26.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1533b7eb683fb5f38c1d68a3c78f5fdd8f1412fa6b9bf03b40f450785a0ab915"}, + {file = "rpds_py-0.26.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c5ab0ee51f560d179b057555b4f601b7df909ed31312d301b99f8b9fc6028284"}, + {file = "rpds_py-0.26.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:e5162afc9e0d1f9cae3b577d9c29ddbab3505ab39012cb794d94a005825bde21"}, + {file = "rpds_py-0.26.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:43f10b007033f359bc3fa9cd5e6c1e76723f056ffa9a6b5c117cc35720a80292"}, + {file = "rpds_py-0.26.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:e3730a48e5622e598293eee0762b09cff34dd3f271530f47b0894891281f051d"}, + {file = "rpds_py-0.26.0-cp39-cp39-win32.whl", hash = "sha256:4b1f66eb81eab2e0ff5775a3a312e5e2e16bf758f7b06be82fb0d04078c7ac51"}, + {file = "rpds_py-0.26.0-cp39-cp39-win_amd64.whl", hash = "sha256:519067e29f67b5c90e64fb1a6b6e9d2ec0ba28705c51956637bac23a2f4ddae1"}, + {file = "rpds_py-0.26.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3c0909c5234543ada2515c05dc08595b08d621ba919629e94427e8e03539c958"}, + {file = "rpds_py-0.26.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:c1fb0cda2abcc0ac62f64e2ea4b4e64c57dfd6b885e693095460c61bde7bb18e"}, + {file = "rpds_py-0.26.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84d142d2d6cf9b31c12aa4878d82ed3b2324226270b89b676ac62ccd7df52d08"}, + {file = "rpds_py-0.26.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a547e21c5610b7e9093d870be50682a6a6cf180d6da0f42c47c306073bfdbbf6"}, + {file = "rpds_py-0.26.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:35e9a70a0f335371275cdcd08bc5b8051ac494dd58bff3bbfb421038220dc871"}, + {file = "rpds_py-0.26.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0dfa6115c6def37905344d56fb54c03afc49104e2ca473d5dedec0f6606913b4"}, + {file = "rpds_py-0.26.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:313cfcd6af1a55a286a3c9a25f64af6d0e46cf60bc5798f1db152d97a216ff6f"}, + {file = "rpds_py-0.26.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f7bf2496fa563c046d05e4d232d7b7fd61346e2402052064b773e5c378bf6f73"}, + {file = "rpds_py-0.26.0-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:aa81873e2c8c5aa616ab8e017a481a96742fdf9313c40f14338ca7dbf50cb55f"}, + {file = "rpds_py-0.26.0-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:68ffcf982715f5b5b7686bdd349ff75d422e8f22551000c24b30eaa1b7f7ae84"}, + {file = "rpds_py-0.26.0-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:6188de70e190847bb6db3dc3981cbadff87d27d6fe9b4f0e18726d55795cee9b"}, + {file = "rpds_py-0.26.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:1c962145c7473723df9722ba4c058de12eb5ebedcb4e27e7d902920aa3831ee8"}, + {file = "rpds_py-0.26.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f61a9326f80ca59214d1cceb0a09bb2ece5b2563d4e0cd37bfd5515c28510674"}, + {file = "rpds_py-0.26.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:183f857a53bcf4b1b42ef0f57ca553ab56bdd170e49d8091e96c51c3d69ca696"}, + {file = "rpds_py-0.26.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:941c1cfdf4799d623cf3aa1d326a6b4fdb7a5799ee2687f3516738216d2262fb"}, + {file = "rpds_py-0.26.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:72a8d9564a717ee291f554eeb4bfeafe2309d5ec0aa6c475170bdab0f9ee8e88"}, + {file = "rpds_py-0.26.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:511d15193cbe013619dd05414c35a7dedf2088fcee93c6bbb7c77859765bd4e8"}, + {file = "rpds_py-0.26.0-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aea1f9741b603a8d8fedb0ed5502c2bc0accbc51f43e2ad1337fe7259c2b77a5"}, + {file = "rpds_py-0.26.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4019a9d473c708cf2f16415688ef0b4639e07abaa569d72f74745bbeffafa2c7"}, + {file = "rpds_py-0.26.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:093d63b4b0f52d98ebae33b8c50900d3d67e0666094b1be7a12fffd7f65de74b"}, + {file = "rpds_py-0.26.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:2abe21d8ba64cded53a2a677e149ceb76dcf44284202d737178afe7ba540c1eb"}, + {file = "rpds_py-0.26.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:4feb7511c29f8442cbbc28149a92093d32e815a28aa2c50d333826ad2a20fdf0"}, + {file = "rpds_py-0.26.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:e99685fc95d386da368013e7fb4269dd39c30d99f812a8372d62f244f662709c"}, + {file = "rpds_py-0.26.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a90a13408a7a856b87be8a9f008fff53c5080eea4e4180f6c2e546e4a972fb5d"}, + {file = "rpds_py-0.26.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:3ac51b65e8dc76cf4949419c54c5528adb24fc721df722fd452e5fbc236f5c40"}, + {file = "rpds_py-0.26.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59b2093224a18c6508d95cfdeba8db9cbfd6f3494e94793b58972933fcee4c6d"}, + {file = "rpds_py-0.26.0-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4f01a5d6444a3258b00dc07b6ea4733e26f8072b788bef750baa37b370266137"}, + {file = "rpds_py-0.26.0-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b6e2c12160c72aeda9d1283e612f68804621f448145a210f1bf1d79151c47090"}, + {file = "rpds_py-0.26.0-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cb28c1f569f8d33b2b5dcd05d0e6ef7005d8639c54c2f0be824f05aedf715255"}, + {file = "rpds_py-0.26.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1766b5724c3f779317d5321664a343c07773c8c5fd1532e4039e6cc7d1a815be"}, + {file = "rpds_py-0.26.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b6d9e5a2ed9c4988c8f9b28b3bc0e3e5b1aaa10c28d210a594ff3a8c02742daf"}, + {file = "rpds_py-0.26.0-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:b5f7a446ddaf6ca0fad9a5535b56fbfc29998bf0e0b450d174bbec0d600e1d72"}, + {file = "rpds_py-0.26.0-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:eed5ac260dd545fbc20da5f4f15e7efe36a55e0e7cf706e4ec005b491a9546a0"}, + {file = "rpds_py-0.26.0-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:582462833ba7cee52e968b0341b85e392ae53d44c0f9af6a5927c80e539a8b67"}, + {file = "rpds_py-0.26.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:69a607203441e07e9a8a529cff1d5b73f6a160f22db1097211e6212a68567d11"}, + {file = "rpds_py-0.26.0.tar.gz", hash = "sha256:20dae58a859b0906f0685642e591056f1e787f3a8b39c8e8749a45dc7d26bdb0"}, ] [[package]] @@ -2190,42 +2239,42 @@ pyasn1 = ">=0.1.3" [[package]] name = "ruff" -version = "0.12.1" +version = "0.12.7" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" groups = ["format"] files = [ - {file = "ruff-0.12.1-py3-none-linux_armv6l.whl", hash = "sha256:6013a46d865111e2edb71ad692fbb8262e6c172587a57c0669332a449384a36b"}, - {file = "ruff-0.12.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b3f75a19e03a4b0757d1412edb7f27cffb0c700365e9d6b60bc1b68d35bc89e0"}, - {file = "ruff-0.12.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:9a256522893cb7e92bb1e1153283927f842dea2e48619c803243dccc8437b8be"}, - {file = "ruff-0.12.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:069052605fe74c765a5b4272eb89880e0ff7a31e6c0dbf8767203c1fbd31c7ff"}, - {file = "ruff-0.12.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a684f125a4fec2d5a6501a466be3841113ba6847827be4573fddf8308b83477d"}, - {file = "ruff-0.12.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bdecdef753bf1e95797593007569d8e1697a54fca843d78f6862f7dc279e23bd"}, - {file = "ruff-0.12.1-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:70d52a058c0e7b88b602f575d23596e89bd7d8196437a4148381a3f73fcd5010"}, - {file = "ruff-0.12.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84d0a69d1e8d716dfeab22d8d5e7c786b73f2106429a933cee51d7b09f861d4e"}, - {file = "ruff-0.12.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6cc32e863adcf9e71690248607ccdf25252eeeab5193768e6873b901fd441fed"}, - {file = "ruff-0.12.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7fd49a4619f90d5afc65cf42e07b6ae98bb454fd5029d03b306bd9e2273d44cc"}, - {file = "ruff-0.12.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:ed5af6aaaea20710e77698e2055b9ff9b3494891e1b24d26c07055459bb717e9"}, - {file = "ruff-0.12.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:801d626de15e6bf988fbe7ce59b303a914ff9c616d5866f8c79eb5012720ae13"}, - {file = "ruff-0.12.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:2be9d32a147f98a1972c1e4df9a6956d612ca5f5578536814372113d09a27a6c"}, - {file = "ruff-0.12.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:49b7ce354eed2a322fbaea80168c902de9504e6e174fd501e9447cad0232f9e6"}, - {file = "ruff-0.12.1-py3-none-win32.whl", hash = "sha256:d973fa626d4c8267848755bd0414211a456e99e125dcab147f24daa9e991a245"}, - {file = "ruff-0.12.1-py3-none-win_amd64.whl", hash = "sha256:9e1123b1c033f77bd2590e4c1fe7e8ea72ef990a85d2484351d408224d603013"}, - {file = "ruff-0.12.1-py3-none-win_arm64.whl", hash = "sha256:78ad09a022c64c13cc6077707f036bab0fac8cd7088772dcd1e5be21c5002efc"}, - {file = "ruff-0.12.1.tar.gz", hash = "sha256:806bbc17f1104fd57451a98a58df35388ee3ab422e029e8f5cf30aa4af2c138c"}, + {file = "ruff-0.12.7-py3-none-linux_armv6l.whl", hash = "sha256:76e4f31529899b8c434c3c1dede98c4483b89590e15fb49f2d46183801565303"}, + {file = "ruff-0.12.7-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:789b7a03e72507c54fb3ba6209e4bb36517b90f1a3569ea17084e3fd295500fb"}, + {file = "ruff-0.12.7-py3-none-macosx_11_0_arm64.whl", hash = "sha256:2e1c2a3b8626339bb6369116e7030a4cf194ea48f49b64bb505732a7fce4f4e3"}, + {file = "ruff-0.12.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32dec41817623d388e645612ec70d5757a6d9c035f3744a52c7b195a57e03860"}, + {file = "ruff-0.12.7-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:47ef751f722053a5df5fa48d412dbb54d41ab9b17875c6840a58ec63ff0c247c"}, + {file = "ruff-0.12.7-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a828a5fc25a3efd3e1ff7b241fd392686c9386f20e5ac90aa9234a5faa12c423"}, + {file = "ruff-0.12.7-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:5726f59b171111fa6a69d82aef48f00b56598b03a22f0f4170664ff4d8298efb"}, + {file = "ruff-0.12.7-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:74e6f5c04c4dd4aba223f4fe6e7104f79e0eebf7d307e4f9b18c18362124bccd"}, + {file = "ruff-0.12.7-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5d0bfe4e77fba61bf2ccadf8cf005d6133e3ce08793bbe870dd1c734f2699a3e"}, + {file = "ruff-0.12.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06bfb01e1623bf7f59ea749a841da56f8f653d641bfd046edee32ede7ff6c606"}, + {file = "ruff-0.12.7-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e41df94a957d50083fd09b916d6e89e497246698c3f3d5c681c8b3e7b9bb4ac8"}, + {file = "ruff-0.12.7-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:4000623300563c709458d0ce170c3d0d788c23a058912f28bbadc6f905d67afa"}, + {file = "ruff-0.12.7-py3-none-musllinux_1_2_i686.whl", hash = "sha256:69ffe0e5f9b2cf2b8e289a3f8945b402a1b19eff24ec389f45f23c42a3dd6fb5"}, + {file = "ruff-0.12.7-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:a07a5c8ffa2611a52732bdc67bf88e243abd84fe2d7f6daef3826b59abbfeda4"}, + {file = "ruff-0.12.7-py3-none-win32.whl", hash = "sha256:c928f1b2ec59fb77dfdf70e0419408898b63998789cc98197e15f560b9e77f77"}, + {file = "ruff-0.12.7-py3-none-win_amd64.whl", hash = "sha256:9c18f3d707ee9edf89da76131956aba1270c6348bfee8f6c647de841eac7194f"}, + {file = "ruff-0.12.7-py3-none-win_arm64.whl", hash = "sha256:dfce05101dbd11833a0776716d5d1578641b7fddb537fe7fa956ab85d1769b69"}, + {file = "ruff-0.12.7.tar.gz", hash = "sha256:1fc3193f238bc2d7968772c82831a4ff69252f673be371fb49663f0068b7ec71"}, ] [[package]] name = "s3transfer" -version = "0.13.0" +version = "0.13.1" description = "An Amazon S3 Transfer Manager" optional = false python-versions = ">=3.9" groups = ["main", "integration"] files = [ - {file = "s3transfer-0.13.0-py3-none-any.whl", hash = "sha256:0148ef34d6dd964d0d8cf4311b2b21c474693e57c2e069ec708ce043d2b527be"}, - {file = "s3transfer-0.13.0.tar.gz", hash = "sha256:f5e6db74eb7776a37208001113ea7aa97695368242b364d73e91c981ac522177"}, + {file = "s3transfer-0.13.1-py3-none-any.whl", hash = "sha256:a981aa7429be23fe6dfc13e80e4020057cbab622b08c0315288758d67cabc724"}, + {file = "s3transfer-0.13.1.tar.gz", hash = "sha256:c3fdba22ba1bd367922f27ec8032d6a1cf5f10c934fb5d68cf60fd5a23d936cf"}, ] [package.dependencies] @@ -2355,14 +2404,14 @@ test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0, [[package]] name = "typing-extensions" -version = "4.14.0" +version = "4.14.1" description = "Backported and Experimental Type Hints for Python 3.9+" optional = false python-versions = ">=3.9" groups = ["main", "charm-libs", "integration", "unit"] files = [ - {file = "typing_extensions-4.14.0-py3-none-any.whl", hash = "sha256:a1514509136dd0b477638fc68d6a91497af5076466ad0fa6c338e44e359944af"}, - {file = "typing_extensions-4.14.0.tar.gz", hash = "sha256:8676b788e32f02ab42d9e7c61324048ae4c6d844a399eebace3d4979d75ceef4"}, + {file = "typing_extensions-4.14.1-py3-none-any.whl", hash = "sha256:d1e1e3b58374dc93031d6eda2420a48ea44a36c2b4766a4fdeb3710755731d76"}, + {file = "typing_extensions-4.14.1.tar.gz", hash = "sha256:38b39f4aeeab64884ce9f74c94263ef78f3c22467c8724005483154c26648d36"}, ] markers = {unit = "python_version < \"3.13\""} @@ -2620,4 +2669,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = "^3.10" -content-hash = "0b3f1bbe43e1ca66207dd2f4093f05657bda68ac5508be815e043130e1055370" +content-hash = "197d41501bbfad15511a26e1ddd0608cc856972b4038d52c458dfadbc6ecde83" diff --git a/pyproject.toml b/pyproject.toml index c63378b64e..a1154f8dd2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,8 +7,8 @@ requires-poetry = ">=2.0.0" [tool.poetry.dependencies] python = "^3.10" -ops = "^2.23.0" -boto3 = "^1.39.0" +ops = "^2.23.1" +boto3 = "^1.39.17" pgconnstr = "^1.0.1" requests = "^2.32.4" tenacity = "^9.1.2" @@ -40,7 +40,7 @@ opentelemetry-exporter-otlp-proto-http = "1.21.0" optional = true [tool.poetry.group.format.dependencies] -ruff = "^0.12.1" +ruff = "^0.12.7" [tool.poetry.group.lint] optional = true @@ -52,26 +52,26 @@ codespell = "^2.4.1" optional = true [tool.poetry.group.unit.dependencies] -coverage = {extras = ["toml"], version = "^7.9.1"} +coverage = {extras = ["toml"], version = "^7.10.1"} pytest = "^8.4.1" pytest-asyncio = "*" parameterized = "^0.9.0" -jsonschema = "^4.24.0" +jsonschema = "^4.25.0" [tool.poetry.group.integration] optional = true [tool.poetry.group.integration.dependencies] pytest = "^8.4.1" -pytest-operator = "^0.42.0" +pytest-operator = "^0.43.1" # renovate caret doesn't work: https://github.com/renovatebot/renovate/issues/26940 -juju = "<=3.6.1.2" +juju = "<=3.6.1.3" boto3 = "*" tenacity = "*" landscape-api-py3 = "^0.9.0" mailmanclient = "^3.3.5" psycopg2-binary = "^2.9.10" -allure-pytest = "^2.14.3" +allure-pytest = "^2.15.0" allure-pytest-default-results = "^0.1.3" # Testing tools configuration From 834101f53944c86b15812a5cd5abcdba213af3b3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 1 Aug 2025 13:47:40 +0300 Subject: [PATCH 068/112] Migrate config .github/renovate.json5 (#1074) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/renovate.json5 | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/renovate.json5 b/.github/renovate.json5 index c69f3357cb..24750054eb 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -6,7 +6,10 @@ reviewers: [ 'team:data-postgresql', ], - "baseBranches": ["main", "/^*\\/edge$/"], + baseBranchPatterns: [ + 'main', + '/^*\\/edge$/', + ], packageRules: [ { matchPackageNames: [ @@ -15,6 +18,5 @@ allowedVersions: '<2.0.0', }, ], - customManagers: [ - ], + customManagers: [], } From 3fa4c66f3c85c74331bf4905c801f1009f1cb6f2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 2 Aug 2025 15:05:19 +0300 Subject: [PATCH 069/112] Update charmcraft.yaml build tools (#1010) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- charmcraft.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/charmcraft.yaml b/charmcraft.yaml index 60ea2be8ea..fddccfe8c1 100644 --- a/charmcraft.yaml +++ b/charmcraft.yaml @@ -24,10 +24,10 @@ parts: # Use environment variable instead of `--break-system-packages` to avoid failing on older # versions of pip that do not recognize `--break-system-packages` # `--user` needed (in addition to `--break-system-packages`) for Ubuntu >=24.04 - PIP_BREAK_SYSTEM_PACKAGES=true python3 -m pip install --user --upgrade pip==25.1.1 # renovate: charmcraft-pip-latest + PIP_BREAK_SYSTEM_PACKAGES=true python3 -m pip install --user --upgrade pip==25.2 # renovate: charmcraft-pip-latest # Use uv to install poetry so that a newer version of Python can be installed if needed by poetry - curl --proto '=https' --tlsv1.2 -LsSf https://github.com/astral-sh/uv/releases/download/0.7.14/uv-installer.sh | sh # renovate: charmcraft-uv-latest + curl --proto '=https' --tlsv1.2 -LsSf https://github.com/astral-sh/uv/releases/download/0.8.4/uv-installer.sh | sh # renovate: charmcraft-uv-latest # poetry 2.0.0 requires Python >=3.9 if ! "$HOME/.local/bin/uv" python find '>=3.9' then @@ -75,7 +75,7 @@ parts: # rpds-py (Python package) >=0.19.0 requires rustc >=1.76, which is not available in the # Ubuntu 22.04 archive. Install rustc and cargo using rustup instead of the Ubuntu archive rustup set profile minimal - rustup default 1.87.0 # renovate: charmcraft-rust-latest + rustup default 1.88.0 # renovate: charmcraft-rust-latest craftctl default # Include requirements.txt in *.charm artifact for easier debugging From 9d270e60215d3a5237f24f37d5b40d2ace44d31b Mon Sep 17 00:00:00 2001 From: Marcelo Henrique Neppel Date: Mon, 4 Aug 2025 12:58:36 -0300 Subject: [PATCH 070/112] [DPE-7871] Reorder map logic (#1075) * Reorder map logic Signed-off-by: Marcelo Henrique Neppel * Remove unneeded check Signed-off-by: Marcelo Henrique Neppel --------- Signed-off-by: Marcelo Henrique Neppel --- src/charm.py | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/charm.py b/src/charm.py index f48c38d886..2eb31eb3e1 100755 --- a/src/charm.py +++ b/src/charm.py @@ -2158,9 +2158,21 @@ def client_relations(self) -> list[Relation]: @property def relations_user_databases_map(self) -> dict: """Returns a user->databases map for all relations.""" - if not self.is_cluster_initialised or not self._patroni.member_started: - return {USER: "all", REPLICATION_USER: "all", REWIND_USER: "all"} user_database_map = {} + # Copy relations users directly instead of waiting for them to be created + for relation in self.model.relations[self.postgresql_client_relation.relation_name]: + user = f"relation-{relation.id}" + if database := self.postgresql_client_relation.database_provides.fetch_relation_field( + relation.id, "database" + ): + user_database_map[user] = database + if not self.is_cluster_initialised or not self._patroni.member_started: + user_database_map.update({ + USER: "all", + REPLICATION_USER: "all", + REWIND_USER: "all", + }) + return user_database_map try: for user in sorted( self.postgresql.list_users_from_relation(current_host=self.is_connectivity_enabled) @@ -2194,17 +2206,6 @@ def relations_user_databases_map(self) -> dict: REPLICATION_USER: "all", REWIND_USER: "all", }) - - # Copy relations users directly instead of waiting for them to be created - for relation in self.model.relations[self.postgresql_client_relation.relation_name]: - user = f"relation-{relation.id}" - if user not in user_database_map and ( - database - := self.postgresql_client_relation.database_provides.fetch_relation_field( - relation.id, "database" - ) - ): - user_database_map[user] = database return user_database_map except PostgreSQLListUsersError: logger.debug("relations_user_databases_map: Unable to get users") From 3dae0b82c180dc175e0a46f445a1d24e4f563f83 Mon Sep 17 00:00:00 2001 From: Dragomir Penev <6687393+dragomirp@users.noreply.github.com> Date: Tue, 5 Aug 2025 03:58:46 +0300 Subject: [PATCH 071/112] [DPE-7594] Add custom users to pg_hba filter (#1073) * Add custom users to pg_hba filter * Fix unit test --- src/charm.py | 13 ++++++++++--- tests/unit/test_charm.py | 2 +- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/charm.py b/src/charm.py index 2eb31eb3e1..b9d2ff8aa2 100755 --- a/src/charm.py +++ b/src/charm.py @@ -2174,9 +2174,16 @@ def relations_user_databases_map(self) -> dict: }) return user_database_map try: - for user in sorted( - self.postgresql.list_users_from_relation(current_host=self.is_connectivity_enabled) - ): + for user in self.postgresql.list_users(current_host=self.is_connectivity_enabled): + if user in ( + "backup", + "monitoring", + "operator", + "postgres", + "replication", + "rewind", + ): + continue user_database_map[user] = ",".join( sorted( self.postgresql.list_accessible_databases_for_user( diff --git a/tests/unit/test_charm.py b/tests/unit/test_charm.py index 20417dfb91..84b5d53569 100644 --- a/tests/unit/test_charm.py +++ b/tests/unit/test_charm.py @@ -2958,7 +2958,7 @@ def test_relations_user_databases_map(harness): assert harness.charm.relations_user_databases_map == {} # Test when there are relation users in the database. - _postgresql.list_users_from_relation.return_value = {"user1", "user2"} + _postgresql.list_users.return_value = ["user1", "user2"] _postgresql.list_accessible_databases_for_user.side_effect = [{"db1", "db2"}, {"db3"}] assert harness.charm.relations_user_databases_map == {"user1": "db1,db2", "user2": "db3"} From 848d15b2d2bd877faa0bc3460037c68b476c3a41 Mon Sep 17 00:00:00 2001 From: Gere_X <52193900+Gere321123@users.noreply.github.com> Date: Tue, 5 Aug 2025 16:19:04 +0200 Subject: [PATCH 072/112] Tests for async replication.py (#1033) * def test_can_promote_cluster(): * test_handle_database_start * _on_async_relation_changed * test_on_secret_changed first if * change a lit bit * add tests for stop database function * still need some upgrades * add this * add learning * test__configure_primary_cluster * clean up * we don't need import application * start test__on_async_relation_departed * format * done test__on_async_relation_departed * test_on_async_relation_joined * test_on_create_replication * test_promote_to_primary * add test * test_wait_for_standby_leader * formatize * formatize 2.0 * test_get_partner_addresses * test_handle_replication_change * test_handle_forceful_promotion * add tests * test_on_async_relation_broken * formatize * finishing * need some help * date * add aplications * format * promote_standby_cluster is none * add unit name --------- Co-authored-by: Dragomir Penev --- tests/unit/test_async_replication.py | 871 +++++++++++++++++++++++++++ 1 file changed, 871 insertions(+) create mode 100644 tests/unit/test_async_replication.py diff --git a/tests/unit/test_async_replication.py b/tests/unit/test_async_replication.py new file mode 100644 index 0000000000..0174a0080d --- /dev/null +++ b/tests/unit/test_async_replication.py @@ -0,0 +1,871 @@ +# Copyright 2025 Canonical Ltd. +# See LICENSE file for licensing details. + +from unittest.mock import MagicMock, PropertyMock, patch + +import pytest +from ops import Application +from ops.model import WaitingStatus +from tenacity import RetryError + +from src.relations.async_replication import ( + READ_ONLY_MODE_BLOCKING_MESSAGE, + REPLICATION_CONSUMER_RELATION, + NotReadyError, + PostgreSQLAsyncReplication, + StandbyClusterAlreadyPromotedError, +) + + +def create_mock_unit(name="unit"): + unit = MagicMock() + unit.name = name + return unit + + +def test_can_promote_cluster(): + # 1. Test when cluster is not initialized + mock_charm = MagicMock() + mock_event = MagicMock() + type(mock_charm).is_cluster_initialised = PropertyMock(return_value=False) + + relation = PostgreSQLAsyncReplication(mock_charm) + + assert relation._can_promote_cluster(mock_event) is False + mock_event.fail.assert_called_with("Cluster not initialised yet.") + + # 2. Test when cluster is initialized but no relation exists + mock_charm = MagicMock() + mock_event = MagicMock() + type(mock_charm).is_cluster_initialised = PropertyMock(return_value=True) + + mock_peers_data = MagicMock() + mock_peers_data.update = MagicMock() + + with patch.multiple( + PostgreSQLAsyncReplication, + _relation=None, + _get_primary_cluster=MagicMock(), + _set_app_status=MagicMock(), + _handle_forceful_promotion=MagicMock(return_value=False), + ): + mock_charm._patroni = MagicMock() + mock_charm._patroni.get_standby_leader.return_value = "postgresql/1" + mock_charm._patroni.promote_standby_cluster.return_value = None + mock_charm.app.status.message = READ_ONLY_MODE_BLOCKING_MESSAGE + mock_charm._peers = MagicMock() + mock_charm._peers.data = {mock_charm.app: mock_peers_data} + mock_charm._set_primary_status_message = MagicMock() + + relation = PostgreSQLAsyncReplication(mock_charm) + assert relation._can_promote_cluster(mock_event) is False + + mock_peers_data.update.assert_called_once_with({"promoted-cluster-counter": ""}) + relation._set_app_status.assert_called_once() + mock_charm._set_primary_status_message.assert_called_once() + + # 2b. Test when standby leader exists but promotion fails + mock_charm._patroni.promote_standby_cluster.side_effect = ( + StandbyClusterAlreadyPromotedError("Already promoted") + ) + relation = PostgreSQLAsyncReplication(mock_charm) + assert relation._can_promote_cluster(mock_event) is False + mock_event.fail.assert_called_with("Already promoted") + + # 2c. Test when no standby leader exists + mock_charm._patroni.get_standby_leader.return_value = None + relation = PostgreSQLAsyncReplication(mock_charm) + assert relation._can_promote_cluster(mock_event) is False + mock_event.fail.assert_called_with("No relation and no standby leader found.") + + # 3. Test normal case with relation exists + mock_charm = MagicMock() + mock_event = MagicMock() + type(mock_charm).is_cluster_initialised = PropertyMock(return_value=True) + + with ( + patch.object(PostgreSQLAsyncReplication, "_get_primary_cluster") as mock_get_primary, + patch.object( + PostgreSQLAsyncReplication, "_relation", new_callable=PropertyMock + ) as mock_relation, + patch.object(PostgreSQLAsyncReplication, "_handle_forceful_promotion", return_value=True), + ): + mock_relation.return_value = MagicMock() + mock_get_primary.return_value = (MagicMock(), "1") + relation = PostgreSQLAsyncReplication(mock_charm) + assert relation._can_promote_cluster(mock_event) is True + + # 4. + mock_app = MagicMock() + mock_charm.app = mock_app + + with patch.object(PostgreSQLAsyncReplication, "_get_primary_cluster") as mock_get_primary: + mock_get_primary.return_value = mock_app + + relation = PostgreSQLAsyncReplication(mock_charm) + result = relation._can_promote_cluster(mock_event) + + assert result is False + mock_event.fail.assert_called_with("This cluster is already the primary cluster.") + + +def test_handle_database_start(): + # 1. Test when database is started (member_started = True) and all units ready + mock_charm = MagicMock() + mock_event = MagicMock() + mock_charm._patroni.member_started = True + mock_charm.unit.is_leader.return_value = True + + mock_unit1 = create_mock_unit() + mock_unit2 = create_mock_unit() + mock_charm.unit = create_mock_unit() + mock_charm.app = MagicMock() + + mock_peers_data = { + mock_charm.unit: MagicMock(), + mock_unit1: MagicMock(), + mock_unit2: MagicMock(), + mock_charm.app: MagicMock(), + } + mock_charm._peers = MagicMock() + mock_charm._peers.data = mock_peers_data + mock_charm._peers.units = [mock_unit1, mock_unit2] + + with ( + patch.object( + PostgreSQLAsyncReplication, + "_get_highest_promoted_cluster_counter_value", + return_value="1", + ), + patch.object( + PostgreSQLAsyncReplication, "_is_following_promoted_cluster", return_value=False + ), + ): + for unit in [mock_unit1, mock_unit2, mock_charm.unit]: + mock_peers_data[unit].get.return_value = "1" + + relation = PostgreSQLAsyncReplication(mock_charm) + relation._handle_database_start(mock_event) + + mock_peers_data[mock_charm.unit].update.assert_any_call({"stopped": ""}) + mock_peers_data[mock_charm.unit].update.assert_any_call({ + "unit-promoted-cluster-counter": "1" + }) + mock_charm.update_config.assert_called_once() + mock_peers_data[mock_charm.app].update.assert_called_once_with({ + "cluster_initialised": "True" + }) + mock_charm._set_primary_status_message.assert_called_once() + + # 2. Test when not all units are ready (leader case) + mock_charm = MagicMock() + mock_event = MagicMock() + mock_charm._patroni.member_started = True + mock_charm.unit.is_leader.return_value = True + + mock_unit1 = create_mock_unit() + mock_unit2 = create_mock_unit() + mock_charm.unit = create_mock_unit() + mock_charm.app = MagicMock() + + mock_peers_data = { + mock_charm.unit: MagicMock(), + mock_unit1: MagicMock(), + mock_unit2: MagicMock(), + mock_charm.app: MagicMock(), + } + mock_charm._peers = MagicMock() + mock_charm._peers.data = mock_peers_data + mock_charm._peers.units = [mock_unit1, mock_unit2] + + with ( + patch.object( + PostgreSQLAsyncReplication, + "_get_highest_promoted_cluster_counter_value", + return_value="1", + ), + patch.object( + PostgreSQLAsyncReplication, "_is_following_promoted_cluster", return_value=True + ), + ): + mock_peers_data[mock_charm.unit].get.return_value = "1" + mock_peers_data[mock_unit1].get.return_value = "1" + mock_peers_data[mock_unit2].get.return_value = "0" + + relation = PostgreSQLAsyncReplication(mock_charm) + relation._handle_database_start(mock_event) + + assert isinstance(mock_charm.unit.status, WaitingStatus) + mock_event.defer.assert_called_once() + + # 3. Test when database is not started (non-leader case) + mock_charm = MagicMock() + mock_event = MagicMock() + mock_charm._patroni.member_started = False + mock_charm.unit.is_leader.return_value = False + + with ( + patch.object(PostgreSQLAsyncReplication, "_get_highest_promoted_cluster_counter_value"), + patch("src.relations.async_replication.contextlib.suppress") as mock_suppress, + ): + mock_suppress.return_value.__enter__.return_value = None + mock_charm._patroni.reload_patroni_configuration.side_effect = NotReadyError() + + relation = PostgreSQLAsyncReplication(mock_charm) + relation._handle_database_start(mock_event) + + mock_charm._patroni.reload_patroni_configuration.assert_called_once() + assert isinstance(mock_charm.unit.status, WaitingStatus) + mock_event.defer.assert_called_once() + + # 4. Test when database is starting (leader case) + mock_charm = MagicMock() + mock_event = MagicMock() + mock_charm._patroni.member_started = False + mock_charm.unit.is_leader.return_value = True + + relation = PostgreSQLAsyncReplication(mock_charm) + relation._handle_database_start(mock_event) + + # Verify waiting status and deferral + assert isinstance(mock_charm.unit.status, WaitingStatus) + mock_event.defer.assert_called_once() + + +def test_on_async_relation_changed(): + mock_charm = MagicMock() + mock_event = MagicMock() + mock_charm.unit.is_leader.return_value = True + mock_charm.unit = create_mock_unit("leader") + mock_charm.app = MagicMock() + mock_unit1 = create_mock_unit("unit1") + mock_unit2 = create_mock_unit("unit2") + mock_charm._peers.units = [mock_unit1, mock_unit2] + mock_charm._peers.data = { + mock_charm.unit: {"stopped": "1"}, + mock_unit1: {"unit-promoted-cluster-counter": "5"}, + mock_unit2: {"unit-promoted-cluster-counter": "5"}, + mock_charm.app: {"promoted-cluster-counter": "5"}, + } + mock_charm.is_unit_stopped = True + + relation = PostgreSQLAsyncReplication(mock_charm) + + with ( + patch.object(relation, "_get_primary_cluster", return_value=None), + patch.object(relation, "_set_app_status") as mock_status, + ): + relation._on_async_relation_changed(mock_event) + mock_status.assert_called_once() + mock_event.defer.assert_not_called() + + with ( + patch.object(relation, "_get_primary_cluster", return_value="clusterX"), + patch.object(relation, "_configure_primary_cluster", return_value=True), + ): + relation._on_async_relation_changed(mock_event) + mock_event.defer.assert_not_called() + + mock_charm.unit.is_leader.return_value = False + with ( + patch.object(relation, "_get_primary_cluster", return_value="clusterX"), + patch.object(relation, "_configure_primary_cluster", return_value=False), + patch.object(relation, "_is_following_promoted_cluster", return_value=True), + ): + relation._on_async_relation_changed(mock_event) + mock_event.defer.assert_not_called() + + mock_charm.unit.is_leader.return_value = True + mock_charm.is_unit_stopped = False + with ( + patch.object(relation, "_get_primary_cluster", return_value="clusterX"), + patch.object(relation, "_configure_primary_cluster", return_value=False), + patch.object(relation, "_is_following_promoted_cluster", return_value=False), + patch.object(relation, "_stop_database", return_value=True), + patch.object(relation, "_get_highest_promoted_cluster_counter_value", return_value="5"), + ): + relation._on_async_relation_changed(mock_event) + assert isinstance(mock_charm.unit.status, WaitingStatus) + mock_event.defer.assert_called() + + mock_charm.is_unit_stopped = True + with ( + patch.object(relation, "_get_primary_cluster", return_value="clusterX"), + patch.object(relation, "_configure_primary_cluster", return_value=False), + patch.object(relation, "_is_following_promoted_cluster", return_value=False), + patch.object(relation, "_stop_database", return_value=True), + patch.object(relation, "_get_highest_promoted_cluster_counter_value", return_value="5"), + patch.object(relation, "_wait_for_standby_leader", return_value=True), + ): + relation._on_async_relation_changed(mock_event) + + mock_charm._patroni.start_patroni.assert_not_called() + + with ( + patch.object(relation, "_get_primary_cluster", return_value="clusterX"), + patch.object(relation, "_configure_primary_cluster", return_value=False), + patch.object(relation, "_is_following_promoted_cluster", return_value=False), + patch.object(relation, "_stop_database", return_value=True), + patch.object(relation, "_get_highest_promoted_cluster_counter_value", return_value="5"), + patch.object(relation, "_wait_for_standby_leader", return_value=False), + patch.object(mock_charm._patroni, "start_patroni", return_value=True), + patch.object(relation, "_handle_database_start") as mock_handle_start, + ): + relation._on_async_relation_changed(mock_event) + mock_charm.update_config.assert_called_once() + mock_handle_start.assert_called_once_with(mock_event) + + +def test_on_secret_changed(): + # 1. relation is None + mock_charm = MagicMock() + mock_event = MagicMock() + + relation = PostgreSQLAsyncReplication(mock_charm) + + with ( + patch.object( + PostgreSQLAsyncReplication, "_relation", new_callable=PropertyMock, return_value=None + ), + patch("logging.Logger.debug") as mock_debug, + ): + relation._on_secret_changed(mock_event) + + mock_debug.assert_called_once_with("Early exit on_secret_changed: No relation found.") + mock_event.defer.assert_not_called() + + +def test_stop_database(): + mock_charm = MagicMock() + mock_event = MagicMock() + mock_charm.is_unit_stopped = False + mock_charm.unit.is_leader.return_value = False + mock_charm._patroni.stop_patroni.return_value = True + + mock_unit = MagicMock() + mock_app = MagicMock() + mock_charm.unit = mock_unit + mock_charm.app = mock_app + mock_charm._peers.data = {mock_app: {}, mock_unit: {}} + + relation = PostgreSQLAsyncReplication(mock_charm) + + # 1. Test early exit when following promoted cluster + with ( + patch.object( + PostgreSQLAsyncReplication, "_is_following_promoted_cluster", return_value=True + ), + patch("os.path.exists", return_value=True), + ): + result = relation._stop_database(mock_event) + assert result is True + mock_charm._patroni.stop_patroni.assert_not_called() + + # 2. Test non-leader with no data path + mock_charm._patroni.stop_patroni.return_value = True + with ( + patch.object( + PostgreSQLAsyncReplication, "_is_following_promoted_cluster", return_value=False + ), + patch("os.path.exists", return_value=False), + ): + mock_charm.unit.is_leader.return_value = False + result = relation._stop_database(mock_event) + assert result is False + mock_charm._patroni.stop_patroni.assert_not_called() + + # 3. Test leader unit behavior + with ( + patch.object( + PostgreSQLAsyncReplication, "_is_following_promoted_cluster", return_value=False + ), + patch("os.path.exists", return_value=True), + patch.object(PostgreSQLAsyncReplication, "_configure_standby_cluster", return_value=True), + patch.object(PostgreSQLAsyncReplication, "_reinitialise_pgdata"), + patch("shutil.rmtree"), + patch("pathlib.Path") as mock_path, + ): + mock_path_instance = MagicMock() + mock_path.return_value = mock_path_instance + mock_path_instance.exists.return_value = True + mock_path_instance.is_dir.return_value = True + + mock_charm.unit.is_leader.return_value = True + result = relation._stop_database(mock_event) + assert result is True + mock_charm._patroni.stop_patroni.assert_called_once() + assert mock_charm._peers.data[mock_app].get("cluster_initialised") == "" + assert mock_charm._peers.data[mock_unit].get("stopped") == "True" + + +def test__configure_primary_cluster(): + # 1. + mock_charm = MagicMock() + mock_event = MagicMock() + mock_charm.app = MagicMock() + + relation = PostgreSQLAsyncReplication(mock_charm) + + result = relation._configure_primary_cluster(None, mock_event) + assert result is False + + # 2. + mock_charm = MagicMock() + mock_event = MagicMock() + mock_charm.app = MagicMock() + mock_charm.unit.is_leader.return_value = False + mock_charm.update_config = MagicMock() + + relation = PostgreSQLAsyncReplication(mock_charm) + relation.is_primary_cluster = MagicMock(return_value=False) + result = relation._configure_primary_cluster(mock_charm.app, mock_event) + mock_charm.update_config.assert_called_once() + assert result is True + + # 3. + mock_charm = MagicMock() + mock_event = MagicMock() + mock_charm.app = MagicMock() + mock_charm.unit.is_leader.return_value = True + mock_charm.update_config = MagicMock() + mock_charm._patroni.get_standby_leader.return_value = True + mock_charm._patroni.promote_standby_cluster = MagicMock() + + relation = PostgreSQLAsyncReplication(mock_charm) + relation.is_primary_cluster = MagicMock(return_value=True) + + relation._update_primary_cluster_data = MagicMock() + + result = relation._configure_primary_cluster(mock_charm.app, mock_event) + + mock_charm.update_config.assert_called_once() + relation._update_primary_cluster_data.assert_called_once() + mock_charm._patroni.promote_standby_cluster() + assert result is True + + # 4. + mock_charm = MagicMock() + mock_event = MagicMock() + mock_charm.app = MagicMock() + mock_charm.unit.is_leader.return_value = True + mock_charm.update_config = MagicMock() + mock_charm._patroni.get_standby_leader.return_value = None + + relation = PostgreSQLAsyncReplication(mock_charm) + relation.is_primary_cluster = MagicMock(return_value=True) + + relation._update_primary_cluster_data = MagicMock() + + result = relation._configure_primary_cluster(mock_charm.app, mock_event) + + mock_charm.update_config.assert_called_once() + relation._update_primary_cluster_data.assert_called_once() + assert result is True + + +def test__on_async_relation_departed(): + mock_charm = MagicMock() + mock_event = MagicMock() + mock_peers = MagicMock() + mock_unit_data = {} + mock_event.departing_unit = MagicMock() + mock_charm.unit = mock_event.departing_unit + mock_charm._peers = mock_peers + mock_peers.data = {mock_charm.unit: mock_unit_data} + + relation = PostgreSQLAsyncReplication(mock_charm) + + result = relation._on_async_relation_departed(mock_event) + assert result is None + assert mock_unit_data == {"departing": "True"} + + +def test_on_async_relation_joined(): + mock_charm = MagicMock() + mock_event = MagicMock() + mock_peers = MagicMock() + mock_unit_data = {} + + mock_charm._unit_ip = "10.0.0.1" + mock_charm._peers = mock_peers + mock_peers.data = {mock_charm.unit: mock_unit_data} + + relation = PostgreSQLAsyncReplication(mock_charm) + + relation._get_highest_promoted_cluster_counter_value = MagicMock(return_value="1") + + result = relation._on_async_relation_joined(mock_event) + + assert result is None + + assert mock_unit_data == {"unit-promoted-cluster-counter": "1"} + + relation._get_highest_promoted_cluster_counter_value.assert_called_once() + + +def test_on_create_replication(): + # 1. + mock_charm = MagicMock() + mock_event = MagicMock() + relation = PostgreSQLAsyncReplication(mock_charm) + + mock_application = MagicMock(spec=Application) + relation._get_primary_cluster = MagicMock(return_value=mock_application) + + result = relation._on_create_replication(mock_event) + + assert result is None + mock_event.fail.assert_called_once_with("There is already a replication set up.") + + # 2. + mock_charm = MagicMock() + mock_event = MagicMock() + + relation = PostgreSQLAsyncReplication(mock_charm) + + relation._get_primary_cluster = MagicMock(return_value=None) + + mock_relation = MagicMock() + mock_relation.name = REPLICATION_CONSUMER_RELATION + type(relation)._relation = PropertyMock(return_value=mock_relation) + + result = relation._on_create_replication(mock_event) + + assert result is None + mock_event.fail.assert_called_once_with( + "This action must be run in the cluster where the offer was created." + ) + # 3. + mock_charm = MagicMock() + mock_event = MagicMock() + + relation = PostgreSQLAsyncReplication(mock_charm) + + relation._get_primary_cluster = MagicMock(return_value=None) + + relation._handle_replication_change = MagicMock(return_value=True) + + mock_relation = MagicMock() + mock_relation.name = "Something" + type(relation)._relation = PropertyMock(return_value=mock_relation) + + result = relation._on_create_replication(mock_event) + + assert result is None + + # 4. + mock_charm = MagicMock() + mock_event = MagicMock() + + relation = PostgreSQLAsyncReplication(mock_charm) + + relation._get_primary_cluster = MagicMock(return_value=None) + + relation._handle_replication_change = MagicMock(return_value=False) + + mock_relation = MagicMock() + mock_relation.name = "Something" + type(relation)._relation = PropertyMock(return_value=mock_relation) + + result = relation._on_create_replication(mock_event) + + assert result is None + + +def test_promote_to_primary(): + # 1. + mock_charm = MagicMock() + mock_event = MagicMock() + mock_relation = MagicMock() + mock_relation.status = MagicMock() + mock_relation.status.message = "Something" + + relation = PostgreSQLAsyncReplication(mock_charm) + relation._get_primary_cluster = MagicMock(return_value=None) + + type(relation).app = PropertyMock(return_value=mock_relation) + result = relation.promote_to_primary(mock_event) + assert result is None + + mock_event.fail.assert_called_once_with( + "No primary cluster found. Run `create-replication` action in the cluster where the offer was created." + ) + + # 2. + mock_charm = MagicMock() + mock_event = MagicMock() + mock_relation = MagicMock() + mock_app = MagicMock(spec=Application) + mock_relation.status = MagicMock() + mock_relation.status.message = READ_ONLY_MODE_BLOCKING_MESSAGE + + relation = PostgreSQLAsyncReplication(mock_charm) + relation._get_primary_cluster = MagicMock(return_value=None) + + type(relation).app = PropertyMock(return_value=mock_app) + relation._handle_replication_change = MagicMock(return_value=False) + + result = relation.promote_to_primary(mock_event) + + assert result is None + + +def test__configure_standby_cluster(): + mock_charm = MagicMock() + mock_event = MagicMock() + + relation = PostgreSQLAsyncReplication(mock_charm) + relation._relation = MagicMock() + relation._relation.name = REPLICATION_CONSUMER_RELATION + relation._update_internal_secret = MagicMock(return_value=False) + + result = relation._configure_standby_cluster(mock_event) + + assert result is False + + mock_event.defer.assert_called_once() + + # 2. + mock_charm = MagicMock() + mock_event = MagicMock() + + relation = PostgreSQLAsyncReplication(mock_charm) + relation._relation = MagicMock() + relation._relation.name = "something_else" + relation._update_internal_secret = MagicMock(return_value=True) + relation.get_system_identifier = MagicMock(return_value=(None, 2)) + + with pytest.raises(Exception) as exc_info: + relation._configure_standby_cluster(mock_event) + + assert str(exc_info.value) == "2" + + # 3. + mock_charm = MagicMock() + mock_event = MagicMock() + + relation = PostgreSQLAsyncReplication(mock_charm) + relation._relation = MagicMock() + relation._relation.name = "some_relation" + relation._relation.app = "remote-app" + relation._relation.data = {relation._relation.app: {"system-id": "123"}} + + relation._update_internal_secret = MagicMock(return_value=True) + relation.get_system_identifier = MagicMock(return_value=("456", None)) + relation.charm = MagicMock() + relation.charm.app_peer_data = {} + + with patch("subprocess.check_call") as mock_check_call: + result = relation._configure_standby_cluster(mock_event) + + assert result is True + mock_check_call.assert_called_once() + + +def test_wait_for_standby_leader(): + # 1. + mock_charm = MagicMock() + mock_event = MagicMock() + + relation = PostgreSQLAsyncReplication(mock_charm) + + mock_charm._patroni.get_standby_leader.return_value = None + mock_charm.unit.is_leader.return_value = False + mock_charm._patroni.is_member_isolated = True + mock_charm._patroni.restart_patroni = MagicMock() + + result = relation._wait_for_standby_leader(mock_event) + assert result is True + mock_charm._patroni.restart_patroni.assert_called_once() + mock_event.defer.assert_called_once() + + # 2. + mock_charm = MagicMock() + mock_event = MagicMock() + + relation = PostgreSQLAsyncReplication(mock_charm) + + mock_charm._patroni.get_standby_leader.return_value = None + mock_charm.unit.is_leader.return_value = False + mock_charm._patroni.is_member_isolated = False + + result = relation._wait_for_standby_leader(mock_event) + assert result is True + mock_event.defer.assert_called_once() + + # 3. + mock_charm = MagicMock() + mock_event = MagicMock() + + relation = PostgreSQLAsyncReplication(mock_charm) + mock_charm._patroni.get_standby_leader.return_value = None + mock_charm.unit.is_leader.return_value = True + + result = relation._wait_for_standby_leader(mock_event) + assert result is False + + +def test_get_partner_addresses(): + mock_charm = MagicMock() + + mock_charm._peer_members_ips = ["str"] + mock_charm.app = MagicMock() + mock_charm.unit = MagicMock() + mock_charm.unit.is_leader.return_value = True + mock_charm._peers = MagicMock() + mock_charm._peers.data = {mock_charm.unit: {}} + + relation = PostgreSQLAsyncReplication(mock_charm) + relation._get_primary_cluster = MagicMock(return_value=None) + relation._get_highest_promoted_cluster_counter_value = MagicMock(return_value=None) + + result = relation.get_partner_addresses() + + assert result == ["str"] + + +def test_handle_replication_change(): + # 1. + mock_charm = MagicMock() + mock_event = MagicMock() + relation = PostgreSQLAsyncReplication(mock_charm) + relation._can_promote_cluster = MagicMock(return_value=False) + result = relation._handle_replication_change(mock_event) + assert result is False + # 2. + mock_charm = MagicMock() + mock_event = MagicMock() + relation = PostgreSQLAsyncReplication(mock_charm) + relation._can_promote_cluster = MagicMock(return_value=True) + relation.get_system_identifier = MagicMock(return_value=(12345, "some error")) + result = relation._handle_replication_change(mock_event) + assert result is False + + # 3. + mock_charm = MagicMock() + mock_event = MagicMock() + mock_relation = MagicMock() + + mock_unit1 = MagicMock() + mock_unit2 = MagicMock() + mock_relation.units = [mock_unit1, mock_unit2] + mock_relation.data = { + mock_unit1: {"unit-address": "10.0.0.1"}, + mock_unit2: {"unit-address": "10.0.0.2"}, + mock_charm.app: {}, + } + + relation = PostgreSQLAsyncReplication(mock_charm) + relation._relation = mock_relation + relation._can_promote_cluster = MagicMock(return_value=True) + relation.get_system_identifier = MagicMock(return_value=(12345, None)) + relation._get_highest_promoted_cluster_counter_value = MagicMock(return_value="1") + relation._update_primary_cluster_data = MagicMock() + relation._re_emit_async_relation_changed_event = MagicMock() + + result = relation._handle_replication_change(mock_event) + + assert result is True + relation._can_promote_cluster.assert_called_once_with(mock_event) + relation.get_system_identifier.assert_called_once() + relation._get_highest_promoted_cluster_counter_value.assert_called_once() + relation._update_primary_cluster_data.assert_called_once_with(2, 12345) + relation._re_emit_async_relation_changed_event.assert_called_once() + mock_event.fail.assert_not_called() + + +def test_handle_forceful_promotion(): + # 1. + mock_charm = MagicMock() + mock_event = MagicMock() + + mock_event.params.get.return_value = True + relation = PostgreSQLAsyncReplication(mock_charm) + result = relation._handle_forceful_promotion(mock_event) + + assert result is True + # 2. + mock_charm = MagicMock() + mock_event = MagicMock() + + mock_event.params.get.return_value = False + + relation = PostgreSQLAsyncReplication(mock_charm) + + relation._relation = MagicMock() + relation._relation.app = MagicMock() + relation._relation.app.name = "test-app" + + relation.get_all_primary_cluster_endpoints = MagicMock(return_value=[1, 2, 3]) + + mock_charm._patroni.get_primary.side_effect = RetryError("timeout") + + result = relation._handle_forceful_promotion(mock_event) + + mock_event.fail.assert_called_once_with( + "test-app isn't reachable. Pass `force=true` to promote anyway." + ) + assert result is False + # 3. + mock_charm = MagicMock() + mock_event = MagicMock() + + mock_event.params.get.return_value = False + + relation = PostgreSQLAsyncReplication(mock_charm) + + relation._relation = MagicMock() + relation._relation.app = MagicMock() + relation._relation.app.name = "test-app" + + relation.get_all_primary_cluster_endpoints = MagicMock(return_value=[1, 2, 3]) + + mock_charm._patroni.get_primary.side_effect = None + + result = relation._handle_forceful_promotion(mock_event) + + assert result is True + # 4. + mock_charm = MagicMock() + mock_event = MagicMock() + + mock_event.params.get.return_value = False + + relation = PostgreSQLAsyncReplication(mock_charm) + + relation._relation = MagicMock() + relation._relation.app = MagicMock() + relation._relation.app.name = "test-app" + + relation.get_all_primary_cluster_endpoints = MagicMock(return_value=[]) + + mock_charm._patroni.get_primary.side_effect = None + + result = relation._handle_forceful_promotion(mock_event) + + assert result is True + + +def test_on_async_relation_broken(): + # 1. + mock_charm = MagicMock() + mock_event = MagicMock() + mock_charm._peers = True + + relation = PostgreSQLAsyncReplication(mock_charm) + + result = relation._on_async_relation_broken(mock_event) + + assert result is None + # 2. + mock_charm = MagicMock() + mock_charm._peers = MagicMock() + mock_charm.is_unit_departing = False + mock_charm._patroni.get_standby_leader.return_value = None + mock_charm.unit.is_leader.return_value = True + mock_event = MagicMock() + + relation = PostgreSQLAsyncReplication(mock_charm) + relation._on_async_relation_broken(mock_event) + + assert mock_charm.update_config.called From 51fdcfa33d0849eb58ab92838c3a3dc2f9e3b4e7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 6 Aug 2025 01:58:06 +0300 Subject: [PATCH 073/112] Lock file maintenance Python dependencies (#1077) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- poetry.lock | 223 ++++++++++++++++++++++++++----------------------- pyproject.toml | 4 +- 2 files changed, 119 insertions(+), 108 deletions(-) diff --git a/poetry.lock b/poetry.lock index 3b4b3a4ae3..a648e96f07 100644 --- a/poetry.lock +++ b/poetry.lock @@ -233,18 +233,18 @@ typecheck = ["mypy"] [[package]] name = "boto3" -version = "1.39.17" +version = "1.40.2" description = "The AWS SDK for Python" optional = false python-versions = ">=3.9" groups = ["main", "integration"] files = [ - {file = "boto3-1.39.17-py3-none-any.whl", hash = "sha256:6af9f7d6db7b5e72d6869ae22ebad1b0c6602591af2ef5d914b331a055953df5"}, - {file = "boto3-1.39.17.tar.gz", hash = "sha256:a6904a40b1c61f6a1766574b3155ec75a6020399fb570be2b51bf93a2c0a2b3d"}, + {file = "boto3-1.40.2-py3-none-any.whl", hash = "sha256:3d99325ee874190e8f3bfd38823987327c826cdfbab943420851bdb7684d727c"}, + {file = "boto3-1.40.2.tar.gz", hash = "sha256:2dfbc214fdbf94abfd61eec687ea39089d05af43bb00be792c76f3a6c1393f7b"}, ] [package.dependencies] -botocore = ">=1.39.17,<1.40.0" +botocore = ">=1.40.2,<1.41.0" jmespath = ">=0.7.1,<2.0.0" s3transfer = ">=0.13.0,<0.14.0" @@ -253,14 +253,14 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.39.17" +version = "1.40.2" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">=3.9" groups = ["main", "integration"] files = [ - {file = "botocore-1.39.17-py3-none-any.whl", hash = "sha256:41db169e919f821b3ef684794c5e67dd7bb1f5ab905d33729b1d8c27fafe8004"}, - {file = "botocore-1.39.17.tar.gz", hash = "sha256:1a1f0b29dab5d1b10d16f14423c16ac0a3043272f579e9ab0d757753ee9a7d2b"}, + {file = "botocore-1.40.2-py3-none-any.whl", hash = "sha256:a31e6269af05498f8dc1c7f2b3f34448a0f16c79a8601c0389ecddab51b2c2ab"}, + {file = "botocore-1.40.2.tar.gz", hash = "sha256:77c4710bf37b28e897833b5b1f47d6a83e45a29985cd01a560dfdb8b6ad524e5"}, ] [package.dependencies] @@ -285,14 +285,14 @@ files = [ [[package]] name = "certifi" -version = "2025.7.14" +version = "2025.8.3" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.7" groups = ["main", "charm-libs", "integration"] files = [ - {file = "certifi-2025.7.14-py3-none-any.whl", hash = "sha256:6b31f564a415d79ee77df69d757bb49a5bb53bd9f756cbbe24394ffd6fc1f4b2"}, - {file = "certifi-2025.7.14.tar.gz", hash = "sha256:8ea99dbdfaaf2ba2f9bac77b9249ef62ec5218e7c2b2e903378ed5fccf765995"}, + {file = "certifi-2025.8.3-py3-none-any.whl", hash = "sha256:f6c12493cfb1b06ba2ff328595af9350c65d6644968e5d3a2ffd78699af217a5"}, + {file = "certifi-2025.8.3.tar.gz", hash = "sha256:e564105f78ded564e3ae7c923924435e1daa7463faeab5bb932bc53ffae63407"}, ] [[package]] @@ -530,100 +530,100 @@ typing-extensions = "*" [[package]] name = "coverage" -version = "7.10.1" +version = "7.10.2" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.9" groups = ["unit"] files = [ - {file = "coverage-7.10.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1c86eb388bbd609d15560e7cc0eb936c102b6f43f31cf3e58b4fd9afe28e1372"}, - {file = "coverage-7.10.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6b4ba0f488c1bdb6bd9ba81da50715a372119785458831c73428a8566253b86b"}, - {file = "coverage-7.10.1-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:083442ecf97d434f0cb3b3e3676584443182653da08b42e965326ba12d6b5f2a"}, - {file = "coverage-7.10.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c1a40c486041006b135759f59189385da7c66d239bad897c994e18fd1d0c128f"}, - {file = "coverage-7.10.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3beb76e20b28046989300c4ea81bf690df84ee98ade4dc0bbbf774a28eb98440"}, - {file = "coverage-7.10.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:bc265a7945e8d08da28999ad02b544963f813a00f3ed0a7a0ce4165fd77629f8"}, - {file = "coverage-7.10.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:47c91f32ba4ac46f1e224a7ebf3f98b4b24335bad16137737fe71a5961a0665c"}, - {file = "coverage-7.10.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:1a108dd78ed185020f66f131c60078f3fae3f61646c28c8bb4edd3fa121fc7fc"}, - {file = "coverage-7.10.1-cp310-cp310-win32.whl", hash = "sha256:7092cc82382e634075cc0255b0b69cb7cada7c1f249070ace6a95cb0f13548ef"}, - {file = "coverage-7.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:ac0c5bba938879c2fc0bc6c1b47311b5ad1212a9dcb8b40fe2c8110239b7faed"}, - {file = "coverage-7.10.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b45e2f9d5b0b5c1977cb4feb5f594be60eb121106f8900348e29331f553a726f"}, - {file = "coverage-7.10.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3a7a4d74cb0f5e3334f9aa26af7016ddb94fb4bfa11b4a573d8e98ecba8c34f1"}, - {file = "coverage-7.10.1-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d4b0aab55ad60ead26159ff12b538c85fbab731a5e3411c642b46c3525863437"}, - {file = "coverage-7.10.1-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:dcc93488c9ebd229be6ee1f0d9aad90da97b33ad7e2912f5495804d78a3cd6b7"}, - {file = "coverage-7.10.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:aa309df995d020f3438407081b51ff527171cca6772b33cf8f85344b8b4b8770"}, - {file = "coverage-7.10.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cfb8b9d8855c8608f9747602a48ab525b1d320ecf0113994f6df23160af68262"}, - {file = "coverage-7.10.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:320d86da829b012982b414c7cdda65f5d358d63f764e0e4e54b33097646f39a3"}, - {file = "coverage-7.10.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:dc60ddd483c556590da1d9482a4518292eec36dd0e1e8496966759a1f282bcd0"}, - {file = "coverage-7.10.1-cp311-cp311-win32.whl", hash = "sha256:4fcfe294f95b44e4754da5b58be750396f2b1caca8f9a0e78588e3ef85f8b8be"}, - {file = "coverage-7.10.1-cp311-cp311-win_amd64.whl", hash = "sha256:efa23166da3fe2915f8ab452dde40319ac84dc357f635737174a08dbd912980c"}, - {file = "coverage-7.10.1-cp311-cp311-win_arm64.whl", hash = "sha256:d12b15a8c3759e2bb580ffa423ae54be4f184cf23beffcbd641f4fe6e1584293"}, - {file = "coverage-7.10.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6b7dc7f0a75a7eaa4584e5843c873c561b12602439d2351ee28c7478186c4da4"}, - {file = "coverage-7.10.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:607f82389f0ecafc565813aa201a5cade04f897603750028dd660fb01797265e"}, - {file = "coverage-7.10.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:f7da31a1ba31f1c1d4d5044b7c5813878adae1f3af8f4052d679cc493c7328f4"}, - {file = "coverage-7.10.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:51fe93f3fe4f5d8483d51072fddc65e717a175490804e1942c975a68e04bf97a"}, - {file = "coverage-7.10.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3e59d00830da411a1feef6ac828b90bbf74c9b6a8e87b8ca37964925bba76dbe"}, - {file = "coverage-7.10.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:924563481c27941229cb4e16eefacc35da28563e80791b3ddc5597b062a5c386"}, - {file = "coverage-7.10.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:ca79146ee421b259f8131f153102220b84d1a5e6fb9c8aed13b3badfd1796de6"}, - {file = "coverage-7.10.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2b225a06d227f23f386fdc0eab471506d9e644be699424814acc7d114595495f"}, - {file = "coverage-7.10.1-cp312-cp312-win32.whl", hash = "sha256:5ba9a8770effec5baaaab1567be916c87d8eea0c9ad11253722d86874d885eca"}, - {file = "coverage-7.10.1-cp312-cp312-win_amd64.whl", hash = "sha256:9eb245a8d8dd0ad73b4062135a251ec55086fbc2c42e0eb9725a9b553fba18a3"}, - {file = "coverage-7.10.1-cp312-cp312-win_arm64.whl", hash = "sha256:7718060dd4434cc719803a5e526838a5d66e4efa5dc46d2b25c21965a9c6fcc4"}, - {file = "coverage-7.10.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ebb08d0867c5a25dffa4823377292a0ffd7aaafb218b5d4e2e106378b1061e39"}, - {file = "coverage-7.10.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f32a95a83c2e17422f67af922a89422cd24c6fa94041f083dd0bb4f6057d0bc7"}, - {file = "coverage-7.10.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:c4c746d11c8aba4b9f58ca8bfc6fbfd0da4efe7960ae5540d1a1b13655ee8892"}, - {file = "coverage-7.10.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7f39edd52c23e5c7ed94e0e4bf088928029edf86ef10b95413e5ea670c5e92d7"}, - {file = "coverage-7.10.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ab6e19b684981d0cd968906e293d5628e89faacb27977c92f3600b201926b994"}, - {file = "coverage-7.10.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5121d8cf0eacb16133501455d216bb5f99899ae2f52d394fe45d59229e6611d0"}, - {file = "coverage-7.10.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:df1c742ca6f46a6f6cbcaef9ac694dc2cb1260d30a6a2f5c68c5f5bcfee1cfd7"}, - {file = "coverage-7.10.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:40f9a38676f9c073bf4b9194707aa1eb97dca0e22cc3766d83879d72500132c7"}, - {file = "coverage-7.10.1-cp313-cp313-win32.whl", hash = "sha256:2348631f049e884839553b9974f0821d39241c6ffb01a418efce434f7eba0fe7"}, - {file = "coverage-7.10.1-cp313-cp313-win_amd64.whl", hash = "sha256:4072b31361b0d6d23f750c524f694e1a417c1220a30d3ef02741eed28520c48e"}, - {file = "coverage-7.10.1-cp313-cp313-win_arm64.whl", hash = "sha256:3e31dfb8271937cab9425f19259b1b1d1f556790e98eb266009e7a61d337b6d4"}, - {file = "coverage-7.10.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:1c4f679c6b573a5257af6012f167a45be4c749c9925fd44d5178fd641ad8bf72"}, - {file = "coverage-7.10.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:871ebe8143da284bd77b84a9136200bd638be253618765d21a1fce71006d94af"}, - {file = "coverage-7.10.1-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:998c4751dabf7d29b30594af416e4bf5091f11f92a8d88eb1512c7ba136d1ed7"}, - {file = "coverage-7.10.1-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:780f750a25e7749d0af6b3631759c2c14f45de209f3faaa2398312d1c7a22759"}, - {file = "coverage-7.10.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:590bdba9445df4763bdbebc928d8182f094c1f3947a8dc0fc82ef014dbdd8324"}, - {file = "coverage-7.10.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b2df80cb6a2af86d300e70acb82e9b79dab2c1e6971e44b78dbfc1a1e736b53"}, - {file = "coverage-7.10.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:d6a558c2725bfb6337bf57c1cd366c13798bfd3bfc9e3dd1f4a6f6fc95a4605f"}, - {file = "coverage-7.10.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e6150d167f32f2a54690e572e0a4c90296fb000a18e9b26ab81a6489e24e78dd"}, - {file = "coverage-7.10.1-cp313-cp313t-win32.whl", hash = "sha256:d946a0c067aa88be4a593aad1236493313bafaa27e2a2080bfe88db827972f3c"}, - {file = "coverage-7.10.1-cp313-cp313t-win_amd64.whl", hash = "sha256:e37c72eaccdd5ed1130c67a92ad38f5b2af66eeff7b0abe29534225db2ef7b18"}, - {file = "coverage-7.10.1-cp313-cp313t-win_arm64.whl", hash = "sha256:89ec0ffc215c590c732918c95cd02b55c7d0f569d76b90bb1a5e78aa340618e4"}, - {file = "coverage-7.10.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:166d89c57e877e93d8827dac32cedae6b0277ca684c6511497311249f35a280c"}, - {file = "coverage-7.10.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:bed4a2341b33cd1a7d9ffc47df4a78ee61d3416d43b4adc9e18b7d266650b83e"}, - {file = "coverage-7.10.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:ddca1e4f5f4c67980533df01430184c19b5359900e080248bbf4ed6789584d8b"}, - {file = "coverage-7.10.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:37b69226001d8b7de7126cad7366b0778d36777e4d788c66991455ba817c5b41"}, - {file = "coverage-7.10.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b2f22102197bcb1722691296f9e589f02b616f874e54a209284dd7b9294b0b7f"}, - {file = "coverage-7.10.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:1e0c768b0f9ac5839dac5cf88992a4bb459e488ee8a1f8489af4cb33b1af00f1"}, - {file = "coverage-7.10.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:991196702d5e0b120a8fef2664e1b9c333a81d36d5f6bcf6b225c0cf8b0451a2"}, - {file = "coverage-7.10.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ae8e59e5f4fd85d6ad34c2bb9d74037b5b11be072b8b7e9986beb11f957573d4"}, - {file = "coverage-7.10.1-cp314-cp314-win32.whl", hash = "sha256:042125c89cf74a074984002e165d61fe0e31c7bd40ebb4bbebf07939b5924613"}, - {file = "coverage-7.10.1-cp314-cp314-win_amd64.whl", hash = "sha256:a22c3bfe09f7a530e2c94c87ff7af867259c91bef87ed2089cd69b783af7b84e"}, - {file = "coverage-7.10.1-cp314-cp314-win_arm64.whl", hash = "sha256:ee6be07af68d9c4fca4027c70cea0c31a0f1bc9cb464ff3c84a1f916bf82e652"}, - {file = "coverage-7.10.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:d24fb3c0c8ff0d517c5ca5de7cf3994a4cd559cde0315201511dbfa7ab528894"}, - {file = "coverage-7.10.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1217a54cfd79be20512a67ca81c7da3f2163f51bbfd188aab91054df012154f5"}, - {file = "coverage-7.10.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:51f30da7a52c009667e02f125737229d7d8044ad84b79db454308033a7808ab2"}, - {file = "coverage-7.10.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:ed3718c757c82d920f1c94089066225ca2ad7f00bb904cb72b1c39ebdd906ccb"}, - {file = "coverage-7.10.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cc452481e124a819ced0c25412ea2e144269ef2f2534b862d9f6a9dae4bda17b"}, - {file = "coverage-7.10.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:9d6f494c307e5cb9b1e052ec1a471060f1dea092c8116e642e7a23e79d9388ea"}, - {file = "coverage-7.10.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:fc0e46d86905ddd16b85991f1f4919028092b4e511689bbdaff0876bd8aab3dd"}, - {file = "coverage-7.10.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:80b9ccd82e30038b61fc9a692a8dc4801504689651b281ed9109f10cc9fe8b4d"}, - {file = "coverage-7.10.1-cp314-cp314t-win32.whl", hash = "sha256:e58991a2b213417285ec866d3cd32db17a6a88061a985dbb7e8e8f13af429c47"}, - {file = "coverage-7.10.1-cp314-cp314t-win_amd64.whl", hash = "sha256:e88dd71e4ecbc49d9d57d064117462c43f40a21a1383507811cf834a4a620651"}, - {file = "coverage-7.10.1-cp314-cp314t-win_arm64.whl", hash = "sha256:1aadfb06a30c62c2eb82322171fe1f7c288c80ca4156d46af0ca039052814bab"}, - {file = "coverage-7.10.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:57b6e8789cbefdef0667e4a94f8ffa40f9402cee5fc3b8e4274c894737890145"}, - {file = "coverage-7.10.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:85b22a9cce00cb03156334da67eb86e29f22b5e93876d0dd6a98646bb8a74e53"}, - {file = "coverage-7.10.1-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:97b6983a2f9c76d345ca395e843a049390b39652984e4a3b45b2442fa733992d"}, - {file = "coverage-7.10.1-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:ddf2a63b91399a1c2f88f40bc1705d5a7777e31c7e9eb27c602280f477b582ba"}, - {file = "coverage-7.10.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:47ab6dbbc31a14c5486420c2c1077fcae692097f673cf5be9ddbec8cdaa4cdbc"}, - {file = "coverage-7.10.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:21eb7d8b45d3700e7c2936a736f732794c47615a20f739f4133d5230a6512a88"}, - {file = "coverage-7.10.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:283005bb4d98ae33e45f2861cd2cde6a21878661c9ad49697f6951b358a0379b"}, - {file = "coverage-7.10.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:fefe31d61d02a8b2c419700b1fade9784a43d726de26495f243b663cd9fe1513"}, - {file = "coverage-7.10.1-cp39-cp39-win32.whl", hash = "sha256:e8ab8e4c7ec7f8a55ac05b5b715a051d74eac62511c6d96d5bb79aaafa3b04cf"}, - {file = "coverage-7.10.1-cp39-cp39-win_amd64.whl", hash = "sha256:c36baa0ecde742784aa76c2b816466d3ea888d5297fda0edbac1bf48fa94688a"}, - {file = "coverage-7.10.1-py3-none-any.whl", hash = "sha256:fa2a258aa6bf188eb9a8948f7102a83da7c430a0dce918dbd8b60ef8fcb772d7"}, - {file = "coverage-7.10.1.tar.gz", hash = "sha256:ae2b4856f29ddfe827106794f3589949a57da6f0d38ab01e24ec35107979ba57"}, + {file = "coverage-7.10.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:79f0283ab5e6499fd5fe382ca3d62afa40fb50ff227676a3125d18af70eabf65"}, + {file = "coverage-7.10.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e4545e906f595ee8ab8e03e21be20d899bfc06647925bc5b224ad7e8c40e08b8"}, + {file = "coverage-7.10.2-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:ae385e1d58fbc6a9b1c315e5510ac52281e271478b45f92ca9b5ad42cf39643f"}, + {file = "coverage-7.10.2-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6f0cbe5f7dd19f3a32bac2251b95d51c3b89621ac88a2648096ce40f9a5aa1e7"}, + {file = "coverage-7.10.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fd17f427f041f6b116dc90b4049c6f3e1230524407d00daa2d8c7915037b5947"}, + {file = "coverage-7.10.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7f10ca4cde7b466405cce0a0e9971a13eb22e57a5ecc8b5f93a81090cc9c7eb9"}, + {file = "coverage-7.10.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3b990df23dd51dccce26d18fb09fd85a77ebe46368f387b0ffba7a74e470b31b"}, + {file = "coverage-7.10.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cc3902584d25c7eef57fb38f440aa849a26a3a9f761a029a72b69acfca4e31f8"}, + {file = "coverage-7.10.2-cp310-cp310-win32.whl", hash = "sha256:9dd37e9ac00d5eb72f38ed93e3cdf2280b1dbda3bb9b48c6941805f265ad8d87"}, + {file = "coverage-7.10.2-cp310-cp310-win_amd64.whl", hash = "sha256:99d16f15cb5baf0729354c5bd3080ae53847a4072b9ba1e10957522fb290417f"}, + {file = "coverage-7.10.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c3b210d79925a476dfc8d74c7d53224888421edebf3a611f3adae923e212b27"}, + {file = "coverage-7.10.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bf67d1787cd317c3f8b2e4c6ed1ae93497be7e30605a0d32237ac37a37a8a322"}, + {file = "coverage-7.10.2-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:069b779d03d458602bc0e27189876e7d8bdf6b24ac0f12900de22dd2154e6ad7"}, + {file = "coverage-7.10.2-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:4c2de4cb80b9990e71c62c2d3e9f3ec71b804b1f9ca4784ec7e74127e0f42468"}, + {file = "coverage-7.10.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:75bf7ab2374a7eb107602f1e07310cda164016cd60968abf817b7a0b5703e288"}, + {file = "coverage-7.10.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3f37516458ec1550815134937f73d6d15b434059cd10f64678a2068f65c62406"}, + {file = "coverage-7.10.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:de3c6271c482c250d3303fb5c6bdb8ca025fff20a67245e1425df04dc990ece9"}, + {file = "coverage-7.10.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:98a838101321ac3089c9bb1d4bfa967e8afed58021fda72d7880dc1997f20ae1"}, + {file = "coverage-7.10.2-cp311-cp311-win32.whl", hash = "sha256:f2a79145a531a0e42df32d37be5af069b4a914845b6f686590739b786f2f7bce"}, + {file = "coverage-7.10.2-cp311-cp311-win_amd64.whl", hash = "sha256:e4f5f1320f8ee0d7cfa421ceb257bef9d39fd614dd3ddcfcacd284d4824ed2c2"}, + {file = "coverage-7.10.2-cp311-cp311-win_arm64.whl", hash = "sha256:d8f2d83118f25328552c728b8e91babf93217db259ca5c2cd4dd4220b8926293"}, + {file = "coverage-7.10.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:890ad3a26da9ec7bf69255b9371800e2a8da9bc223ae5d86daeb940b42247c83"}, + {file = "coverage-7.10.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:38fd1ccfca7838c031d7a7874d4353e2f1b98eb5d2a80a2fe5732d542ae25e9c"}, + {file = "coverage-7.10.2-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:76c1ffaaf4f6f0f6e8e9ca06f24bb6454a7a5d4ced97a1bc466f0d6baf4bd518"}, + {file = "coverage-7.10.2-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:86da8a3a84b79ead5c7d0e960c34f580bc3b231bb546627773a3f53c532c2f21"}, + {file = "coverage-7.10.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:99cef9731c8a39801830a604cc53c93c9e57ea8b44953d26589499eded9576e0"}, + {file = "coverage-7.10.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ea58b112f2966a8b91eb13f5d3b1f8bb43c180d624cd3283fb33b1cedcc2dd75"}, + {file = "coverage-7.10.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:20f405188d28da9522b7232e51154e1b884fc18d0b3a10f382d54784715bbe01"}, + {file = "coverage-7.10.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:64586ce42bbe0da4d9f76f97235c545d1abb9b25985a8791857690f96e23dc3b"}, + {file = "coverage-7.10.2-cp312-cp312-win32.whl", hash = "sha256:bc2e69b795d97ee6d126e7e22e78a509438b46be6ff44f4dccbb5230f550d340"}, + {file = "coverage-7.10.2-cp312-cp312-win_amd64.whl", hash = "sha256:adda2268b8cf0d11f160fad3743b4dfe9813cd6ecf02c1d6397eceaa5b45b388"}, + {file = "coverage-7.10.2-cp312-cp312-win_arm64.whl", hash = "sha256:164429decd0d6b39a0582eaa30c67bf482612c0330572343042d0ed9e7f15c20"}, + {file = "coverage-7.10.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:aca7b5645afa688de6d4f8e89d30c577f62956fefb1bad021490d63173874186"}, + {file = "coverage-7.10.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:96e5921342574a14303dfdb73de0019e1ac041c863743c8fe1aa6c2b4a257226"}, + {file = "coverage-7.10.2-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:11333094c1bff621aa811b67ed794865cbcaa99984dedea4bd9cf780ad64ecba"}, + {file = "coverage-7.10.2-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6eb586fa7d2aee8d65d5ae1dd71414020b2f447435c57ee8de8abea0a77d5074"}, + {file = "coverage-7.10.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2d358f259d8019d4ef25d8c5b78aca4c7af25e28bd4231312911c22a0e824a57"}, + {file = "coverage-7.10.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5250bda76e30382e0a2dcd68d961afcab92c3a7613606e6269855c6979a1b0bb"}, + {file = "coverage-7.10.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:a91e027d66eff214d88d9afbe528e21c9ef1ecdf4956c46e366c50f3094696d0"}, + {file = "coverage-7.10.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:228946da741558904e2c03ce870ba5efd9cd6e48cbc004d9a27abee08100a15a"}, + {file = "coverage-7.10.2-cp313-cp313-win32.whl", hash = "sha256:95e23987b52d02e7c413bf2d6dc6288bd5721beb518052109a13bfdc62c8033b"}, + {file = "coverage-7.10.2-cp313-cp313-win_amd64.whl", hash = "sha256:f35481d42c6d146d48ec92d4e239c23f97b53a3f1fbd2302e7c64336f28641fe"}, + {file = "coverage-7.10.2-cp313-cp313-win_arm64.whl", hash = "sha256:65b451949cb789c346f9f9002441fc934d8ccedcc9ec09daabc2139ad13853f7"}, + {file = "coverage-7.10.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:e8415918856a3e7d57a4e0ad94651b761317de459eb74d34cc1bb51aad80f07e"}, + {file = "coverage-7.10.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f287a25a8ca53901c613498e4a40885b19361a2fe8fbfdbb7f8ef2cad2a23f03"}, + {file = "coverage-7.10.2-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:75cc1a3f8c88c69bf16a871dab1fe5a7303fdb1e9f285f204b60f1ee539b8fc0"}, + {file = "coverage-7.10.2-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:ca07fa78cc9d26bc8c4740de1abd3489cf9c47cc06d9a8ab3d552ff5101af4c0"}, + {file = "coverage-7.10.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c2e117e64c26300032755d4520cd769f2623cde1a1d1c3515b05a3b8add0ade1"}, + {file = "coverage-7.10.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:daaf98009977f577b71f8800208f4d40d4dcf5c2db53d4d822787cdc198d76e1"}, + {file = "coverage-7.10.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:ea8d8fe546c528535c761ba424410bbeb36ba8a0f24be653e94b70c93fd8a8ca"}, + {file = "coverage-7.10.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:fe024d40ac31eb8d5aae70215b41dafa264676caa4404ae155f77d2fa95c37bb"}, + {file = "coverage-7.10.2-cp313-cp313t-win32.whl", hash = "sha256:8f34b09f68bdadec122ffad312154eda965ade433559cc1eadd96cca3de5c824"}, + {file = "coverage-7.10.2-cp313-cp313t-win_amd64.whl", hash = "sha256:71d40b3ac0f26fa9ffa6ee16219a714fed5c6ec197cdcd2018904ab5e75bcfa3"}, + {file = "coverage-7.10.2-cp313-cp313t-win_arm64.whl", hash = "sha256:abb57fdd38bf6f7dcc66b38dafb7af7c5fdc31ac6029ce373a6f7f5331d6f60f"}, + {file = "coverage-7.10.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:a3e853cc04987c85ec410905667eed4bf08b1d84d80dfab2684bb250ac8da4f6"}, + {file = "coverage-7.10.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0100b19f230df72c90fdb36db59d3f39232391e8d89616a7de30f677da4f532b"}, + {file = "coverage-7.10.2-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:9c1cd71483ea78331bdfadb8dcec4f4edfb73c7002c1206d8e0af6797853f5be"}, + {file = "coverage-7.10.2-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9f75dbf4899e29a37d74f48342f29279391668ef625fdac6d2f67363518056a1"}, + {file = "coverage-7.10.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a7df481e7508de1c38b9b8043da48d94931aefa3e32b47dd20277e4978ed5b95"}, + {file = "coverage-7.10.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:835f39e618099325e7612b3406f57af30ab0a0af350490eff6421e2e5f608e46"}, + {file = "coverage-7.10.2-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:12e52b5aa00aa720097d6947d2eb9e404e7c1101ad775f9661ba165ed0a28303"}, + {file = "coverage-7.10.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:718044729bf1fe3e9eb9f31b52e44ddae07e434ec050c8c628bf5adc56fe4bdd"}, + {file = "coverage-7.10.2-cp314-cp314-win32.whl", hash = "sha256:f256173b48cc68486299d510a3e729a96e62c889703807482dbf56946befb5c8"}, + {file = "coverage-7.10.2-cp314-cp314-win_amd64.whl", hash = "sha256:2e980e4179f33d9b65ac4acb86c9c0dde904098853f27f289766657ed16e07b3"}, + {file = "coverage-7.10.2-cp314-cp314-win_arm64.whl", hash = "sha256:14fb5b6641ab5b3c4161572579f0f2ea8834f9d3af2f7dd8fbaecd58ef9175cc"}, + {file = "coverage-7.10.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:e96649ac34a3d0e6491e82a2af71098e43be2874b619547c3282fc11d3840a4b"}, + {file = "coverage-7.10.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1a2e934e9da26341d342d30bfe91422bbfdb3f1f069ec87f19b2909d10d8dcc4"}, + {file = "coverage-7.10.2-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:651015dcd5fd9b5a51ca79ece60d353cacc5beaf304db750407b29c89f72fe2b"}, + {file = "coverage-7.10.2-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:81bf6a32212f9f66da03d63ecb9cd9bd48e662050a937db7199dbf47d19831de"}, + {file = "coverage-7.10.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d800705f6951f75a905ea6feb03fff8f3ea3468b81e7563373ddc29aa3e5d1ca"}, + {file = "coverage-7.10.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:248b5394718e10d067354448dc406d651709c6765669679311170da18e0e9af8"}, + {file = "coverage-7.10.2-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:5c61675a922b569137cf943770d7ad3edd0202d992ce53ac328c5ff68213ccf4"}, + {file = "coverage-7.10.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:52d708b5fd65589461381fa442d9905f5903d76c086c6a4108e8e9efdca7a7ed"}, + {file = "coverage-7.10.2-cp314-cp314t-win32.whl", hash = "sha256:916369b3b914186b2c5e5ad2f7264b02cff5df96cdd7cdad65dccd39aa5fd9f0"}, + {file = "coverage-7.10.2-cp314-cp314t-win_amd64.whl", hash = "sha256:5b9d538e8e04916a5df63052d698b30c74eb0174f2ca9cd942c981f274a18eaf"}, + {file = "coverage-7.10.2-cp314-cp314t-win_arm64.whl", hash = "sha256:04c74f9ef1f925456a9fd23a7eef1103126186d0500ef9a0acb0bd2514bdc7cc"}, + {file = "coverage-7.10.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:765b13b164685a2f8b2abef867ad07aebedc0e090c757958a186f64e39d63dbd"}, + {file = "coverage-7.10.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a219b70100500d0c7fd3ebb824a3302efb6b1a122baa9d4eb3f43df8f0b3d899"}, + {file = "coverage-7.10.2-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:e33e79a219105aa315439ee051bd50b6caa705dc4164a5aba6932c8ac3ce2d98"}, + {file = "coverage-7.10.2-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:bc3945b7bad33957a9eca16e9e5eae4b17cb03173ef594fdaad228f4fc7da53b"}, + {file = "coverage-7.10.2-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9bdff88e858ee608a924acfad32a180d2bf6e13e059d6a7174abbae075f30436"}, + {file = "coverage-7.10.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:44329cbed24966c0b49acb386352c9722219af1f0c80db7f218af7793d251902"}, + {file = "coverage-7.10.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:be127f292496d0fbe20d8025f73221b36117b3587f890346e80a13b310712982"}, + {file = "coverage-7.10.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:6c031da749a05f7a01447dd7f47beedb498edd293e31e1878c0d52db18787df0"}, + {file = "coverage-7.10.2-cp39-cp39-win32.whl", hash = "sha256:22aca3e691c7709c5999ccf48b7a8ff5cf5a8bd6fe9b36efbd4993f5a36b2fcf"}, + {file = "coverage-7.10.2-cp39-cp39-win_amd64.whl", hash = "sha256:c7195444b932356055a8e287fa910bf9753a84a1bc33aeb3770e8fca521e032e"}, + {file = "coverage-7.10.2-py3-none-any.whl", hash = "sha256:95db3750dd2e6e93d99fa2498f3a1580581e49c494bddccc6f85c5c21604921f"}, + {file = "coverage-7.10.2.tar.gz", hash = "sha256:5d6e6d84e6dd31a8ded64759626627247d676a23c1b892e1326f7c55c8d61055"}, ] [package.dependencies] @@ -866,6 +866,18 @@ files = [ {file = "iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7"}, ] +[[package]] +name = "invoke" +version = "2.2.0" +description = "Pythonic task execution" +optional = false +python-versions = ">=3.6" +groups = ["integration"] +files = [ + {file = "invoke-2.2.0-py3-none-any.whl", hash = "sha256:6ea924cc53d4f78e3d98bc436b08069a03077e6f85ad1ddaa8a116d7dad15820"}, + {file = "invoke-2.2.0.tar.gz", hash = "sha256:ee6cbb101af1a859c7fe84f2a264c059020b0cb7fe3535f9424300ab568f6bd5"}, +] + [[package]] name = "ipdb" version = "0.13.13" @@ -1388,25 +1400,24 @@ dev = ["jinja2"] [[package]] name = "paramiko" -version = "3.5.1" +version = "4.0.0" description = "SSH2 protocol library" optional = false -python-versions = ">=3.6" +python-versions = ">=3.9" groups = ["integration"] files = [ - {file = "paramiko-3.5.1-py3-none-any.whl", hash = "sha256:43b9a0501fc2b5e70680388d9346cf252cfb7d00b0667c39e80eb43a408b8f61"}, - {file = "paramiko-3.5.1.tar.gz", hash = "sha256:b2c665bc45b2b215bd7d7f039901b14b067da00f3a11e6640995fd58f2664822"}, + {file = "paramiko-4.0.0-py3-none-any.whl", hash = "sha256:0e20e00ac666503bf0b4eda3b6d833465a2b7aff2e2b3d79a8bba5ef144ee3b9"}, + {file = "paramiko-4.0.0.tar.gz", hash = "sha256:6a25f07b380cc9c9a88d2b920ad37167ac4667f8d9886ccebd8f90f654b5d69f"}, ] [package.dependencies] bcrypt = ">=3.2" cryptography = ">=3.3" +invoke = ">=2.0" pynacl = ">=1.5" [package.extras] -all = ["gssapi (>=1.4.1) ; platform_system != \"Windows\"", "invoke (>=2.0)", "pyasn1 (>=0.1.7)", "pywin32 (>=2.1.8) ; platform_system == \"Windows\""] gssapi = ["gssapi (>=1.4.1) ; platform_system != \"Windows\"", "pyasn1 (>=0.1.7)", "pywin32 (>=2.1.8) ; platform_system == \"Windows\""] -invoke = ["invoke (>=2.0)"] [[package]] name = "parso" @@ -2669,4 +2680,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = "^3.10" -content-hash = "197d41501bbfad15511a26e1ddd0608cc856972b4038d52c458dfadbc6ecde83" +content-hash = "2190b6beb8339d651097b6f13926d55686d198017af262f39adfecd8861536c4" diff --git a/pyproject.toml b/pyproject.toml index a1154f8dd2..7d4d1265a9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ requires-poetry = ">=2.0.0" [tool.poetry.dependencies] python = "^3.10" ops = "^2.23.1" -boto3 = "^1.39.17" +boto3 = "^1.40.2" pgconnstr = "^1.0.1" requests = "^2.32.4" tenacity = "^9.1.2" @@ -52,7 +52,7 @@ codespell = "^2.4.1" optional = true [tool.poetry.group.unit.dependencies] -coverage = {extras = ["toml"], version = "^7.10.1"} +coverage = {extras = ["toml"], version = "^7.10.2"} pytest = "^8.4.1" pytest-asyncio = "*" parameterized = "^0.9.0" From 86a7d6ceaf40fc0929696f56264e803129040430 Mon Sep 17 00:00:00 2001 From: Alex Lutay <1928266+taurus-forever@users.noreply.github.com> Date: Mon, 11 Aug 2025 13:32:48 +0200 Subject: [PATCH 074/112] Add SNAP revisions to Releases page (#1086) * Add SNAP revisions to Releases page For end-users, it is hard to find the proper/expected SNAP revison for the specific Charm revision in Git. This should simplify it. * fix broken URLs --------- Co-authored-by: andreia --- docs/how-to/deploy/tls-vip-access.md | 2 +- docs/reference/releases.md | 28 ++++++++++++++-------------- docs/reference/versions.md | 2 +- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/docs/how-to/deploy/tls-vip-access.md b/docs/how-to/deploy/tls-vip-access.md index 9e373110a2..f69586507c 100644 --- a/docs/how-to/deploy/tls-vip-access.md +++ b/docs/how-to/deploy/tls-vip-access.md @@ -14,7 +14,7 @@ The basic requirements to follow along with this example setup are the following * A fully deployed and running Juju machine environment * See the [PostgreSQL Tutorial](/tutorial/index) for a quick setup with Multipass - * See the official [Juju deployment guide](https://juju.is/docs/juju/tutorial#deploy) for more details + * See the official [Juju deployment guide](https://juju.is/docs/juju/tutorial) for more details * A spare virtual IP address for [`hacluster`](https://discourse.charmhub.io/t/pgbouncer-how-to-externally-access/15741) * See the PgBouncer guide: [How to use a VIP to connect to PgBouncer](https://charmhub.io/pgbouncer/docs/h-external-access?channel=1/stable) * DNS record pointing to VIP above (`my-tls-example-db.local` is used as an example here) diff --git a/docs/reference/releases.md b/docs/reference/releases.md index 91d819f4d3..d16fb323a7 100644 --- a/docs/reference/releases.md +++ b/docs/reference/releases.md @@ -40,24 +40,24 @@ Check the tables below, or use [`juju info`](https://juju.is/docs/juju/juju-info ### Release 552-553 -| Revision | amd64 | arm64 | Ubuntu 22.04 LTS -|:--------:|:-----:|:-----:|:-----:| -|[553] | ![check] | | ![check] | -|[552] | | ![check] | ![check] | +| Revision | amd64 | arm64 | Ubuntu 22.04 LTS | Snap revision | +|:--------:|:-----:|:-----:|:-----:|:-----:| +|[553] | ![check] | | ![check] | 143 | +|[552] | | ![check] | ![check] | 142 |
Older releases -| Revision | amd64 | arm64 | Ubuntu 22.04 LTS -|:--------:|:-----:|:-----:|:-----:| -|[468] |![check] | | ![check] | -|[467] | | ![check] | ![check] | -|[430] | | ![check] | ![check] | -|[429] |![check] | | ![check] | -|[363] |![check] | | ![check] | -|[351] |![check] | | ![check] | -|[336] |![check] | | ![check] | -|[288] |![check] | | ![check] | +| Revision | amd64 | arm64 | Ubuntu 22.04 LTS | Snap revision | +|:--------:|:-----:|:-----:|:-----:|:-----:| +|[468] |![check] | | ![check] | 120 | +|[467] | | ![check] | ![check] | 121 | +|[430] | | ![check] | ![check] | 114 | +|[429] |![check] | | ![check] | 115 | +|[363] |![check] | | ![check] | 96 | +|[351] |![check] | | ![check] | 89 | +|[336] |![check] | | ![check] | 85 | +|[288] |![check] | | ![check] | 31 |
diff --git a/docs/reference/versions.md b/docs/reference/versions.md index 9787337944..4789413ec3 100644 --- a/docs/reference/versions.md +++ b/docs/reference/versions.md @@ -28,7 +28,7 @@ PostgreSQL 16 is shipped in track `16` and is available for testing in the chann * All replicas are now [synchronous units] * Switchover the primary unit via `promote-to-primary scope=unit` * Raft re-init helper: `promote-to-primary scope=unit force=yes` -* [Juju user secrets](https://documentation.ubuntu.com/juju/latest/reference/secret/index.html#user) for charm [internal passwords](/how-to/manage-passwords) +* [Juju user secrets](https://documentation.ubuntu.com/juju/latest/reference/secret/index.html#user-secret) for charm [internal passwords](/how-to/manage-passwords) * [Timescale Community Edition] * [Extended COS integration] * [Profiling via Parca] From 51752e6c0806c79c5a0e5acaf67e11a67e3b4230 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 14 Aug 2025 12:42:51 +0300 Subject: [PATCH 075/112] Update canonical/data-platform-workflows action to v32.2.2 (#1088) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/approve_renovate_pr.yaml | 2 +- .github/workflows/check_pr.yaml | 2 +- .github/workflows/ci.yaml | 4 ++-- .github/workflows/promote.yaml | 2 +- .github/workflows/release.yaml | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/approve_renovate_pr.yaml b/.github/workflows/approve_renovate_pr.yaml index be0c1ee058..713a352098 100644 --- a/.github/workflows/approve_renovate_pr.yaml +++ b/.github/workflows/approve_renovate_pr.yaml @@ -10,6 +10,6 @@ on: jobs: approve-pr: name: Approve Renovate pull request - uses: canonical/data-platform-workflows/.github/workflows/approve_renovate_pr.yaml@v32.2.1 + uses: canonical/data-platform-workflows/.github/workflows/approve_renovate_pr.yaml@v32.2.2 permissions: pull-requests: write # Needed to approve PR diff --git a/.github/workflows/check_pr.yaml b/.github/workflows/check_pr.yaml index e5bf04489a..e81b2f5bf9 100644 --- a/.github/workflows/check_pr.yaml +++ b/.github/workflows/check_pr.yaml @@ -16,4 +16,4 @@ on: jobs: check-pr: name: Check pull request - uses: canonical/data-platform-workflows/.github/workflows/check_charm_pr.yaml@v32.2.1 + uses: canonical/data-platform-workflows/.github/workflows/check_charm_pr.yaml@v32.2.2 diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 4d3259ee7a..e27998892c 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -27,7 +27,7 @@ on: jobs: lint: name: Lint - uses: canonical/data-platform-workflows/.github/workflows/lint.yaml@v32.2.1 + uses: canonical/data-platform-workflows/.github/workflows/lint.yaml@v32.2.2 unit-test: name: Unit test charm @@ -49,7 +49,7 @@ jobs: build: name: Build charm - uses: canonical/data-platform-workflows/.github/workflows/build_charm.yaml@v32.2.1 + uses: canonical/data-platform-workflows/.github/workflows/build_charm.yaml@v32.2.2 integration-test: name: Integration test charm diff --git a/.github/workflows/promote.yaml b/.github/workflows/promote.yaml index dcd9d19863..ee95a53057 100644 --- a/.github/workflows/promote.yaml +++ b/.github/workflows/promote.yaml @@ -25,7 +25,7 @@ on: jobs: promote: name: Promote charm - uses: canonical/data-platform-workflows/.github/workflows/_promote_charm.yaml@v32.2.1 + uses: canonical/data-platform-workflows/.github/workflows/_promote_charm.yaml@v32.2.2 with: track: '14' from-risk: ${{ inputs.from-risk }} diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index f21f08e3ca..c0f368a327 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -27,7 +27,7 @@ jobs: name: Release charm needs: - ci-tests - uses: canonical/data-platform-workflows/.github/workflows/release_charm_edge.yaml@v32.2.1 + uses: canonical/data-platform-workflows/.github/workflows/release_charm_edge.yaml@v32.2.2 with: track: 14 artifact-prefix: ${{ needs.ci-tests.outputs.artifact-prefix }} From a4980d606a324bb695912a187116c116b9c2a484 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 15 Aug 2025 12:35:11 +0300 Subject: [PATCH 076/112] Update GitHub actions to v5 (#1090) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/ci.yaml | 2 +- .github/workflows/integration_test.yaml | 12 ++++++------ .github/workflows/lib-check.yaml | 2 +- .github/workflows/tiobe_scan.yaml | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index e27998892c..f2341067f6 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -35,7 +35,7 @@ jobs: timeout-minutes: 5 steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Install tox & poetry run: | pipx install tox diff --git a/.github/workflows/integration_test.yaml b/.github/workflows/integration_test.yaml index a89194c525..3ac1b994db 100644 --- a/.github/workflows/integration_test.yaml +++ b/.github/workflows/integration_test.yaml @@ -16,7 +16,7 @@ jobs: timeout-minutes: 5 steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Set up environment run: | sudo snap install charmcraft --classic @@ -97,7 +97,7 @@ jobs: df --human-readable - name: Checkout timeout-minutes: 3 - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Set up environment timeout-minutes: 5 run: sudo snap install charmcraft --classic @@ -108,7 +108,7 @@ jobs: go install github.com/snapcore/spread/cmd/spread@latest - name: Download packed charm(s) timeout-minutes: 5 - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v5 with: pattern: ${{ inputs.artifact-prefix }}-* merge-multiple: true @@ -207,19 +207,19 @@ jobs: # git push origin gh-pages-beta # ) - name: Checkout GitHub pages branch - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: ref: gh-pages-beta path: repo/ - name: Download default test results # Default test results in case the integration tests time out or runner set up fails # (So that Allure report will show "unknown"/"failed" test result, instead of omitting the test) - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v5 with: path: allure-default-results/ name: allure-default-results-integration-test - name: Download test results - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v5 with: path: allure-results/ pattern: allure-results-integration-test-* diff --git a/.github/workflows/lib-check.yaml b/.github/workflows/lib-check.yaml index 52b318a9f6..410b773176 100644 --- a/.github/workflows/lib-check.yaml +++ b/.github/workflows/lib-check.yaml @@ -24,7 +24,7 @@ jobs: if: ${{ github.event.pull_request.head.repo.full_name == 'canonical/postgresql-operator' }} steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: fetch-depth: 0 - name: Check libs diff --git a/.github/workflows/tiobe_scan.yaml b/.github/workflows/tiobe_scan.yaml index b81b022ef0..9d5c028fde 100644 --- a/.github/workflows/tiobe_scan.yaml +++ b/.github/workflows/tiobe_scan.yaml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-24.04 steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Create and activate virtual environment run: | From 8c592a625807a884736e2297354ef7e59feaad25 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 15 Aug 2025 12:36:32 +0300 Subject: [PATCH 077/112] Lock file maintenance Python dependencies (#1091) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- poetry.lock | 784 ++++++++++++++++++++++++------------------------- pyproject.toml | 6 +- 2 files changed, 394 insertions(+), 396 deletions(-) diff --git a/poetry.lock b/poetry.lock index a648e96f07..abda6be253 100644 --- a/poetry.lock +++ b/poetry.lock @@ -233,18 +233,18 @@ typecheck = ["mypy"] [[package]] name = "boto3" -version = "1.40.2" +version = "1.40.7" description = "The AWS SDK for Python" optional = false python-versions = ">=3.9" groups = ["main", "integration"] files = [ - {file = "boto3-1.40.2-py3-none-any.whl", hash = "sha256:3d99325ee874190e8f3bfd38823987327c826cdfbab943420851bdb7684d727c"}, - {file = "boto3-1.40.2.tar.gz", hash = "sha256:2dfbc214fdbf94abfd61eec687ea39089d05af43bb00be792c76f3a6c1393f7b"}, + {file = "boto3-1.40.7-py3-none-any.whl", hash = "sha256:8727cac601a679d2885dc78b8119a0548bbbe04e49b72f7d94021a629154c080"}, + {file = "boto3-1.40.7.tar.gz", hash = "sha256:61b15f70761f1eadd721c6ba41a92658f003eaaef09500ca7642f5ae68ec8945"}, ] [package.dependencies] -botocore = ">=1.40.2,<1.41.0" +botocore = ">=1.40.7,<1.41.0" jmespath = ">=0.7.1,<2.0.0" s3transfer = ">=0.13.0,<0.14.0" @@ -253,14 +253,14 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.40.2" +version = "1.40.7" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">=3.9" groups = ["main", "integration"] files = [ - {file = "botocore-1.40.2-py3-none-any.whl", hash = "sha256:a31e6269af05498f8dc1c7f2b3f34448a0f16c79a8601c0389ecddab51b2c2ab"}, - {file = "botocore-1.40.2.tar.gz", hash = "sha256:77c4710bf37b28e897833b5b1f47d6a83e45a29985cd01a560dfdb8b6ad524e5"}, + {file = "botocore-1.40.7-py3-none-any.whl", hash = "sha256:a06956f3d7222e80ef6ae193608f358c3b7898e1a2b88553479d8f9737fbb03e"}, + {file = "botocore-1.40.7.tar.gz", hash = "sha256:33793696680cf3a0c4b5ace4f9070c67c4d4fcb19c999fd85cfee55de3dcf913"}, ] [package.dependencies] @@ -378,104 +378,91 @@ pycparser = "*" [[package]] name = "charset-normalizer" -version = "3.4.2" +version = "3.4.3" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7" groups = ["main", "charm-libs", "integration"] files = [ - {file = "charset_normalizer-3.4.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c48ed483eb946e6c04ccbe02c6b4d1d48e51944b6db70f697e089c193404941"}, - {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2d318c11350e10662026ad0eb71bb51c7812fc8590825304ae0bdd4ac283acd"}, - {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9cbfacf36cb0ec2897ce0ebc5d08ca44213af24265bd56eca54bee7923c48fd6"}, - {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18dd2e350387c87dabe711b86f83c9c78af772c748904d372ade190b5c7c9d4d"}, - {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8075c35cd58273fee266c58c0c9b670947c19df5fb98e7b66710e04ad4e9ff86"}, - {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5bf4545e3b962767e5c06fe1738f951f77d27967cb2caa64c28be7c4563e162c"}, - {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7a6ab32f7210554a96cd9e33abe3ddd86732beeafc7a28e9955cdf22ffadbab0"}, - {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:b33de11b92e9f75a2b545d6e9b6f37e398d86c3e9e9653c4864eb7e89c5773ef"}, - {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8755483f3c00d6c9a77f490c17e6ab0c8729e39e6390328e42521ef175380ae6"}, - {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:68a328e5f55ec37c57f19ebb1fdc56a248db2e3e9ad769919a58672958e8f366"}, - {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:21b2899062867b0e1fde9b724f8aecb1af14f2778d69aacd1a5a1853a597a5db"}, - {file = "charset_normalizer-3.4.2-cp310-cp310-win32.whl", hash = "sha256:e8082b26888e2f8b36a042a58307d5b917ef2b1cacab921ad3323ef91901c71a"}, - {file = "charset_normalizer-3.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:f69a27e45c43520f5487f27627059b64aaf160415589230992cec34c5e18a509"}, - {file = "charset_normalizer-3.4.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:be1e352acbe3c78727a16a455126d9ff83ea2dfdcbc83148d2982305a04714c2"}, - {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa88ca0b1932e93f2d961bf3addbb2db902198dca337d88c89e1559e066e7645"}, - {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d524ba3f1581b35c03cb42beebab4a13e6cdad7b36246bd22541fa585a56cccd"}, - {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28a1005facc94196e1fb3e82a3d442a9d9110b8434fc1ded7a24a2983c9888d8"}, - {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fdb20a30fe1175ecabed17cbf7812f7b804b8a315a25f24678bcdf120a90077f"}, - {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f5d9ed7f254402c9e7d35d2f5972c9bbea9040e99cd2861bd77dc68263277c7"}, - {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:efd387a49825780ff861998cd959767800d54f8308936b21025326de4b5a42b9"}, - {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f0aa37f3c979cf2546b73e8222bbfa3dc07a641585340179d768068e3455e544"}, - {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e70e990b2137b29dc5564715de1e12701815dacc1d056308e2b17e9095372a82"}, - {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0c8c57f84ccfc871a48a47321cfa49ae1df56cd1d965a09abe84066f6853b9c0"}, - {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6b66f92b17849b85cad91259efc341dce9c1af48e2173bf38a85c6329f1033e5"}, - {file = "charset_normalizer-3.4.2-cp311-cp311-win32.whl", hash = "sha256:daac4765328a919a805fa5e2720f3e94767abd632ae410a9062dff5412bae65a"}, - {file = "charset_normalizer-3.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:e53efc7c7cee4c1e70661e2e112ca46a575f90ed9ae3fef200f2a25e954f4b28"}, - {file = "charset_normalizer-3.4.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0c29de6a1a95f24b9a1aa7aefd27d2487263f00dfd55a77719b530788f75cff7"}, - {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cddf7bd982eaa998934a91f69d182aec997c6c468898efe6679af88283b498d3"}, - {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcbe676a55d7445b22c10967bceaaf0ee69407fbe0ece4d032b6eb8d4565982a"}, - {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d41c4d287cfc69060fa91cae9683eacffad989f1a10811995fa309df656ec214"}, - {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e594135de17ab3866138f496755f302b72157d115086d100c3f19370839dd3a"}, - {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf713fe9a71ef6fd5adf7a79670135081cd4431c2943864757f0fa3a65b1fafd"}, - {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a370b3e078e418187da8c3674eddb9d983ec09445c99a3a263c2011993522981"}, - {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a955b438e62efdf7e0b7b52a64dc5c3396e2634baa62471768a64bc2adb73d5c"}, - {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7222ffd5e4de8e57e03ce2cef95a4c43c98fcb72ad86909abdfc2c17d227fc1b"}, - {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:bee093bf902e1d8fc0ac143c88902c3dfc8941f7ea1d6a8dd2bcb786d33db03d"}, - {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dedb8adb91d11846ee08bec4c8236c8549ac721c245678282dcb06b221aab59f"}, - {file = "charset_normalizer-3.4.2-cp312-cp312-win32.whl", hash = "sha256:db4c7bf0e07fc3b7d89ac2a5880a6a8062056801b83ff56d8464b70f65482b6c"}, - {file = "charset_normalizer-3.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:5a9979887252a82fefd3d3ed2a8e3b937a7a809f65dcb1e068b090e165bbe99e"}, - {file = "charset_normalizer-3.4.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:926ca93accd5d36ccdabd803392ddc3e03e6d4cd1cf17deff3b989ab8e9dbcf0"}, - {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eba9904b0f38a143592d9fc0e19e2df0fa2e41c3c3745554761c5f6447eedabf"}, - {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3fddb7e2c84ac87ac3a947cb4e66d143ca5863ef48e4a5ecb83bd48619e4634e"}, - {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98f862da73774290f251b9df8d11161b6cf25b599a66baf087c1ffe340e9bfd1"}, - {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c9379d65defcab82d07b2a9dfbfc2e95bc8fe0ebb1b176a3190230a3ef0e07c"}, - {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e635b87f01ebc977342e2697d05b56632f5f879a4f15955dfe8cef2448b51691"}, - {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1c95a1e2902a8b722868587c0e1184ad5c55631de5afc0eb96bc4b0d738092c0"}, - {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ef8de666d6179b009dce7bcb2ad4c4a779f113f12caf8dc77f0162c29d20490b"}, - {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:32fc0341d72e0f73f80acb0a2c94216bd704f4f0bce10aedea38f30502b271ff"}, - {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:289200a18fa698949d2b39c671c2cc7a24d44096784e76614899a7ccf2574b7b"}, - {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a476b06fbcf359ad25d34a057b7219281286ae2477cc5ff5e3f70a246971148"}, - {file = "charset_normalizer-3.4.2-cp313-cp313-win32.whl", hash = "sha256:aaeeb6a479c7667fbe1099af9617c83aaca22182d6cf8c53966491a0f1b7ffb7"}, - {file = "charset_normalizer-3.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980"}, - {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cad5f45b3146325bb38d6855642f6fd609c3f7cad4dbaf75549bf3b904d3184"}, - {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b2680962a4848b3c4f155dc2ee64505a9c57186d0d56b43123b17ca3de18f0fa"}, - {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:36b31da18b8890a76ec181c3cf44326bf2c48e36d393ca1b72b3f484113ea344"}, - {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f4074c5a429281bf056ddd4c5d3b740ebca4d43ffffe2ef4bf4d2d05114299da"}, - {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c9e36a97bee9b86ef9a1cf7bb96747eb7a15c2f22bdb5b516434b00f2a599f02"}, - {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:1b1bde144d98e446b056ef98e59c256e9294f6b74d7af6846bf5ffdafd687a7d"}, - {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:915f3849a011c1f593ab99092f3cecfcb4d65d8feb4a64cf1bf2d22074dc0ec4"}, - {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:fb707f3e15060adf5b7ada797624a6c6e0138e2a26baa089df64c68ee98e040f"}, - {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:25a23ea5c7edc53e0f29bae2c44fcb5a1aa10591aae107f2a2b2583a9c5cbc64"}, - {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:770cab594ecf99ae64c236bc9ee3439c3f46be49796e265ce0cc8bc17b10294f"}, - {file = "charset_normalizer-3.4.2-cp37-cp37m-win32.whl", hash = "sha256:6a0289e4589e8bdfef02a80478f1dfcb14f0ab696b5a00e1f4b8a14a307a3c58"}, - {file = "charset_normalizer-3.4.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6fc1f5b51fa4cecaa18f2bd7a003f3dd039dd615cd69a2afd6d3b19aed6775f2"}, - {file = "charset_normalizer-3.4.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:76af085e67e56c8816c3ccf256ebd136def2ed9654525348cfa744b6802b69eb"}, - {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e45ba65510e2647721e35323d6ef54c7974959f6081b58d4ef5d87c60c84919a"}, - {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:046595208aae0120559a67693ecc65dd75d46f7bf687f159127046628178dc45"}, - {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75d10d37a47afee94919c4fab4c22b9bc2a8bf7d4f46f87363bcf0573f3ff4f5"}, - {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6333b3aa5a12c26b2a4d4e7335a28f1475e0e5e17d69d55141ee3cab736f66d1"}, - {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e8323a9b031aa0393768b87f04b4164a40037fb2a3c11ac06a03ffecd3618027"}, - {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:24498ba8ed6c2e0b56d4acbf83f2d989720a93b41d712ebd4f4979660db4417b"}, - {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:844da2b5728b5ce0e32d863af26f32b5ce61bc4273a9c720a9f3aa9df73b1455"}, - {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:65c981bdbd3f57670af8b59777cbfae75364b483fa8a9f420f08094531d54a01"}, - {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:3c21d4fca343c805a52c0c78edc01e3477f6dd1ad7c47653241cf2a206d4fc58"}, - {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:dc7039885fa1baf9be153a0626e337aa7ec8bf96b0128605fb0d77788ddc1681"}, - {file = "charset_normalizer-3.4.2-cp38-cp38-win32.whl", hash = "sha256:8272b73e1c5603666618805fe821edba66892e2870058c94c53147602eab29c7"}, - {file = "charset_normalizer-3.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:70f7172939fdf8790425ba31915bfbe8335030f05b9913d7ae00a87d4395620a"}, - {file = "charset_normalizer-3.4.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:005fa3432484527f9732ebd315da8da8001593e2cf46a3d817669f062c3d9ed4"}, - {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e92fca20c46e9f5e1bb485887d074918b13543b1c2a1185e69bb8d17ab6236a7"}, - {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:50bf98d5e563b83cc29471fa114366e6806bc06bc7a25fd59641e41445327836"}, - {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:721c76e84fe669be19c5791da68232ca2e05ba5185575086e384352e2c309597"}, - {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82d8fd25b7f4675d0c47cf95b594d4e7b158aca33b76aa63d07186e13c0e0ab7"}, - {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3daeac64d5b371dea99714f08ffc2c208522ec6b06fbc7866a450dd446f5c0f"}, - {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dccab8d5fa1ef9bfba0590ecf4d46df048d18ffe3eec01eeb73a42e0d9e7a8ba"}, - {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:aaf27faa992bfee0264dc1f03f4c75e9fcdda66a519db6b957a3f826e285cf12"}, - {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:eb30abc20df9ab0814b5a2524f23d75dcf83cde762c161917a2b4b7b55b1e518"}, - {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:c72fbbe68c6f32f251bdc08b8611c7b3060612236e960ef848e0a517ddbe76c5"}, - {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:982bb1e8b4ffda883b3d0a521e23abcd6fd17418f6d2c4118d257a10199c0ce3"}, - {file = "charset_normalizer-3.4.2-cp39-cp39-win32.whl", hash = "sha256:43e0933a0eff183ee85833f341ec567c0980dae57c464d8a508e1b2ceb336471"}, - {file = "charset_normalizer-3.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:d11b54acf878eef558599658b0ffca78138c8c3655cf4f3a4a673c437e67732e"}, - {file = "charset_normalizer-3.4.2-py3-none-any.whl", hash = "sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0"}, - {file = "charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:fb7f67a1bfa6e40b438170ebdc8158b78dc465a5a67b6dde178a46987b244a72"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cc9370a2da1ac13f0153780040f465839e6cccb4a1e44810124b4e22483c93fe"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:07a0eae9e2787b586e129fdcbe1af6997f8d0e5abaa0bc98c0e20e124d67e601"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:74d77e25adda8581ffc1c720f1c81ca082921329452eba58b16233ab1842141c"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d0e909868420b7049dafd3a31d45125b31143eec59235311fc4c57ea26a4acd2"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c6f162aabe9a91a309510d74eeb6507fab5fff92337a15acbe77753d88d9dcf0"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4ca4c094de7771a98d7fbd67d9e5dbf1eb73efa4f744a730437d8a3a5cf994f0"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:02425242e96bcf29a49711b0ca9f37e451da7c70562bc10e8ed992a5a7a25cc0"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:78deba4d8f9590fe4dae384aeff04082510a709957e968753ff3c48399f6f92a"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-win32.whl", hash = "sha256:d79c198e27580c8e958906f803e63cddb77653731be08851c7df0b1a14a8fc0f"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-win_amd64.whl", hash = "sha256:c6e490913a46fa054e03699c70019ab869e990270597018cef1d8562132c2669"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b256ee2e749283ef3ddcff51a675ff43798d92d746d1a6e4631bf8c707d22d0b"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:13faeacfe61784e2559e690fc53fa4c5ae97c6fcedb8eb6fb8d0a15b475d2c64"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:00237675befef519d9af72169d8604a067d92755e84fe76492fef5441db05b91"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:585f3b2a80fbd26b048a0be90c5aae8f06605d3c92615911c3a2b03a8a3b796f"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e78314bdc32fa80696f72fa16dc61168fda4d6a0c014e0380f9d02f0e5d8a07"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:96b2b3d1a83ad55310de8c7b4a2d04d9277d5591f40761274856635acc5fcb30"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:939578d9d8fd4299220161fdd76e86c6a251987476f5243e8864a7844476ba14"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:fd10de089bcdcd1be95a2f73dbe6254798ec1bda9f450d5828c96f93e2536b9c"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1e8ac75d72fa3775e0b7cb7e4629cec13b7514d928d15ef8ea06bca03ef01cae"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-win32.whl", hash = "sha256:6cf8fd4c04756b6b60146d98cd8a77d0cdae0e1ca20329da2ac85eed779b6849"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-win_amd64.whl", hash = "sha256:31a9a6f775f9bcd865d88ee350f0ffb0e25936a7f930ca98995c05abf1faf21c"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e28e334d3ff134e88989d90ba04b47d84382a828c061d0d1027b1b12a62b39b1"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0cacf8f7297b0c4fcb74227692ca46b4a5852f8f4f24b3c766dd94a1075c4884"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c6fd51128a41297f5409deab284fecbe5305ebd7e5a1f959bee1c054622b7018"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3cfb2aad70f2c6debfbcb717f23b7eb55febc0bb23dcffc0f076009da10c6392"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1606f4a55c0fd363d754049cdf400175ee96c992b1f8018b993941f221221c5f"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:027b776c26d38b7f15b26a5da1044f376455fb3766df8fc38563b4efbc515154"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:42e5088973e56e31e4fa58eb6bd709e42fc03799c11c42929592889a2e54c491"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:cc34f233c9e71701040d772aa7490318673aa7164a0efe3172b2981218c26d93"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:320e8e66157cc4e247d9ddca8e21f427efc7a04bbd0ac8a9faf56583fa543f9f"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-win32.whl", hash = "sha256:fb6fecfd65564f208cbf0fba07f107fb661bcd1a7c389edbced3f7a493f70e37"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-win_amd64.whl", hash = "sha256:86df271bf921c2ee3818f0522e9a5b8092ca2ad8b065ece5d7d9d0e9f4849bcc"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:14c2a87c65b351109f6abfc424cab3927b3bdece6f706e4d12faaf3d52ee5efe"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41d1fc408ff5fdfb910200ec0e74abc40387bccb3252f3f27c0676731df2b2c8"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1bb60174149316da1c35fa5233681f7c0f9f514509b8e399ab70fea5f17e45c9"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:30d006f98569de3459c2fc1f2acde170b7b2bd265dc1943e87e1a4efe1b67c31"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:416175faf02e4b0810f1f38bcb54682878a4af94059a1cd63b8747244420801f"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6aab0f181c486f973bc7262a97f5aca3ee7e1437011ef0c2ec04b5a11d16c927"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabf8315679312cfa71302f9bd509ded4f2f263fb5b765cf1433b39106c3cc9"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:bd28b817ea8c70215401f657edef3a8aa83c29d447fb0b622c35403780ba11d5"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:18343b2d246dc6761a249ba1fb13f9ee9a2bcd95decc767319506056ea4ad4dc"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-win32.whl", hash = "sha256:6fb70de56f1859a3f71261cbe41005f56a7842cc348d3aeb26237560bfa5e0ce"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-win_amd64.whl", hash = "sha256:cf1ebb7d78e1ad8ec2a8c4732c7be2e736f6e5123a4146c5b89c9d1f585f8cef"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3cd35b7e8aedeb9e34c41385fda4f73ba609e561faedfae0a9e75e44ac558a15"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b89bc04de1d83006373429975f8ef9e7932534b8cc9ca582e4db7d20d91816db"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2001a39612b241dae17b4687898843f254f8748b796a2e16f1051a17078d991d"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8dcfc373f888e4fb39a7bc57e93e3b845e7f462dacc008d9749568b1c4ece096"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18b97b8404387b96cdbd30ad660f6407799126d26a39ca65729162fd810a99aa"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ccf600859c183d70eb47e05a44cd80a4ce77394d1ac0f79dbd2dd90a69a3a049"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:53cd68b185d98dde4ad8990e56a58dea83a4162161b1ea9272e5c9182ce415e0"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:30a96e1e1f865f78b030d65241c1ee850cdf422d869e9028e2fc1d5e4db73b92"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d716a916938e03231e86e43782ca7878fb602a125a91e7acb8b5112e2e96ac16"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-win32.whl", hash = "sha256:c6dbd0ccdda3a2ba7c2ecd9d77b37f3b5831687d8dc1b6ca5f56a4880cc7b7ce"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-win_amd64.whl", hash = "sha256:73dc19b562516fc9bcf6e5d6e596df0b4eb98d87e4f79f3ae71840e6ed21361c"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0f2be7e0cf7754b9a30eb01f4295cc3d4358a479843b31f328afd210e2c7598c"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c60e092517a73c632ec38e290eba714e9627abe9d301c8c8a12ec32c314a2a4b"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:252098c8c7a873e17dd696ed98bbe91dbacd571da4b87df3736768efa7a792e4"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3653fad4fe3ed447a596ae8638b437f827234f01a8cd801842e43f3d0a6b281b"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8999f965f922ae054125286faf9f11bc6932184b93011d138925a1773830bbe9"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:d95bfb53c211b57198bb91c46dd5a2d8018b3af446583aab40074bf7988401cb"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:5b413b0b1bfd94dbf4023ad6945889f374cd24e3f62de58d6bb102c4d9ae534a"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:b5e3b2d152e74e100a9e9573837aba24aab611d39428ded46f4e4022ea7d1942"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:a2d08ac246bb48479170408d6c19f6385fa743e7157d716e144cad849b2dd94b"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-win32.whl", hash = "sha256:ec557499516fc90fd374bf2e32349a2887a876fbf162c160e3c01b6849eaf557"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:5d8d01eac18c423815ed4f4a2ec3b439d654e55ee4ad610e153cf02faf67ea40"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:70bfc5f2c318afece2f5838ea5e4c3febada0be750fcf4775641052bbba14d05"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:23b6b24d74478dc833444cbd927c338349d6ae852ba53a0d02a2de1fce45b96e"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:34a7f768e3f985abdb42841e20e17b330ad3aaf4bb7e7aeeb73db2e70f077b99"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fb731e5deb0c7ef82d698b0f4c5bb724633ee2a489401594c5c88b02e6cb15f7"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:257f26fed7d7ff59921b78244f3cd93ed2af1800ff048c33f624c87475819dd7"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1ef99f0456d3d46a50945c98de1774da86f8e992ab5c77865ea8b8195341fc19"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:2c322db9c8c89009a990ef07c3bcc9f011a3269bc06782f916cd3d9eed7c9312"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:511729f456829ef86ac41ca78c63a5cb55240ed23b4b737faca0eb1abb1c41bc"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:88ab34806dea0671532d3f82d82b85e8fc23d7b2dd12fa837978dad9bb392a34"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-win32.whl", hash = "sha256:16a8770207946ac75703458e2c743631c79c59c5890c80011d536248f8eaa432"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:d22dbedd33326a4a5190dd4fe9e9e693ef12160c77382d9e87919bce54f3d4ca"}, + {file = "charset_normalizer-3.4.3-py3-none-any.whl", hash = "sha256:ce571ab16d890d23b5c278547ba694193a45011ff86a9162a71307ed9f86759a"}, + {file = "charset_normalizer-3.4.3.tar.gz", hash = "sha256:6fce4b8500244f6fcb71465d4a4930d132ba9ab8e71a7859e6a5d59851068d14"}, ] [[package]] @@ -530,100 +517,100 @@ typing-extensions = "*" [[package]] name = "coverage" -version = "7.10.2" +version = "7.10.3" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.9" groups = ["unit"] files = [ - {file = "coverage-7.10.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:79f0283ab5e6499fd5fe382ca3d62afa40fb50ff227676a3125d18af70eabf65"}, - {file = "coverage-7.10.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e4545e906f595ee8ab8e03e21be20d899bfc06647925bc5b224ad7e8c40e08b8"}, - {file = "coverage-7.10.2-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:ae385e1d58fbc6a9b1c315e5510ac52281e271478b45f92ca9b5ad42cf39643f"}, - {file = "coverage-7.10.2-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6f0cbe5f7dd19f3a32bac2251b95d51c3b89621ac88a2648096ce40f9a5aa1e7"}, - {file = "coverage-7.10.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fd17f427f041f6b116dc90b4049c6f3e1230524407d00daa2d8c7915037b5947"}, - {file = "coverage-7.10.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7f10ca4cde7b466405cce0a0e9971a13eb22e57a5ecc8b5f93a81090cc9c7eb9"}, - {file = "coverage-7.10.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3b990df23dd51dccce26d18fb09fd85a77ebe46368f387b0ffba7a74e470b31b"}, - {file = "coverage-7.10.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cc3902584d25c7eef57fb38f440aa849a26a3a9f761a029a72b69acfca4e31f8"}, - {file = "coverage-7.10.2-cp310-cp310-win32.whl", hash = "sha256:9dd37e9ac00d5eb72f38ed93e3cdf2280b1dbda3bb9b48c6941805f265ad8d87"}, - {file = "coverage-7.10.2-cp310-cp310-win_amd64.whl", hash = "sha256:99d16f15cb5baf0729354c5bd3080ae53847a4072b9ba1e10957522fb290417f"}, - {file = "coverage-7.10.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c3b210d79925a476dfc8d74c7d53224888421edebf3a611f3adae923e212b27"}, - {file = "coverage-7.10.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bf67d1787cd317c3f8b2e4c6ed1ae93497be7e30605a0d32237ac37a37a8a322"}, - {file = "coverage-7.10.2-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:069b779d03d458602bc0e27189876e7d8bdf6b24ac0f12900de22dd2154e6ad7"}, - {file = "coverage-7.10.2-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:4c2de4cb80b9990e71c62c2d3e9f3ec71b804b1f9ca4784ec7e74127e0f42468"}, - {file = "coverage-7.10.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:75bf7ab2374a7eb107602f1e07310cda164016cd60968abf817b7a0b5703e288"}, - {file = "coverage-7.10.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3f37516458ec1550815134937f73d6d15b434059cd10f64678a2068f65c62406"}, - {file = "coverage-7.10.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:de3c6271c482c250d3303fb5c6bdb8ca025fff20a67245e1425df04dc990ece9"}, - {file = "coverage-7.10.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:98a838101321ac3089c9bb1d4bfa967e8afed58021fda72d7880dc1997f20ae1"}, - {file = "coverage-7.10.2-cp311-cp311-win32.whl", hash = "sha256:f2a79145a531a0e42df32d37be5af069b4a914845b6f686590739b786f2f7bce"}, - {file = "coverage-7.10.2-cp311-cp311-win_amd64.whl", hash = "sha256:e4f5f1320f8ee0d7cfa421ceb257bef9d39fd614dd3ddcfcacd284d4824ed2c2"}, - {file = "coverage-7.10.2-cp311-cp311-win_arm64.whl", hash = "sha256:d8f2d83118f25328552c728b8e91babf93217db259ca5c2cd4dd4220b8926293"}, - {file = "coverage-7.10.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:890ad3a26da9ec7bf69255b9371800e2a8da9bc223ae5d86daeb940b42247c83"}, - {file = "coverage-7.10.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:38fd1ccfca7838c031d7a7874d4353e2f1b98eb5d2a80a2fe5732d542ae25e9c"}, - {file = "coverage-7.10.2-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:76c1ffaaf4f6f0f6e8e9ca06f24bb6454a7a5d4ced97a1bc466f0d6baf4bd518"}, - {file = "coverage-7.10.2-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:86da8a3a84b79ead5c7d0e960c34f580bc3b231bb546627773a3f53c532c2f21"}, - {file = "coverage-7.10.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:99cef9731c8a39801830a604cc53c93c9e57ea8b44953d26589499eded9576e0"}, - {file = "coverage-7.10.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ea58b112f2966a8b91eb13f5d3b1f8bb43c180d624cd3283fb33b1cedcc2dd75"}, - {file = "coverage-7.10.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:20f405188d28da9522b7232e51154e1b884fc18d0b3a10f382d54784715bbe01"}, - {file = "coverage-7.10.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:64586ce42bbe0da4d9f76f97235c545d1abb9b25985a8791857690f96e23dc3b"}, - {file = "coverage-7.10.2-cp312-cp312-win32.whl", hash = "sha256:bc2e69b795d97ee6d126e7e22e78a509438b46be6ff44f4dccbb5230f550d340"}, - {file = "coverage-7.10.2-cp312-cp312-win_amd64.whl", hash = "sha256:adda2268b8cf0d11f160fad3743b4dfe9813cd6ecf02c1d6397eceaa5b45b388"}, - {file = "coverage-7.10.2-cp312-cp312-win_arm64.whl", hash = "sha256:164429decd0d6b39a0582eaa30c67bf482612c0330572343042d0ed9e7f15c20"}, - {file = "coverage-7.10.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:aca7b5645afa688de6d4f8e89d30c577f62956fefb1bad021490d63173874186"}, - {file = "coverage-7.10.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:96e5921342574a14303dfdb73de0019e1ac041c863743c8fe1aa6c2b4a257226"}, - {file = "coverage-7.10.2-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:11333094c1bff621aa811b67ed794865cbcaa99984dedea4bd9cf780ad64ecba"}, - {file = "coverage-7.10.2-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6eb586fa7d2aee8d65d5ae1dd71414020b2f447435c57ee8de8abea0a77d5074"}, - {file = "coverage-7.10.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2d358f259d8019d4ef25d8c5b78aca4c7af25e28bd4231312911c22a0e824a57"}, - {file = "coverage-7.10.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5250bda76e30382e0a2dcd68d961afcab92c3a7613606e6269855c6979a1b0bb"}, - {file = "coverage-7.10.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:a91e027d66eff214d88d9afbe528e21c9ef1ecdf4956c46e366c50f3094696d0"}, - {file = "coverage-7.10.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:228946da741558904e2c03ce870ba5efd9cd6e48cbc004d9a27abee08100a15a"}, - {file = "coverage-7.10.2-cp313-cp313-win32.whl", hash = "sha256:95e23987b52d02e7c413bf2d6dc6288bd5721beb518052109a13bfdc62c8033b"}, - {file = "coverage-7.10.2-cp313-cp313-win_amd64.whl", hash = "sha256:f35481d42c6d146d48ec92d4e239c23f97b53a3f1fbd2302e7c64336f28641fe"}, - {file = "coverage-7.10.2-cp313-cp313-win_arm64.whl", hash = "sha256:65b451949cb789c346f9f9002441fc934d8ccedcc9ec09daabc2139ad13853f7"}, - {file = "coverage-7.10.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:e8415918856a3e7d57a4e0ad94651b761317de459eb74d34cc1bb51aad80f07e"}, - {file = "coverage-7.10.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f287a25a8ca53901c613498e4a40885b19361a2fe8fbfdbb7f8ef2cad2a23f03"}, - {file = "coverage-7.10.2-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:75cc1a3f8c88c69bf16a871dab1fe5a7303fdb1e9f285f204b60f1ee539b8fc0"}, - {file = "coverage-7.10.2-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:ca07fa78cc9d26bc8c4740de1abd3489cf9c47cc06d9a8ab3d552ff5101af4c0"}, - {file = "coverage-7.10.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c2e117e64c26300032755d4520cd769f2623cde1a1d1c3515b05a3b8add0ade1"}, - {file = "coverage-7.10.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:daaf98009977f577b71f8800208f4d40d4dcf5c2db53d4d822787cdc198d76e1"}, - {file = "coverage-7.10.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:ea8d8fe546c528535c761ba424410bbeb36ba8a0f24be653e94b70c93fd8a8ca"}, - {file = "coverage-7.10.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:fe024d40ac31eb8d5aae70215b41dafa264676caa4404ae155f77d2fa95c37bb"}, - {file = "coverage-7.10.2-cp313-cp313t-win32.whl", hash = "sha256:8f34b09f68bdadec122ffad312154eda965ade433559cc1eadd96cca3de5c824"}, - {file = "coverage-7.10.2-cp313-cp313t-win_amd64.whl", hash = "sha256:71d40b3ac0f26fa9ffa6ee16219a714fed5c6ec197cdcd2018904ab5e75bcfa3"}, - {file = "coverage-7.10.2-cp313-cp313t-win_arm64.whl", hash = "sha256:abb57fdd38bf6f7dcc66b38dafb7af7c5fdc31ac6029ce373a6f7f5331d6f60f"}, - {file = "coverage-7.10.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:a3e853cc04987c85ec410905667eed4bf08b1d84d80dfab2684bb250ac8da4f6"}, - {file = "coverage-7.10.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0100b19f230df72c90fdb36db59d3f39232391e8d89616a7de30f677da4f532b"}, - {file = "coverage-7.10.2-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:9c1cd71483ea78331bdfadb8dcec4f4edfb73c7002c1206d8e0af6797853f5be"}, - {file = "coverage-7.10.2-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9f75dbf4899e29a37d74f48342f29279391668ef625fdac6d2f67363518056a1"}, - {file = "coverage-7.10.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a7df481e7508de1c38b9b8043da48d94931aefa3e32b47dd20277e4978ed5b95"}, - {file = "coverage-7.10.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:835f39e618099325e7612b3406f57af30ab0a0af350490eff6421e2e5f608e46"}, - {file = "coverage-7.10.2-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:12e52b5aa00aa720097d6947d2eb9e404e7c1101ad775f9661ba165ed0a28303"}, - {file = "coverage-7.10.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:718044729bf1fe3e9eb9f31b52e44ddae07e434ec050c8c628bf5adc56fe4bdd"}, - {file = "coverage-7.10.2-cp314-cp314-win32.whl", hash = "sha256:f256173b48cc68486299d510a3e729a96e62c889703807482dbf56946befb5c8"}, - {file = "coverage-7.10.2-cp314-cp314-win_amd64.whl", hash = "sha256:2e980e4179f33d9b65ac4acb86c9c0dde904098853f27f289766657ed16e07b3"}, - {file = "coverage-7.10.2-cp314-cp314-win_arm64.whl", hash = "sha256:14fb5b6641ab5b3c4161572579f0f2ea8834f9d3af2f7dd8fbaecd58ef9175cc"}, - {file = "coverage-7.10.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:e96649ac34a3d0e6491e82a2af71098e43be2874b619547c3282fc11d3840a4b"}, - {file = "coverage-7.10.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1a2e934e9da26341d342d30bfe91422bbfdb3f1f069ec87f19b2909d10d8dcc4"}, - {file = "coverage-7.10.2-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:651015dcd5fd9b5a51ca79ece60d353cacc5beaf304db750407b29c89f72fe2b"}, - {file = "coverage-7.10.2-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:81bf6a32212f9f66da03d63ecb9cd9bd48e662050a937db7199dbf47d19831de"}, - {file = "coverage-7.10.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d800705f6951f75a905ea6feb03fff8f3ea3468b81e7563373ddc29aa3e5d1ca"}, - {file = "coverage-7.10.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:248b5394718e10d067354448dc406d651709c6765669679311170da18e0e9af8"}, - {file = "coverage-7.10.2-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:5c61675a922b569137cf943770d7ad3edd0202d992ce53ac328c5ff68213ccf4"}, - {file = "coverage-7.10.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:52d708b5fd65589461381fa442d9905f5903d76c086c6a4108e8e9efdca7a7ed"}, - {file = "coverage-7.10.2-cp314-cp314t-win32.whl", hash = "sha256:916369b3b914186b2c5e5ad2f7264b02cff5df96cdd7cdad65dccd39aa5fd9f0"}, - {file = "coverage-7.10.2-cp314-cp314t-win_amd64.whl", hash = "sha256:5b9d538e8e04916a5df63052d698b30c74eb0174f2ca9cd942c981f274a18eaf"}, - {file = "coverage-7.10.2-cp314-cp314t-win_arm64.whl", hash = "sha256:04c74f9ef1f925456a9fd23a7eef1103126186d0500ef9a0acb0bd2514bdc7cc"}, - {file = "coverage-7.10.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:765b13b164685a2f8b2abef867ad07aebedc0e090c757958a186f64e39d63dbd"}, - {file = "coverage-7.10.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a219b70100500d0c7fd3ebb824a3302efb6b1a122baa9d4eb3f43df8f0b3d899"}, - {file = "coverage-7.10.2-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:e33e79a219105aa315439ee051bd50b6caa705dc4164a5aba6932c8ac3ce2d98"}, - {file = "coverage-7.10.2-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:bc3945b7bad33957a9eca16e9e5eae4b17cb03173ef594fdaad228f4fc7da53b"}, - {file = "coverage-7.10.2-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9bdff88e858ee608a924acfad32a180d2bf6e13e059d6a7174abbae075f30436"}, - {file = "coverage-7.10.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:44329cbed24966c0b49acb386352c9722219af1f0c80db7f218af7793d251902"}, - {file = "coverage-7.10.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:be127f292496d0fbe20d8025f73221b36117b3587f890346e80a13b310712982"}, - {file = "coverage-7.10.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:6c031da749a05f7a01447dd7f47beedb498edd293e31e1878c0d52db18787df0"}, - {file = "coverage-7.10.2-cp39-cp39-win32.whl", hash = "sha256:22aca3e691c7709c5999ccf48b7a8ff5cf5a8bd6fe9b36efbd4993f5a36b2fcf"}, - {file = "coverage-7.10.2-cp39-cp39-win_amd64.whl", hash = "sha256:c7195444b932356055a8e287fa910bf9753a84a1bc33aeb3770e8fca521e032e"}, - {file = "coverage-7.10.2-py3-none-any.whl", hash = "sha256:95db3750dd2e6e93d99fa2498f3a1580581e49c494bddccc6f85c5c21604921f"}, - {file = "coverage-7.10.2.tar.gz", hash = "sha256:5d6e6d84e6dd31a8ded64759626627247d676a23c1b892e1326f7c55c8d61055"}, + {file = "coverage-7.10.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:53808194afdf948c462215e9403cca27a81cf150d2f9b386aee4dab614ae2ffe"}, + {file = "coverage-7.10.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f4d1b837d1abf72187a61645dbf799e0d7705aa9232924946e1f57eb09a3bf00"}, + {file = "coverage-7.10.3-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:2a90dd4505d3cc68b847ab10c5ee81822a968b5191664e8a0801778fa60459fa"}, + {file = "coverage-7.10.3-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:d52989685ff5bf909c430e6d7f6550937bc6d6f3e6ecb303c97a86100efd4596"}, + {file = "coverage-7.10.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bdb558a1d97345bde3a9f4d3e8d11c9e5611f748646e9bb61d7d612a796671b5"}, + {file = "coverage-7.10.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c9e6331a8f09cb1fc8bda032752af03c366870b48cce908875ba2620d20d0ad4"}, + {file = "coverage-7.10.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:992f48bf35b720e174e7fae916d943599f1a66501a2710d06c5f8104e0756ee1"}, + {file = "coverage-7.10.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c5595fc4ad6a39312c786ec3326d7322d0cf10e3ac6a6df70809910026d67cfb"}, + {file = "coverage-7.10.3-cp310-cp310-win32.whl", hash = "sha256:9e92fa1f2bd5a57df9d00cf9ce1eb4ef6fccca4ceabec1c984837de55329db34"}, + {file = "coverage-7.10.3-cp310-cp310-win_amd64.whl", hash = "sha256:b96524d6e4a3ce6a75c56bb15dbd08023b0ae2289c254e15b9fbdddf0c577416"}, + {file = "coverage-7.10.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f2ff2e2afdf0d51b9b8301e542d9c21a8d084fd23d4c8ea2b3a1b3c96f5f7397"}, + {file = "coverage-7.10.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:18ecc5d1b9a8c570f6c9b808fa9a2b16836b3dd5414a6d467ae942208b095f85"}, + {file = "coverage-7.10.3-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1af4461b25fe92889590d438905e1fc79a95680ec2a1ff69a591bb3fdb6c7157"}, + {file = "coverage-7.10.3-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:3966bc9a76b09a40dc6063c8b10375e827ea5dfcaffae402dd65953bef4cba54"}, + {file = "coverage-7.10.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:205a95b87ef4eb303b7bc5118b47b6b6604a644bcbdb33c336a41cfc0a08c06a"}, + {file = "coverage-7.10.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5b3801b79fb2ad61e3c7e2554bab754fc5f105626056980a2b9cf3aef4f13f84"}, + {file = "coverage-7.10.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:b0dc69c60224cda33d384572da945759756e3f06b9cdac27f302f53961e63160"}, + {file = "coverage-7.10.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a83d4f134bab2c7ff758e6bb1541dd72b54ba295ced6a63d93efc2e20cb9b124"}, + {file = "coverage-7.10.3-cp311-cp311-win32.whl", hash = "sha256:54e409dd64e5302b2a8fdf44ec1c26f47abd1f45a2dcf67bd161873ee05a59b8"}, + {file = "coverage-7.10.3-cp311-cp311-win_amd64.whl", hash = "sha256:30c601610a9b23807c5e9e2e442054b795953ab85d525c3de1b1b27cebeb2117"}, + {file = "coverage-7.10.3-cp311-cp311-win_arm64.whl", hash = "sha256:dabe662312a97958e932dee056f2659051d822552c0b866823e8ba1c2fe64770"}, + {file = "coverage-7.10.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:449c1e2d3a84d18bd204258a897a87bc57380072eb2aded6a5b5226046207b42"}, + {file = "coverage-7.10.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1d4f9ce50b9261ad196dc2b2e9f1fbbee21651b54c3097a25ad783679fd18294"}, + {file = "coverage-7.10.3-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:4dd4564207b160d0d45c36a10bc0a3d12563028e8b48cd6459ea322302a156d7"}, + {file = "coverage-7.10.3-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:5ca3c9530ee072b7cb6a6ea7b640bcdff0ad3b334ae9687e521e59f79b1d0437"}, + {file = "coverage-7.10.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b6df359e59fa243c9925ae6507e27f29c46698359f45e568fd51b9315dbbe587"}, + {file = "coverage-7.10.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a181e4c2c896c2ff64c6312db3bda38e9ade2e1aa67f86a5628ae85873786cea"}, + {file = "coverage-7.10.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a374d4e923814e8b72b205ef6b3d3a647bb50e66f3558582eda074c976923613"}, + {file = "coverage-7.10.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:daeefff05993e5e8c6e7499a8508e7bd94502b6b9a9159c84fd1fe6bce3151cb"}, + {file = "coverage-7.10.3-cp312-cp312-win32.whl", hash = "sha256:187ecdcac21f9636d570e419773df7bd2fda2e7fa040f812e7f95d0bddf5f79a"}, + {file = "coverage-7.10.3-cp312-cp312-win_amd64.whl", hash = "sha256:4a50ad2524ee7e4c2a95e60d2b0b83283bdfc745fe82359d567e4f15d3823eb5"}, + {file = "coverage-7.10.3-cp312-cp312-win_arm64.whl", hash = "sha256:c112f04e075d3495fa3ed2200f71317da99608cbb2e9345bdb6de8819fc30571"}, + {file = "coverage-7.10.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b99e87304ffe0eb97c5308447328a584258951853807afdc58b16143a530518a"}, + {file = "coverage-7.10.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4af09c7574d09afbc1ea7da9dcea23665c01f3bc1b1feb061dac135f98ffc53a"}, + {file = "coverage-7.10.3-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:488e9b50dc5d2aa9521053cfa706209e5acf5289e81edc28291a24f4e4488f46"}, + {file = "coverage-7.10.3-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:913ceddb4289cbba3a310704a424e3fb7aac2bc0c3a23ea473193cb290cf17d4"}, + {file = "coverage-7.10.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b1f91cbc78c7112ab84ed2a8defbccd90f888fcae40a97ddd6466b0bec6ae8a"}, + {file = "coverage-7.10.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b0bac054d45af7cd938834b43a9878b36ea92781bcb009eab040a5b09e9927e3"}, + {file = "coverage-7.10.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:fe72cbdd12d9e0f4aca873fa6d755e103888a7f9085e4a62d282d9d5b9f7928c"}, + {file = "coverage-7.10.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c1e2e927ab3eadd7c244023927d646e4c15c65bb2ac7ae3c3e9537c013700d21"}, + {file = "coverage-7.10.3-cp313-cp313-win32.whl", hash = "sha256:24d0c13de473b04920ddd6e5da3c08831b1170b8f3b17461d7429b61cad59ae0"}, + {file = "coverage-7.10.3-cp313-cp313-win_amd64.whl", hash = "sha256:3564aae76bce4b96e2345cf53b4c87e938c4985424a9be6a66ee902626edec4c"}, + {file = "coverage-7.10.3-cp313-cp313-win_arm64.whl", hash = "sha256:f35580f19f297455f44afcd773c9c7a058e52eb6eb170aa31222e635f2e38b87"}, + {file = "coverage-7.10.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:07009152f497a0464ffdf2634586787aea0e69ddd023eafb23fc38267db94b84"}, + {file = "coverage-7.10.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:8dd2ba5f0c7e7e8cc418be2f0c14c4d9e3f08b8fb8e4c0f83c2fe87d03eb655e"}, + {file = "coverage-7.10.3-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1ae22b97003c74186e034a93e4f946c75fad8c0ce8d92fbbc168b5e15ee2841f"}, + {file = "coverage-7.10.3-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:eb329f1046888a36b1dc35504d3029e1dd5afe2196d94315d18c45ee380f67d5"}, + {file = "coverage-7.10.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ce01048199a91f07f96ca3074b0c14021f4fe7ffd29a3e6a188ac60a5c3a4af8"}, + {file = "coverage-7.10.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:08b989a06eb9dfacf96d42b7fb4c9a22bafa370d245dc22fa839f2168c6f9fa1"}, + {file = "coverage-7.10.3-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:669fe0d4e69c575c52148511029b722ba8d26e8a3129840c2ce0522e1452b256"}, + {file = "coverage-7.10.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:3262d19092771c83f3413831d9904b1ccc5f98da5de4ffa4ad67f5b20c7aaf7b"}, + {file = "coverage-7.10.3-cp313-cp313t-win32.whl", hash = "sha256:cc0ee4b2ccd42cab7ee6be46d8a67d230cb33a0a7cd47a58b587a7063b6c6b0e"}, + {file = "coverage-7.10.3-cp313-cp313t-win_amd64.whl", hash = "sha256:03db599f213341e2960430984e04cf35fb179724e052a3ee627a068653cf4a7c"}, + {file = "coverage-7.10.3-cp313-cp313t-win_arm64.whl", hash = "sha256:46eae7893ba65f53c71284585a262f083ef71594f05ec5c85baf79c402369098"}, + {file = "coverage-7.10.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:bce8b8180912914032785850d8f3aacb25ec1810f5f54afc4a8b114e7a9b55de"}, + {file = "coverage-7.10.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:07790b4b37d56608536f7c1079bd1aa511567ac2966d33d5cec9cf520c50a7c8"}, + {file = "coverage-7.10.3-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:e79367ef2cd9166acedcbf136a458dfe9a4a2dd4d1ee95738fb2ee581c56f667"}, + {file = "coverage-7.10.3-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:419d2a0f769f26cb1d05e9ccbc5eab4cb5d70231604d47150867c07822acbdf4"}, + {file = "coverage-7.10.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee221cf244757cdc2ac882e3062ab414b8464ad9c884c21e878517ea64b3fa26"}, + {file = "coverage-7.10.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c2079d8cdd6f7373d628e14b3357f24d1db02c9dc22e6a007418ca7a2be0435a"}, + {file = "coverage-7.10.3-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:bd8df1f83c0703fa3ca781b02d36f9ec67ad9cb725b18d486405924f5e4270bd"}, + {file = "coverage-7.10.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6b4e25e0fa335c8aa26e42a52053f3786a61cc7622b4d54ae2dad994aa754fec"}, + {file = "coverage-7.10.3-cp314-cp314-win32.whl", hash = "sha256:d7c3d02c2866deb217dce664c71787f4b25420ea3eaf87056f44fb364a3528f5"}, + {file = "coverage-7.10.3-cp314-cp314-win_amd64.whl", hash = "sha256:9c8916d44d9e0fe6cdb2227dc6b0edd8bc6c8ef13438bbbf69af7482d9bb9833"}, + {file = "coverage-7.10.3-cp314-cp314-win_arm64.whl", hash = "sha256:1007d6a2b3cf197c57105cc1ba390d9ff7f0bee215ced4dea530181e49c65ab4"}, + {file = "coverage-7.10.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:ebc8791d346410d096818788877d675ca55c91db87d60e8f477bd41c6970ffc6"}, + {file = "coverage-7.10.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1f4e4d8e75f6fd3c6940ebeed29e3d9d632e1f18f6fb65d33086d99d4d073241"}, + {file = "coverage-7.10.3-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:24581ed69f132b6225a31b0228ae4885731cddc966f8a33fe5987288bdbbbd5e"}, + {file = "coverage-7.10.3-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:ec151569ddfccbf71bac8c422dce15e176167385a00cd86e887f9a80035ce8a5"}, + {file = "coverage-7.10.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2ae8e7c56290b908ee817200c0b65929b8050bc28530b131fe7c6dfee3e7d86b"}, + {file = "coverage-7.10.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5fb742309766d7e48e9eb4dc34bc95a424707bc6140c0e7d9726e794f11b92a0"}, + {file = "coverage-7.10.3-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:c65e2a5b32fbe1e499f1036efa6eb9cb4ea2bf6f7168d0e7a5852f3024f471b1"}, + {file = "coverage-7.10.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d48d2cb07d50f12f4f18d2bb75d9d19e3506c26d96fffabf56d22936e5ed8f7c"}, + {file = "coverage-7.10.3-cp314-cp314t-win32.whl", hash = "sha256:dec0d9bc15ee305e09fe2cd1911d3f0371262d3cfdae05d79515d8cb712b4869"}, + {file = "coverage-7.10.3-cp314-cp314t-win_amd64.whl", hash = "sha256:424ea93a323aa0f7f01174308ea78bde885c3089ec1bef7143a6d93c3e24ef64"}, + {file = "coverage-7.10.3-cp314-cp314t-win_arm64.whl", hash = "sha256:f5983c132a62d93d71c9ef896a0b9bf6e6828d8d2ea32611f58684fba60bba35"}, + {file = "coverage-7.10.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:da749daa7e141985487e1ff90a68315b0845930ed53dc397f4ae8f8bab25b551"}, + {file = "coverage-7.10.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f3126fb6a47d287f461d9b1aa5d1a8c97034d1dffb4f452f2cf211289dae74ef"}, + {file = "coverage-7.10.3-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3da794db13cc27ca40e1ec8127945b97fab78ba548040047d54e7bfa6d442dca"}, + {file = "coverage-7.10.3-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:4e27bebbd184ef8d1c1e092b74a2b7109dcbe2618dce6e96b1776d53b14b3fe8"}, + {file = "coverage-7.10.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8fd4ee2580b9fefbd301b4f8f85b62ac90d1e848bea54f89a5748cf132782118"}, + {file = "coverage-7.10.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:6999920bdd73259ce11cabfc1307484f071ecc6abdb2ca58d98facbcefc70f16"}, + {file = "coverage-7.10.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:c3623f929db885fab100cb88220a5b193321ed37e03af719efdbaf5d10b6e227"}, + {file = "coverage-7.10.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:25b902c5e15dea056485d782e420bb84621cc08ee75d5131ecb3dbef8bd1365f"}, + {file = "coverage-7.10.3-cp39-cp39-win32.whl", hash = "sha256:f930a4d92b004b643183451fe9c8fe398ccf866ed37d172ebaccfd443a097f61"}, + {file = "coverage-7.10.3-cp39-cp39-win_amd64.whl", hash = "sha256:08e638a93c8acba13c7842953f92a33d52d73e410329acd472280d2a21a6c0e1"}, + {file = "coverage-7.10.3-py3-none-any.whl", hash = "sha256:416a8d74dc0adfd33944ba2f405897bab87b7e9e84a391e09d241956bd953ce1"}, + {file = "coverage-7.10.3.tar.gz", hash = "sha256:812ba9250532e4a823b070b0420a36499859542335af3dca8f47fc6aa1a05619"}, ] [package.dependencies] @@ -634,49 +621,49 @@ toml = ["tomli ; python_full_version <= \"3.11.0a6\""] [[package]] name = "cryptography" -version = "45.0.5" +version = "45.0.6" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false python-versions = "!=3.9.0,!=3.9.1,>=3.7" groups = ["charm-libs", "integration"] files = [ - {file = "cryptography-45.0.5-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:101ee65078f6dd3e5a028d4f19c07ffa4dd22cce6a20eaa160f8b5219911e7d8"}, - {file = "cryptography-45.0.5-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3a264aae5f7fbb089dbc01e0242d3b67dffe3e6292e1f5182122bdf58e65215d"}, - {file = "cryptography-45.0.5-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e74d30ec9c7cb2f404af331d5b4099a9b322a8a6b25c4632755c8757345baac5"}, - {file = "cryptography-45.0.5-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:3af26738f2db354aafe492fb3869e955b12b2ef2e16908c8b9cb928128d42c57"}, - {file = "cryptography-45.0.5-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e6c00130ed423201c5bc5544c23359141660b07999ad82e34e7bb8f882bb78e0"}, - {file = "cryptography-45.0.5-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:dd420e577921c8c2d31289536c386aaa30140b473835e97f83bc71ea9d2baf2d"}, - {file = "cryptography-45.0.5-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:d05a38884db2ba215218745f0781775806bde4f32e07b135348355fe8e4991d9"}, - {file = "cryptography-45.0.5-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:ad0caded895a00261a5b4aa9af828baede54638754b51955a0ac75576b831b27"}, - {file = "cryptography-45.0.5-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9024beb59aca9d31d36fcdc1604dd9bbeed0a55bface9f1908df19178e2f116e"}, - {file = "cryptography-45.0.5-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:91098f02ca81579c85f66df8a588c78f331ca19089763d733e34ad359f474174"}, - {file = "cryptography-45.0.5-cp311-abi3-win32.whl", hash = "sha256:926c3ea71a6043921050eaa639137e13dbe7b4ab25800932a8498364fc1abec9"}, - {file = "cryptography-45.0.5-cp311-abi3-win_amd64.whl", hash = "sha256:b85980d1e345fe769cfc57c57db2b59cff5464ee0c045d52c0df087e926fbe63"}, - {file = "cryptography-45.0.5-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:f3562c2f23c612f2e4a6964a61d942f891d29ee320edb62ff48ffb99f3de9ae8"}, - {file = "cryptography-45.0.5-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3fcfbefc4a7f332dece7272a88e410f611e79458fab97b5efe14e54fe476f4fd"}, - {file = "cryptography-45.0.5-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:460f8c39ba66af7db0545a8c6f2eabcbc5a5528fc1cf6c3fa9a1e44cec33385e"}, - {file = "cryptography-45.0.5-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:9b4cf6318915dccfe218e69bbec417fdd7c7185aa7aab139a2c0beb7468c89f0"}, - {file = "cryptography-45.0.5-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2089cc8f70a6e454601525e5bf2779e665d7865af002a5dec8d14e561002e135"}, - {file = "cryptography-45.0.5-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:0027d566d65a38497bc37e0dd7c2f8ceda73597d2ac9ba93810204f56f52ebc7"}, - {file = "cryptography-45.0.5-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:be97d3a19c16a9be00edf79dca949c8fa7eff621763666a145f9f9535a5d7f42"}, - {file = "cryptography-45.0.5-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:7760c1c2e1a7084153a0f68fab76e754083b126a47d0117c9ed15e69e2103492"}, - {file = "cryptography-45.0.5-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:6ff8728d8d890b3dda5765276d1bc6fb099252915a2cd3aff960c4c195745dd0"}, - {file = "cryptography-45.0.5-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:7259038202a47fdecee7e62e0fd0b0738b6daa335354396c6ddebdbe1206af2a"}, - {file = "cryptography-45.0.5-cp37-abi3-win32.whl", hash = "sha256:1e1da5accc0c750056c556a93c3e9cb828970206c68867712ca5805e46dc806f"}, - {file = "cryptography-45.0.5-cp37-abi3-win_amd64.whl", hash = "sha256:90cb0a7bb35959f37e23303b7eed0a32280510030daba3f7fdfbb65defde6a97"}, - {file = "cryptography-45.0.5-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:206210d03c1193f4e1ff681d22885181d47efa1ab3018766a7b32a7b3d6e6afd"}, - {file = "cryptography-45.0.5-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c648025b6840fe62e57107e0a25f604db740e728bd67da4f6f060f03017d5097"}, - {file = "cryptography-45.0.5-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:b8fa8b0a35a9982a3c60ec79905ba5bb090fc0b9addcfd3dc2dd04267e45f25e"}, - {file = "cryptography-45.0.5-pp310-pypy310_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:14d96584701a887763384f3c47f0ca7c1cce322aa1c31172680eb596b890ec30"}, - {file = "cryptography-45.0.5-pp310-pypy310_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:57c816dfbd1659a367831baca4b775b2a5b43c003daf52e9d57e1d30bc2e1b0e"}, - {file = "cryptography-45.0.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b9e38e0a83cd51e07f5a48ff9691cae95a79bea28fe4ded168a8e5c6c77e819d"}, - {file = "cryptography-45.0.5-pp311-pypy311_pp73-macosx_10_9_x86_64.whl", hash = "sha256:8c4a6ff8a30e9e3d38ac0539e9a9e02540ab3f827a3394f8852432f6b0ea152e"}, - {file = "cryptography-45.0.5-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:bd4c45986472694e5121084c6ebbd112aa919a25e783b87eb95953c9573906d6"}, - {file = "cryptography-45.0.5-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:982518cd64c54fcada9d7e5cf28eabd3ee76bd03ab18e08a48cad7e8b6f31b18"}, - {file = "cryptography-45.0.5-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:12e55281d993a793b0e883066f590c1ae1e802e3acb67f8b442e721e475e6463"}, - {file = "cryptography-45.0.5-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:5aa1e32983d4443e310f726ee4b071ab7569f58eedfdd65e9675484a4eb67bd1"}, - {file = "cryptography-45.0.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:e357286c1b76403dd384d938f93c46b2b058ed4dfcdce64a770f0537ed3feb6f"}, - {file = "cryptography-45.0.5.tar.gz", hash = "sha256:72e76caa004ab63accdf26023fccd1d087f6d90ec6048ff33ad0445abf7f605a"}, + {file = "cryptography-45.0.6-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:048e7ad9e08cf4c0ab07ff7f36cc3115924e22e2266e034450a890d9e312dd74"}, + {file = "cryptography-45.0.6-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:44647c5d796f5fc042bbc6d61307d04bf29bccb74d188f18051b635f20a9c75f"}, + {file = "cryptography-45.0.6-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e40b80ecf35ec265c452eea0ba94c9587ca763e739b8e559c128d23bff7ebbbf"}, + {file = "cryptography-45.0.6-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:00e8724bdad672d75e6f069b27970883179bd472cd24a63f6e620ca7e41cc0c5"}, + {file = "cryptography-45.0.6-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7a3085d1b319d35296176af31c90338eeb2ddac8104661df79f80e1d9787b8b2"}, + {file = "cryptography-45.0.6-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:1b7fa6a1c1188c7ee32e47590d16a5a0646270921f8020efc9a511648e1b2e08"}, + {file = "cryptography-45.0.6-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:275ba5cc0d9e320cd70f8e7b96d9e59903c815ca579ab96c1e37278d231fc402"}, + {file = "cryptography-45.0.6-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:f4028f29a9f38a2025abedb2e409973709c660d44319c61762202206ed577c42"}, + {file = "cryptography-45.0.6-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ee411a1b977f40bd075392c80c10b58025ee5c6b47a822a33c1198598a7a5f05"}, + {file = "cryptography-45.0.6-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:e2a21a8eda2d86bb604934b6b37691585bd095c1f788530c1fcefc53a82b3453"}, + {file = "cryptography-45.0.6-cp311-abi3-win32.whl", hash = "sha256:d063341378d7ee9c91f9d23b431a3502fc8bfacd54ef0a27baa72a0843b29159"}, + {file = "cryptography-45.0.6-cp311-abi3-win_amd64.whl", hash = "sha256:833dc32dfc1e39b7376a87b9a6a4288a10aae234631268486558920029b086ec"}, + {file = "cryptography-45.0.6-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:3436128a60a5e5490603ab2adbabc8763613f638513ffa7d311c900a8349a2a0"}, + {file = "cryptography-45.0.6-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0d9ef57b6768d9fa58e92f4947cea96ade1233c0e236db22ba44748ffedca394"}, + {file = "cryptography-45.0.6-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ea3c42f2016a5bbf71825537c2ad753f2870191134933196bee408aac397b3d9"}, + {file = "cryptography-45.0.6-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:20ae4906a13716139d6d762ceb3e0e7e110f7955f3bc3876e3a07f5daadec5f3"}, + {file = "cryptography-45.0.6-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2dac5ec199038b8e131365e2324c03d20e97fe214af051d20c49db129844e8b3"}, + {file = "cryptography-45.0.6-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:18f878a34b90d688982e43f4b700408b478102dd58b3e39de21b5ebf6509c301"}, + {file = "cryptography-45.0.6-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:5bd6020c80c5b2b2242d6c48487d7b85700f5e0038e67b29d706f98440d66eb5"}, + {file = "cryptography-45.0.6-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:eccddbd986e43014263eda489abbddfbc287af5cddfd690477993dbb31e31016"}, + {file = "cryptography-45.0.6-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:550ae02148206beb722cfe4ef0933f9352bab26b087af00e48fdfb9ade35c5b3"}, + {file = "cryptography-45.0.6-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5b64e668fc3528e77efa51ca70fadcd6610e8ab231e3e06ae2bab3b31c2b8ed9"}, + {file = "cryptography-45.0.6-cp37-abi3-win32.whl", hash = "sha256:780c40fb751c7d2b0c6786ceee6b6f871e86e8718a8ff4bc35073ac353c7cd02"}, + {file = "cryptography-45.0.6-cp37-abi3-win_amd64.whl", hash = "sha256:20d15aed3ee522faac1a39fbfdfee25d17b1284bafd808e1640a74846d7c4d1b"}, + {file = "cryptography-45.0.6-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:705bb7c7ecc3d79a50f236adda12ca331c8e7ecfbea51edd931ce5a7a7c4f012"}, + {file = "cryptography-45.0.6-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:826b46dae41a1155a0c0e66fafba43d0ede1dc16570b95e40c4d83bfcf0a451d"}, + {file = "cryptography-45.0.6-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:cc4d66f5dc4dc37b89cfef1bd5044387f7a1f6f0abb490815628501909332d5d"}, + {file = "cryptography-45.0.6-pp310-pypy310_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:f68f833a9d445cc49f01097d95c83a850795921b3f7cc6488731e69bde3288da"}, + {file = "cryptography-45.0.6-pp310-pypy310_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:3b5bf5267e98661b9b888a9250d05b063220dfa917a8203744454573c7eb79db"}, + {file = "cryptography-45.0.6-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:2384f2ab18d9be88a6e4f8972923405e2dbb8d3e16c6b43f15ca491d7831bd18"}, + {file = "cryptography-45.0.6-pp311-pypy311_pp73-macosx_10_9_x86_64.whl", hash = "sha256:fc022c1fa5acff6def2fc6d7819bbbd31ccddfe67d075331a65d9cfb28a20983"}, + {file = "cryptography-45.0.6-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:3de77e4df42ac8d4e4d6cdb342d989803ad37707cf8f3fbf7b088c9cbdd46427"}, + {file = "cryptography-45.0.6-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:599c8d7df950aa68baa7e98f7b73f4f414c9f02d0e8104a30c0182a07732638b"}, + {file = "cryptography-45.0.6-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:31a2b9a10530a1cb04ffd6aa1cd4d3be9ed49f7d77a4dafe198f3b382f41545c"}, + {file = "cryptography-45.0.6-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:e5b3dda1b00fb41da3af4c5ef3f922a200e33ee5ba0f0bc9ecf0b0c173958385"}, + {file = "cryptography-45.0.6-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:629127cfdcdc6806dfe234734d7cb8ac54edaf572148274fa377a7d3405b0043"}, + {file = "cryptography-45.0.6.tar.gz", hash = "sha256:5c966c732cf6e4a276ce83b6e4c729edda2df6929083a952cc7da973c539c719"}, ] [package.dependencies] @@ -689,7 +676,7 @@ nox = ["nox (>=2024.4.15)", "nox[uv] (>=2024.3.2) ; python_full_version >= \"3.8 pep8test = ["check-sdist ; python_full_version >= \"3.8.0\"", "click (>=8.0.1)", "mypy (>=1.4)", "ruff (>=0.3.6)"] sdist = ["build (>=1.0.0)"] ssh = ["bcrypt (>=3.1.5)"] -test = ["certifi (>=2024)", "cryptography-vectors (==45.0.5)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"] +test = ["certifi (>=2024)", "cryptography-vectors (==45.0.6)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"] test-randomorder = ["pytest-randomly"] [[package]] @@ -2081,156 +2068,167 @@ rsa = ["oauthlib[signedtoken] (>=3.0.0)"] [[package]] name = "rpds-py" -version = "0.26.0" +version = "0.27.0" description = "Python bindings to Rust's persistent data structures (rpds)" optional = false python-versions = ">=3.9" groups = ["charm-libs", "unit"] files = [ - {file = "rpds_py-0.26.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:4c70c70f9169692b36307a95f3d8c0a9fcd79f7b4a383aad5eaa0e9718b79b37"}, - {file = "rpds_py-0.26.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:777c62479d12395bfb932944e61e915741e364c843afc3196b694db3d669fcd0"}, - {file = "rpds_py-0.26.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec671691e72dff75817386aa02d81e708b5a7ec0dec6669ec05213ff6b77e1bd"}, - {file = "rpds_py-0.26.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6a1cb5d6ce81379401bbb7f6dbe3d56de537fb8235979843f0d53bc2e9815a79"}, - {file = "rpds_py-0.26.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4f789e32fa1fb6a7bf890e0124e7b42d1e60d28ebff57fe806719abb75f0e9a3"}, - {file = "rpds_py-0.26.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c55b0a669976cf258afd718de3d9ad1b7d1fe0a91cd1ab36f38b03d4d4aeaaf"}, - {file = "rpds_py-0.26.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c70d9ec912802ecfd6cd390dadb34a9578b04f9bcb8e863d0a7598ba5e9e7ccc"}, - {file = "rpds_py-0.26.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3021933c2cb7def39d927b9862292e0f4c75a13d7de70eb0ab06efed4c508c19"}, - {file = "rpds_py-0.26.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8a7898b6ca3b7d6659e55cdac825a2e58c638cbf335cde41f4619e290dd0ad11"}, - {file = "rpds_py-0.26.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:12bff2ad9447188377f1b2794772f91fe68bb4bbfa5a39d7941fbebdbf8c500f"}, - {file = "rpds_py-0.26.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:191aa858f7d4902e975d4cf2f2d9243816c91e9605070aeb09c0a800d187e323"}, - {file = "rpds_py-0.26.0-cp310-cp310-win32.whl", hash = "sha256:b37a04d9f52cb76b6b78f35109b513f6519efb481d8ca4c321f6a3b9580b3f45"}, - {file = "rpds_py-0.26.0-cp310-cp310-win_amd64.whl", hash = "sha256:38721d4c9edd3eb6670437d8d5e2070063f305bfa2d5aa4278c51cedcd508a84"}, - {file = "rpds_py-0.26.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:9e8cb77286025bdb21be2941d64ac6ca016130bfdcd228739e8ab137eb4406ed"}, - {file = "rpds_py-0.26.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5e09330b21d98adc8ccb2dbb9fc6cb434e8908d4c119aeaa772cb1caab5440a0"}, - {file = "rpds_py-0.26.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c9c1b92b774b2e68d11193dc39620d62fd8ab33f0a3c77ecdabe19c179cdbc1"}, - {file = "rpds_py-0.26.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:824e6d3503ab990d7090768e4dfd9e840837bae057f212ff9f4f05ec6d1975e7"}, - {file = "rpds_py-0.26.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8ad7fd2258228bf288f2331f0a6148ad0186b2e3643055ed0db30990e59817a6"}, - {file = "rpds_py-0.26.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0dc23bbb3e06ec1ea72d515fb572c1fea59695aefbffb106501138762e1e915e"}, - {file = "rpds_py-0.26.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d80bf832ac7b1920ee29a426cdca335f96a2b5caa839811803e999b41ba9030d"}, - {file = "rpds_py-0.26.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0919f38f5542c0a87e7b4afcafab6fd2c15386632d249e9a087498571250abe3"}, - {file = "rpds_py-0.26.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d422b945683e409000c888e384546dbab9009bb92f7c0b456e217988cf316107"}, - {file = "rpds_py-0.26.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:77a7711fa562ba2da1aa757e11024ad6d93bad6ad7ede5afb9af144623e5f76a"}, - {file = "rpds_py-0.26.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:238e8c8610cb7c29460e37184f6799547f7e09e6a9bdbdab4e8edb90986a2318"}, - {file = "rpds_py-0.26.0-cp311-cp311-win32.whl", hash = "sha256:893b022bfbdf26d7bedb083efeea624e8550ca6eb98bf7fea30211ce95b9201a"}, - {file = "rpds_py-0.26.0-cp311-cp311-win_amd64.whl", hash = "sha256:87a5531de9f71aceb8af041d72fc4cab4943648d91875ed56d2e629bef6d4c03"}, - {file = "rpds_py-0.26.0-cp311-cp311-win_arm64.whl", hash = "sha256:de2713f48c1ad57f89ac25b3cb7daed2156d8e822cf0eca9b96a6f990718cc41"}, - {file = "rpds_py-0.26.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:894514d47e012e794f1350f076c427d2347ebf82f9b958d554d12819849a369d"}, - {file = "rpds_py-0.26.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc921b96fa95a097add244da36a1d9e4f3039160d1d30f1b35837bf108c21136"}, - {file = "rpds_py-0.26.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e1157659470aa42a75448b6e943c895be8c70531c43cb78b9ba990778955582"}, - {file = "rpds_py-0.26.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:521ccf56f45bb3a791182dc6b88ae5f8fa079dd705ee42138c76deb1238e554e"}, - {file = "rpds_py-0.26.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9def736773fd56b305c0eef698be5192c77bfa30d55a0e5885f80126c4831a15"}, - {file = "rpds_py-0.26.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cdad4ea3b4513b475e027be79e5a0ceac8ee1c113a1a11e5edc3c30c29f964d8"}, - {file = "rpds_py-0.26.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82b165b07f416bdccf5c84546a484cc8f15137ca38325403864bfdf2b5b72f6a"}, - {file = "rpds_py-0.26.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d04cab0a54b9dba4d278fe955a1390da3cf71f57feb78ddc7cb67cbe0bd30323"}, - {file = "rpds_py-0.26.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:79061ba1a11b6a12743a2b0f72a46aa2758613d454aa6ba4f5a265cc48850158"}, - {file = "rpds_py-0.26.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:f405c93675d8d4c5ac87364bb38d06c988e11028a64b52a47158a355079661f3"}, - {file = "rpds_py-0.26.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dafd4c44b74aa4bed4b250f1aed165b8ef5de743bcca3b88fc9619b6087093d2"}, - {file = "rpds_py-0.26.0-cp312-cp312-win32.whl", hash = "sha256:3da5852aad63fa0c6f836f3359647870e21ea96cf433eb393ffa45263a170d44"}, - {file = "rpds_py-0.26.0-cp312-cp312-win_amd64.whl", hash = "sha256:cf47cfdabc2194a669dcf7a8dbba62e37a04c5041d2125fae0233b720da6f05c"}, - {file = "rpds_py-0.26.0-cp312-cp312-win_arm64.whl", hash = "sha256:20ab1ae4fa534f73647aad289003f1104092890849e0266271351922ed5574f8"}, - {file = "rpds_py-0.26.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:696764a5be111b036256c0b18cd29783fab22154690fc698062fc1b0084b511d"}, - {file = "rpds_py-0.26.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1e6c15d2080a63aaed876e228efe4f814bc7889c63b1e112ad46fdc8b368b9e1"}, - {file = "rpds_py-0.26.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:390e3170babf42462739a93321e657444f0862c6d722a291accc46f9d21ed04e"}, - {file = "rpds_py-0.26.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7da84c2c74c0f5bc97d853d9e17bb83e2dcafcff0dc48286916001cc114379a1"}, - {file = "rpds_py-0.26.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c5fe114a6dd480a510b6d3661d09d67d1622c4bf20660a474507aaee7eeeee9"}, - {file = "rpds_py-0.26.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3100b3090269f3a7ea727b06a6080d4eb7439dca4c0e91a07c5d133bb1727ea7"}, - {file = "rpds_py-0.26.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c03c9b0c64afd0320ae57de4c982801271c0c211aa2d37f3003ff5feb75bb04"}, - {file = "rpds_py-0.26.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5963b72ccd199ade6ee493723d18a3f21ba7d5b957017607f815788cef50eaf1"}, - {file = "rpds_py-0.26.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9da4e873860ad5bab3291438525cae80169daecbfafe5657f7f5fb4d6b3f96b9"}, - {file = "rpds_py-0.26.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:5afaddaa8e8c7f1f7b4c5c725c0070b6eed0228f705b90a1732a48e84350f4e9"}, - {file = "rpds_py-0.26.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4916dc96489616a6f9667e7526af8fa693c0fdb4f3acb0e5d9f4400eb06a47ba"}, - {file = "rpds_py-0.26.0-cp313-cp313-win32.whl", hash = "sha256:2a343f91b17097c546b93f7999976fd6c9d5900617aa848c81d794e062ab302b"}, - {file = "rpds_py-0.26.0-cp313-cp313-win_amd64.whl", hash = "sha256:0a0b60701f2300c81b2ac88a5fb893ccfa408e1c4a555a77f908a2596eb875a5"}, - {file = "rpds_py-0.26.0-cp313-cp313-win_arm64.whl", hash = "sha256:257d011919f133a4746958257f2c75238e3ff54255acd5e3e11f3ff41fd14256"}, - {file = "rpds_py-0.26.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:529c8156d7506fba5740e05da8795688f87119cce330c244519cf706a4a3d618"}, - {file = "rpds_py-0.26.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f53ec51f9d24e9638a40cabb95078ade8c99251945dad8d57bf4aabe86ecee35"}, - {file = "rpds_py-0.26.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab504c4d654e4a29558eaa5bb8cea5fdc1703ea60a8099ffd9c758472cf913f"}, - {file = "rpds_py-0.26.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fd0641abca296bc1a00183fe44f7fced8807ed49d501f188faa642d0e4975b83"}, - {file = "rpds_py-0.26.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:69b312fecc1d017b5327afa81d4da1480f51c68810963a7336d92203dbb3d4f1"}, - {file = "rpds_py-0.26.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c741107203954f6fc34d3066d213d0a0c40f7bb5aafd698fb39888af277c70d8"}, - {file = "rpds_py-0.26.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc3e55a7db08dc9a6ed5fb7103019d2c1a38a349ac41901f9f66d7f95750942f"}, - {file = "rpds_py-0.26.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9e851920caab2dbcae311fd28f4313c6953993893eb5c1bb367ec69d9a39e7ed"}, - {file = "rpds_py-0.26.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:dfbf280da5f876d0b00c81f26bedce274e72a678c28845453885a9b3c22ae632"}, - {file = "rpds_py-0.26.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:1cc81d14ddfa53d7f3906694d35d54d9d3f850ef8e4e99ee68bc0d1e5fed9a9c"}, - {file = "rpds_py-0.26.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dca83c498b4650a91efcf7b88d669b170256bf8017a5db6f3e06c2bf031f57e0"}, - {file = "rpds_py-0.26.0-cp313-cp313t-win32.whl", hash = "sha256:4d11382bcaf12f80b51d790dee295c56a159633a8e81e6323b16e55d81ae37e9"}, - {file = "rpds_py-0.26.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ff110acded3c22c033e637dd8896e411c7d3a11289b2edf041f86663dbc791e9"}, - {file = "rpds_py-0.26.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:da619979df60a940cd434084355c514c25cf8eb4cf9a508510682f6c851a4f7a"}, - {file = "rpds_py-0.26.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ea89a2458a1a75f87caabefe789c87539ea4e43b40f18cff526052e35bbb4fdf"}, - {file = "rpds_py-0.26.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:feac1045b3327a45944e7dcbeb57530339f6b17baff154df51ef8b0da34c8c12"}, - {file = "rpds_py-0.26.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b818a592bd69bfe437ee8368603d4a2d928c34cffcdf77c2e761a759ffd17d20"}, - {file = "rpds_py-0.26.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1a8b0dd8648709b62d9372fc00a57466f5fdeefed666afe3fea5a6c9539a0331"}, - {file = "rpds_py-0.26.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6d3498ad0df07d81112aa6ec6c95a7e7b1ae00929fb73e7ebee0f3faaeabad2f"}, - {file = "rpds_py-0.26.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24a4146ccb15be237fdef10f331c568e1b0e505f8c8c9ed5d67759dac58ac246"}, - {file = "rpds_py-0.26.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a9a63785467b2d73635957d32a4f6e73d5e4df497a16a6392fa066b753e87387"}, - {file = "rpds_py-0.26.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:de4ed93a8c91debfd5a047be327b7cc8b0cc6afe32a716bbbc4aedca9e2a83af"}, - {file = "rpds_py-0.26.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:caf51943715b12af827696ec395bfa68f090a4c1a1d2509eb4e2cb69abbbdb33"}, - {file = "rpds_py-0.26.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:4a59e5bc386de021f56337f757301b337d7ab58baa40174fb150accd480bc953"}, - {file = "rpds_py-0.26.0-cp314-cp314-win32.whl", hash = "sha256:92c8db839367ef16a662478f0a2fe13e15f2227da3c1430a782ad0f6ee009ec9"}, - {file = "rpds_py-0.26.0-cp314-cp314-win_amd64.whl", hash = "sha256:b0afb8cdd034150d4d9f53926226ed27ad15b7f465e93d7468caaf5eafae0d37"}, - {file = "rpds_py-0.26.0-cp314-cp314-win_arm64.whl", hash = "sha256:ca3f059f4ba485d90c8dc75cb5ca897e15325e4e609812ce57f896607c1c0867"}, - {file = "rpds_py-0.26.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:5afea17ab3a126006dc2f293b14ffc7ef3c85336cf451564a0515ed7648033da"}, - {file = "rpds_py-0.26.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:69f0c0a3df7fd3a7eec50a00396104bb9a843ea6d45fcc31c2d5243446ffd7a7"}, - {file = "rpds_py-0.26.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:801a71f70f9813e82d2513c9a96532551fce1e278ec0c64610992c49c04c2dad"}, - {file = "rpds_py-0.26.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:df52098cde6d5e02fa75c1f6244f07971773adb4a26625edd5c18fee906fa84d"}, - {file = "rpds_py-0.26.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9bc596b30f86dc6f0929499c9e574601679d0341a0108c25b9b358a042f51bca"}, - {file = "rpds_py-0.26.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9dfbe56b299cf5875b68eb6f0ebaadc9cac520a1989cac0db0765abfb3709c19"}, - {file = "rpds_py-0.26.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac64f4b2bdb4ea622175c9ab7cf09444e412e22c0e02e906978b3b488af5fde8"}, - {file = "rpds_py-0.26.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:181ef9b6bbf9845a264f9aa45c31836e9f3c1f13be565d0d010e964c661d1e2b"}, - {file = "rpds_py-0.26.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:49028aa684c144ea502a8e847d23aed5e4c2ef7cadfa7d5eaafcb40864844b7a"}, - {file = "rpds_py-0.26.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:e5d524d68a474a9688336045bbf76cb0def88549c1b2ad9dbfec1fb7cfbe9170"}, - {file = "rpds_py-0.26.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c1851f429b822831bd2edcbe0cfd12ee9ea77868f8d3daf267b189371671c80e"}, - {file = "rpds_py-0.26.0-cp314-cp314t-win32.whl", hash = "sha256:7bdb17009696214c3b66bb3590c6d62e14ac5935e53e929bcdbc5a495987a84f"}, - {file = "rpds_py-0.26.0-cp314-cp314t-win_amd64.whl", hash = "sha256:f14440b9573a6f76b4ee4770c13f0b5921f71dde3b6fcb8dabbefd13b7fe05d7"}, - {file = "rpds_py-0.26.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:7a48af25d9b3c15684059d0d1fc0bc30e8eee5ca521030e2bffddcab5be40226"}, - {file = "rpds_py-0.26.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0c71c2f6bf36e61ee5c47b2b9b5d47e4d1baad6426bfed9eea3e858fc6ee8806"}, - {file = "rpds_py-0.26.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d815d48b1804ed7867b539236b6dd62997850ca1c91cad187f2ddb1b7bbef19"}, - {file = "rpds_py-0.26.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:84cfbd4d4d2cdeb2be61a057a258d26b22877266dd905809e94172dff01a42ae"}, - {file = "rpds_py-0.26.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fbaa70553ca116c77717f513e08815aec458e6b69a028d4028d403b3bc84ff37"}, - {file = "rpds_py-0.26.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:39bfea47c375f379d8e87ab4bb9eb2c836e4f2069f0f65731d85e55d74666387"}, - {file = "rpds_py-0.26.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1533b7eb683fb5f38c1d68a3c78f5fdd8f1412fa6b9bf03b40f450785a0ab915"}, - {file = "rpds_py-0.26.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c5ab0ee51f560d179b057555b4f601b7df909ed31312d301b99f8b9fc6028284"}, - {file = "rpds_py-0.26.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:e5162afc9e0d1f9cae3b577d9c29ddbab3505ab39012cb794d94a005825bde21"}, - {file = "rpds_py-0.26.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:43f10b007033f359bc3fa9cd5e6c1e76723f056ffa9a6b5c117cc35720a80292"}, - {file = "rpds_py-0.26.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:e3730a48e5622e598293eee0762b09cff34dd3f271530f47b0894891281f051d"}, - {file = "rpds_py-0.26.0-cp39-cp39-win32.whl", hash = "sha256:4b1f66eb81eab2e0ff5775a3a312e5e2e16bf758f7b06be82fb0d04078c7ac51"}, - {file = "rpds_py-0.26.0-cp39-cp39-win_amd64.whl", hash = "sha256:519067e29f67b5c90e64fb1a6b6e9d2ec0ba28705c51956637bac23a2f4ddae1"}, - {file = "rpds_py-0.26.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3c0909c5234543ada2515c05dc08595b08d621ba919629e94427e8e03539c958"}, - {file = "rpds_py-0.26.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:c1fb0cda2abcc0ac62f64e2ea4b4e64c57dfd6b885e693095460c61bde7bb18e"}, - {file = "rpds_py-0.26.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84d142d2d6cf9b31c12aa4878d82ed3b2324226270b89b676ac62ccd7df52d08"}, - {file = "rpds_py-0.26.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a547e21c5610b7e9093d870be50682a6a6cf180d6da0f42c47c306073bfdbbf6"}, - {file = "rpds_py-0.26.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:35e9a70a0f335371275cdcd08bc5b8051ac494dd58bff3bbfb421038220dc871"}, - {file = "rpds_py-0.26.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0dfa6115c6def37905344d56fb54c03afc49104e2ca473d5dedec0f6606913b4"}, - {file = "rpds_py-0.26.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:313cfcd6af1a55a286a3c9a25f64af6d0e46cf60bc5798f1db152d97a216ff6f"}, - {file = "rpds_py-0.26.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f7bf2496fa563c046d05e4d232d7b7fd61346e2402052064b773e5c378bf6f73"}, - {file = "rpds_py-0.26.0-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:aa81873e2c8c5aa616ab8e017a481a96742fdf9313c40f14338ca7dbf50cb55f"}, - {file = "rpds_py-0.26.0-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:68ffcf982715f5b5b7686bdd349ff75d422e8f22551000c24b30eaa1b7f7ae84"}, - {file = "rpds_py-0.26.0-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:6188de70e190847bb6db3dc3981cbadff87d27d6fe9b4f0e18726d55795cee9b"}, - {file = "rpds_py-0.26.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:1c962145c7473723df9722ba4c058de12eb5ebedcb4e27e7d902920aa3831ee8"}, - {file = "rpds_py-0.26.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f61a9326f80ca59214d1cceb0a09bb2ece5b2563d4e0cd37bfd5515c28510674"}, - {file = "rpds_py-0.26.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:183f857a53bcf4b1b42ef0f57ca553ab56bdd170e49d8091e96c51c3d69ca696"}, - {file = "rpds_py-0.26.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:941c1cfdf4799d623cf3aa1d326a6b4fdb7a5799ee2687f3516738216d2262fb"}, - {file = "rpds_py-0.26.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:72a8d9564a717ee291f554eeb4bfeafe2309d5ec0aa6c475170bdab0f9ee8e88"}, - {file = "rpds_py-0.26.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:511d15193cbe013619dd05414c35a7dedf2088fcee93c6bbb7c77859765bd4e8"}, - {file = "rpds_py-0.26.0-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aea1f9741b603a8d8fedb0ed5502c2bc0accbc51f43e2ad1337fe7259c2b77a5"}, - {file = "rpds_py-0.26.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4019a9d473c708cf2f16415688ef0b4639e07abaa569d72f74745bbeffafa2c7"}, - {file = "rpds_py-0.26.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:093d63b4b0f52d98ebae33b8c50900d3d67e0666094b1be7a12fffd7f65de74b"}, - {file = "rpds_py-0.26.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:2abe21d8ba64cded53a2a677e149ceb76dcf44284202d737178afe7ba540c1eb"}, - {file = "rpds_py-0.26.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:4feb7511c29f8442cbbc28149a92093d32e815a28aa2c50d333826ad2a20fdf0"}, - {file = "rpds_py-0.26.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:e99685fc95d386da368013e7fb4269dd39c30d99f812a8372d62f244f662709c"}, - {file = "rpds_py-0.26.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a90a13408a7a856b87be8a9f008fff53c5080eea4e4180f6c2e546e4a972fb5d"}, - {file = "rpds_py-0.26.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:3ac51b65e8dc76cf4949419c54c5528adb24fc721df722fd452e5fbc236f5c40"}, - {file = "rpds_py-0.26.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59b2093224a18c6508d95cfdeba8db9cbfd6f3494e94793b58972933fcee4c6d"}, - {file = "rpds_py-0.26.0-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4f01a5d6444a3258b00dc07b6ea4733e26f8072b788bef750baa37b370266137"}, - {file = "rpds_py-0.26.0-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b6e2c12160c72aeda9d1283e612f68804621f448145a210f1bf1d79151c47090"}, - {file = "rpds_py-0.26.0-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cb28c1f569f8d33b2b5dcd05d0e6ef7005d8639c54c2f0be824f05aedf715255"}, - {file = "rpds_py-0.26.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1766b5724c3f779317d5321664a343c07773c8c5fd1532e4039e6cc7d1a815be"}, - {file = "rpds_py-0.26.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b6d9e5a2ed9c4988c8f9b28b3bc0e3e5b1aaa10c28d210a594ff3a8c02742daf"}, - {file = "rpds_py-0.26.0-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:b5f7a446ddaf6ca0fad9a5535b56fbfc29998bf0e0b450d174bbec0d600e1d72"}, - {file = "rpds_py-0.26.0-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:eed5ac260dd545fbc20da5f4f15e7efe36a55e0e7cf706e4ec005b491a9546a0"}, - {file = "rpds_py-0.26.0-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:582462833ba7cee52e968b0341b85e392ae53d44c0f9af6a5927c80e539a8b67"}, - {file = "rpds_py-0.26.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:69a607203441e07e9a8a529cff1d5b73f6a160f22db1097211e6212a68567d11"}, - {file = "rpds_py-0.26.0.tar.gz", hash = "sha256:20dae58a859b0906f0685642e591056f1e787f3a8b39c8e8749a45dc7d26bdb0"}, + {file = "rpds_py-0.27.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:130c1ffa5039a333f5926b09e346ab335f0d4ec393b030a18549a7c7e7c2cea4"}, + {file = "rpds_py-0.27.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a4cf32a26fa744101b67bfd28c55d992cd19438aff611a46cac7f066afca8fd4"}, + {file = "rpds_py-0.27.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64a0fe3f334a40b989812de70160de6b0ec7e3c9e4a04c0bbc48d97c5d3600ae"}, + {file = "rpds_py-0.27.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9a0ff7ee28583ab30a52f371b40f54e7138c52ca67f8ca17ccb7ccf0b383cb5f"}, + {file = "rpds_py-0.27.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:15ea4d2e182345dd1b4286593601d766411b43f868924afe297570658c31a62b"}, + {file = "rpds_py-0.27.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:36184b44bf60a480863e51021c26aca3dfe8dd2f5eeabb33622b132b9d8b8b54"}, + {file = "rpds_py-0.27.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b78430703cfcf5f5e86eb74027a1ed03a93509273d7c705babb547f03e60016"}, + {file = "rpds_py-0.27.0-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:dbd749cff1defbde270ca346b69b3baf5f1297213ef322254bf2a28537f0b046"}, + {file = "rpds_py-0.27.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6bde37765564cd22a676dd8101b657839a1854cfaa9c382c5abf6ff7accfd4ae"}, + {file = "rpds_py-0.27.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:1d66f45b9399036e890fb9c04e9f70c33857fd8f58ac8db9f3278cfa835440c3"}, + {file = "rpds_py-0.27.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:d85d784c619370d9329bbd670f41ff5f2ae62ea4519761b679d0f57f0f0ee267"}, + {file = "rpds_py-0.27.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5df559e9e7644d9042f626f2c3997b555f347d7a855a15f170b253f6c5bfe358"}, + {file = "rpds_py-0.27.0-cp310-cp310-win32.whl", hash = "sha256:b8a4131698b6992b2a56015f51646711ec5d893a0b314a4b985477868e240c87"}, + {file = "rpds_py-0.27.0-cp310-cp310-win_amd64.whl", hash = "sha256:cbc619e84a5e3ab2d452de831c88bdcad824414e9c2d28cd101f94dbdf26329c"}, + {file = "rpds_py-0.27.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:dbc2ab5d10544eb485baa76c63c501303b716a5c405ff2469a1d8ceffaabf622"}, + {file = "rpds_py-0.27.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7ec85994f96a58cf7ed288caa344b7fe31fd1d503bdf13d7331ead5f70ab60d5"}, + {file = "rpds_py-0.27.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:190d7285cd3bb6d31d37a0534d7359c1ee191eb194c511c301f32a4afa5a1dd4"}, + {file = "rpds_py-0.27.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c10d92fb6d7fd827e44055fcd932ad93dac6a11e832d51534d77b97d1d85400f"}, + {file = "rpds_py-0.27.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dd2c1d27ebfe6a015cfa2005b7fe8c52d5019f7bbdd801bc6f7499aab9ae739e"}, + {file = "rpds_py-0.27.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4790c9d5dd565ddb3e9f656092f57268951398cef52e364c405ed3112dc7c7c1"}, + {file = "rpds_py-0.27.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4300e15e7d03660f04be84a125d1bdd0e6b2f674bc0723bc0fd0122f1a4585dc"}, + {file = "rpds_py-0.27.0-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:59195dc244fc183209cf8a93406889cadde47dfd2f0a6b137783aa9c56d67c85"}, + {file = "rpds_py-0.27.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fae4a01ef8c4cb2bbe92ef2063149596907dc4a881a8d26743b3f6b304713171"}, + {file = "rpds_py-0.27.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e3dc8d4ede2dbae6c0fc2b6c958bf51ce9fd7e9b40c0f5b8835c3fde44f5807d"}, + {file = "rpds_py-0.27.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:c3782fb753aa825b4ccabc04292e07897e2fd941448eabf666856c5530277626"}, + {file = "rpds_py-0.27.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:887ab1f12b0d227e9260558a4a2320024b20102207ada65c43e1ffc4546df72e"}, + {file = "rpds_py-0.27.0-cp311-cp311-win32.whl", hash = "sha256:5d6790ff400254137b81b8053b34417e2c46921e302d655181d55ea46df58cf7"}, + {file = "rpds_py-0.27.0-cp311-cp311-win_amd64.whl", hash = "sha256:e24d8031a2c62f34853756d9208eeafa6b940a1efcbfe36e8f57d99d52bb7261"}, + {file = "rpds_py-0.27.0-cp311-cp311-win_arm64.whl", hash = "sha256:08680820d23df1df0a0260f714d12966bc6c42d02e8055a91d61e03f0c47dda0"}, + {file = "rpds_py-0.27.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:19c990fdf5acecbf0623e906ae2e09ce1c58947197f9bced6bbd7482662231c4"}, + {file = "rpds_py-0.27.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6c27a7054b5224710fcfb1a626ec3ff4f28bcb89b899148c72873b18210e446b"}, + {file = "rpds_py-0.27.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09965b314091829b378b60607022048953e25f0b396c2b70e7c4c81bcecf932e"}, + {file = "rpds_py-0.27.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:14f028eb47f59e9169bfdf9f7ceafd29dd64902141840633683d0bad5b04ff34"}, + {file = "rpds_py-0.27.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6168af0be75bba990a39f9431cdfae5f0ad501f4af32ae62e8856307200517b8"}, + {file = "rpds_py-0.27.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ab47fe727c13c09d0e6f508e3a49e545008e23bf762a245b020391b621f5b726"}, + {file = "rpds_py-0.27.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fa01b3d5e3b7d97efab65bd3d88f164e289ec323a8c033c5c38e53ee25c007e"}, + {file = "rpds_py-0.27.0-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:6c135708e987f46053e0a1246a206f53717f9fadfba27174a9769ad4befba5c3"}, + {file = "rpds_py-0.27.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fc327f4497b7087d06204235199daf208fd01c82d80465dc5efa4ec9df1c5b4e"}, + {file = "rpds_py-0.27.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7e57906e38583a2cba67046a09c2637e23297618dc1f3caddbc493f2be97c93f"}, + {file = "rpds_py-0.27.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f4f69d7a4300fbf91efb1fb4916421bd57804c01ab938ab50ac9c4aa2212f03"}, + {file = "rpds_py-0.27.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b4c4fbbcff474e1e5f38be1bf04511c03d492d42eec0babda5d03af3b5589374"}, + {file = "rpds_py-0.27.0-cp312-cp312-win32.whl", hash = "sha256:27bac29bbbf39601b2aab474daf99dbc8e7176ca3389237a23944b17f8913d97"}, + {file = "rpds_py-0.27.0-cp312-cp312-win_amd64.whl", hash = "sha256:8a06aa1197ec0281eb1d7daf6073e199eb832fe591ffa329b88bae28f25f5fe5"}, + {file = "rpds_py-0.27.0-cp312-cp312-win_arm64.whl", hash = "sha256:e14aab02258cb776a108107bd15f5b5e4a1bbaa61ef33b36693dfab6f89d54f9"}, + {file = "rpds_py-0.27.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:443d239d02d9ae55b74015234f2cd8eb09e59fbba30bf60baeb3123ad4c6d5ff"}, + {file = "rpds_py-0.27.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b8a7acf04fda1f30f1007f3cc96d29d8cf0a53e626e4e1655fdf4eabc082d367"}, + {file = "rpds_py-0.27.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d0f92b78cfc3b74a42239fdd8c1266f4715b573204c234d2f9fc3fc7a24f185"}, + {file = "rpds_py-0.27.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ce4ed8e0c7dbc5b19352b9c2c6131dd23b95fa8698b5cdd076307a33626b72dc"}, + {file = "rpds_py-0.27.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fde355b02934cc6b07200cc3b27ab0c15870a757d1a72fd401aa92e2ea3c6bfe"}, + {file = "rpds_py-0.27.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:13bbc4846ae4c993f07c93feb21a24d8ec637573d567a924b1001e81c8ae80f9"}, + {file = "rpds_py-0.27.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be0744661afbc4099fef7f4e604e7f1ea1be1dd7284f357924af12a705cc7d5c"}, + {file = "rpds_py-0.27.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:069e0384a54f427bd65d7fda83b68a90606a3835901aaff42185fcd94f5a9295"}, + {file = "rpds_py-0.27.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4bc262ace5a1a7dc3e2eac2fa97b8257ae795389f688b5adf22c5db1e2431c43"}, + {file = "rpds_py-0.27.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2fe6e18e5c8581f0361b35ae575043c7029d0a92cb3429e6e596c2cdde251432"}, + {file = "rpds_py-0.27.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d93ebdb82363d2e7bec64eecdc3632b59e84bd270d74fe5be1659f7787052f9b"}, + {file = "rpds_py-0.27.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0954e3a92e1d62e83a54ea7b3fdc9efa5d61acef8488a8a3d31fdafbfb00460d"}, + {file = "rpds_py-0.27.0-cp313-cp313-win32.whl", hash = "sha256:2cff9bdd6c7b906cc562a505c04a57d92e82d37200027e8d362518df427f96cd"}, + {file = "rpds_py-0.27.0-cp313-cp313-win_amd64.whl", hash = "sha256:dc79d192fb76fc0c84f2c58672c17bbbc383fd26c3cdc29daae16ce3d927e8b2"}, + {file = "rpds_py-0.27.0-cp313-cp313-win_arm64.whl", hash = "sha256:5b3a5c8089eed498a3af23ce87a80805ff98f6ef8f7bdb70bd1b7dae5105f6ac"}, + {file = "rpds_py-0.27.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:90fb790138c1a89a2e58c9282fe1089638401f2f3b8dddd758499041bc6e0774"}, + {file = "rpds_py-0.27.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:010c4843a3b92b54373e3d2291a7447d6c3fc29f591772cc2ea0e9f5c1da434b"}, + {file = "rpds_py-0.27.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9ce7a9e967afc0a2af7caa0d15a3e9c1054815f73d6a8cb9225b61921b419bd"}, + {file = "rpds_py-0.27.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:aa0bf113d15e8abdfee92aa4db86761b709a09954083afcb5bf0f952d6065fdb"}, + {file = "rpds_py-0.27.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb91d252b35004a84670dfeafadb042528b19842a0080d8b53e5ec1128e8f433"}, + {file = "rpds_py-0.27.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:db8a6313dbac934193fc17fe7610f70cd8181c542a91382531bef5ed785e5615"}, + {file = "rpds_py-0.27.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce96ab0bdfcef1b8c371ada2100767ace6804ea35aacce0aef3aeb4f3f499ca8"}, + {file = "rpds_py-0.27.0-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:7451ede3560086abe1aa27dcdcf55cd15c96b56f543fb12e5826eee6f721f858"}, + {file = "rpds_py-0.27.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:32196b5a99821476537b3f7732432d64d93a58d680a52c5e12a190ee0135d8b5"}, + {file = "rpds_py-0.27.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a029be818059870664157194e46ce0e995082ac49926f1423c1f058534d2aaa9"}, + {file = "rpds_py-0.27.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3841f66c1ffdc6cebce8aed64e36db71466f1dc23c0d9a5592e2a782a3042c79"}, + {file = "rpds_py-0.27.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:42894616da0fc0dcb2ec08a77896c3f56e9cb2f4b66acd76fc8992c3557ceb1c"}, + {file = "rpds_py-0.27.0-cp313-cp313t-win32.whl", hash = "sha256:b1fef1f13c842a39a03409e30ca0bf87b39a1e2a305a9924deadb75a43105d23"}, + {file = "rpds_py-0.27.0-cp313-cp313t-win_amd64.whl", hash = "sha256:183f5e221ba3e283cd36fdfbe311d95cd87699a083330b4f792543987167eff1"}, + {file = "rpds_py-0.27.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:f3cd110e02c5bf17d8fb562f6c9df5c20e73029d587cf8602a2da6c5ef1e32cb"}, + {file = "rpds_py-0.27.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:8d0e09cf4863c74106b5265c2c310f36146e2b445ff7b3018a56799f28f39f6f"}, + {file = "rpds_py-0.27.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64f689ab822f9b5eb6dfc69893b4b9366db1d2420f7db1f6a2adf2a9ca15ad64"}, + {file = "rpds_py-0.27.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e36c80c49853b3ffda7aa1831bf175c13356b210c73128c861f3aa93c3cc4015"}, + {file = "rpds_py-0.27.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6de6a7f622860af0146cb9ee148682ff4d0cea0b8fd3ad51ce4d40efb2f061d0"}, + {file = "rpds_py-0.27.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4045e2fc4b37ec4b48e8907a5819bdd3380708c139d7cc358f03a3653abedb89"}, + {file = "rpds_py-0.27.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9da162b718b12c4219eeeeb68a5b7552fbc7aadedf2efee440f88b9c0e54b45d"}, + {file = "rpds_py-0.27.0-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:0665be515767dc727ffa5f74bd2ef60b0ff85dad6bb8f50d91eaa6b5fb226f51"}, + {file = "rpds_py-0.27.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:203f581accef67300a942e49a37d74c12ceeef4514874c7cede21b012613ca2c"}, + {file = "rpds_py-0.27.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7873b65686a6471c0037139aa000d23fe94628e0daaa27b6e40607c90e3f5ec4"}, + {file = "rpds_py-0.27.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:249ab91ceaa6b41abc5f19513cb95b45c6f956f6b89f1fe3d99c81255a849f9e"}, + {file = "rpds_py-0.27.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d2f184336bc1d6abfaaa1262ed42739c3789b1e3a65a29916a615307d22ffd2e"}, + {file = "rpds_py-0.27.0-cp314-cp314-win32.whl", hash = "sha256:d3c622c39f04d5751408f5b801ecb527e6e0a471b367f420a877f7a660d583f6"}, + {file = "rpds_py-0.27.0-cp314-cp314-win_amd64.whl", hash = "sha256:cf824aceaeffff029ccfba0da637d432ca71ab21f13e7f6f5179cd88ebc77a8a"}, + {file = "rpds_py-0.27.0-cp314-cp314-win_arm64.whl", hash = "sha256:86aca1616922b40d8ac1b3073a1ead4255a2f13405e5700c01f7c8d29a03972d"}, + {file = "rpds_py-0.27.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:341d8acb6724c0c17bdf714319c393bb27f6d23d39bc74f94221b3e59fc31828"}, + {file = "rpds_py-0.27.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6b96b0b784fe5fd03beffff2b1533dc0d85e92bab8d1b2c24ef3a5dc8fac5669"}, + {file = "rpds_py-0.27.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0c431bfb91478d7cbe368d0a699978050d3b112d7f1d440a41e90faa325557fd"}, + {file = "rpds_py-0.27.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:20e222a44ae9f507d0f2678ee3dd0c45ec1e930f6875d99b8459631c24058aec"}, + {file = "rpds_py-0.27.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:184f0d7b342967f6cda94a07d0e1fae177d11d0b8f17d73e06e36ac02889f303"}, + {file = "rpds_py-0.27.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a00c91104c173c9043bc46f7b30ee5e6d2f6b1149f11f545580f5d6fdff42c0b"}, + {file = "rpds_py-0.27.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7a37dd208f0d658e0487522078b1ed68cd6bce20ef4b5a915d2809b9094b410"}, + {file = "rpds_py-0.27.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:92f3b3ec3e6008a1fe00b7c0946a170f161ac00645cde35e3c9a68c2475e8156"}, + {file = "rpds_py-0.27.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a1b3db5fae5cbce2131b7420a3f83553d4d89514c03d67804ced36161fe8b6b2"}, + {file = "rpds_py-0.27.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5355527adaa713ab693cbce7c1e0ec71682f599f61b128cf19d07e5c13c9b1f1"}, + {file = "rpds_py-0.27.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:fcc01c57ce6e70b728af02b2401c5bc853a9e14eb07deda30624374f0aebfe42"}, + {file = "rpds_py-0.27.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3001013dae10f806380ba739d40dee11db1ecb91684febb8406a87c2ded23dae"}, + {file = "rpds_py-0.27.0-cp314-cp314t-win32.whl", hash = "sha256:0f401c369186a5743694dd9fc08cba66cf70908757552e1f714bfc5219c655b5"}, + {file = "rpds_py-0.27.0-cp314-cp314t-win_amd64.whl", hash = "sha256:8a1dca5507fa1337f75dcd5070218b20bc68cf8844271c923c1b79dfcbc20391"}, + {file = "rpds_py-0.27.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:e0d7151a1bd5d0a203a5008fc4ae51a159a610cb82ab0a9b2c4d80241745582e"}, + {file = "rpds_py-0.27.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:42ccc57ff99166a55a59d8c7d14f1a357b7749f9ed3584df74053fd098243451"}, + {file = "rpds_py-0.27.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e377e4cf8795cdbdff75b8f0223d7b6c68ff4fef36799d88ccf3a995a91c0112"}, + {file = "rpds_py-0.27.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:79af163a4b40bbd8cfd7ca86ec8b54b81121d3b213b4435ea27d6568bcba3e9d"}, + {file = "rpds_py-0.27.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b2eff8ee57c5996b0d2a07c3601fb4ce5fbc37547344a26945dd9e5cbd1ed27a"}, + {file = "rpds_py-0.27.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7cf9bc4508efb18d8dff6934b602324eb9f8c6644749627ce001d6f38a490889"}, + {file = "rpds_py-0.27.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05284439ebe7d9f5f5a668d4d8a0a1d851d16f7d47c78e1fab968c8ad30cab04"}, + {file = "rpds_py-0.27.0-cp39-cp39-manylinux_2_31_riscv64.whl", hash = "sha256:1321bce595ad70e80f97f998db37356b2e22cf98094eba6fe91782e626da2f71"}, + {file = "rpds_py-0.27.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:737005088449ddd3b3df5a95476ee1c2c5c669f5c30eed909548a92939c0e12d"}, + {file = "rpds_py-0.27.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:9b2a4e17bfd68536c3b801800941c95a1d4a06e3cada11c146093ba939d9638d"}, + {file = "rpds_py-0.27.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:dc6b0d5a1ea0318ef2def2b6a55dccf1dcaf77d605672347271ed7b829860765"}, + {file = "rpds_py-0.27.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:4c3f8a0d4802df34fcdbeb3dfe3a4d8c9a530baea8fafdf80816fcaac5379d83"}, + {file = "rpds_py-0.27.0-cp39-cp39-win32.whl", hash = "sha256:699c346abc73993962cac7bb4f02f58e438840fa5458a048d3a178a7a670ba86"}, + {file = "rpds_py-0.27.0-cp39-cp39-win_amd64.whl", hash = "sha256:be806e2961cd390a89d6c3ce8c2ae34271cfcd05660f716257838bb560f1c3b6"}, + {file = "rpds_py-0.27.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:46f48482c1a4748ab2773f75fffbdd1951eb59794e32788834b945da857c47a8"}, + {file = "rpds_py-0.27.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:419dd9c98bcc9fb0242be89e0c6e922df333b975d4268faa90d58499fd9c9ebe"}, + {file = "rpds_py-0.27.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55d42a0ef2bdf6bc81e1cc2d49d12460f63c6ae1423c4f4851b828e454ccf6f1"}, + {file = "rpds_py-0.27.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2e39169ac6aae06dd79c07c8a69d9da867cef6a6d7883a0186b46bb46ccfb0c3"}, + {file = "rpds_py-0.27.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:935afcdea4751b0ac918047a2df3f720212892347767aea28f5b3bf7be4f27c0"}, + {file = "rpds_py-0.27.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8de567dec6d451649a781633d36f5c7501711adee329d76c095be2178855b042"}, + {file = "rpds_py-0.27.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:555ed147cbe8c8f76e72a4c6cd3b7b761cbf9987891b9448808148204aed74a5"}, + {file = "rpds_py-0.27.0-pp310-pypy310_pp73-manylinux_2_31_riscv64.whl", hash = "sha256:d2cc2b34f9e1d31ce255174da82902ad75bd7c0d88a33df54a77a22f2ef421ee"}, + {file = "rpds_py-0.27.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cb0702c12983be3b2fab98ead349ac63a98216d28dda6f518f52da5498a27a1b"}, + {file = "rpds_py-0.27.0-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:ba783541be46f27c8faea5a6645e193943c17ea2f0ffe593639d906a327a9bcc"}, + {file = "rpds_py-0.27.0-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:2406d034635d1497c596c40c85f86ecf2bf9611c1df73d14078af8444fe48031"}, + {file = "rpds_py-0.27.0-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:dea0808153f1fbbad772669d906cddd92100277533a03845de6893cadeffc8be"}, + {file = "rpds_py-0.27.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d2a81bdcfde4245468f7030a75a37d50400ac2455c3a4819d9d550c937f90ab5"}, + {file = "rpds_py-0.27.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e6491658dd2569f05860bad645569145c8626ac231877b0fb2d5f9bcb7054089"}, + {file = "rpds_py-0.27.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:bec77545d188f8bdd29d42bccb9191682a46fb2e655e3d1fb446d47c55ac3b8d"}, + {file = "rpds_py-0.27.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25a4aebf8ca02bbb90a9b3e7a463bbf3bee02ab1c446840ca07b1695a68ce424"}, + {file = "rpds_py-0.27.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:44524b96481a4c9b8e6c46d6afe43fa1fb485c261e359fbe32b63ff60e3884d8"}, + {file = "rpds_py-0.27.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:45d04a73c54b6a5fd2bab91a4b5bc8b426949586e61340e212a8484919183859"}, + {file = "rpds_py-0.27.0-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:343cf24de9ed6c728abefc5d5c851d5de06497caa7ac37e5e65dd572921ed1b5"}, + {file = "rpds_py-0.27.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7aed8118ae20515974650d08eb724150dc2e20c2814bcc307089569995e88a14"}, + {file = "rpds_py-0.27.0-pp311-pypy311_pp73-manylinux_2_31_riscv64.whl", hash = "sha256:af9d4fd79ee1cc8e7caf693ee02737daabfc0fcf2773ca0a4735b356c8ad6f7c"}, + {file = "rpds_py-0.27.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f0396e894bd1e66c74ecbc08b4f6a03dc331140942c4b1d345dd131b68574a60"}, + {file = "rpds_py-0.27.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:59714ab0a5af25d723d8e9816638faf7f4254234decb7d212715c1aa71eee7be"}, + {file = "rpds_py-0.27.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:88051c3b7d5325409f433c5a40328fcb0685fc04e5db49ff936e910901d10114"}, + {file = "rpds_py-0.27.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:181bc29e59e5e5e6e9d63b143ff4d5191224d355e246b5a48c88ce6b35c4e466"}, + {file = "rpds_py-0.27.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:9ad08547995a57e74fea6abaf5940d399447935faebbd2612b3b0ca6f987946b"}, + {file = "rpds_py-0.27.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:61490d57e82e23b45c66f96184237994bfafa914433b8cd1a9bb57fecfced59d"}, + {file = "rpds_py-0.27.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7cf5e726b6fa977e428a61880fb108a62f28b6d0c7ef675b117eaff7076df49"}, + {file = "rpds_py-0.27.0-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dc662bc9375a6a394b62dfd331874c434819f10ee3902123200dbcf116963f89"}, + {file = "rpds_py-0.27.0-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:299a245537e697f28a7511d01038c310ac74e8ea213c0019e1fc65f52c0dcb23"}, + {file = "rpds_py-0.27.0-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:be3964f7312ea05ed283b20f87cb533fdc555b2e428cc7be64612c0b2124f08c"}, + {file = "rpds_py-0.27.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33ba649a6e55ae3808e4c39e01580dc9a9b0d5b02e77b66bb86ef117922b1264"}, + {file = "rpds_py-0.27.0-pp39-pypy39_pp73-manylinux_2_31_riscv64.whl", hash = "sha256:81f81bbd7cdb4bdc418c09a73809abeda8f263a6bf8f9c7f93ed98b5597af39d"}, + {file = "rpds_py-0.27.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:11e8e28c0ba0373d052818b600474cfee2fafa6c9f36c8587d217b13ee28ca7d"}, + {file = "rpds_py-0.27.0-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:e3acb9c16530362aeaef4e84d57db357002dc5cbfac9a23414c3e73c08301ab2"}, + {file = "rpds_py-0.27.0-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:2e307cb5f66c59ede95c00e93cd84190a5b7f3533d7953690b2036780622ba81"}, + {file = "rpds_py-0.27.0-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:f09c9d4c26fa79c1bad927efb05aca2391350b8e61c38cbc0d7d3c814e463124"}, + {file = "rpds_py-0.27.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:af22763a0a1eff106426a6e1f13c4582e0d0ad89c1493ab6c058236174cd6c6a"}, + {file = "rpds_py-0.27.0.tar.gz", hash = "sha256:8b23cf252f180cda89220b378d917180f29d313cd6a07b2431c0d3b776aae86f"}, ] [[package]] @@ -2250,30 +2248,30 @@ pyasn1 = ">=0.1.3" [[package]] name = "ruff" -version = "0.12.7" +version = "0.12.8" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" groups = ["format"] files = [ - {file = "ruff-0.12.7-py3-none-linux_armv6l.whl", hash = "sha256:76e4f31529899b8c434c3c1dede98c4483b89590e15fb49f2d46183801565303"}, - {file = "ruff-0.12.7-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:789b7a03e72507c54fb3ba6209e4bb36517b90f1a3569ea17084e3fd295500fb"}, - {file = "ruff-0.12.7-py3-none-macosx_11_0_arm64.whl", hash = "sha256:2e1c2a3b8626339bb6369116e7030a4cf194ea48f49b64bb505732a7fce4f4e3"}, - {file = "ruff-0.12.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32dec41817623d388e645612ec70d5757a6d9c035f3744a52c7b195a57e03860"}, - {file = "ruff-0.12.7-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:47ef751f722053a5df5fa48d412dbb54d41ab9b17875c6840a58ec63ff0c247c"}, - {file = "ruff-0.12.7-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a828a5fc25a3efd3e1ff7b241fd392686c9386f20e5ac90aa9234a5faa12c423"}, - {file = "ruff-0.12.7-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:5726f59b171111fa6a69d82aef48f00b56598b03a22f0f4170664ff4d8298efb"}, - {file = "ruff-0.12.7-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:74e6f5c04c4dd4aba223f4fe6e7104f79e0eebf7d307e4f9b18c18362124bccd"}, - {file = "ruff-0.12.7-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5d0bfe4e77fba61bf2ccadf8cf005d6133e3ce08793bbe870dd1c734f2699a3e"}, - {file = "ruff-0.12.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06bfb01e1623bf7f59ea749a841da56f8f653d641bfd046edee32ede7ff6c606"}, - {file = "ruff-0.12.7-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e41df94a957d50083fd09b916d6e89e497246698c3f3d5c681c8b3e7b9bb4ac8"}, - {file = "ruff-0.12.7-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:4000623300563c709458d0ce170c3d0d788c23a058912f28bbadc6f905d67afa"}, - {file = "ruff-0.12.7-py3-none-musllinux_1_2_i686.whl", hash = "sha256:69ffe0e5f9b2cf2b8e289a3f8945b402a1b19eff24ec389f45f23c42a3dd6fb5"}, - {file = "ruff-0.12.7-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:a07a5c8ffa2611a52732bdc67bf88e243abd84fe2d7f6daef3826b59abbfeda4"}, - {file = "ruff-0.12.7-py3-none-win32.whl", hash = "sha256:c928f1b2ec59fb77dfdf70e0419408898b63998789cc98197e15f560b9e77f77"}, - {file = "ruff-0.12.7-py3-none-win_amd64.whl", hash = "sha256:9c18f3d707ee9edf89da76131956aba1270c6348bfee8f6c647de841eac7194f"}, - {file = "ruff-0.12.7-py3-none-win_arm64.whl", hash = "sha256:dfce05101dbd11833a0776716d5d1578641b7fddb537fe7fa956ab85d1769b69"}, - {file = "ruff-0.12.7.tar.gz", hash = "sha256:1fc3193f238bc2d7968772c82831a4ff69252f673be371fb49663f0068b7ec71"}, + {file = "ruff-0.12.8-py3-none-linux_armv6l.whl", hash = "sha256:63cb5a5e933fc913e5823a0dfdc3c99add73f52d139d6cd5cc8639d0e0465513"}, + {file = "ruff-0.12.8-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:9a9bbe28f9f551accf84a24c366c1aa8774d6748438b47174f8e8565ab9dedbc"}, + {file = "ruff-0.12.8-py3-none-macosx_11_0_arm64.whl", hash = "sha256:2fae54e752a3150f7ee0e09bce2e133caf10ce9d971510a9b925392dc98d2fec"}, + {file = "ruff-0.12.8-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c0acbcf01206df963d9331b5838fb31f3b44fa979ee7fa368b9b9057d89f4a53"}, + {file = "ruff-0.12.8-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ae3e7504666ad4c62f9ac8eedb52a93f9ebdeb34742b8b71cd3cccd24912719f"}, + {file = "ruff-0.12.8-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cb82efb5d35d07497813a1c5647867390a7d83304562607f3579602fa3d7d46f"}, + {file = "ruff-0.12.8-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:dbea798fc0065ad0b84a2947b0aff4233f0cb30f226f00a2c5850ca4393de609"}, + {file = "ruff-0.12.8-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:49ebcaccc2bdad86fd51b7864e3d808aad404aab8df33d469b6e65584656263a"}, + {file = "ruff-0.12.8-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ac9c570634b98c71c88cb17badd90f13fc076a472ba6ef1d113d8ed3df109fb"}, + {file = "ruff-0.12.8-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:560e0cd641e45591a3e42cb50ef61ce07162b9c233786663fdce2d8557d99818"}, + {file = "ruff-0.12.8-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:71c83121512e7743fba5a8848c261dcc454cafb3ef2934a43f1b7a4eb5a447ea"}, + {file = "ruff-0.12.8-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:de4429ef2ba091ecddedd300f4c3f24bca875d3d8b23340728c3cb0da81072c3"}, + {file = "ruff-0.12.8-py3-none-musllinux_1_2_i686.whl", hash = "sha256:a2cab5f60d5b65b50fba39a8950c8746df1627d54ba1197f970763917184b161"}, + {file = "ruff-0.12.8-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:45c32487e14f60b88aad6be9fd5da5093dbefb0e3e1224131cb1d441d7cb7d46"}, + {file = "ruff-0.12.8-py3-none-win32.whl", hash = "sha256:daf3475060a617fd5bc80638aeaf2f5937f10af3ec44464e280a9d2218e720d3"}, + {file = "ruff-0.12.8-py3-none-win_amd64.whl", hash = "sha256:7209531f1a1fcfbe8e46bcd7ab30e2f43604d8ba1c49029bb420b103d0b5f76e"}, + {file = "ruff-0.12.8-py3-none-win_arm64.whl", hash = "sha256:c90e1a334683ce41b0e7a04f41790c429bf5073b62c1ae701c9dc5b3d14f0749"}, + {file = "ruff-0.12.8.tar.gz", hash = "sha256:4cb3a45525176e1009b2b64126acf5f9444ea59066262791febf55e40493a033"}, ] [[package]] @@ -2680,4 +2678,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = "^3.10" -content-hash = "2190b6beb8339d651097b6f13926d55686d198017af262f39adfecd8861536c4" +content-hash = "0d284de63c0d6fdd50280106c268dfcb3e500093dd47c3476a6821b3424fdcf9" diff --git a/pyproject.toml b/pyproject.toml index 7d4d1265a9..66113a596b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ requires-poetry = ">=2.0.0" [tool.poetry.dependencies] python = "^3.10" ops = "^2.23.1" -boto3 = "^1.40.2" +boto3 = "^1.40.7" pgconnstr = "^1.0.1" requests = "^2.32.4" tenacity = "^9.1.2" @@ -40,7 +40,7 @@ opentelemetry-exporter-otlp-proto-http = "1.21.0" optional = true [tool.poetry.group.format.dependencies] -ruff = "^0.12.7" +ruff = "^0.12.8" [tool.poetry.group.lint] optional = true @@ -52,7 +52,7 @@ codespell = "^2.4.1" optional = true [tool.poetry.group.unit.dependencies] -coverage = {extras = ["toml"], version = "^7.10.2"} +coverage = {extras = ["toml"], version = "^7.10.3"} pytest = "^8.4.1" pytest-asyncio = "*" parameterized = "^0.9.0" From 3fd7c6103934af90812b335e8956d9959157b02e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 16 Aug 2025 00:22:11 +0300 Subject: [PATCH 078/112] Update charmcraft.yaml build tools (#1089) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- charmcraft.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/charmcraft.yaml b/charmcraft.yaml index fddccfe8c1..11a2491b6e 100644 --- a/charmcraft.yaml +++ b/charmcraft.yaml @@ -27,7 +27,7 @@ parts: PIP_BREAK_SYSTEM_PACKAGES=true python3 -m pip install --user --upgrade pip==25.2 # renovate: charmcraft-pip-latest # Use uv to install poetry so that a newer version of Python can be installed if needed by poetry - curl --proto '=https' --tlsv1.2 -LsSf https://github.com/astral-sh/uv/releases/download/0.8.4/uv-installer.sh | sh # renovate: charmcraft-uv-latest + curl --proto '=https' --tlsv1.2 -LsSf https://github.com/astral-sh/uv/releases/download/0.8.8/uv-installer.sh | sh # renovate: charmcraft-uv-latest # poetry 2.0.0 requires Python >=3.9 if ! "$HOME/.local/bin/uv" python find '>=3.9' then @@ -35,7 +35,7 @@ parts: # (to reduce the number of Python versions we use) "$HOME/.local/bin/uv" python install 3.10.12 # renovate: charmcraft-python-ubuntu-22.04 fi - "$HOME/.local/bin/uv" tool install --no-python-downloads --python '>=3.9' poetry==2.1.3 --with poetry-plugin-export==1.9.0 # renovate: charmcraft-poetry-latest + "$HOME/.local/bin/uv" tool install --no-python-downloads --python '>=3.9' poetry==2.1.4 --with poetry-plugin-export==1.9.0 # renovate: charmcraft-poetry-latest ln -sf "$HOME/.local/bin/poetry" /usr/local/bin/poetry # "charm-poetry" part name is arbitrary; use for consistency @@ -75,7 +75,7 @@ parts: # rpds-py (Python package) >=0.19.0 requires rustc >=1.76, which is not available in the # Ubuntu 22.04 archive. Install rustc and cargo using rustup instead of the Ubuntu archive rustup set profile minimal - rustup default 1.88.0 # renovate: charmcraft-rust-latest + rustup default 1.89.0 # renovate: charmcraft-rust-latest craftctl default # Include requirements.txt in *.charm artifact for easier debugging From 80f47f1f9c8c8345d43597a7c79ce6c4d5111a3f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 19 Aug 2025 12:35:26 +0300 Subject: [PATCH 079/112] Update dependency uv to v0.8.12 (#1103) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- charmcraft.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charmcraft.yaml b/charmcraft.yaml index 11a2491b6e..86c57e66a0 100644 --- a/charmcraft.yaml +++ b/charmcraft.yaml @@ -27,7 +27,7 @@ parts: PIP_BREAK_SYSTEM_PACKAGES=true python3 -m pip install --user --upgrade pip==25.2 # renovate: charmcraft-pip-latest # Use uv to install poetry so that a newer version of Python can be installed if needed by poetry - curl --proto '=https' --tlsv1.2 -LsSf https://github.com/astral-sh/uv/releases/download/0.8.8/uv-installer.sh | sh # renovate: charmcraft-uv-latest + curl --proto '=https' --tlsv1.2 -LsSf https://github.com/astral-sh/uv/releases/download/0.8.12/uv-installer.sh | sh # renovate: charmcraft-uv-latest # poetry 2.0.0 requires Python >=3.9 if ! "$HOME/.local/bin/uv" python find '>=3.9' then From ef563098ec3ff6ccfa78c85545567de133e2e2f6 Mon Sep 17 00:00:00 2001 From: Alex Lutay <1928266+taurus-forever@users.noreply.github.com> Date: Tue, 19 Aug 2025 15:40:11 +0200 Subject: [PATCH 080/112] DPE-7968 Bump snap revision (remove python3-boto3 for CVE-2023-37920) (#1109) --- src/constants.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/constants.py b/src/constants.py index cc21e8f040..564505fe8f 100644 --- a/src/constants.py +++ b/src/constants.py @@ -35,7 +35,7 @@ SNAP_PACKAGES = [ ( POSTGRESQL_SNAP_NAME, - {"revision": {"aarch64": "186", "x86_64": "184"}}, + {"revision": {"aarch64": "221", "x86_64": "220"}}, ) ] From bee0a734cd4095eda83d032c6e927a42266b4ea5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 21 Aug 2025 00:27:45 +0300 Subject: [PATCH 081/112] Lock file maintenance Python dependencies (#1104) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- poetry.lock | 417 +++++++++++++++++++++++++------------------------ pyproject.toml | 10 +- 2 files changed, 215 insertions(+), 212 deletions(-) diff --git a/poetry.lock b/poetry.lock index abda6be253..adbdf4e0df 100644 --- a/poetry.lock +++ b/poetry.lock @@ -233,18 +233,18 @@ typecheck = ["mypy"] [[package]] name = "boto3" -version = "1.40.7" +version = "1.40.12" description = "The AWS SDK for Python" optional = false python-versions = ">=3.9" groups = ["main", "integration"] files = [ - {file = "boto3-1.40.7-py3-none-any.whl", hash = "sha256:8727cac601a679d2885dc78b8119a0548bbbe04e49b72f7d94021a629154c080"}, - {file = "boto3-1.40.7.tar.gz", hash = "sha256:61b15f70761f1eadd721c6ba41a92658f003eaaef09500ca7642f5ae68ec8945"}, + {file = "boto3-1.40.12-py3-none-any.whl", hash = "sha256:3c3d6731390b5b11f5e489d5d9daa57f0c3e171efb63ac8f47203df9c71812b3"}, + {file = "boto3-1.40.12.tar.gz", hash = "sha256:c6b32aee193fbd2eb84696d2b5b2410dcda9fb4a385e1926cff908377d222247"}, ] [package.dependencies] -botocore = ">=1.40.7,<1.41.0" +botocore = ">=1.40.12,<1.41.0" jmespath = ">=0.7.1,<2.0.0" s3transfer = ">=0.13.0,<0.14.0" @@ -253,14 +253,14 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.40.7" +version = "1.40.12" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">=3.9" groups = ["main", "integration"] files = [ - {file = "botocore-1.40.7-py3-none-any.whl", hash = "sha256:a06956f3d7222e80ef6ae193608f358c3b7898e1a2b88553479d8f9737fbb03e"}, - {file = "botocore-1.40.7.tar.gz", hash = "sha256:33793696680cf3a0c4b5ace4f9070c67c4d4fcb19c999fd85cfee55de3dcf913"}, + {file = "botocore-1.40.12-py3-none-any.whl", hash = "sha256:84e96004a8b426c5508f6b5600312d6271364269466a3a957dc377ad8effc438"}, + {file = "botocore-1.40.12.tar.gz", hash = "sha256:c6560578e799b47b762b7e555bd9c5dd5c29c5d23bd778a8a72e98c979b3c727"}, ] [package.dependencies] @@ -269,7 +269,7 @@ python-dateutil = ">=2.1,<3.0.0" urllib3 = {version = ">=1.25.4,<2.2.0 || >2.2.0,<3", markers = "python_version >= \"3.10\""} [package.extras] -crt = ["awscrt (==0.23.8)"] +crt = ["awscrt (==0.27.6)"] [[package]] name = "cachetools" @@ -498,14 +498,14 @@ files = [ [[package]] name = "cosl" -version = "1.0.0" +version = "1.1.0" description = "Utils for COS Lite charms" optional = false python-versions = ">=3.8" groups = ["charm-libs"] files = [ - {file = "cosl-1.0.0-py3-none-any.whl", hash = "sha256:4ed54e818a5614a5164011253c12441cd0bffacfd99c8bd6b5b9740a397e482d"}, - {file = "cosl-1.0.0.tar.gz", hash = "sha256:5cef884faac1313ae6d234fcd6f40db0cbdd44bcdacfd9a6e9ecf9cede219359"}, + {file = "cosl-1.1.0-py3-none-any.whl", hash = "sha256:e5313e6753db057b32fd41a493735b9eb152d38d1e2f688e54ef0b974ba99934"}, + {file = "cosl-1.1.0.tar.gz", hash = "sha256:7a04e32c95cdc2d556bb43517eaadf6fc177bc8449bd9359989a24056b34c9aa"}, ] [package.dependencies] @@ -517,100 +517,100 @@ typing-extensions = "*" [[package]] name = "coverage" -version = "7.10.3" +version = "7.10.4" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.9" groups = ["unit"] files = [ - {file = "coverage-7.10.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:53808194afdf948c462215e9403cca27a81cf150d2f9b386aee4dab614ae2ffe"}, - {file = "coverage-7.10.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f4d1b837d1abf72187a61645dbf799e0d7705aa9232924946e1f57eb09a3bf00"}, - {file = "coverage-7.10.3-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:2a90dd4505d3cc68b847ab10c5ee81822a968b5191664e8a0801778fa60459fa"}, - {file = "coverage-7.10.3-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:d52989685ff5bf909c430e6d7f6550937bc6d6f3e6ecb303c97a86100efd4596"}, - {file = "coverage-7.10.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bdb558a1d97345bde3a9f4d3e8d11c9e5611f748646e9bb61d7d612a796671b5"}, - {file = "coverage-7.10.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c9e6331a8f09cb1fc8bda032752af03c366870b48cce908875ba2620d20d0ad4"}, - {file = "coverage-7.10.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:992f48bf35b720e174e7fae916d943599f1a66501a2710d06c5f8104e0756ee1"}, - {file = "coverage-7.10.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c5595fc4ad6a39312c786ec3326d7322d0cf10e3ac6a6df70809910026d67cfb"}, - {file = "coverage-7.10.3-cp310-cp310-win32.whl", hash = "sha256:9e92fa1f2bd5a57df9d00cf9ce1eb4ef6fccca4ceabec1c984837de55329db34"}, - {file = "coverage-7.10.3-cp310-cp310-win_amd64.whl", hash = "sha256:b96524d6e4a3ce6a75c56bb15dbd08023b0ae2289c254e15b9fbdddf0c577416"}, - {file = "coverage-7.10.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f2ff2e2afdf0d51b9b8301e542d9c21a8d084fd23d4c8ea2b3a1b3c96f5f7397"}, - {file = "coverage-7.10.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:18ecc5d1b9a8c570f6c9b808fa9a2b16836b3dd5414a6d467ae942208b095f85"}, - {file = "coverage-7.10.3-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1af4461b25fe92889590d438905e1fc79a95680ec2a1ff69a591bb3fdb6c7157"}, - {file = "coverage-7.10.3-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:3966bc9a76b09a40dc6063c8b10375e827ea5dfcaffae402dd65953bef4cba54"}, - {file = "coverage-7.10.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:205a95b87ef4eb303b7bc5118b47b6b6604a644bcbdb33c336a41cfc0a08c06a"}, - {file = "coverage-7.10.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5b3801b79fb2ad61e3c7e2554bab754fc5f105626056980a2b9cf3aef4f13f84"}, - {file = "coverage-7.10.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:b0dc69c60224cda33d384572da945759756e3f06b9cdac27f302f53961e63160"}, - {file = "coverage-7.10.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a83d4f134bab2c7ff758e6bb1541dd72b54ba295ced6a63d93efc2e20cb9b124"}, - {file = "coverage-7.10.3-cp311-cp311-win32.whl", hash = "sha256:54e409dd64e5302b2a8fdf44ec1c26f47abd1f45a2dcf67bd161873ee05a59b8"}, - {file = "coverage-7.10.3-cp311-cp311-win_amd64.whl", hash = "sha256:30c601610a9b23807c5e9e2e442054b795953ab85d525c3de1b1b27cebeb2117"}, - {file = "coverage-7.10.3-cp311-cp311-win_arm64.whl", hash = "sha256:dabe662312a97958e932dee056f2659051d822552c0b866823e8ba1c2fe64770"}, - {file = "coverage-7.10.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:449c1e2d3a84d18bd204258a897a87bc57380072eb2aded6a5b5226046207b42"}, - {file = "coverage-7.10.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1d4f9ce50b9261ad196dc2b2e9f1fbbee21651b54c3097a25ad783679fd18294"}, - {file = "coverage-7.10.3-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:4dd4564207b160d0d45c36a10bc0a3d12563028e8b48cd6459ea322302a156d7"}, - {file = "coverage-7.10.3-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:5ca3c9530ee072b7cb6a6ea7b640bcdff0ad3b334ae9687e521e59f79b1d0437"}, - {file = "coverage-7.10.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b6df359e59fa243c9925ae6507e27f29c46698359f45e568fd51b9315dbbe587"}, - {file = "coverage-7.10.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a181e4c2c896c2ff64c6312db3bda38e9ade2e1aa67f86a5628ae85873786cea"}, - {file = "coverage-7.10.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a374d4e923814e8b72b205ef6b3d3a647bb50e66f3558582eda074c976923613"}, - {file = "coverage-7.10.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:daeefff05993e5e8c6e7499a8508e7bd94502b6b9a9159c84fd1fe6bce3151cb"}, - {file = "coverage-7.10.3-cp312-cp312-win32.whl", hash = "sha256:187ecdcac21f9636d570e419773df7bd2fda2e7fa040f812e7f95d0bddf5f79a"}, - {file = "coverage-7.10.3-cp312-cp312-win_amd64.whl", hash = "sha256:4a50ad2524ee7e4c2a95e60d2b0b83283bdfc745fe82359d567e4f15d3823eb5"}, - {file = "coverage-7.10.3-cp312-cp312-win_arm64.whl", hash = "sha256:c112f04e075d3495fa3ed2200f71317da99608cbb2e9345bdb6de8819fc30571"}, - {file = "coverage-7.10.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b99e87304ffe0eb97c5308447328a584258951853807afdc58b16143a530518a"}, - {file = "coverage-7.10.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4af09c7574d09afbc1ea7da9dcea23665c01f3bc1b1feb061dac135f98ffc53a"}, - {file = "coverage-7.10.3-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:488e9b50dc5d2aa9521053cfa706209e5acf5289e81edc28291a24f4e4488f46"}, - {file = "coverage-7.10.3-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:913ceddb4289cbba3a310704a424e3fb7aac2bc0c3a23ea473193cb290cf17d4"}, - {file = "coverage-7.10.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b1f91cbc78c7112ab84ed2a8defbccd90f888fcae40a97ddd6466b0bec6ae8a"}, - {file = "coverage-7.10.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b0bac054d45af7cd938834b43a9878b36ea92781bcb009eab040a5b09e9927e3"}, - {file = "coverage-7.10.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:fe72cbdd12d9e0f4aca873fa6d755e103888a7f9085e4a62d282d9d5b9f7928c"}, - {file = "coverage-7.10.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c1e2e927ab3eadd7c244023927d646e4c15c65bb2ac7ae3c3e9537c013700d21"}, - {file = "coverage-7.10.3-cp313-cp313-win32.whl", hash = "sha256:24d0c13de473b04920ddd6e5da3c08831b1170b8f3b17461d7429b61cad59ae0"}, - {file = "coverage-7.10.3-cp313-cp313-win_amd64.whl", hash = "sha256:3564aae76bce4b96e2345cf53b4c87e938c4985424a9be6a66ee902626edec4c"}, - {file = "coverage-7.10.3-cp313-cp313-win_arm64.whl", hash = "sha256:f35580f19f297455f44afcd773c9c7a058e52eb6eb170aa31222e635f2e38b87"}, - {file = "coverage-7.10.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:07009152f497a0464ffdf2634586787aea0e69ddd023eafb23fc38267db94b84"}, - {file = "coverage-7.10.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:8dd2ba5f0c7e7e8cc418be2f0c14c4d9e3f08b8fb8e4c0f83c2fe87d03eb655e"}, - {file = "coverage-7.10.3-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1ae22b97003c74186e034a93e4f946c75fad8c0ce8d92fbbc168b5e15ee2841f"}, - {file = "coverage-7.10.3-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:eb329f1046888a36b1dc35504d3029e1dd5afe2196d94315d18c45ee380f67d5"}, - {file = "coverage-7.10.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ce01048199a91f07f96ca3074b0c14021f4fe7ffd29a3e6a188ac60a5c3a4af8"}, - {file = "coverage-7.10.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:08b989a06eb9dfacf96d42b7fb4c9a22bafa370d245dc22fa839f2168c6f9fa1"}, - {file = "coverage-7.10.3-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:669fe0d4e69c575c52148511029b722ba8d26e8a3129840c2ce0522e1452b256"}, - {file = "coverage-7.10.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:3262d19092771c83f3413831d9904b1ccc5f98da5de4ffa4ad67f5b20c7aaf7b"}, - {file = "coverage-7.10.3-cp313-cp313t-win32.whl", hash = "sha256:cc0ee4b2ccd42cab7ee6be46d8a67d230cb33a0a7cd47a58b587a7063b6c6b0e"}, - {file = "coverage-7.10.3-cp313-cp313t-win_amd64.whl", hash = "sha256:03db599f213341e2960430984e04cf35fb179724e052a3ee627a068653cf4a7c"}, - {file = "coverage-7.10.3-cp313-cp313t-win_arm64.whl", hash = "sha256:46eae7893ba65f53c71284585a262f083ef71594f05ec5c85baf79c402369098"}, - {file = "coverage-7.10.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:bce8b8180912914032785850d8f3aacb25ec1810f5f54afc4a8b114e7a9b55de"}, - {file = "coverage-7.10.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:07790b4b37d56608536f7c1079bd1aa511567ac2966d33d5cec9cf520c50a7c8"}, - {file = "coverage-7.10.3-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:e79367ef2cd9166acedcbf136a458dfe9a4a2dd4d1ee95738fb2ee581c56f667"}, - {file = "coverage-7.10.3-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:419d2a0f769f26cb1d05e9ccbc5eab4cb5d70231604d47150867c07822acbdf4"}, - {file = "coverage-7.10.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee221cf244757cdc2ac882e3062ab414b8464ad9c884c21e878517ea64b3fa26"}, - {file = "coverage-7.10.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c2079d8cdd6f7373d628e14b3357f24d1db02c9dc22e6a007418ca7a2be0435a"}, - {file = "coverage-7.10.3-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:bd8df1f83c0703fa3ca781b02d36f9ec67ad9cb725b18d486405924f5e4270bd"}, - {file = "coverage-7.10.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6b4e25e0fa335c8aa26e42a52053f3786a61cc7622b4d54ae2dad994aa754fec"}, - {file = "coverage-7.10.3-cp314-cp314-win32.whl", hash = "sha256:d7c3d02c2866deb217dce664c71787f4b25420ea3eaf87056f44fb364a3528f5"}, - {file = "coverage-7.10.3-cp314-cp314-win_amd64.whl", hash = "sha256:9c8916d44d9e0fe6cdb2227dc6b0edd8bc6c8ef13438bbbf69af7482d9bb9833"}, - {file = "coverage-7.10.3-cp314-cp314-win_arm64.whl", hash = "sha256:1007d6a2b3cf197c57105cc1ba390d9ff7f0bee215ced4dea530181e49c65ab4"}, - {file = "coverage-7.10.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:ebc8791d346410d096818788877d675ca55c91db87d60e8f477bd41c6970ffc6"}, - {file = "coverage-7.10.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1f4e4d8e75f6fd3c6940ebeed29e3d9d632e1f18f6fb65d33086d99d4d073241"}, - {file = "coverage-7.10.3-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:24581ed69f132b6225a31b0228ae4885731cddc966f8a33fe5987288bdbbbd5e"}, - {file = "coverage-7.10.3-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:ec151569ddfccbf71bac8c422dce15e176167385a00cd86e887f9a80035ce8a5"}, - {file = "coverage-7.10.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2ae8e7c56290b908ee817200c0b65929b8050bc28530b131fe7c6dfee3e7d86b"}, - {file = "coverage-7.10.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5fb742309766d7e48e9eb4dc34bc95a424707bc6140c0e7d9726e794f11b92a0"}, - {file = "coverage-7.10.3-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:c65e2a5b32fbe1e499f1036efa6eb9cb4ea2bf6f7168d0e7a5852f3024f471b1"}, - {file = "coverage-7.10.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d48d2cb07d50f12f4f18d2bb75d9d19e3506c26d96fffabf56d22936e5ed8f7c"}, - {file = "coverage-7.10.3-cp314-cp314t-win32.whl", hash = "sha256:dec0d9bc15ee305e09fe2cd1911d3f0371262d3cfdae05d79515d8cb712b4869"}, - {file = "coverage-7.10.3-cp314-cp314t-win_amd64.whl", hash = "sha256:424ea93a323aa0f7f01174308ea78bde885c3089ec1bef7143a6d93c3e24ef64"}, - {file = "coverage-7.10.3-cp314-cp314t-win_arm64.whl", hash = "sha256:f5983c132a62d93d71c9ef896a0b9bf6e6828d8d2ea32611f58684fba60bba35"}, - {file = "coverage-7.10.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:da749daa7e141985487e1ff90a68315b0845930ed53dc397f4ae8f8bab25b551"}, - {file = "coverage-7.10.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f3126fb6a47d287f461d9b1aa5d1a8c97034d1dffb4f452f2cf211289dae74ef"}, - {file = "coverage-7.10.3-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3da794db13cc27ca40e1ec8127945b97fab78ba548040047d54e7bfa6d442dca"}, - {file = "coverage-7.10.3-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:4e27bebbd184ef8d1c1e092b74a2b7109dcbe2618dce6e96b1776d53b14b3fe8"}, - {file = "coverage-7.10.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8fd4ee2580b9fefbd301b4f8f85b62ac90d1e848bea54f89a5748cf132782118"}, - {file = "coverage-7.10.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:6999920bdd73259ce11cabfc1307484f071ecc6abdb2ca58d98facbcefc70f16"}, - {file = "coverage-7.10.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:c3623f929db885fab100cb88220a5b193321ed37e03af719efdbaf5d10b6e227"}, - {file = "coverage-7.10.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:25b902c5e15dea056485d782e420bb84621cc08ee75d5131ecb3dbef8bd1365f"}, - {file = "coverage-7.10.3-cp39-cp39-win32.whl", hash = "sha256:f930a4d92b004b643183451fe9c8fe398ccf866ed37d172ebaccfd443a097f61"}, - {file = "coverage-7.10.3-cp39-cp39-win_amd64.whl", hash = "sha256:08e638a93c8acba13c7842953f92a33d52d73e410329acd472280d2a21a6c0e1"}, - {file = "coverage-7.10.3-py3-none-any.whl", hash = "sha256:416a8d74dc0adfd33944ba2f405897bab87b7e9e84a391e09d241956bd953ce1"}, - {file = "coverage-7.10.3.tar.gz", hash = "sha256:812ba9250532e4a823b070b0420a36499859542335af3dca8f47fc6aa1a05619"}, + {file = "coverage-7.10.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d92d6edb0ccafd20c6fbf9891ca720b39c2a6a4b4a6f9cf323ca2c986f33e475"}, + {file = "coverage-7.10.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7202da14dc0236884fcc45665ffb2d79d4991a53fbdf152ab22f69f70923cc22"}, + {file = "coverage-7.10.4-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:ada418633ae24ec8d0fcad5efe6fc7aa3c62497c6ed86589e57844ad04365674"}, + {file = "coverage-7.10.4-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b828e33eca6c3322adda3b5884456f98c435182a44917ded05005adfa1415500"}, + {file = "coverage-7.10.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:802793ba397afcfdbe9f91f89d65ae88b958d95edc8caf948e1f47d8b6b2b606"}, + {file = "coverage-7.10.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d0b23512338c54101d3bf7a1ab107d9d75abda1d5f69bc0887fd079253e4c27e"}, + {file = "coverage-7.10.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:f36b7dcf72d06a8c5e2dd3aca02be2b1b5db5f86404627dff834396efce958f2"}, + {file = "coverage-7.10.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:fce316c367a1dc2c411821365592eeb335ff1781956d87a0410eae248188ba51"}, + {file = "coverage-7.10.4-cp310-cp310-win32.whl", hash = "sha256:8c5dab29fc8070b3766b5fc85f8d89b19634584429a2da6d42da5edfadaf32ae"}, + {file = "coverage-7.10.4-cp310-cp310-win_amd64.whl", hash = "sha256:4b0d114616f0fccb529a1817457d5fb52a10e106f86c5fb3b0bd0d45d0d69b93"}, + {file = "coverage-7.10.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:05d5f98ec893d4a2abc8bc5f046f2f4367404e7e5d5d18b83de8fde1093ebc4f"}, + {file = "coverage-7.10.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9267efd28f8994b750d171e58e481e3bbd69e44baed540e4c789f8e368b24b88"}, + {file = "coverage-7.10.4-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:4456a039fdc1a89ea60823d0330f1ac6f97b0dbe9e2b6fb4873e889584b085fb"}, + {file = "coverage-7.10.4-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c2bfbd2a9f7e68a21c5bd191be94bfdb2691ac40d325bac9ef3ae45ff5c753d9"}, + {file = "coverage-7.10.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ab7765f10ae1df7e7fe37de9e64b5a269b812ee22e2da3f84f97b1c7732a0d8"}, + {file = "coverage-7.10.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0a09b13695166236e171ec1627ff8434b9a9bae47528d0ba9d944c912d33b3d2"}, + {file = "coverage-7.10.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5c9e75dfdc0167d5675e9804f04a56b2cf47fb83a524654297000b578b8adcb7"}, + {file = "coverage-7.10.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c751261bfe6481caba15ec005a194cb60aad06f29235a74c24f18546d8377df0"}, + {file = "coverage-7.10.4-cp311-cp311-win32.whl", hash = "sha256:051c7c9e765f003c2ff6e8c81ccea28a70fb5b0142671e4e3ede7cebd45c80af"}, + {file = "coverage-7.10.4-cp311-cp311-win_amd64.whl", hash = "sha256:1a647b152f10be08fb771ae4a1421dbff66141e3d8ab27d543b5eb9ea5af8e52"}, + {file = "coverage-7.10.4-cp311-cp311-win_arm64.whl", hash = "sha256:b09b9e4e1de0d406ca9f19a371c2beefe3193b542f64a6dd40cfcf435b7d6aa0"}, + {file = "coverage-7.10.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a1f0264abcabd4853d4cb9b3d164adbf1565da7dab1da1669e93f3ea60162d79"}, + {file = "coverage-7.10.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:536cbe6b118a4df231b11af3e0f974a72a095182ff8ec5f4868c931e8043ef3e"}, + {file = "coverage-7.10.4-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:9a4c0d84134797b7bf3f080599d0cd501471f6c98b715405166860d79cfaa97e"}, + {file = "coverage-7.10.4-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7c155fc0f9cee8c9803ea0ad153ab6a3b956baa5d4cd993405dc0b45b2a0b9e0"}, + {file = "coverage-7.10.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0a5f2ab6e451d4b07855d8bcf063adf11e199bff421a4ba57f5bb95b7444ca62"}, + {file = "coverage-7.10.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:685b67d99b945b0c221be0780c336b303a7753b3e0ec0d618c795aada25d5e7a"}, + {file = "coverage-7.10.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0c079027e50c2ae44da51c2e294596cbc9dbb58f7ca45b30651c7e411060fc23"}, + {file = "coverage-7.10.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3749aa72b93ce516f77cf5034d8e3c0dfd45c6e8a163a602ede2dc5f9a0bb927"}, + {file = "coverage-7.10.4-cp312-cp312-win32.whl", hash = "sha256:fecb97b3a52fa9bcd5a7375e72fae209088faf671d39fae67261f37772d5559a"}, + {file = "coverage-7.10.4-cp312-cp312-win_amd64.whl", hash = "sha256:26de58f355626628a21fe6a70e1e1fad95702dafebfb0685280962ae1449f17b"}, + {file = "coverage-7.10.4-cp312-cp312-win_arm64.whl", hash = "sha256:67e8885408f8325198862bc487038a4980c9277d753cb8812510927f2176437a"}, + {file = "coverage-7.10.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2b8e1d2015d5dfdbf964ecef12944c0c8c55b885bb5c0467ae8ef55e0e151233"}, + {file = "coverage-7.10.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:25735c299439018d66eb2dccf54f625aceb78645687a05f9f848f6e6c751e169"}, + {file = "coverage-7.10.4-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:715c06cb5eceac4d9b7cdf783ce04aa495f6aff657543fea75c30215b28ddb74"}, + {file = "coverage-7.10.4-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:e017ac69fac9aacd7df6dc464c05833e834dc5b00c914d7af9a5249fcccf07ef"}, + {file = "coverage-7.10.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bad180cc40b3fccb0f0e8c702d781492654ac2580d468e3ffc8065e38c6c2408"}, + {file = "coverage-7.10.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:becbdcd14f685fada010a5f792bf0895675ecf7481304fe159f0cd3f289550bd"}, + {file = "coverage-7.10.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:0b485ca21e16a76f68060911f97ebbe3e0d891da1dbbce6af7ca1ab3f98b9097"}, + {file = "coverage-7.10.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6c1d098ccfe8e1e0a1ed9a0249138899948afd2978cbf48eb1cc3fcd38469690"}, + {file = "coverage-7.10.4-cp313-cp313-win32.whl", hash = "sha256:8630f8af2ca84b5c367c3df907b1706621abe06d6929f5045fd628968d421e6e"}, + {file = "coverage-7.10.4-cp313-cp313-win_amd64.whl", hash = "sha256:f68835d31c421736be367d32f179e14ca932978293fe1b4c7a6a49b555dff5b2"}, + {file = "coverage-7.10.4-cp313-cp313-win_arm64.whl", hash = "sha256:6eaa61ff6724ca7ebc5326d1fae062d85e19b38dd922d50903702e6078370ae7"}, + {file = "coverage-7.10.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:702978108876bfb3d997604930b05fe769462cc3000150b0e607b7b444f2fd84"}, + {file = "coverage-7.10.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e8f978e8c5521d9c8f2086ac60d931d583fab0a16f382f6eb89453fe998e2484"}, + {file = "coverage-7.10.4-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:df0ac2ccfd19351411c45e43ab60932b74472e4648b0a9edf6a3b58846e246a9"}, + {file = "coverage-7.10.4-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:73a0d1aaaa3796179f336448e1576a3de6fc95ff4f07c2d7251d4caf5d18cf8d"}, + {file = "coverage-7.10.4-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:873da6d0ed6b3ffc0bc01f2c7e3ad7e2023751c0d8d86c26fe7322c314b031dc"}, + {file = "coverage-7.10.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c6446c75b0e7dda5daa876a1c87b480b2b52affb972fedd6c22edf1aaf2e00ec"}, + {file = "coverage-7.10.4-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:6e73933e296634e520390c44758d553d3b573b321608118363e52113790633b9"}, + {file = "coverage-7.10.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:52073d4b08d2cb571234c8a71eb32af3c6923149cf644a51d5957ac128cf6aa4"}, + {file = "coverage-7.10.4-cp313-cp313t-win32.whl", hash = "sha256:e24afb178f21f9ceb1aefbc73eb524769aa9b504a42b26857243f881af56880c"}, + {file = "coverage-7.10.4-cp313-cp313t-win_amd64.whl", hash = "sha256:be04507ff1ad206f4be3d156a674e3fb84bbb751ea1b23b142979ac9eebaa15f"}, + {file = "coverage-7.10.4-cp313-cp313t-win_arm64.whl", hash = "sha256:f3e3ff3f69d02b5dad67a6eac68cc9c71ae343b6328aae96e914f9f2f23a22e2"}, + {file = "coverage-7.10.4-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:a59fe0af7dd7211ba595cf7e2867458381f7e5d7b4cffe46274e0b2f5b9f4eb4"}, + {file = "coverage-7.10.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:3a6c35c5b70f569ee38dc3350cd14fdd0347a8b389a18bb37538cc43e6f730e6"}, + {file = "coverage-7.10.4-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:acb7baf49f513554c4af6ef8e2bd6e8ac74e6ea0c7386df8b3eb586d82ccccc4"}, + {file = "coverage-7.10.4-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:a89afecec1ed12ac13ed203238b560cbfad3522bae37d91c102e690b8b1dc46c"}, + {file = "coverage-7.10.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:480442727f464407d8ade6e677b7f21f3b96a9838ab541b9a28ce9e44123c14e"}, + {file = "coverage-7.10.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a89bf193707f4a17f1ed461504031074d87f035153239f16ce86dfb8f8c7ac76"}, + {file = "coverage-7.10.4-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:3ddd912c2fc440f0fb3229e764feec85669d5d80a988ff1b336a27d73f63c818"}, + {file = "coverage-7.10.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:8a538944ee3a42265e61c7298aeba9ea43f31c01271cf028f437a7b4075592cf"}, + {file = "coverage-7.10.4-cp314-cp314-win32.whl", hash = "sha256:fd2e6002be1c62476eb862b8514b1ba7e7684c50165f2a8d389e77da6c9a2ebd"}, + {file = "coverage-7.10.4-cp314-cp314-win_amd64.whl", hash = "sha256:ec113277f2b5cf188d95fb66a65c7431f2b9192ee7e6ec9b72b30bbfb53c244a"}, + {file = "coverage-7.10.4-cp314-cp314-win_arm64.whl", hash = "sha256:9744954bfd387796c6a091b50d55ca7cac3d08767795b5eec69ad0f7dbf12d38"}, + {file = "coverage-7.10.4-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:5af4829904dda6aabb54a23879f0f4412094ba9ef153aaa464e3c1b1c9bc98e6"}, + {file = "coverage-7.10.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7bba5ed85e034831fac761ae506c0644d24fd5594727e174b5a73aff343a7508"}, + {file = "coverage-7.10.4-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d57d555b0719834b55ad35045de6cc80fc2b28e05adb6b03c98479f9553b387f"}, + {file = "coverage-7.10.4-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:ba62c51a72048bb1ea72db265e6bd8beaabf9809cd2125bbb5306c6ce105f214"}, + {file = "coverage-7.10.4-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0acf0c62a6095f07e9db4ec365cc58c0ef5babb757e54745a1aa2ea2a2564af1"}, + {file = "coverage-7.10.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e1033bf0f763f5cf49ffe6594314b11027dcc1073ac590b415ea93463466deec"}, + {file = "coverage-7.10.4-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:92c29eff894832b6a40da1789b1f252305af921750b03ee4535919db9179453d"}, + {file = "coverage-7.10.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:822c4c830989c2093527e92acd97be4638a44eb042b1bdc0e7a278d84a070bd3"}, + {file = "coverage-7.10.4-cp314-cp314t-win32.whl", hash = "sha256:e694d855dac2e7cf194ba33653e4ba7aad7267a802a7b3fc4347d0517d5d65cd"}, + {file = "coverage-7.10.4-cp314-cp314t-win_amd64.whl", hash = "sha256:efcc54b38ef7d5bfa98050f220b415bc5bb3d432bd6350a861cf6da0ede2cdcd"}, + {file = "coverage-7.10.4-cp314-cp314t-win_arm64.whl", hash = "sha256:6f3a3496c0fa26bfac4ebc458747b778cff201c8ae94fa05e1391bab0dbc473c"}, + {file = "coverage-7.10.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:48fd4d52600c2a9d5622e52dfae674a7845c5e1dceaf68b88c99feb511fbcfd6"}, + {file = "coverage-7.10.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:56217b470d09d69e6b7dcae38200f95e389a77db801cb129101697a4553b18b6"}, + {file = "coverage-7.10.4-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:44ac3f21a6e28c5ff7f7a47bca5f87885f6a1e623e637899125ba47acd87334d"}, + {file = "coverage-7.10.4-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:3387739d72c84d17b4d2f7348749cac2e6700e7152026912b60998ee9a40066b"}, + {file = "coverage-7.10.4-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3f111ff20d9a6348e0125be892608e33408dd268f73b020940dfa8511ad05503"}, + {file = "coverage-7.10.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:01a852f0a9859734b018a3f483cc962d0b381d48d350b1a0c47d618c73a0c398"}, + {file = "coverage-7.10.4-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:225111dd06759ba4e37cee4c0b4f3df2b15c879e9e3c37bf986389300b9917c3"}, + {file = "coverage-7.10.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2178d4183bd1ba608f0bb12e71e55838ba1b7dbb730264f8b08de9f8ef0c27d0"}, + {file = "coverage-7.10.4-cp39-cp39-win32.whl", hash = "sha256:93d175fe81913aee7a6ea430abbdf2a79f1d9fd451610e12e334e4fe3264f563"}, + {file = "coverage-7.10.4-cp39-cp39-win_amd64.whl", hash = "sha256:2221a823404bb941c7721cf0ef55ac6ee5c25d905beb60c0bba5e5e85415d353"}, + {file = "coverage-7.10.4-py3-none-any.whl", hash = "sha256:065d75447228d05121e5c938ca8f0e91eed60a1eb2d1258d42d5084fecfc3302"}, + {file = "coverage-7.10.4.tar.gz", hash = "sha256:25f5130af6c8e7297fd14634955ba9e1697f47143f289e2a23284177c0061d27"}, ] [package.dependencies] @@ -973,14 +973,14 @@ files = [ [[package]] name = "jsonschema" -version = "4.25.0" +version = "4.25.1" description = "An implementation of JSON Schema validation for Python" optional = false python-versions = ">=3.9" groups = ["charm-libs", "unit"] files = [ - {file = "jsonschema-4.25.0-py3-none-any.whl", hash = "sha256:24c2e8da302de79c8b9382fee3e76b355e44d2a4364bb207159ce10b517bd716"}, - {file = "jsonschema-4.25.0.tar.gz", hash = "sha256:e63acf5c11762c0e6672ffb61482bdf57f0876684d8d249c0fe2d730d48bc55f"}, + {file = "jsonschema-4.25.1-py3-none-any.whl", hash = "sha256:3fba0169e345c7175110351d456342c364814cfcf3b964ba4587f22915230a63"}, + {file = "jsonschema-4.25.1.tar.gz", hash = "sha256:e4a9655ce0da0c0b67a085847e00a3a51449e1157f4f75e9fb5aa545e122eb85"}, ] [package.dependencies] @@ -2027,14 +2027,14 @@ typing-extensions = {version = ">=4.4.0", markers = "python_version < \"3.13\""} [[package]] name = "requests" -version = "2.32.4" +version = "2.32.5" description = "Python HTTP for Humans." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main", "charm-libs", "integration"] files = [ - {file = "requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c"}, - {file = "requests-2.32.4.tar.gz", hash = "sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422"}, + {file = "requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6"}, + {file = "requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf"}, ] [package.dependencies] @@ -2248,30 +2248,31 @@ pyasn1 = ">=0.1.3" [[package]] name = "ruff" -version = "0.12.8" +version = "0.12.9" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" groups = ["format"] files = [ - {file = "ruff-0.12.8-py3-none-linux_armv6l.whl", hash = "sha256:63cb5a5e933fc913e5823a0dfdc3c99add73f52d139d6cd5cc8639d0e0465513"}, - {file = "ruff-0.12.8-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:9a9bbe28f9f551accf84a24c366c1aa8774d6748438b47174f8e8565ab9dedbc"}, - {file = "ruff-0.12.8-py3-none-macosx_11_0_arm64.whl", hash = "sha256:2fae54e752a3150f7ee0e09bce2e133caf10ce9d971510a9b925392dc98d2fec"}, - {file = "ruff-0.12.8-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c0acbcf01206df963d9331b5838fb31f3b44fa979ee7fa368b9b9057d89f4a53"}, - {file = "ruff-0.12.8-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ae3e7504666ad4c62f9ac8eedb52a93f9ebdeb34742b8b71cd3cccd24912719f"}, - {file = "ruff-0.12.8-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cb82efb5d35d07497813a1c5647867390a7d83304562607f3579602fa3d7d46f"}, - {file = "ruff-0.12.8-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:dbea798fc0065ad0b84a2947b0aff4233f0cb30f226f00a2c5850ca4393de609"}, - {file = "ruff-0.12.8-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:49ebcaccc2bdad86fd51b7864e3d808aad404aab8df33d469b6e65584656263a"}, - {file = "ruff-0.12.8-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ac9c570634b98c71c88cb17badd90f13fc076a472ba6ef1d113d8ed3df109fb"}, - {file = "ruff-0.12.8-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:560e0cd641e45591a3e42cb50ef61ce07162b9c233786663fdce2d8557d99818"}, - {file = "ruff-0.12.8-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:71c83121512e7743fba5a8848c261dcc454cafb3ef2934a43f1b7a4eb5a447ea"}, - {file = "ruff-0.12.8-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:de4429ef2ba091ecddedd300f4c3f24bca875d3d8b23340728c3cb0da81072c3"}, - {file = "ruff-0.12.8-py3-none-musllinux_1_2_i686.whl", hash = "sha256:a2cab5f60d5b65b50fba39a8950c8746df1627d54ba1197f970763917184b161"}, - {file = "ruff-0.12.8-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:45c32487e14f60b88aad6be9fd5da5093dbefb0e3e1224131cb1d441d7cb7d46"}, - {file = "ruff-0.12.8-py3-none-win32.whl", hash = "sha256:daf3475060a617fd5bc80638aeaf2f5937f10af3ec44464e280a9d2218e720d3"}, - {file = "ruff-0.12.8-py3-none-win_amd64.whl", hash = "sha256:7209531f1a1fcfbe8e46bcd7ab30e2f43604d8ba1c49029bb420b103d0b5f76e"}, - {file = "ruff-0.12.8-py3-none-win_arm64.whl", hash = "sha256:c90e1a334683ce41b0e7a04f41790c429bf5073b62c1ae701c9dc5b3d14f0749"}, - {file = "ruff-0.12.8.tar.gz", hash = "sha256:4cb3a45525176e1009b2b64126acf5f9444ea59066262791febf55e40493a033"}, + {file = "ruff-0.12.9-py3-none-linux_armv6l.whl", hash = "sha256:fcebc6c79fcae3f220d05585229463621f5dbf24d79fdc4936d9302e177cfa3e"}, + {file = "ruff-0.12.9-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:aed9d15f8c5755c0e74467731a007fcad41f19bcce41cd75f768bbd687f8535f"}, + {file = "ruff-0.12.9-py3-none-macosx_11_0_arm64.whl", hash = "sha256:5b15ea354c6ff0d7423814ba6d44be2807644d0c05e9ed60caca87e963e93f70"}, + {file = "ruff-0.12.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d596c2d0393c2502eaabfef723bd74ca35348a8dac4267d18a94910087807c53"}, + {file = "ruff-0.12.9-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1b15599931a1a7a03c388b9c5df1bfa62be7ede6eb7ef753b272381f39c3d0ff"}, + {file = "ruff-0.12.9-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3d02faa2977fb6f3f32ddb7828e212b7dd499c59eb896ae6c03ea5c303575756"}, + {file = "ruff-0.12.9-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:17d5b6b0b3a25259b69ebcba87908496e6830e03acfb929ef9fd4c58675fa2ea"}, + {file = "ruff-0.12.9-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:72db7521860e246adbb43f6ef464dd2a532ef2ef1f5dd0d470455b8d9f1773e0"}, + {file = "ruff-0.12.9-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a03242c1522b4e0885af63320ad754d53983c9599157ee33e77d748363c561ce"}, + {file = "ruff-0.12.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fc83e4e9751e6c13b5046d7162f205d0a7bac5840183c5beebf824b08a27340"}, + {file = "ruff-0.12.9-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:881465ed56ba4dd26a691954650de6ad389a2d1fdb130fe51ff18a25639fe4bb"}, + {file = "ruff-0.12.9-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:43f07a3ccfc62cdb4d3a3348bf0588358a66da756aa113e071b8ca8c3b9826af"}, + {file = "ruff-0.12.9-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:07adb221c54b6bba24387911e5734357f042e5669fa5718920ee728aba3cbadc"}, + {file = "ruff-0.12.9-py3-none-musllinux_1_2_i686.whl", hash = "sha256:f5cd34fabfdea3933ab85d72359f118035882a01bff15bd1d2b15261d85d5f66"}, + {file = "ruff-0.12.9-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:f6be1d2ca0686c54564da8e7ee9e25f93bdd6868263805f8c0b8fc6a449db6d7"}, + {file = "ruff-0.12.9-py3-none-win32.whl", hash = "sha256:cc7a37bd2509974379d0115cc5608a1a4a6c4bff1b452ea69db83c8855d53f93"}, + {file = "ruff-0.12.9-py3-none-win_amd64.whl", hash = "sha256:6fb15b1977309741d7d098c8a3cb7a30bc112760a00fb6efb7abc85f00ba5908"}, + {file = "ruff-0.12.9-py3-none-win_arm64.whl", hash = "sha256:63c8c819739d86b96d500cce885956a1a48ab056bbcbc61b747ad494b2485089"}, + {file = "ruff-0.12.9.tar.gz", hash = "sha256:fbd94b2e3c623f659962934e52c2bea6fc6da11f667a427a368adaf3af2c866a"}, ] [[package]] @@ -2568,91 +2569,93 @@ files = [ [[package]] name = "wrapt" -version = "1.17.2" +version = "1.17.3" description = "Module for decorators, wrappers and monkey patching." optional = false python-versions = ">=3.8" groups = ["main", "charm-libs"] files = [ - {file = "wrapt-1.17.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3d57c572081fed831ad2d26fd430d565b76aa277ed1d30ff4d40670b1c0dd984"}, - {file = "wrapt-1.17.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b5e251054542ae57ac7f3fba5d10bfff615b6c2fb09abeb37d2f1463f841ae22"}, - {file = "wrapt-1.17.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:80dd7db6a7cb57ffbc279c4394246414ec99537ae81ffd702443335a61dbf3a7"}, - {file = "wrapt-1.17.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a6e821770cf99cc586d33833b2ff32faebdbe886bd6322395606cf55153246c"}, - {file = "wrapt-1.17.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b60fb58b90c6d63779cb0c0c54eeb38941bae3ecf7a73c764c52c88c2dcb9d72"}, - {file = "wrapt-1.17.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b870b5df5b71d8c3359d21be8f0d6c485fa0ebdb6477dda51a1ea54a9b558061"}, - {file = "wrapt-1.17.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4011d137b9955791f9084749cba9a367c68d50ab8d11d64c50ba1688c9b457f2"}, - {file = "wrapt-1.17.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:1473400e5b2733e58b396a04eb7f35f541e1fb976d0c0724d0223dd607e0f74c"}, - {file = "wrapt-1.17.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3cedbfa9c940fdad3e6e941db7138e26ce8aad38ab5fe9dcfadfed9db7a54e62"}, - {file = "wrapt-1.17.2-cp310-cp310-win32.whl", hash = "sha256:582530701bff1dec6779efa00c516496968edd851fba224fbd86e46cc6b73563"}, - {file = "wrapt-1.17.2-cp310-cp310-win_amd64.whl", hash = "sha256:58705da316756681ad3c9c73fd15499aa4d8c69f9fd38dc8a35e06c12468582f"}, - {file = "wrapt-1.17.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ff04ef6eec3eee8a5efef2401495967a916feaa353643defcc03fc74fe213b58"}, - {file = "wrapt-1.17.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4db983e7bca53819efdbd64590ee96c9213894272c776966ca6306b73e4affda"}, - {file = "wrapt-1.17.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9abc77a4ce4c6f2a3168ff34b1da9b0f311a8f1cfd694ec96b0603dff1c79438"}, - {file = "wrapt-1.17.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b929ac182f5ace000d459c59c2c9c33047e20e935f8e39371fa6e3b85d56f4a"}, - {file = "wrapt-1.17.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f09b286faeff3c750a879d336fb6d8713206fc97af3adc14def0cdd349df6000"}, - {file = "wrapt-1.17.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a7ed2d9d039bd41e889f6fb9364554052ca21ce823580f6a07c4ec245c1f5d6"}, - {file = "wrapt-1.17.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:129a150f5c445165ff941fc02ee27df65940fcb8a22a61828b1853c98763a64b"}, - {file = "wrapt-1.17.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:1fb5699e4464afe5c7e65fa51d4f99e0b2eadcc176e4aa33600a3df7801d6662"}, - {file = "wrapt-1.17.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9a2bce789a5ea90e51a02dfcc39e31b7f1e662bc3317979aa7e5538e3a034f72"}, - {file = "wrapt-1.17.2-cp311-cp311-win32.whl", hash = "sha256:4afd5814270fdf6380616b321fd31435a462019d834f83c8611a0ce7484c7317"}, - {file = "wrapt-1.17.2-cp311-cp311-win_amd64.whl", hash = "sha256:acc130bc0375999da18e3d19e5a86403667ac0c4042a094fefb7eec8ebac7cf3"}, - {file = "wrapt-1.17.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:d5e2439eecc762cd85e7bd37161d4714aa03a33c5ba884e26c81559817ca0925"}, - {file = "wrapt-1.17.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3fc7cb4c1c744f8c05cd5f9438a3caa6ab94ce8344e952d7c45a8ed59dd88392"}, - {file = "wrapt-1.17.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8fdbdb757d5390f7c675e558fd3186d590973244fab0c5fe63d373ade3e99d40"}, - {file = "wrapt-1.17.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5bb1d0dbf99411f3d871deb6faa9aabb9d4e744d67dcaaa05399af89d847a91d"}, - {file = "wrapt-1.17.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d18a4865f46b8579d44e4fe1e2bcbc6472ad83d98e22a26c963d46e4c125ef0b"}, - {file = "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"}, - {file = "wrapt-1.17.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6d9187b01bebc3875bac9b087948a2bccefe464a7d8f627cf6e48b1bbae30f82"}, - {file = "wrapt-1.17.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:9e8659775f1adf02eb1e6f109751268e493c73716ca5761f8acb695e52a756ae"}, - {file = "wrapt-1.17.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e8b2816ebef96d83657b56306152a93909a83f23994f4b30ad4573b00bd11bb9"}, - {file = "wrapt-1.17.2-cp312-cp312-win32.whl", hash = "sha256:468090021f391fe0056ad3e807e3d9034e0fd01adcd3bdfba977b6fdf4213ea9"}, - {file = "wrapt-1.17.2-cp312-cp312-win_amd64.whl", hash = "sha256:ec89ed91f2fa8e3f52ae53cd3cf640d6feff92ba90d62236a81e4e563ac0e991"}, - {file = "wrapt-1.17.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6ed6ffac43aecfe6d86ec5b74b06a5be33d5bb9243d055141e8cabb12aa08125"}, - {file = "wrapt-1.17.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:35621ae4c00e056adb0009f8e86e28eb4a41a4bfa8f9bfa9fca7d343fe94f998"}, - {file = "wrapt-1.17.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a604bf7a053f8362d27eb9fefd2097f82600b856d5abe996d623babd067b1ab5"}, - {file = "wrapt-1.17.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5cbabee4f083b6b4cd282f5b817a867cf0b1028c54d445b7ec7cfe6505057cf8"}, - {file = "wrapt-1.17.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49703ce2ddc220df165bd2962f8e03b84c89fee2d65e1c24a7defff6f988f4d6"}, - {file = "wrapt-1.17.2-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8112e52c5822fc4253f3901b676c55ddf288614dc7011634e2719718eaa187dc"}, - {file = "wrapt-1.17.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9fee687dce376205d9a494e9c121e27183b2a3df18037f89d69bd7b35bcf59e2"}, - {file = "wrapt-1.17.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:18983c537e04d11cf027fbb60a1e8dfd5190e2b60cc27bc0808e653e7b218d1b"}, - {file = "wrapt-1.17.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:703919b1633412ab54bcf920ab388735832fdcb9f9a00ae49387f0fe67dad504"}, - {file = "wrapt-1.17.2-cp313-cp313-win32.whl", hash = "sha256:abbb9e76177c35d4e8568e58650aa6926040d6a9f6f03435b7a522bf1c487f9a"}, - {file = "wrapt-1.17.2-cp313-cp313-win_amd64.whl", hash = "sha256:69606d7bb691b50a4240ce6b22ebb319c1cfb164e5f6569835058196e0f3a845"}, - {file = "wrapt-1.17.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:4a721d3c943dae44f8e243b380cb645a709ba5bd35d3ad27bc2ed947e9c68192"}, - {file = "wrapt-1.17.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:766d8bbefcb9e00c3ac3b000d9acc51f1b399513f44d77dfe0eb026ad7c9a19b"}, - {file = "wrapt-1.17.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e496a8ce2c256da1eb98bd15803a79bee00fc351f5dfb9ea82594a3f058309e0"}, - {file = "wrapt-1.17.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40d615e4fe22f4ad3528448c193b218e077656ca9ccb22ce2cb20db730f8d306"}, - {file = "wrapt-1.17.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a5aaeff38654462bc4b09023918b7f21790efb807f54c000a39d41d69cf552cb"}, - {file = "wrapt-1.17.2-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a7d15bbd2bc99e92e39f49a04653062ee6085c0e18b3b7512a4f2fe91f2d681"}, - {file = "wrapt-1.17.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:e3890b508a23299083e065f435a492b5435eba6e304a7114d2f919d400888cc6"}, - {file = "wrapt-1.17.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:8c8b293cd65ad716d13d8dd3624e42e5a19cc2a2f1acc74b30c2c13f15cb61a6"}, - {file = "wrapt-1.17.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4c82b8785d98cdd9fed4cac84d765d234ed3251bd6afe34cb7ac523cb93e8b4f"}, - {file = "wrapt-1.17.2-cp313-cp313t-win32.whl", hash = "sha256:13e6afb7fe71fe7485a4550a8844cc9ffbe263c0f1a1eea569bc7091d4898555"}, - {file = "wrapt-1.17.2-cp313-cp313t-win_amd64.whl", hash = "sha256:eaf675418ed6b3b31c7a989fd007fa7c3be66ce14e5c3b27336383604c9da85c"}, - {file = "wrapt-1.17.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5c803c401ea1c1c18de70a06a6f79fcc9c5acfc79133e9869e730ad7f8ad8ef9"}, - {file = "wrapt-1.17.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f917c1180fdb8623c2b75a99192f4025e412597c50b2ac870f156de8fb101119"}, - {file = "wrapt-1.17.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ecc840861360ba9d176d413a5489b9a0aff6d6303d7e733e2c4623cfa26904a6"}, - {file = "wrapt-1.17.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb87745b2e6dc56361bfde481d5a378dc314b252a98d7dd19a651a3fa58f24a9"}, - {file = "wrapt-1.17.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58455b79ec2661c3600e65c0a716955adc2410f7383755d537584b0de41b1d8a"}, - {file = "wrapt-1.17.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b4e42a40a5e164cbfdb7b386c966a588b1047558a990981ace551ed7e12ca9c2"}, - {file = "wrapt-1.17.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:91bd7d1773e64019f9288b7a5101f3ae50d3d8e6b1de7edee9c2ccc1d32f0c0a"}, - {file = "wrapt-1.17.2-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:bb90fb8bda722a1b9d48ac1e6c38f923ea757b3baf8ebd0c82e09c5c1a0e7a04"}, - {file = "wrapt-1.17.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:08e7ce672e35efa54c5024936e559469436f8b8096253404faeb54d2a878416f"}, - {file = "wrapt-1.17.2-cp38-cp38-win32.whl", hash = "sha256:410a92fefd2e0e10d26210e1dfb4a876ddaf8439ef60d6434f21ef8d87efc5b7"}, - {file = "wrapt-1.17.2-cp38-cp38-win_amd64.whl", hash = "sha256:95c658736ec15602da0ed73f312d410117723914a5c91a14ee4cdd72f1d790b3"}, - {file = "wrapt-1.17.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:99039fa9e6306880572915728d7f6c24a86ec57b0a83f6b2491e1d8ab0235b9a"}, - {file = "wrapt-1.17.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2696993ee1eebd20b8e4ee4356483c4cb696066ddc24bd70bcbb80fa56ff9061"}, - {file = "wrapt-1.17.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:612dff5db80beef9e649c6d803a8d50c409082f1fedc9dbcdfde2983b2025b82"}, - {file = "wrapt-1.17.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62c2caa1585c82b3f7a7ab56afef7b3602021d6da34fbc1cf234ff139fed3cd9"}, - {file = "wrapt-1.17.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c958bcfd59bacc2d0249dcfe575e71da54f9dcf4a8bdf89c4cb9a68a1170d73f"}, - {file = "wrapt-1.17.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc78a84e2dfbc27afe4b2bd7c80c8db9bca75cc5b85df52bfe634596a1da846b"}, - {file = "wrapt-1.17.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:ba0f0eb61ef00ea10e00eb53a9129501f52385c44853dbd6c4ad3f403603083f"}, - {file = "wrapt-1.17.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1e1fe0e6ab7775fd842bc39e86f6dcfc4507ab0ffe206093e76d61cde37225c8"}, - {file = "wrapt-1.17.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c86563182421896d73858e08e1db93afdd2b947a70064b813d515d66549e15f9"}, - {file = "wrapt-1.17.2-cp39-cp39-win32.whl", hash = "sha256:f393cda562f79828f38a819f4788641ac7c4085f30f1ce1a68672baa686482bb"}, - {file = "wrapt-1.17.2-cp39-cp39-win_amd64.whl", hash = "sha256:36ccae62f64235cf8ddb682073a60519426fdd4725524ae38874adf72b5f2aeb"}, - {file = "wrapt-1.17.2-py3-none-any.whl", hash = "sha256:b18f2d1533a71f069c7f82d524a52599053d4c7166e9dd374ae2136b7f40f7c8"}, - {file = "wrapt-1.17.2.tar.gz", hash = "sha256:41388e9d4d1522446fe79d3213196bd9e3b301a336965b9e27ca2788ebd122f3"}, + {file = "wrapt-1.17.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:88bbae4d40d5a46142e70d58bf664a89b6b4befaea7b2ecc14e03cedb8e06c04"}, + {file = "wrapt-1.17.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6b13af258d6a9ad602d57d889f83b9d5543acd471eee12eb51f5b01f8eb1bc2"}, + {file = "wrapt-1.17.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd341868a4b6714a5962c1af0bd44f7c404ef78720c7de4892901e540417111c"}, + {file = "wrapt-1.17.3-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f9b2601381be482f70e5d1051a5965c25fb3625455a2bf520b5a077b22afb775"}, + {file = "wrapt-1.17.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:343e44b2a8e60e06a7e0d29c1671a0d9951f59174f3709962b5143f60a2a98bd"}, + {file = "wrapt-1.17.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:33486899acd2d7d3066156b03465b949da3fd41a5da6e394ec49d271baefcf05"}, + {file = "wrapt-1.17.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e6f40a8aa5a92f150bdb3e1c44b7e98fb7113955b2e5394122fa5532fec4b418"}, + {file = "wrapt-1.17.3-cp310-cp310-win32.whl", hash = "sha256:a36692b8491d30a8c75f1dfee65bef119d6f39ea84ee04d9f9311f83c5ad9390"}, + {file = "wrapt-1.17.3-cp310-cp310-win_amd64.whl", hash = "sha256:afd964fd43b10c12213574db492cb8f73b2f0826c8df07a68288f8f19af2ebe6"}, + {file = "wrapt-1.17.3-cp310-cp310-win_arm64.whl", hash = "sha256:af338aa93554be859173c39c85243970dc6a289fa907402289eeae7543e1ae18"}, + {file = "wrapt-1.17.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:273a736c4645e63ac582c60a56b0acb529ef07f78e08dc6bfadf6a46b19c0da7"}, + {file = "wrapt-1.17.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5531d911795e3f935a9c23eb1c8c03c211661a5060aab167065896bbf62a5f85"}, + {file = "wrapt-1.17.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0610b46293c59a3adbae3dee552b648b984176f8562ee0dba099a56cfbe4df1f"}, + {file = "wrapt-1.17.3-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b32888aad8b6e68f83a8fdccbf3165f5469702a7544472bdf41f582970ed3311"}, + {file = "wrapt-1.17.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8cccf4f81371f257440c88faed6b74f1053eef90807b77e31ca057b2db74edb1"}, + {file = "wrapt-1.17.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8a210b158a34164de8bb68b0e7780041a903d7b00c87e906fb69928bf7890d5"}, + {file = "wrapt-1.17.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:79573c24a46ce11aab457b472efd8d125e5a51da2d1d24387666cd85f54c05b2"}, + {file = "wrapt-1.17.3-cp311-cp311-win32.whl", hash = "sha256:c31eebe420a9a5d2887b13000b043ff6ca27c452a9a22fa71f35f118e8d4bf89"}, + {file = "wrapt-1.17.3-cp311-cp311-win_amd64.whl", hash = "sha256:0b1831115c97f0663cb77aa27d381237e73ad4f721391a9bfb2fe8bc25fa6e77"}, + {file = "wrapt-1.17.3-cp311-cp311-win_arm64.whl", hash = "sha256:5a7b3c1ee8265eb4c8f1b7d29943f195c00673f5ab60c192eba2d4a7eae5f46a"}, + {file = "wrapt-1.17.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ab232e7fdb44cdfbf55fc3afa31bcdb0d8980b9b95c38b6405df2acb672af0e0"}, + {file = "wrapt-1.17.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:9baa544e6acc91130e926e8c802a17f3b16fbea0fd441b5a60f5cf2cc5c3deba"}, + {file = "wrapt-1.17.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6b538e31eca1a7ea4605e44f81a48aa24c4632a277431a6ed3f328835901f4fd"}, + {file = "wrapt-1.17.3-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:042ec3bb8f319c147b1301f2393bc19dba6e176b7da446853406d041c36c7828"}, + {file = "wrapt-1.17.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3af60380ba0b7b5aeb329bc4e402acd25bd877e98b3727b0135cb5c2efdaefe9"}, + {file = "wrapt-1.17.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0b02e424deef65c9f7326d8c19220a2c9040c51dc165cddb732f16198c168396"}, + {file = "wrapt-1.17.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:74afa28374a3c3a11b3b5e5fca0ae03bef8450d6aa3ab3a1e2c30e3a75d023dc"}, + {file = "wrapt-1.17.3-cp312-cp312-win32.whl", hash = "sha256:4da9f45279fff3543c371d5ababc57a0384f70be244de7759c85a7f989cb4ebe"}, + {file = "wrapt-1.17.3-cp312-cp312-win_amd64.whl", hash = "sha256:e71d5c6ebac14875668a1e90baf2ea0ef5b7ac7918355850c0908ae82bcb297c"}, + {file = "wrapt-1.17.3-cp312-cp312-win_arm64.whl", hash = "sha256:604d076c55e2fdd4c1c03d06dc1a31b95130010517b5019db15365ec4a405fc6"}, + {file = "wrapt-1.17.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a47681378a0439215912ef542c45a783484d4dd82bac412b71e59cf9c0e1cea0"}, + {file = "wrapt-1.17.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:54a30837587c6ee3cd1a4d1c2ec5d24e77984d44e2f34547e2323ddb4e22eb77"}, + {file = "wrapt-1.17.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:16ecf15d6af39246fe33e507105d67e4b81d8f8d2c6598ff7e3ca1b8a37213f7"}, + {file = "wrapt-1.17.3-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6fd1ad24dc235e4ab88cda009e19bf347aabb975e44fd5c2fb22a3f6e4141277"}, + {file = "wrapt-1.17.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ed61b7c2d49cee3c027372df5809a59d60cf1b6c2f81ee980a091f3afed6a2d"}, + {file = "wrapt-1.17.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:423ed5420ad5f5529db9ce89eac09c8a2f97da18eb1c870237e84c5a5c2d60aa"}, + {file = "wrapt-1.17.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e01375f275f010fcbf7f643b4279896d04e571889b8a5b3f848423d91bf07050"}, + {file = "wrapt-1.17.3-cp313-cp313-win32.whl", hash = "sha256:53e5e39ff71b3fc484df8a522c933ea2b7cdd0d5d15ae82e5b23fde87d44cbd8"}, + {file = "wrapt-1.17.3-cp313-cp313-win_amd64.whl", hash = "sha256:1f0b2f40cf341ee8cc1a97d51ff50dddb9fcc73241b9143ec74b30fc4f44f6cb"}, + {file = "wrapt-1.17.3-cp313-cp313-win_arm64.whl", hash = "sha256:7425ac3c54430f5fc5e7b6f41d41e704db073309acfc09305816bc6a0b26bb16"}, + {file = "wrapt-1.17.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:cf30f6e3c077c8e6a9a7809c94551203c8843e74ba0c960f4a98cd80d4665d39"}, + {file = "wrapt-1.17.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:e228514a06843cae89621384cfe3a80418f3c04aadf8a3b14e46a7be704e4235"}, + {file = "wrapt-1.17.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:5ea5eb3c0c071862997d6f3e02af1d055f381b1d25b286b9d6644b79db77657c"}, + {file = "wrapt-1.17.3-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:281262213373b6d5e4bb4353bc36d1ba4084e6d6b5d242863721ef2bf2c2930b"}, + {file = "wrapt-1.17.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dc4a8d2b25efb6681ecacad42fca8859f88092d8732b170de6a5dddd80a1c8fa"}, + {file = "wrapt-1.17.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:373342dd05b1d07d752cecbec0c41817231f29f3a89aa8b8843f7b95992ed0c7"}, + {file = "wrapt-1.17.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d40770d7c0fd5cbed9d84b2c3f2e156431a12c9a37dc6284060fb4bec0b7ffd4"}, + {file = "wrapt-1.17.3-cp314-cp314-win32.whl", hash = "sha256:fbd3c8319de8e1dc79d346929cd71d523622da527cca14e0c1d257e31c2b8b10"}, + {file = "wrapt-1.17.3-cp314-cp314-win_amd64.whl", hash = "sha256:e1a4120ae5705f673727d3253de3ed0e016f7cd78dc463db1b31e2463e1f3cf6"}, + {file = "wrapt-1.17.3-cp314-cp314-win_arm64.whl", hash = "sha256:507553480670cab08a800b9463bdb881b2edeed77dc677b0a5915e6106e91a58"}, + {file = "wrapt-1.17.3-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:ed7c635ae45cfbc1a7371f708727bf74690daedc49b4dba310590ca0bd28aa8a"}, + {file = "wrapt-1.17.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:249f88ed15503f6492a71f01442abddd73856a0032ae860de6d75ca62eed8067"}, + {file = "wrapt-1.17.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5a03a38adec8066d5a37bea22f2ba6bbf39fcdefbe2d91419ab864c3fb515454"}, + {file = "wrapt-1.17.3-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:5d4478d72eb61c36e5b446e375bbc49ed002430d17cdec3cecb36993398e1a9e"}, + {file = "wrapt-1.17.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:223db574bb38637e8230eb14b185565023ab624474df94d2af18f1cdb625216f"}, + {file = "wrapt-1.17.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e405adefb53a435f01efa7ccdec012c016b5a1d3f35459990afc39b6be4d5056"}, + {file = "wrapt-1.17.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:88547535b787a6c9ce4086917b6e1d291aa8ed914fdd3a838b3539dc95c12804"}, + {file = "wrapt-1.17.3-cp314-cp314t-win32.whl", hash = "sha256:41b1d2bc74c2cac6f9074df52b2efbef2b30bdfe5f40cb78f8ca22963bc62977"}, + {file = "wrapt-1.17.3-cp314-cp314t-win_amd64.whl", hash = "sha256:73d496de46cd2cdbdbcce4ae4bcdb4afb6a11234a1df9c085249d55166b95116"}, + {file = "wrapt-1.17.3-cp314-cp314t-win_arm64.whl", hash = "sha256:f38e60678850c42461d4202739f9bf1e3a737c7ad283638251e79cc49effb6b6"}, + {file = "wrapt-1.17.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:70d86fa5197b8947a2fa70260b48e400bf2ccacdcab97bb7de47e3d1e6312225"}, + {file = "wrapt-1.17.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:df7d30371a2accfe4013e90445f6388c570f103d61019b6b7c57e0265250072a"}, + {file = "wrapt-1.17.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:caea3e9c79d5f0d2c6d9ab96111601797ea5da8e6d0723f77eabb0d4068d2b2f"}, + {file = "wrapt-1.17.3-cp38-cp38-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:758895b01d546812d1f42204bd443b8c433c44d090248bf22689df673ccafe00"}, + {file = "wrapt-1.17.3-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:02b551d101f31694fc785e58e0720ef7d9a10c4e62c1c9358ce6f63f23e30a56"}, + {file = "wrapt-1.17.3-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:656873859b3b50eeebe6db8b1455e99d90c26ab058db8e427046dbc35c3140a5"}, + {file = "wrapt-1.17.3-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:a9a2203361a6e6404f80b99234fe7fb37d1fc73487b5a78dc1aa5b97201e0f22"}, + {file = "wrapt-1.17.3-cp38-cp38-win32.whl", hash = "sha256:55cbbc356c2842f39bcc553cf695932e8b30e30e797f961860afb308e6b1bb7c"}, + {file = "wrapt-1.17.3-cp38-cp38-win_amd64.whl", hash = "sha256:ad85e269fe54d506b240d2d7b9f5f2057c2aa9a2ea5b32c66f8902f768117ed2"}, + {file = "wrapt-1.17.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:30ce38e66630599e1193798285706903110d4f057aab3168a34b7fdc85569afc"}, + {file = "wrapt-1.17.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:65d1d00fbfb3ea5f20add88bbc0f815150dbbde3b026e6c24759466c8b5a9ef9"}, + {file = "wrapt-1.17.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a7c06742645f914f26c7f1fa47b8bc4c91d222f76ee20116c43d5ef0912bba2d"}, + {file = "wrapt-1.17.3-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7e18f01b0c3e4a07fe6dfdb00e29049ba17eadbc5e7609a2a3a4af83ab7d710a"}, + {file = "wrapt-1.17.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f5f51a6466667a5a356e6381d362d259125b57f059103dd9fdc8c0cf1d14139"}, + {file = "wrapt-1.17.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:59923aa12d0157f6b82d686c3fd8e1166fa8cdfb3e17b42ce3b6147ff81528df"}, + {file = "wrapt-1.17.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:46acc57b331e0b3bcb3e1ca3b421d65637915cfcd65eb783cb2f78a511193f9b"}, + {file = "wrapt-1.17.3-cp39-cp39-win32.whl", hash = "sha256:3e62d15d3cfa26e3d0788094de7b64efa75f3a53875cdbccdf78547aed547a81"}, + {file = "wrapt-1.17.3-cp39-cp39-win_amd64.whl", hash = "sha256:1f23fa283f51c890eda8e34e4937079114c74b4c81d2b2f1f1d94948f5cc3d7f"}, + {file = "wrapt-1.17.3-cp39-cp39-win_arm64.whl", hash = "sha256:24c2ed34dc222ed754247a2702b1e1e89fdbaa4016f324b4b8f1a802d4ffe87f"}, + {file = "wrapt-1.17.3-py3-none-any.whl", hash = "sha256:7171ae35d2c33d326ac19dd8facb1e82e5fd04ef8c6c0e394d7af55a55051c22"}, + {file = "wrapt-1.17.3.tar.gz", hash = "sha256:f66eb08feaa410fe4eebd17f2a2c8e2e46d3476e9f8c783daa8e09e0faa666d0"}, ] [[package]] @@ -2678,4 +2681,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = "^3.10" -content-hash = "0d284de63c0d6fdd50280106c268dfcb3e500093dd47c3476a6821b3424fdcf9" +content-hash = "7cd622932c4e5ac2acbe6ee2013eda2802dd4d3cab61b28faed683ca0658fd7b" diff --git a/pyproject.toml b/pyproject.toml index 66113a596b..a6f861063e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,9 +8,9 @@ requires-poetry = ">=2.0.0" [tool.poetry.dependencies] python = "^3.10" ops = "^2.23.1" -boto3 = "^1.40.7" +boto3 = "^1.40.12" pgconnstr = "^1.0.1" -requests = "^2.32.4" +requests = "^2.32.5" tenacity = "^9.1.2" psycopg2 = "^2.9.10" pydantic = "^1.10.22" @@ -40,7 +40,7 @@ opentelemetry-exporter-otlp-proto-http = "1.21.0" optional = true [tool.poetry.group.format.dependencies] -ruff = "^0.12.8" +ruff = "^0.12.9" [tool.poetry.group.lint] optional = true @@ -52,11 +52,11 @@ codespell = "^2.4.1" optional = true [tool.poetry.group.unit.dependencies] -coverage = {extras = ["toml"], version = "^7.10.3"} +coverage = {extras = ["toml"], version = "^7.10.4"} pytest = "^8.4.1" pytest-asyncio = "*" parameterized = "^0.9.0" -jsonschema = "^4.25.0" +jsonschema = "^4.25.1" [tool.poetry.group.integration] optional = true From 796fe0951fa94782fd0a10e8857f4bb603a507c4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 21 Aug 2025 02:39:39 +0300 Subject: [PATCH 082/112] Update canonical/data-platform-workflows action to v32.2.3 (#1102) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/approve_renovate_pr.yaml | 2 +- .github/workflows/check_pr.yaml | 2 +- .github/workflows/ci.yaml | 4 ++-- .github/workflows/promote.yaml | 2 +- .github/workflows/release.yaml | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/approve_renovate_pr.yaml b/.github/workflows/approve_renovate_pr.yaml index 713a352098..157d2bba6a 100644 --- a/.github/workflows/approve_renovate_pr.yaml +++ b/.github/workflows/approve_renovate_pr.yaml @@ -10,6 +10,6 @@ on: jobs: approve-pr: name: Approve Renovate pull request - uses: canonical/data-platform-workflows/.github/workflows/approve_renovate_pr.yaml@v32.2.2 + uses: canonical/data-platform-workflows/.github/workflows/approve_renovate_pr.yaml@v32.2.3 permissions: pull-requests: write # Needed to approve PR diff --git a/.github/workflows/check_pr.yaml b/.github/workflows/check_pr.yaml index e81b2f5bf9..280c7c9bc0 100644 --- a/.github/workflows/check_pr.yaml +++ b/.github/workflows/check_pr.yaml @@ -16,4 +16,4 @@ on: jobs: check-pr: name: Check pull request - uses: canonical/data-platform-workflows/.github/workflows/check_charm_pr.yaml@v32.2.2 + uses: canonical/data-platform-workflows/.github/workflows/check_charm_pr.yaml@v32.2.3 diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index f2341067f6..6933a29450 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -27,7 +27,7 @@ on: jobs: lint: name: Lint - uses: canonical/data-platform-workflows/.github/workflows/lint.yaml@v32.2.2 + uses: canonical/data-platform-workflows/.github/workflows/lint.yaml@v32.2.3 unit-test: name: Unit test charm @@ -49,7 +49,7 @@ jobs: build: name: Build charm - uses: canonical/data-platform-workflows/.github/workflows/build_charm.yaml@v32.2.2 + uses: canonical/data-platform-workflows/.github/workflows/build_charm.yaml@v32.2.3 integration-test: name: Integration test charm diff --git a/.github/workflows/promote.yaml b/.github/workflows/promote.yaml index ee95a53057..b268d79844 100644 --- a/.github/workflows/promote.yaml +++ b/.github/workflows/promote.yaml @@ -25,7 +25,7 @@ on: jobs: promote: name: Promote charm - uses: canonical/data-platform-workflows/.github/workflows/_promote_charm.yaml@v32.2.2 + uses: canonical/data-platform-workflows/.github/workflows/_promote_charm.yaml@v32.2.3 with: track: '14' from-risk: ${{ inputs.from-risk }} diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index c0f368a327..5d40966486 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -27,7 +27,7 @@ jobs: name: Release charm needs: - ci-tests - uses: canonical/data-platform-workflows/.github/workflows/release_charm_edge.yaml@v32.2.2 + uses: canonical/data-platform-workflows/.github/workflows/release_charm_edge.yaml@v32.2.3 with: track: 14 artifact-prefix: ${{ needs.ci-tests.outputs.artifact-prefix }} From 693dd4347c8b563923167a3b0031160b15ebcc60 Mon Sep 17 00:00:00 2001 From: Andreia Date: Fri, 22 Aug 2025 12:01:47 +0200 Subject: [PATCH 083/112] Update Charmhub home page (14) (#1110) * Update metadata.yaml * Update VM terminology --- metadata.yaml | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/metadata.yaml b/metadata.yaml index 61d7ae7533..dcacc0b171 100644 --- a/metadata.yaml +++ b/metadata.yaml @@ -3,17 +3,23 @@ name: postgresql display-name: Charmed PostgreSQL VM -summary: Charmed PostgreSQL VM operator +summary: Charmed PostgreSQL 14 for VMs description: | - Charm to operate the PostgreSQL database on machines. -docs: https://discourse.charmhub.io/t/charmed-postgresql-documentation/9710 + PostgreSQL is an open-source relational database management system + built to handle a wide range of workloads. This charmed operator deploys + and operates PostgreSQL on virtual machines and bare metal. + + For deployment on Kubernetes, see [Charmed PostgreSQL K8s](https://charmhub.io/postgresql-k8s). + + To learn more about how to deploy and manage this charm, see the + [official documentation](https://canonical-charmed-postgresql.readthedocs-hosted.com/14/). +docs: https://canonical-charmed-postgresql.readthedocs-hosted.com/14/ source: https://github.com/canonical/postgresql-operator issues: https://github.com/canonical/postgresql-operator/issues website: - https://ubuntu.com/data/postgresql - https://charmhub.io/postgresql - https://github.com/canonical/postgresql-operator - - https://chat.charmhub.io/charmhub/channels/data-platform maintainers: - Canonical Data Platform From 39b41e773e5aab85f86264349743ceca161ef801 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 29 Aug 2025 19:00:48 +0300 Subject: [PATCH 084/112] Lock file maintenance Python dependencies (#1121) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- poetry.lock | 246 ++++++++++++++++++++++++------------------------- pyproject.toml | 6 +- 2 files changed, 126 insertions(+), 126 deletions(-) diff --git a/poetry.lock b/poetry.lock index adbdf4e0df..0109e2e6e8 100644 --- a/poetry.lock +++ b/poetry.lock @@ -233,18 +233,18 @@ typecheck = ["mypy"] [[package]] name = "boto3" -version = "1.40.12" +version = "1.40.17" description = "The AWS SDK for Python" optional = false python-versions = ">=3.9" groups = ["main", "integration"] files = [ - {file = "boto3-1.40.12-py3-none-any.whl", hash = "sha256:3c3d6731390b5b11f5e489d5d9daa57f0c3e171efb63ac8f47203df9c71812b3"}, - {file = "boto3-1.40.12.tar.gz", hash = "sha256:c6b32aee193fbd2eb84696d2b5b2410dcda9fb4a385e1926cff908377d222247"}, + {file = "boto3-1.40.17-py3-none-any.whl", hash = "sha256:2cacecd689cb51d81fbf54f84b64d0e6e922fbc18ee513c568b9f61caf4221e0"}, + {file = "boto3-1.40.17.tar.gz", hash = "sha256:e115dc87d5975d32dfa0ebaf19c39e360665317a350004fa94b03200fe853f2e"}, ] [package.dependencies] -botocore = ">=1.40.12,<1.41.0" +botocore = ">=1.40.17,<1.41.0" jmespath = ">=0.7.1,<2.0.0" s3transfer = ">=0.13.0,<0.14.0" @@ -253,14 +253,14 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.40.12" +version = "1.40.17" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">=3.9" groups = ["main", "integration"] files = [ - {file = "botocore-1.40.12-py3-none-any.whl", hash = "sha256:84e96004a8b426c5508f6b5600312d6271364269466a3a957dc377ad8effc438"}, - {file = "botocore-1.40.12.tar.gz", hash = "sha256:c6560578e799b47b762b7e555bd9c5dd5c29c5d23bd778a8a72e98c979b3c727"}, + {file = "botocore-1.40.17-py3-none-any.whl", hash = "sha256:603951935c1a741ae70236bf15725c5293074f28503e7029ad0e24ece476a342"}, + {file = "botocore-1.40.17.tar.gz", hash = "sha256:769cd04a6a612f2d48b5f456c676fd81733fab682870952f7e2887260ea6a2bc"}, ] [package.dependencies] @@ -517,100 +517,100 @@ typing-extensions = "*" [[package]] name = "coverage" -version = "7.10.4" +version = "7.10.5" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.9" groups = ["unit"] files = [ - {file = "coverage-7.10.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d92d6edb0ccafd20c6fbf9891ca720b39c2a6a4b4a6f9cf323ca2c986f33e475"}, - {file = "coverage-7.10.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7202da14dc0236884fcc45665ffb2d79d4991a53fbdf152ab22f69f70923cc22"}, - {file = "coverage-7.10.4-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:ada418633ae24ec8d0fcad5efe6fc7aa3c62497c6ed86589e57844ad04365674"}, - {file = "coverage-7.10.4-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b828e33eca6c3322adda3b5884456f98c435182a44917ded05005adfa1415500"}, - {file = "coverage-7.10.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:802793ba397afcfdbe9f91f89d65ae88b958d95edc8caf948e1f47d8b6b2b606"}, - {file = "coverage-7.10.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d0b23512338c54101d3bf7a1ab107d9d75abda1d5f69bc0887fd079253e4c27e"}, - {file = "coverage-7.10.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:f36b7dcf72d06a8c5e2dd3aca02be2b1b5db5f86404627dff834396efce958f2"}, - {file = "coverage-7.10.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:fce316c367a1dc2c411821365592eeb335ff1781956d87a0410eae248188ba51"}, - {file = "coverage-7.10.4-cp310-cp310-win32.whl", hash = "sha256:8c5dab29fc8070b3766b5fc85f8d89b19634584429a2da6d42da5edfadaf32ae"}, - {file = "coverage-7.10.4-cp310-cp310-win_amd64.whl", hash = "sha256:4b0d114616f0fccb529a1817457d5fb52a10e106f86c5fb3b0bd0d45d0d69b93"}, - {file = "coverage-7.10.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:05d5f98ec893d4a2abc8bc5f046f2f4367404e7e5d5d18b83de8fde1093ebc4f"}, - {file = "coverage-7.10.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9267efd28f8994b750d171e58e481e3bbd69e44baed540e4c789f8e368b24b88"}, - {file = "coverage-7.10.4-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:4456a039fdc1a89ea60823d0330f1ac6f97b0dbe9e2b6fb4873e889584b085fb"}, - {file = "coverage-7.10.4-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c2bfbd2a9f7e68a21c5bd191be94bfdb2691ac40d325bac9ef3ae45ff5c753d9"}, - {file = "coverage-7.10.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ab7765f10ae1df7e7fe37de9e64b5a269b812ee22e2da3f84f97b1c7732a0d8"}, - {file = "coverage-7.10.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0a09b13695166236e171ec1627ff8434b9a9bae47528d0ba9d944c912d33b3d2"}, - {file = "coverage-7.10.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5c9e75dfdc0167d5675e9804f04a56b2cf47fb83a524654297000b578b8adcb7"}, - {file = "coverage-7.10.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c751261bfe6481caba15ec005a194cb60aad06f29235a74c24f18546d8377df0"}, - {file = "coverage-7.10.4-cp311-cp311-win32.whl", hash = "sha256:051c7c9e765f003c2ff6e8c81ccea28a70fb5b0142671e4e3ede7cebd45c80af"}, - {file = "coverage-7.10.4-cp311-cp311-win_amd64.whl", hash = "sha256:1a647b152f10be08fb771ae4a1421dbff66141e3d8ab27d543b5eb9ea5af8e52"}, - {file = "coverage-7.10.4-cp311-cp311-win_arm64.whl", hash = "sha256:b09b9e4e1de0d406ca9f19a371c2beefe3193b542f64a6dd40cfcf435b7d6aa0"}, - {file = "coverage-7.10.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a1f0264abcabd4853d4cb9b3d164adbf1565da7dab1da1669e93f3ea60162d79"}, - {file = "coverage-7.10.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:536cbe6b118a4df231b11af3e0f974a72a095182ff8ec5f4868c931e8043ef3e"}, - {file = "coverage-7.10.4-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:9a4c0d84134797b7bf3f080599d0cd501471f6c98b715405166860d79cfaa97e"}, - {file = "coverage-7.10.4-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7c155fc0f9cee8c9803ea0ad153ab6a3b956baa5d4cd993405dc0b45b2a0b9e0"}, - {file = "coverage-7.10.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0a5f2ab6e451d4b07855d8bcf063adf11e199bff421a4ba57f5bb95b7444ca62"}, - {file = "coverage-7.10.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:685b67d99b945b0c221be0780c336b303a7753b3e0ec0d618c795aada25d5e7a"}, - {file = "coverage-7.10.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0c079027e50c2ae44da51c2e294596cbc9dbb58f7ca45b30651c7e411060fc23"}, - {file = "coverage-7.10.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3749aa72b93ce516f77cf5034d8e3c0dfd45c6e8a163a602ede2dc5f9a0bb927"}, - {file = "coverage-7.10.4-cp312-cp312-win32.whl", hash = "sha256:fecb97b3a52fa9bcd5a7375e72fae209088faf671d39fae67261f37772d5559a"}, - {file = "coverage-7.10.4-cp312-cp312-win_amd64.whl", hash = "sha256:26de58f355626628a21fe6a70e1e1fad95702dafebfb0685280962ae1449f17b"}, - {file = "coverage-7.10.4-cp312-cp312-win_arm64.whl", hash = "sha256:67e8885408f8325198862bc487038a4980c9277d753cb8812510927f2176437a"}, - {file = "coverage-7.10.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2b8e1d2015d5dfdbf964ecef12944c0c8c55b885bb5c0467ae8ef55e0e151233"}, - {file = "coverage-7.10.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:25735c299439018d66eb2dccf54f625aceb78645687a05f9f848f6e6c751e169"}, - {file = "coverage-7.10.4-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:715c06cb5eceac4d9b7cdf783ce04aa495f6aff657543fea75c30215b28ddb74"}, - {file = "coverage-7.10.4-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:e017ac69fac9aacd7df6dc464c05833e834dc5b00c914d7af9a5249fcccf07ef"}, - {file = "coverage-7.10.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bad180cc40b3fccb0f0e8c702d781492654ac2580d468e3ffc8065e38c6c2408"}, - {file = "coverage-7.10.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:becbdcd14f685fada010a5f792bf0895675ecf7481304fe159f0cd3f289550bd"}, - {file = "coverage-7.10.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:0b485ca21e16a76f68060911f97ebbe3e0d891da1dbbce6af7ca1ab3f98b9097"}, - {file = "coverage-7.10.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6c1d098ccfe8e1e0a1ed9a0249138899948afd2978cbf48eb1cc3fcd38469690"}, - {file = "coverage-7.10.4-cp313-cp313-win32.whl", hash = "sha256:8630f8af2ca84b5c367c3df907b1706621abe06d6929f5045fd628968d421e6e"}, - {file = "coverage-7.10.4-cp313-cp313-win_amd64.whl", hash = "sha256:f68835d31c421736be367d32f179e14ca932978293fe1b4c7a6a49b555dff5b2"}, - {file = "coverage-7.10.4-cp313-cp313-win_arm64.whl", hash = "sha256:6eaa61ff6724ca7ebc5326d1fae062d85e19b38dd922d50903702e6078370ae7"}, - {file = "coverage-7.10.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:702978108876bfb3d997604930b05fe769462cc3000150b0e607b7b444f2fd84"}, - {file = "coverage-7.10.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e8f978e8c5521d9c8f2086ac60d931d583fab0a16f382f6eb89453fe998e2484"}, - {file = "coverage-7.10.4-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:df0ac2ccfd19351411c45e43ab60932b74472e4648b0a9edf6a3b58846e246a9"}, - {file = "coverage-7.10.4-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:73a0d1aaaa3796179f336448e1576a3de6fc95ff4f07c2d7251d4caf5d18cf8d"}, - {file = "coverage-7.10.4-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:873da6d0ed6b3ffc0bc01f2c7e3ad7e2023751c0d8d86c26fe7322c314b031dc"}, - {file = "coverage-7.10.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c6446c75b0e7dda5daa876a1c87b480b2b52affb972fedd6c22edf1aaf2e00ec"}, - {file = "coverage-7.10.4-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:6e73933e296634e520390c44758d553d3b573b321608118363e52113790633b9"}, - {file = "coverage-7.10.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:52073d4b08d2cb571234c8a71eb32af3c6923149cf644a51d5957ac128cf6aa4"}, - {file = "coverage-7.10.4-cp313-cp313t-win32.whl", hash = "sha256:e24afb178f21f9ceb1aefbc73eb524769aa9b504a42b26857243f881af56880c"}, - {file = "coverage-7.10.4-cp313-cp313t-win_amd64.whl", hash = "sha256:be04507ff1ad206f4be3d156a674e3fb84bbb751ea1b23b142979ac9eebaa15f"}, - {file = "coverage-7.10.4-cp313-cp313t-win_arm64.whl", hash = "sha256:f3e3ff3f69d02b5dad67a6eac68cc9c71ae343b6328aae96e914f9f2f23a22e2"}, - {file = "coverage-7.10.4-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:a59fe0af7dd7211ba595cf7e2867458381f7e5d7b4cffe46274e0b2f5b9f4eb4"}, - {file = "coverage-7.10.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:3a6c35c5b70f569ee38dc3350cd14fdd0347a8b389a18bb37538cc43e6f730e6"}, - {file = "coverage-7.10.4-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:acb7baf49f513554c4af6ef8e2bd6e8ac74e6ea0c7386df8b3eb586d82ccccc4"}, - {file = "coverage-7.10.4-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:a89afecec1ed12ac13ed203238b560cbfad3522bae37d91c102e690b8b1dc46c"}, - {file = "coverage-7.10.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:480442727f464407d8ade6e677b7f21f3b96a9838ab541b9a28ce9e44123c14e"}, - {file = "coverage-7.10.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a89bf193707f4a17f1ed461504031074d87f035153239f16ce86dfb8f8c7ac76"}, - {file = "coverage-7.10.4-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:3ddd912c2fc440f0fb3229e764feec85669d5d80a988ff1b336a27d73f63c818"}, - {file = "coverage-7.10.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:8a538944ee3a42265e61c7298aeba9ea43f31c01271cf028f437a7b4075592cf"}, - {file = "coverage-7.10.4-cp314-cp314-win32.whl", hash = "sha256:fd2e6002be1c62476eb862b8514b1ba7e7684c50165f2a8d389e77da6c9a2ebd"}, - {file = "coverage-7.10.4-cp314-cp314-win_amd64.whl", hash = "sha256:ec113277f2b5cf188d95fb66a65c7431f2b9192ee7e6ec9b72b30bbfb53c244a"}, - {file = "coverage-7.10.4-cp314-cp314-win_arm64.whl", hash = "sha256:9744954bfd387796c6a091b50d55ca7cac3d08767795b5eec69ad0f7dbf12d38"}, - {file = "coverage-7.10.4-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:5af4829904dda6aabb54a23879f0f4412094ba9ef153aaa464e3c1b1c9bc98e6"}, - {file = "coverage-7.10.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7bba5ed85e034831fac761ae506c0644d24fd5594727e174b5a73aff343a7508"}, - {file = "coverage-7.10.4-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d57d555b0719834b55ad35045de6cc80fc2b28e05adb6b03c98479f9553b387f"}, - {file = "coverage-7.10.4-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:ba62c51a72048bb1ea72db265e6bd8beaabf9809cd2125bbb5306c6ce105f214"}, - {file = "coverage-7.10.4-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0acf0c62a6095f07e9db4ec365cc58c0ef5babb757e54745a1aa2ea2a2564af1"}, - {file = "coverage-7.10.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e1033bf0f763f5cf49ffe6594314b11027dcc1073ac590b415ea93463466deec"}, - {file = "coverage-7.10.4-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:92c29eff894832b6a40da1789b1f252305af921750b03ee4535919db9179453d"}, - {file = "coverage-7.10.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:822c4c830989c2093527e92acd97be4638a44eb042b1bdc0e7a278d84a070bd3"}, - {file = "coverage-7.10.4-cp314-cp314t-win32.whl", hash = "sha256:e694d855dac2e7cf194ba33653e4ba7aad7267a802a7b3fc4347d0517d5d65cd"}, - {file = "coverage-7.10.4-cp314-cp314t-win_amd64.whl", hash = "sha256:efcc54b38ef7d5bfa98050f220b415bc5bb3d432bd6350a861cf6da0ede2cdcd"}, - {file = "coverage-7.10.4-cp314-cp314t-win_arm64.whl", hash = "sha256:6f3a3496c0fa26bfac4ebc458747b778cff201c8ae94fa05e1391bab0dbc473c"}, - {file = "coverage-7.10.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:48fd4d52600c2a9d5622e52dfae674a7845c5e1dceaf68b88c99feb511fbcfd6"}, - {file = "coverage-7.10.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:56217b470d09d69e6b7dcae38200f95e389a77db801cb129101697a4553b18b6"}, - {file = "coverage-7.10.4-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:44ac3f21a6e28c5ff7f7a47bca5f87885f6a1e623e637899125ba47acd87334d"}, - {file = "coverage-7.10.4-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:3387739d72c84d17b4d2f7348749cac2e6700e7152026912b60998ee9a40066b"}, - {file = "coverage-7.10.4-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3f111ff20d9a6348e0125be892608e33408dd268f73b020940dfa8511ad05503"}, - {file = "coverage-7.10.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:01a852f0a9859734b018a3f483cc962d0b381d48d350b1a0c47d618c73a0c398"}, - {file = "coverage-7.10.4-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:225111dd06759ba4e37cee4c0b4f3df2b15c879e9e3c37bf986389300b9917c3"}, - {file = "coverage-7.10.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2178d4183bd1ba608f0bb12e71e55838ba1b7dbb730264f8b08de9f8ef0c27d0"}, - {file = "coverage-7.10.4-cp39-cp39-win32.whl", hash = "sha256:93d175fe81913aee7a6ea430abbdf2a79f1d9fd451610e12e334e4fe3264f563"}, - {file = "coverage-7.10.4-cp39-cp39-win_amd64.whl", hash = "sha256:2221a823404bb941c7721cf0ef55ac6ee5c25d905beb60c0bba5e5e85415d353"}, - {file = "coverage-7.10.4-py3-none-any.whl", hash = "sha256:065d75447228d05121e5c938ca8f0e91eed60a1eb2d1258d42d5084fecfc3302"}, - {file = "coverage-7.10.4.tar.gz", hash = "sha256:25f5130af6c8e7297fd14634955ba9e1697f47143f289e2a23284177c0061d27"}, + {file = "coverage-7.10.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c6a5c3414bfc7451b879141ce772c546985163cf553f08e0f135f0699a911801"}, + {file = "coverage-7.10.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:bc8e4d99ce82f1710cc3c125adc30fd1487d3cf6c2cd4994d78d68a47b16989a"}, + {file = "coverage-7.10.5-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:02252dc1216e512a9311f596b3169fad54abcb13827a8d76d5630c798a50a754"}, + {file = "coverage-7.10.5-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:73269df37883e02d460bee0cc16be90509faea1e3bd105d77360b512d5bb9c33"}, + {file = "coverage-7.10.5-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1f8a81b0614642f91c9effd53eec284f965577591f51f547a1cbeb32035b4c2f"}, + {file = "coverage-7.10.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6a29f8e0adb7f8c2b95fa2d4566a1d6e6722e0a637634c6563cb1ab844427dd9"}, + {file = "coverage-7.10.5-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fcf6ab569436b4a647d4e91accba12509ad9f2554bc93d3aee23cc596e7f99c3"}, + {file = "coverage-7.10.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:90dc3d6fb222b194a5de60af8d190bedeeddcbc7add317e4a3cd333ee6b7c879"}, + {file = "coverage-7.10.5-cp310-cp310-win32.whl", hash = "sha256:414a568cd545f9dc75f0686a0049393de8098414b58ea071e03395505b73d7a8"}, + {file = "coverage-7.10.5-cp310-cp310-win_amd64.whl", hash = "sha256:e551f9d03347196271935fd3c0c165f0e8c049220280c1120de0084d65e9c7ff"}, + {file = "coverage-7.10.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c177e6ffe2ebc7c410785307758ee21258aa8e8092b44d09a2da767834f075f2"}, + {file = "coverage-7.10.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:14d6071c51ad0f703d6440827eaa46386169b5fdced42631d5a5ac419616046f"}, + {file = "coverage-7.10.5-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:61f78c7c3bc272a410c5ae3fde7792b4ffb4acc03d35a7df73ca8978826bb7ab"}, + {file = "coverage-7.10.5-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f39071caa126f69d63f99b324fb08c7b1da2ec28cbb1fe7b5b1799926492f65c"}, + {file = "coverage-7.10.5-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:343a023193f04d46edc46b2616cdbee68c94dd10208ecd3adc56fcc54ef2baa1"}, + {file = "coverage-7.10.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:585ffe93ae5894d1ebdee69fc0b0d4b7c75d8007983692fb300ac98eed146f78"}, + {file = "coverage-7.10.5-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:b0ef4e66f006ed181df29b59921bd8fc7ed7cd6a9289295cd8b2824b49b570df"}, + {file = "coverage-7.10.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:eb7b0bbf7cc1d0453b843eca7b5fa017874735bef9bfdfa4121373d2cc885ed6"}, + {file = "coverage-7.10.5-cp311-cp311-win32.whl", hash = "sha256:1d043a8a06987cc0c98516e57c4d3fc2c1591364831e9deb59c9e1b4937e8caf"}, + {file = "coverage-7.10.5-cp311-cp311-win_amd64.whl", hash = "sha256:fefafcca09c3ac56372ef64a40f5fe17c5592fab906e0fdffd09543f3012ba50"}, + {file = "coverage-7.10.5-cp311-cp311-win_arm64.whl", hash = "sha256:7e78b767da8b5fc5b2faa69bb001edafcd6f3995b42a331c53ef9572c55ceb82"}, + {file = "coverage-7.10.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c2d05c7e73c60a4cecc7d9b60dbfd603b4ebc0adafaef371445b47d0f805c8a9"}, + {file = "coverage-7.10.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:32ddaa3b2c509778ed5373b177eb2bf5662405493baeff52278a0b4f9415188b"}, + {file = "coverage-7.10.5-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:dd382410039fe062097aa0292ab6335a3f1e7af7bba2ef8d27dcda484918f20c"}, + {file = "coverage-7.10.5-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7fa22800f3908df31cea6fb230f20ac49e343515d968cc3a42b30d5c3ebf9b5a"}, + {file = "coverage-7.10.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f366a57ac81f5e12797136552f5b7502fa053c861a009b91b80ed51f2ce651c6"}, + {file = "coverage-7.10.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5f1dc8f1980a272ad4a6c84cba7981792344dad33bf5869361576b7aef42733a"}, + {file = "coverage-7.10.5-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:2285c04ee8676f7938b02b4936d9b9b672064daab3187c20f73a55f3d70e6b4a"}, + {file = "coverage-7.10.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c2492e4dd9daab63f5f56286f8a04c51323d237631eb98505d87e4c4ff19ec34"}, + {file = "coverage-7.10.5-cp312-cp312-win32.whl", hash = "sha256:38a9109c4ee8135d5df5505384fc2f20287a47ccbe0b3f04c53c9a1989c2bbaf"}, + {file = "coverage-7.10.5-cp312-cp312-win_amd64.whl", hash = "sha256:6b87f1ad60b30bc3c43c66afa7db6b22a3109902e28c5094957626a0143a001f"}, + {file = "coverage-7.10.5-cp312-cp312-win_arm64.whl", hash = "sha256:672a6c1da5aea6c629819a0e1461e89d244f78d7b60c424ecf4f1f2556c041d8"}, + {file = "coverage-7.10.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ef3b83594d933020f54cf65ea1f4405d1f4e41a009c46df629dd964fcb6e907c"}, + {file = "coverage-7.10.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2b96bfdf7c0ea9faebce088a3ecb2382819da4fbc05c7b80040dbc428df6af44"}, + {file = "coverage-7.10.5-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:63df1fdaffa42d914d5c4d293e838937638bf75c794cf20bee12978fc8c4e3bc"}, + {file = "coverage-7.10.5-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8002dc6a049aac0e81ecec97abfb08c01ef0c1fbf962d0c98da3950ace89b869"}, + {file = "coverage-7.10.5-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:63d4bb2966d6f5f705a6b0c6784c8969c468dbc4bcf9d9ded8bff1c7e092451f"}, + {file = "coverage-7.10.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1f672efc0731a6846b157389b6e6d5d5e9e59d1d1a23a5c66a99fd58339914d5"}, + {file = "coverage-7.10.5-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:3f39cef43d08049e8afc1fde4a5da8510fc6be843f8dea350ee46e2a26b2f54c"}, + {file = "coverage-7.10.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2968647e3ed5a6c019a419264386b013979ff1fb67dd11f5c9886c43d6a31fc2"}, + {file = "coverage-7.10.5-cp313-cp313-win32.whl", hash = "sha256:0d511dda38595b2b6934c2b730a1fd57a3635c6aa2a04cb74714cdfdd53846f4"}, + {file = "coverage-7.10.5-cp313-cp313-win_amd64.whl", hash = "sha256:9a86281794a393513cf117177fd39c796b3f8e3759bb2764259a2abba5cce54b"}, + {file = "coverage-7.10.5-cp313-cp313-win_arm64.whl", hash = "sha256:cebd8e906eb98bb09c10d1feed16096700b1198d482267f8bf0474e63a7b8d84"}, + {file = "coverage-7.10.5-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0520dff502da5e09d0d20781df74d8189ab334a1e40d5bafe2efaa4158e2d9e7"}, + {file = "coverage-7.10.5-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:d9cd64aca68f503ed3f1f18c7c9174cbb797baba02ca8ab5112f9d1c0328cd4b"}, + {file = "coverage-7.10.5-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:0913dd1613a33b13c4f84aa6e3f4198c1a21ee28ccb4f674985c1f22109f0aae"}, + {file = "coverage-7.10.5-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:1b7181c0feeb06ed8a02da02792f42f829a7b29990fef52eff257fef0885d760"}, + {file = "coverage-7.10.5-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:36d42b7396b605f774d4372dd9c49bed71cbabce4ae1ccd074d155709dd8f235"}, + {file = "coverage-7.10.5-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b4fdc777e05c4940b297bf47bf7eedd56a39a61dc23ba798e4b830d585486ca5"}, + {file = "coverage-7.10.5-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:42144e8e346de44a6f1dbd0a56575dd8ab8dfa7e9007da02ea5b1c30ab33a7db"}, + {file = "coverage-7.10.5-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:66c644cbd7aed8fe266d5917e2c9f65458a51cfe5eeff9c05f15b335f697066e"}, + {file = "coverage-7.10.5-cp313-cp313t-win32.whl", hash = "sha256:2d1b73023854068c44b0c554578a4e1ef1b050ed07cf8b431549e624a29a66ee"}, + {file = "coverage-7.10.5-cp313-cp313t-win_amd64.whl", hash = "sha256:54a1532c8a642d8cc0bd5a9a51f5a9dcc440294fd06e9dda55e743c5ec1a8f14"}, + {file = "coverage-7.10.5-cp313-cp313t-win_arm64.whl", hash = "sha256:74d5b63fe3f5f5d372253a4ef92492c11a4305f3550631beaa432fc9df16fcff"}, + {file = "coverage-7.10.5-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:68c5e0bc5f44f68053369fa0d94459c84548a77660a5f2561c5e5f1e3bed7031"}, + {file = "coverage-7.10.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:cf33134ffae93865e32e1e37df043bef15a5e857d8caebc0099d225c579b0fa3"}, + {file = "coverage-7.10.5-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:ad8fa9d5193bafcf668231294241302b5e683a0518bf1e33a9a0dfb142ec3031"}, + {file = "coverage-7.10.5-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:146fa1531973d38ab4b689bc764592fe6c2f913e7e80a39e7eeafd11f0ef6db2"}, + {file = "coverage-7.10.5-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6013a37b8a4854c478d3219ee8bc2392dea51602dd0803a12d6f6182a0061762"}, + {file = "coverage-7.10.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:eb90fe20db9c3d930fa2ad7a308207ab5b86bf6a76f54ab6a40be4012d88fcae"}, + {file = "coverage-7.10.5-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:384b34482272e960c438703cafe63316dfbea124ac62006a455c8410bf2a2262"}, + {file = "coverage-7.10.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:467dc74bd0a1a7de2bedf8deaf6811f43602cb532bd34d81ffd6038d6d8abe99"}, + {file = "coverage-7.10.5-cp314-cp314-win32.whl", hash = "sha256:556d23d4e6393ca898b2e63a5bca91e9ac2d5fb13299ec286cd69a09a7187fde"}, + {file = "coverage-7.10.5-cp314-cp314-win_amd64.whl", hash = "sha256:f4446a9547681533c8fa3e3c6cf62121eeee616e6a92bd9201c6edd91beffe13"}, + {file = "coverage-7.10.5-cp314-cp314-win_arm64.whl", hash = "sha256:5e78bd9cf65da4c303bf663de0d73bf69f81e878bf72a94e9af67137c69b9fe9"}, + {file = "coverage-7.10.5-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:5661bf987d91ec756a47c7e5df4fbcb949f39e32f9334ccd3f43233bbb65e508"}, + {file = "coverage-7.10.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a46473129244db42a720439a26984f8c6f834762fc4573616c1f37f13994b357"}, + {file = "coverage-7.10.5-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1f64b8d3415d60f24b058b58d859e9512624bdfa57a2d1f8aff93c1ec45c429b"}, + {file = "coverage-7.10.5-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:44d43de99a9d90b20e0163f9770542357f58860a26e24dc1d924643bd6aa7cb4"}, + {file = "coverage-7.10.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a931a87e5ddb6b6404e65443b742cb1c14959622777f2a4efd81fba84f5d91ba"}, + {file = "coverage-7.10.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:f9559b906a100029274448f4c8b8b0a127daa4dade5661dfd821b8c188058842"}, + {file = "coverage-7.10.5-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:b08801e25e3b4526ef9ced1aa29344131a8f5213c60c03c18fe4c6170ffa2874"}, + {file = "coverage-7.10.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ed9749bb8eda35f8b636fb7632f1c62f735a236a5d4edadd8bbcc5ea0542e732"}, + {file = "coverage-7.10.5-cp314-cp314t-win32.whl", hash = "sha256:609b60d123fc2cc63ccee6d17e4676699075db72d14ac3c107cc4976d516f2df"}, + {file = "coverage-7.10.5-cp314-cp314t-win_amd64.whl", hash = "sha256:0666cf3d2c1626b5a3463fd5b05f5e21f99e6aec40a3192eee4d07a15970b07f"}, + {file = "coverage-7.10.5-cp314-cp314t-win_arm64.whl", hash = "sha256:bc85eb2d35e760120540afddd3044a5bf69118a91a296a8b3940dfc4fdcfe1e2"}, + {file = "coverage-7.10.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:62835c1b00c4a4ace24c1a88561a5a59b612fbb83a525d1c70ff5720c97c0610"}, + {file = "coverage-7.10.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5255b3bbcc1d32a4069d6403820ac8e6dbcc1d68cb28a60a1ebf17e47028e898"}, + {file = "coverage-7.10.5-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3876385722e335d6e991c430302c24251ef9c2a9701b2b390f5473199b1b8ebf"}, + {file = "coverage-7.10.5-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8048ce4b149c93447a55d279078c8ae98b08a6951a3c4d2d7e87f4efc7bfe100"}, + {file = "coverage-7.10.5-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4028e7558e268dd8bcf4d9484aad393cafa654c24b4885f6f9474bf53183a82a"}, + {file = "coverage-7.10.5-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:03f47dc870eec0367fcdd603ca6a01517d2504e83dc18dbfafae37faec66129a"}, + {file = "coverage-7.10.5-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:2d488d7d42b6ded7ea0704884f89dcabd2619505457de8fc9a6011c62106f6e5"}, + {file = "coverage-7.10.5-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b3dcf2ead47fa8be14224ee817dfc1df98043af568fe120a22f81c0eb3c34ad2"}, + {file = "coverage-7.10.5-cp39-cp39-win32.whl", hash = "sha256:02650a11324b80057b8c9c29487020073d5e98a498f1857f37e3f9b6ea1b2426"}, + {file = "coverage-7.10.5-cp39-cp39-win_amd64.whl", hash = "sha256:b45264dd450a10f9e03237b41a9a24e85cbb1e278e5a32adb1a303f58f0017f3"}, + {file = "coverage-7.10.5-py3-none-any.whl", hash = "sha256:0be24d35e4db1d23d0db5c0f6a74a962e2ec83c426b5cac09f4234aadef38e4a"}, + {file = "coverage-7.10.5.tar.gz", hash = "sha256:f2e57716a78bc3ae80b2207be0709a3b2b63b9f2dcf9740ee6ac03588a2015b6"}, ] [package.dependencies] @@ -1408,14 +1408,14 @@ gssapi = ["gssapi (>=1.4.1) ; platform_system != \"Windows\"", "pyasn1 (>=0.1.7) [[package]] name = "parso" -version = "0.8.4" +version = "0.8.5" description = "A Python Parser" optional = false python-versions = ">=3.6" groups = ["integration"] files = [ - {file = "parso-0.8.4-py2.py3-none-any.whl", hash = "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18"}, - {file = "parso-0.8.4.tar.gz", hash = "sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d"}, + {file = "parso-0.8.5-py2.py3-none-any.whl", hash = "sha256:646204b5ee239c396d040b90f9e272e9a8017c630092bf59980beb62fd033887"}, + {file = "parso-0.8.5.tar.gz", hash = "sha256:034d7354a9a018bdce352f48b2a8a450f05e9d6ee85db84764e9b6bd96dafe5a"}, ] [package.extras] @@ -2248,31 +2248,31 @@ pyasn1 = ">=0.1.3" [[package]] name = "ruff" -version = "0.12.9" +version = "0.12.10" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" groups = ["format"] files = [ - {file = "ruff-0.12.9-py3-none-linux_armv6l.whl", hash = "sha256:fcebc6c79fcae3f220d05585229463621f5dbf24d79fdc4936d9302e177cfa3e"}, - {file = "ruff-0.12.9-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:aed9d15f8c5755c0e74467731a007fcad41f19bcce41cd75f768bbd687f8535f"}, - {file = "ruff-0.12.9-py3-none-macosx_11_0_arm64.whl", hash = "sha256:5b15ea354c6ff0d7423814ba6d44be2807644d0c05e9ed60caca87e963e93f70"}, - {file = "ruff-0.12.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d596c2d0393c2502eaabfef723bd74ca35348a8dac4267d18a94910087807c53"}, - {file = "ruff-0.12.9-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1b15599931a1a7a03c388b9c5df1bfa62be7ede6eb7ef753b272381f39c3d0ff"}, - {file = "ruff-0.12.9-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3d02faa2977fb6f3f32ddb7828e212b7dd499c59eb896ae6c03ea5c303575756"}, - {file = "ruff-0.12.9-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:17d5b6b0b3a25259b69ebcba87908496e6830e03acfb929ef9fd4c58675fa2ea"}, - {file = "ruff-0.12.9-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:72db7521860e246adbb43f6ef464dd2a532ef2ef1f5dd0d470455b8d9f1773e0"}, - {file = "ruff-0.12.9-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a03242c1522b4e0885af63320ad754d53983c9599157ee33e77d748363c561ce"}, - {file = "ruff-0.12.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fc83e4e9751e6c13b5046d7162f205d0a7bac5840183c5beebf824b08a27340"}, - {file = "ruff-0.12.9-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:881465ed56ba4dd26a691954650de6ad389a2d1fdb130fe51ff18a25639fe4bb"}, - {file = "ruff-0.12.9-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:43f07a3ccfc62cdb4d3a3348bf0588358a66da756aa113e071b8ca8c3b9826af"}, - {file = "ruff-0.12.9-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:07adb221c54b6bba24387911e5734357f042e5669fa5718920ee728aba3cbadc"}, - {file = "ruff-0.12.9-py3-none-musllinux_1_2_i686.whl", hash = "sha256:f5cd34fabfdea3933ab85d72359f118035882a01bff15bd1d2b15261d85d5f66"}, - {file = "ruff-0.12.9-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:f6be1d2ca0686c54564da8e7ee9e25f93bdd6868263805f8c0b8fc6a449db6d7"}, - {file = "ruff-0.12.9-py3-none-win32.whl", hash = "sha256:cc7a37bd2509974379d0115cc5608a1a4a6c4bff1b452ea69db83c8855d53f93"}, - {file = "ruff-0.12.9-py3-none-win_amd64.whl", hash = "sha256:6fb15b1977309741d7d098c8a3cb7a30bc112760a00fb6efb7abc85f00ba5908"}, - {file = "ruff-0.12.9-py3-none-win_arm64.whl", hash = "sha256:63c8c819739d86b96d500cce885956a1a48ab056bbcbc61b747ad494b2485089"}, - {file = "ruff-0.12.9.tar.gz", hash = "sha256:fbd94b2e3c623f659962934e52c2bea6fc6da11f667a427a368adaf3af2c866a"}, + {file = "ruff-0.12.10-py3-none-linux_armv6l.whl", hash = "sha256:8b593cb0fb55cc8692dac7b06deb29afda78c721c7ccfed22db941201b7b8f7b"}, + {file = "ruff-0.12.10-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ebb7333a45d56efc7c110a46a69a1b32365d5c5161e7244aaf3aa20ce62399c1"}, + {file = "ruff-0.12.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d59e58586829f8e4a9920788f6efba97a13d1fa320b047814e8afede381c6839"}, + {file = "ruff-0.12.10-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:822d9677b560f1fdeab69b89d1f444bf5459da4aa04e06e766cf0121771ab844"}, + {file = "ruff-0.12.10-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:37b4a64f4062a50c75019c61c7017ff598cb444984b638511f48539d3a1c98db"}, + {file = "ruff-0.12.10-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2c6f4064c69d2542029b2a61d39920c85240c39837599d7f2e32e80d36401d6e"}, + {file = "ruff-0.12.10-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:059e863ea3a9ade41407ad71c1de2badfbe01539117f38f763ba42a1206f7559"}, + {file = "ruff-0.12.10-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1bef6161e297c68908b7218fa6e0e93e99a286e5ed9653d4be71e687dff101cf"}, + {file = "ruff-0.12.10-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4f1345fbf8fb0531cd722285b5f15af49b2932742fc96b633e883da8d841896b"}, + {file = "ruff-0.12.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f68433c4fbc63efbfa3ba5db31727db229fa4e61000f452c540474b03de52a9"}, + {file = "ruff-0.12.10-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:141ce3d88803c625257b8a6debf4a0473eb6eed9643a6189b68838b43e78165a"}, + {file = "ruff-0.12.10-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:f3fc21178cd44c98142ae7590f42ddcb587b8e09a3b849cbc84edb62ee95de60"}, + {file = "ruff-0.12.10-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:7d1a4e0bdfafcd2e3e235ecf50bf0176f74dd37902f241588ae1f6c827a36c56"}, + {file = "ruff-0.12.10-py3-none-musllinux_1_2_i686.whl", hash = "sha256:e67d96827854f50b9e3e8327b031647e7bcc090dbe7bb11101a81a3a2cbf1cc9"}, + {file = "ruff-0.12.10-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:ae479e1a18b439c59138f066ae79cc0f3ee250712a873d00dbafadaad9481e5b"}, + {file = "ruff-0.12.10-py3-none-win32.whl", hash = "sha256:9de785e95dc2f09846c5e6e1d3a3d32ecd0b283a979898ad427a9be7be22b266"}, + {file = "ruff-0.12.10-py3-none-win_amd64.whl", hash = "sha256:7837eca8787f076f67aba2ca559cefd9c5cbc3a9852fd66186f4201b87c1563e"}, + {file = "ruff-0.12.10-py3-none-win_arm64.whl", hash = "sha256:cc138cc06ed9d4bfa9d667a65af7172b47840e1a98b02ce7011c391e54635ffc"}, + {file = "ruff-0.12.10.tar.gz", hash = "sha256:189ab65149d11ea69a2d775343adf5f49bb2426fc4780f65ee33b423ad2e47f9"}, ] [[package]] @@ -2414,14 +2414,14 @@ test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0, [[package]] name = "typing-extensions" -version = "4.14.1" +version = "4.15.0" description = "Backported and Experimental Type Hints for Python 3.9+" optional = false python-versions = ">=3.9" groups = ["main", "charm-libs", "integration", "unit"] files = [ - {file = "typing_extensions-4.14.1-py3-none-any.whl", hash = "sha256:d1e1e3b58374dc93031d6eda2420a48ea44a36c2b4766a4fdeb3710755731d76"}, - {file = "typing_extensions-4.14.1.tar.gz", hash = "sha256:38b39f4aeeab64884ce9f74c94263ef78f3c22467c8724005483154c26648d36"}, + {file = "typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548"}, + {file = "typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466"}, ] markers = {unit = "python_version < \"3.13\""} @@ -2681,4 +2681,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = "^3.10" -content-hash = "7cd622932c4e5ac2acbe6ee2013eda2802dd4d3cab61b28faed683ca0658fd7b" +content-hash = "d2b7ec1b86f8d6b04f86dc539454ac30b58564c81f44ec78b52c69b6ffac3c00" diff --git a/pyproject.toml b/pyproject.toml index a6f861063e..abd8a941b2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ requires-poetry = ">=2.0.0" [tool.poetry.dependencies] python = "^3.10" ops = "^2.23.1" -boto3 = "^1.40.12" +boto3 = "^1.40.17" pgconnstr = "^1.0.1" requests = "^2.32.5" tenacity = "^9.1.2" @@ -40,7 +40,7 @@ opentelemetry-exporter-otlp-proto-http = "1.21.0" optional = true [tool.poetry.group.format.dependencies] -ruff = "^0.12.9" +ruff = "^0.12.10" [tool.poetry.group.lint] optional = true @@ -52,7 +52,7 @@ codespell = "^2.4.1" optional = true [tool.poetry.group.unit.dependencies] -coverage = {extras = ["toml"], version = "^7.10.4"} +coverage = {extras = ["toml"], version = "^7.10.5"} pytest = "^8.4.1" pytest-asyncio = "*" parameterized = "^0.9.0" From a543105212c536327df4c42d49a9ac80bf2bfdb9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 1 Sep 2025 03:42:28 +0300 Subject: [PATCH 085/112] Update dependency uv to v0.8.13 (#1119) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- charmcraft.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charmcraft.yaml b/charmcraft.yaml index 86c57e66a0..1ab6b176d0 100644 --- a/charmcraft.yaml +++ b/charmcraft.yaml @@ -27,7 +27,7 @@ parts: PIP_BREAK_SYSTEM_PACKAGES=true python3 -m pip install --user --upgrade pip==25.2 # renovate: charmcraft-pip-latest # Use uv to install poetry so that a newer version of Python can be installed if needed by poetry - curl --proto '=https' --tlsv1.2 -LsSf https://github.com/astral-sh/uv/releases/download/0.8.12/uv-installer.sh | sh # renovate: charmcraft-uv-latest + curl --proto '=https' --tlsv1.2 -LsSf https://github.com/astral-sh/uv/releases/download/0.8.13/uv-installer.sh | sh # renovate: charmcraft-uv-latest # poetry 2.0.0 requires Python >=3.9 if ! "$HOME/.local/bin/uv" python find '>=3.9' then From 5f56ec93ccd3155cecc827f290c265d9cb25964b Mon Sep 17 00:00:00 2001 From: Dragomir Penev <6687393+dragomirp@users.noreply.github.com> Date: Mon, 1 Sep 2025 14:58:50 +0300 Subject: [PATCH 086/112] Update charm libs (#1127) --- .../data_platform_libs/v0/data_interfaces.py | 1368 ++++++++++++++++- lib/charms/data_platform_libs/v0/s3.py | 7 +- lib/charms/grafana_agent/v0/cos_agent.py | 22 +- lib/charms/operator_libs_linux/v2/snap.py | 66 +- .../tempo_coordinator_k8s/v0/charm_tracing.py | 66 +- 5 files changed, 1404 insertions(+), 125 deletions(-) diff --git a/lib/charms/data_platform_libs/v0/data_interfaces.py b/lib/charms/data_platform_libs/v0/data_interfaces.py index 109603ad49..a3122b144a 100644 --- a/lib/charms/data_platform_libs/v0/data_interfaces.py +++ b/lib/charms/data_platform_libs/v0/data_interfaces.py @@ -16,7 +16,7 @@ This library contains the Requires and Provides classes for handling the relation between an application and multiple managed application supported by the data-team: -MySQL, Postgresql, MongoDB, Redis, and Kafka. +MySQL, Postgresql, MongoDB, Redis, Kafka, and Karapace. ### Database (MySQL, Postgresql, MongoDB, and Redis) @@ -34,6 +34,7 @@ from charms.data_platform_libs.v0.data_interfaces import ( DatabaseCreatedEvent, DatabaseRequires, + DatabaseEntityCreatedEvent, ) class ApplicationCharm(CharmBase): @@ -45,6 +46,7 @@ def __init__(self, *args): # Charm events defined in the database requires charm library. self.database = DatabaseRequires(self, relation_name="database", database_name="database") self.framework.observe(self.database.on.database_created, self._on_database_created) + self.framework.observe(self.database.on.database_entity_created, self._on_database_entity_created) def _on_database_created(self, event: DatabaseCreatedEvent) -> None: # Handle the created database @@ -61,12 +63,17 @@ def _on_database_created(self, event: DatabaseCreatedEvent) -> None: # Set active status self.unit.status = ActiveStatus("received database credentials") + + def _on_database_entity_created(self, event: DatabaseEntityCreatedEvent) -> None: + # Handle the created entity + ... ``` As shown above, the library provides some custom events to handle specific situations, which are listed below: - database_created: event emitted when the requested database is created. +- database_entity_created: event emitted when the requested entity is created. - endpoints_changed: event emitted when the read/write endpoints of the database have changed. - read_only_endpoints_changed: event emitted when the read-only endpoints of the database have changed. Event is not triggered if read/write endpoints changed too. @@ -141,7 +148,6 @@ def _on_cluster2_database_created(self, event: DatabaseCreatedEvent) -> None: event.endpoints, ) ... - ``` When it's needed to check whether a plugin (extension) is enabled on the PostgreSQL @@ -154,7 +160,6 @@ def _on_cluster2_database_created(self, event: DatabaseCreatedEvent) -> None: charm: charm-binary-python-packages: - psycopg[binary] - ``` ### Provider Charm @@ -187,6 +192,7 @@ def _on_database_requested(self, event: DatabaseRequestedEvent) -> None: self.provided_database.set_credentials(event.relation.id, username, password) # set other variables for the relation event.set_tls("False") ``` + As shown above, the library provides a custom event (database_requested) to handle the situation when an application charm requests a new database to be created. It's preferred to subscribe to this event instead of relation changed event to avoid @@ -207,6 +213,7 @@ def _on_database_requested(self, event: DatabaseRequestedEvent) -> None: BootstrapServerChangedEvent, KafkaRequires, TopicCreatedEvent, + TopicEntityCreatedEvent, ) class ApplicationCharm(CharmBase): @@ -220,6 +227,9 @@ def __init__(self, *args): self.framework.observe( self.kafka.on.topic_created, self._on_kafka_topic_created ) + self.framework.observe( + self.kafka.on.topic_entity_created, self._on_kafka_topic_entity_created + ) def _on_kafka_bootstrap_server_changed(self, event: BootstrapServerChangedEvent): # Event triggered when a bootstrap server was changed for this application @@ -238,6 +248,9 @@ def _on_kafka_topic_created(self, event: TopicCreatedEvent): zookeeper_uris = event.zookeeper_uris ... + def _on_kafka_topic_entity_created(self, event: TopicEntityCreatedEvent): + # Event triggered when an entity was created for this application + ... ``` As shown above, the library provides some custom events to handle specific situations, @@ -268,6 +281,7 @@ def __init__(self, *args): # Charm events defined in the Kafka Provides charm library. self.kafka_provider = KafkaProvides(self, relation_name="kafka_client") self.framework.observe(self.kafka_provider.on.topic_requested, self._on_topic_requested) + self.framework.observe(self.kafka_provider.on.topic_entity_requested, self._on_entity_requested) # Kafka generic helper self.kafka = KafkaHelper() @@ -283,12 +297,114 @@ def _on_topic_requested(self, event: TopicRequestedEvent): self.kafka_provider.set_tls(relation_id, "False") self.kafka_provider.set_zookeeper_uris(relation_id, ...) + def _on_entity_requested(self, event: EntityRequestedEvent): + # Handle the on_topic_entity_requested event. + ... ``` As shown above, the library provides a custom event (topic_requested) to handle the situation when an application charm requests a new topic to be created. It is preferred to subscribe to this event instead of relation changed event to avoid creating a new topic when other information other than a topic name is exchanged in the relation databag. + +### Karapace + +This library is the interface to use and interact with the Karapace charm. This library contains +custom events that add convenience to manage Karapace, and provides methods to consume the +application related data. + +#### Requirer Charm + +```python + +from charms.data_platform_libs.v0.data_interfaces import ( + EndpointsChangedEvent, + KarapaceRequires, + SubjectAllowedEvent, +) + +class ApplicationCharm(CharmBase): + + def __init__(self, *args): + super().__init__(*args) + self.karapace = KarapaceRequires(self, relation_name="karapace_client", subject="test-subject") + self.framework.observe( + self.karapace.on.server_changed, self._on_karapace_server_changed + ) + self.framework.observe( + self.karapace.on.subject_allowed, self._on_karapace_subject_allowed + ) + self.framework.observe( + self.karapace.on.subject_entity_created, self._on_subject_entity_created + ) + + + def _on_karapace_server_changed(self, event: EndpointsChangedEvent): + # Event triggered when a server endpoint was changed for this application + new_server = event.endpoints + ... + + def _on_karapace_subject_allowed(self, event: SubjectAllowedEvent): + # Event triggered when a subject was allowed for this application + username = event.username + password = event.password + tls = event.tls + endpoints = event.endpoints + ... + + def _on_subject_entity_created(self, event: SubjectEntityCreatedEvent): + # Event triggered when a subject entity was created this application + entity_name = event.entity_name + entity_password = event.entity_password + ... +``` + +As shown above, the library provides some custom events to handle specific situations, +which are listed below: + +- subject_allowed: event emitted when the requested subject is allowed. +- server_changed: event emitted when the server endpoints have changed. + +#### Provider Charm + +Following the previous example, this is an example of the provider charm. + +```python +class SampleCharm(CharmBase): + +from charms.data_platform_libs.v0.data_interfaces import ( + KarapaceProvides, + SubjectRequestedEvent, +) + + def __init__(self, *args): + super().__init__(*args) + + # Default charm events. + self.framework.observe(self.on.start, self._on_start) + + # Charm events defined in the Karapace Provides charm library. + self.karapace_provider = KarapaceProvides(self, relation_name="karapace_client") + self.framework.observe(self.karapace_provider.on.subject_requested, self._on_subject_requested) + # Karapace generic helper + self.karapace = KarapaceHelper() + + def _on_subject_requested(self, event: SubjectRequestedEvent): + # Handle the on_subject_requested event. + + subject = event.subject + relation_id = event.relation.id + # set connection info in the databag relation + self.karapace_provider.set_endpoint(relation_id, self.karapace.get_endpoint()) + self.karapace_provider.set_credentials(relation_id, username=username, password=password) + self.karapace_provider.set_tls(relation_id, "False") +``` + +As shown above, the library provides a custom event (subject_requested) to handle +the situation when an application charm requests a new subject to be created. +It is preferred to subscribe to this event instead of relation changed event to avoid +creating a new subject when other information other than a subject name is +exchanged in the relation databag. """ import copy @@ -301,6 +417,7 @@ def _on_topic_requested(self, event: TopicRequestedEvent): from typing import ( Callable, Dict, + Final, ItemsView, KeysView, List, @@ -331,7 +448,7 @@ def _on_topic_requested(self, event: TopicRequestedEvent): # Increment this PATCH version before using `charmcraft publish-lib` or reset # to 0 if you are raising the major API version -LIBPATCH = 49 +LIBPATCH = 54 PYDEPS = ["ops>=2.0.0"] @@ -349,6 +466,8 @@ def _on_topic_requested(self, event: TopicRequestedEvent): changed - keys that still exist but have new values deleted - key that were deleted""" +ENTITY_USER = "USER" +ENTITY_GROUP = "GROUP" PROV_SECRET_PREFIX = "secret-" PROV_SECRET_FIELDS = "provided-secrets" @@ -587,6 +706,7 @@ def __init__(self): self.USER = SecretGroup("user") self.TLS = SecretGroup("tls") self.MTLS = SecretGroup("mtls") + self.ENTITY = SecretGroup("entity") self.EXTRA = SecretGroup("extra") def __setattr__(self, name, value): @@ -953,7 +1073,7 @@ def get(self, key: str, default: Optional[str] = None) -> Optional[str]: class Data(ABC): - """Base relation data mainpulation (abstract) class.""" + """Base relation data manipulation (abstract) class.""" SCOPE = Scope.APP @@ -966,6 +1086,8 @@ class Data(ABC): "tls": SECRET_GROUPS.TLS, "tls-ca": SECRET_GROUPS.TLS, "mtls-cert": SECRET_GROUPS.MTLS, + "entity-name": SECRET_GROUPS.ENTITY, + "entity-password": SECRET_GROUPS.ENTITY, } SECRET_FIELDS = [] @@ -1729,6 +1851,24 @@ def set_credentials(self, relation_id: int, username: str, password: str) -> Non """ self.update_relation_data(relation_id, {"username": username, "password": password}) + def set_entity_credentials( + self, relation_id: int, entity_name: str, entity_password: Optional[str] = None + ) -> None: + """Set entity credentials. + + This function writes in the application data bag, therefore, + only the leader unit can call it. + + Args: + relation_id: the identifier for a particular relation. + entity_name: name of the created entity + entity_password: password of the created entity. + """ + self.update_relation_data( + relation_id, + {"entity-name": entity_name, "entity-password": entity_password}, + ) + def set_tls(self, relation_id: int, tls: str) -> None: """Set whether TLS is enabled. @@ -1766,7 +1906,16 @@ def _load_secrets_from_databag(self, relation: Relation) -> None: class RequirerData(Data): """Requirer-side of the relation.""" - SECRET_FIELDS = ["username", "password", "tls", "tls-ca", "uris", "read-only-uris"] + SECRET_FIELDS = [ + "username", + "password", + "tls", + "tls-ca", + "uris", + "read-only-uris", + "entity-name", + "entity-password", + ] def __init__( self, @@ -1774,10 +1923,39 @@ def __init__( relation_name: str, extra_user_roles: Optional[str] = None, additional_secret_fields: Optional[List[str]] = [], + extra_group_roles: Optional[str] = None, + entity_type: Optional[str] = None, + entity_permissions: Optional[str] = None, + requested_entity_secret: Optional[str] = None, + requested_entity_name: Optional[str] = None, + requested_entity_password: Optional[str] = None, ): """Manager of base client relations.""" super().__init__(model, relation_name) self.extra_user_roles = extra_user_roles + self.extra_group_roles = extra_group_roles + self.entity_type = entity_type + self.entity_permissions = entity_permissions + self.requested_entity_secret = requested_entity_secret + self.requested_entity_name = requested_entity_name + self.requested_entity_password = requested_entity_password + + if ( + self.requested_entity_secret or self.requested_entity_name + ) and not self.secrets_enabled: + raise SecretsUnavailableError("Secrets unavailable on current Juju version") + + if self.requested_entity_secret and ( + self.requested_entity_name or self.requested_entity_password + ): + raise IllegalOperationError("Unable to use provided and automated entity name secret") + + if self.requested_entity_password and not self.requested_entity_name: + raise IllegalOperationError("Unable to set entity password without an entity name") + + self._validate_entity_type() + self._validate_entity_permissions() + self._remote_secret_fields = list(self.SECRET_FIELDS) self._local_secret_fields = [ field @@ -1788,18 +1966,52 @@ def __init__( self._remote_secret_fields += additional_secret_fields self.data_component = self.local_unit - # Internal helper functions + # Internal functions def _is_resource_created_for_relation(self, relation: Relation) -> bool: if not relation.app: return False - data = self.fetch_relation_data([relation.id], ["username", "password"]).get( - relation.id, {} + data = self.fetch_relation_data( + [relation.id], + ["username", "password", "entity-name", "entity-password"], + ).get(relation.id, {}) + + return any( + [ + all(bool(data.get(field)) for field in ("username", "password")), + all(bool(data.get(field)) for field in ("entity-name",)), + ] ) - return bool(data.get("username")) and bool(data.get("password")) + + def _validate_entity_type(self) -> None: + """Validates the consistency of the provided entity-type and its extra roles.""" + if self.entity_type and self.entity_type not in {ENTITY_USER, ENTITY_GROUP}: + raise ValueError("Invalid entity-type. Possible values are USER and GROUP") + + if self.entity_type == ENTITY_USER and self.extra_group_roles: + raise ValueError("Inconsistent entity information. Use extra_user_roles instead") + + if self.entity_type == ENTITY_GROUP and self.extra_user_roles: + raise ValueError("Inconsistent entity information. Use extra_group_roles instead") + + def _validate_entity_permissions(self) -> None: + """Validates whether the provided entity permissions follow the right JSON format.""" + if not self.entity_permissions: + return + + accepted_keys = {"resource_name", "resource_type", "privileges"} + + try: + permissions = json.loads(self.entity_permissions) + for permission in permissions: + if permission.keys() != accepted_keys: + raise ValueError("Invalid entity permissions format. See accepted keys") + except json.decoder.JSONDecodeError: + raise ValueError("Invalid entity permissions format. It must be JSON format") # Public functions + def is_resource_created(self, relation_id: Optional[int] = None) -> bool: """Check if the resource has been created. @@ -1856,6 +2068,26 @@ def __init__(self, charm: CharmBase, relation_data: RequirerData, unique_key: st """Manager of base client relations.""" super().__init__(charm, relation_data, unique_key) + def _main_credentials_shared(self, diff: Diff) -> bool: + """Whether the relation data-bag contains username / password keys.""" + user_secret = self.relation_data._generate_secret_field_name(SECRET_GROUPS.USER) + return any( + [ + user_secret in diff.added, + "username" in diff.added and "password" in diff.added, + ] + ) + + def _entity_credentials_shared(self, diff: Diff) -> bool: + """Whether the relation data-bag contains rolename / password keys.""" + entity_secret = self.relation_data._generate_secret_field_name(SECRET_GROUPS.ENTITY) + return any( + [ + entity_secret in diff.added, + "entity-name" in diff.added, + ] + ) + # Event handlers def _on_relation_created_event(self, event: RelationCreatedEvent) -> None: @@ -1902,6 +2134,21 @@ def __init__(self, charm: CharmBase, relation_data: ProviderData, unique_key: st """Manager of base client relations.""" super().__init__(charm, relation_data, unique_key) + @staticmethod + def _validate_entity_consistency(event: RelationEvent, diff: Diff) -> None: + """Validates that entity information is not changed after relation is established. + + - When entity-type changes, backwards compatibility is broken. + - When extra-user-roles changes, role membership checks become incredibly complex. + - When extra-group-roles changes, role membership checks become incredibly complex. + """ + if not isinstance(event, RelationChangedEvent): + return + + for key in ["entity-type", "extra-user-roles", "extra-group-roles"]: + if key in diff.changed: + raise ValueError(f"Cannot change {key} after relation has already been created") + # Event handlers def _on_relation_changed_event(self, event: RelationChangedEvent) -> None: @@ -1931,7 +2178,6 @@ def __init__( self, model, relation_name: str, - extra_user_roles: Optional[str] = None, additional_secret_fields: Optional[List[str]] = [], additional_secret_group_mapping: Dict[str, str] = {}, secret_field_name: Optional[str] = None, @@ -1939,10 +2185,9 @@ def __init__( ): RequirerData.__init__( self, - model, - relation_name, - extra_user_roles, - additional_secret_fields, + model=model, + relation_name=relation_name, + additional_secret_fields=additional_secret_fields, ) self.secret_field_name = secret_field_name if secret_field_name else self.SECRET_FIELD_NAME self.deleted_label = deleted_label @@ -2006,6 +2251,7 @@ def current_secret_fields(self) -> List[str]: SECRET_GROUPS.get_group("user"), SECRET_GROUPS.get_group("tls"), SECRET_GROUPS.get_group("mtls"), + SECRET_GROUPS.get_group("entity"), ] for group in SECRET_GROUPS.groups(): if group in ignores: @@ -2458,7 +2704,6 @@ def __init__( self, charm, relation_name: str, - extra_user_roles: Optional[str] = None, additional_secret_fields: Optional[List[str]] = [], additional_secret_group_mapping: Dict[str, str] = {}, secret_field_name: Optional[str] = None, @@ -2469,7 +2714,6 @@ def __init__( self, charm.model, relation_name, - extra_user_roles, additional_secret_fields, additional_secret_group_mapping, secret_field_name, @@ -2494,7 +2738,6 @@ def __init__( self, charm, relation_name: str, - extra_user_roles: Optional[str] = None, additional_secret_fields: Optional[List[str]] = [], additional_secret_group_mapping: Dict[str, str] = {}, secret_field_name: Optional[str] = None, @@ -2505,7 +2748,6 @@ def __init__( self, charm.model, relation_name, - extra_user_roles, additional_secret_fields, additional_secret_group_mapping, secret_field_name, @@ -2548,7 +2790,6 @@ def __init__( unit: Unit, charm: CharmBase, relation_name: str, - extra_user_roles: Optional[str] = None, additional_secret_fields: Optional[List[str]] = [], additional_secret_group_mapping: Dict[str, str] = {}, secret_field_name: Optional[str] = None, @@ -2559,7 +2800,6 @@ def __init__( unit, charm.model, relation_name, - extra_user_roles, additional_secret_fields, additional_secret_group_mapping, secret_field_name, @@ -2575,18 +2815,6 @@ def __init__( # Generic events -class ExtraRoleEvent(RelationEvent): - """Base class for data events.""" - - @property - def extra_user_roles(self) -> Optional[str]: - """Returns the extra user roles that were requested.""" - if not self.relation.app: - return None - - return self.relation.data[self.relation.app].get("extra-user-roles") - - class RelationEventWithSecret(RelationEvent): """Base class for Relation Events that need to handle secrets.""" @@ -2618,6 +2846,76 @@ def secrets_enabled(self): return JujuVersion.from_environ().has_secrets +class EntityProvidesEvent(RelationEvent): + """Base class for data events.""" + + @property + def extra_user_roles(self) -> Optional[str]: + """Returns the extra user roles that were requested.""" + if not self.relation.app: + return None + + return self.relation.data[self.relation.app].get("extra-user-roles") + + @property + def extra_group_roles(self) -> Optional[str]: + """Returns the extra group roles that were requested.""" + if not self.relation.app: + return None + + return self.relation.data[self.relation.app].get("extra-group-roles") + + @property + def entity_type(self) -> Optional[str]: + """Returns the entity_type that were requested.""" + if not self.relation.app: + return None + + return self.relation.data[self.relation.app].get("entity-type") + + @property + def entity_permissions(self) -> Optional[str]: + """Returns the entity_permissions that were requested.""" + if not self.relation.app: + return None + + return self.relation.data[self.relation.app].get("entity-permissions") + + +class EntityRequiresEvent(RelationEventWithSecret): + """Base class for authentication fields for events. + + The amount of logic added here is not ideal -- but this was the only way to preserve + the interface when moving to Juju Secrets + """ + + @property + def entity_name(self) -> Optional[str]: + """Returns the name for the created entity.""" + if not self.relation.app: + return None + + if self.secrets_enabled: + secret = self._get_secret("entity") + if secret: + return secret.get("entity-name") + + return self.relation.data[self.relation.app].get("entity-name") + + @property + def entity_password(self) -> Optional[str]: + """Returns the password for the created entity.""" + if not self.relation.app: + return None + + if self.secrets_enabled: + secret = self._get_secret("entity") + if secret: + return secret.get("entity-password") + + return self.relation.data[self.relation.app].get("entity-password") + + class AuthenticationEvent(RelationEventWithSecret): """Base class for authentication fields for events. @@ -2693,9 +2991,17 @@ def database(self) -> Optional[str]: return self.relation.data[self.relation.app].get("database") -class DatabaseRequestedEvent(DatabaseProvidesEvent, ExtraRoleEvent): +class DatabaseRequestedEvent(DatabaseProvidesEvent): """Event emitted when a new database is requested for use on this relation.""" + @property + def extra_user_roles(self) -> Optional[str]: + """Returns the extra user roles that were requested.""" + if not self.relation.app: + return None + + return self.relation.data[self.relation.app].get("extra-user-roles") + @property def external_node_connectivity(self) -> bool: """Returns the requested external_node_connectivity field.""" @@ -2707,6 +3013,29 @@ def external_node_connectivity(self) -> bool: == "true" ) + @property + def requested_entity_secret_content(self) -> Optional[Dict[str, Optional[str]]]: + """Returns the content of the requested entity secret.""" + names = None + if secret_uri := self.relation.data.get(self.relation.app, {}).get( + "requested-entity-secret" + ): + secret = self.framework.model.get_secret(id=secret_uri) + if content := secret.get_content(refresh=True): + if "entity-name" in content: + names = {content["entity-name"]: content.get("password")} + else: + logger.warning("Invalid requested-entity-secret: no entity name") + return names + + +class DatabaseEntityRequestedEvent(DatabaseProvidesEvent, EntityProvidesEvent): + """Event emitted when a new entity is requested for use on this relation.""" + + +class DatabaseEntityPermissionsChangedEvent(DatabaseProvidesEvent, EntityProvidesEvent): + """Event emitted when existing entity permissions are changed on this relation.""" + class DatabaseProvidesEvents(CharmEvents): """Database events. @@ -2715,6 +3044,8 @@ class DatabaseProvidesEvents(CharmEvents): """ database_requested = EventSource(DatabaseRequestedEvent) + database_entity_requested = EventSource(DatabaseEntityRequestedEvent) + database_entity_permissions_changed = EventSource(DatabaseEntityPermissionsChangedEvent) class DatabaseRequiresEvent(RelationEventWithSecret): @@ -2808,6 +3139,10 @@ class DatabaseCreatedEvent(AuthenticationEvent, DatabaseRequiresEvent): """Event emitted when a new database is created for use on this relation.""" +class DatabaseEntityCreatedEvent(EntityRequiresEvent, DatabaseRequiresEvent): + """Event emitted when a new entity is created for use on this relation.""" + + class DatabaseEndpointsChangedEvent(AuthenticationEvent, DatabaseRequiresEvent): """Event emitted when the read/write endpoints are changed.""" @@ -2823,6 +3158,7 @@ class DatabaseRequiresEvents(CharmEvents): """ database_created = EventSource(DatabaseCreatedEvent) + database_entity_created = EventSource(DatabaseEntityCreatedEvent) endpoints_changed = EventSource(DatabaseEndpointsChangedEvent) read_only_endpoints_changed = EventSource(DatabaseReadOnlyEndpointsChangedEvent) @@ -2944,16 +3280,47 @@ def _on_relation_changed_event(self, event: RelationChangedEvent) -> None: # Leader only if not self.relation_data.local_unit.is_leader(): return + # Check which data has changed to emit customs events. diff = self._diff(event) - # Emit a database requested event if the setup key (database name and optional - # extra user roles) was added to the relation databag by the application. - if "database" in diff.added: + # Validate entity information is not dynamically changed + self._validate_entity_consistency(event, diff) + + # Emit a database requested event if the setup key (database name) + # was added to the relation databag, but the entity-type key was not. + if "database" in diff.added and "entity-type" not in diff.added: getattr(self.on, "database_requested").emit( event.relation, app=event.app, unit=event.unit ) + # To avoid unnecessary application restarts do not trigger other events. + return + + # Emit an entity requested event if the setup key (database name) + # was added to the relation databag, in addition to the entity-type key. + if "database" in diff.added and "entity-type" in diff.added: + getattr(self.on, "database_entity_requested").emit( + event.relation, app=event.app, unit=event.unit + ) + + # To avoid unnecessary application restarts do not trigger other events. + return + + # Emit a permissions changed event if the setup key (database name) + # was added to the relation databag, and the entity-permissions key changed. + if ( + "database" not in diff.added + and "entity-type" not in diff.added + and ("entity-permissions" in diff.added or "entity-permissions" in diff.changed) + ): + getattr(self.on, "database_entity_permissions_changed").emit( + event.relation, app=event.app, unit=event.unit + ) + + # To avoid unnecessary application restarts do not trigger other events. + return + def _on_secret_changed_event(self, event: SecretChangedEvent) -> None: """Event emitted when the secret has changed.""" pass @@ -2979,9 +3346,26 @@ def __init__( relations_aliases: Optional[List[str]] = None, additional_secret_fields: Optional[List[str]] = [], external_node_connectivity: bool = False, + extra_group_roles: Optional[str] = None, + entity_type: Optional[str] = None, + entity_permissions: Optional[str] = None, + requested_entity_secret: Optional[str] = None, + requested_entity_name: Optional[str] = None, + requested_entity_password: Optional[str] = None, ): """Manager of database client relations.""" - super().__init__(model, relation_name, extra_user_roles, additional_secret_fields) + super().__init__( + model, + relation_name, + extra_user_roles, + additional_secret_fields, + extra_group_roles, + entity_type, + entity_permissions, + requested_entity_secret, + requested_entity_name, + requested_entity_password, + ) self.database = database_name self.relations_aliases = relations_aliases self.external_node_connectivity = external_node_connectivity @@ -3064,9 +3448,17 @@ def __init__( if self.relation_data.relations_aliases: for relation_alias in self.relation_data.relations_aliases: - self.on.define_event(f"{relation_alias}_database_created", DatabaseCreatedEvent) self.on.define_event( - f"{relation_alias}_endpoints_changed", DatabaseEndpointsChangedEvent + f"{relation_alias}_database_created", + DatabaseCreatedEvent, + ) + self.on.define_event( + f"{relation_alias}_database_entity_created", + DatabaseEntityCreatedEvent, + ) + self.on.define_event( + f"{relation_alias}_endpoints_changed", + DatabaseEndpointsChangedEvent, ) self.on.define_event( f"{relation_alias}_read_only_endpoints_changed", @@ -3156,6 +3548,30 @@ def _on_relation_created_event(self, event: RelationCreatedEvent) -> None: if self.relation_data.extra_user_roles: event_data["extra-user-roles"] = self.relation_data.extra_user_roles + if self.relation_data.extra_group_roles: + event_data["extra-group-roles"] = self.relation_data.extra_group_roles + if self.relation_data.entity_type: + event_data["entity-type"] = self.relation_data.entity_type + if self.relation_data.entity_permissions: + event_data["entity-permissions"] = self.relation_data.entity_permissions + if self.relation_data.requested_entity_secret: + event_data["requested-entity-secret"] = self.relation_data.requested_entity_secret + + # Create helper secret if needed + if ( + self.relation_data.requested_entity_name + and not self.relation_data.requested_entity_secret + ): + content = {"entity-name": self.relation_data.requested_entity_name} + if self.relation_data.requested_entity_password: + content["password"] = self.relation_data.requested_entity_password + secret = self.charm.app.add_secret( + content, label=f"{self.model.uuid}-{event.relation.id}-requested-entity" + ) + secret.grant(event.relation) + if not secret.id: + raise SecretError("Secret helper missing Id") + event_data["requested-entity-secret"] = secret.id # set external-node-connectivity field if self.relation_data.external_node_connectivity: @@ -3163,6 +3579,19 @@ def _on_relation_created_event(self, event: RelationCreatedEvent) -> None: self.relation_data.update_relation_data(event.relation.id, event_data) + def _clear_helper_secret(self, event: RelationChangedEvent, app_databag: Dict) -> None: + """Remove helper secret if set.""" + if ( + self.relation_data.local_unit.is_leader() + and self.relation_data.requested_entity_name + and (secret_uri := app_databag.get("requested-entity-secret")) + ): + try: + secret = self.framework.model.get_secret(id=secret_uri) + secret.remove_all_revisions() + except ModelError: + logger.debug("Unable to remove helper secret") + def _on_relation_changed_event(self, event: RelationChangedEvent) -> None: """Event emitted when the database relation has changed.""" is_subordinate = False @@ -3174,10 +3603,7 @@ def _on_relation_changed_event(self, event: RelationChangedEvent) -> None: is_subordinate = event.relation.data[key].get("subordinated") == "true" if is_subordinate: - if not remote_unit_data: - return - - if remote_unit_data.get("state") != "ready": + if not remote_unit_data or remote_unit_data.get("state") != "ready": return # Check which data has changed to emit customs events. @@ -3187,12 +3613,13 @@ def _on_relation_changed_event(self, event: RelationChangedEvent) -> None: if any(newval for newval in diff.added if self.relation_data._is_secret_field(newval)): self.relation_data._register_secrets_to_relation(event.relation, diff.added) + app_databag = get_encoded_dict(event.relation, event.app, "data") + if app_databag is None: + app_databag = {} + # Check if the database is created # (the database charm shared the credentials). - secret_field_user = self.relation_data._generate_secret_field_name(SECRET_GROUPS.USER) - if ( - "username" in diff.added and "password" in diff.added - ) or secret_field_user in diff.added: + if self._main_credentials_shared(diff) and "entity-type" not in app_databag: # Emit the default event (the one without an alias). logger.info("database created at %s", datetime.now()) getattr(self.on, "database_created").emit( @@ -3201,9 +3628,23 @@ def _on_relation_changed_event(self, event: RelationChangedEvent) -> None: # Emit the aliased event (if any). self._emit_aliased_event(event, "database_created") + self._clear_helper_secret(event, app_databag) + + # To avoid unnecessary application restarts do not trigger other events. + return + + if self._entity_credentials_shared(diff) and "entity-type" in app_databag: + # Emit the default event (the one without an alias). + logger.info("entity created at %s", datetime.now()) + getattr(self.on, "database_entity_created").emit( + event.relation, app=event.app, unit=event.unit + ) + + # Emit the aliased event (if any). + self._emit_aliased_event(event, "database_entity_created") + self._clear_helper_secret(event, app_databag) - # To avoid unnecessary application restarts do not trigger - # “endpoints_changed“ event if “database_created“ is triggered. + # To avoid unnecessary application restarts do not trigger other events. return # Emit an endpoints changed event if the database @@ -3218,8 +3659,7 @@ def _on_relation_changed_event(self, event: RelationChangedEvent) -> None: # Emit the aliased event (if any). self._emit_aliased_event(event, "endpoints_changed") - # To avoid unnecessary application restarts do not trigger - # “read_only_endpoints_changed“ event if “endpoints_changed“ is triggered. + # To avoid unnecessary application restarts do not trigger other events. return # Emit a read only endpoints changed event if the database @@ -3247,6 +3687,12 @@ def __init__( relations_aliases: Optional[List[str]] = None, additional_secret_fields: Optional[List[str]] = [], external_node_connectivity: bool = False, + extra_group_roles: Optional[str] = None, + entity_type: Optional[str] = None, + entity_permissions: Optional[str] = None, + requested_entity_secret: Optional[str] = None, + requested_entity_name: Optional[str] = None, + requested_entity_password: Optional[str] = None, ): DatabaseRequirerData.__init__( self, @@ -3257,6 +3703,12 @@ def __init__( relations_aliases, additional_secret_fields, external_node_connectivity, + extra_group_roles, + entity_type, + entity_permissions, + requested_entity_secret, + requested_entity_name, + requested_entity_password, ) DatabaseRequirerEventHandlers.__init__(self, charm, self) @@ -3322,17 +3774,35 @@ def restore(self, snapshot): self.old_mtls_cert = snapshot["old_mtls_cert"] -class TopicRequestedEvent(KafkaProvidesEvent, ExtraRoleEvent): +class TopicRequestedEvent(KafkaProvidesEvent): """Event emitted when a new topic is requested for use on this relation.""" + @property + def extra_user_roles(self) -> Optional[str]: + """Returns the extra user roles that were requested.""" + if not self.relation.app: + return None -class KafkaProvidesEvents(CharmEvents): - """Kafka events. + return self.relation.data[self.relation.app].get("extra-user-roles") - This class defines the events that the Kafka can emit. + +class TopicEntityRequestedEvent(KafkaProvidesEvent, EntityProvidesEvent): + """Event emitted when a new entity is requested for use on this relation.""" + + +class TopicEntityPermissionsChangedEvent(KafkaProvidesEvent, EntityProvidesEvent): + """Event emitted when existing entity permissions are changed on this relation.""" + + +class KafkaProvidesEvents(CharmEvents): + """Kafka events. + + This class defines the events that the Kafka can emit. """ topic_requested = EventSource(TopicRequestedEvent) + topic_entity_requested = EventSource(TopicEntityRequestedEvent) + topic_entity_permissions_changed = EventSource(TopicEntityPermissionsChangedEvent) mtls_cert_updated = EventSource(KafkaClientMtlsCertUpdatedEvent) @@ -3376,6 +3846,10 @@ class TopicCreatedEvent(AuthenticationEvent, KafkaRequiresEvent): """Event emitted when a new topic is created for use on this relation.""" +class TopicEntityCreatedEvent(EntityRequiresEvent, KafkaRequiresEvent): + """Event emitted when a new entity is created for use on this relation.""" + + class BootstrapServerChangedEvent(AuthenticationEvent, KafkaRequiresEvent): """Event emitted when the bootstrap server is changed.""" @@ -3387,6 +3861,7 @@ class KafkaRequiresEvents(CharmEvents): """ topic_created = EventSource(TopicCreatedEvent) + topic_entity_created = EventSource(TopicEntityCreatedEvent) bootstrap_server_changed = EventSource(BootstrapServerChangedEvent) @@ -3465,13 +3940,43 @@ def _on_relation_changed_event(self, event: RelationChangedEvent) -> None: # Check which data has changed to emit customs events. diff = self._diff(event) - # Emit a topic requested event if the setup key (topic name and optional - # extra user roles) was added to the relation databag by the application. - if "topic" in diff.added: + # Validate entity information is not dynamically changed + self._validate_entity_consistency(event, diff) + + # Emit a topic requested event if the setup key (topic name) + # was added to the relation databag, but the entity-type key was not. + if "topic" in diff.added and "entity-type" not in diff.added: getattr(self.on, "topic_requested").emit( event.relation, app=event.app, unit=event.unit ) + # To avoid unnecessary application restarts do not trigger other events. + return + + # Emit an entity requested event if the setup key (topic name) + # was added to the relation databag, in addition to the entity-type key. + if "topic" in diff.added and "entity-type" in diff.added: + getattr(self.on, "topic_entity_requested").emit( + event.relation, app=event.app, unit=event.unit + ) + + # To avoid unnecessary application restarts do not trigger other events. + return + + # Emit a permissions changed event if the setup key (topic name) + # was added to the relation databag, and the entity-permissions key changed. + if ( + "topic" not in diff.added + and "entity-type" not in diff.added + and ("entity-permissions" in diff.added or "entity-permissions" in diff.changed) + ): + getattr(self.on, "topic_entity_permissions_changed").emit( + event.relation, app=event.app, unit=event.unit + ) + + # To avoid unnecessary application restarts do not trigger other events. + return + def _on_secret_changed_event(self, event: SecretChangedEvent): """Event notifying about a new value of a secret.""" if not event.secret.label: @@ -3520,9 +4025,20 @@ def __init__( consumer_group_prefix: Optional[str] = None, additional_secret_fields: Optional[List[str]] = [], mtls_cert: Optional[str] = None, + extra_group_roles: Optional[str] = None, + entity_type: Optional[str] = None, + entity_permissions: Optional[str] = None, ): """Manager of Kafka client relations.""" - super().__init__(model, relation_name, extra_user_roles, additional_secret_fields) + super().__init__( + model, + relation_name, + extra_user_roles, + additional_secret_fields, + extra_group_roles, + entity_type, + entity_permissions, + ) self.topic = topic self.consumer_group_prefix = consumer_group_prefix or "" self.mtls_cert = mtls_cert @@ -3576,12 +4092,18 @@ def _on_relation_created_event(self, event: RelationCreatedEvent) -> None: if self.relation_data.mtls_cert: relation_data["mtls-cert"] = self.relation_data.mtls_cert - if self.relation_data.extra_user_roles: - relation_data["extra-user-roles"] = self.relation_data.extra_user_roles - if self.relation_data.consumer_group_prefix: relation_data["consumer-group-prefix"] = self.relation_data.consumer_group_prefix + if self.relation_data.extra_user_roles: + relation_data["extra-user-roles"] = self.relation_data.extra_user_roles + if self.relation_data.extra_group_roles: + relation_data["extra-group-roles"] = self.relation_data.extra_group_roles + if self.relation_data.entity_type: + relation_data["entity-type"] = self.relation_data.entity_type + if self.relation_data.entity_permissions: + relation_data["entity-permissions"] = self.relation_data.entity_permissions + self.relation_data.update_relation_data(event.relation.id, relation_data) def _on_secret_changed_event(self, event: SecretChangedEvent): @@ -3600,16 +4122,26 @@ def _on_relation_changed_event(self, event: RelationChangedEvent) -> None: if any(newval for newval in diff.added if self.relation_data._is_secret_field(newval)): self.relation_data._register_secrets_to_relation(event.relation, diff.added) - secret_field_user = self.relation_data._generate_secret_field_name(SECRET_GROUPS.USER) - if ( - "username" in diff.added and "password" in diff.added - ) or secret_field_user in diff.added: + app_databag = get_encoded_dict(event.relation, event.app, "data") + if app_databag is None: + app_databag = {} + + if self._main_credentials_shared(diff) and "entity-type" not in app_databag: # Emit the default event (the one without an alias). logger.info("topic created at %s", datetime.now()) getattr(self.on, "topic_created").emit(event.relation, app=event.app, unit=event.unit) - # To avoid unnecessary application restarts do not trigger - # “endpoints_changed“ event if “topic_created“ is triggered. + # To avoid unnecessary application restarts do not trigger other events. + return + + if self._entity_credentials_shared(diff) and "entity-type" in app_databag: + # Emit the default event (the one without an alias). + logger.info("entity created at %s", datetime.now()) + getattr(self.on, "topic_entity_created").emit( + event.relation, app=event.app, unit=event.unit + ) + + # To avoid unnecessary application restarts do not trigger other events. return # Emit an endpoints (bootstrap-server) changed event if the Kafka endpoints @@ -3620,6 +4152,8 @@ def _on_relation_changed_event(self, event: RelationChangedEvent) -> None: getattr(self.on, "bootstrap_server_changed").emit( event.relation, app=event.app, unit=event.unit ) # here check if this is the right design + + # To avoid unnecessary application restarts do not trigger other events. return @@ -3635,6 +4169,9 @@ def __init__( consumer_group_prefix: Optional[str] = None, additional_secret_fields: Optional[List[str]] = [], mtls_cert: Optional[str] = None, + extra_group_roles: Optional[str] = None, + entity_type: Optional[str] = None, + entity_permissions: Optional[str] = None, ) -> None: KafkaRequirerData.__init__( self, @@ -3645,10 +4182,561 @@ def __init__( consumer_group_prefix=consumer_group_prefix, additional_secret_fields=additional_secret_fields, mtls_cert=mtls_cert, + extra_group_roles=extra_group_roles, + entity_type=entity_type, + entity_permissions=entity_permissions, ) KafkaRequirerEventHandlers.__init__(self, charm, self) +# Karapace related events + + +class KarapaceProvidesEvent(RelationEvent): + """Base class for Karapace events.""" + + @property + def subject(self) -> Optional[str]: + """Returns the subject that was requested.""" + if not self.relation.app: + return None + + return self.relation.data[self.relation.app].get("subject") + + +class SubjectRequestedEvent(KarapaceProvidesEvent): + """Event emitted when a new subject is requested for use on this relation.""" + + @property + def extra_user_roles(self) -> Optional[str]: + """Returns the extra user roles that were requested.""" + if not self.relation.app: + return None + + return self.relation.data[self.relation.app].get("extra-user-roles") + + +class SubjectEntityRequestedEvent(KarapaceProvidesEvent, EntityProvidesEvent): + """Event emitted when a new entity is requested for use on this relation.""" + + +class SubjectEntityPermissionsChangedEvent(KarapaceProvidesEvent, EntityProvidesEvent): + """Event emitted when existing entity permissions are changed on this relation.""" + + +class KarapaceProvidesEvents(CharmEvents): + """Karapace events. + + This class defines the events that the Karapace can emit. + """ + + subject_requested = EventSource(SubjectRequestedEvent) + subject_entity_requested = EventSource(SubjectEntityRequestedEvent) + subject_entity_permissions_changed = EventSource(SubjectEntityPermissionsChangedEvent) + + +class KarapaceRequiresEvent(RelationEvent): + """Base class for Karapace events.""" + + @property + def subject(self) -> Optional[str]: + """Returns the subject.""" + if not self.relation.app: + return None + + return self.relation.data[self.relation.app].get("subject") + + @property + def endpoints(self) -> Optional[str]: + """Returns a comma-separated list of broker uris.""" + if not self.relation.app: + return None + + return self.relation.data[self.relation.app].get("endpoints") + + +class SubjectAllowedEvent(AuthenticationEvent, KarapaceRequiresEvent): + """Event emitted when a new subject ACL is created for use on this relation.""" + + +class SubjectEntityCreatedEvent(EntityRequiresEvent, KarapaceRequiresEvent): + """Event emitted when a new entity is created for use on this relation.""" + + +class EndpointsChangedEvent(AuthenticationEvent, KarapaceRequiresEvent): + """Event emitted when the endpoints are changed.""" + + +class KarapaceRequiresEvents(CharmEvents): + """Karapace events. + + This class defines the events that Karapace can emit. + """ + + subject_allowed = EventSource(SubjectAllowedEvent) + subject_entity_created = EventSource(SubjectEntityCreatedEvent) + server_changed = EventSource(EndpointsChangedEvent) + + +# Karapace Provides and Requires + + +class KarapaceProviderData(ProviderData): + """Provider-side of the Karapace relation.""" + + RESOURCE_FIELD = "subject" + + def __init__(self, model: Model, relation_name: str) -> None: + super().__init__(model, relation_name) + + def set_subject(self, relation_id: int, subject: str) -> None: + """Set subject name in the application relation databag. + + Args: + relation_id: the identifier for a particular relation. + subject: the subject name. + """ + self.update_relation_data(relation_id, {"subject": subject}) + + def set_endpoint(self, relation_id: int, endpoint: str) -> None: + """Set the endpoint in the application relation databag. + + Args: + relation_id: the identifier for a particular relation. + endpoint: the server address. + """ + self.update_relation_data(relation_id, {"endpoints": endpoint}) + + +class KarapaceProviderEventHandlers(ProviderEventHandlers): + """Provider-side of the Karapace relation.""" + + on = KarapaceProvidesEvents() # pyright: ignore [reportAssignmentType] + + def __init__(self, charm: CharmBase, relation_data: KarapaceProviderData) -> None: + super().__init__(charm, relation_data) + # Just to keep lint quiet, can't resolve inheritance. The same happened in super().__init__() above + self.relation_data = relation_data + + def _on_relation_changed_event(self, event: RelationChangedEvent) -> None: + """Event emitted when the relation has changed.""" + super()._on_relation_changed_event(event) + + # Leader only + if not self.relation_data.local_unit.is_leader(): + return + + # Check which data has changed to emit customs events. + diff = self._diff(event) + + # Validate entity information is not dynamically changed + self._validate_entity_consistency(event, diff) + + # Emit a subject requested event if the setup key (subject name) + # was added to the relation databag, but the entity-type key was not. + if "subject" in diff.added and "entity-type" not in diff.added: + getattr(self.on, "subject_requested").emit( + event.relation, app=event.app, unit=event.unit + ) + + # To avoid unnecessary application restarts do not trigger other events. + return + + # Emit an entity requested event if the setup key (subject name) + # was added to the relation databag, in addition to the entity-type key. + if "subject" in diff.added and "entity-type" in diff.added: + getattr(self.on, "subject_entity_requested").emit( + event.relation, app=event.app, unit=event.unit + ) + + # To avoid unnecessary application restarts do not trigger other events. + return + + # Emit a permissions changed event if the setup key (subject name) + # was added to the relation databag, and the entity-permissions key changed. + if ( + "subject" not in diff.added + and "entity-type" not in diff.added + and ("entity-permissions" in diff.added or "entity-permissions" in diff.changed) + ): + getattr(self.on, "subject_entity_permissions_changed").emit( + event.relation, app=event.app, unit=event.unit + ) + + # To avoid unnecessary application restarts do not trigger other events. + return + + def _on_secret_changed_event(self, event: SecretChangedEvent): + """Event notifying about a new value of a secret.""" + pass + + +class KarapaceProvides(KarapaceProviderData, KarapaceProviderEventHandlers): + """Provider-side of the Karapace relation.""" + + def __init__(self, charm: CharmBase, relation_name: str) -> None: + KarapaceProviderData.__init__(self, charm.model, relation_name) + KarapaceProviderEventHandlers.__init__(self, charm, self) + + +class KarapaceRequirerData(RequirerData): + """Requirer-side of the Karapace relation.""" + + def __init__( + self, + model: Model, + relation_name: str, + subject: str, + extra_user_roles: Optional[str] = None, + additional_secret_fields: Optional[List[str]] = [], + extra_group_roles: Optional[str] = None, + entity_type: Optional[str] = None, + entity_permissions: Optional[str] = None, + ): + """Manager of Karapace client relations.""" + super().__init__( + model, + relation_name, + extra_user_roles, + additional_secret_fields, + extra_group_roles, + entity_type, + entity_permissions, + ) + self.subject = subject + + @property + def subject(self): + """Topic to use in Karapace.""" + return self._subject + + @subject.setter + def subject(self, value): + # Avoid wildcards + if value == "*": + raise ValueError(f"Error on subject '{value}', cannot be a wildcard.") + self._subject = value + + +class KarapaceRequirerEventHandlers(RequirerEventHandlers): + """Requires-side of the Karapace relation.""" + + on = KarapaceRequiresEvents() # pyright: ignore [reportAssignmentType] + + def __init__(self, charm: CharmBase, relation_data: KarapaceRequirerData) -> None: + super().__init__(charm, relation_data) + # Just to keep lint quiet, can't resolve inheritance. The same happened in super().__init__() above + self.relation_data = relation_data + + def _on_relation_created_event(self, event: RelationCreatedEvent) -> None: + """Event emitted when the Karapace relation is created.""" + super()._on_relation_created_event(event) + + if not self.relation_data.local_unit.is_leader(): + return + + # Sets subject and extra user roles + relation_data = {"subject": self.relation_data.subject} + + if self.relation_data.extra_user_roles: + relation_data["extra-user-roles"] = self.relation_data.extra_user_roles + if self.relation_data.extra_group_roles: + relation_data["extra-group-roles"] = self.relation_data.extra_group_roles + if self.relation_data.entity_type: + relation_data["entity-type"] = self.relation_data.entity_type + if self.relation_data.entity_permissions: + relation_data["entity-permissions"] = self.relation_data.entity_permissions + + self.relation_data.update_relation_data(event.relation.id, relation_data) + + def _on_secret_changed_event(self, event: SecretChangedEvent): + """Event notifying about a new value of a secret.""" + pass + + def _on_relation_changed_event(self, event: RelationChangedEvent) -> None: + """Event emitted when the Karapace relation has changed.""" + # Check which data has changed to emit customs events. + diff = self._diff(event) + + # Check if the subject ACLs are created + # (the Karapace charm shared the credentials). + + # Register all new secrets with their labels + if any(newval for newval in diff.added if self.relation_data._is_secret_field(newval)): + self.relation_data._register_secrets_to_relation(event.relation, diff.added) + + app_databag = get_encoded_dict(event.relation, event.app, "data") + if app_databag is None: + app_databag = {} + + if self._main_credentials_shared(diff) and "entity-type" not in app_databag: + # Emit the default event (the one without an alias). + logger.info("subject ACL created at %s", datetime.now()) + getattr(self.on, "subject_allowed").emit( + event.relation, app=event.app, unit=event.unit + ) + + # To avoid unnecessary application restarts do not trigger other events. + return + + if self._entity_credentials_shared(diff) and "entity-type" in app_databag: + # Emit the default event (the one without an alias). + logger.info("entity created at %s", datetime.now()) + getattr(self.on, "subject_entity_created").emit( + event.relation, app=event.app, unit=event.unit + ) + + # To avoid unnecessary application restarts do not trigger other events. + return + + # Emit an endpoints changed event if the Karapace endpoints added or changed + # this info in the relation databag. + if "endpoints" in diff.added or "endpoints" in diff.changed: + # Emit the default event (the one without an alias). + logger.info("endpoints changed on %s", datetime.now()) + getattr(self.on, "server_changed").emit( + event.relation, app=event.app, unit=event.unit + ) # here check if this is the right design + + # To avoid unnecessary application restarts do not trigger other events. + return + + +class KarapaceRequires(KarapaceRequirerData, KarapaceRequirerEventHandlers): + """Provider-side of the Karapace relation.""" + + def __init__( + self, + charm: CharmBase, + relation_name: str, + subject: str, + extra_user_roles: Optional[str] = None, + additional_secret_fields: Optional[List[str]] = [], + extra_group_roles: Optional[str] = None, + entity_type: Optional[str] = None, + entity_permissions: Optional[str] = None, + ) -> None: + KarapaceRequirerData.__init__( + self, + charm.model, + relation_name, + subject, + extra_user_roles, + additional_secret_fields, + extra_group_roles, + entity_type, + entity_permissions, + ) + KarapaceRequirerEventHandlers.__init__(self, charm, self) + + +# Kafka Connect Events + + +class KafkaConnectProvidesEvent(RelationEvent): + """Base class for Kafka Connect Provider events.""" + + @property + def plugin_url(self) -> Optional[str]: + """Returns the REST endpoint URL which serves the connector plugin.""" + if not self.relation.app: + return None + + return self.relation.data[self.relation.app].get("plugin-url") + + +class IntegrationRequestedEvent(KafkaConnectProvidesEvent): + """Event emitted when a new integrator boots up and is ready to serve the connector plugin.""" + + +class KafkaConnectProvidesEvents(CharmEvents): + """Kafka Connect Provider Events.""" + + integration_requested = EventSource(IntegrationRequestedEvent) + + +class KafkaConnectRequiresEvent(AuthenticationEvent): + """Base class for Kafka Connect Requirer events.""" + + @property + def plugin_url(self) -> Optional[str]: + """Returns the REST endpoint URL which serves the connector plugin.""" + if not self.relation.app: + return None + + return self.relation.data[self.relation.app].get("plugin-url") + + +class IntegrationCreatedEvent(KafkaConnectRequiresEvent): + """Event emitted when the credentials are created for this integrator.""" + + +class IntegrationEndpointsChangedEvent(KafkaConnectRequiresEvent): + """Event emitted when Kafka Connect REST endpoints change.""" + + +class KafkaConnectRequiresEvents(CharmEvents): + """Kafka Connect Requirer Events.""" + + integration_created = EventSource(IntegrationCreatedEvent) + integration_endpoints_changed = EventSource(IntegrationEndpointsChangedEvent) + + +class KafkaConnectProviderData(ProviderData): + """Provider-side of the Kafka Connect relation.""" + + RESOURCE_FIELD = "plugin-url" + + def __init__(self, model: Model, relation_name: str) -> None: + super().__init__(model, relation_name) + + def set_endpoints(self, relation_id: int, endpoints: str) -> None: + """Sets REST endpoints of the Kafka Connect service.""" + self.update_relation_data(relation_id, {"endpoints": endpoints}) + + +class KafkaConnectProviderEventHandlers(EventHandlers): + """Provider-side implementation of the Kafka Connect event handlers.""" + + on = KafkaConnectProvidesEvents() # pyright: ignore [reportAssignmentType] + + def __init__(self, charm: CharmBase, relation_data: KafkaConnectProviderData) -> None: + super().__init__(charm, relation_data) + self.relation_data = relation_data + + def _on_relation_changed_event(self, event: RelationChangedEvent) -> None: + """Event emitted when the relation has changed.""" + # Leader only + if not self.relation_data.local_unit.is_leader(): + return + + # Check which data has changed to emit customs events. + diff = self._diff(event) + + if "plugin-url" in diff.added: + getattr(self.on, "integration_requested").emit( + event.relation, app=event.app, unit=event.unit + ) + + def _on_secret_changed_event(self, event: SecretChangedEvent): + """Event notifying about a new value of a secret.""" + pass + + +class KafkaConnectProvides(KafkaConnectProviderData, KafkaConnectProviderEventHandlers): + """Provider-side implementation of the Kafka Connect relation.""" + + def __init__(self, charm: CharmBase, relation_name: str) -> None: + KafkaConnectProviderData.__init__(self, charm.model, relation_name) + KafkaConnectProviderEventHandlers.__init__(self, charm, self) + + +# Sentinel value passed from Kafka Connect requirer side when it does not need to serve any plugins. +PLUGIN_URL_NOT_REQUIRED: Final[str] = "NOT-REQUIRED" + + +class KafkaConnectRequirerData(RequirerData): + """Requirer-side of the Kafka Connect relation.""" + + def __init__( + self, + model: Model, + relation_name: str, + plugin_url: str, + extra_user_roles: Optional[str] = None, + additional_secret_fields: Optional[List[str]] = [], + ): + """Manager of Kafka client relations.""" + super().__init__( + model, + relation_name, + extra_user_roles=extra_user_roles, + additional_secret_fields=additional_secret_fields, + ) + self.plugin_url = plugin_url + + @property + def plugin_url(self): + """The REST endpoint URL which serves the connector plugin.""" + return self._plugin_url + + @plugin_url.setter + def plugin_url(self, value): + self._plugin_url = value + + +class KafkaConnectRequirerEventHandlers(RequirerEventHandlers): + """Requirer-side of the Kafka Connect relation.""" + + on = KafkaConnectRequiresEvents() # pyright: ignore [reportAssignmentType] + + def __init__(self, charm: CharmBase, relation_data: KafkaConnectRequirerData) -> None: + super().__init__(charm, relation_data) + self.relation_data = relation_data + + def _on_relation_created_event(self, event: RelationCreatedEvent) -> None: + """Event emitted when the Kafka Connect relation is created.""" + super()._on_relation_created_event(event) + + if not self.relation_data.local_unit.is_leader(): + return + + relation_data = {"plugin-url": self.relation_data.plugin_url} + self.relation_data.update_relation_data(event.relation.id, relation_data) + + def _on_secret_changed_event(self, event: SecretChangedEvent): + """Event notifying about a new value of a secret.""" + pass + + def _on_relation_changed_event(self, event: RelationChangedEvent) -> None: + """Event emitted when the Kafka Connect relation has changed.""" + # Check which data has changed to emit customs events. + diff = self._diff(event) + + # Register all new secrets with their labels + if any(newval for newval in diff.added if self.relation_data._is_secret_field(newval)): + self.relation_data._register_secrets_to_relation(event.relation, diff.added) + + if self._main_credentials_shared(diff): + logger.info("integration created at %s", datetime.now()) + getattr(self.on, "integration_created").emit( + event.relation, app=event.app, unit=event.unit + ) + return + + # Emit an endpoints changed event if the provider added or + # changed this info in the relation databag. + if "endpoints" in diff.added or "endpoints" in diff.changed: + # Emit the default event (the one without an alias). + logger.info("endpoints changed on %s", datetime.now()) + getattr(self.on, "integration_endpoints_changed").emit( + event.relation, app=event.app, unit=event.unit + ) + return + + +class KafkaConnectRequires(KafkaConnectRequirerData, KafkaConnectRequirerEventHandlers): + """Requirer-side implementation of the Kafka Connect relation.""" + + def __init__( + self, + charm: CharmBase, + relation_name: str, + plugin_url: str, + extra_user_roles: Optional[str] = None, + additional_secret_fields: Optional[List[str]] = [], + ) -> None: + KafkaConnectRequirerData.__init__( + self, + charm.model, + relation_name, + plugin_url, + extra_user_roles=extra_user_roles, + additional_secret_fields=additional_secret_fields, + ) + KafkaConnectRequirerEventHandlers.__init__(self, charm, self) + + # Opensearch related events @@ -3664,9 +4752,25 @@ def index(self) -> Optional[str]: return self.relation.data[self.relation.app].get("index") -class IndexRequestedEvent(OpenSearchProvidesEvent, ExtraRoleEvent): +class IndexRequestedEvent(OpenSearchProvidesEvent): """Event emitted when a new index is requested for use on this relation.""" + @property + def extra_user_roles(self) -> Optional[str]: + """Returns the extra user roles that were requested.""" + if not self.relation.app: + return None + + return self.relation.data[self.relation.app].get("extra-user-roles") + + +class IndexEntityRequestedEvent(OpenSearchProvidesEvent, EntityProvidesEvent): + """Event emitted when a new entity is requested for use on this relation.""" + + +class IndexEntityPermissionsChangedEvent(OpenSearchProvidesEvent, EntityProvidesEvent): + """Event emitted when existing entity permissions are changed on this relation.""" + class OpenSearchProvidesEvents(CharmEvents): """OpenSearch events. @@ -3675,6 +4779,8 @@ class OpenSearchProvidesEvents(CharmEvents): """ index_requested = EventSource(IndexRequestedEvent) + index_entity_requested = EventSource(IndexEntityRequestedEvent) + index_entity_permissions_changed = EventSource(IndexEntityPermissionsChangedEvent) class OpenSearchRequiresEvent(DatabaseRequiresEvent): @@ -3685,6 +4791,10 @@ class IndexCreatedEvent(AuthenticationEvent, OpenSearchRequiresEvent): """Event emitted when a new index is created for use on this relation.""" +class IndexEntityCreatedEvent(EntityRequiresEvent, OpenSearchRequiresEvent): + """Event emitted when a new index is created for use on this relation.""" + + class OpenSearchRequiresEvents(CharmEvents): """OpenSearch events. @@ -3692,6 +4802,7 @@ class OpenSearchRequiresEvents(CharmEvents): """ index_created = EventSource(IndexCreatedEvent) + index_entity_created = EventSource(IndexEntityCreatedEvent) endpoints_changed = EventSource(DatabaseEndpointsChangedEvent) authentication_updated = EventSource(AuthenticationEvent) @@ -3754,16 +4865,47 @@ def _on_relation_changed_event(self, event: RelationChangedEvent) -> None: # Leader only if not self.relation_data.local_unit.is_leader(): return + # Check which data has changed to emit customs events. diff = self._diff(event) - # Emit an index requested event if the setup key (index name and optional extra user roles) - # have been added to the relation databag by the application. - if "index" in diff.added: + # Validate entity information is not dynamically changed + self._validate_entity_consistency(event, diff) + + # Emit an index requested event if the setup key (index name) + # was added to the relation databag, but the entity-type key was not. + if "index" in diff.added and "entity-type" not in diff.added: getattr(self.on, "index_requested").emit( event.relation, app=event.app, unit=event.unit ) + # To avoid unnecessary application restarts do not trigger other events. + return + + # Emit an entity requested event if the setup key (index name) + # was added to the relation databag, in addition to the entity-type key. + if "index" in diff.added and "entity-type" in diff.added: + getattr(self.on, "index_entity_requested").emit( + event.relation, app=event.app, unit=event.unit + ) + + # To avoid unnecessary application restarts do not trigger other events. + return + + # Emit a permissions changed event if the setup key (index name) + # was added to the relation databag, and the entity-permissions key changed. + if ( + "index" not in diff.added + and "entity-type" not in diff.added + and ("entity-permissions" in diff.added or "entity-permissions" in diff.changed) + ): + getattr(self.on, "index_entity_permissions_changed").emit( + event.relation, app=event.app, unit=event.unit + ) + + # To avoid unnecessary application restarts do not trigger other events. + return + def _on_secret_changed_event(self, event: SecretChangedEvent) -> None: """Event emitted when the relation data has changed.""" pass @@ -3787,9 +4929,20 @@ def __init__( index: str, extra_user_roles: Optional[str] = None, additional_secret_fields: Optional[List[str]] = [], + extra_group_roles: Optional[str] = None, + entity_type: Optional[str] = None, + entity_permissions: Optional[str] = None, ): """Manager of OpenSearch client relations.""" - super().__init__(model, relation_name, extra_user_roles, additional_secret_fields) + super().__init__( + model, + relation_name, + extra_user_roles, + additional_secret_fields, + extra_group_roles, + entity_type, + entity_permissions, + ) self.index = index @@ -3813,8 +4966,15 @@ def _on_relation_created_event(self, event: RelationCreatedEvent) -> None: # Sets both index and extra user roles in the relation if the roles are provided. # Otherwise, sets only the index. data = {"index": self.relation_data.index} + if self.relation_data.extra_user_roles: data["extra-user-roles"] = self.relation_data.extra_user_roles + if self.relation_data.extra_group_roles: + data["extra-group-roles"] = self.relation_data.extra_group_roles + if self.relation_data.entity_type: + data["entity-type"] = self.relation_data.entity_type + if self.relation_data.entity_permissions: + data["entity-permissions"] = self.relation_data.entity_permissions self.relation_data.update_relation_data(event.relation.id, data) @@ -3864,27 +5024,40 @@ def _on_relation_changed_event(self, event: RelationChangedEvent) -> None: event.relation, app=event.app, unit=event.unit ) + app_databag = get_encoded_dict(event.relation, event.app, "data") + if app_databag is None: + app_databag = {} + # Check if the index is created # (the OpenSearch charm shares the credentials). - if ( - "username" in diff.added and "password" in diff.added - ) or secret_field_user in diff.added: + if self._main_credentials_shared(diff) and "entity-type" not in app_databag: # Emit the default event (the one without an alias). logger.info("index created at: %s", datetime.now()) getattr(self.on, "index_created").emit(event.relation, app=event.app, unit=event.unit) - # To avoid unnecessary application restarts do not trigger - # “endpoints_changed“ event if “index_created“ is triggered. + # To avoid unnecessary application restarts do not trigger other events. return - # Emit a endpoints changed event if the OpenSearch application added or changed this info - # in the relation databag. + if self._entity_credentials_shared(diff) and "entity-type" in app_databag: + # Emit the default event (the one without an alias). + logger.info("entity created at: %s", datetime.now()) + getattr(self.on, "index_entity_created").emit( + event.relation, app=event.app, unit=event.unit + ) + + # To avoid unnecessary application restarts do not trigger other events. + return + + # Emit a endpoints changed event if the OpenSearch application + # added or changed this info in the relation databag. if "endpoints" in diff.added or "endpoints" in diff.changed: # Emit the default event (the one without an alias). logger.info("endpoints changed on %s", datetime.now()) getattr(self.on, "endpoints_changed").emit( event.relation, app=event.app, unit=event.unit - ) # here check if this is the right design + ) + + # To avoid unnecessary application restarts do not trigger other events. return @@ -3898,6 +5071,9 @@ def __init__( index: str, extra_user_roles: Optional[str] = None, additional_secret_fields: Optional[List[str]] = [], + extra_group_roles: Optional[str] = None, + entity_type: Optional[str] = None, + entity_permissions: Optional[str] = None, ) -> None: OpenSearchRequiresData.__init__( self, @@ -3906,6 +5082,9 @@ def __init__( index, extra_user_roles, additional_secret_fields, + extra_group_roles, + entity_type, + entity_permissions, ) OpenSearchRequiresEventHandlers.__init__(self, charm, self) @@ -4048,6 +5227,12 @@ def _on_relation_changed_event(self, event: RelationChangedEvent) -> None: if any(newval for newval in new_data_keys if self.relation_data._is_secret_field(newval)): self.relation_data._register_secrets_to_relation(event.relation, new_data_keys) + # Check which data has changed to emit customs events. + diff = self._diff(event) + + # Validate entity information is not dynamically changed + self._validate_entity_consistency(event, diff) + getattr(self.on, "mtls_cert_updated").emit(event.relation, app=event.app, unit=event.unit) return @@ -4100,9 +5285,20 @@ def __init__( mtls_cert: Optional[str], extra_user_roles: Optional[str] = None, additional_secret_fields: Optional[List[str]] = [], + extra_group_roles: Optional[str] = None, + entity_type: Optional[str] = None, + entity_permissions: Optional[str] = None, ): """Manager of Etcd client relations.""" - super().__init__(model, relation_name, extra_user_roles, additional_secret_fields) + super().__init__( + model, + relation_name, + extra_user_roles, + additional_secret_fields, + extra_group_roles, + entity_type, + entity_permissions, + ) self.prefix = prefix self.mtls_cert = mtls_cert @@ -4212,6 +5408,9 @@ def __init__( mtls_cert: Optional[str], extra_user_roles: Optional[str] = None, additional_secret_fields: Optional[List[str]] = [], + extra_group_roles: Optional[str] = None, + entity_type: Optional[str] = None, + entity_permissions: Optional[str] = None, ) -> None: EtcdRequirerData.__init__( self, @@ -4221,6 +5420,9 @@ def __init__( mtls_cert, extra_user_roles, additional_secret_fields, + extra_group_roles, + entity_type, + entity_permissions, ) EtcdRequirerEventHandlers.__init__(self, charm, self) if not self.secrets_enabled: diff --git a/lib/charms/data_platform_libs/v0/s3.py b/lib/charms/data_platform_libs/v0/s3.py index f5614aaf6b..dbf4d5bb72 100644 --- a/lib/charms/data_platform_libs/v0/s3.py +++ b/lib/charms/data_platform_libs/v0/s3.py @@ -110,6 +110,7 @@ def _on_credential_gone(self, event: CredentialsGoneEvent): ``` """ + import json import logging from collections import namedtuple @@ -137,7 +138,7 @@ def _on_credential_gone(self, event: CredentialsGoneEvent): # Increment this PATCH version before using `charmcraft publish-lib` or reset # to 0 if you are raising the major API version -LIBPATCH = 5 +LIBPATCH = 6 logger = logging.getLogger(__name__) @@ -354,7 +355,7 @@ def update_connection_info(self, relation_id: int, connection_data: dict) -> Non updated_connection_data[configuration_option] = configuration_value relation.data[self.local_app].update(updated_connection_data) - logger.debug(f"Updated S3 connection info: {updated_connection_data}") + logger.debug("Updated S3 connection info.") @property def relations(self) -> List[Relation]: @@ -721,7 +722,7 @@ def update_connection_info(self, relation_id: int, connection_data: dict) -> Non updated_connection_data[configuration_option] = configuration_value relation.data[self.local_app].update(updated_connection_data) - logger.debug(f"Updated S3 credentials: {updated_connection_data}") + logger.debug("Updated S3 credentials.") def _load_relation_data(self, raw_relation_data: RelationDataContent) -> Dict[str, str]: """Loads relation data from the relation data bag. diff --git a/lib/charms/grafana_agent/v0/cos_agent.py b/lib/charms/grafana_agent/v0/cos_agent.py index b18c271342..7bf3eb1a5e 100644 --- a/lib/charms/grafana_agent/v0/cos_agent.py +++ b/lib/charms/grafana_agent/v0/cos_agent.py @@ -254,16 +254,12 @@ class _MetricsEndpointDict(TypedDict): LIBID = "dc15fa84cef84ce58155fb84f6c6213a" LIBAPI = 0 -LIBPATCH = 20 +LIBPATCH = 22 PYDEPS = ["cosl >= 0.0.50", "pydantic"] DEFAULT_RELATION_NAME = "cos-agent" DEFAULT_PEER_RELATION_NAME = "peers" -DEFAULT_SCRAPE_CONFIG = { - "static_configs": [{"targets": ["localhost:80"]}], - "metrics_path": "/metrics", -} logger = logging.getLogger(__name__) SnapEndpoint = namedtuple("SnapEndpoint", "owner, name") @@ -472,7 +468,7 @@ def dump(self, databag: Optional[MutableMapping] = None, clear: bool = True): return databag -class CosAgentProviderUnitData(DatabagModel): +class CosAgentProviderUnitData(DatabagModel): # type: ignore """Unit databag model for `cos-agent` relation.""" # The following entries are the same for all units of the same principal. @@ -499,7 +495,7 @@ class CosAgentProviderUnitData(DatabagModel): KEY: ClassVar[str] = "config" -class CosAgentPeersUnitData(DatabagModel): +class CosAgentPeersUnitData(DatabagModel): # type: ignore """Unit databag model for `peers` cos-agent machine charm peer relation.""" # We need the principal unit name and relation metadata to be able to render identifiers @@ -598,7 +594,7 @@ class Receiver(pydantic.BaseModel): ) -class CosAgentRequirerUnitData(DatabagModel): # noqa: D101 +class CosAgentRequirerUnitData(DatabagModel): # type: ignore """Application databag model for the COS-agent requirer.""" receivers: List[Receiver] = pydantic.Field( @@ -714,7 +710,7 @@ def _scrape_jobs(self) -> List[Dict]: } ) - scrape_configs = scrape_configs or [DEFAULT_SCRAPE_CONFIG] + scrape_configs = scrape_configs or [] # Augment job name to include the app name and a unique id (index) for idx, scrape_config in enumerate(scrape_configs): @@ -923,6 +919,7 @@ def __init__( relation_name: str = DEFAULT_RELATION_NAME, peer_relation_name: str = DEFAULT_PEER_RELATION_NAME, refresh_events: Optional[List[str]] = None, + is_tracing_ready: Optional[Callable] = None, ): """Create a COSAgentRequirer instance. @@ -931,12 +928,14 @@ def __init__( relation_name: The name of the relation to communicate over. peer_relation_name: The name of the peer relation to communicate over. refresh_events: List of events on which to refresh relation data. + is_tracing_ready: Custom function to evaluate whether the trace receiver url should be sent. """ super().__init__(charm, relation_name) self._charm = charm self._relation_name = relation_name self._peer_relation_name = peer_relation_name self._refresh_events = refresh_events or [self._charm.on.config_changed] + self._is_tracing_ready = is_tracing_ready events = self._charm.on[relation_name] self.framework.observe( @@ -1046,6 +1045,9 @@ def _on_relation_data_changed(self, event: RelationChangedEvent): def update_tracing_receivers(self): """Updates the list of exposed tracing receivers in all relations.""" + tracing_ready = ( + self._is_tracing_ready if self._is_tracing_ready else self._charm.tracing.is_ready # type: ignore + ) try: for relation in self._charm.model.relations[self._relation_name]: CosAgentRequirerUnitData( @@ -1059,7 +1061,7 @@ def update_tracing_receivers(self): # databag contents (as it expects a string in URL) but that won't cause any errors as # tracing endpoints are the only content in the grafana-agent's side of the databag. url=f"{self._get_tracing_receiver_url(protocol)}" - if self._charm.tracing.is_ready() # type: ignore + if tracing_ready() else None, protocol=ProtocolType( name=protocol, diff --git a/lib/charms/operator_libs_linux/v2/snap.py b/lib/charms/operator_libs_linux/v2/snap.py index b0d65017e8..a706c16628 100644 --- a/lib/charms/operator_libs_linux/v2/snap.py +++ b/lib/charms/operator_libs_linux/v2/snap.py @@ -54,6 +54,10 @@ except snap.SnapError as e: logger.error("An exception occurred when installing snaps. Reason: %s" % e.message) ``` + +Dependencies: +Note that this module requires `opentelemetry-api`, which is already included into +your charm's virtual environment via `ops >= 2.21`. """ from __future__ import annotations @@ -85,6 +89,8 @@ TypeVar, ) +import opentelemetry.trace + if typing.TYPE_CHECKING: # avoid typing_extensions import at runtime from typing_extensions import NotRequired, ParamSpec, Required, Self, TypeAlias, Unpack @@ -93,6 +99,7 @@ _T = TypeVar("_T") logger = logging.getLogger(__name__) +tracer = opentelemetry.trace.get_tracer(__name__) # The unique Charmhub library identifier, never change it LIBID = "05394e5893f94f2d90feb7cbe6b633cd" @@ -102,7 +109,9 @@ # Increment this PATCH version before using `charmcraft publish-lib` or reset # to 0 if you are raising the major API version -LIBPATCH = 12 +LIBPATCH = 14 + +PYDEPS = ["opentelemetry-api"] # Regex to locate 7-bit C1 ANSI sequences @@ -140,6 +149,7 @@ class _SnapDict(TypedDict, total=True): name: str channel: str revision: str + version: str confinement: str apps: NotRequired[list[dict[str, JSONType]] | None] @@ -277,7 +287,9 @@ def _from_called_process_error(cls, msg: str, error: CalledProcessError) -> Self lines.extend(['Stderr:', error.stderr]) try: cmd = ['journalctl', '--unit', 'snapd', '--lines', '20'] - logs = subprocess.check_output(cmd, text=True) + with tracer.start_as_current_span(cmd[0]) as span: + span.set_attribute("argv", cmd) + logs = subprocess.check_output(cmd, text=True) except Exception as e: lines.extend(['Error fetching logs:', str(e)]) else: @@ -298,6 +310,7 @@ class Snap: - channel: "stable", "candidate", "beta", and "edge" are common - revision: a string representing the snap's revision - confinement: "classic", "strict", or "devmode" + - version: a string representing the snap's version, if set by the snap author """ def __init__( @@ -309,6 +322,8 @@ def __init__( confinement: str, apps: list[dict[str, JSONType]] | None = None, cohort: str | None = None, + *, + version: str | None = None, ) -> None: self._name = name self._state = state @@ -317,6 +332,7 @@ def __init__( self._confinement = confinement self._cohort = cohort or "" self._apps = apps or [] + self._version = version self._snap_client = SnapClient() def __eq__(self, other: object) -> bool: @@ -356,7 +372,9 @@ def _snap(self, command: str, optargs: Iterable[str] | None = None) -> str: optargs = optargs or [] args = ["snap", command, self._name, *optargs] try: - return subprocess.check_output(args, text=True, stderr=subprocess.PIPE) + with tracer.start_as_current_span(args[0]) as span: + span.set_attribute("argv", args) + return subprocess.check_output(args, text=True, stderr=subprocess.PIPE) except CalledProcessError as e: msg = f'Snap: {self._name!r} -- command {args!r} failed!' raise SnapError._from_called_process_error(msg=msg, error=e) from e @@ -384,7 +402,9 @@ def _snap_daemons( args = ["snap", *command, *services] try: - return subprocess.run(args, text=True, check=True, capture_output=True) + with tracer.start_as_current_span(args[0]) as span: + span.set_attribute("argv", args) + return subprocess.run(args, text=True, check=True, capture_output=True) except CalledProcessError as e: msg = f'Snap: {self._name!r} -- command {args!r} failed!' raise SnapError._from_called_process_error(msg=msg, error=e) from e @@ -491,7 +511,9 @@ def connect(self, plug: str, service: str | None = None, slot: str | None = None args = ["snap", *command] try: - subprocess.run(args, text=True, check=True, capture_output=True) + with tracer.start_as_current_span(args[0]) as span: + span.set_attribute("argv", args) + subprocess.run(args, text=True, check=True, capture_output=True) except CalledProcessError as e: msg = f'Snap: {self._name!r} -- command {args!r} failed!' raise SnapError._from_called_process_error(msg=msg, error=e) from e @@ -523,7 +545,9 @@ def alias(self, application: str, alias: str | None = None) -> None: alias = application args = ["snap", "alias", f"{self.name}.{application}", alias] try: - subprocess.run(args, text=True, check=True, capture_output=True) + with tracer.start_as_current_span(args[0]) as span: + span.set_attribute("argv", args) + subprocess.run(args, text=True, check=True, capture_output=True) except CalledProcessError as e: msg = f'Snap: {self._name!r} -- command {args!r} failed!' raise SnapError._from_called_process_error(msg=msg, error=e) from e @@ -764,6 +788,11 @@ def held(self) -> bool: info = self._snap("info") return "hold:" in info + @property + def version(self) -> str | None: + """Returns the version for a snap.""" + return self._version + class _UnixSocketConnection(http.client.HTTPConnection): """Implementation of HTTPConnection that connects to a named Unix socket.""" @@ -932,15 +961,20 @@ def _request_raw( def get_installed_snaps(self) -> list[dict[str, JSONType]]: """Get information about currently installed snaps.""" - return self._request("GET", "snaps") # type: ignore + with tracer.start_as_current_span("get_installed_snaps"): + return self._request("GET", "snaps") # type: ignore def get_snap_information(self, name: str) -> dict[str, JSONType]: """Query the snap server for information about single snap.""" - return self._request("GET", "find", {"name": name})[0] # type: ignore + with tracer.start_as_current_span("get_snap_information") as span: + span.set_attribute("name", name) + return self._request("GET", "find", {"name": name})[0] # type: ignore def get_installed_snap_apps(self, name: str) -> list[dict[str, JSONType]]: """Query the snap server for apps belonging to a named, currently installed snap.""" - return self._request("GET", "apps", {"names": name, "select": "service"}) # type: ignore + with tracer.start_as_current_span("get_installed_snap_apps") as span: + span.set_attribute("name", name) + return self._request("GET", "apps", {"names": name, "select": "service"}) # type: ignore def _put_snap_conf(self, name: str, conf: dict[str, JSONAble]) -> None: """Set the configuration details for an installed snap.""" @@ -1024,6 +1058,7 @@ def _load_installed_snaps(self) -> None: revision=i["revision"], confinement=i["confinement"], apps=i.get("apps"), + version=i.get("version"), ) self._snap_map[snap.name] = snap @@ -1043,6 +1078,7 @@ def _load_info(self, name: str) -> Snap: revision=info["revision"], confinement=info["confinement"], apps=None, + version=info.get("version"), ) @@ -1280,7 +1316,13 @@ def install_local( if dangerous: args.append("--dangerous") try: - result = subprocess.check_output(args, text=True, stderr=subprocess.PIPE).splitlines()[-1] + with tracer.start_as_current_span(args[0]) as span: + span.set_attribute("argv", args) + result = subprocess.check_output( + args, + text=True, + stderr=subprocess.PIPE, + ).splitlines()[-1] snap_name, _ = result.split(" ", 1) snap_name = ansi_filter.sub("", snap_name) @@ -1309,7 +1351,9 @@ def _system_set(config_item: str, value: str) -> None: """ args = ["snap", "set", "system", f"{config_item}={value}"] try: - subprocess.run(args, text=True, check=True, capture_output=True) + with tracer.start_as_current_span(args[0]) as span: + span.set_attribute("argv", args) + subprocess.run(args, text=True, check=True, capture_output=True) except CalledProcessError as e: msg = f"Failed setting system config '{config_item}' to '{value}'" raise SnapError._from_called_process_error(msg=msg, error=e) from e diff --git a/lib/charms/tempo_coordinator_k8s/v0/charm_tracing.py b/lib/charms/tempo_coordinator_k8s/v0/charm_tracing.py index 61fcf07716..f58ee72e0f 100644 --- a/lib/charms/tempo_coordinator_k8s/v0/charm_tracing.py +++ b/lib/charms/tempo_coordinator_k8s/v0/charm_tracing.py @@ -273,7 +273,9 @@ def _remove_stale_otel_sdk_packages(): if len(distributions_) <= 1: continue - otel_logger.debug(f"Package {name} has multiple ({len(distributions_)}) distributions.") + otel_logger.debug( + f"Package {name} has multiple ({len(distributions_)}) distributions." + ) for distribution in distributions_: if not distribution.files: # Not None or empty list path = distribution._path # type: ignore @@ -313,8 +315,8 @@ def _remove_stale_otel_sdk_packages(): import opentelemetry import ops -from opentelemetry.exporter.otlp.proto.common._internal.trace_encoder import ( # type: ignore - encode_spans # type: ignore +from opentelemetry.exporter.otlp.proto.common._internal.trace_encoder import ( # type: ignore + encode_spans, # type: ignore ) from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter # type: ignore from opentelemetry.sdk.resources import Resource @@ -348,7 +350,7 @@ def _remove_stale_otel_sdk_packages(): # Increment this PATCH version before using `charmcraft publish-lib` or reset # to 0 if you are raising the major API version -LIBPATCH = 9 +LIBPATCH = 10 PYDEPS = ["opentelemetry-exporter-otlp-proto-http==1.21.0"] @@ -394,10 +396,14 @@ class _Buffer: _SPANSEP = b"__CHARM_TRACING_BUFFER_SPAN_SEP__" - def __init__(self, db_file: Path, max_event_history_length: int, max_buffer_size_mib: int): + def __init__( + self, db_file: Path, max_event_history_length: int, max_buffer_size_mib: int + ): self._db_file = db_file self._max_event_history_length = max_event_history_length - self._max_buffer_size_mib = max(max_buffer_size_mib, _BUFFER_CACHE_FILE_SIZE_LIMIT_MiB_MIN) + self._max_buffer_size_mib = max( + max_buffer_size_mib, _BUFFER_CACHE_FILE_SIZE_LIMIT_MiB_MIN + ) # set by caller self.exporter: Optional[OTLPSpanExporter] = None @@ -535,7 +541,9 @@ def flush(self) -> Optional[bool]: ) errors = True except Exception: - logger.exception("unexpected error while flushing span batch from buffer") + logger.exception( + "unexpected error while flushing span batch from buffer" + ) errors = True if not errors: @@ -684,7 +692,9 @@ def _get_tracing_endpoint( f"got {tracing_endpoint} instead." ) - dev_logger.debug(f"Setting up span exporter to endpoint: {tracing_endpoint}/v1/traces") + dev_logger.debug( + f"Setting up span exporter to endpoint: {tracing_endpoint}/v1/traces" + ) return f"{tracing_endpoint}/v1/traces" @@ -765,7 +775,9 @@ def wrap_init(self: CharmBase, framework: Framework, *args, **kwargs): provider = TracerProvider(resource=resource) # if anything goes wrong with retrieving the endpoint, we let the exception bubble up. - tracing_endpoint = _get_tracing_endpoint(tracing_endpoint_attr, self, charm_type) + tracing_endpoint = _get_tracing_endpoint( + tracing_endpoint_attr, self, charm_type + ) buffer_only = False # whether we're only exporting to buffer, or also to the otlp exporter. @@ -776,10 +788,14 @@ def wrap_init(self: CharmBase, framework: Framework, *args, **kwargs): buffer_only = True server_cert: Optional[Union[str, Path]] = ( - _get_server_cert(server_cert_attr, self, charm_type) if server_cert_attr else None + _get_server_cert(server_cert_attr, self, charm_type) + if server_cert_attr + else None ) - if (tracing_endpoint and tracing_endpoint.startswith("https://")) and not server_cert: + if ( + tracing_endpoint and tracing_endpoint.startswith("https://") + ) and not server_cert: logger.error( "Tracing endpoint is https, but no server_cert has been passed." "Please point @trace_charm to a `server_cert` attr. " @@ -810,7 +826,9 @@ def wrap_init(self: CharmBase, framework: Framework, *args, **kwargs): # and retry the next time otlp_exporter = _OTLPSpanExporter( endpoint=tracing_endpoint, - certificate_file=str(Path(server_cert).absolute()) if server_cert else None, + certificate_file=str(Path(server_cert).absolute()) + if server_cert + else None, timeout=_OTLP_SPAN_EXPORTER_TIMEOUT, # give individual requests 1 second to succeed ) exporters.append(otlp_exporter) @@ -825,10 +843,16 @@ def wrap_init(self: CharmBase, framework: Framework, *args, **kwargs): _tracer = get_tracer(_service_name) # type: ignore _tracer_token = tracer.set(_tracer) - dispatch_path = os.getenv("JUJU_DISPATCH_PATH", "") # something like hooks/install - event_name = dispatch_path.split("/")[1] if "/" in dispatch_path else dispatch_path + dispatch_path = os.getenv( + "JUJU_DISPATCH_PATH", "" + ) # something like hooks/install + event_name = ( + dispatch_path.split("/")[1] if "/" in dispatch_path else dispatch_path + ) root_span_name = f"{unit_name}: {event_name} event" - span = _tracer.start_span(root_span_name, attributes={"juju.dispatch_path": dispatch_path}) + span = _tracer.start_span( + root_span_name, attributes={"juju.dispatch_path": dispatch_path} + ) # all these shenanigans are to work around the fact that the opentelemetry tracing API is built # on the assumption that spans will be used as contextmanagers. @@ -863,13 +887,17 @@ def wrap_close(): opentelemetry.context.detach(span_token) # type: ignore tracer.reset(_tracer_token) tp = cast(TracerProvider, get_tracer_provider()) - flush_successful = tp.force_flush(timeout_millis=1000) # don't block for too long + flush_successful = tp.force_flush( + timeout_millis=1000 + ) # don't block for too long if buffer_only: # if we're in buffer_only mode, it means we couldn't even set up the exporter for # tempo as we're missing some data. # so attempting to flush the buffer doesn't make sense - dev_logger.debug("tracing backend unavailable: all spans pushed to buffer") + dev_logger.debug( + "tracing backend unavailable: all spans pushed to buffer" + ) else: dev_logger.debug("tracing backend found: attempting to flush buffer...") @@ -885,7 +913,9 @@ def wrap_close(): if not previous_spans_buffered: # if the buffer was empty to begin with, any spans we collected now can be discarded buffer.drop() - dev_logger.debug("buffer dropped: this trace has been sent already") + dev_logger.debug( + "buffer dropped: this trace has been sent already" + ) else: # if the buffer was nonempty, we can attempt to flush it dev_logger.debug("attempting buffer flush...") From 784c2bb368c77561296c64a6aa38d98f2914e0a6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 2 Sep 2025 17:40:00 +0300 Subject: [PATCH 087/112] Update canonical/data-platform-workflows action to v35 (#1120) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/approve_renovate_pr.yaml | 2 +- .github/workflows/check_pr.yaml | 2 +- .github/workflows/ci.yaml | 4 ++-- .github/workflows/promote.yaml | 2 +- .github/workflows/release.yaml | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/approve_renovate_pr.yaml b/.github/workflows/approve_renovate_pr.yaml index 157d2bba6a..214ad51783 100644 --- a/.github/workflows/approve_renovate_pr.yaml +++ b/.github/workflows/approve_renovate_pr.yaml @@ -10,6 +10,6 @@ on: jobs: approve-pr: name: Approve Renovate pull request - uses: canonical/data-platform-workflows/.github/workflows/approve_renovate_pr.yaml@v32.2.3 + uses: canonical/data-platform-workflows/.github/workflows/approve_renovate_pr.yaml@v35.0.2 permissions: pull-requests: write # Needed to approve PR diff --git a/.github/workflows/check_pr.yaml b/.github/workflows/check_pr.yaml index 280c7c9bc0..4fd1ff1abb 100644 --- a/.github/workflows/check_pr.yaml +++ b/.github/workflows/check_pr.yaml @@ -16,4 +16,4 @@ on: jobs: check-pr: name: Check pull request - uses: canonical/data-platform-workflows/.github/workflows/check_charm_pr.yaml@v32.2.3 + uses: canonical/data-platform-workflows/.github/workflows/check_charm_pr.yaml@v35.0.2 diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 6933a29450..08cbb37f67 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -27,7 +27,7 @@ on: jobs: lint: name: Lint - uses: canonical/data-platform-workflows/.github/workflows/lint.yaml@v32.2.3 + uses: canonical/data-platform-workflows/.github/workflows/lint.yaml@v35.0.2 unit-test: name: Unit test charm @@ -49,7 +49,7 @@ jobs: build: name: Build charm - uses: canonical/data-platform-workflows/.github/workflows/build_charm.yaml@v32.2.3 + uses: canonical/data-platform-workflows/.github/workflows/build_charm.yaml@v35.0.2 integration-test: name: Integration test charm diff --git a/.github/workflows/promote.yaml b/.github/workflows/promote.yaml index b268d79844..3c86301b1b 100644 --- a/.github/workflows/promote.yaml +++ b/.github/workflows/promote.yaml @@ -25,7 +25,7 @@ on: jobs: promote: name: Promote charm - uses: canonical/data-platform-workflows/.github/workflows/_promote_charm.yaml@v32.2.3 + uses: canonical/data-platform-workflows/.github/workflows/_promote_charm.yaml@v35.0.2 with: track: '14' from-risk: ${{ inputs.from-risk }} diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 5d40966486..54938a3db3 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -27,7 +27,7 @@ jobs: name: Release charm needs: - ci-tests - uses: canonical/data-platform-workflows/.github/workflows/release_charm_edge.yaml@v32.2.3 + uses: canonical/data-platform-workflows/.github/workflows/release_charm_edge.yaml@v35.0.2 with: track: 14 artifact-prefix: ${{ needs.ci-tests.outputs.artifact-prefix }} From cca32a0032fadc0021a1836236f626eb40f37ef5 Mon Sep 17 00:00:00 2001 From: Marcelo Henrique Neppel Date: Tue, 2 Sep 2025 12:40:47 -0300 Subject: [PATCH 088/112] Enable ceph test on arm (#1129) Signed-off-by: Marcelo Henrique Neppel --- tests/integration/test_backups_ceph.py | 6 +++--- tests/spread/test_backups_ceph.py/task.yaml | 2 -- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/tests/integration/test_backups_ceph.py b/tests/integration/test_backups_ceph.py index 7583fe80c6..57f1d268af 100644 --- a/tests/integration/test_backups_ceph.py +++ b/tests/integration/test_backups_ceph.py @@ -14,7 +14,6 @@ import pytest from pytest_operator.plugin import OpsTest -from . import markers from .helpers import ( backup_operations, ) @@ -112,7 +111,9 @@ def microceph(): ) logger.info("Setting up microceph") - subprocess.run(["sudo", "snap", "install", "microceph", "--revision", "1169"], check=True) + subprocess.run( + ["sudo", "snap", "install", "microceph", "--channel", "squid/stable"], check=True + ) subprocess.run(["sudo", "microceph", "cluster", "bootstrap"], check=True) subprocess.run(["sudo", "microceph", "disk", "add", "loop,1G,3"], check=True) subprocess.run( @@ -190,7 +191,6 @@ def cloud_configs(microceph: ConnectionInformation): } -@markers.amd64_only async def test_backup_ceph(ops_test: OpsTest, cloud_configs, cloud_credentials, charm) -> None: """Build and deploy two units of PostgreSQL in microceph, test backup and restore actions.""" await backup_operations( diff --git a/tests/spread/test_backups_ceph.py/task.yaml b/tests/spread/test_backups_ceph.py/task.yaml index 8f6c8a387d..22336bfea3 100644 --- a/tests/spread/test_backups_ceph.py/task.yaml +++ b/tests/spread/test_backups_ceph.py/task.yaml @@ -5,5 +5,3 @@ execute: | tox run -e integration -- "tests/integration/$TEST_MODULE" --model testing --alluredir="$SPREAD_TASK/allure-results" artifacts: - allure-results -systems: - - -ubuntu-24.04-arm From b79efdb1c74c76b15ecf460cb7bafab91a23381d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 3 Sep 2025 00:24:34 +0300 Subject: [PATCH 089/112] Update dependency uv to v0.8.14 (#1130) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- charmcraft.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charmcraft.yaml b/charmcraft.yaml index 1ab6b176d0..3490a29ccf 100644 --- a/charmcraft.yaml +++ b/charmcraft.yaml @@ -27,7 +27,7 @@ parts: PIP_BREAK_SYSTEM_PACKAGES=true python3 -m pip install --user --upgrade pip==25.2 # renovate: charmcraft-pip-latest # Use uv to install poetry so that a newer version of Python can be installed if needed by poetry - curl --proto '=https' --tlsv1.2 -LsSf https://github.com/astral-sh/uv/releases/download/0.8.13/uv-installer.sh | sh # renovate: charmcraft-uv-latest + curl --proto '=https' --tlsv1.2 -LsSf https://github.com/astral-sh/uv/releases/download/0.8.14/uv-installer.sh | sh # renovate: charmcraft-uv-latest # poetry 2.0.0 requires Python >=3.9 if ! "$HOME/.local/bin/uv" python find '>=3.9' then From 66d33426d5e2690254c62e2548915537b63af370 Mon Sep 17 00:00:00 2001 From: Dragomir Penev <6687393+dragomirp@users.noreply.github.com> Date: Wed, 3 Sep 2025 00:59:23 +0300 Subject: [PATCH 090/112] Don't block if the snap cannot be installed (#1136) --- src/charm.py | 6 +----- tests/unit/test_charm.py | 16 ---------------- 2 files changed, 1 insertion(+), 21 deletions(-) diff --git a/src/charm.py b/src/charm.py index b9d2ff8aa2..e979ea81d7 100755 --- a/src/charm.py +++ b/src/charm.py @@ -1070,11 +1070,7 @@ def _on_install(self, event: InstallEvent) -> None: self.unit.status = MaintenanceStatus("installing PostgreSQL") # Install the charmed PostgreSQL snap. - try: - self._install_snap_packages(packages=SNAP_PACKAGES) - except snap.SnapError: - self.unit.status = BlockedStatus("failed to install snap packages") - return + self._install_snap_packages(packages=SNAP_PACKAGES) cache = snap.SnapCache() postgres_snap = cache[POSTGRESQL_SNAP_NAME] diff --git a/tests/unit/test_charm.py b/tests/unit/test_charm.py index 84b5d53569..9c8b9efc4d 100644 --- a/tests/unit/test_charm.py +++ b/tests/unit/test_charm.py @@ -134,22 +134,6 @@ def test_on_install_failed_to_create_home(harness): assert isinstance(harness.model.unit.status, WaitingStatus) -def test_on_install_snap_failure(harness): - with ( - patch("charm.PostgresqlOperatorCharm._install_snap_packages") as _install_snap_packages, - patch( - "charm.PostgresqlOperatorCharm._is_storage_attached", return_value=True - ) as _is_storage_attached, - ): - # Mock the result of the call. - _install_snap_packages.side_effect = snap.SnapError - # Trigger the hook. - harness.charm.on.install.emit() - # Assert that the needed calls were made. - _install_snap_packages.assert_called_once() - assert isinstance(harness.model.unit.status, BlockedStatus) - - def test_patroni_scrape_config_no_tls(harness): result = harness.charm.patroni_scrape_config() From cc1a6239cd77e84951438db0e51cbf68bc45f953 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 3 Sep 2025 04:14:28 +0300 Subject: [PATCH 091/112] Lock file maintenance Python dependencies (#1131) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- poetry.lock | 636 ++++++++++++++++++++++++------------------------- pyproject.toml | 6 +- 2 files changed, 321 insertions(+), 321 deletions(-) diff --git a/poetry.lock b/poetry.lock index 0109e2e6e8..cb5a966c59 100644 --- a/poetry.lock +++ b/poetry.lock @@ -233,18 +233,18 @@ typecheck = ["mypy"] [[package]] name = "boto3" -version = "1.40.17" +version = "1.40.21" description = "The AWS SDK for Python" optional = false python-versions = ">=3.9" groups = ["main", "integration"] files = [ - {file = "boto3-1.40.17-py3-none-any.whl", hash = "sha256:2cacecd689cb51d81fbf54f84b64d0e6e922fbc18ee513c568b9f61caf4221e0"}, - {file = "boto3-1.40.17.tar.gz", hash = "sha256:e115dc87d5975d32dfa0ebaf19c39e360665317a350004fa94b03200fe853f2e"}, + {file = "boto3-1.40.21-py3-none-any.whl", hash = "sha256:3772fb828864d3b7046c8bdf2f4860aaca4a79f25b7b060206c6a5f4944ea7f9"}, + {file = "boto3-1.40.21.tar.gz", hash = "sha256:876ccc0b25517b992bd27976282510773a11ebc771aa5b836a238ea426c82187"}, ] [package.dependencies] -botocore = ">=1.40.17,<1.41.0" +botocore = ">=1.40.21,<1.41.0" jmespath = ">=0.7.1,<2.0.0" s3transfer = ">=0.13.0,<0.14.0" @@ -253,14 +253,14 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.40.17" +version = "1.40.21" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">=3.9" groups = ["main", "integration"] files = [ - {file = "botocore-1.40.17-py3-none-any.whl", hash = "sha256:603951935c1a741ae70236bf15725c5293074f28503e7029ad0e24ece476a342"}, - {file = "botocore-1.40.17.tar.gz", hash = "sha256:769cd04a6a612f2d48b5f456c676fd81733fab682870952f7e2887260ea6a2bc"}, + {file = "botocore-1.40.21-py3-none-any.whl", hash = "sha256:574ecf9b68c1721650024a27e00e0080b6f141c281ebfce49e0d302969270ef4"}, + {file = "botocore-1.40.21.tar.gz", hash = "sha256:f77e9c199df0252b14ea739a9ac99723940f6bde90f4c2e7802701553a62827b"}, ] [package.dependencies] @@ -517,100 +517,100 @@ typing-extensions = "*" [[package]] name = "coverage" -version = "7.10.5" +version = "7.10.6" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.9" groups = ["unit"] files = [ - {file = "coverage-7.10.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c6a5c3414bfc7451b879141ce772c546985163cf553f08e0f135f0699a911801"}, - {file = "coverage-7.10.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:bc8e4d99ce82f1710cc3c125adc30fd1487d3cf6c2cd4994d78d68a47b16989a"}, - {file = "coverage-7.10.5-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:02252dc1216e512a9311f596b3169fad54abcb13827a8d76d5630c798a50a754"}, - {file = "coverage-7.10.5-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:73269df37883e02d460bee0cc16be90509faea1e3bd105d77360b512d5bb9c33"}, - {file = "coverage-7.10.5-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1f8a81b0614642f91c9effd53eec284f965577591f51f547a1cbeb32035b4c2f"}, - {file = "coverage-7.10.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6a29f8e0adb7f8c2b95fa2d4566a1d6e6722e0a637634c6563cb1ab844427dd9"}, - {file = "coverage-7.10.5-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fcf6ab569436b4a647d4e91accba12509ad9f2554bc93d3aee23cc596e7f99c3"}, - {file = "coverage-7.10.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:90dc3d6fb222b194a5de60af8d190bedeeddcbc7add317e4a3cd333ee6b7c879"}, - {file = "coverage-7.10.5-cp310-cp310-win32.whl", hash = "sha256:414a568cd545f9dc75f0686a0049393de8098414b58ea071e03395505b73d7a8"}, - {file = "coverage-7.10.5-cp310-cp310-win_amd64.whl", hash = "sha256:e551f9d03347196271935fd3c0c165f0e8c049220280c1120de0084d65e9c7ff"}, - {file = "coverage-7.10.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c177e6ffe2ebc7c410785307758ee21258aa8e8092b44d09a2da767834f075f2"}, - {file = "coverage-7.10.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:14d6071c51ad0f703d6440827eaa46386169b5fdced42631d5a5ac419616046f"}, - {file = "coverage-7.10.5-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:61f78c7c3bc272a410c5ae3fde7792b4ffb4acc03d35a7df73ca8978826bb7ab"}, - {file = "coverage-7.10.5-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f39071caa126f69d63f99b324fb08c7b1da2ec28cbb1fe7b5b1799926492f65c"}, - {file = "coverage-7.10.5-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:343a023193f04d46edc46b2616cdbee68c94dd10208ecd3adc56fcc54ef2baa1"}, - {file = "coverage-7.10.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:585ffe93ae5894d1ebdee69fc0b0d4b7c75d8007983692fb300ac98eed146f78"}, - {file = "coverage-7.10.5-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:b0ef4e66f006ed181df29b59921bd8fc7ed7cd6a9289295cd8b2824b49b570df"}, - {file = "coverage-7.10.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:eb7b0bbf7cc1d0453b843eca7b5fa017874735bef9bfdfa4121373d2cc885ed6"}, - {file = "coverage-7.10.5-cp311-cp311-win32.whl", hash = "sha256:1d043a8a06987cc0c98516e57c4d3fc2c1591364831e9deb59c9e1b4937e8caf"}, - {file = "coverage-7.10.5-cp311-cp311-win_amd64.whl", hash = "sha256:fefafcca09c3ac56372ef64a40f5fe17c5592fab906e0fdffd09543f3012ba50"}, - {file = "coverage-7.10.5-cp311-cp311-win_arm64.whl", hash = "sha256:7e78b767da8b5fc5b2faa69bb001edafcd6f3995b42a331c53ef9572c55ceb82"}, - {file = "coverage-7.10.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c2d05c7e73c60a4cecc7d9b60dbfd603b4ebc0adafaef371445b47d0f805c8a9"}, - {file = "coverage-7.10.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:32ddaa3b2c509778ed5373b177eb2bf5662405493baeff52278a0b4f9415188b"}, - {file = "coverage-7.10.5-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:dd382410039fe062097aa0292ab6335a3f1e7af7bba2ef8d27dcda484918f20c"}, - {file = "coverage-7.10.5-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7fa22800f3908df31cea6fb230f20ac49e343515d968cc3a42b30d5c3ebf9b5a"}, - {file = "coverage-7.10.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f366a57ac81f5e12797136552f5b7502fa053c861a009b91b80ed51f2ce651c6"}, - {file = "coverage-7.10.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5f1dc8f1980a272ad4a6c84cba7981792344dad33bf5869361576b7aef42733a"}, - {file = "coverage-7.10.5-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:2285c04ee8676f7938b02b4936d9b9b672064daab3187c20f73a55f3d70e6b4a"}, - {file = "coverage-7.10.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c2492e4dd9daab63f5f56286f8a04c51323d237631eb98505d87e4c4ff19ec34"}, - {file = "coverage-7.10.5-cp312-cp312-win32.whl", hash = "sha256:38a9109c4ee8135d5df5505384fc2f20287a47ccbe0b3f04c53c9a1989c2bbaf"}, - {file = "coverage-7.10.5-cp312-cp312-win_amd64.whl", hash = "sha256:6b87f1ad60b30bc3c43c66afa7db6b22a3109902e28c5094957626a0143a001f"}, - {file = "coverage-7.10.5-cp312-cp312-win_arm64.whl", hash = "sha256:672a6c1da5aea6c629819a0e1461e89d244f78d7b60c424ecf4f1f2556c041d8"}, - {file = "coverage-7.10.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ef3b83594d933020f54cf65ea1f4405d1f4e41a009c46df629dd964fcb6e907c"}, - {file = "coverage-7.10.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2b96bfdf7c0ea9faebce088a3ecb2382819da4fbc05c7b80040dbc428df6af44"}, - {file = "coverage-7.10.5-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:63df1fdaffa42d914d5c4d293e838937638bf75c794cf20bee12978fc8c4e3bc"}, - {file = "coverage-7.10.5-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8002dc6a049aac0e81ecec97abfb08c01ef0c1fbf962d0c98da3950ace89b869"}, - {file = "coverage-7.10.5-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:63d4bb2966d6f5f705a6b0c6784c8969c468dbc4bcf9d9ded8bff1c7e092451f"}, - {file = "coverage-7.10.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1f672efc0731a6846b157389b6e6d5d5e9e59d1d1a23a5c66a99fd58339914d5"}, - {file = "coverage-7.10.5-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:3f39cef43d08049e8afc1fde4a5da8510fc6be843f8dea350ee46e2a26b2f54c"}, - {file = "coverage-7.10.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2968647e3ed5a6c019a419264386b013979ff1fb67dd11f5c9886c43d6a31fc2"}, - {file = "coverage-7.10.5-cp313-cp313-win32.whl", hash = "sha256:0d511dda38595b2b6934c2b730a1fd57a3635c6aa2a04cb74714cdfdd53846f4"}, - {file = "coverage-7.10.5-cp313-cp313-win_amd64.whl", hash = "sha256:9a86281794a393513cf117177fd39c796b3f8e3759bb2764259a2abba5cce54b"}, - {file = "coverage-7.10.5-cp313-cp313-win_arm64.whl", hash = "sha256:cebd8e906eb98bb09c10d1feed16096700b1198d482267f8bf0474e63a7b8d84"}, - {file = "coverage-7.10.5-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0520dff502da5e09d0d20781df74d8189ab334a1e40d5bafe2efaa4158e2d9e7"}, - {file = "coverage-7.10.5-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:d9cd64aca68f503ed3f1f18c7c9174cbb797baba02ca8ab5112f9d1c0328cd4b"}, - {file = "coverage-7.10.5-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:0913dd1613a33b13c4f84aa6e3f4198c1a21ee28ccb4f674985c1f22109f0aae"}, - {file = "coverage-7.10.5-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:1b7181c0feeb06ed8a02da02792f42f829a7b29990fef52eff257fef0885d760"}, - {file = "coverage-7.10.5-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:36d42b7396b605f774d4372dd9c49bed71cbabce4ae1ccd074d155709dd8f235"}, - {file = "coverage-7.10.5-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b4fdc777e05c4940b297bf47bf7eedd56a39a61dc23ba798e4b830d585486ca5"}, - {file = "coverage-7.10.5-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:42144e8e346de44a6f1dbd0a56575dd8ab8dfa7e9007da02ea5b1c30ab33a7db"}, - {file = "coverage-7.10.5-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:66c644cbd7aed8fe266d5917e2c9f65458a51cfe5eeff9c05f15b335f697066e"}, - {file = "coverage-7.10.5-cp313-cp313t-win32.whl", hash = "sha256:2d1b73023854068c44b0c554578a4e1ef1b050ed07cf8b431549e624a29a66ee"}, - {file = "coverage-7.10.5-cp313-cp313t-win_amd64.whl", hash = "sha256:54a1532c8a642d8cc0bd5a9a51f5a9dcc440294fd06e9dda55e743c5ec1a8f14"}, - {file = "coverage-7.10.5-cp313-cp313t-win_arm64.whl", hash = "sha256:74d5b63fe3f5f5d372253a4ef92492c11a4305f3550631beaa432fc9df16fcff"}, - {file = "coverage-7.10.5-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:68c5e0bc5f44f68053369fa0d94459c84548a77660a5f2561c5e5f1e3bed7031"}, - {file = "coverage-7.10.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:cf33134ffae93865e32e1e37df043bef15a5e857d8caebc0099d225c579b0fa3"}, - {file = "coverage-7.10.5-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:ad8fa9d5193bafcf668231294241302b5e683a0518bf1e33a9a0dfb142ec3031"}, - {file = "coverage-7.10.5-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:146fa1531973d38ab4b689bc764592fe6c2f913e7e80a39e7eeafd11f0ef6db2"}, - {file = "coverage-7.10.5-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6013a37b8a4854c478d3219ee8bc2392dea51602dd0803a12d6f6182a0061762"}, - {file = "coverage-7.10.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:eb90fe20db9c3d930fa2ad7a308207ab5b86bf6a76f54ab6a40be4012d88fcae"}, - {file = "coverage-7.10.5-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:384b34482272e960c438703cafe63316dfbea124ac62006a455c8410bf2a2262"}, - {file = "coverage-7.10.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:467dc74bd0a1a7de2bedf8deaf6811f43602cb532bd34d81ffd6038d6d8abe99"}, - {file = "coverage-7.10.5-cp314-cp314-win32.whl", hash = "sha256:556d23d4e6393ca898b2e63a5bca91e9ac2d5fb13299ec286cd69a09a7187fde"}, - {file = "coverage-7.10.5-cp314-cp314-win_amd64.whl", hash = "sha256:f4446a9547681533c8fa3e3c6cf62121eeee616e6a92bd9201c6edd91beffe13"}, - {file = "coverage-7.10.5-cp314-cp314-win_arm64.whl", hash = "sha256:5e78bd9cf65da4c303bf663de0d73bf69f81e878bf72a94e9af67137c69b9fe9"}, - {file = "coverage-7.10.5-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:5661bf987d91ec756a47c7e5df4fbcb949f39e32f9334ccd3f43233bbb65e508"}, - {file = "coverage-7.10.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a46473129244db42a720439a26984f8c6f834762fc4573616c1f37f13994b357"}, - {file = "coverage-7.10.5-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1f64b8d3415d60f24b058b58d859e9512624bdfa57a2d1f8aff93c1ec45c429b"}, - {file = "coverage-7.10.5-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:44d43de99a9d90b20e0163f9770542357f58860a26e24dc1d924643bd6aa7cb4"}, - {file = "coverage-7.10.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a931a87e5ddb6b6404e65443b742cb1c14959622777f2a4efd81fba84f5d91ba"}, - {file = "coverage-7.10.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:f9559b906a100029274448f4c8b8b0a127daa4dade5661dfd821b8c188058842"}, - {file = "coverage-7.10.5-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:b08801e25e3b4526ef9ced1aa29344131a8f5213c60c03c18fe4c6170ffa2874"}, - {file = "coverage-7.10.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ed9749bb8eda35f8b636fb7632f1c62f735a236a5d4edadd8bbcc5ea0542e732"}, - {file = "coverage-7.10.5-cp314-cp314t-win32.whl", hash = "sha256:609b60d123fc2cc63ccee6d17e4676699075db72d14ac3c107cc4976d516f2df"}, - {file = "coverage-7.10.5-cp314-cp314t-win_amd64.whl", hash = "sha256:0666cf3d2c1626b5a3463fd5b05f5e21f99e6aec40a3192eee4d07a15970b07f"}, - {file = "coverage-7.10.5-cp314-cp314t-win_arm64.whl", hash = "sha256:bc85eb2d35e760120540afddd3044a5bf69118a91a296a8b3940dfc4fdcfe1e2"}, - {file = "coverage-7.10.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:62835c1b00c4a4ace24c1a88561a5a59b612fbb83a525d1c70ff5720c97c0610"}, - {file = "coverage-7.10.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5255b3bbcc1d32a4069d6403820ac8e6dbcc1d68cb28a60a1ebf17e47028e898"}, - {file = "coverage-7.10.5-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3876385722e335d6e991c430302c24251ef9c2a9701b2b390f5473199b1b8ebf"}, - {file = "coverage-7.10.5-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8048ce4b149c93447a55d279078c8ae98b08a6951a3c4d2d7e87f4efc7bfe100"}, - {file = "coverage-7.10.5-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4028e7558e268dd8bcf4d9484aad393cafa654c24b4885f6f9474bf53183a82a"}, - {file = "coverage-7.10.5-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:03f47dc870eec0367fcdd603ca6a01517d2504e83dc18dbfafae37faec66129a"}, - {file = "coverage-7.10.5-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:2d488d7d42b6ded7ea0704884f89dcabd2619505457de8fc9a6011c62106f6e5"}, - {file = "coverage-7.10.5-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b3dcf2ead47fa8be14224ee817dfc1df98043af568fe120a22f81c0eb3c34ad2"}, - {file = "coverage-7.10.5-cp39-cp39-win32.whl", hash = "sha256:02650a11324b80057b8c9c29487020073d5e98a498f1857f37e3f9b6ea1b2426"}, - {file = "coverage-7.10.5-cp39-cp39-win_amd64.whl", hash = "sha256:b45264dd450a10f9e03237b41a9a24e85cbb1e278e5a32adb1a303f58f0017f3"}, - {file = "coverage-7.10.5-py3-none-any.whl", hash = "sha256:0be24d35e4db1d23d0db5c0f6a74a962e2ec83c426b5cac09f4234aadef38e4a"}, - {file = "coverage-7.10.5.tar.gz", hash = "sha256:f2e57716a78bc3ae80b2207be0709a3b2b63b9f2dcf9740ee6ac03588a2015b6"}, + {file = "coverage-7.10.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:70e7bfbd57126b5554aa482691145f798d7df77489a177a6bef80de78860a356"}, + {file = "coverage-7.10.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e41be6f0f19da64af13403e52f2dec38bbc2937af54df8ecef10850ff8d35301"}, + {file = "coverage-7.10.6-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:c61fc91ab80b23f5fddbee342d19662f3d3328173229caded831aa0bd7595460"}, + {file = "coverage-7.10.6-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:10356fdd33a7cc06e8051413140bbdc6f972137508a3572e3f59f805cd2832fd"}, + {file = "coverage-7.10.6-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:80b1695cf7c5ebe7b44bf2521221b9bb8cdf69b1f24231149a7e3eb1ae5fa2fb"}, + {file = "coverage-7.10.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:2e4c33e6378b9d52d3454bd08847a8651f4ed23ddbb4a0520227bd346382bbc6"}, + {file = "coverage-7.10.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:c8a3ec16e34ef980a46f60dc6ad86ec60f763c3f2fa0db6d261e6e754f72e945"}, + {file = "coverage-7.10.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7d79dabc0a56f5af990cc6da9ad1e40766e82773c075f09cc571e2076fef882e"}, + {file = "coverage-7.10.6-cp310-cp310-win32.whl", hash = "sha256:86b9b59f2b16e981906e9d6383eb6446d5b46c278460ae2c36487667717eccf1"}, + {file = "coverage-7.10.6-cp310-cp310-win_amd64.whl", hash = "sha256:e132b9152749bd33534e5bd8565c7576f135f157b4029b975e15ee184325f528"}, + {file = "coverage-7.10.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c706db3cabb7ceef779de68270150665e710b46d56372455cd741184f3868d8f"}, + {file = "coverage-7.10.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8e0c38dc289e0508ef68ec95834cb5d2e96fdbe792eaccaa1bccac3966bbadcc"}, + {file = "coverage-7.10.6-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:752a3005a1ded28f2f3a6e8787e24f28d6abe176ca64677bcd8d53d6fe2ec08a"}, + {file = "coverage-7.10.6-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:689920ecfd60f992cafca4f5477d55720466ad2c7fa29bb56ac8d44a1ac2b47a"}, + {file = "coverage-7.10.6-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ec98435796d2624d6905820a42f82149ee9fc4f2d45c2c5bc5a44481cc50db62"}, + {file = "coverage-7.10.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b37201ce4a458c7a758ecc4efa92fa8ed783c66e0fa3c42ae19fc454a0792153"}, + {file = "coverage-7.10.6-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:2904271c80898663c810a6b067920a61dd8d38341244a3605bd31ab55250dad5"}, + {file = "coverage-7.10.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5aea98383463d6e1fa4e95416d8de66f2d0cb588774ee20ae1b28df826bcb619"}, + {file = "coverage-7.10.6-cp311-cp311-win32.whl", hash = "sha256:e3fb1fa01d3598002777dd259c0c2e6d9d5e10e7222976fc8e03992f972a2cba"}, + {file = "coverage-7.10.6-cp311-cp311-win_amd64.whl", hash = "sha256:f35ed9d945bece26553d5b4c8630453169672bea0050a564456eb88bdffd927e"}, + {file = "coverage-7.10.6-cp311-cp311-win_arm64.whl", hash = "sha256:99e1a305c7765631d74b98bf7dbf54eeea931f975e80f115437d23848ee8c27c"}, + {file = "coverage-7.10.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5b2dd6059938063a2c9fee1af729d4f2af28fd1a545e9b7652861f0d752ebcea"}, + {file = "coverage-7.10.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:388d80e56191bf846c485c14ae2bc8898aa3124d9d35903fef7d907780477634"}, + {file = "coverage-7.10.6-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:90cb5b1a4670662719591aa92d0095bb41714970c0b065b02a2610172dbf0af6"}, + {file = "coverage-7.10.6-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:961834e2f2b863a0e14260a9a273aff07ff7818ab6e66d2addf5628590c628f9"}, + {file = "coverage-7.10.6-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf9a19f5012dab774628491659646335b1928cfc931bf8d97b0d5918dd58033c"}, + {file = "coverage-7.10.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:99c4283e2a0e147b9c9cc6bc9c96124de9419d6044837e9799763a0e29a7321a"}, + {file = "coverage-7.10.6-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:282b1b20f45df57cc508c1e033403f02283adfb67d4c9c35a90281d81e5c52c5"}, + {file = "coverage-7.10.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8cdbe264f11afd69841bd8c0d83ca10b5b32853263ee62e6ac6a0ab63895f972"}, + {file = "coverage-7.10.6-cp312-cp312-win32.whl", hash = "sha256:a517feaf3a0a3eca1ee985d8373135cfdedfbba3882a5eab4362bda7c7cf518d"}, + {file = "coverage-7.10.6-cp312-cp312-win_amd64.whl", hash = "sha256:856986eadf41f52b214176d894a7de05331117f6035a28ac0016c0f63d887629"}, + {file = "coverage-7.10.6-cp312-cp312-win_arm64.whl", hash = "sha256:acf36b8268785aad739443fa2780c16260ee3fa09d12b3a70f772ef100939d80"}, + {file = "coverage-7.10.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ffea0575345e9ee0144dfe5701aa17f3ba546f8c3bb48db62ae101afb740e7d6"}, + {file = "coverage-7.10.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:95d91d7317cde40a1c249d6b7382750b7e6d86fad9d8eaf4fa3f8f44cf171e80"}, + {file = "coverage-7.10.6-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3e23dd5408fe71a356b41baa82892772a4cefcf758f2ca3383d2aa39e1b7a003"}, + {file = "coverage-7.10.6-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0f3f56e4cb573755e96a16501a98bf211f100463d70275759e73f3cbc00d4f27"}, + {file = "coverage-7.10.6-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:db4a1d897bbbe7339946ffa2fe60c10cc81c43fab8b062d3fcb84188688174a4"}, + {file = "coverage-7.10.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d8fd7879082953c156d5b13c74aa6cca37f6a6f4747b39538504c3f9c63d043d"}, + {file = "coverage-7.10.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:28395ca3f71cd103b8c116333fa9db867f3a3e1ad6a084aa3725ae002b6583bc"}, + {file = "coverage-7.10.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:61c950fc33d29c91b9e18540e1aed7d9f6787cc870a3e4032493bbbe641d12fc"}, + {file = "coverage-7.10.6-cp313-cp313-win32.whl", hash = "sha256:160c00a5e6b6bdf4e5984b0ef21fc860bc94416c41b7df4d63f536d17c38902e"}, + {file = "coverage-7.10.6-cp313-cp313-win_amd64.whl", hash = "sha256:628055297f3e2aa181464c3808402887643405573eb3d9de060d81531fa79d32"}, + {file = "coverage-7.10.6-cp313-cp313-win_arm64.whl", hash = "sha256:df4ec1f8540b0bcbe26ca7dd0f541847cc8a108b35596f9f91f59f0c060bfdd2"}, + {file = "coverage-7.10.6-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:c9a8b7a34a4de3ed987f636f71881cd3b8339f61118b1aa311fbda12741bff0b"}, + {file = "coverage-7.10.6-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:8dd5af36092430c2b075cee966719898f2ae87b636cefb85a653f1d0ba5d5393"}, + {file = "coverage-7.10.6-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:b0353b0f0850d49ada66fdd7d0c7cdb0f86b900bb9e367024fd14a60cecc1e27"}, + {file = "coverage-7.10.6-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:d6b9ae13d5d3e8aeca9ca94198aa7b3ebbc5acfada557d724f2a1f03d2c0b0df"}, + {file = "coverage-7.10.6-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:675824a363cc05781b1527b39dc2587b8984965834a748177ee3c37b64ffeafb"}, + {file = "coverage-7.10.6-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:692d70ea725f471a547c305f0d0fc6a73480c62fb0da726370c088ab21aed282"}, + {file = "coverage-7.10.6-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:851430a9a361c7a8484a36126d1d0ff8d529d97385eacc8dfdc9bfc8c2d2cbe4"}, + {file = "coverage-7.10.6-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:d9369a23186d189b2fc95cc08b8160ba242057e887d766864f7adf3c46b2df21"}, + {file = "coverage-7.10.6-cp313-cp313t-win32.whl", hash = "sha256:92be86fcb125e9bda0da7806afd29a3fd33fdf58fba5d60318399adf40bf37d0"}, + {file = "coverage-7.10.6-cp313-cp313t-win_amd64.whl", hash = "sha256:6b3039e2ca459a70c79523d39347d83b73f2f06af5624905eba7ec34d64d80b5"}, + {file = "coverage-7.10.6-cp313-cp313t-win_arm64.whl", hash = "sha256:3fb99d0786fe17b228eab663d16bee2288e8724d26a199c29325aac4b0319b9b"}, + {file = "coverage-7.10.6-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:6008a021907be8c4c02f37cdc3ffb258493bdebfeaf9a839f9e71dfdc47b018e"}, + {file = "coverage-7.10.6-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:5e75e37f23eb144e78940b40395b42f2321951206a4f50e23cfd6e8a198d3ceb"}, + {file = "coverage-7.10.6-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:0f7cb359a448e043c576f0da00aa8bfd796a01b06aa610ca453d4dde09cc1034"}, + {file = "coverage-7.10.6-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c68018e4fc4e14b5668f1353b41ccf4bc83ba355f0e1b3836861c6f042d89ac1"}, + {file = "coverage-7.10.6-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cd4b2b0707fc55afa160cd5fc33b27ccbf75ca11d81f4ec9863d5793fc6df56a"}, + {file = "coverage-7.10.6-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:4cec13817a651f8804a86e4f79d815b3b28472c910e099e4d5a0e8a3b6a1d4cb"}, + {file = "coverage-7.10.6-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:f2a6a8e06bbda06f78739f40bfb56c45d14eb8249d0f0ea6d4b3d48e1f7c695d"}, + {file = "coverage-7.10.6-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:081b98395ced0d9bcf60ada7661a0b75f36b78b9d7e39ea0790bb4ed8da14747"}, + {file = "coverage-7.10.6-cp314-cp314-win32.whl", hash = "sha256:6937347c5d7d069ee776b2bf4e1212f912a9f1f141a429c475e6089462fcecc5"}, + {file = "coverage-7.10.6-cp314-cp314-win_amd64.whl", hash = "sha256:adec1d980fa07e60b6ef865f9e5410ba760e4e1d26f60f7e5772c73b9a5b0713"}, + {file = "coverage-7.10.6-cp314-cp314-win_arm64.whl", hash = "sha256:a80f7aef9535442bdcf562e5a0d5a5538ce8abe6bb209cfbf170c462ac2c2a32"}, + {file = "coverage-7.10.6-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:0de434f4fbbe5af4fa7989521c655c8c779afb61c53ab561b64dcee6149e4c65"}, + {file = "coverage-7.10.6-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6e31b8155150c57e5ac43ccd289d079eb3f825187d7c66e755a055d2c85794c6"}, + {file = "coverage-7.10.6-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:98cede73eb83c31e2118ae8d379c12e3e42736903a8afcca92a7218e1f2903b0"}, + {file = "coverage-7.10.6-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f863c08f4ff6b64fa8045b1e3da480f5374779ef187f07b82e0538c68cb4ff8e"}, + {file = "coverage-7.10.6-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2b38261034fda87be356f2c3f42221fdb4171c3ce7658066ae449241485390d5"}, + {file = "coverage-7.10.6-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:0e93b1476b79eae849dc3872faeb0bf7948fd9ea34869590bc16a2a00b9c82a7"}, + {file = "coverage-7.10.6-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:ff8a991f70f4c0cf53088abf1e3886edcc87d53004c7bb94e78650b4d3dac3b5"}, + {file = "coverage-7.10.6-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ac765b026c9f33044419cbba1da913cfb82cca1b60598ac1c7a5ed6aac4621a0"}, + {file = "coverage-7.10.6-cp314-cp314t-win32.whl", hash = "sha256:441c357d55f4936875636ef2cfb3bee36e466dcf50df9afbd398ce79dba1ebb7"}, + {file = "coverage-7.10.6-cp314-cp314t-win_amd64.whl", hash = "sha256:073711de3181b2e204e4870ac83a7c4853115b42e9cd4d145f2231e12d670930"}, + {file = "coverage-7.10.6-cp314-cp314t-win_arm64.whl", hash = "sha256:137921f2bac5559334ba66122b753db6dc5d1cf01eb7b64eb412bb0d064ef35b"}, + {file = "coverage-7.10.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:90558c35af64971d65fbd935c32010f9a2f52776103a259f1dee865fe8259352"}, + {file = "coverage-7.10.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8953746d371e5695405806c46d705a3cd170b9cc2b9f93953ad838f6c1e58612"}, + {file = "coverage-7.10.6-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:c83f6afb480eae0313114297d29d7c295670a41c11b274e6bca0c64540c1ce7b"}, + {file = "coverage-7.10.6-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7eb68d356ba0cc158ca535ce1381dbf2037fa8cb5b1ae5ddfc302e7317d04144"}, + {file = "coverage-7.10.6-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5b15a87265e96307482746d86995f4bff282f14b027db75469c446da6127433b"}, + {file = "coverage-7.10.6-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:fc53ba868875bfbb66ee447d64d6413c2db91fddcfca57025a0e7ab5b07d5862"}, + {file = "coverage-7.10.6-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:efeda443000aa23f276f4df973cb82beca682fd800bb119d19e80504ffe53ec2"}, + {file = "coverage-7.10.6-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:9702b59d582ff1e184945d8b501ffdd08d2cee38d93a2206aa5f1365ce0b8d78"}, + {file = "coverage-7.10.6-cp39-cp39-win32.whl", hash = "sha256:2195f8e16ba1a44651ca684db2ea2b2d4b5345da12f07d9c22a395202a05b23c"}, + {file = "coverage-7.10.6-cp39-cp39-win_amd64.whl", hash = "sha256:f32ff80e7ef6a5b5b606ea69a36e97b219cd9dc799bcf2963018a4d8f788cfbf"}, + {file = "coverage-7.10.6-py3-none-any.whl", hash = "sha256:92c4ecf6bf11b2e85fd4d8204814dc26e6a19f0c9d938c207c5cb0eadfcabbe3"}, + {file = "coverage-7.10.6.tar.gz", hash = "sha256:f644a3ae5933a552a29dbb9aa2f90c677a875f80ebea028e5a52a4f429044b90"}, ] [package.dependencies] @@ -621,49 +621,49 @@ toml = ["tomli ; python_full_version <= \"3.11.0a6\""] [[package]] name = "cryptography" -version = "45.0.6" +version = "45.0.7" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false python-versions = "!=3.9.0,!=3.9.1,>=3.7" groups = ["charm-libs", "integration"] files = [ - {file = "cryptography-45.0.6-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:048e7ad9e08cf4c0ab07ff7f36cc3115924e22e2266e034450a890d9e312dd74"}, - {file = "cryptography-45.0.6-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:44647c5d796f5fc042bbc6d61307d04bf29bccb74d188f18051b635f20a9c75f"}, - {file = "cryptography-45.0.6-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e40b80ecf35ec265c452eea0ba94c9587ca763e739b8e559c128d23bff7ebbbf"}, - {file = "cryptography-45.0.6-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:00e8724bdad672d75e6f069b27970883179bd472cd24a63f6e620ca7e41cc0c5"}, - {file = "cryptography-45.0.6-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7a3085d1b319d35296176af31c90338eeb2ddac8104661df79f80e1d9787b8b2"}, - {file = "cryptography-45.0.6-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:1b7fa6a1c1188c7ee32e47590d16a5a0646270921f8020efc9a511648e1b2e08"}, - {file = "cryptography-45.0.6-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:275ba5cc0d9e320cd70f8e7b96d9e59903c815ca579ab96c1e37278d231fc402"}, - {file = "cryptography-45.0.6-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:f4028f29a9f38a2025abedb2e409973709c660d44319c61762202206ed577c42"}, - {file = "cryptography-45.0.6-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ee411a1b977f40bd075392c80c10b58025ee5c6b47a822a33c1198598a7a5f05"}, - {file = "cryptography-45.0.6-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:e2a21a8eda2d86bb604934b6b37691585bd095c1f788530c1fcefc53a82b3453"}, - {file = "cryptography-45.0.6-cp311-abi3-win32.whl", hash = "sha256:d063341378d7ee9c91f9d23b431a3502fc8bfacd54ef0a27baa72a0843b29159"}, - {file = "cryptography-45.0.6-cp311-abi3-win_amd64.whl", hash = "sha256:833dc32dfc1e39b7376a87b9a6a4288a10aae234631268486558920029b086ec"}, - {file = "cryptography-45.0.6-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:3436128a60a5e5490603ab2adbabc8763613f638513ffa7d311c900a8349a2a0"}, - {file = "cryptography-45.0.6-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0d9ef57b6768d9fa58e92f4947cea96ade1233c0e236db22ba44748ffedca394"}, - {file = "cryptography-45.0.6-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ea3c42f2016a5bbf71825537c2ad753f2870191134933196bee408aac397b3d9"}, - {file = "cryptography-45.0.6-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:20ae4906a13716139d6d762ceb3e0e7e110f7955f3bc3876e3a07f5daadec5f3"}, - {file = "cryptography-45.0.6-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2dac5ec199038b8e131365e2324c03d20e97fe214af051d20c49db129844e8b3"}, - {file = "cryptography-45.0.6-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:18f878a34b90d688982e43f4b700408b478102dd58b3e39de21b5ebf6509c301"}, - {file = "cryptography-45.0.6-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:5bd6020c80c5b2b2242d6c48487d7b85700f5e0038e67b29d706f98440d66eb5"}, - {file = "cryptography-45.0.6-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:eccddbd986e43014263eda489abbddfbc287af5cddfd690477993dbb31e31016"}, - {file = "cryptography-45.0.6-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:550ae02148206beb722cfe4ef0933f9352bab26b087af00e48fdfb9ade35c5b3"}, - {file = "cryptography-45.0.6-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5b64e668fc3528e77efa51ca70fadcd6610e8ab231e3e06ae2bab3b31c2b8ed9"}, - {file = "cryptography-45.0.6-cp37-abi3-win32.whl", hash = "sha256:780c40fb751c7d2b0c6786ceee6b6f871e86e8718a8ff4bc35073ac353c7cd02"}, - {file = "cryptography-45.0.6-cp37-abi3-win_amd64.whl", hash = "sha256:20d15aed3ee522faac1a39fbfdfee25d17b1284bafd808e1640a74846d7c4d1b"}, - {file = "cryptography-45.0.6-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:705bb7c7ecc3d79a50f236adda12ca331c8e7ecfbea51edd931ce5a7a7c4f012"}, - {file = "cryptography-45.0.6-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:826b46dae41a1155a0c0e66fafba43d0ede1dc16570b95e40c4d83bfcf0a451d"}, - {file = "cryptography-45.0.6-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:cc4d66f5dc4dc37b89cfef1bd5044387f7a1f6f0abb490815628501909332d5d"}, - {file = "cryptography-45.0.6-pp310-pypy310_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:f68f833a9d445cc49f01097d95c83a850795921b3f7cc6488731e69bde3288da"}, - {file = "cryptography-45.0.6-pp310-pypy310_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:3b5bf5267e98661b9b888a9250d05b063220dfa917a8203744454573c7eb79db"}, - {file = "cryptography-45.0.6-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:2384f2ab18d9be88a6e4f8972923405e2dbb8d3e16c6b43f15ca491d7831bd18"}, - {file = "cryptography-45.0.6-pp311-pypy311_pp73-macosx_10_9_x86_64.whl", hash = "sha256:fc022c1fa5acff6def2fc6d7819bbbd31ccddfe67d075331a65d9cfb28a20983"}, - {file = "cryptography-45.0.6-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:3de77e4df42ac8d4e4d6cdb342d989803ad37707cf8f3fbf7b088c9cbdd46427"}, - {file = "cryptography-45.0.6-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:599c8d7df950aa68baa7e98f7b73f4f414c9f02d0e8104a30c0182a07732638b"}, - {file = "cryptography-45.0.6-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:31a2b9a10530a1cb04ffd6aa1cd4d3be9ed49f7d77a4dafe198f3b382f41545c"}, - {file = "cryptography-45.0.6-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:e5b3dda1b00fb41da3af4c5ef3f922a200e33ee5ba0f0bc9ecf0b0c173958385"}, - {file = "cryptography-45.0.6-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:629127cfdcdc6806dfe234734d7cb8ac54edaf572148274fa377a7d3405b0043"}, - {file = "cryptography-45.0.6.tar.gz", hash = "sha256:5c966c732cf6e4a276ce83b6e4c729edda2df6929083a952cc7da973c539c719"}, + {file = "cryptography-45.0.7-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:3be4f21c6245930688bd9e162829480de027f8bf962ede33d4f8ba7d67a00cee"}, + {file = "cryptography-45.0.7-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:67285f8a611b0ebc0857ced2081e30302909f571a46bfa7a3cc0ad303fe015c6"}, + {file = "cryptography-45.0.7-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:577470e39e60a6cd7780793202e63536026d9b8641de011ed9d8174da9ca5339"}, + {file = "cryptography-45.0.7-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:4bd3e5c4b9682bc112d634f2c6ccc6736ed3635fc3319ac2bb11d768cc5a00d8"}, + {file = "cryptography-45.0.7-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:465ccac9d70115cd4de7186e60cfe989de73f7bb23e8a7aa45af18f7412e75bf"}, + {file = "cryptography-45.0.7-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:16ede8a4f7929b4b7ff3642eba2bf79aa1d71f24ab6ee443935c0d269b6bc513"}, + {file = "cryptography-45.0.7-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:8978132287a9d3ad6b54fcd1e08548033cc09dc6aacacb6c004c73c3eb5d3ac3"}, + {file = "cryptography-45.0.7-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:b6a0e535baec27b528cb07a119f321ac024592388c5681a5ced167ae98e9fff3"}, + {file = "cryptography-45.0.7-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:a24ee598d10befaec178efdff6054bc4d7e883f615bfbcd08126a0f4931c83a6"}, + {file = "cryptography-45.0.7-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:fa26fa54c0a9384c27fcdc905a2fb7d60ac6e47d14bc2692145f2b3b1e2cfdbd"}, + {file = "cryptography-45.0.7-cp311-abi3-win32.whl", hash = "sha256:bef32a5e327bd8e5af915d3416ffefdbe65ed975b646b3805be81b23580b57b8"}, + {file = "cryptography-45.0.7-cp311-abi3-win_amd64.whl", hash = "sha256:3808e6b2e5f0b46d981c24d79648e5c25c35e59902ea4391a0dcb3e667bf7443"}, + {file = "cryptography-45.0.7-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:bfb4c801f65dd61cedfc61a83732327fafbac55a47282e6f26f073ca7a41c3b2"}, + {file = "cryptography-45.0.7-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:81823935e2f8d476707e85a78a405953a03ef7b7b4f55f93f7c2d9680e5e0691"}, + {file = "cryptography-45.0.7-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3994c809c17fc570c2af12c9b840d7cea85a9fd3e5c0e0491f4fa3c029216d59"}, + {file = "cryptography-45.0.7-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:dad43797959a74103cb59c5dac71409f9c27d34c8a05921341fb64ea8ccb1dd4"}, + {file = "cryptography-45.0.7-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:ce7a453385e4c4693985b4a4a3533e041558851eae061a58a5405363b098fcd3"}, + {file = "cryptography-45.0.7-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:b04f85ac3a90c227b6e5890acb0edbaf3140938dbecf07bff618bf3638578cf1"}, + {file = "cryptography-45.0.7-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:48c41a44ef8b8c2e80ca4527ee81daa4c527df3ecbc9423c41a420a9559d0e27"}, + {file = "cryptography-45.0.7-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:f3df7b3d0f91b88b2106031fd995802a2e9ae13e02c36c1fc075b43f420f3a17"}, + {file = "cryptography-45.0.7-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:dd342f085542f6eb894ca00ef70236ea46070c8a13824c6bde0dfdcd36065b9b"}, + {file = "cryptography-45.0.7-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1993a1bb7e4eccfb922b6cd414f072e08ff5816702a0bdb8941c247a6b1b287c"}, + {file = "cryptography-45.0.7-cp37-abi3-win32.whl", hash = "sha256:18fcf70f243fe07252dcb1b268a687f2358025ce32f9f88028ca5c364b123ef5"}, + {file = "cryptography-45.0.7-cp37-abi3-win_amd64.whl", hash = "sha256:7285a89df4900ed3bfaad5679b1e668cb4b38a8de1ccbfc84b05f34512da0a90"}, + {file = "cryptography-45.0.7-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:de58755d723e86175756f463f2f0bddd45cc36fbd62601228a3f8761c9f58252"}, + {file = "cryptography-45.0.7-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:a20e442e917889d1a6b3c570c9e3fa2fdc398c20868abcea268ea33c024c4083"}, + {file = "cryptography-45.0.7-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:258e0dff86d1d891169b5af222d362468a9570e2532923088658aa866eb11130"}, + {file = "cryptography-45.0.7-pp310-pypy310_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:d97cf502abe2ab9eff8bd5e4aca274da8d06dd3ef08b759a8d6143f4ad65d4b4"}, + {file = "cryptography-45.0.7-pp310-pypy310_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:c987dad82e8c65ebc985f5dae5e74a3beda9d0a2a4daf8a1115f3772b59e5141"}, + {file = "cryptography-45.0.7-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c13b1e3afd29a5b3b2656257f14669ca8fa8d7956d509926f0b130b600b50ab7"}, + {file = "cryptography-45.0.7-pp311-pypy311_pp73-macosx_10_9_x86_64.whl", hash = "sha256:4a862753b36620af6fc54209264f92c716367f2f0ff4624952276a6bbd18cbde"}, + {file = "cryptography-45.0.7-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:06ce84dc14df0bf6ea84666f958e6080cdb6fe1231be2a51f3fc1267d9f3fb34"}, + {file = "cryptography-45.0.7-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:d0c5c6bac22b177bf8da7435d9d27a6834ee130309749d162b26c3105c0795a9"}, + {file = "cryptography-45.0.7-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:2f641b64acc00811da98df63df7d59fd4706c0df449da71cb7ac39a0732b40ae"}, + {file = "cryptography-45.0.7-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:f5414a788ecc6ee6bc58560e85ca624258a55ca434884445440a810796ea0e0b"}, + {file = "cryptography-45.0.7-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:1f3d56f73595376f4244646dd5c5870c14c196949807be39e79e7bd9bac3da63"}, + {file = "cryptography-45.0.7.tar.gz", hash = "sha256:4b1654dfc64ea479c242508eb8c724044f1e964a47d1d1cacc5132292d851971"}, ] [package.dependencies] @@ -676,7 +676,7 @@ nox = ["nox (>=2024.4.15)", "nox[uv] (>=2024.3.2) ; python_full_version >= \"3.8 pep8test = ["check-sdist ; python_full_version >= \"3.8.0\"", "click (>=8.0.1)", "mypy (>=1.4)", "ruff (>=0.3.6)"] sdist = ["build (>=1.0.0)"] ssh = ["bcrypt (>=3.1.5)"] -test = ["certifi (>=2024)", "cryptography-vectors (==45.0.6)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"] +test = ["certifi (>=2024)", "cryptography-vectors (==45.0.7)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"] test-randomorder = ["pytest-randomly"] [[package]] @@ -730,14 +730,14 @@ test = ["pytest (>=6)"] [[package]] name = "executing" -version = "2.2.0" +version = "2.2.1" description = "Get the currently executing AST node of a frame, and other information" optional = false python-versions = ">=3.8" groups = ["integration"] files = [ - {file = "executing-2.2.0-py2.py3-none-any.whl", hash = "sha256:11387150cad388d62750327a53d3339fad4888b39a6fe233c3afbb54ecffd3aa"}, - {file = "executing-2.2.0.tar.gz", hash = "sha256:5d108c028108fe2551d1a7b2e8b713341e2cb4fc0aa7dcf966fa4327a5226755"}, + {file = "executing-2.2.1-py2.py3-none-any.whl", hash = "sha256:760643d3452b4d777d295bb167ccc74c64a81df23fb5e08eff250c425a4b2017"}, + {file = "executing-2.2.1.tar.gz", hash = "sha256:3632cc370565f6648cc328b32435bd120a1e4ebb20c77e3fdde9a13cd1e533c4"}, ] [package.extras] @@ -1480,14 +1480,14 @@ files = [ [[package]] name = "prompt-toolkit" -version = "3.0.51" +version = "3.0.52" description = "Library for building powerful interactive command lines in Python" optional = false python-versions = ">=3.8" groups = ["integration"] files = [ - {file = "prompt_toolkit-3.0.51-py3-none-any.whl", hash = "sha256:52742911fde84e2d423e2f9a4cf1de7d7ac4e51958f648d9540e0fb8db077b07"}, - {file = "prompt_toolkit-3.0.51.tar.gz", hash = "sha256:931a162e3b27fc90c86f1b48bb1fb2c528c2761475e57c9c06de13311c7b54ed"}, + {file = "prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955"}, + {file = "prompt_toolkit-3.0.52.tar.gz", hash = "sha256:28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855"}, ] [package.dependencies] @@ -2068,167 +2068,167 @@ rsa = ["oauthlib[signedtoken] (>=3.0.0)"] [[package]] name = "rpds-py" -version = "0.27.0" +version = "0.27.1" description = "Python bindings to Rust's persistent data structures (rpds)" optional = false python-versions = ">=3.9" groups = ["charm-libs", "unit"] files = [ - {file = "rpds_py-0.27.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:130c1ffa5039a333f5926b09e346ab335f0d4ec393b030a18549a7c7e7c2cea4"}, - {file = "rpds_py-0.27.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a4cf32a26fa744101b67bfd28c55d992cd19438aff611a46cac7f066afca8fd4"}, - {file = "rpds_py-0.27.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64a0fe3f334a40b989812de70160de6b0ec7e3c9e4a04c0bbc48d97c5d3600ae"}, - {file = "rpds_py-0.27.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9a0ff7ee28583ab30a52f371b40f54e7138c52ca67f8ca17ccb7ccf0b383cb5f"}, - {file = "rpds_py-0.27.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:15ea4d2e182345dd1b4286593601d766411b43f868924afe297570658c31a62b"}, - {file = "rpds_py-0.27.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:36184b44bf60a480863e51021c26aca3dfe8dd2f5eeabb33622b132b9d8b8b54"}, - {file = "rpds_py-0.27.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b78430703cfcf5f5e86eb74027a1ed03a93509273d7c705babb547f03e60016"}, - {file = "rpds_py-0.27.0-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:dbd749cff1defbde270ca346b69b3baf5f1297213ef322254bf2a28537f0b046"}, - {file = "rpds_py-0.27.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6bde37765564cd22a676dd8101b657839a1854cfaa9c382c5abf6ff7accfd4ae"}, - {file = "rpds_py-0.27.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:1d66f45b9399036e890fb9c04e9f70c33857fd8f58ac8db9f3278cfa835440c3"}, - {file = "rpds_py-0.27.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:d85d784c619370d9329bbd670f41ff5f2ae62ea4519761b679d0f57f0f0ee267"}, - {file = "rpds_py-0.27.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5df559e9e7644d9042f626f2c3997b555f347d7a855a15f170b253f6c5bfe358"}, - {file = "rpds_py-0.27.0-cp310-cp310-win32.whl", hash = "sha256:b8a4131698b6992b2a56015f51646711ec5d893a0b314a4b985477868e240c87"}, - {file = "rpds_py-0.27.0-cp310-cp310-win_amd64.whl", hash = "sha256:cbc619e84a5e3ab2d452de831c88bdcad824414e9c2d28cd101f94dbdf26329c"}, - {file = "rpds_py-0.27.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:dbc2ab5d10544eb485baa76c63c501303b716a5c405ff2469a1d8ceffaabf622"}, - {file = "rpds_py-0.27.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7ec85994f96a58cf7ed288caa344b7fe31fd1d503bdf13d7331ead5f70ab60d5"}, - {file = "rpds_py-0.27.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:190d7285cd3bb6d31d37a0534d7359c1ee191eb194c511c301f32a4afa5a1dd4"}, - {file = "rpds_py-0.27.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c10d92fb6d7fd827e44055fcd932ad93dac6a11e832d51534d77b97d1d85400f"}, - {file = "rpds_py-0.27.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dd2c1d27ebfe6a015cfa2005b7fe8c52d5019f7bbdd801bc6f7499aab9ae739e"}, - {file = "rpds_py-0.27.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4790c9d5dd565ddb3e9f656092f57268951398cef52e364c405ed3112dc7c7c1"}, - {file = "rpds_py-0.27.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4300e15e7d03660f04be84a125d1bdd0e6b2f674bc0723bc0fd0122f1a4585dc"}, - {file = "rpds_py-0.27.0-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:59195dc244fc183209cf8a93406889cadde47dfd2f0a6b137783aa9c56d67c85"}, - {file = "rpds_py-0.27.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fae4a01ef8c4cb2bbe92ef2063149596907dc4a881a8d26743b3f6b304713171"}, - {file = "rpds_py-0.27.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e3dc8d4ede2dbae6c0fc2b6c958bf51ce9fd7e9b40c0f5b8835c3fde44f5807d"}, - {file = "rpds_py-0.27.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:c3782fb753aa825b4ccabc04292e07897e2fd941448eabf666856c5530277626"}, - {file = "rpds_py-0.27.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:887ab1f12b0d227e9260558a4a2320024b20102207ada65c43e1ffc4546df72e"}, - {file = "rpds_py-0.27.0-cp311-cp311-win32.whl", hash = "sha256:5d6790ff400254137b81b8053b34417e2c46921e302d655181d55ea46df58cf7"}, - {file = "rpds_py-0.27.0-cp311-cp311-win_amd64.whl", hash = "sha256:e24d8031a2c62f34853756d9208eeafa6b940a1efcbfe36e8f57d99d52bb7261"}, - {file = "rpds_py-0.27.0-cp311-cp311-win_arm64.whl", hash = "sha256:08680820d23df1df0a0260f714d12966bc6c42d02e8055a91d61e03f0c47dda0"}, - {file = "rpds_py-0.27.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:19c990fdf5acecbf0623e906ae2e09ce1c58947197f9bced6bbd7482662231c4"}, - {file = "rpds_py-0.27.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6c27a7054b5224710fcfb1a626ec3ff4f28bcb89b899148c72873b18210e446b"}, - {file = "rpds_py-0.27.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09965b314091829b378b60607022048953e25f0b396c2b70e7c4c81bcecf932e"}, - {file = "rpds_py-0.27.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:14f028eb47f59e9169bfdf9f7ceafd29dd64902141840633683d0bad5b04ff34"}, - {file = "rpds_py-0.27.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6168af0be75bba990a39f9431cdfae5f0ad501f4af32ae62e8856307200517b8"}, - {file = "rpds_py-0.27.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ab47fe727c13c09d0e6f508e3a49e545008e23bf762a245b020391b621f5b726"}, - {file = "rpds_py-0.27.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fa01b3d5e3b7d97efab65bd3d88f164e289ec323a8c033c5c38e53ee25c007e"}, - {file = "rpds_py-0.27.0-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:6c135708e987f46053e0a1246a206f53717f9fadfba27174a9769ad4befba5c3"}, - {file = "rpds_py-0.27.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fc327f4497b7087d06204235199daf208fd01c82d80465dc5efa4ec9df1c5b4e"}, - {file = "rpds_py-0.27.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7e57906e38583a2cba67046a09c2637e23297618dc1f3caddbc493f2be97c93f"}, - {file = "rpds_py-0.27.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f4f69d7a4300fbf91efb1fb4916421bd57804c01ab938ab50ac9c4aa2212f03"}, - {file = "rpds_py-0.27.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b4c4fbbcff474e1e5f38be1bf04511c03d492d42eec0babda5d03af3b5589374"}, - {file = "rpds_py-0.27.0-cp312-cp312-win32.whl", hash = "sha256:27bac29bbbf39601b2aab474daf99dbc8e7176ca3389237a23944b17f8913d97"}, - {file = "rpds_py-0.27.0-cp312-cp312-win_amd64.whl", hash = "sha256:8a06aa1197ec0281eb1d7daf6073e199eb832fe591ffa329b88bae28f25f5fe5"}, - {file = "rpds_py-0.27.0-cp312-cp312-win_arm64.whl", hash = "sha256:e14aab02258cb776a108107bd15f5b5e4a1bbaa61ef33b36693dfab6f89d54f9"}, - {file = "rpds_py-0.27.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:443d239d02d9ae55b74015234f2cd8eb09e59fbba30bf60baeb3123ad4c6d5ff"}, - {file = "rpds_py-0.27.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b8a7acf04fda1f30f1007f3cc96d29d8cf0a53e626e4e1655fdf4eabc082d367"}, - {file = "rpds_py-0.27.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d0f92b78cfc3b74a42239fdd8c1266f4715b573204c234d2f9fc3fc7a24f185"}, - {file = "rpds_py-0.27.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ce4ed8e0c7dbc5b19352b9c2c6131dd23b95fa8698b5cdd076307a33626b72dc"}, - {file = "rpds_py-0.27.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fde355b02934cc6b07200cc3b27ab0c15870a757d1a72fd401aa92e2ea3c6bfe"}, - {file = "rpds_py-0.27.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:13bbc4846ae4c993f07c93feb21a24d8ec637573d567a924b1001e81c8ae80f9"}, - {file = "rpds_py-0.27.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be0744661afbc4099fef7f4e604e7f1ea1be1dd7284f357924af12a705cc7d5c"}, - {file = "rpds_py-0.27.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:069e0384a54f427bd65d7fda83b68a90606a3835901aaff42185fcd94f5a9295"}, - {file = "rpds_py-0.27.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4bc262ace5a1a7dc3e2eac2fa97b8257ae795389f688b5adf22c5db1e2431c43"}, - {file = "rpds_py-0.27.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2fe6e18e5c8581f0361b35ae575043c7029d0a92cb3429e6e596c2cdde251432"}, - {file = "rpds_py-0.27.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d93ebdb82363d2e7bec64eecdc3632b59e84bd270d74fe5be1659f7787052f9b"}, - {file = "rpds_py-0.27.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0954e3a92e1d62e83a54ea7b3fdc9efa5d61acef8488a8a3d31fdafbfb00460d"}, - {file = "rpds_py-0.27.0-cp313-cp313-win32.whl", hash = "sha256:2cff9bdd6c7b906cc562a505c04a57d92e82d37200027e8d362518df427f96cd"}, - {file = "rpds_py-0.27.0-cp313-cp313-win_amd64.whl", hash = "sha256:dc79d192fb76fc0c84f2c58672c17bbbc383fd26c3cdc29daae16ce3d927e8b2"}, - {file = "rpds_py-0.27.0-cp313-cp313-win_arm64.whl", hash = "sha256:5b3a5c8089eed498a3af23ce87a80805ff98f6ef8f7bdb70bd1b7dae5105f6ac"}, - {file = "rpds_py-0.27.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:90fb790138c1a89a2e58c9282fe1089638401f2f3b8dddd758499041bc6e0774"}, - {file = "rpds_py-0.27.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:010c4843a3b92b54373e3d2291a7447d6c3fc29f591772cc2ea0e9f5c1da434b"}, - {file = "rpds_py-0.27.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9ce7a9e967afc0a2af7caa0d15a3e9c1054815f73d6a8cb9225b61921b419bd"}, - {file = "rpds_py-0.27.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:aa0bf113d15e8abdfee92aa4db86761b709a09954083afcb5bf0f952d6065fdb"}, - {file = "rpds_py-0.27.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb91d252b35004a84670dfeafadb042528b19842a0080d8b53e5ec1128e8f433"}, - {file = "rpds_py-0.27.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:db8a6313dbac934193fc17fe7610f70cd8181c542a91382531bef5ed785e5615"}, - {file = "rpds_py-0.27.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce96ab0bdfcef1b8c371ada2100767ace6804ea35aacce0aef3aeb4f3f499ca8"}, - {file = "rpds_py-0.27.0-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:7451ede3560086abe1aa27dcdcf55cd15c96b56f543fb12e5826eee6f721f858"}, - {file = "rpds_py-0.27.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:32196b5a99821476537b3f7732432d64d93a58d680a52c5e12a190ee0135d8b5"}, - {file = "rpds_py-0.27.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a029be818059870664157194e46ce0e995082ac49926f1423c1f058534d2aaa9"}, - {file = "rpds_py-0.27.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3841f66c1ffdc6cebce8aed64e36db71466f1dc23c0d9a5592e2a782a3042c79"}, - {file = "rpds_py-0.27.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:42894616da0fc0dcb2ec08a77896c3f56e9cb2f4b66acd76fc8992c3557ceb1c"}, - {file = "rpds_py-0.27.0-cp313-cp313t-win32.whl", hash = "sha256:b1fef1f13c842a39a03409e30ca0bf87b39a1e2a305a9924deadb75a43105d23"}, - {file = "rpds_py-0.27.0-cp313-cp313t-win_amd64.whl", hash = "sha256:183f5e221ba3e283cd36fdfbe311d95cd87699a083330b4f792543987167eff1"}, - {file = "rpds_py-0.27.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:f3cd110e02c5bf17d8fb562f6c9df5c20e73029d587cf8602a2da6c5ef1e32cb"}, - {file = "rpds_py-0.27.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:8d0e09cf4863c74106b5265c2c310f36146e2b445ff7b3018a56799f28f39f6f"}, - {file = "rpds_py-0.27.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64f689ab822f9b5eb6dfc69893b4b9366db1d2420f7db1f6a2adf2a9ca15ad64"}, - {file = "rpds_py-0.27.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e36c80c49853b3ffda7aa1831bf175c13356b210c73128c861f3aa93c3cc4015"}, - {file = "rpds_py-0.27.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6de6a7f622860af0146cb9ee148682ff4d0cea0b8fd3ad51ce4d40efb2f061d0"}, - {file = "rpds_py-0.27.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4045e2fc4b37ec4b48e8907a5819bdd3380708c139d7cc358f03a3653abedb89"}, - {file = "rpds_py-0.27.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9da162b718b12c4219eeeeb68a5b7552fbc7aadedf2efee440f88b9c0e54b45d"}, - {file = "rpds_py-0.27.0-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:0665be515767dc727ffa5f74bd2ef60b0ff85dad6bb8f50d91eaa6b5fb226f51"}, - {file = "rpds_py-0.27.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:203f581accef67300a942e49a37d74c12ceeef4514874c7cede21b012613ca2c"}, - {file = "rpds_py-0.27.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7873b65686a6471c0037139aa000d23fe94628e0daaa27b6e40607c90e3f5ec4"}, - {file = "rpds_py-0.27.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:249ab91ceaa6b41abc5f19513cb95b45c6f956f6b89f1fe3d99c81255a849f9e"}, - {file = "rpds_py-0.27.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d2f184336bc1d6abfaaa1262ed42739c3789b1e3a65a29916a615307d22ffd2e"}, - {file = "rpds_py-0.27.0-cp314-cp314-win32.whl", hash = "sha256:d3c622c39f04d5751408f5b801ecb527e6e0a471b367f420a877f7a660d583f6"}, - {file = "rpds_py-0.27.0-cp314-cp314-win_amd64.whl", hash = "sha256:cf824aceaeffff029ccfba0da637d432ca71ab21f13e7f6f5179cd88ebc77a8a"}, - {file = "rpds_py-0.27.0-cp314-cp314-win_arm64.whl", hash = "sha256:86aca1616922b40d8ac1b3073a1ead4255a2f13405e5700c01f7c8d29a03972d"}, - {file = "rpds_py-0.27.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:341d8acb6724c0c17bdf714319c393bb27f6d23d39bc74f94221b3e59fc31828"}, - {file = "rpds_py-0.27.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6b96b0b784fe5fd03beffff2b1533dc0d85e92bab8d1b2c24ef3a5dc8fac5669"}, - {file = "rpds_py-0.27.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0c431bfb91478d7cbe368d0a699978050d3b112d7f1d440a41e90faa325557fd"}, - {file = "rpds_py-0.27.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:20e222a44ae9f507d0f2678ee3dd0c45ec1e930f6875d99b8459631c24058aec"}, - {file = "rpds_py-0.27.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:184f0d7b342967f6cda94a07d0e1fae177d11d0b8f17d73e06e36ac02889f303"}, - {file = "rpds_py-0.27.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a00c91104c173c9043bc46f7b30ee5e6d2f6b1149f11f545580f5d6fdff42c0b"}, - {file = "rpds_py-0.27.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7a37dd208f0d658e0487522078b1ed68cd6bce20ef4b5a915d2809b9094b410"}, - {file = "rpds_py-0.27.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:92f3b3ec3e6008a1fe00b7c0946a170f161ac00645cde35e3c9a68c2475e8156"}, - {file = "rpds_py-0.27.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a1b3db5fae5cbce2131b7420a3f83553d4d89514c03d67804ced36161fe8b6b2"}, - {file = "rpds_py-0.27.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5355527adaa713ab693cbce7c1e0ec71682f599f61b128cf19d07e5c13c9b1f1"}, - {file = "rpds_py-0.27.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:fcc01c57ce6e70b728af02b2401c5bc853a9e14eb07deda30624374f0aebfe42"}, - {file = "rpds_py-0.27.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3001013dae10f806380ba739d40dee11db1ecb91684febb8406a87c2ded23dae"}, - {file = "rpds_py-0.27.0-cp314-cp314t-win32.whl", hash = "sha256:0f401c369186a5743694dd9fc08cba66cf70908757552e1f714bfc5219c655b5"}, - {file = "rpds_py-0.27.0-cp314-cp314t-win_amd64.whl", hash = "sha256:8a1dca5507fa1337f75dcd5070218b20bc68cf8844271c923c1b79dfcbc20391"}, - {file = "rpds_py-0.27.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:e0d7151a1bd5d0a203a5008fc4ae51a159a610cb82ab0a9b2c4d80241745582e"}, - {file = "rpds_py-0.27.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:42ccc57ff99166a55a59d8c7d14f1a357b7749f9ed3584df74053fd098243451"}, - {file = "rpds_py-0.27.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e377e4cf8795cdbdff75b8f0223d7b6c68ff4fef36799d88ccf3a995a91c0112"}, - {file = "rpds_py-0.27.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:79af163a4b40bbd8cfd7ca86ec8b54b81121d3b213b4435ea27d6568bcba3e9d"}, - {file = "rpds_py-0.27.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b2eff8ee57c5996b0d2a07c3601fb4ce5fbc37547344a26945dd9e5cbd1ed27a"}, - {file = "rpds_py-0.27.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7cf9bc4508efb18d8dff6934b602324eb9f8c6644749627ce001d6f38a490889"}, - {file = "rpds_py-0.27.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05284439ebe7d9f5f5a668d4d8a0a1d851d16f7d47c78e1fab968c8ad30cab04"}, - {file = "rpds_py-0.27.0-cp39-cp39-manylinux_2_31_riscv64.whl", hash = "sha256:1321bce595ad70e80f97f998db37356b2e22cf98094eba6fe91782e626da2f71"}, - {file = "rpds_py-0.27.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:737005088449ddd3b3df5a95476ee1c2c5c669f5c30eed909548a92939c0e12d"}, - {file = "rpds_py-0.27.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:9b2a4e17bfd68536c3b801800941c95a1d4a06e3cada11c146093ba939d9638d"}, - {file = "rpds_py-0.27.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:dc6b0d5a1ea0318ef2def2b6a55dccf1dcaf77d605672347271ed7b829860765"}, - {file = "rpds_py-0.27.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:4c3f8a0d4802df34fcdbeb3dfe3a4d8c9a530baea8fafdf80816fcaac5379d83"}, - {file = "rpds_py-0.27.0-cp39-cp39-win32.whl", hash = "sha256:699c346abc73993962cac7bb4f02f58e438840fa5458a048d3a178a7a670ba86"}, - {file = "rpds_py-0.27.0-cp39-cp39-win_amd64.whl", hash = "sha256:be806e2961cd390a89d6c3ce8c2ae34271cfcd05660f716257838bb560f1c3b6"}, - {file = "rpds_py-0.27.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:46f48482c1a4748ab2773f75fffbdd1951eb59794e32788834b945da857c47a8"}, - {file = "rpds_py-0.27.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:419dd9c98bcc9fb0242be89e0c6e922df333b975d4268faa90d58499fd9c9ebe"}, - {file = "rpds_py-0.27.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55d42a0ef2bdf6bc81e1cc2d49d12460f63c6ae1423c4f4851b828e454ccf6f1"}, - {file = "rpds_py-0.27.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2e39169ac6aae06dd79c07c8a69d9da867cef6a6d7883a0186b46bb46ccfb0c3"}, - {file = "rpds_py-0.27.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:935afcdea4751b0ac918047a2df3f720212892347767aea28f5b3bf7be4f27c0"}, - {file = "rpds_py-0.27.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8de567dec6d451649a781633d36f5c7501711adee329d76c095be2178855b042"}, - {file = "rpds_py-0.27.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:555ed147cbe8c8f76e72a4c6cd3b7b761cbf9987891b9448808148204aed74a5"}, - {file = "rpds_py-0.27.0-pp310-pypy310_pp73-manylinux_2_31_riscv64.whl", hash = "sha256:d2cc2b34f9e1d31ce255174da82902ad75bd7c0d88a33df54a77a22f2ef421ee"}, - {file = "rpds_py-0.27.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cb0702c12983be3b2fab98ead349ac63a98216d28dda6f518f52da5498a27a1b"}, - {file = "rpds_py-0.27.0-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:ba783541be46f27c8faea5a6645e193943c17ea2f0ffe593639d906a327a9bcc"}, - {file = "rpds_py-0.27.0-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:2406d034635d1497c596c40c85f86ecf2bf9611c1df73d14078af8444fe48031"}, - {file = "rpds_py-0.27.0-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:dea0808153f1fbbad772669d906cddd92100277533a03845de6893cadeffc8be"}, - {file = "rpds_py-0.27.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d2a81bdcfde4245468f7030a75a37d50400ac2455c3a4819d9d550c937f90ab5"}, - {file = "rpds_py-0.27.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e6491658dd2569f05860bad645569145c8626ac231877b0fb2d5f9bcb7054089"}, - {file = "rpds_py-0.27.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:bec77545d188f8bdd29d42bccb9191682a46fb2e655e3d1fb446d47c55ac3b8d"}, - {file = "rpds_py-0.27.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25a4aebf8ca02bbb90a9b3e7a463bbf3bee02ab1c446840ca07b1695a68ce424"}, - {file = "rpds_py-0.27.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:44524b96481a4c9b8e6c46d6afe43fa1fb485c261e359fbe32b63ff60e3884d8"}, - {file = "rpds_py-0.27.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:45d04a73c54b6a5fd2bab91a4b5bc8b426949586e61340e212a8484919183859"}, - {file = "rpds_py-0.27.0-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:343cf24de9ed6c728abefc5d5c851d5de06497caa7ac37e5e65dd572921ed1b5"}, - {file = "rpds_py-0.27.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7aed8118ae20515974650d08eb724150dc2e20c2814bcc307089569995e88a14"}, - {file = "rpds_py-0.27.0-pp311-pypy311_pp73-manylinux_2_31_riscv64.whl", hash = "sha256:af9d4fd79ee1cc8e7caf693ee02737daabfc0fcf2773ca0a4735b356c8ad6f7c"}, - {file = "rpds_py-0.27.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f0396e894bd1e66c74ecbc08b4f6a03dc331140942c4b1d345dd131b68574a60"}, - {file = "rpds_py-0.27.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:59714ab0a5af25d723d8e9816638faf7f4254234decb7d212715c1aa71eee7be"}, - {file = "rpds_py-0.27.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:88051c3b7d5325409f433c5a40328fcb0685fc04e5db49ff936e910901d10114"}, - {file = "rpds_py-0.27.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:181bc29e59e5e5e6e9d63b143ff4d5191224d355e246b5a48c88ce6b35c4e466"}, - {file = "rpds_py-0.27.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:9ad08547995a57e74fea6abaf5940d399447935faebbd2612b3b0ca6f987946b"}, - {file = "rpds_py-0.27.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:61490d57e82e23b45c66f96184237994bfafa914433b8cd1a9bb57fecfced59d"}, - {file = "rpds_py-0.27.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7cf5e726b6fa977e428a61880fb108a62f28b6d0c7ef675b117eaff7076df49"}, - {file = "rpds_py-0.27.0-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dc662bc9375a6a394b62dfd331874c434819f10ee3902123200dbcf116963f89"}, - {file = "rpds_py-0.27.0-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:299a245537e697f28a7511d01038c310ac74e8ea213c0019e1fc65f52c0dcb23"}, - {file = "rpds_py-0.27.0-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:be3964f7312ea05ed283b20f87cb533fdc555b2e428cc7be64612c0b2124f08c"}, - {file = "rpds_py-0.27.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33ba649a6e55ae3808e4c39e01580dc9a9b0d5b02e77b66bb86ef117922b1264"}, - {file = "rpds_py-0.27.0-pp39-pypy39_pp73-manylinux_2_31_riscv64.whl", hash = "sha256:81f81bbd7cdb4bdc418c09a73809abeda8f263a6bf8f9c7f93ed98b5597af39d"}, - {file = "rpds_py-0.27.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:11e8e28c0ba0373d052818b600474cfee2fafa6c9f36c8587d217b13ee28ca7d"}, - {file = "rpds_py-0.27.0-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:e3acb9c16530362aeaef4e84d57db357002dc5cbfac9a23414c3e73c08301ab2"}, - {file = "rpds_py-0.27.0-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:2e307cb5f66c59ede95c00e93cd84190a5b7f3533d7953690b2036780622ba81"}, - {file = "rpds_py-0.27.0-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:f09c9d4c26fa79c1bad927efb05aca2391350b8e61c38cbc0d7d3c814e463124"}, - {file = "rpds_py-0.27.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:af22763a0a1eff106426a6e1f13c4582e0d0ad89c1493ab6c058236174cd6c6a"}, - {file = "rpds_py-0.27.0.tar.gz", hash = "sha256:8b23cf252f180cda89220b378d917180f29d313cd6a07b2431c0d3b776aae86f"}, + {file = "rpds_py-0.27.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:68afeec26d42ab3b47e541b272166a0b4400313946871cba3ed3a4fc0cab1cef"}, + {file = "rpds_py-0.27.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:74e5b2f7bb6fa38b1b10546d27acbacf2a022a8b5543efb06cfebc72a59c85be"}, + {file = "rpds_py-0.27.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9024de74731df54546fab0bfbcdb49fae19159ecaecfc8f37c18d2c7e2c0bd61"}, + {file = "rpds_py-0.27.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:31d3ebadefcd73b73928ed0b2fd696f7fefda8629229f81929ac9c1854d0cffb"}, + {file = "rpds_py-0.27.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b2e7f8f169d775dd9092a1743768d771f1d1300453ddfe6325ae3ab5332b4657"}, + {file = "rpds_py-0.27.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d905d16f77eb6ab2e324e09bfa277b4c8e5e6b8a78a3e7ff8f3cdf773b4c013"}, + {file = "rpds_py-0.27.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50c946f048209e6362e22576baea09193809f87687a95a8db24e5fbdb307b93a"}, + {file = "rpds_py-0.27.1-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:3deab27804d65cd8289eb814c2c0e807c4b9d9916c9225e363cb0cf875eb67c1"}, + {file = "rpds_py-0.27.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8b61097f7488de4be8244c89915da8ed212832ccf1e7c7753a25a394bf9b1f10"}, + {file = "rpds_py-0.27.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8a3f29aba6e2d7d90528d3c792555a93497fe6538aa65eb675b44505be747808"}, + {file = "rpds_py-0.27.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:dd6cd0485b7d347304067153a6dc1d73f7d4fd995a396ef32a24d24b8ac63ac8"}, + {file = "rpds_py-0.27.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:6f4461bf931108c9fa226ffb0e257c1b18dc2d44cd72b125bec50ee0ab1248a9"}, + {file = "rpds_py-0.27.1-cp310-cp310-win32.whl", hash = "sha256:ee5422d7fb21f6a00c1901bf6559c49fee13a5159d0288320737bbf6585bd3e4"}, + {file = "rpds_py-0.27.1-cp310-cp310-win_amd64.whl", hash = "sha256:3e039aabf6d5f83c745d5f9a0a381d031e9ed871967c0a5c38d201aca41f3ba1"}, + {file = "rpds_py-0.27.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:be898f271f851f68b318872ce6ebebbc62f303b654e43bf72683dbdc25b7c881"}, + {file = "rpds_py-0.27.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:62ac3d4e3e07b58ee0ddecd71d6ce3b1637de2d373501412df395a0ec5f9beb5"}, + {file = "rpds_py-0.27.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4708c5c0ceb2d034f9991623631d3d23cb16e65c83736ea020cdbe28d57c0a0e"}, + {file = "rpds_py-0.27.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:abfa1171a9952d2e0002aba2ad3780820b00cc3d9c98c6630f2e93271501f66c"}, + {file = "rpds_py-0.27.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4b507d19f817ebaca79574b16eb2ae412e5c0835542c93fe9983f1e432aca195"}, + {file = "rpds_py-0.27.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:168b025f8fd8d8d10957405f3fdcef3dc20f5982d398f90851f4abc58c566c52"}, + {file = "rpds_py-0.27.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb56c6210ef77caa58e16e8c17d35c63fe3f5b60fd9ba9d424470c3400bcf9ed"}, + {file = "rpds_py-0.27.1-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:d252f2d8ca0195faa707f8eb9368955760880b2b42a8ee16d382bf5dd807f89a"}, + {file = "rpds_py-0.27.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6e5e54da1e74b91dbc7996b56640f79b195d5925c2b78efaa8c5d53e1d88edde"}, + {file = "rpds_py-0.27.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ffce0481cc6e95e5b3f0a47ee17ffbd234399e6d532f394c8dce320c3b089c21"}, + {file = "rpds_py-0.27.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:a205fdfe55c90c2cd8e540ca9ceba65cbe6629b443bc05db1f590a3db8189ff9"}, + {file = "rpds_py-0.27.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:689fb5200a749db0415b092972e8eba85847c23885c8543a8b0f5c009b1a5948"}, + {file = "rpds_py-0.27.1-cp311-cp311-win32.whl", hash = "sha256:3182af66048c00a075010bc7f4860f33913528a4b6fc09094a6e7598e462fe39"}, + {file = "rpds_py-0.27.1-cp311-cp311-win_amd64.whl", hash = "sha256:b4938466c6b257b2f5c4ff98acd8128ec36b5059e5c8f8372d79316b1c36bb15"}, + {file = "rpds_py-0.27.1-cp311-cp311-win_arm64.whl", hash = "sha256:2f57af9b4d0793e53266ee4325535a31ba48e2f875da81a9177c9926dfa60746"}, + {file = "rpds_py-0.27.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:ae2775c1973e3c30316892737b91f9283f9908e3cc7625b9331271eaaed7dc90"}, + {file = "rpds_py-0.27.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2643400120f55c8a96f7c9d858f7be0c88d383cd4653ae2cf0d0c88f668073e5"}, + {file = "rpds_py-0.27.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:16323f674c089b0360674a4abd28d5042947d54ba620f72514d69be4ff64845e"}, + {file = "rpds_py-0.27.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9a1f4814b65eacac94a00fc9a526e3fdafd78e439469644032032d0d63de4881"}, + {file = "rpds_py-0.27.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ba32c16b064267b22f1850a34051121d423b6f7338a12b9459550eb2096e7ec"}, + {file = "rpds_py-0.27.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5c20f33fd10485b80f65e800bbe5f6785af510b9f4056c5a3c612ebc83ba6cb"}, + {file = "rpds_py-0.27.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:466bfe65bd932da36ff279ddd92de56b042f2266d752719beb97b08526268ec5"}, + {file = "rpds_py-0.27.1-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:41e532bbdcb57c92ba3be62c42e9f096431b4cf478da9bc3bc6ce5c38ab7ba7a"}, + {file = "rpds_py-0.27.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f149826d742b406579466283769a8ea448eed82a789af0ed17b0cd5770433444"}, + {file = "rpds_py-0.27.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:80c60cfb5310677bd67cb1e85a1e8eb52e12529545441b43e6f14d90b878775a"}, + {file = "rpds_py-0.27.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:7ee6521b9baf06085f62ba9c7a3e5becffbc32480d2f1b351559c001c38ce4c1"}, + {file = "rpds_py-0.27.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a512c8263249a9d68cac08b05dd59d2b3f2061d99b322813cbcc14c3c7421998"}, + {file = "rpds_py-0.27.1-cp312-cp312-win32.whl", hash = "sha256:819064fa048ba01b6dadc5116f3ac48610435ac9a0058bbde98e569f9e785c39"}, + {file = "rpds_py-0.27.1-cp312-cp312-win_amd64.whl", hash = "sha256:d9199717881f13c32c4046a15f024971a3b78ad4ea029e8da6b86e5aa9cf4594"}, + {file = "rpds_py-0.27.1-cp312-cp312-win_arm64.whl", hash = "sha256:33aa65b97826a0e885ef6e278fbd934e98cdcfed80b63946025f01e2f5b29502"}, + {file = "rpds_py-0.27.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:e4b9fcfbc021633863a37e92571d6f91851fa656f0180246e84cbd8b3f6b329b"}, + {file = "rpds_py-0.27.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1441811a96eadca93c517d08df75de45e5ffe68aa3089924f963c782c4b898cf"}, + {file = "rpds_py-0.27.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55266dafa22e672f5a4f65019015f90336ed31c6383bd53f5e7826d21a0e0b83"}, + {file = "rpds_py-0.27.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d78827d7ac08627ea2c8e02c9e5b41180ea5ea1f747e9db0915e3adf36b62dcf"}, + {file = "rpds_py-0.27.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae92443798a40a92dc5f0b01d8a7c93adde0c4dc965310a29ae7c64d72b9fad2"}, + {file = "rpds_py-0.27.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c46c9dd2403b66a2a3b9720ec4b74d4ab49d4fabf9f03dfdce2d42af913fe8d0"}, + {file = "rpds_py-0.27.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2efe4eb1d01b7f5f1939f4ef30ecea6c6b3521eec451fb93191bf84b2a522418"}, + {file = "rpds_py-0.27.1-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:15d3b4d83582d10c601f481eca29c3f138d44c92187d197aff663a269197c02d"}, + {file = "rpds_py-0.27.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4ed2e16abbc982a169d30d1a420274a709949e2cbdef119fe2ec9d870b42f274"}, + {file = "rpds_py-0.27.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a75f305c9b013289121ec0f1181931975df78738cdf650093e6b86d74aa7d8dd"}, + {file = "rpds_py-0.27.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:67ce7620704745881a3d4b0ada80ab4d99df390838839921f99e63c474f82cf2"}, + {file = "rpds_py-0.27.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9d992ac10eb86d9b6f369647b6a3f412fc0075cfd5d799530e84d335e440a002"}, + {file = "rpds_py-0.27.1-cp313-cp313-win32.whl", hash = "sha256:4f75e4bd8ab8db624e02c8e2fc4063021b58becdbe6df793a8111d9343aec1e3"}, + {file = "rpds_py-0.27.1-cp313-cp313-win_amd64.whl", hash = "sha256:f9025faafc62ed0b75a53e541895ca272815bec18abe2249ff6501c8f2e12b83"}, + {file = "rpds_py-0.27.1-cp313-cp313-win_arm64.whl", hash = "sha256:ed10dc32829e7d222b7d3b93136d25a406ba9788f6a7ebf6809092da1f4d279d"}, + {file = "rpds_py-0.27.1-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:92022bbbad0d4426e616815b16bc4127f83c9a74940e1ccf3cfe0b387aba0228"}, + {file = "rpds_py-0.27.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:47162fdab9407ec3f160805ac3e154df042e577dd53341745fc7fb3f625e6d92"}, + {file = "rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb89bec23fddc489e5d78b550a7b773557c9ab58b7946154a10a6f7a214a48b2"}, + {file = "rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e48af21883ded2b3e9eb48cb7880ad8598b31ab752ff3be6457001d78f416723"}, + {file = "rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6f5b7bd8e219ed50299e58551a410b64daafb5017d54bbe822e003856f06a802"}, + {file = "rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08f1e20bccf73b08d12d804d6e1c22ca5530e71659e6673bce31a6bb71c1e73f"}, + {file = "rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0dc5dceeaefcc96dc192e3a80bbe1d6c410c469e97bdd47494a7d930987f18b2"}, + {file = "rpds_py-0.27.1-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:d76f9cc8665acdc0c9177043746775aa7babbf479b5520b78ae4002d889f5c21"}, + {file = "rpds_py-0.27.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:134fae0e36022edad8290a6661edf40c023562964efea0cc0ec7f5d392d2aaef"}, + {file = "rpds_py-0.27.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:eb11a4f1b2b63337cfd3b4d110af778a59aae51c81d195768e353d8b52f88081"}, + {file = "rpds_py-0.27.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:13e608ac9f50a0ed4faec0e90ece76ae33b34c0e8656e3dceb9a7db994c692cd"}, + {file = "rpds_py-0.27.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dd2135527aa40f061350c3f8f89da2644de26cd73e4de458e79606384f4f68e7"}, + {file = "rpds_py-0.27.1-cp313-cp313t-win32.whl", hash = "sha256:3020724ade63fe320a972e2ffd93b5623227e684315adce194941167fee02688"}, + {file = "rpds_py-0.27.1-cp313-cp313t-win_amd64.whl", hash = "sha256:8ee50c3e41739886606388ba3ab3ee2aae9f35fb23f833091833255a31740797"}, + {file = "rpds_py-0.27.1-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:acb9aafccaae278f449d9c713b64a9e68662e7799dbd5859e2c6b3c67b56d334"}, + {file = "rpds_py-0.27.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:b7fb801aa7f845ddf601c49630deeeccde7ce10065561d92729bfe81bd21fb33"}, + {file = "rpds_py-0.27.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe0dd05afb46597b9a2e11c351e5e4283c741237e7f617ffb3252780cca9336a"}, + {file = "rpds_py-0.27.1-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b6dfb0e058adb12d8b1d1b25f686e94ffa65d9995a5157afe99743bf7369d62b"}, + {file = "rpds_py-0.27.1-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ed090ccd235f6fa8bb5861684567f0a83e04f52dfc2e5c05f2e4b1309fcf85e7"}, + {file = "rpds_py-0.27.1-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bf876e79763eecf3e7356f157540d6a093cef395b65514f17a356f62af6cc136"}, + {file = "rpds_py-0.27.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:12ed005216a51b1d6e2b02a7bd31885fe317e45897de81d86dcce7d74618ffff"}, + {file = "rpds_py-0.27.1-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:ee4308f409a40e50593c7e3bb8cbe0b4d4c66d1674a316324f0c2f5383b486f9"}, + {file = "rpds_py-0.27.1-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0b08d152555acf1f455154d498ca855618c1378ec810646fcd7c76416ac6dc60"}, + {file = "rpds_py-0.27.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:dce51c828941973a5684d458214d3a36fcd28da3e1875d659388f4f9f12cc33e"}, + {file = "rpds_py-0.27.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:c1476d6f29eb81aa4151c9a31219b03f1f798dc43d8af1250a870735516a1212"}, + {file = "rpds_py-0.27.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:3ce0cac322b0d69b63c9cdb895ee1b65805ec9ffad37639f291dd79467bee675"}, + {file = "rpds_py-0.27.1-cp314-cp314-win32.whl", hash = "sha256:dfbfac137d2a3d0725758cd141f878bf4329ba25e34979797c89474a89a8a3a3"}, + {file = "rpds_py-0.27.1-cp314-cp314-win_amd64.whl", hash = "sha256:a6e57b0abfe7cc513450fcf529eb486b6e4d3f8aee83e92eb5f1ef848218d456"}, + {file = "rpds_py-0.27.1-cp314-cp314-win_arm64.whl", hash = "sha256:faf8d146f3d476abfee026c4ae3bdd9ca14236ae4e4c310cbd1cf75ba33d24a3"}, + {file = "rpds_py-0.27.1-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:ba81d2b56b6d4911ce735aad0a1d4495e808b8ee4dc58715998741a26874e7c2"}, + {file = "rpds_py-0.27.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:84f7d509870098de0e864cad0102711c1e24e9b1a50ee713b65928adb22269e4"}, + {file = "rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9e960fc78fecd1100539f14132425e1d5fe44ecb9239f8f27f079962021523e"}, + {file = "rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:62f85b665cedab1a503747617393573995dac4600ff51869d69ad2f39eb5e817"}, + {file = "rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fed467af29776f6556250c9ed85ea5a4dd121ab56a5f8b206e3e7a4c551e48ec"}, + {file = "rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2729615f9d430af0ae6b36cf042cb55c0936408d543fb691e1a9e36648fd35a"}, + {file = "rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1b207d881a9aef7ba753d69c123a35d96ca7cb808056998f6b9e8747321f03b8"}, + {file = "rpds_py-0.27.1-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:639fd5efec029f99b79ae47e5d7e00ad8a773da899b6309f6786ecaf22948c48"}, + {file = "rpds_py-0.27.1-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fecc80cb2a90e28af8a9b366edacf33d7a91cbfe4c2c4544ea1246e949cfebeb"}, + {file = "rpds_py-0.27.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:42a89282d711711d0a62d6f57d81aa43a1368686c45bc1c46b7f079d55692734"}, + {file = "rpds_py-0.27.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:cf9931f14223de59551ab9d38ed18d92f14f055a5f78c1d8ad6493f735021bbb"}, + {file = "rpds_py-0.27.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f39f58a27cc6e59f432b568ed8429c7e1641324fbe38131de852cd77b2d534b0"}, + {file = "rpds_py-0.27.1-cp314-cp314t-win32.whl", hash = "sha256:d5fa0ee122dc09e23607a28e6d7b150da16c662e66409bbe85230e4c85bb528a"}, + {file = "rpds_py-0.27.1-cp314-cp314t-win_amd64.whl", hash = "sha256:6567d2bb951e21232c2f660c24cf3470bb96de56cdcb3f071a83feeaff8a2772"}, + {file = "rpds_py-0.27.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:c918c65ec2e42c2a78d19f18c553d77319119bf43aa9e2edf7fb78d624355527"}, + {file = "rpds_py-0.27.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1fea2b1a922c47c51fd07d656324531adc787e415c8b116530a1d29c0516c62d"}, + {file = "rpds_py-0.27.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bbf94c58e8e0cd6b6f38d8de67acae41b3a515c26169366ab58bdca4a6883bb8"}, + {file = "rpds_py-0.27.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c2a8fed130ce946d5c585eddc7c8eeef0051f58ac80a8ee43bd17835c144c2cc"}, + {file = "rpds_py-0.27.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:037a2361db72ee98d829bc2c5b7cc55598ae0a5e0ec1823a56ea99374cfd73c1"}, + {file = "rpds_py-0.27.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5281ed1cc1d49882f9997981c88df1a22e140ab41df19071222f7e5fc4e72125"}, + {file = "rpds_py-0.27.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fd50659a069c15eef8aa3d64bbef0d69fd27bb4a50c9ab4f17f83a16cbf8905"}, + {file = "rpds_py-0.27.1-cp39-cp39-manylinux_2_31_riscv64.whl", hash = "sha256:c4b676c4ae3921649a15d28ed10025548e9b561ded473aa413af749503c6737e"}, + {file = "rpds_py-0.27.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:079bc583a26db831a985c5257797b2b5d3affb0386e7ff886256762f82113b5e"}, + {file = "rpds_py-0.27.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:4e44099bd522cba71a2c6b97f68e19f40e7d85399de899d66cdb67b32d7cb786"}, + {file = "rpds_py-0.27.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:e202e6d4188e53c6661af813b46c37ca2c45e497fc558bacc1a7630ec2695aec"}, + {file = "rpds_py-0.27.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:f41f814b8eaa48768d1bb551591f6ba45f87ac76899453e8ccd41dba1289b04b"}, + {file = "rpds_py-0.27.1-cp39-cp39-win32.whl", hash = "sha256:9e71f5a087ead99563c11fdaceee83ee982fd39cf67601f4fd66cb386336ee52"}, + {file = "rpds_py-0.27.1-cp39-cp39-win_amd64.whl", hash = "sha256:71108900c9c3c8590697244b9519017a400d9ba26a36c48381b3f64743a44aab"}, + {file = "rpds_py-0.27.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:7ba22cb9693df986033b91ae1d7a979bc399237d45fccf875b76f62bb9e52ddf"}, + {file = "rpds_py-0.27.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:5b640501be9288c77738b5492b3fd3abc4ba95c50c2e41273c8a1459f08298d3"}, + {file = "rpds_py-0.27.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb08b65b93e0c6dd70aac7f7890a9c0938d5ec71d5cb32d45cf844fb8ae47636"}, + {file = "rpds_py-0.27.1-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d7ff07d696a7a38152ebdb8212ca9e5baab56656749f3d6004b34ab726b550b8"}, + {file = "rpds_py-0.27.1-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fb7c72262deae25366e3b6c0c0ba46007967aea15d1eea746e44ddba8ec58dcc"}, + {file = "rpds_py-0.27.1-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7b002cab05d6339716b03a4a3a2ce26737f6231d7b523f339fa061d53368c9d8"}, + {file = "rpds_py-0.27.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23f6b69d1c26c4704fec01311963a41d7de3ee0570a84ebde4d544e5a1859ffc"}, + {file = "rpds_py-0.27.1-pp310-pypy310_pp73-manylinux_2_31_riscv64.whl", hash = "sha256:530064db9146b247351f2a0250b8f00b289accea4596a033e94be2389977de71"}, + {file = "rpds_py-0.27.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7b90b0496570bd6b0321724a330d8b545827c4df2034b6ddfc5f5275f55da2ad"}, + {file = "rpds_py-0.27.1-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:879b0e14a2da6a1102a3fc8af580fc1ead37e6d6692a781bd8c83da37429b5ab"}, + {file = "rpds_py-0.27.1-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:0d807710df3b5faa66c731afa162ea29717ab3be17bdc15f90f2d9f183da4059"}, + {file = "rpds_py-0.27.1-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:3adc388fc3afb6540aec081fa59e6e0d3908722771aa1e37ffe22b220a436f0b"}, + {file = "rpds_py-0.27.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c796c0c1cc68cb08b0284db4229f5af76168172670c74908fdbd4b7d7f515819"}, + {file = "rpds_py-0.27.1-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:cdfe4bb2f9fe7458b7453ad3c33e726d6d1c7c0a72960bcc23800d77384e42df"}, + {file = "rpds_py-0.27.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:8fabb8fd848a5f75a2324e4a84501ee3a5e3c78d8603f83475441866e60b94a3"}, + {file = "rpds_py-0.27.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eda8719d598f2f7f3e0f885cba8646644b55a187762bec091fa14a2b819746a9"}, + {file = "rpds_py-0.27.1-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3c64d07e95606ec402a0a1c511fe003873fa6af630bda59bac77fac8b4318ebc"}, + {file = "rpds_py-0.27.1-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:93a2ed40de81bcff59aabebb626562d48332f3d028ca2036f1d23cbb52750be4"}, + {file = "rpds_py-0.27.1-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:387ce8c44ae94e0ec50532d9cb0edce17311024c9794eb196b90e1058aadeb66"}, + {file = "rpds_py-0.27.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aaf94f812c95b5e60ebaf8bfb1898a7d7cb9c1af5744d4a67fa47796e0465d4e"}, + {file = "rpds_py-0.27.1-pp311-pypy311_pp73-manylinux_2_31_riscv64.whl", hash = "sha256:4848ca84d6ded9b58e474dfdbad4b8bfb450344c0551ddc8d958bf4b36aa837c"}, + {file = "rpds_py-0.27.1-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2bde09cbcf2248b73c7c323be49b280180ff39fadcfe04e7b6f54a678d02a7cf"}, + {file = "rpds_py-0.27.1-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:94c44ee01fd21c9058f124d2d4f0c9dc7634bec93cd4b38eefc385dabe71acbf"}, + {file = "rpds_py-0.27.1-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:df8b74962e35c9249425d90144e721eed198e6555a0e22a563d29fe4486b51f6"}, + {file = "rpds_py-0.27.1-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:dc23e6820e3b40847e2f4a7726462ba0cf53089512abe9ee16318c366494c17a"}, + {file = "rpds_py-0.27.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:aa8933159edc50be265ed22b401125c9eebff3171f570258854dbce3ecd55475"}, + {file = "rpds_py-0.27.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:a50431bf02583e21bf273c71b89d710e7a710ad5e39c725b14e685610555926f"}, + {file = "rpds_py-0.27.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78af06ddc7fe5cc0e967085a9115accee665fb912c22a3f54bad70cc65b05fe6"}, + {file = "rpds_py-0.27.1-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:70d0738ef8fee13c003b100c2fbd667ec4f133468109b3472d249231108283a3"}, + {file = "rpds_py-0.27.1-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e2f6fd8a1cea5bbe599b6e78a6e5ee08db434fc8ffea51ff201c8765679698b3"}, + {file = "rpds_py-0.27.1-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8177002868d1426305bb5de1e138161c2ec9eb2d939be38291d7c431c4712df8"}, + {file = "rpds_py-0.27.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:008b839781d6c9bf3b6a8984d1d8e56f0ec46dc56df61fd669c49b58ae800400"}, + {file = "rpds_py-0.27.1-pp39-pypy39_pp73-manylinux_2_31_riscv64.whl", hash = "sha256:a55b9132bb1ade6c734ddd2759c8dc132aa63687d259e725221f106b83a0e485"}, + {file = "rpds_py-0.27.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a46fdec0083a26415f11d5f236b79fa1291c32aaa4a17684d82f7017a1f818b1"}, + {file = "rpds_py-0.27.1-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:8a63b640a7845f2bdd232eb0d0a4a2dd939bcdd6c57e6bb134526487f3160ec5"}, + {file = "rpds_py-0.27.1-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:7e32721e5d4922deaaf963469d795d5bde6093207c52fec719bd22e5d1bedbc4"}, + {file = "rpds_py-0.27.1-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:2c426b99a068601b5f4623573df7a7c3d72e87533a2dd2253353a03e7502566c"}, + {file = "rpds_py-0.27.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:4fc9b7fe29478824361ead6e14e4f5aed570d477e06088826537e202d25fe859"}, + {file = "rpds_py-0.27.1.tar.gz", hash = "sha256:26a1c73171d10b7acccbded82bf6a586ab8203601e565badc74bbbf8bc5a10f8"}, ] [[package]] @@ -2248,31 +2248,31 @@ pyasn1 = ">=0.1.3" [[package]] name = "ruff" -version = "0.12.10" +version = "0.12.11" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" groups = ["format"] files = [ - {file = "ruff-0.12.10-py3-none-linux_armv6l.whl", hash = "sha256:8b593cb0fb55cc8692dac7b06deb29afda78c721c7ccfed22db941201b7b8f7b"}, - {file = "ruff-0.12.10-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ebb7333a45d56efc7c110a46a69a1b32365d5c5161e7244aaf3aa20ce62399c1"}, - {file = "ruff-0.12.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d59e58586829f8e4a9920788f6efba97a13d1fa320b047814e8afede381c6839"}, - {file = "ruff-0.12.10-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:822d9677b560f1fdeab69b89d1f444bf5459da4aa04e06e766cf0121771ab844"}, - {file = "ruff-0.12.10-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:37b4a64f4062a50c75019c61c7017ff598cb444984b638511f48539d3a1c98db"}, - {file = "ruff-0.12.10-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2c6f4064c69d2542029b2a61d39920c85240c39837599d7f2e32e80d36401d6e"}, - {file = "ruff-0.12.10-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:059e863ea3a9ade41407ad71c1de2badfbe01539117f38f763ba42a1206f7559"}, - {file = "ruff-0.12.10-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1bef6161e297c68908b7218fa6e0e93e99a286e5ed9653d4be71e687dff101cf"}, - {file = "ruff-0.12.10-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4f1345fbf8fb0531cd722285b5f15af49b2932742fc96b633e883da8d841896b"}, - {file = "ruff-0.12.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f68433c4fbc63efbfa3ba5db31727db229fa4e61000f452c540474b03de52a9"}, - {file = "ruff-0.12.10-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:141ce3d88803c625257b8a6debf4a0473eb6eed9643a6189b68838b43e78165a"}, - {file = "ruff-0.12.10-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:f3fc21178cd44c98142ae7590f42ddcb587b8e09a3b849cbc84edb62ee95de60"}, - {file = "ruff-0.12.10-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:7d1a4e0bdfafcd2e3e235ecf50bf0176f74dd37902f241588ae1f6c827a36c56"}, - {file = "ruff-0.12.10-py3-none-musllinux_1_2_i686.whl", hash = "sha256:e67d96827854f50b9e3e8327b031647e7bcc090dbe7bb11101a81a3a2cbf1cc9"}, - {file = "ruff-0.12.10-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:ae479e1a18b439c59138f066ae79cc0f3ee250712a873d00dbafadaad9481e5b"}, - {file = "ruff-0.12.10-py3-none-win32.whl", hash = "sha256:9de785e95dc2f09846c5e6e1d3a3d32ecd0b283a979898ad427a9be7be22b266"}, - {file = "ruff-0.12.10-py3-none-win_amd64.whl", hash = "sha256:7837eca8787f076f67aba2ca559cefd9c5cbc3a9852fd66186f4201b87c1563e"}, - {file = "ruff-0.12.10-py3-none-win_arm64.whl", hash = "sha256:cc138cc06ed9d4bfa9d667a65af7172b47840e1a98b02ce7011c391e54635ffc"}, - {file = "ruff-0.12.10.tar.gz", hash = "sha256:189ab65149d11ea69a2d775343adf5f49bb2426fc4780f65ee33b423ad2e47f9"}, + {file = "ruff-0.12.11-py3-none-linux_armv6l.whl", hash = "sha256:93fce71e1cac3a8bf9200e63a38ac5c078f3b6baebffb74ba5274fb2ab276065"}, + {file = "ruff-0.12.11-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b8e33ac7b28c772440afa80cebb972ffd823621ded90404f29e5ab6d1e2d4b93"}, + {file = "ruff-0.12.11-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d69fb9d4937aa19adb2e9f058bc4fbfe986c2040acb1a4a9747734834eaa0bfd"}, + {file = "ruff-0.12.11-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:411954eca8464595077a93e580e2918d0a01a19317af0a72132283e28ae21bee"}, + {file = "ruff-0.12.11-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6a2c0a2e1a450f387bf2c6237c727dd22191ae8c00e448e0672d624b2bbd7fb0"}, + {file = "ruff-0.12.11-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ca4c3a7f937725fd2413c0e884b5248a19369ab9bdd850b5781348ba283f644"}, + {file = "ruff-0.12.11-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:4d1df0098124006f6a66ecf3581a7f7e754c4df7644b2e6704cd7ca80ff95211"}, + {file = "ruff-0.12.11-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5a8dd5f230efc99a24ace3b77e3555d3fbc0343aeed3fc84c8d89e75ab2ff793"}, + {file = "ruff-0.12.11-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4dc75533039d0ed04cd33fb8ca9ac9620b99672fe7ff1533b6402206901c34ee"}, + {file = "ruff-0.12.11-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4fc58f9266d62c6eccc75261a665f26b4ef64840887fc6cbc552ce5b29f96cc8"}, + {file = "ruff-0.12.11-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:5a0113bd6eafd545146440225fe60b4e9489f59eb5f5f107acd715ba5f0b3d2f"}, + {file = "ruff-0.12.11-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:0d737b4059d66295c3ea5720e6efc152623bb83fde5444209b69cd33a53e2000"}, + {file = "ruff-0.12.11-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:916fc5defee32dbc1fc1650b576a8fed68f5e8256e2180d4d9855aea43d6aab2"}, + {file = "ruff-0.12.11-py3-none-musllinux_1_2_i686.whl", hash = "sha256:c984f07d7adb42d3ded5be894fb4007f30f82c87559438b4879fe7aa08c62b39"}, + {file = "ruff-0.12.11-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e07fbb89f2e9249f219d88331c833860489b49cdf4b032b8e4432e9b13e8a4b9"}, + {file = "ruff-0.12.11-py3-none-win32.whl", hash = "sha256:c792e8f597c9c756e9bcd4d87cf407a00b60af77078c96f7b6366ea2ce9ba9d3"}, + {file = "ruff-0.12.11-py3-none-win_amd64.whl", hash = "sha256:a3283325960307915b6deb3576b96919ee89432ebd9c48771ca12ee8afe4a0fd"}, + {file = "ruff-0.12.11-py3-none-win_arm64.whl", hash = "sha256:bae4d6e6a2676f8fb0f98b74594a048bae1b944aab17e9f5d504062303c6dbea"}, + {file = "ruff-0.12.11.tar.gz", hash = "sha256:c6b09ae8426a65bbee5425b9d0b82796dbb07cb1af045743c79bfb163001165d"}, ] [[package]] @@ -2681,4 +2681,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = "^3.10" -content-hash = "d2b7ec1b86f8d6b04f86dc539454ac30b58564c81f44ec78b52c69b6ffac3c00" +content-hash = "501c997762ac2a88b47a1ebc2ac05ea362dc2fb7f29aeb93f65f9655ea3ca087" diff --git a/pyproject.toml b/pyproject.toml index abd8a941b2..305d86c88c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ requires-poetry = ">=2.0.0" [tool.poetry.dependencies] python = "^3.10" ops = "^2.23.1" -boto3 = "^1.40.17" +boto3 = "^1.40.21" pgconnstr = "^1.0.1" requests = "^2.32.5" tenacity = "^9.1.2" @@ -40,7 +40,7 @@ opentelemetry-exporter-otlp-proto-http = "1.21.0" optional = true [tool.poetry.group.format.dependencies] -ruff = "^0.12.10" +ruff = "^0.12.11" [tool.poetry.group.lint] optional = true @@ -52,7 +52,7 @@ codespell = "^2.4.1" optional = true [tool.poetry.group.unit.dependencies] -coverage = {extras = ["toml"], version = "^7.10.5"} +coverage = {extras = ["toml"], version = "^7.10.6"} pytest = "^8.4.1" pytest-asyncio = "*" parameterized = "^0.9.0" From 2010ac34050578879604d5ce69a91ccf56814899 Mon Sep 17 00:00:00 2001 From: Dragomir Penev <6687393+dragomirp@users.noreply.github.com> Date: Wed, 10 Sep 2025 13:37:38 +0300 Subject: [PATCH 092/112] Add back raft encryption check (#1146) --- src/cluster.py | 8 +++++++- src/upgrade.py | 10 +++++++++- tests/unit/test_cluster.py | 5 +++++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/cluster.py b/src/cluster.py index b3212b6b7e..3e09123480 100644 --- a/src/cluster.py +++ b/src/cluster.py @@ -459,7 +459,7 @@ def is_creating_backup(self) -> bool: for member in r.json()["members"] ) - def is_replication_healthy(self) -> bool: + def is_replication_healthy(self, raft_encryption: bool = False) -> bool: """Return whether the replication is healthy.""" try: for attempt in Retrying(stop=stop_after_delay(60), wait=wait_fixed(3)): @@ -477,6 +477,12 @@ def is_replication_healthy(self) -> bool: auth=self._patroni_auth, timeout=PATRONI_TIMEOUT, ) + # If raft is getting encrypted some of the calls will fail + if member_status.status_code == 503 and raft_encryption: + logger.warning( + f"Failed replication check for {members_ip} during raft encryption" + ) + continue if member_status.status_code != 200: logger.debug( f"Failed replication check for {members_ip} with code {member_status.status_code}" diff --git a/src/upgrade.py b/src/upgrade.py index 7728af28b0..ed430e0cf4 100644 --- a/src/upgrade.py +++ b/src/upgrade.py @@ -157,6 +157,14 @@ def _on_upgrade_granted(self, event: UpgradeGrantedEvent) -> None: self.set_unit_failed() return + raft_encryption = ( + int( + json.loads(self.peer_relation.data[self.charm.app].get("dependencies", "{}")) + .get("charm", {}) + .get("version", 0) + ) + < 3 + ) self.charm._setup_exporter() self.charm.backup.start_stop_pgbackrest_service() @@ -178,7 +186,7 @@ def _on_upgrade_granted(self, event: UpgradeGrantedEvent) -> None: not self.charm._patroni.member_started or self.charm.unit.name.replace("/", "-") not in self.charm._patroni.cluster_members - or not self.charm._patroni.is_replication_healthy() + or not self.charm._patroni.is_replication_healthy(raft_encryption) ): logger.debug( "Instance not yet back in the cluster." diff --git a/tests/unit/test_cluster.py b/tests/unit/test_cluster.py index 3ee9ba4bf7..e46dde3c31 100644 --- a/tests/unit/test_cluster.py +++ b/tests/unit/test_cluster.py @@ -267,6 +267,11 @@ def test_is_replication_healthy(peers_ips, patroni): ] assert not patroni.is_replication_healthy() + # Test ignoring errors in case of raft encryption. + _get.side_effect = None + _get.return_value.status_code = 503 + assert patroni.is_replication_healthy(True) + def test_is_member_isolated(peers_ips, patroni): with ( From edabe0301e14fc89252b03317e8b3bcf9cfbb402 Mon Sep 17 00:00:00 2001 From: Alex Lutay <1928266+taurus-forever@users.noreply.github.com> Date: Fri, 12 Sep 2025 12:53:50 +0200 Subject: [PATCH 093/112] DPE-8299 Bump disk cleanup timeout 1=>10 (#1148) --- .github/workflows/integration_test.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/integration_test.yaml b/.github/workflows/integration_test.yaml index 3ac1b994db..b730374b2b 100644 --- a/.github/workflows/integration_test.yaml +++ b/.github/workflows/integration_test.yaml @@ -84,10 +84,10 @@ jobs: needs: - collect-integration-tests runs-on: ${{ matrix.job.runner }} - timeout-minutes: 217 # Sum of steps `timeout-minutes` + 5 + timeout-minutes: 226 # Sum of steps `timeout-minutes` + 5 steps: - name: Free up disk space - timeout-minutes: 1 + timeout-minutes: 10 run: | printf '\nDisk usage before cleanup\n' df --human-readable From 0b2aa925f79db949a5473b64ed1972363ddceec9 Mon Sep 17 00:00:00 2001 From: Dragomir Penev <6687393+dragomirp@users.noreply.github.com> Date: Mon, 15 Sep 2025 15:21:41 +0300 Subject: [PATCH 094/112] [DPE-8005] Handle empty region (#1157) * Handle empty region * Handle invalid stanza name --- src/backups.py | 57 ++++++++++++++------------ templates/pgbackrest.conf.j2 | 4 ++ tests/integration/conftest.py | 2 +- tests/integration/test_backups_ceph.py | 21 ---------- tests/integration/test_backups_gcp.py | 16 ++++++++ tests/unit/test_backups.py | 25 +++++++++-- 6 files changed, 73 insertions(+), 52 deletions(-) diff --git a/src/backups.py b/src/backups.py index d4502c01c8..0f16aa8093 100644 --- a/src/backups.py +++ b/src/backups.py @@ -16,13 +16,12 @@ from pathlib import Path from subprocess import TimeoutExpired, run -import boto3 as boto3 -import botocore -from botocore.exceptions import ClientError, ParamValidationError, SSLError -from charms.data_platform_libs.v0.s3 import ( - CredentialsChangedEvent, - S3Requirer, -) +from boto3.session import Session +from botocore.client import Config +from botocore.exceptions import ClientError, ConnectTimeoutError, ParamValidationError, SSLError +from botocore.loaders import create_loader +from botocore.regions import EndpointResolver +from charms.data_platform_libs.v0.s3 import CredentialsChangedEvent, S3Requirer from charms.operator_libs_linux.v2 import snap from jinja2 import Template from ops.charm import ActionEvent, HookEvent @@ -101,16 +100,18 @@ def _tls_ca_chain_filename(self) -> str: return "" def _get_s3_session_resource(self, s3_parameters: dict): - session = boto3.session.Session( - aws_access_key_id=s3_parameters["access-key"], - aws_secret_access_key=s3_parameters["secret-key"], - region_name=s3_parameters["region"], - ) + kwargs = { + "aws_access_key_id": s3_parameters["access-key"], + "aws_secret_access_key": s3_parameters["secret-key"], + } + if "region" in s3_parameters: + kwargs["region_name"] = s3_parameters["region"] + session = Session(**kwargs) return session.resource( "s3", endpoint_url=self._construct_endpoint(s3_parameters), verify=(self._tls_ca_chain_filename or None), - config=botocore.client.Config( + config=Config( # https://github.com/boto/boto3/issues/4400#issuecomment-2600742103 request_checksum_calculation="when_required", response_checksum_validation="when_required", @@ -208,13 +209,16 @@ def can_use_s3_repository(self) -> tuple[bool, str | None]: else: if return_code != 0: - logger.error(stderr) + logger.error(f"Failed to run pgbackrest: {stderr}") return False, FAILED_TO_INITIALIZE_STANZA_ERROR_MESSAGE for stanza in json.loads(stdout): - if stanza.get("name") != self.stanza_name: + if (stanza_name := stanza.get("name")) and stanza_name == "[invalid]": + logger.error("Invalid stanza name from s3") + return False, FAILED_TO_INITIALIZE_STANZA_ERROR_MESSAGE + if stanza_name != self.stanza_name: logger.debug( - f"can_use_s3_repository: incompatible stanza name s3={stanza.get('name', '')}, local={self.stanza_name}" + f"can_use_s3_repository: incompatible stanza name s3={stanza_name or ''}, local={self.stanza_name}" ) return False, ANOTHER_CLUSTER_REPOSITORY_ERROR_MESSAGE @@ -255,12 +259,12 @@ def _construct_endpoint(self, s3_parameters: dict) -> str: endpoint = s3_parameters["endpoint"] # Load endpoints data. - loader = botocore.loaders.create_loader() + loader = create_loader() data = loader.load_data("endpoints") # Construct the endpoint using the region. - resolver = botocore.regions.EndpointResolver(data) - endpoint_data = resolver.construct_endpoint("s3", s3_parameters["region"]) + resolver = EndpointResolver(data) + endpoint_data = resolver.construct_endpoint("s3", s3_parameters.get("region")) # Use the built endpoint if it is an AWS endpoint. if endpoint_data and endpoint.endswith(endpoint_data["dnsSuffix"]): @@ -274,7 +278,7 @@ def _create_bucket_if_not_exists(self) -> None: return bucket_name = s3_parameters["bucket"] - region = s3_parameters.get("region") + region = s3_parameters.get("region", "") try: s3 = self._get_s3_session_resource(s3_parameters) @@ -286,7 +290,7 @@ def _create_bucket_if_not_exists(self) -> None: bucket.meta.client.head_bucket(Bucket=bucket_name) logger.info("Bucket %s exists.", bucket_name) exists = True - except botocore.exceptions.ConnectTimeoutError as e: + except ConnectTimeoutError as e: # Re-raise the error if the connection timeouts, so the user has the possibility to # fix network issues and call juju resolve to re-trigger the hook that calls # this method. @@ -647,10 +651,10 @@ def _initialise_stanza(self, event: HookEvent) -> bool: raise Exception(stderr) except TimeoutError as e: raise e - except Exception as e: + except Exception: # If the check command doesn't succeed, remove the stanza name # and rollback the configuration. - logger.exception(e) + logger.exception("Failed to initialise stanza:") self._s3_initialization_set_failure(FAILED_TO_INITIALIZE_STANZA_ERROR_MESSAGE) return False @@ -971,8 +975,8 @@ def _run_backup( else: try: backup_id = list(self._list_backups(show_failed=True).keys())[-1] - except ListBackupsError as e: - logger.exception(e) + except ListBackupsError: + logger.exception(error_message) error_message = "Failed to retrieve backup id" logger.error(f"Backup failed: {error_message}") event.fail(error_message) @@ -1301,7 +1305,6 @@ def _retrieve_s3_parameters(self) -> tuple[dict, list[str]]: # Add some sensible defaults (as expected by the code) for missing optional parameters s3_parameters.setdefault("endpoint", "https://s3.amazonaws.com") - s3_parameters.setdefault("region") s3_parameters.setdefault("path", "") s3_parameters.setdefault("s3-uri-style", "host") s3_parameters.setdefault("delete-older-than-days", "9999999") @@ -1419,7 +1422,7 @@ def _read_content_from_s3(self, s3_path: str, s3_parameters: dict) -> str | None with BytesIO() as buf: bucket.download_fileobj(processed_s3_path, buf) return buf.getvalue().decode("utf-8") - except botocore.exceptions.ClientError as e: + except ClientError as e: if e.response["Error"]["Code"] == "404": logger.info( f"No such object to read from S3 bucket={bucket_name}, path={processed_s3_path}" diff --git a/templates/pgbackrest.conf.j2 b/templates/pgbackrest.conf.j2 index bf43b83516..922998d7b9 100644 --- a/templates/pgbackrest.conf.j2 +++ b/templates/pgbackrest.conf.j2 @@ -8,7 +8,11 @@ repo1-retention-full={{ retention_full }} repo1-retention-history=365 repo1-type=s3 repo1-path={{ path }} +{%- if region %} repo1-s3-region={{ region }} +{% else %} +repo1-s3-region="" +{%- endif %} repo1-s3-endpoint={{ endpoint }} repo1-s3-bucket={{ bucket }} repo1-s3-uri-style={{ s3_uri_style }} diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py index e644af55cd..c469a04eb7 100644 --- a/tests/integration/conftest.py +++ b/tests/integration/conftest.py @@ -42,7 +42,7 @@ def get_cloud_config(cloud: str) -> tuple[dict[str, str], dict[str, str]]: "endpoint": "https://storage.googleapis.com", "bucket": "data-charms-testing", "path": f"/postgresql-k8s/{uuid.uuid1()}", - "region": "", + "region": "us-east-1", }, { "access-key": os.environ["GCP_ACCESS_KEY"], "secret-key": os.environ["GCP_SECRET_KEY"], diff --git a/tests/integration/test_backups_ceph.py b/tests/integration/test_backups_ceph.py index 57f1d268af..3c4c74c43f 100644 --- a/tests/integration/test_backups_ceph.py +++ b/tests/integration/test_backups_ceph.py @@ -7,10 +7,7 @@ import os import socket import subprocess -import time -import boto3 -import botocore.exceptions import pytest from pytest_operator.plugin import OpsTest @@ -139,24 +136,6 @@ def microceph(): key = json.loads(output)["keys"][0] key_id = key["access_key"] secret_key = key["secret_key"] - logger.info("Creating microceph bucket") - for attempt in range(3): - try: - boto3.client( - "s3", - endpoint_url=f"https://{host_ip}", - aws_access_key_id=key_id, - aws_secret_access_key=secret_key, - verify="./ca.crt", - ).create_bucket(Bucket=_BUCKET) - except botocore.exceptions.EndpointConnectionError: - if attempt == 2: - raise - # microceph is not ready yet - logger.info("Unable to connect to microceph via S3. Retrying") - time.sleep(1) - else: - break logger.info("Set up microceph") return ConnectionInformation(key_id, secret_key, _BUCKET) diff --git a/tests/integration/test_backups_gcp.py b/tests/integration/test_backups_gcp.py index 3ec8979ec9..4ebc51e432 100644 --- a/tests/integration/test_backups_gcp.py +++ b/tests/integration/test_backups_gcp.py @@ -24,6 +24,7 @@ FAILED_TO_ACCESS_CREATE_BUCKET_ERROR_MESSAGE = ( "failed to access/create the bucket, check your S3 settings" ) +FAILED_TO_INITIALIZE_STANZA_ERROR_MESSAGE = "failed to initialize stanza, check your S3 settings" S3_INTEGRATOR_APP_NAME = "s3-integrator" if juju_major_version < 3: tls_certificates_app_name = "tls-certificates-operator" @@ -215,3 +216,18 @@ async def test_invalid_config_and_recovery_after_fixing_it( await ops_test.model.wait_for_idle( apps=[database_app_name, S3_INTEGRATOR_APP_NAME], status="active" ) + + +async def test_block_on_missing_region( + ops_test: OpsTest, gcp_cloud_configs: tuple[dict, dict] +) -> None: + await ops_test.model.applications[S3_INTEGRATOR_APP_NAME].set_config({ + **gcp_cloud_configs[0], + "region": "", + }) + database_app_name = f"new-{DATABASE_APP_NAME}" + logger.info("waiting for the database charm to become blocked") + unit = ops_test.model.units.get(f"{database_app_name}/0") + await ops_test.model.block_until( + lambda: unit.workload_status_message == FAILED_TO_INITIALIZE_STANZA_ERROR_MESSAGE + ) diff --git a/tests/unit/test_backups.py b/tests/unit/test_backups.py index 1942a20fdc..18d5b73e0e 100644 --- a/tests/unit/test_backups.py +++ b/tests/unit/test_backups.py @@ -240,6 +240,26 @@ def test_can_use_s3_repository(harness): "", ) + # Invalid stanza name + pgbackrest_info_other_cluster_name_backup_output = ( + 0, + '[{"db": [{"system-id": "12345"}], "name": "[invalid]"}]', + "", + ) + same_instance_system_identifier_output = ( + 0, + "Database system identifier: 12345", + "", + ) + _execute_command.side_effect = [ + pgbackrest_info_other_cluster_name_backup_output, + same_instance_system_identifier_output, + ] + assert harness.charm.backup.can_use_s3_repository() == ( + False, + FAILED_TO_INITIALIZE_STANZA_ERROR_MESSAGE, + ) + # Test when the cluster system id can be retrieved, but it's different from the stanza system id. pgbackrest_info_other_cluster_system_id_backup_output = ( 0, @@ -343,7 +363,7 @@ def test_create_bucket_if_not_exists(harness, tls_ca_chain_filename): new_callable=PropertyMock(return_value=tls_ca_chain_filename), ) as _tls_ca_chain_filename, patch("charm.PostgreSQLBackups._retrieve_s3_parameters") as _retrieve_s3_parameters, - patch("backups.botocore.client.Config") as _config, + patch("backups.Config") as _config, ): # Test when there are missing S3 parameters. _retrieve_s3_parameters.return_value = ([], ["bucket", "access-key", "secret-key"]) @@ -1835,7 +1855,6 @@ def test_retrieve_s3_parameters(harness): "delete-older-than-days": "9999999", "endpoint": "https://s3.amazonaws.com", "path": "/", - "region": None, "s3-uri-style": "host", "secret-key": "test-secret-key", }, @@ -1962,7 +1981,7 @@ def test_upload_content_to_s3(harness, tls_ca_chain_filename): patch("tempfile.NamedTemporaryFile") as _named_temporary_file, patch("charm.PostgreSQLBackups._construct_endpoint") as _construct_endpoint, patch("boto3.session.Session.resource") as _resource, - patch("backups.botocore.client.Config") as _config, + patch("backups.Config") as _config, patch( "charm.PostgreSQLBackups._tls_ca_chain_filename", new_callable=PropertyMock(return_value=tls_ca_chain_filename), From d183bc77b48cbb99c683108ebdcadb847235571a Mon Sep 17 00:00:00 2001 From: Alex Lutay <1928266+taurus-forever@users.noreply.github.com> Date: Tue, 16 Sep 2025 16:04:39 +0200 Subject: [PATCH 095/112] DPE-8296 Bump PostgreSQL to 14.19 (#1147) --- src/constants.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/constants.py b/src/constants.py index 564505fe8f..29cecb93d0 100644 --- a/src/constants.py +++ b/src/constants.py @@ -35,7 +35,7 @@ SNAP_PACKAGES = [ ( POSTGRESQL_SNAP_NAME, - {"revision": {"aarch64": "221", "x86_64": "220"}}, + {"revision": {"aarch64": "230", "x86_64": "229"}}, ) ] From 7542643d1d6e8328632e25dab8808fa7812b2ec3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 17 Sep 2025 14:40:05 +0300 Subject: [PATCH 096/112] Lock file maintenance Python dependencies (#1143) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- poetry.lock | 455 +++++++++++++++++++++++++++++-------------------- pyproject.toml | 10 +- 2 files changed, 276 insertions(+), 189 deletions(-) diff --git a/poetry.lock b/poetry.lock index cb5a966c59..09b2ca2fbb 100644 --- a/poetry.lock +++ b/poetry.lock @@ -233,34 +233,34 @@ typecheck = ["mypy"] [[package]] name = "boto3" -version = "1.40.21" +version = "1.40.31" description = "The AWS SDK for Python" optional = false python-versions = ">=3.9" groups = ["main", "integration"] files = [ - {file = "boto3-1.40.21-py3-none-any.whl", hash = "sha256:3772fb828864d3b7046c8bdf2f4860aaca4a79f25b7b060206c6a5f4944ea7f9"}, - {file = "boto3-1.40.21.tar.gz", hash = "sha256:876ccc0b25517b992bd27976282510773a11ebc771aa5b836a238ea426c82187"}, + {file = "boto3-1.40.31-py3-none-any.whl", hash = "sha256:61d5f9975c54ff919a24ff9d472c6c09c8a443a083fe56d30c04fc22d22ac42b"}, + {file = "boto3-1.40.31.tar.gz", hash = "sha256:8c5f1270f09431694412f326cfb5ac9786d41ea3bc6ac54cbb7161d40afc660d"}, ] [package.dependencies] -botocore = ">=1.40.21,<1.41.0" +botocore = ">=1.40.31,<1.41.0" jmespath = ">=0.7.1,<2.0.0" -s3transfer = ">=0.13.0,<0.14.0" +s3transfer = ">=0.14.0,<0.15.0" [package.extras] crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.40.21" +version = "1.40.31" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">=3.9" groups = ["main", "integration"] files = [ - {file = "botocore-1.40.21-py3-none-any.whl", hash = "sha256:574ecf9b68c1721650024a27e00e0080b6f141c281ebfce49e0d302969270ef4"}, - {file = "botocore-1.40.21.tar.gz", hash = "sha256:f77e9c199df0252b14ea739a9ac99723940f6bde90f4c2e7802701553a62827b"}, + {file = "botocore-1.40.31-py3-none-any.whl", hash = "sha256:4033a00f8c6a4b5c3acb30af9283963123917227a437e5fc165189d07bd3cf8a"}, + {file = "botocore-1.40.31.tar.gz", hash = "sha256:9496b91bbe40ed01d341dc8f6ff0492d7f546e80f1a862b00ec5bc9045fa3324"}, ] [package.dependencies] @@ -297,84 +297,101 @@ files = [ [[package]] name = "cffi" -version = "1.17.1" +version = "2.0.0" description = "Foreign Function Interface for Python calling C code." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["charm-libs", "integration"] -files = [ - {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"}, - {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"}, - {file = "cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382"}, - {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702"}, - {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3"}, - {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6"}, - {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17"}, - {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8"}, - {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e"}, - {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be"}, - {file = "cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c"}, - {file = "cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15"}, - {file = "cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401"}, - {file = "cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf"}, - {file = "cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4"}, - {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41"}, - {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1"}, - {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6"}, - {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d"}, - {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6"}, - {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f"}, - {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b"}, - {file = "cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655"}, - {file = "cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0"}, - {file = "cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4"}, - {file = "cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c"}, - {file = "cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36"}, - {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5"}, - {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff"}, - {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99"}, - {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93"}, - {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3"}, - {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8"}, - {file = "cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65"}, - {file = "cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903"}, - {file = "cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e"}, - {file = "cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2"}, - {file = "cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3"}, - {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683"}, - {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5"}, - {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4"}, - {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd"}, - {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed"}, - {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9"}, - {file = "cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d"}, - {file = "cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a"}, - {file = "cffi-1.17.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b"}, - {file = "cffi-1.17.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964"}, - {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9"}, - {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc"}, - {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c"}, - {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1"}, - {file = "cffi-1.17.1-cp38-cp38-win32.whl", hash = "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8"}, - {file = "cffi-1.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1"}, - {file = "cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16"}, - {file = "cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36"}, - {file = "cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8"}, - {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576"}, - {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87"}, - {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0"}, - {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3"}, - {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595"}, - {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a"}, - {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e"}, - {file = "cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7"}, - {file = "cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662"}, - {file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"}, -] -markers = {charm-libs = "platform_python_implementation != \"PyPy\""} +markers = "platform_python_implementation != \"PyPy\"" +files = [ + {file = "cffi-2.0.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44"}, + {file = "cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49"}, + {file = "cffi-2.0.0-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c"}, + {file = "cffi-2.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb"}, + {file = "cffi-2.0.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5eda85d6d1879e692d546a078b44251cdd08dd1cfb98dfb77b670c97cee49ea0"}, + {file = "cffi-2.0.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9332088d75dc3241c702d852d4671613136d90fa6881da7d770a483fd05248b4"}, + {file = "cffi-2.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453"}, + {file = "cffi-2.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495"}, + {file = "cffi-2.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5"}, + {file = "cffi-2.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb"}, + {file = "cffi-2.0.0-cp310-cp310-win32.whl", hash = "sha256:1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a"}, + {file = "cffi-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739"}, + {file = "cffi-2.0.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe"}, + {file = "cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c"}, + {file = "cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92"}, + {file = "cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93"}, + {file = "cffi-2.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5"}, + {file = "cffi-2.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664"}, + {file = "cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26"}, + {file = "cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9"}, + {file = "cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414"}, + {file = "cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743"}, + {file = "cffi-2.0.0-cp311-cp311-win32.whl", hash = "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5"}, + {file = "cffi-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5"}, + {file = "cffi-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d"}, + {file = "cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d"}, + {file = "cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c"}, + {file = "cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe"}, + {file = "cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062"}, + {file = "cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e"}, + {file = "cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037"}, + {file = "cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba"}, + {file = "cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94"}, + {file = "cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187"}, + {file = "cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18"}, + {file = "cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5"}, + {file = "cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6"}, + {file = "cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb"}, + {file = "cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca"}, + {file = "cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b"}, + {file = "cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b"}, + {file = "cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2"}, + {file = "cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3"}, + {file = "cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26"}, + {file = "cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c"}, + {file = "cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b"}, + {file = "cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27"}, + {file = "cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75"}, + {file = "cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91"}, + {file = "cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5"}, + {file = "cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13"}, + {file = "cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b"}, + {file = "cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c"}, + {file = "cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef"}, + {file = "cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775"}, + {file = "cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205"}, + {file = "cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1"}, + {file = "cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f"}, + {file = "cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25"}, + {file = "cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad"}, + {file = "cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9"}, + {file = "cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d"}, + {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c"}, + {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8"}, + {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc"}, + {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592"}, + {file = "cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512"}, + {file = "cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4"}, + {file = "cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e"}, + {file = "cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6"}, + {file = "cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9"}, + {file = "cffi-2.0.0-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:fe562eb1a64e67dd297ccc4f5addea2501664954f2692b69a76449ec7913ecbf"}, + {file = "cffi-2.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:de8dad4425a6ca6e4e5e297b27b5c824ecc7581910bf9aee86cb6835e6812aa7"}, + {file = "cffi-2.0.0-cp39-cp39-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:4647afc2f90d1ddd33441e5b0e85b16b12ddec4fca55f0d9671fef036ecca27c"}, + {file = "cffi-2.0.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3f4d46d8b35698056ec29bca21546e1551a205058ae1a181d871e278b0b28165"}, + {file = "cffi-2.0.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:e6e73b9e02893c764e7e8d5bb5ce277f1a009cd5243f8228f75f842bf937c534"}, + {file = "cffi-2.0.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:cb527a79772e5ef98fb1d700678fe031e353e765d1ca2d409c92263c6d43e09f"}, + {file = "cffi-2.0.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:61d028e90346df14fedc3d1e5441df818d095f3b87d286825dfcbd6459b7ef63"}, + {file = "cffi-2.0.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0f6084a0ea23d05d20c3edcda20c3d006f9b6f3fefeac38f59262e10cef47ee2"}, + {file = "cffi-2.0.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1cd13c99ce269b3ed80b417dcd591415d3372bcac067009b6e0f59c7d4015e65"}, + {file = "cffi-2.0.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:89472c9762729b5ae1ad974b777416bfda4ac5642423fa93bd57a09204712322"}, + {file = "cffi-2.0.0-cp39-cp39-win32.whl", hash = "sha256:2081580ebb843f759b9f617314a24ed5738c51d2aee65d31e02f6f7a2b97707a"}, + {file = "cffi-2.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:b882b3df248017dba09d6b16defe9b5c407fe32fc7c65a9c69798e6175601be9"}, + {file = "cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529"}, +] [package.dependencies] -pycparser = "*" +pycparser = {version = "*", markers = "implementation_name != \"PyPy\""} [[package]] name = "charset-normalizer" @@ -889,6 +906,7 @@ description = "IPython: Productive Interactive Computing" optional = false python-versions = ">=3.10" groups = ["integration"] +markers = "python_version < \"3.14\" or platform_python_implementation == \"PyPy\"" files = [ {file = "ipython-8.37.0-py3-none-any.whl", hash = "sha256:ed87326596b878932dbcb171e3e698845434d8c61b8d8cd474bf663041a9dcf2"}, {file = "ipython-8.37.0.tar.gz", hash = "sha256:ca815841e1a41a1e6b73a0b08f3038af9b2252564d01fc405356d34033012216"}, @@ -921,6 +939,55 @@ qtconsole = ["qtconsole"] test = ["packaging", "pickleshare", "pytest", "pytest-asyncio (<0.22)", "testpath"] test-extra = ["curio", "ipython[test]", "jupyter_ai", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.23)", "pandas", "trio"] +[[package]] +name = "ipython" +version = "9.5.0" +description = "IPython: Productive Interactive Computing" +optional = false +python-versions = ">=3.11" +groups = ["integration"] +markers = "platform_python_implementation != \"PyPy\" and python_version >= \"3.14\"" +files = [ + {file = "ipython-9.5.0-py3-none-any.whl", hash = "sha256:88369ffa1d5817d609120daa523a6da06d02518e582347c29f8451732a9c5e72"}, + {file = "ipython-9.5.0.tar.gz", hash = "sha256:129c44b941fe6d9b82d36fc7a7c18127ddb1d6f02f78f867f402e2e3adde3113"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "sys_platform == \"win32\""} +decorator = "*" +ipython-pygments-lexers = "*" +jedi = ">=0.16" +matplotlib-inline = "*" +pexpect = {version = ">4.3", markers = "sys_platform != \"win32\" and sys_platform != \"emscripten\""} +prompt_toolkit = ">=3.0.41,<3.1.0" +pygments = ">=2.4.0" +stack_data = "*" +traitlets = ">=5.13.0" + +[package.extras] +all = ["ipython[doc,matplotlib,test,test-extra]"] +black = ["black"] +doc = ["docrepr", "exceptiongroup", "intersphinx_registry", "ipykernel", "ipython[test]", "matplotlib", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "sphinx_toml (==0.0.4)", "typing_extensions"] +matplotlib = ["matplotlib"] +test = ["packaging", "pytest", "pytest-asyncio", "testpath"] +test-extra = ["curio", "ipykernel", "ipython[test]", "jupyter_ai", "matplotlib (!=3.2.0)", "nbclient", "nbformat", "numpy (>=1.23)", "pandas", "trio"] + +[[package]] +name = "ipython-pygments-lexers" +version = "1.1.1" +description = "Defines a variety of Pygments lexers for highlighting IPython code." +optional = false +python-versions = ">=3.8" +groups = ["integration"] +markers = "platform_python_implementation != \"PyPy\" and python_version >= \"3.14\"" +files = [ + {file = "ipython_pygments_lexers-1.1.1-py3-none-any.whl", hash = "sha256:a9462224a505ade19a605f71f8fa63c2048833ce50abc86768a0d81d876dc81c"}, + {file = "ipython_pygments_lexers-1.1.1.tar.gz", hash = "sha256:09c0138009e56b6854f9535736f4171d855c8c08a563a0dcd8022f78355c7e81"}, +] + +[package.dependencies] +pygments = "*" + [[package]] name = "jedi" version = "0.19.2" @@ -995,14 +1062,14 @@ format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339- [[package]] name = "jsonschema-specifications" -version = "2025.4.1" +version = "2025.9.1" description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry" optional = false python-versions = ">=3.9" groups = ["charm-libs", "unit"] files = [ - {file = "jsonschema_specifications-2025.4.1-py3-none-any.whl", hash = "sha256:4653bffbd6584f7de83a67e0d620ef16900b390ddc7939d56684d6c81e33f1af"}, - {file = "jsonschema_specifications-2025.4.1.tar.gz", hash = "sha256:630159c9f4dbea161a6a2205c3011cc4f18ff381b189fff48bb39b9bf26ae608"}, + {file = "jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe"}, + {file = "jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d"}, ] [package.dependencies] @@ -1468,14 +1535,14 @@ testing = ["coverage", "pytest", "pytest-benchmark"] [[package]] name = "poetry-core" -version = "2.1.3" +version = "2.2.0" description = "Poetry PEP 517 Build Backend" optional = false python-versions = "<4.0,>=3.9" groups = ["charm-libs"] files = [ - {file = "poetry_core-2.1.3-py3-none-any.whl", hash = "sha256:2c704f05016698a54ca1d327f46ce2426d72eaca6ff614132c8477c292266771"}, - {file = "poetry_core-2.1.3.tar.gz", hash = "sha256:0522a015477ed622c89aad56a477a57813cace0c8e7ff2a2906b7ef4a2e296a4"}, + {file = "poetry_core-2.2.0-py3-none-any.whl", hash = "sha256:0edea81d07e88cbd407369eef753c722da8ff1338f554788dc04636e756318fc"}, + {file = "poetry_core-2.2.0.tar.gz", hash = "sha256:b4033b71b99717a942030e074fec7e3082e5fde7a8ed10f02cd2413bdf940b1f"}, ] [[package]] @@ -1693,75 +1760,75 @@ pyasn1 = ">=0.6.1,<0.7.0" [[package]] name = "pycparser" -version = "2.22" +version = "2.23" description = "C parser in Python" optional = false python-versions = ">=3.8" groups = ["charm-libs", "integration"] +markers = "platform_python_implementation != \"PyPy\" and implementation_name != \"PyPy\"" files = [ - {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, - {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, + {file = "pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934"}, + {file = "pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2"}, ] -markers = {charm-libs = "platform_python_implementation != \"PyPy\""} [[package]] name = "pydantic" -version = "1.10.22" +version = "1.10.23" description = "Data validation and settings management using python type hints" optional = false python-versions = ">=3.7" groups = ["main", "charm-libs"] files = [ - {file = "pydantic-1.10.22-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:57889565ccc1e5b7b73343329bbe6198ebc472e3ee874af2fa1865cfe7048228"}, - {file = "pydantic-1.10.22-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:90729e22426de79bc6a3526b4c45ec4400caf0d4f10d7181ba7f12c01bb3897d"}, - {file = "pydantic-1.10.22-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8684d347f351554ec94fdcb507983d3116dc4577fb8799fed63c65869a2d10"}, - {file = "pydantic-1.10.22-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c8dad498ceff2d9ef1d2e2bc6608f5b59b8e1ba2031759b22dfb8c16608e1802"}, - {file = "pydantic-1.10.22-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fac529cc654d4575cf8de191cce354b12ba705f528a0a5c654de6d01f76cd818"}, - {file = "pydantic-1.10.22-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:4148232aded8dd1dd13cf910a01b32a763c34bd79a0ab4d1ee66164fcb0b7b9d"}, - {file = "pydantic-1.10.22-cp310-cp310-win_amd64.whl", hash = "sha256:ece68105d9e436db45d8650dc375c760cc85a6793ae019c08769052902dca7db"}, - {file = "pydantic-1.10.22-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8e530a8da353f791ad89e701c35787418605d35085f4bdda51b416946070e938"}, - {file = "pydantic-1.10.22-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:654322b85642e9439d7de4c83cb4084ddd513df7ff8706005dada43b34544946"}, - {file = "pydantic-1.10.22-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8bece75bd1b9fc1c32b57a32831517943b1159ba18b4ba32c0d431d76a120ae"}, - {file = "pydantic-1.10.22-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eccb58767f13c6963dcf96d02cb8723ebb98b16692030803ac075d2439c07b0f"}, - {file = "pydantic-1.10.22-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7778e6200ff8ed5f7052c1516617423d22517ad36cc7a3aedd51428168e3e5e8"}, - {file = "pydantic-1.10.22-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bffe02767d27c39af9ca7dc7cd479c00dda6346bb62ffc89e306f665108317a2"}, - {file = "pydantic-1.10.22-cp311-cp311-win_amd64.whl", hash = "sha256:23bc19c55427091b8e589bc08f635ab90005f2dc99518f1233386f46462c550a"}, - {file = "pydantic-1.10.22-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:92d0f97828a075a71d9efc65cf75db5f149b4d79a38c89648a63d2932894d8c9"}, - {file = "pydantic-1.10.22-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6af5a2811b6b95b58b829aeac5996d465a5f0c7ed84bd871d603cf8646edf6ff"}, - {file = "pydantic-1.10.22-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6cf06d8d40993e79af0ab2102ef5da77b9ddba51248e4cb27f9f3f591fbb096e"}, - {file = "pydantic-1.10.22-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:184b7865b171a6057ad97f4a17fbac81cec29bd103e996e7add3d16b0d95f609"}, - {file = "pydantic-1.10.22-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:923ad861677ab09d89be35d36111156063a7ebb44322cdb7b49266e1adaba4bb"}, - {file = "pydantic-1.10.22-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:82d9a3da1686443fb854c8d2ab9a473251f8f4cdd11b125522efb4d7c646e7bc"}, - {file = "pydantic-1.10.22-cp312-cp312-win_amd64.whl", hash = "sha256:1612604929af4c602694a7f3338b18039d402eb5ddfbf0db44f1ebfaf07f93e7"}, - {file = "pydantic-1.10.22-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b259dc89c9abcd24bf42f31951fb46c62e904ccf4316393f317abeeecda39978"}, - {file = "pydantic-1.10.22-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9238aa0964d80c0908d2f385e981add58faead4412ca80ef0fa352094c24e46d"}, - {file = "pydantic-1.10.22-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f8029f05b04080e3f1a550575a1bca747c0ea4be48e2d551473d47fd768fc1b"}, - {file = "pydantic-1.10.22-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5c06918894f119e0431a36c9393bc7cceeb34d1feeb66670ef9b9ca48c073937"}, - {file = "pydantic-1.10.22-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:e205311649622ee8fc1ec9089bd2076823797f5cd2c1e3182dc0e12aab835b35"}, - {file = "pydantic-1.10.22-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:815f0a73d5688d6dd0796a7edb9eca7071bfef961a7b33f91e618822ae7345b7"}, - {file = "pydantic-1.10.22-cp313-cp313-win_amd64.whl", hash = "sha256:9dfce71d42a5cde10e78a469e3d986f656afc245ab1b97c7106036f088dd91f8"}, - {file = "pydantic-1.10.22-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3ecaf8177b06aac5d1f442db1288e3b46d9f05f34fd17fdca3ad34105328b61a"}, - {file = "pydantic-1.10.22-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb36c2de9ea74bd7f66b5481dea8032d399affd1cbfbb9bb7ce539437f1fce62"}, - {file = "pydantic-1.10.22-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e6b8d14a256be3b8fff9286d76c532f1a7573fbba5f189305b22471c6679854d"}, - {file = "pydantic-1.10.22-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:1c33269e815db4324e71577174c29c7aa30d1bba51340ce6be976f6f3053a4c6"}, - {file = "pydantic-1.10.22-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:8661b3ab2735b2a9ccca2634738534a795f4a10bae3ab28ec0a10c96baa20182"}, - {file = "pydantic-1.10.22-cp37-cp37m-win_amd64.whl", hash = "sha256:22bdd5fe70d4549995981c55b970f59de5c502d5656b2abdfcd0a25be6f3763e"}, - {file = "pydantic-1.10.22-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e3f33d1358aa4bc2795208cc29ff3118aeaad0ea36f0946788cf7cadeccc166b"}, - {file = "pydantic-1.10.22-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:813f079f9cd136cac621f3f9128a4406eb8abd2ad9fdf916a0731d91c6590017"}, - {file = "pydantic-1.10.22-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab618ab8dca6eac7f0755db25f6aba3c22c40e3463f85a1c08dc93092d917704"}, - {file = "pydantic-1.10.22-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d128e1aaa38db88caca920d5822c98fc06516a09a58b6d3d60fa5ea9099b32cc"}, - {file = "pydantic-1.10.22-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:cc97bbc25def7025e55fc9016080773167cda2aad7294e06a37dda04c7d69ece"}, - {file = "pydantic-1.10.22-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0dda5d7157d543b1fa565038cae6e952549d0f90071c839b3740fb77c820fab8"}, - {file = "pydantic-1.10.22-cp38-cp38-win_amd64.whl", hash = "sha256:a093fe44fe518cb445d23119511a71f756f8503139d02fcdd1173f7b76c95ffe"}, - {file = "pydantic-1.10.22-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ec54c89b2568b258bb30d7348ac4d82bec1b58b377fb56a00441e2ac66b24587"}, - {file = "pydantic-1.10.22-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d8f1d1a1532e4f3bcab4e34e8d2197a7def4b67072acd26cfa60e92d75803a48"}, - {file = "pydantic-1.10.22-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ad83ca35508c27eae1005b6b61f369f78aae6d27ead2135ec156a2599910121"}, - {file = "pydantic-1.10.22-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:53cdb44b78c420f570ff16b071ea8cd5a477635c6b0efc343c8a91e3029bbf1a"}, - {file = "pydantic-1.10.22-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:16d0a5ae9d98264186ce31acdd7686ec05fd331fab9d68ed777d5cb2d1514e5e"}, - {file = "pydantic-1.10.22-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:8aee040e25843f036192b1a1af62117504a209a043aa8db12e190bb86ad7e611"}, - {file = "pydantic-1.10.22-cp39-cp39-win_amd64.whl", hash = "sha256:7f691eec68dbbfca497d3c11b92a3e5987393174cbedf03ec7a4184c35c2def6"}, - {file = "pydantic-1.10.22-py3-none-any.whl", hash = "sha256:343037d608bcbd34df937ac259708bfc83664dadf88afe8516c4f282d7d471a9"}, - {file = "pydantic-1.10.22.tar.gz", hash = "sha256:ee1006cebd43a8e7158fb7190bb8f4e2da9649719bff65d0c287282ec38dec6d"}, + {file = "pydantic-1.10.23-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1ce178e49a471ebf867451872a3403b89da6194bc2c9761e78ce22f619794d0d"}, + {file = "pydantic-1.10.23-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d5f2ab29db92a2b11c7cd49466f68858583bf227165c42a3fae2b50042a1ab51"}, + {file = "pydantic-1.10.23-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8e84ece91eb806586ffa4f92c149308cb07b0fa14a7e1204e18cde01aac283f7"}, + {file = "pydantic-1.10.23-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:757c8a2f459311bf277f6ddb4891222f69ba93fb301eee095c985fc7239d5afd"}, + {file = "pydantic-1.10.23-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:50b4726ab72a027fb69da865e849ae16107bdbea01ff1670daf4560e078a1606"}, + {file = "pydantic-1.10.23-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:4ed07c43d5c3f6f391eceeef7ead84c8c54083e0a1b5fa009302191c07775a73"}, + {file = "pydantic-1.10.23-cp310-cp310-win_amd64.whl", hash = "sha256:bc5547c3be3b8494a444adf3703c037bdf2170e30af802f5d7bb14a232698106"}, + {file = "pydantic-1.10.23-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b2e9d81546af42331248bbffde26a441631c8823515ebf328ee2ec04d771cd73"}, + {file = "pydantic-1.10.23-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7e13f39ce65232a2826d1c32a9e2c6f9ca5451d6e51c6e5ea9fdebc285fc2980"}, + {file = "pydantic-1.10.23-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:041308bdb4804f0b387b02f870ebdf4e86020de344a969020de853f5ea8d5508"}, + {file = "pydantic-1.10.23-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed01648e2a469e2c35984bab9ff5080648c53af3b8b98312e1d7823eacd33d77"}, + {file = "pydantic-1.10.23-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:18056741c9febebeb043798414099ada8d8e74cc47ec2059d7fbdc7d091d0e7b"}, + {file = "pydantic-1.10.23-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7411a18deef02a6b7825edb3930b9ab0251f7b131ebb1cb1ffe0aadf74d60c6d"}, + {file = "pydantic-1.10.23-cp311-cp311-win_amd64.whl", hash = "sha256:890213289bf40481a715b1d8b3e8a602af9e481d9f0e0b2b00dc375a12b0cfbb"}, + {file = "pydantic-1.10.23-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:136b6428b644691d0ee2a3a7de395d0d1b01ce6388b747bd371bb9ca65b4cc32"}, + {file = "pydantic-1.10.23-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b47c210416606b7c8e236c7546647500856eaba0d01564d5cddacb30d1b5daec"}, + {file = "pydantic-1.10.23-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c9c436e12d81b7c3d3208f66a5d35b401c8ec25fafc9bff446c77f1072ed5f5"}, + {file = "pydantic-1.10.23-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edba6ac9bd6040daf3e876c284257624171884011e0729d90b90f5fe11f7217d"}, + {file = "pydantic-1.10.23-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:101ae7dcd77c23003d4766bcf23e08cd3d012173379ad549bdb2c898855b2a57"}, + {file = "pydantic-1.10.23-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9b05416d8dcf36fd291348bba8f565d015fce4c594577d2ef5bc0c5ec8f54a29"}, + {file = "pydantic-1.10.23-cp312-cp312-win_amd64.whl", hash = "sha256:0f309b3dd80ed4d3487b1219c69dfd9036e51a863aeaa41a3b67497b81c4cb8f"}, + {file = "pydantic-1.10.23-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a6aa6881a18657fe66b9249e0572a9690ebc6f0b37c32872beb06bc51bff738f"}, + {file = "pydantic-1.10.23-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c57bfade74111335062c8ac830d5a14004742ff5b037c52c410d9e9011258bf5"}, + {file = "pydantic-1.10.23-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:723cb7f6aca0b471bac9d7dceb42d151d26aabdca655bd4190be3a7de008a054"}, + {file = "pydantic-1.10.23-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1b81db6c9108c3f6509c897fcdf842e5993d7233e9140a7f1c4dc1c2f85b0a8d"}, + {file = "pydantic-1.10.23-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:9e9544d07d96df6c6405b64462fb3122e5d0af46a1c4ddf94c180b17ac29f047"}, + {file = "pydantic-1.10.23-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4dff5e26a14424f4e6cf44cbd45861b458f31e37d316e92a78bf99ec6d1ef2ee"}, + {file = "pydantic-1.10.23-cp313-cp313-win_amd64.whl", hash = "sha256:633235236c9af4a16e7cf47be3ffab15445552613a122b44a8946868c2ace426"}, + {file = "pydantic-1.10.23-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:33fdacc8ffadaa0efecb1f8fec8d1ba8653c644f1c6a946c64f3e5e9563ac040"}, + {file = "pydantic-1.10.23-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d6c46c8055833bce5786c5e66cb30208db0bd5534f007890c3b76556d2f24d11"}, + {file = "pydantic-1.10.23-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0bed91a634855400f5c3b180999d0437a3b418b0170222fc8f6294aa2a08848a"}, + {file = "pydantic-1.10.23-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:e812b0f2a708595227aed10c636a54df4d02a1b3a5c90555df108a5e1244b2e9"}, + {file = "pydantic-1.10.23-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:8a52b2eedc25215c9cc1d96340d8364f8c8b6787a7cf2cc202d058e73e06cbef"}, + {file = "pydantic-1.10.23-cp37-cp37m-win_amd64.whl", hash = "sha256:38549feff6fac3c7a9e73fef6f8a2599300b10d71813ff329854449deb458aa6"}, + {file = "pydantic-1.10.23-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f71590dcd1ff354107cecc1c26b85406dd11e6f87d9b8416c5defd3cf4d54a51"}, + {file = "pydantic-1.10.23-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:46b3cd6fb8edf973380ddf1ac7387cca5f0624c07579bf9d15121dd77986b57c"}, + {file = "pydantic-1.10.23-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89e9a801a538d056fd91edf0d01dec02abde1b325e3c019c5c06d75fcca86929"}, + {file = "pydantic-1.10.23-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7ee7fa1a9bfa45aad5652001efa552a79a40f9ea7a1b11185685dd047895d3a8"}, + {file = "pydantic-1.10.23-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:0db70ae0e58eed1ffd01fbfdd23f6c6e5ae5e1bf2cd50dfeb0a2853656766e68"}, + {file = "pydantic-1.10.23-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:d037210949ac9e837360239d91a834cab3cf02e84cf295ea66c6ff73137f3723"}, + {file = "pydantic-1.10.23-cp38-cp38-win_amd64.whl", hash = "sha256:aa8d57384c6305febd9724b4f8de6860b5ba5821b7948dbbd0ddf733d50d7677"}, + {file = "pydantic-1.10.23-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:cdb4c8fdf8344b912285ca85c99d44433bd3d877f44b9ffcfc79cefedbc08869"}, + {file = "pydantic-1.10.23-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:144f739a617f2c12fa8d135d2efe26b9cf16033a44f2fe5400d7d0e9d9c90dca"}, + {file = "pydantic-1.10.23-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3449e59f27a42ba2c35c2e92aea345794696e5dddba3b5d88d123155eac4ee83"}, + {file = "pydantic-1.10.23-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10e9d8259fab4599498c3246703b84a5e9500240544bf49c54fc57996c6d093a"}, + {file = "pydantic-1.10.23-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:08b576239a4acbbfd35365b603cbee5fee6d3c56323abba54f0142e7ad6ff406"}, + {file = "pydantic-1.10.23-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:0f20e4dfe6413ee79fc1b4ac9c9f4112ff9d4cf44a19577592422d09774ee085"}, + {file = "pydantic-1.10.23-cp39-cp39-win_amd64.whl", hash = "sha256:45fcc5ed6adde6703f9f22f898362a087d1d140a337ecc4caca2477f4d735390"}, + {file = "pydantic-1.10.23-py3-none-any.whl", hash = "sha256:6294bb84565c294a3a6408c52b26a42803f258d5ebfdb3ae896cd7cccfa07211"}, + {file = "pydantic-1.10.23.tar.gz", hash = "sha256:81ee80fe4bd69236aeb65c8beeb5150655b8a49b946fce6664a720d6cf5ec717"}, ] [package.dependencies] @@ -1804,30 +1871,50 @@ six = ">=1.8.0" [[package]] name = "pynacl" -version = "1.5.0" +version = "1.6.0" description = "Python binding to the Networking and Cryptography (NaCl) library" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" groups = ["integration"] files = [ - {file = "PyNaCl-1.5.0-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:401002a4aaa07c9414132aaed7f6836ff98f59277a234704ff66878c2ee4a0d1"}, - {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:52cb72a79269189d4e0dc537556f4740f7f0a9ec41c1322598799b0bdad4ef92"}, - {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a36d4a9dda1f19ce6e03c9a784a2921a4b726b02e1c736600ca9c22029474394"}, - {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:0c84947a22519e013607c9be43706dd42513f9e6ae5d39d3613ca1e142fba44d"}, - {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06b8f6fa7f5de8d5d2f7573fe8c863c051225a27b61e6860fd047b1775807858"}, - {file = "PyNaCl-1.5.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:a422368fc821589c228f4c49438a368831cb5bbc0eab5ebe1d7fac9dded6567b"}, - {file = "PyNaCl-1.5.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:61f642bf2378713e2c2e1de73444a3778e5f0a38be6fee0fe532fe30060282ff"}, - {file = "PyNaCl-1.5.0-cp36-abi3-win32.whl", hash = "sha256:e46dae94e34b085175f8abb3b0aaa7da40767865ac82c928eeb9e57e1ea8a543"}, - {file = "PyNaCl-1.5.0-cp36-abi3-win_amd64.whl", hash = "sha256:20f42270d27e1b6a29f54032090b972d97f0a1b0948cc52392041ef7831fee93"}, - {file = "PyNaCl-1.5.0.tar.gz", hash = "sha256:8ac7448f09ab85811607bdd21ec2464495ac8b7c66d146bf545b0f08fb9220ba"}, + {file = "pynacl-1.6.0-cp314-cp314t-macosx_10_10_universal2.whl", hash = "sha256:f46386c24a65383a9081d68e9c2de909b1834ec74ff3013271f1bca9c2d233eb"}, + {file = "pynacl-1.6.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:dea103a1afcbc333bc0e992e64233d360d393d1e63d0bc88554f572365664348"}, + {file = "pynacl-1.6.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:04f20784083014e265ad58c1b2dd562c3e35864b5394a14ab54f5d150ee9e53e"}, + {file = "pynacl-1.6.0-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bbcc4452a1eb10cd5217318c822fde4be279c9de8567f78bad24c773c21254f8"}, + {file = "pynacl-1.6.0-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:51fed9fe1bec9e7ff9af31cd0abba179d0e984a2960c77e8e5292c7e9b7f7b5d"}, + {file = "pynacl-1.6.0-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:10d755cf2a455d8c0f8c767a43d68f24d163b8fe93ccfaabfa7bafd26be58d73"}, + {file = "pynacl-1.6.0-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:536703b8f90e911294831a7fbcd0c062b837f3ccaa923d92a6254e11178aaf42"}, + {file = "pynacl-1.6.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:6b08eab48c9669d515a344fb0ef27e2cbde847721e34bba94a343baa0f33f1f4"}, + {file = "pynacl-1.6.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5789f016e08e5606803161ba24de01b5a345d24590a80323379fc4408832d290"}, + {file = "pynacl-1.6.0-cp314-cp314t-win32.whl", hash = "sha256:4853c154dc16ea12f8f3ee4b7e763331876316cc3a9f06aeedf39bcdca8f9995"}, + {file = "pynacl-1.6.0-cp314-cp314t-win_amd64.whl", hash = "sha256:347dcddce0b4d83ed3f32fd00379c83c425abee5a9d2cd0a2c84871334eaff64"}, + {file = "pynacl-1.6.0-cp314-cp314t-win_arm64.whl", hash = "sha256:2d6cd56ce4998cb66a6c112fda7b1fdce5266c9f05044fa72972613bef376d15"}, + {file = "pynacl-1.6.0-cp38-abi3-macosx_10_10_universal2.whl", hash = "sha256:f4b3824920e206b4f52abd7de621ea7a44fd3cb5c8daceb7c3612345dfc54f2e"}, + {file = "pynacl-1.6.0-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:16dd347cdc8ae0b0f6187a2608c0af1c8b7ecbbe6b4a06bff8253c192f696990"}, + {file = "pynacl-1.6.0-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:16c60daceee88d04f8d41d0a4004a7ed8d9a5126b997efd2933e08e93a3bd850"}, + {file = "pynacl-1.6.0-cp38-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:25720bad35dfac34a2bcdd61d9e08d6bfc6041bebc7751d9c9f2446cf1e77d64"}, + {file = "pynacl-1.6.0-cp38-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8bfaa0a28a1ab718bad6239979a5a57a8d1506d0caf2fba17e524dbb409441cf"}, + {file = "pynacl-1.6.0-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:ef214b90556bb46a485b7da8258e59204c244b1b5b576fb71848819b468c44a7"}, + {file = "pynacl-1.6.0-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:49c336dd80ea54780bcff6a03ee1a476be1612423010472e60af83452aa0f442"}, + {file = "pynacl-1.6.0-cp38-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:f3482abf0f9815e7246d461fab597aa179b7524628a4bc36f86a7dc418d2608d"}, + {file = "pynacl-1.6.0-cp38-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:140373378e34a1f6977e573033d1dd1de88d2a5d90ec6958c9485b2fd9f3eb90"}, + {file = "pynacl-1.6.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:6b393bc5e5a0eb86bb85b533deb2d2c815666665f840a09e0aa3362bb6088736"}, + {file = "pynacl-1.6.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:4a25cfede801f01e54179b8ff9514bd7b5944da560b7040939732d1804d25419"}, + {file = "pynacl-1.6.0-cp38-abi3-win32.whl", hash = "sha256:dcdeb41c22ff3c66eef5e63049abf7639e0db4edee57ba70531fc1b6b133185d"}, + {file = "pynacl-1.6.0-cp38-abi3-win_amd64.whl", hash = "sha256:cf831615cc16ba324240de79d925eacae8265b7691412ac6b24221db157f6bd1"}, + {file = "pynacl-1.6.0-cp38-abi3-win_arm64.whl", hash = "sha256:84709cea8f888e618c21ed9a0efdb1a59cc63141c403db8bf56c469b71ad56f2"}, + {file = "pynacl-1.6.0.tar.gz", hash = "sha256:cb36deafe6e2bce3b286e5d1f3e1c246e0ccdb8808ddb4550bb2792f2df298f2"}, ] [package.dependencies] -cffi = ">=1.4.1" +cffi = [ + {version = ">=1.4.1", markers = "platform_python_implementation != \"PyPy\" and python_version < \"3.14\""}, + {version = ">=2.0.0", markers = "platform_python_implementation != \"PyPy\" and python_version >= \"3.14\""}, +] [package.extras] -docs = ["sphinx (>=1.6.5)", "sphinx-rtd-theme"] -tests = ["hypothesis (>=3.27.0)", "pytest (>=3.2.1,!=3.3.0)"] +docs = ["sphinx (<7)", "sphinx_rtd_theme"] +tests = ["hypothesis (>=3.27.0)", "pytest (>=7.4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"] [[package]] name = "pyrfc3339" @@ -1857,14 +1944,14 @@ files = [ [[package]] name = "pytest" -version = "8.4.1" +version = "8.4.2" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.9" groups = ["integration", "unit"] files = [ - {file = "pytest-8.4.1-py3-none-any.whl", hash = "sha256:539c70ba6fcead8e78eebbf1115e8b589e7565830d7d006a8723f19ac8a0afb7"}, - {file = "pytest-8.4.1.tar.gz", hash = "sha256:7c67fd69174877359ed9371ec3af8a3d2b04741818c51e5e99cc1742251fa93c"}, + {file = "pytest-8.4.2-py3-none-any.whl", hash = "sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79"}, + {file = "pytest-8.4.2.tar.gz", hash = "sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01"}, ] [package.dependencies] @@ -2248,43 +2335,43 @@ pyasn1 = ">=0.1.3" [[package]] name = "ruff" -version = "0.12.11" +version = "0.13.0" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" groups = ["format"] files = [ - {file = "ruff-0.12.11-py3-none-linux_armv6l.whl", hash = "sha256:93fce71e1cac3a8bf9200e63a38ac5c078f3b6baebffb74ba5274fb2ab276065"}, - {file = "ruff-0.12.11-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b8e33ac7b28c772440afa80cebb972ffd823621ded90404f29e5ab6d1e2d4b93"}, - {file = "ruff-0.12.11-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d69fb9d4937aa19adb2e9f058bc4fbfe986c2040acb1a4a9747734834eaa0bfd"}, - {file = "ruff-0.12.11-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:411954eca8464595077a93e580e2918d0a01a19317af0a72132283e28ae21bee"}, - {file = "ruff-0.12.11-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6a2c0a2e1a450f387bf2c6237c727dd22191ae8c00e448e0672d624b2bbd7fb0"}, - {file = "ruff-0.12.11-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ca4c3a7f937725fd2413c0e884b5248a19369ab9bdd850b5781348ba283f644"}, - {file = "ruff-0.12.11-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:4d1df0098124006f6a66ecf3581a7f7e754c4df7644b2e6704cd7ca80ff95211"}, - {file = "ruff-0.12.11-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5a8dd5f230efc99a24ace3b77e3555d3fbc0343aeed3fc84c8d89e75ab2ff793"}, - {file = "ruff-0.12.11-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4dc75533039d0ed04cd33fb8ca9ac9620b99672fe7ff1533b6402206901c34ee"}, - {file = "ruff-0.12.11-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4fc58f9266d62c6eccc75261a665f26b4ef64840887fc6cbc552ce5b29f96cc8"}, - {file = "ruff-0.12.11-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:5a0113bd6eafd545146440225fe60b4e9489f59eb5f5f107acd715ba5f0b3d2f"}, - {file = "ruff-0.12.11-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:0d737b4059d66295c3ea5720e6efc152623bb83fde5444209b69cd33a53e2000"}, - {file = "ruff-0.12.11-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:916fc5defee32dbc1fc1650b576a8fed68f5e8256e2180d4d9855aea43d6aab2"}, - {file = "ruff-0.12.11-py3-none-musllinux_1_2_i686.whl", hash = "sha256:c984f07d7adb42d3ded5be894fb4007f30f82c87559438b4879fe7aa08c62b39"}, - {file = "ruff-0.12.11-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e07fbb89f2e9249f219d88331c833860489b49cdf4b032b8e4432e9b13e8a4b9"}, - {file = "ruff-0.12.11-py3-none-win32.whl", hash = "sha256:c792e8f597c9c756e9bcd4d87cf407a00b60af77078c96f7b6366ea2ce9ba9d3"}, - {file = "ruff-0.12.11-py3-none-win_amd64.whl", hash = "sha256:a3283325960307915b6deb3576b96919ee89432ebd9c48771ca12ee8afe4a0fd"}, - {file = "ruff-0.12.11-py3-none-win_arm64.whl", hash = "sha256:bae4d6e6a2676f8fb0f98b74594a048bae1b944aab17e9f5d504062303c6dbea"}, - {file = "ruff-0.12.11.tar.gz", hash = "sha256:c6b09ae8426a65bbee5425b9d0b82796dbb07cb1af045743c79bfb163001165d"}, + {file = "ruff-0.13.0-py3-none-linux_armv6l.whl", hash = "sha256:137f3d65d58ee828ae136a12d1dc33d992773d8f7644bc6b82714570f31b2004"}, + {file = "ruff-0.13.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:21ae48151b66e71fd111b7d79f9ad358814ed58c339631450c66a4be33cc28b9"}, + {file = "ruff-0.13.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:64de45f4ca5441209e41742d527944635a05a6e7c05798904f39c85bafa819e3"}, + {file = "ruff-0.13.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2b2c653ae9b9d46e0ef62fc6fbf5b979bda20a0b1d2b22f8f7eb0cde9f4963b8"}, + {file = "ruff-0.13.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4cec632534332062bc9eb5884a267b689085a1afea9801bf94e3ba7498a2d207"}, + {file = "ruff-0.13.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dcd628101d9f7d122e120ac7c17e0a0f468b19bc925501dbe03c1cb7f5415b24"}, + {file = "ruff-0.13.0-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:afe37db8e1466acb173bb2a39ca92df00570e0fd7c94c72d87b51b21bb63efea"}, + {file = "ruff-0.13.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0f96a8d90bb258d7d3358b372905fe7333aaacf6c39e2408b9f8ba181f4b6ef2"}, + {file = "ruff-0.13.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:94b5e3d883e4f924c5298e3f2ee0f3085819c14f68d1e5b6715597681433f153"}, + {file = "ruff-0.13.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03447f3d18479df3d24917a92d768a89f873a7181a064858ea90a804a7538991"}, + {file = "ruff-0.13.0-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:fbc6b1934eb1c0033da427c805e27d164bb713f8e273a024a7e86176d7f462cf"}, + {file = "ruff-0.13.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:a8ab6a3e03665d39d4a25ee199d207a488724f022db0e1fe4002968abdb8001b"}, + {file = "ruff-0.13.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:d2a5c62f8ccc6dd2fe259917482de7275cecc86141ee10432727c4816235bc41"}, + {file = "ruff-0.13.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:b7b85ca27aeeb1ab421bc787009831cffe6048faae08ad80867edab9f2760945"}, + {file = "ruff-0.13.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:79ea0c44a3032af768cabfd9616e44c24303af49d633b43e3a5096e009ebe823"}, + {file = "ruff-0.13.0-py3-none-win32.whl", hash = "sha256:4e473e8f0e6a04e4113f2e1de12a5039579892329ecc49958424e5568ef4f768"}, + {file = "ruff-0.13.0-py3-none-win_amd64.whl", hash = "sha256:48e5c25c7a3713eea9ce755995767f4dcd1b0b9599b638b12946e892123d1efb"}, + {file = "ruff-0.13.0-py3-none-win_arm64.whl", hash = "sha256:ab80525317b1e1d38614addec8ac954f1b3e662de9d59114ecbf771d00cf613e"}, + {file = "ruff-0.13.0.tar.gz", hash = "sha256:5b4b1ee7eb35afae128ab94459b13b2baaed282b1fb0f472a73c82c996c8ae60"}, ] [[package]] name = "s3transfer" -version = "0.13.1" +version = "0.14.0" description = "An Amazon S3 Transfer Manager" optional = false python-versions = ">=3.9" groups = ["main", "integration"] files = [ - {file = "s3transfer-0.13.1-py3-none-any.whl", hash = "sha256:a981aa7429be23fe6dfc13e80e4020057cbab622b08c0315288758d67cabc724"}, - {file = "s3transfer-0.13.1.tar.gz", hash = "sha256:c3fdba22ba1bd367922f27ec8032d6a1cf5f10c934fb5d68cf60fd5a23d936cf"}, + {file = "s3transfer-0.14.0-py3-none-any.whl", hash = "sha256:ea3b790c7077558ed1f02a3072fb3cb992bbbd253392f4b6e9e8976941c7d456"}, + {file = "s3transfer-0.14.0.tar.gz", hash = "sha256:eff12264e7c8b4985074ccce27a3b38a485bb7f7422cc8046fee9be4983e4125"}, ] [package.dependencies] @@ -2681,4 +2768,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = "^3.10" -content-hash = "501c997762ac2a88b47a1ebc2ac05ea362dc2fb7f29aeb93f65f9655ea3ca087" +content-hash = "b9e4437b9bba14c8b3fa1450c50a21854cd7217576edaaf4e42b30a51cf7b7e5" diff --git a/pyproject.toml b/pyproject.toml index 305d86c88c..ea2e85c9cd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,12 +8,12 @@ requires-poetry = ">=2.0.0" [tool.poetry.dependencies] python = "^3.10" ops = "^2.23.1" -boto3 = "^1.40.21" +boto3 = "^1.40.31" pgconnstr = "^1.0.1" requests = "^2.32.5" tenacity = "^9.1.2" psycopg2 = "^2.9.10" -pydantic = "^1.10.22" +pydantic = "^1.10.23" jinja2 = "^3.1.6" pysyncobj = "^0.3.14" psutil = "^7.0.0" @@ -40,7 +40,7 @@ opentelemetry-exporter-otlp-proto-http = "1.21.0" optional = true [tool.poetry.group.format.dependencies] -ruff = "^0.12.11" +ruff = "^0.13.0" [tool.poetry.group.lint] optional = true @@ -53,7 +53,7 @@ optional = true [tool.poetry.group.unit.dependencies] coverage = {extras = ["toml"], version = "^7.10.6"} -pytest = "^8.4.1" +pytest = "^8.4.2" pytest-asyncio = "*" parameterized = "^0.9.0" jsonschema = "^4.25.1" @@ -62,7 +62,7 @@ jsonschema = "^4.25.1" optional = true [tool.poetry.group.integration.dependencies] -pytest = "^8.4.1" +pytest = "^8.4.2" pytest-operator = "^0.43.1" # renovate caret doesn't work: https://github.com/renovatebot/renovate/issues/26940 juju = "<=3.6.1.3" From 7379b5065bbd0de16921b6daf1cd5e08177da569 Mon Sep 17 00:00:00 2001 From: Alex Lutay <1928266+taurus-forever@users.noreply.github.com> Date: Thu, 18 Sep 2025 23:10:17 +0200 Subject: [PATCH 097/112] DPE-8296 Downgrade promote.yaml to _promote_charm.yaml@v31.1.1 (#1161) D-p-w v32+ requires refresh v3 versioning, otherwise: https://github.com/canonical/postgresql-operator/actions/runs/17777132580 > Invalid workflow file: .github/workflows/promote.yaml#L28 > error parsing called workflow ".github/workflows/promote.yaml" -> > "canonical/data-platform-workflows/.github/workflows/_promote_charm.yaml@v35.0.2": > failed to fetch workflow: workflow was not found. --- .github/workflows/promote.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/promote.yaml b/.github/workflows/promote.yaml index 3c86301b1b..4bd89c205f 100644 --- a/.github/workflows/promote.yaml +++ b/.github/workflows/promote.yaml @@ -25,7 +25,7 @@ on: jobs: promote: name: Promote charm - uses: canonical/data-platform-workflows/.github/workflows/_promote_charm.yaml@v35.0.2 + uses: canonical/data-platform-workflows/.github/workflows/_promote_charm.yaml@v31.1.1 # Use v32+ with refresh v3 charms only! with: track: '14' from-risk: ${{ inputs.from-risk }} From 1a8928712eb279775442832ddde13d1f2a56f963 Mon Sep 17 00:00:00 2001 From: Dragomir Penev <6687393+dragomirp@users.noreply.github.com> Date: Mon, 22 Sep 2025 14:00:15 +0300 Subject: [PATCH 098/112] Remove reinits (#1168) --- src/charm.py | 54 ++-------------------------------------- tests/unit/test_charm.py | 25 +------------------ 2 files changed, 3 insertions(+), 76 deletions(-) diff --git a/src/charm.py b/src/charm.py index e979ea81d7..3b2bb9bb2f 100755 --- a/src/charm.py +++ b/src/charm.py @@ -715,23 +715,6 @@ def _on_peer_relation_changed(self, event: HookEvent): event.defer() return - # Restart the workload if it's stuck on the starting state after a timeline divergence - # due to a backup that was restored. - if ( - not self.is_primary - and not self.is_standby_leader - and ( - self._patroni.member_replication_lag == "unknown" - or int(self._patroni.member_replication_lag) > 1000 - ) - ): - logger.warning("Degraded member detected: reinitialising unit") - self.unit.status = MaintenanceStatus("reinitialising replica") - self._patroni.reinitialize_postgresql() - logger.debug("Deferring on_peer_relation_changed: reinitialising replica") - event.defer() - return - self._start_stop_pgbackrest_service(event) # This is intended to be executed only when leader is reinitializing S3 connection due to the leader change. @@ -1635,7 +1618,8 @@ def _on_update_status(self, _) -> None: if self.primary_endpoint: self._update_relation_endpoints() - if self._handle_workload_failures(): + if not self._patroni.member_started and self._patroni.is_member_isolated: + self._patroni.restart_patroni() return # Update the sync-standby endpoint in the async replication data. @@ -1745,40 +1729,6 @@ def _handle_processes_failures(self) -> bool: return False - def _handle_workload_failures(self) -> bool: - """Handle workload (Patroni or PostgreSQL) failures. - - Returns: - a bool indicating whether the charm performed any action. - """ - # Restart the workload if it's stuck on the starting state after a restart. - try: - is_primary = self.is_primary - is_standby_leader = self.is_standby_leader - except RetryError: - return False - - if ( - not self.has_raft_keys() - and not is_primary - and not is_standby_leader - and not self._patroni.member_started - and "postgresql_restarted" in self._peers.data[self.unit] - and self._patroni.member_replication_lag == "unknown" - ): - logger.warning("Workload failure detected. Reinitialising unit.") - self.unit.status = MaintenanceStatus("reinitialising replica") - self._patroni.reinitialize_postgresql() - return True - - # Restart the service if the current cluster member is isolated from the cluster - # (stuck with the "awaiting for member to start" message). - if not self._patroni.member_started and self._patroni.is_member_isolated: - self._patroni.restart_patroni() - return True - - return False - def _set_primary_status_message(self) -> None: """Display 'Primary' in the unit status message if the current unit is the primary.""" try: diff --git a/tests/unit/test_charm.py b/tests/unit/test_charm.py index 9c8b9efc4d..db5a67d1b8 100644 --- a/tests/unit/test_charm.py +++ b/tests/unit/test_charm.py @@ -907,7 +907,6 @@ def test_on_update_status(harness): ) as _set_primary_status_message, patch("charm.Patroni.restart_patroni") as _restart_patroni, patch("charm.Patroni.is_member_isolated") as _is_member_isolated, - patch("charm.Patroni.reinitialize_postgresql") as _reinitialize_postgresql, patch( "charm.Patroni.member_replication_lag", new_callable=PropertyMock ) as _member_replication_lag, @@ -979,24 +978,9 @@ def test_on_update_status(harness): harness.charm.on.update_status.emit() _set_primary_status_message.assert_called_once() - # Test the reinitialisation of the replica when its lag is unknown - # after a restart. + # Test call to restart when the member is isolated from the cluster. _set_primary_status_message.reset_mock() - _is_primary.return_value = False - _is_standby_leader.return_value = False _member_started.return_value = False - _is_member_isolated.return_value = False - _member_replication_lag.return_value = "unknown" - with harness.hooks_disabled(): - harness.update_relation_data( - rel_id, harness.charm.unit.name, {"postgresql_restarted": "True"} - ) - harness.charm.on.update_status.emit() - _reinitialize_postgresql.assert_called_once() - _restart_patroni.assert_not_called() - _set_primary_status_message.assert_not_called() - - # Test call to restart when the member is isolated from the cluster. _is_member_isolated.return_value = True with harness.hooks_disabled(): harness.update_relation_data( @@ -1013,9 +997,6 @@ def test_on_update_status_after_restore_operation(harness): patch( "charm.PostgresqlOperatorCharm._set_primary_status_message" ) as _set_primary_status_message, - patch( - "charm.PostgresqlOperatorCharm._handle_workload_failures" - ) as _handle_workload_failures, patch( "charm.PostgresqlOperatorCharm._update_relation_endpoints" ) as _update_relation_endpoints, @@ -1052,7 +1033,6 @@ def test_on_update_status_after_restore_operation(harness): _handle_processes_failures.assert_not_called() _oversee_users.assert_not_called() _update_relation_endpoints.assert_not_called() - _handle_workload_failures.assert_not_called() _set_primary_status_message.assert_not_called() assert isinstance(harness.charm.unit.status, BlockedStatus) @@ -1065,7 +1045,6 @@ def test_on_update_status_after_restore_operation(harness): _handle_processes_failures.assert_not_called() _oversee_users.assert_not_called() _update_relation_endpoints.assert_not_called() - _handle_workload_failures.assert_not_called() _set_primary_status_message.assert_not_called() assert isinstance(harness.charm.unit.status, ActiveStatus) @@ -1079,13 +1058,11 @@ def test_on_update_status_after_restore_operation(harness): _member_started.return_value = True _can_use_s3_repository.return_value = (True, None) _handle_processes_failures.return_value = False - _handle_workload_failures.return_value = False harness.charm.on.update_status.emit() _update_config.assert_called_once() _handle_processes_failures.assert_called_once() _oversee_users.assert_called_once() _update_relation_endpoints.assert_called_once() - _handle_workload_failures.assert_called_once() _set_primary_status_message.assert_called_once() assert isinstance(harness.charm.unit.status, ActiveStatus) From c5096110d1c6e11e1afa237286c0895e14c4487f Mon Sep 17 00:00:00 2001 From: Dragomir Penev <6687393+dragomirp@users.noreply.github.com> Date: Mon, 22 Sep 2025 16:08:32 +0300 Subject: [PATCH 099/112] [MISC] Config hash (#1166) * Use Patroni API for is_restart_pending * Cached props * Magic sleep and legacy rel names * Hash config value and restart only on change * Tweaks * Legacy interface fix * Fix legacy test * Increase idle period * Wrong username * Remove copypasta --- .../tempo_coordinator_k8s/v0/charm_tracing.py | 53 +++++---- src/backups.py | 3 +- src/charm.py | 111 +++++++++++------- src/cluster.py | 12 +- src/relations/db.py | 35 ++++-- tests/integration/test_db.py | 7 +- tests/unit/test_charm.py | 4 +- tests/unit/test_cluster.py | 2 +- tests/unit/test_db.py | 11 +- 9 files changed, 141 insertions(+), 97 deletions(-) diff --git a/lib/charms/tempo_coordinator_k8s/v0/charm_tracing.py b/lib/charms/tempo_coordinator_k8s/v0/charm_tracing.py index f58ee72e0f..254c681f8b 100644 --- a/lib/charms/tempo_coordinator_k8s/v0/charm_tracing.py +++ b/lib/charms/tempo_coordinator_k8s/v0/charm_tracing.py @@ -266,7 +266,7 @@ def _remove_stale_otel_sdk_packages(): if name.startswith("opentelemetry_"): otel_distributions[name].append(distribution) - otel_logger.debug(f"Found {len(otel_distributions)} opentelemetry distributions") + otel_logger.debug("Found %d opentelemetry distributions", len(otel_distributions)) # If we have multiple distributions with the same name, remove any that have 0 associated files for name, distributions_ in otel_distributions.items(): @@ -274,12 +274,12 @@ def _remove_stale_otel_sdk_packages(): continue otel_logger.debug( - f"Package {name} has multiple ({len(distributions_)}) distributions." + "Package %s has multiple (%d) distributions.", name, len(distributions_) ) for distribution in distributions_: if not distribution.files: # Not None or empty list path = distribution._path # type: ignore - otel_logger.info(f"Removing empty distribution of {name} at {path}.") + otel_logger.info("Removing empty distribution of %s at %s.", name, path) shutil.rmtree(path) otel_logger.debug("Successfully applied _remove_stale_otel_sdk_packages patch. ") @@ -350,7 +350,7 @@ def _remove_stale_otel_sdk_packages(): # Increment this PATCH version before using `charmcraft publish-lib` or reset # to 0 if you are raising the major API version -LIBPATCH = 10 +LIBPATCH = 11 PYDEPS = ["opentelemetry-exporter-otlp-proto-http==1.21.0"] @@ -430,7 +430,8 @@ def _prune(self, queue: Sequence[bytes]) -> Sequence[bytes]: if overflow > 0: n_dropped_spans += overflow logger.warning( - f"charm tracing buffer exceeds max history length ({self._max_event_history_length} events)" + "charm tracing buffer exceeds max history length (%d events)", + self._max_event_history_length, ) new_spans = deque(queue[-self._max_event_history_length :]) @@ -446,19 +447,21 @@ def _prune(self, queue: Sequence[bytes]) -> Sequence[bytes]: # only do this once if not logged_drop: logger.warning( - f"charm tracing buffer exceeds size limit ({self._max_buffer_size_mib}MiB)." + "charm tracing buffer exceeds size limit (%dMiB).", + self._max_buffer_size_mib, ) logged_drop = True if n_dropped_spans > 0: dev_logger.debug( - f"charm tracing buffer overflow: dropped {n_dropped_spans} older spans. " - f"Please increase the buffer limits, or ensure the spans can be flushed." + "charm tracing buffer overflow: dropped %d older spans. " + "Please increase the buffer limits, or ensure the spans can be flushed.", + n_dropped_spans, ) return new_spans def _save(self, spans: Sequence[ReadableSpan], replace: bool = False): - dev_logger.debug(f"saving {len(spans)} new spans to buffer") + dev_logger.debug("saving %d new spans to buffer", len(spans)) old = [] if replace else self.load() queue = old + [self._serialize(spans)] new_buffer = self._prune(queue) @@ -480,7 +483,7 @@ def _write(self, spans: Sequence[bytes]): # ensure the destination folder exists db_file_dir = self._db_file.parent if not db_file_dir.exists(): - dev_logger.info(f"creating buffer dir: {db_file_dir}") + dev_logger.info("creating buffer dir: %s", db_file_dir) db_file_dir.mkdir(parents=True) self._db_file.write_bytes(self._SPANSEP.join(spans)) @@ -496,7 +499,7 @@ def load(self) -> List[bytes]: try: spans = self._db_file.read_bytes().split(self._SPANSEP) except Exception: - logger.exception(f"error parsing {self._db_file}") + logger.exception("error parsing %s", self._db_file) return [] return spans @@ -504,7 +507,7 @@ def drop(self, n_spans: Optional[int] = None): """Drop some currently buffered spans from the cache file.""" current = self.load() if n_spans: - dev_logger.debug(f"dropping {n_spans} spans from buffer") + dev_logger.debug("dropping %d spans from buffer", n_spans) new = current[n_spans:] else: dev_logger.debug("emptying buffer") @@ -693,7 +696,7 @@ def _get_tracing_endpoint( ) dev_logger.debug( - f"Setting up span exporter to endpoint: {tracing_endpoint}/v1/traces" + "Setting up span exporter to endpoint: %s/v1/traces", tracing_endpoint ) return f"{tracing_endpoint}/v1/traces" @@ -711,13 +714,17 @@ def _get_server_cert( if server_cert is None: logger.warning( - f"{charm_type}.{server_cert_attr} is None; sending traces over INSECURE connection." + "%s.%s is None; sending traces over INSECURE connection.", + charm_type, + server_cert_attr, ) return if not isinstance(server_cert, (str, Path)): logger.warning( - f"{charm_type}.{server_cert_attr} has unexpected type {type(server_cert)}; " - f"sending traces over INSECURE connection." + "%s.%s has unexpected type %s; sending traces over INSECURE connection.", + charm_type, + server_cert_attr, + type(server_cert), ) return path = Path(server_cert) @@ -862,13 +869,13 @@ def wrap_init(self: CharmBase, framework: Framework, *args, **kwargs): # log a trace id, so we can pick it up from the logs (and jhack) to look it up in tempo. root_trace_id = hex(span.get_span_context().trace_id)[2:] # strip 0x prefix - logger.debug(f"Starting root trace with id={root_trace_id!r}.") + logger.debug("Starting root trace with id=%r.", root_trace_id) span_token = opentelemetry.context.attach(ctx) # type: ignore @contextmanager def wrap_event_context(event_name: str): - dev_logger.debug(f"entering event context: {event_name}") + dev_logger.debug("entering event context: %s", event_name) # when the framework enters an event context, we create a span. with _span("event: " + event_name) as event_context_span: if event_context_span: @@ -1059,7 +1066,7 @@ def _autoinstrument( Minimum 10MiB. :param buffer_path: path to buffer file to use for saving buffered spans. """ - dev_logger.debug(f"instrumenting {charm_type}") + dev_logger.debug("instrumenting %s", charm_type) _setup_root_span_initializer( charm_type, tracing_endpoint_attr, @@ -1083,12 +1090,12 @@ def trace_type(cls: _T) -> _T: It assumes that this class is only instantiated after a charm type decorated with `@trace_charm` has been instantiated. """ - dev_logger.debug(f"instrumenting {cls}") + dev_logger.debug("instrumenting %s", cls) for name, method in inspect.getmembers(cls, predicate=inspect.isfunction): - dev_logger.debug(f"discovered {method}") + dev_logger.debug("discovered %s", method) if method.__name__.startswith("__"): - dev_logger.debug(f"skipping {method} (dunder)") + dev_logger.debug("skipping %s (dunder)", method) continue # the span title in the general case should be: @@ -1134,7 +1141,7 @@ def trace_function(function: _F, name: Optional[str] = None) -> _F: def _trace_callable(callable: _F, qualifier: str, name: Optional[str] = None) -> _F: - dev_logger.debug(f"instrumenting {callable}") + dev_logger.debug("instrumenting %s", callable) # sig = inspect.signature(callable) @functools.wraps(callable) diff --git a/src/backups.py b/src/backups.py index 0f16aa8093..141b9cec6d 100644 --- a/src/backups.py +++ b/src/backups.py @@ -12,6 +12,7 @@ import tempfile import time from datetime import datetime, timezone +from functools import cached_property from io import BytesIO from pathlib import Path from subprocess import TimeoutExpired, run @@ -86,7 +87,7 @@ def __init__(self, charm, relation_name: str): self.framework.observe(self.charm.on.list_backups_action, self._on_list_backups_action) self.framework.observe(self.charm.on.restore_action, self._on_restore_action) - @property + @cached_property def stanza_name(self) -> str: """Stanza name, composed by model and cluster name.""" return f"{self.model.name}.{self.charm.cluster_name}" diff --git a/src/charm.py b/src/charm.py index 3b2bb9bb2f..87c8b5edf1 100755 --- a/src/charm.py +++ b/src/charm.py @@ -14,6 +14,7 @@ import sys import time from datetime import datetime +from functools import cached_property from hashlib import shake_128 from pathlib import Path from typing import Literal, get_args @@ -236,7 +237,7 @@ def __init__(self, *args): log_slots=[f"{POSTGRESQL_SNAP_NAME}:logs"], tracing_protocols=[TRACING_PROTOCOL], ) - self._tracing_endpoint_config, _ = charm_tracing_config(self._grafana_agent, None) + self.tracing_endpoint, _ = charm_tracing_config(self._grafana_agent, None) def _on_databases_change(self, _): """Handle databases change event.""" @@ -290,11 +291,6 @@ def unit_peer_data(self) -> dict: return relation.data[self.unit] - @property - def tracing_endpoint(self) -> str | None: - """Otlp http endpoint for charm instrumentation.""" - return self._tracing_endpoint_config - def _peer_data(self, scope: Scopes) -> dict: """Return corresponding databag for app/unit.""" relation = self.model.get_relation(PEER) @@ -389,7 +385,7 @@ def is_unit_stopped(self) -> bool: """Returns whether the unit is stopped.""" return "stopped" in self.unit_peer_data - @property + @cached_property def postgresql(self) -> PostgreSQL: """Returns an instance of the object used to interact with the database.""" return PostgreSQL( @@ -401,7 +397,7 @@ def postgresql(self) -> PostgreSQL: system_users=SYSTEM_USERS, ) - @property + @cached_property def primary_endpoint(self) -> str | None: """Returns the endpoint of the primary instance or None when no primary available.""" if not self._peers: @@ -783,7 +779,11 @@ def _reconfigure_cluster(self, event: HookEvent): return False if ip_to_remove in self.members_ips: self._remove_from_members_ips(ip_to_remove) - self._add_members(event) + try: + self._add_members(event) + except Exception: + logger.debug("Deferring on_peer_relation_changed: Unable to add members") + return False return True def _update_member_ip(self) -> bool: @@ -1720,8 +1720,9 @@ def _handle_processes_failures(self) -> bool: # process is running by the PostgreSQL process not). if self._unit_ip in self.members_ips and self._patroni.member_inactive: try: - self._patroni.restart_patroni() logger.info("restarted PostgreSQL because it was not running") + self._patroni.restart_patroni() + self._observer.start_observer() return True except RetryError: logger.error("failed to restart PostgreSQL after checking that it was not running") @@ -1935,12 +1936,13 @@ def _is_workload_running(self) -> bool: @property def _can_connect_to_postgresql(self) -> bool: try: - for attempt in Retrying(stop=stop_after_delay(30), wait=wait_fixed(3)): + for attempt in Retrying(stop=stop_after_delay(10), wait=wait_fixed(3)): with attempt: if not self.postgresql.get_postgresql_timezones(): + logger.debug("Cannot connect to database (CannotConnectError)") raise CannotConnectError except RetryError: - logger.debug("Cannot connect to database") + logger.debug("Cannot connect to database (RetryError)") return False return True @@ -2007,7 +2009,9 @@ def update_config(self, is_creating_backup: bool = False, no_peers: bool = False "wal_keep_size": self.config.durability_wal_keep_size, }) - self._handle_postgresql_restart_need(enable_tls) + self._handle_postgresql_restart_need( + enable_tls, self.unit_peer_data.get("config_hash") != self.generate_config_hash + ) cache = snap.SnapCache() postgres_snap = cache[POSTGRESQL_SNAP_NAME] @@ -2019,7 +2023,10 @@ def update_config(self, is_creating_backup: bool = False, no_peers: bool = False self._restart_metrics_service(postgres_snap) self._restart_ldap_sync_service(postgres_snap) - self.unit_peer_data.update({"user_hash": self.generate_user_hash}) + self.unit_peer_data.update({ + "user_hash": self.generate_user_hash, + "config_hash": self.generate_config_hash, + }) if self.unit.is_leader(): self.app_peer_data.update({"user_hash": self.generate_user_hash}) return True @@ -2051,22 +2058,30 @@ def _validate_config_options(self) -> None: "storage_default_table_access_method config option has an invalid value" ) - def _handle_postgresql_restart_need(self, enable_tls: bool) -> None: + def _handle_postgresql_restart_need(self, enable_tls: bool, config_changed: bool) -> None: """Handle PostgreSQL restart need based on the TLS configuration and configuration changes.""" restart_postgresql = self.is_tls_enabled != self.postgresql.is_tls_enabled() - self._patroni.reload_patroni_configuration() - # Wait for some more time than the Patroni's loop_wait default value (10 seconds), - # which tells how much time Patroni will wait before checking the configuration - # file again to reload it. try: - for attempt in Retrying(stop=stop_after_attempt(5), wait=wait_fixed(3)): - with attempt: - restart_postgresql = restart_postgresql or self.postgresql.is_restart_pending() - if not restart_postgresql: - raise Exception - except RetryError: - # Ignore the error, as it happens only to indicate that the configuration has not changed. - pass + self._patroni.reload_patroni_configuration() + except Exception as e: + logger.error(f"Reload patroni call failed! error: {e!s}") + + if config_changed and not restart_postgresql: + # Wait for some more time than the Patroni's loop_wait default value (10 seconds), + # which tells how much time Patroni will wait before checking the configuration + # file again to reload it. + try: + for attempt in Retrying(stop=stop_after_attempt(5), wait=wait_fixed(3)): + with attempt: + restart_postgresql = ( + restart_postgresql or self.postgresql.is_restart_pending() + ) + if not restart_postgresql: + raise Exception + except RetryError: + # Ignore the error, as it happens only to indicate that the configuration has not changed. + pass + self.unit_peer_data.update({"tls": "enabled" if enable_tls else ""}) self.postgresql_client_relation.update_endpoints() @@ -2104,14 +2119,9 @@ def client_relations(self) -> list[Relation]: @property def relations_user_databases_map(self) -> dict: """Returns a user->databases map for all relations.""" - user_database_map = {} # Copy relations users directly instead of waiting for them to be created - for relation in self.model.relations[self.postgresql_client_relation.relation_name]: - user = f"relation-{relation.id}" - if database := self.postgresql_client_relation.database_provides.fetch_relation_field( - relation.id, "database" - ): - user_database_map[user] = database + user_database_map = self._collect_user_relations() + if not self.is_cluster_initialised or not self._patroni.member_started: user_database_map.update({ USER: "all", @@ -2164,17 +2174,32 @@ def relations_user_databases_map(self) -> dict: logger.debug("relations_user_databases_map: Unable to get users") return {USER: "all", REPLICATION_USER: "all", REWIND_USER: "all"} - @property + def _collect_user_relations(self) -> dict[str, str]: + user_db_pairs = {} + for relation in self.client_relations: + user = f"relation-{relation.id}" + if relation.name == "database": + if ( + database + := self.postgresql_client_relation.database_provides.fetch_relation_field( + relation.id, "database" + ) + ): + user_db_pairs[user] = database + else: + if database := self.get_secret(APP_SCOPE, f"{user}-database"): + user_db_pairs[user] = database + return user_db_pairs + + @cached_property def generate_user_hash(self) -> str: """Generate expected user and database hash.""" - user_db_pairs = {} - for relation in self.model.relations[self.postgresql_client_relation.relation_name]: - if database := self.postgresql_client_relation.database_provides.fetch_relation_field( - relation.id, "database" - ): - user = f"relation_id_{relation.id}" - user_db_pairs[user] = database - return shake_128(str(user_db_pairs).encode()).hexdigest(16) + return shake_128(str(self._collect_user_relations()).encode()).hexdigest(16) + + @cached_property + def generate_config_hash(self) -> str: + """Generate current configuration hash.""" + return shake_128(str(self.config.dict()).encode()).hexdigest(16) def override_patroni_restart_condition( self, new_condition: str, repeat_cause: str | None diff --git a/src/cluster.py b/src/cluster.py index 3e09123480..4e6055a2b1 100644 --- a/src/cluster.py +++ b/src/cluster.py @@ -11,6 +11,7 @@ import re import shutil import subprocess +from functools import cached_property from pathlib import Path from typing import Any @@ -154,11 +155,11 @@ def __init__( # TLS is enabled, otherwise True is set because it's the default value. self.verify = f"{PATRONI_CONF_PATH}/{TLS_CA_FILE}" if tls_enabled else True - @property + @cached_property def _patroni_auth(self) -> requests.auth.HTTPBasicAuth: return requests.auth.HTTPBasicAuth("patroni", self.patroni_password) - @property + @cached_property def _patroni_url(self) -> str: """Patroni REST API URL.""" return f"{'https' if self.tls_enabled else 'http'}://{self.unit_ip}:8008" @@ -202,8 +203,7 @@ def _change_owner(self, path: str) -> None: # Set the correct ownership for the file or directory. os.chown(path, uid=user_database.pw_uid, gid=user_database.pw_gid) - @property - @retry(stop=stop_after_attempt(10), wait=wait_exponential(multiplier=1, min=2, max=10)) + @cached_property def cluster_members(self) -> set: """Get the current cluster members.""" # Request info from cluster endpoint (which returns all members of the cluster). @@ -686,7 +686,7 @@ def render_patroni_yml_file( partner_addrs=self.charm.async_replication.get_partner_addresses() if not no_peers else [], - peers_ips=self.peers_ips if not no_peers else set(), + peers_ips=sorted(self.peers_ips) if not no_peers else set(), pgbackrest_configuration_file=PGBACKREST_CONFIGURATION_FILE, scope=self.cluster_name, self_ip=self.unit_ip, @@ -1034,7 +1034,7 @@ def bulk_update_parameters_controller_by_patroni(self, parameters: dict[str, Any timeout=PATRONI_TIMEOUT, ) - @property + @cached_property def _synchronous_node_count(self) -> int: planned_units = self.charm.app.planned_units() if self.charm.config.synchronous_node_count == "all": diff --git a/src/relations/db.py b/src/relations/db.py index d789d6d15b..ce0b80c9dd 100644 --- a/src/relations/db.py +++ b/src/relations/db.py @@ -11,6 +11,7 @@ PostgreSQLCreateDatabaseError, PostgreSQLCreateUserError, PostgreSQLGetPostgreSQLVersionError, + PostgreSQLListUsersError, ) from ops.charm import ( CharmBase, @@ -111,12 +112,17 @@ def _on_relation_changed(self, event: RelationChangedEvent) -> None: """ # Check for some conditions before trying to access the PostgreSQL instance. if not self.charm.unit.is_leader(): - if ( - not self.charm._patroni.member_started - or f"relation-{event.relation.id}" - not in self.charm.postgresql.list_users(current_host=True) - ): - logger.debug("Deferring on_relation_changed: user was not created yet") + try: + if ( + not self.charm._patroni.member_started + or f"relation-{event.relation.id}" + not in self.charm.postgresql.list_users(current_host=True) + ): + logger.debug("Deferring on_relation_changed: user was not created yet") + event.defer() + return + except PostgreSQLListUsersError: + logger.debug("Deferring on_relation_changed: unable to list users") event.defer() return @@ -142,6 +148,12 @@ def _on_relation_changed(self, event: RelationChangedEvent) -> None: self.set_up_relation(event.relation) + if not self.charm.postgresql.is_user_in_hba(f"relation-{event.relation.id}"): + logger.debug("Deferring on_relation_changed: User not in pg_hba yet.") + event.defer() + return + self.update_endpoints(event.relation) + def _get_extensions(self, relation: Relation) -> tuple[list, set]: """Returns the list of required and disabled extensions.""" requested_extensions = relation.data.get(relation.app, {}).get("extensions", "").split(",") @@ -196,14 +208,19 @@ def set_up_relation(self, relation: Relation) -> bool: # a database name in it (like the relation with Landscape server charm), # so create a database with the other application name. if not database: - database = relation.app.name + if relation.app: + database = relation.app.name + else: + logger.debug("Early exit setup relation: no remote application") + return False try: unit_relation_databag = relation.data[self.charm.unit] # Creates the user and the database for this specific relation if it was not already # created in a previous relation changed event. - password = unit_relation_databag.get("password", new_password()) + if not (password := self.charm.get_secret(APP_SCOPE, user)): + password = unit_relation_databag.get("password", new_password()) # Store the user, password and database name in the secret store to be accessible by # non-leader units when the cluster topology changes. @@ -225,8 +242,6 @@ def set_up_relation(self, relation: Relation) -> bool: ) return False - self.update_endpoints(relation) - self._update_unit_status(relation) self.charm.update_config() diff --git a/tests/integration/test_db.py b/tests/integration/test_db.py index 3b643be254..70854e9d2a 100644 --- a/tests/integration/test_db.py +++ b/tests/integration/test_db.py @@ -58,6 +58,7 @@ async def test_mailman3_core_db(ops_test: OpsTest, charm: str) -> None: apps=[DATABASE_APP_NAME], status="active", timeout=1500, + idle_period=30, wait_for_exact_units=DATABASE_UNITS, ) @@ -135,7 +136,11 @@ async def test_relation_data_is_updated_correctly_when_scaling(ops_test: OpsTest ) await ops_test.model.applications[DATABASE_APP_NAME].destroy_units(leader_unit.name) await ops_test.model.wait_for_idle( - apps=[DATABASE_APP_NAME], status="active", timeout=600, wait_for_exact_units=2 + apps=[DATABASE_APP_NAME], + status="active", + timeout=600, + wait_for_exact_units=2, + idle_period=30, ) logger.info( diff --git a/tests/unit/test_charm.py b/tests/unit/test_charm.py index db5a67d1b8..d1a524e226 100644 --- a/tests/unit/test_charm.py +++ b/tests/unit/test_charm.py @@ -1287,7 +1287,7 @@ def test_update_config(harness): no_peers=False, user_databases_map={"operator": "all", "replication": "all", "rewind": "all"}, ) - _handle_postgresql_restart_need.assert_called_once_with(False) + _handle_postgresql_restart_need.assert_called_once_with(False, True) _restart_ldap_sync_service.assert_called_once() _restart_metrics_service.assert_called_once() assert "tls" not in harness.get_relation_data(rel_id, harness.charm.unit.name) @@ -2353,7 +2353,7 @@ def test_handle_postgresql_restart_need(harness): postgresql_mock.is_tls_enabled = PropertyMock(return_value=values[2]) postgresql_mock.is_restart_pending = PropertyMock(return_value=values[3]) - harness.charm._handle_postgresql_restart_need(values[0]) + harness.charm._handle_postgresql_restart_need(values[0], True) _reload_patroni_configuration.assert_called_once() if values[0]: assert "tls" in harness.get_relation_data(rel_id, harness.charm.unit) diff --git a/tests/unit/test_cluster.py b/tests/unit/test_cluster.py index e46dde3c31..9fc41363fa 100644 --- a/tests/unit/test_cluster.py +++ b/tests/unit/test_cluster.py @@ -366,7 +366,7 @@ def test_render_patroni_yml_file(peers_ips, patroni): postgresql_log_path=POSTGRESQL_LOGS_PATH, member_name=member_name, partner_addrs=["2.2.2.2", "3.3.3.3"], - peers_ips=peers_ips, + peers_ips=sorted(peers_ips), scope=scope, self_ip=patroni.unit_ip, superuser="operator", diff --git a/tests/unit/test_db.py b/tests/unit/test_db.py index a811687f3a..65a9e01a4b 100644 --- a/tests/unit/test_db.py +++ b/tests/unit/test_db.py @@ -86,6 +86,7 @@ def test_on_relation_changed(harness): patch("charm.PostgresqlOperatorCharm.update_config"), patch.object(PostgresqlOperatorCharm, "postgresql", Mock()) as postgresql_mock, patch("charm.DbProvides.set_up_relation") as _set_up_relation, + patch("charm.DbProvides.update_endpoints"), patch.object(EventBase, "defer") as _defer, patch( "charm.PostgresqlOperatorCharm.primary_endpoint", @@ -188,7 +189,6 @@ def test_set_up_relation(harness): patch.object(PostgresqlOperatorCharm, "postgresql", Mock()) as postgresql_mock, patch("subprocess.check_output", return_value=b"C"), patch("relations.db.DbProvides._update_unit_status") as _update_unit_status, - patch("relations.db.DbProvides.update_endpoints") as _update_endpoints, patch("relations.db.new_password", return_value="test-password") as _new_password, patch("relations.db.DbProvides._get_extensions") as _get_extensions, ): @@ -218,7 +218,6 @@ def test_set_up_relation(harness): postgresql_mock.create_user.assert_not_called() postgresql_mock.create_database.assert_not_called() postgresql_mock.get_postgresql_version.assert_not_called() - _update_endpoints.assert_not_called() _update_unit_status.assert_not_called() # Assert that the correct calls were made in a successful setup. @@ -237,7 +236,6 @@ def test_set_up_relation(harness): postgresql_mock.create_database.assert_called_once_with( DATABASE, user, plugins=["pgaudit"], client_relations=[relation] ) - _update_endpoints.assert_called_once() _update_unit_status.assert_called_once() assert not isinstance(harness.model.unit.status, BlockedStatus) @@ -246,7 +244,6 @@ def test_set_up_relation(harness): postgresql_mock.create_user.reset_mock() postgresql_mock.create_database.reset_mock() postgresql_mock.get_postgresql_version.reset_mock() - _update_endpoints.reset_mock() _update_unit_status.reset_mock() with harness.hooks_disabled(): harness.update_relation_data( @@ -266,7 +263,6 @@ def test_set_up_relation(harness): postgresql_mock.create_database.assert_called_once_with( DATABASE, user, plugins=["pgaudit"], client_relations=[relation] ) - _update_endpoints.assert_called_once() _update_unit_status.assert_called_once() assert not isinstance(harness.model.unit.status, BlockedStatus) @@ -274,7 +270,6 @@ def test_set_up_relation(harness): postgresql_mock.create_user.reset_mock() postgresql_mock.create_database.reset_mock() postgresql_mock.get_postgresql_version.reset_mock() - _update_endpoints.reset_mock() _update_unit_status.reset_mock() with harness.hooks_disabled(): harness.update_relation_data( @@ -289,25 +284,21 @@ def test_set_up_relation(harness): postgresql_mock.create_database.assert_called_once_with( "test_database", user, plugins=["pgaudit"], client_relations=[relation] ) - _update_endpoints.assert_called_once() _update_unit_status.assert_called_once() assert not isinstance(harness.model.unit.status, BlockedStatus) # BlockedStatus due to a PostgreSQLCreateUserError. postgresql_mock.create_database.reset_mock() postgresql_mock.get_postgresql_version.reset_mock() - _update_endpoints.reset_mock() _update_unit_status.reset_mock() assert not harness.charm.legacy_db_relation.set_up_relation(relation) postgresql_mock.create_database.assert_not_called() - _update_endpoints.assert_not_called() _update_unit_status.assert_not_called() assert isinstance(harness.model.unit.status, BlockedStatus) # BlockedStatus due to a PostgreSQLCreateDatabaseError. harness.charm.unit.status = ActiveStatus() assert not harness.charm.legacy_db_relation.set_up_relation(relation) - _update_endpoints.assert_not_called() _update_unit_status.assert_not_called() assert isinstance(harness.model.unit.status, BlockedStatus) From 544ac72f050cd06a5a153a733587a09cf8bb64c7 Mon Sep 17 00:00:00 2001 From: Andreia Date: Mon, 22 Sep 2025 19:38:13 +0200 Subject: [PATCH 100/112] Update versions and release documentation (14) (#1158) * Refactor charm version explanation pages * refactor releases reference pages * Move all legacy information to legacy charm page * Add feature lists back to modern charm versions page * fix broken references --- docs/conf.py | 4 +- docs/explanation/charm-versions/index.md | 44 ++++++ .../charm-versions/legacy-charm.md | 85 ++++++++++++ .../charm-versions/modern-charm.md | 110 +++++++++++++++ docs/explanation/index.md | 2 +- docs/explanation/interfaces-and-endpoints.md | 4 +- docs/explanation/legacy-charm.md | 103 --------------- docs/explanation/security/index.md | 2 +- docs/how-to/deploy/juju-storage.md | 2 +- docs/how-to/deploy/tls-vip-access.md | 2 +- .../development/integrate-with-your-charm.md | 3 +- .../migrate-data-via-backup-restore.md | 4 +- .../development/migrate-data-via-pg-dump.md | 4 +- .../integrate-with-another-application.md | 2 +- docs/index.md | 2 +- docs/redirects.txt | 4 +- docs/reference/index.md | 1 - docs/reference/releases.md | 13 +- docs/reference/statuses.md | 2 +- docs/reference/versions.md | 125 ------------------ 20 files changed, 266 insertions(+), 252 deletions(-) create mode 100644 docs/explanation/charm-versions/index.md create mode 100644 docs/explanation/charm-versions/legacy-charm.md create mode 100644 docs/explanation/charm-versions/modern-charm.md delete mode 100644 docs/explanation/legacy-charm.md delete mode 100644 docs/reference/versions.md diff --git a/docs/conf.py b/docs/conf.py index eba2ae7345..4465ed9727 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -335,5 +335,7 @@ # Add configuration for intersphinx mapping intersphinx_mapping = { - 'starter-pack': ('https://canonical-example-product-documentation.readthedocs-hosted.com/en/latest', None) + 'postgresql-16': ('https://canonical-charmed-postgresql.readthedocs-hosted.com/16/', None) } + +myst_url_schemes = ["http", "https", ] diff --git a/docs/explanation/charm-versions/index.md b/docs/explanation/charm-versions/index.md new file mode 100644 index 0000000000..2e073e9d57 --- /dev/null +++ b/docs/explanation/charm-versions/index.md @@ -0,0 +1,44 @@ +# PostgreSQL major versions + +Charmed PostgreSQL is available in multiple versions to support different deployment requirements and lifecycle stages. It is shipped in the following [tracks](https://documentation.ubuntu.com/juju/3.6/reference/charm/#track): + + +| Charm name | Charmhub channel | Type | Status | +| ----------------------- | ---------------- | ------ | ----------------------------------------------------------------- | +| PostgreSQL 16 | `16/stable` | modern | ![check] Latest version - new features are released here | +| PostgreSQL 14 | `14/stable` | modern | ![check] In maintenance mode - bug fixes and security updates only | +| Legacy PostgreSQL charm | `latest/stable` | legacy | ![cross] Deprecated | + +## Legacy vs. modern + +There are two [generations](https://documentation.ubuntu.com/juju/3.6/reference/charm/#by-generation) of charms stored under the same charm name `postgresql`. In these docs, we refer to them as "legacy" and "modern". + +Legacy charm +: Also known as a [Reactive charm](https://documentation.ubuntu.com/juju/3.6/reference/charm/#reactive-charm). Found in the Charmhub channel `latest/stable`. +: Provided `db` and `db-admin` endpoints for the `pgsql` interface. + +Modern charm +: Also known as an [Ops charm](https://documentation.ubuntu.com/juju/3.6/reference/charm/#ops-charm). Found in the Charmhub channels `14/stable` and `16/stable`. +: `14/stable` provides legacy endpoints and new `database` endpoint for the `postgresql_client` interface. +: `16/stable` **does not** provide legacy endpoints - only the new `database` `database` endpoint for the `postgresql_client` interface. + +```{seealso} +* [](/explanation/charm-versions/legacy-charm) +* [](/explanation/charm-versions/modern-charm) +* [](/explanation/interfaces-and-endpoints) +``` + + + +[cross]: https://img.icons8.com/?size=16&id=CKkTANal1fTY&format=png&color=D00303 +[check]: https://img.icons8.com/color/20/checkmark--v1.png + +```{toctree} +:titlesonly: +:maxdepth: 2 +:glob: +:hidden: + +Legacy charm +Modern charm +``` \ No newline at end of file diff --git a/docs/explanation/charm-versions/legacy-charm.md b/docs/explanation/charm-versions/legacy-charm.md new file mode 100644 index 0000000000..227f7c56a4 --- /dev/null +++ b/docs/explanation/charm-versions/legacy-charm.md @@ -0,0 +1,85 @@ +# Legacy PostgreSQL charm + +The legacy PostgreSQL charm is a [Reactive charm](https://documentation.ubuntu.com/juju/3.6/reference/charm/#reactive-charm) in the Charmhub channel `latest/stable`. + +It provided `db` and `db-admin` endpoints for the `pgsql` interface. + +**We strongly advise against using the now deprecated `latest/` track**. It will be removed from Charmhub in the near future. + +## The default Charmhub track + +The [default track](https://docs.openstack.org/charm-guide/yoga/project/charm-delivery.html) was switched from the `latest/` to `14/` to ensure all new deployments use a modern codebase. See [this Discourse post](https://discourse.charmhub.io/t/request-switch-default-track-from-latest-to-14-for-postgresql-k8s-charms/10314) for more information about the switch. + +## How to migrate from legacy to modern + +To migrate from the legacy PostgreSQL charm to the modern PostgreSQL 14 charm, you can use two approaches: + +**Quick method**: Since PostgreSQL 14 provides the legacy databases, you can simply relate your application with the new charm with the same `db` endpoint without any extra changes: + +```text + postgresql: + charm: postgresql + channel: 14/stable +``` + +However, keep in mind that PostgreSQL 16 no longer supports legacy interfaces, so if you plan on moving to 16 in the future, you will need to use the method below eventually. + +**Recommended method**: Migrate your application to the new [`postgresql_client` interface](https://github.com/canonical/charm-relation-interfaces). + +The application will connect to PostgreSQL using the [`data_interfaces`](https://charmhub.io/data-platform-libs/libraries/data_interfaces) library from [data-platform-libs](https://github.com/canonical/data-platform-libs/) via the `database` endpoint. + +See: [](/how-to/development/integrate-with-your-charm) + +## How to deploy the legacy PostgreSQL charm + +Deploy the charm using the channel `latest/stable`: + +```yaml + postgresql: + charm: postgresql + channel: latest/stable +``` + +```{caution} +Remove the charm store prefix `cs:` from the bundle. Otherwise, the modern charm will be chosen by Juju (due to the default track pointing to `14/stable` and not `latest/stable`). + +A common error message is: `cannot deploy application "postgresql": unknown option "..."`. +``` + +## Configuration options + +The legacy charm config options were not moved to the modern charms. Modern charms apply the best possible configuration automatically. + +Feel free to [contact us](/reference/contacts) about the database tuning and configuration options. + +## Extensions supported by modern charm + +The legacy charm provided plugins/extensions enabling through the relation (interface `pgsql`).This is NOT supported by modern charms (neither `pgsql` nor `postgresql_client` interfaces). Please enable the necessary extensions using appropriate `plugin_*_enable` [config option](https://charmhub.io/postgresql/configure) of the modern charm. After enabling the modern charm, it will provide plugins support for both `pgsql` (only if it's PostgreSQL 14) and `postgresql_client` interfaces. + +See: [](/reference/plugins-extensions) + +Feel free to [contact us](/reference/contacts) if there is a particular extension you are interested in. + +## Roles supported by modern charm + +In the legacy charm, the user could request roles by setting the `roles` field to a comma separated list of desired roles. This is NOT supported by the `14/` modern charm implementation of the legacy `pgsql` interface. + +The same functionality is provided via the modern `postgresql_client` using [extra-user-roles](/explanation/users). + +For more information about migrating the new interface on PostgreSQL 14, see {ref}`integrate-with-your-charm`. + +## Workload artifacts + +The legacy charm used to deploy PostgreSQL from APT/Debian packages, +while the modern charm installs and operates PostgreSQL snap [charmed-postgresql](https://snapcraft.io/charmed-postgresql). + +See: [](/explanation/architecture). + +## How to report issues and contact authors + +The legacy charm (from `latest/stable`) is stored on [Launchpad](https://git.launchpad.net/postgresql-charm/). Report legacy charm issues [here](https://bugs.launchpad.net/postgresql-charm). + +The modern charms are stored on GitHub: [PostgreSQL 14 branch](https://github.com/canonical/postgresql-operator/tree/main) and [PostgreSQL 16 branch](https://github.com/canonical/postgresql-operator/tree/16/edge) . Report modern charm issues [here](https://github.com/canonical/postgresql-operator/issues/new/choose). + +Do you have questions? [Contact us](/reference/contacts)! + diff --git a/docs/explanation/charm-versions/modern-charm.md b/docs/explanation/charm-versions/modern-charm.md new file mode 100644 index 0000000000..7367f5c86d --- /dev/null +++ b/docs/explanation/charm-versions/modern-charm.md @@ -0,0 +1,110 @@ +# Modern PostgreSQL charm + +Modern PostgreSQL charms are [Ops charms](https://documentation.ubuntu.com/juju/3.6/reference/charm/#ops-charm) released in the Charmhub channels `14/` and `16/`. + +Both modern charms provide the `database` endpoint for the `postgresql_client` interface. + +PostgreSQL 14 (track `14/`) additionally provides `db` and `db-admin` endpoints for the legacy `pgsql` interface, and supports migration from the legacy charm. + +PostgreSQL 16 (track `16/`) does not provide legacy endpoints. + +```{note} +You are currently viewing the documentation for **Charmed PostgreSQL 14**. + +To switch between versions, use the small rectangular menu at the bottom right corner of the page. +``` + +## PostgreSQL 16 + +**Latest stable version** with active feature development. + +* **Base:** Ubuntu 24.04 LTS (Noble) +* **Supported architectures:** `amd64`, `arm64` +* **Channel:** `16/stable` (latest development available for testing in `16/edge`) +* **Juju version:** Requires Juju 3.6+ LTS +* **Support status:** ![check] Active development and full support + +### New features + +* [**Juju spaces**](https://canonical-charmed-postgresql.readthedocs-hosted.com/16/how-to/deploy/juju-spaces) - Enhanced networking capabilities for complex deployment scenarios +* [**Juju user secrets**](https://documentation.ubuntu.com/juju/latest/reference/secret/index.html#user-secret) - Secure management of the charm's [internal passwords](https://canonical-charmed-postgresql.readthedocs-hosted.com/16/how-to/manage-passwords) +* **Improved** [**security hardening**](https://canonical-charmed-postgresql.readthedocs-hosted.com/16/explanation/security) - Enhanced security posture and best practices +* **TLS v4 library migration** + * New endpoints `client-certificates` and `peer-certificates` + * Endpoint `peer-interfaces` uses TLS by default + * See all endpoints on [Charmhub](https://charmhub.io/postgresql/integrations?channel=16/stable) +* [**Timescale Community Edition**](https://canonical-charmed-postgresql.readthedocs-hosted.com/16/how-to/enable-plugins-extensions/enable-timescaledb) replaces Timescale Apache 2 +* **Improved** [**built-in roles**](https://canonical-charmed-postgresql.readthedocs-hosted.com/16/explanation/roles) - Enhanced role-based access control system +* **New** **refresh process** for in-place upgrades + +### Deprecated or removed + +Important changes to keep in mind when migrating from 14 to 16: + +* **Legacy interface `psql`** - Endpoints `db` and `db-admin` are no longer supported + * See [](https://canonical-charmed-postgresql.readthedocs-hosted.com/16/explanation/interfaces-and-endpoints) for current supported interfaces +* **Support for Juju < `v3.6` removed** + * Charmed PostgreSQL 16 requires Juju `3.6+ LTS` due to [Juju secrets](https://documentation.ubuntu.com/juju/3.6/reference/secret/index.html) support +* **Juju actions `get-password` and `set-password` removed** + * Replaced by [Juju secrets](https://documentation.ubuntu.com/juju/3.6/reference/secret/index.html) for enhanced security +* **[Timescale Apache 2 edition](https://docs.timescale.com/about/latest/timescaledb-editions/) replaced** + * Now uses [Timescale Community edition](https://docs.timescale.com/about/latest/timescaledb-editions/) +* **Charm action `set-tls-private-key` removed** + * Will be re-introduced as Juju User Secrets in future releases +* **Charm actions renamed for consistency:** + * `pre-upgrade-check` → `pre-refresh-check` + * `resume-upgrade` → `resume-refresh` + * Changes align with `juju refresh` terminology +* **Charm endpoint `certificates` split into separate endpoints:** + * `client-certificates` - For client certificate management + * `peer-certificates` - For peer-to-peer certificate management + +For detailed information about PostgreSQL 16 features, see the {doc}`PostgreSQL 16 releases page ` + +## PostgreSQL 14 + +**Maintenance mode** with bug fixes and security updates only. + +* **Base:** Ubuntu 22.04 LTS (Jammy) +* **Supported architectures:** `amd64`, `arm64` +* **Channel:** `14/stable` +* **Juju version:** Partially compatible with older Juju versions down to 2.9 +* **Support status:** 🔧 Bug fixes and security updates only + +### Features + +* [**Deployment on multiple cloud services**](/how-to/deploy/index), including Sunbeam, MAAS, AWS, GCE, and Azure +* [**Juju storage**](/how-to/deploy/juju-storage) - Flexible storage configuration options +* [**Back up and restore**](/how-to/back-up-and-restore/index), including point-in-time recovery +* [**COS integration**](/how-to/monitoring-cos/index) - Enable observability tools like Grafana, Loki, Tempo, and Parca +* [**TLS integration**](/how-to/enable-tls) +* [**LDAP integration**](/how-to/enable-ldap) - Centralised authentication for PostgreSQL clusters +* [**`amd64` and `arm64`architecture** support](/reference/system-requirements) + +For detailed information about all PostgreSQL 14 releases, see the [Releases page](/reference/releases). + +## Choosing a version + +| Version | Support Status | Base | Juju Version | Key Features | +|---------|----------------|------|--------------|-------------| +| **PostgreSQL 16** | ![check] Active development | Ubuntu 24.04 LTS | 3.6+ LTS | Modern features, enhanced security, Juju Spaces | +| **PostgreSQL 14** | 🔧 Maintenance mode | Ubuntu 22.04 LTS | 2.9+ | Core database features, stable platform | +| **Legacy** | ![cross] Deprecated | Older base | Legacy versions | Not recommended | + + +* **For new deployments**: Use **PostgreSQL 16** for the latest features and long-term support +* **For existing PostgreSQL 14 deployments**: Continue using PostgreSQL 14 or plan migration to 16 +* **For legacy charm users**: Migrate to PostgreSQL 14 as soon as possible + + + +[PostgreSQL 16]: https://charmhub.io/postgresql?channel=16/beta +[PostgreSQL 14]: https://charmhub.io/postgresql?channel=14/stable +[Legacy PostgreSQL charm]: https://charmhub.io/postgresql?channel=latest/stable + +[Version 16 Release Notes]: /reference/version-16-release-notes +[release notes]: /reference/releases +[legacy charm explanation page]: /explanation/charm-versions/legacy-charm + +[cross]: https://img.icons8.com/?size=16&id=CKkTANal1fTY&format=png&color=D00303 +[check]: https://img.icons8.com/color/20/checkmark--v1.png \ No newline at end of file diff --git a/docs/explanation/index.md b/docs/explanation/index.md index 49990c65f1..af8125944b 100644 --- a/docs/explanation/index.md +++ b/docs/explanation/index.md @@ -10,7 +10,7 @@ Additional context about key concepts behind the PostgreSQL charm, including des Architecture Interfaces and endpoints Juju -Legacy charm +Charm versions ``` ## Operational concepts diff --git a/docs/explanation/interfaces-and-endpoints.md b/docs/explanation/interfaces-and-endpoints.md index 842cb2f3cc..e76b2d7523 100644 --- a/docs/explanation/interfaces-and-endpoints.md +++ b/docs/explanation/interfaces-and-endpoints.md @@ -1,4 +1,4 @@ -# Interfaces/endpoints +# Interfaces and endpoints The charm supports modern `postgresql_client` and legacy `pgsql` interfaces (in a backward compatible mode). @@ -39,7 +39,7 @@ Find all details about default and extra DB user roles in "[Charm Users explanat ```{note} Legacy relations are deprecated and will be discontinued on future releases. Their usage should be avoided. -Check the legacy interfaces implementation limitations in [](/explanation/legacy-charm)" +Check the legacy interfaces implementation limitations in [](/explanation/charm-versions/legacy-charm)" ``` ### Legacy `pgsql` interface (`db` and `db-admin` endpoints): diff --git a/docs/explanation/legacy-charm.md b/docs/explanation/legacy-charm.md deleted file mode 100644 index edbbc3df7e..0000000000 --- a/docs/explanation/legacy-charm.md +++ /dev/null @@ -1,103 +0,0 @@ -# Legacy charm - -There are [two types of charms](https://documentation.ubuntu.com/juju/3.6/reference/charm/#by-generation) stored under the same charm name `postgresql`: - -1. [Reactive](https://documentation.ubuntu.com/juju/3.6/reference/charm/#reactive) charm in the channel `latest/stable` (called `legacy`) -2. [Ops-based](https://documentation.ubuntu.com/juju/3.6/reference/charm/#ops) charm in the channel `14/stable` (called `modern`) - -The legacy charm provided endpoints `db` and `db-admin` (for the interface `pgsql`). The modern charm provides old endpoints as well + new endpoint `database` (for the interface `postgresql_client`). Read more details about the available [endpoints/interfaces](/explanation/interfaces-and-endpoints). - -```{note} -Choose one endpoint to use, rather than relating both simultaneously. -``` - -## The default track "latest" vs "14" - -The [default track](https://docs.openstack.org/charm-guide/yoga/project/charm-delivery.html) has been switched from the `latest` to `14`. It is [to ensure](https://discourse.charmhub.io/t/request-switch-default-track-from-latest-to-14-for-postgresql-k8s-charms/10314) all new deployments use a modern codebase. We strongly advise against using the latest track due to its implicit nature. In doing so, a future charm upgrade may result in a PostgreSQL version incompatible with an integrated application. Track 14 guarantees PostgreSQL 14 deployment only. The track `latest` will be closed after all applications migrated from Reactive to Ops-based charm. - -## How to migrate from "legacy" to "modern" charm - -The "modern" charm provides temporary support for the legacy interfaces: - -* **quick try**: relate the current application with new charm using endpoint `db` (set the channel to `14/stable`). No extra changes necessary: - -```text - postgresql: - charm: postgresql - channel: 14/stable -``` - -* **proper migration**: migrate the application to the new interface "[postgresql_client](https://github.com/canonical/charm-relation-interfaces)". The application will connect PostgreSQL using "[data_interfaces](https://charmhub.io/data-platform-libs/libraries/data_interfaces)" library from "[data-platform-libs](https://github.com/canonical/data-platform-libs/)" via endpoint `database`. - - -```{warning} -**In-place upgrades are not supported for this case.** - -Reactive charms cannot be upgraded to an operator-framework-based version. To move database data, the new DB application must be launched nearby, and data should be copied from "legacy" application to the "modern" one. - -Please [contact us](/reference/contacts) if you need migration instructions. -``` - -## How to deploy old "legacy" PostgreSQL charm - -Deploy the charm using the channel `latest/stable`: - -```text - postgresql: - charm: postgresql - channel: latest/stable -``` - -```{caution} -Remove the charm store prefix `cs:` from the bundle. - -Otherwise, the modern charm will be chosen by Juju (due to the default track pointing to `14/stable` and not `latest/stable`). - -A common error message is: `cannot deploy application "postgresql": unknown option "..."`. -``` - -## Config options supported by modern charm - -The legacy charm config options were not moved to the modern charm due to no need. The modern charm applies the best possible configuration automatically. - -Feel free to [contact us](/reference/contacts) about the DB tuning/config options. - -## Extensions supported by modern charm - -The legacy charm provided plugins/extensions enabling through the relation (interface `pgsql`). It is NOT supported by the modern charm (neither `pgsql` nor `postgresql_client` interfaces). Please enable the necessary extensions using appropriate `plugin_*_enable` [config option](https://charmhub.io/postgresql/configure) of the modern charm. After enabling the modern charm, it will provide plugins support for both `pgsql` and `postgresql_client` interfaces. - -Please find the list of supported PostgreSQL [Extensions](/reference/plugins-extensions) by modern charm. - -Feel free to [contact us](/reference/contacts) with a list of required extensions. - -## Roles supported by modern charm - -In the legacy charm, the user could request roles by setting the `roles` field to a comma separated list of desired roles. It is NOT supported by the modern charm implementation of the legacy `pgsql` interface. The same functionality is provided via the modern `postgresql_client` using "[extra-user-roles](/explanation/users)". - -For more information about migrating the new interface, see [this guide](/how-to/development/integrate-with-your-charm). - -## Supported PostgreSQL versions by modern charm - -At the moment, the modern charms support PostgreSQL 14 (based on Jammy/22.04 series) only. - -Please [contact us](/reference/contacts) if you need different versions/series. - -## Supported architectures - -Currently, the charm supports architecture `amd64` (all revisions) and `arm64` (from revision 396+). - -See the technical details in [Supported architectures](/reference/system-requirements). - -## Workload artifacts - -The legacy charm used to deploy PostgreSQL from APT/Debian packages, -while the modern charm installs and operates PostgreSQL snap "[charmed-postgresql](https://snapcraft.io/charmed-postgresql)". Check more details in [the modern charm architecture](/explanation/architecture). - -## How to report issues and contact authors - -The "legacy charm" (from `latest/stable`) is stored on [Launchpad](https://git.launchpad.net/postgresql-charm/), here is the link to report all [legacy charm issues](https://bugs.launchpad.net/postgresql-charm). - -The "modern charm" (from `14/stable`) is stored on [GitHub](https://github.com/canonical/postgresql-operator), here is the link to report [modern charm issues](https://github.com/canonical/postgresql-operator/issues/new/choose). - -Do you have questions? [Contact us](/reference/contacts)! - diff --git a/docs/explanation/security/index.md b/docs/explanation/security/index.md index 813cfcb0f9..f304cef7da 100644 --- a/docs/explanation/security/index.md +++ b/docs/explanation/security/index.md @@ -22,7 +22,7 @@ Charmed PostgreSQL can be deployed on top of several clouds and virtualisation l ### Juju -Juju is the component responsible for orchestrating the entire lifecycle, from deployment to Day 2 operations. For more information on Juju security hardening, see the [Juju security page](https://canonical-juju.readthedocs-hosted.com/en/latest/user/explanation/juju-security/) and the [How to harden your deployment](https://documentation.ubuntu.com/juju/latest/howto/manage-your-deployment/#harden-your-deployment) guide. +Juju is the component responsible for orchestrating the entire lifecycle, from deployment to Day 2 operations. For more information on Juju security hardening, see the [Juju security page](https://canonical-juju.readthedocs-hosted.com/en/latest/user/explanation/juju-security/) and the [How to harden your deployment](https://documentation.ubuntu.com/juju/latest/howto/manage-your-juju-deployment/harden-your-juju-deployment/#harden-your-deployment) guide. #### Cloud credentials diff --git a/docs/how-to/deploy/juju-storage.md b/docs/how-to/deploy/juju-storage.md index 3573210fd4..c9d5294b6f 100644 --- a/docs/how-to/deploy/juju-storage.md +++ b/docs/how-to/deploy/juju-storage.md @@ -4,7 +4,7 @@ Charmed PostgreSQL uses the [Juju storage](https://documentation.ubuntu.com/juju Charmed PostgreSQL 14 supports a single storage: `pgdata`. -The [legacy PostgreSQL charm](/explanation/legacy-charm) in track [`latest/`](https://charmhub.io/postgresql?channel=latest/stable)" does **not** support the Juju storage abstraction. +The [legacy PostgreSQL charm](/explanation/charm-versions/legacy-charm) in track [`latest/`](https://charmhub.io/postgresql?channel=latest/stable)" does **not** support the Juju storage abstraction. ## Check storage details diff --git a/docs/how-to/deploy/tls-vip-access.md b/docs/how-to/deploy/tls-vip-access.md index f69586507c..3427460392 100644 --- a/docs/how-to/deploy/tls-vip-access.md +++ b/docs/how-to/deploy/tls-vip-access.md @@ -32,7 +32,7 @@ This setup deploys the following components: * The [`postgresql`](https://charmhub.io/postgresql) charm (3 units, as a single cluster). * The [`self-signed-certificates`](https://charmhub.io/self-signed-certificates) charm as the TLS provider. * Note that this is not suitable for production deployments. See the guide: [Security with X.509 certificates](https://charmhub.io/topics/security-with-x-509-certificates). -* The [`data-integrator`](https://charmhub.io/data-integrator) charm as a [principal](https://documentation.ubuntu.com/juju/3.6/reference/charm/#principal) charm for the [subordinated](https://documentation.ubuntu.com/juju/3.6/reference/charm/#subordinate) charms below (3 units for high availability): +* The [`data-integrator`](https://charmhub.io/data-integrator) charm as a [principal](https://documentation.ubuntu.com/juju/3.6/reference/charm/#principal-charm) charm for the [subordinated](https://documentation.ubuntu.com/juju/3.6/reference/charm/#subordinate-charm) charms below (3 units for high availability): * The latest [`pgbouncer`](https://charmhub.io/pgbouncer?channel=1/stable) charm as a load-balancer and connection pooler (3 units). * The [`hacluster`](https://charmhub.io/hacluster) charm for VIP handling (3 units are the minimum for HA). * (optional) The COS [`grafana-agent`](https://charmhub.io/grafana-agent) charm for Monitoring purposes. diff --git a/docs/how-to/development/integrate-with-your-charm.md b/docs/how-to/development/integrate-with-your-charm.md index 997480707d..fbfb9e4713 100644 --- a/docs/how-to/development/integrate-with-your-charm.md +++ b/docs/how-to/development/integrate-with-your-charm.md @@ -1,3 +1,4 @@ +(integrate-with-your-charm)= # How to integrate PostgreSQL with your charm Charmed PostgreSQL can be integrated with any charmed application that supports its interfaces. This page provides some guidance and resources for charm developers to develop, integrate, and troubleshoot their charm so that it may connect with PostgreSQL. @@ -8,7 +9,7 @@ First, we recommend that you check [the supported interfaces](/explanation/inter Most existing charms currently use [ops-lib-pgsql](https://github.com/canonical/ops-lib-pgsql) interface (legacy). For new charms, **Canonical recommends using [data-platform-libs](https://github.com/canonical/data-platform-libs).** -Legacy charm details are described [here](/explanation/legacy-charm). +Legacy charm details are described [here](/explanation/charm-versions/legacy-charm). ## Integrate your charm with PostgreSQL diff --git a/docs/how-to/development/migrate-data-via-backup-restore.md b/docs/how-to/development/migrate-data-via-backup-restore.md index a72ee046d6..fc64d4356d 100644 --- a/docs/how-to/development/migrate-data-via-backup-restore.md +++ b/docs/how-to/development/migrate-data-via-backup-restore.md @@ -1,6 +1,6 @@ # Migrate database data using ‘backup/restore’ -This is a guide for migrating data from modern charms. To migrate [legacy charms](/explanation/legacy-charm) data, refer to the guide [Migrate data via pg_dump](/how-to/development/migrate-data-via-pg-dump). +This is a guide for migrating data from modern charms. To migrate [legacy charms](/explanation/charm-versions/legacy-charm) data, refer to the guide [Migrate data via pg_dump](/how-to/development/migrate-data-via-pg-dump). This Charmed PostgreSQL operator is able to restore its own [backups](/how-to/back-up-and-restore/restore-a-backup) stored on [S3-compatible storage](/how-to/back-up-and-restore/configure-s3-aws). The same restore approach is applicable to restore [foreign backups](/how-to/back-up-and-restore/migrate-a-cluster) made by different Charmed PostgreSQL installation or even another PostgreSQL charm. The backup have to be created manually using [pgBackRest](https://pgbackrest.org/)! @@ -12,7 +12,7 @@ Always test a migration in a test environment before performing it in production ## Prerequisites -* **Check [your application compatibility](/explanation/legacy-charm)** with Charmed PostgreSQL VM before migrating production data from legacy charm +* **Check [your application compatibility](/explanation/charm-versions/index)** with Charmed PostgreSQL VM before migrating production data from legacy charm * Make sure **PostgreSQL versions are identical** before the migration ## Migrate database data diff --git a/docs/how-to/development/migrate-data-via-pg-dump.md b/docs/how-to/development/migrate-data-via-pg-dump.md index 46b2195adc..b0c93b7b4c 100644 --- a/docs/how-to/development/migrate-data-via-pg-dump.md +++ b/docs/how-to/development/migrate-data-via-pg-dump.md @@ -16,7 +16,7 @@ This guide can be used to copy data between different installations of the same ## Summary -The legacy VM charm archived in the `latest/stable` channel, read more [here](/explanation/legacy-charm). +The legacy VM charm archived in the `latest/stable` channel, read more [here](/explanation/charm-versions/legacy-charm). A minor difference in commands might be necessary for different revisions and/or Juju versions, but the general logic remains: * Deploy the modern charm nearby @@ -33,7 +33,7 @@ Always test migration in a safe environment before performing it in production! ## Prerequisites -- **[Your application is compatible](/explanation/legacy-charm) with Charmed PostgreSQL VM** +- **[Your application is compatible](/explanation/charm-versions/index) with Charmed PostgreSQL VM** - A client machine with access to the deployed legacy charm - `juju v.2.9` or later (check [Juju 3.0 Release Notes](https://documentation.ubuntu.com/juju/3.6/reference/juju/juju-roadmap-and-releases/#juju-3-0-0-22-oct-2022) for more information about key differences) - Enough storage in the cluster to support backup/restore of the databases. diff --git a/docs/how-to/integrate-with-another-application.md b/docs/how-to/integrate-with-another-application.md index d14fef771a..6594714f1e 100644 --- a/docs/how-to/integrate-with-another-application.md +++ b/docs/how-to/integrate-with-another-application.md @@ -36,7 +36,7 @@ juju remove-relation postgresql ### Legacy `pgsql` interface ```{caution} -Note that this interface is **deprecated**. See [](/explanation/legacy-charm). +Note that this interface is **deprecated**. See [](/explanation/charm-versions/legacy-charm). ``` To integrate via the legacy interface, run diff --git a/docs/index.md b/docs/index.md index 317d2dc791..12324a925f 100644 --- a/docs/index.md +++ b/docs/index.md @@ -13,7 +13,7 @@ This is a **IAAS/VM** operator. To deploy on Kubernetes, see [Charmed PostgreSQL | | | |--|--| | [**Get started**](/tutorial/index) - [Deploy on a cloud](/how-to/deploy/index) \| [Scale](/how-to/scale-replicas) \| [Manage passwords](/how-to/manage-passwords) \| [Enable encryption](/how-to/enable-tls) \| [Back up](/how-to/back-up-and-restore/index) \| [Monitoring](/how-to/monitoring-cos/index)
| [**How-to guides**](/how-to/index) for key tasks, use-cases, and problems. These guides assume basic familiarity with Juju and PostgreSQL.
| -| [**Reference**](/reference/index) - Technical information for quick lookup, such as [requirements](/reference/system-requirements), [plugins](/reference/plugins-extensions), and [statuses](/reference/statuses). | [**Explanation**](/explanation/interfaces-and-endpoints) - Discussion and clarification of key topics such as [architecture](/explanation/architecture), [users](/explanation/users), and [legacy charms](/explanation/legacy-charm)| +| [**Reference**](/reference/index) - Technical information for quick lookup, such as [requirements](/reference/system-requirements), [plugins](/reference/plugins-extensions), and [statuses](/reference/statuses). | [**Explanation**](/explanation/interfaces-and-endpoints) - Discussion and clarification of key topics such as [architecture](/explanation/architecture), [users](/explanation/users), and [charm versions](/explanation/charm-versions/index)| ## Project and community diff --git a/docs/redirects.txt b/docs/redirects.txt index 72d254089f..bb8ef1e695 100644 --- a/docs/redirects.txt +++ b/docs/redirects.txt @@ -76,7 +76,7 @@ h-migrate-backup-restore/ how-to/development/migrate-data-via-backup-restore # Reference r-releases/ reference/releases -r-versions/ reference/versions +r-versions/ explanation/charm-versions r-system-requirements/ reference/system-requirements r-software-testing/ reference/software-testing r-performance/ reference/performance-and-resources @@ -94,7 +94,7 @@ r-contacts/ reference/contacts e-architecture/ explanation/architecture e-interfaces-endpoints/ explanation/interfaces-and-endpoints e-juju-details/ explanation/juju -e-legacy-charm/ explanation/legacy-charm +e-legacy-charm/ explanation/charm-versions/legacy-charm e-units/ explanation/units e-users/ explanation/users e-roles/ explanation/roles diff --git a/docs/reference/index.md b/docs/reference/index.md index 8bddca053b..644b04f3f0 100644 --- a/docs/reference/index.md +++ b/docs/reference/index.md @@ -18,7 +18,6 @@ The following guides contain technical specifications, APIs, release notes, and :glob: Releases -Versions System requirements Software testing Performance and resources diff --git a/docs/reference/releases.md b/docs/reference/releases.md index d16fb323a7..e453397095 100644 --- a/docs/reference/releases.md +++ b/docs/reference/releases.md @@ -1,6 +1,6 @@ # Releases -This page provides high-level overviews of the dependencies and features that are supported by each revision in every stable release. +This page provides high-level overviews of the dependencies and features that are supported by each revision in every stable release of Charmed PostgreSQL 14. To learn more about the different release tracks and channels, see the [Juju documentation about channels](https://documentation.ubuntu.com/juju/3.6/reference/charm/#risk). @@ -8,11 +8,7 @@ To see all releases and commits, check the [Charmed PostgreSQL Releases page on ## Dependencies and supported features -For a given release, this table shows: -* The PostgreSQL 14 version packaged inside. -* The minimum Juju 3 version required to reliably operate **all** features of the release - > This charm still supports older versions of Juju down to 2.9. See the [Juju section of the system requirements](/reference/system-requirements) for more details. -* Support for specific features +The table below shows information for all minor releases of Charmed PostgreSQL 14. | Release | PostgreSQL version | Juju 3 version | [TLS encryption](/how-to/enable-tls)* | [COS monitoring](/how-to/monitoring-cos/enable-monitoring) | [Minor version upgrades](/how-to/upgrade/perform-a-minor-upgrade) | [Cross-regional async replication](/how-to/cross-regional-async-replication/index) | [Point-in-time recovery](/how-to/back-up-and-restore/restore-a-backup) | |:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:| @@ -26,6 +22,11 @@ For a given release, this table shows: \* **TLS encryption**: Support for **`v2` or higher** of the [`tls-certificates` interface](https://charmhub.io/tls-certificates-interface/libraries/tls_certificates). This means that you can integrate with [modern TLS charms](https://charmhub.io/topics/security-with-x-509-certificates). +```{seealso} +* [Information about all major versions](/explanation/charm-versions/index) +* {doc}`Charmed PostgreSQL 16 releases ` +``` + ## Architecture and base Several [revisions](https://documentation.ubuntu.com/juju/3.6/reference/charm/#charm-revision) are released simultaneously for different [bases/series](https://juju.is/docs/juju/base) using the same charm code. In other words, one release contains multiple revisions. diff --git a/docs/reference/statuses.md b/docs/reference/statuses.md index 0bf6c86db2..cabcfd7197 100644 --- a/docs/reference/statuses.md +++ b/docs/reference/statuses.md @@ -19,7 +19,7 @@ The charm follows [standard Juju applications statuses](https://documentation.ub | **blocked** | failed to start Patroni | TODO: error/retry? | | | **blocked** | Failed to create postgres user | The charm couldn't create the default `postgres` database user due to connection problems | Connect to the database using the `operator` user and the password from the `get-password` action, then run `CREATE ROLE postgres WITH LOGIN SUPERUSER;` | | **blocked** | Failed to restore backup | The database couldn't start after the restore | The charm needs fix in the code to recover from this status and enable a new restore to be requested | -| **blocked** | Please choose one endpoint to use. No need to relate all of them simultaneously! | [The modern / legacy interfaces](/explanation/legacy-charm) should not be used simultaneously. | Remove modern or legacy relation. Choose one to use at a time. | +| **blocked** | Please choose one endpoint to use. No need to relate all of them simultaneously! | [The modern and legacy interfaces](/explanation/charm-versions/index) should not be used simultaneously. | Remove modern or legacy relation. Choose one to use at a time. | | **error** | any | An unhanded internal error happened | Read the message hint. Execute `juju resolve ` after addressing the root of the error state | | **terminated** | any | The unit is gone and will be cleaned by Juju soon | No actions possible | | **unknown** | any | Juju doesn't know the charm app/unit status. Possible reason: K8s charm termination in progress. | Manual investigation required if status is permanent | diff --git a/docs/reference/versions.md b/docs/reference/versions.md deleted file mode 100644 index 4789413ec3..0000000000 --- a/docs/reference/versions.md +++ /dev/null @@ -1,125 +0,0 @@ -# PostgreSQL major versions - -Charmed PostgreSQL is shipped in following [tracks](https://documentation.ubuntu.com/juju/3.6/reference/charm/#track): - -* [PostgreSQL 16] (channel `16/candidate`) -* [PostgreSQL 14] (channel `14/stable`) -* [Legacy PostgreSQL charm] (channel `latest/stable`) -> **deprecated** - -This includes two major PostgreSQL versions, `14` and `16`, matching [Ubuntu versioning](https://packages.ubuntu.com/postgresql) for PostgreSQL. - -## PostgreSQL 16 - -PostgreSQL 16 is shipped in track `16` and is available for testing in the channel `16/candidate`. - ->Released alongside [PgBouncer] and [Data Integrator](https://charmhub.io/data-integrator) for Ubuntu 24.04 - -**Base:** Noble (Ubuntu 24.04) - -**Supported architectures:** `arm64` and `amd64`. - -### Supported features - -* Juju spaces support -* [Multiple Juju storage support] -* [LDAP integration] (also supported by PostgreSQL `14`) -* [SoS report integration] (also supported by PostgreSQL `14`) -* [Recovery improvements] (also supported by PostgreSQL `14`) - * All replicas are now [synchronous units] - * Switchover the primary unit via `promote-to-primary scope=unit` - * Raft re-init helper: `promote-to-primary scope=unit force=yes` -* [Juju user secrets](https://documentation.ubuntu.com/juju/latest/reference/secret/index.html#user-secret) for charm [internal passwords](/how-to/manage-passwords) -* [Timescale Community Edition] -* [Extended COS integration] - * [Profiling via Parca] - * [Tracing via Tempo] -* Improved [security hardening] -* (WIP) [Improved built-in roles](/explanation/roles) -* New "juju refresh" library (Refresh v3) - - - -Read more about Charmed PostgreSQL 16 features in the [release notes]. - -### Deprecated / removed - -* Legacy interface `psql` (endpoints `db` and `db-admin`). - * See more about supported interfaces in [Interfaces and endpoints]. -* Support for Juju < `v3.6` - * Charmed PostgreSQL 16 requires Juju `3.6+ LTS` due to [Juju secrets](https://documentation.ubuntu.com/juju/3.6/reference/secret/index.html) support. -* Juju actions `get-password` and `set-password`. - * For security reasons, these actions are replaced by [Juju secrets](https://documentation.ubuntu.com/juju/3.6/reference/secret/index.html). -* [Timescale Apache 2 edition](https://docs.timescale.com/about/latest/timescaledb-editions/) has been replaced by [Timescale Community edition](https://docs.timescale.com/about/latest/timescaledb-editions/). -* The charm action `set-tls-private-key ` has been removed (will be re-introduced as Juju User Secrets) -* The charm actions `pre-upgrade-check` and `resume-upgrade ` have been removed (replaced with `pre-refresh-check` and `resume-refresh` accordingly to be consistent with `juju refresh`) - - -## PostgreSQL 14 - -PostgreSQL 14 is shipped in track `14` and available for production in the channel `14/stable`. - -**Base:** Jammy (Ubuntu 22.04) - -**Supported architectures:** `arm64` and `amd64`. - -### Supported features - -* [Deployment] on multiple cloud services -* [Backup and restore] - * Including point-in-time recovery (PITR) -* [COS integration] -* [TLS integration] -* [LDAP integration] -* [`arm64` architecture] - -Read more about Charmed PostgreSQL 14 features in the [release notes]. - -### Deprecated - -* The track `14` is in bug-fixing/support mode. New Charmed PostgreSQL `16` features will NOT be back-ported to track `14`. -* Charmed PostgreSQL 14 ships [Timescale Apache 2 edition](https://docs.timescale.com/about/latest/timescaledb-editions/) only. - -## Legacy PostgreSQL charm - -The legacy charm in the track `latest` has been deprecated and is **not supported.** It is still available here for the historical and comparative reasons only. - -Please use the supported tracks of the modern charm: `14/` and `16/`. - -Learn more in the [legacy charm explanation page]. - - - -[PostgreSQL 16]: https://charmhub.io/postgresql?channel=16/beta -[PostgreSQL 14]: https://charmhub.io/postgresql?channel=14/stable -[Legacy PostgreSQL charm]: https://charmhub.io/postgresql?channel=latest/stable - -[PgBouncer]: https://charmhub.io/pgbouncer - -[LDAP integration]: /how-to/enable-ldap -[SoS report integration]: /reference/troubleshooting/sos-report -[Recovery improvements]: /how-to/switchover-failover -[synchronous units]: https://charmhub.io/postgresql/configurations?channel=14/edge#synchronous_node_count -[internal charm passwords]: /explanation/users -[rotation]: /tutorial/5-manage-passwords -[Timescale Community Edition]: /how-to/enable-plugins-extensions/enable-timescaledb -[Extended COS integration]: /how-to/monitoring-cos/enable-monitoring -[Profiling via Parca]: /how-to/monitoring-cos/enable-profiling -[Tracing via Tempo]: /how-to/monitoring-cos/enable-tracing -[security hardening]: /explanation/security/index -[Multiple Juju storage support]: /how-to/deploy/juju-storage - -[release notes]: /reference/releases - -[Interfaces and endpoints]: /explanation/interfaces-and-endpoints - -[Deployment]: /how-to/deploy/index -[Backup and restore]: /how-to/back-up-and-restore/create-a-backup -[COS integration]: /how-to/monitoring-cos/enable-monitoring -[TLS integration]: /how-to/enable-tls -[`arm64` architecture]: /reference/system-requirements - -[legacy charm explanation page]: /explanation/legacy-charm - From 415854e68066efdabff5b18b9a6feec6ee2608ec Mon Sep 17 00:00:00 2001 From: Dragomir Penev <6687393+dragomirp@users.noreply.github.com> Date: Wed, 24 Sep 2025 15:29:02 +0300 Subject: [PATCH 101/112] [MISC] Fix smoke test (#1184) * Volume tests * Manually deploying --- tests/integration/ha_tests/test_smoke.py | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/tests/integration/ha_tests/test_smoke.py b/tests/integration/ha_tests/test_smoke.py index 3e718522ee..59cefdfece 100644 --- a/tests/integration/ha_tests/test_smoke.py +++ b/tests/integration/ha_tests/test_smoke.py @@ -6,7 +6,6 @@ import logging import pytest -from juju import tag from pytest_operator.plugin import OpsTest from tenacity import Retrying, stop_after_delay, wait_fixed @@ -143,14 +142,9 @@ async def test_app_resources_conflicts_v3(ops_test: OpsTest, charm: str): garbage_storage = await get_any_deatached_storage(ops_test) logger.info("deploying duplicate application with attached storage") - await ops_test.model.deploy( - charm, - application_name=DUP_APPLICATION_NAME, - num_units=1, - base=CHARM_BASE, - attach_storage=[tag.storage(garbage_storage)], - config={"profile": "testing"}, - ) + deploy_cmd = f"deploy ./{charm} {DUP_APPLICATION_NAME} --model={ops_test.model.info.name} --attach-storage={garbage_storage} --config profile=testing".split() + return_code, _, _ = await ops_test.juju(*deploy_cmd) + assert return_code == 0, "Failed to add unit with storage" # Reducing the update status frequency to speed up the triggering of deferred events. await ops_test.model.set_config({"update-status-hook-interval": "10s"}) From d72e37f80ce9b56013efe1392ab310ea8bfade02 Mon Sep 17 00:00:00 2001 From: Alex Lutay <1928266+taurus-forever@users.noreply.github.com> Date: Wed, 24 Sep 2025 14:47:06 +0200 Subject: [PATCH 102/112] [DPE-8337] Disable Patroni config to prevent possible data loss (#1173) * DPE-8337 Disable Patroni config to prevent possible dataloose Disable Patroni config options explecitely: remove_data_directory_on_rewind_failure and remove_data_directory_on_diverged_timelines. P.S. they are disabled by default in Patroni. * DPE-8337 Fix integration tests * Force set the rewind config --------- Co-authored-by: Dragomir Penev --- src/cluster.py | 8 +++++++- templates/patroni.yml.j2 | 4 ++-- tests/integration/test_charm.py | 4 ++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/cluster.py b/src/cluster.py index 4e6055a2b1..1c582f0e43 100644 --- a/src/cluster.py +++ b/src/cluster.py @@ -1029,7 +1029,13 @@ def bulk_update_parameters_controller_by_patroni(self, parameters: dict[str, Any requests.patch( f"{self._patroni_url}/config", verify=self.verify, - json={"postgresql": {"parameters": parameters}}, + json={ + "postgresql": { + "remove_data_directory_on_rewind_failure": False, + "remove_data_directory_on_diverged_timelines": False, + "parameters": parameters, + } + }, auth=self._patroni_auth, timeout=PATRONI_TIMEOUT, ) diff --git a/templates/patroni.yml.j2 b/templates/patroni.yml.j2 index 75a37a5d8a..b02995d4f1 100644 --- a/templates/patroni.yml.j2 +++ b/templates/patroni.yml.j2 @@ -62,8 +62,8 @@ bootstrap: synchronous_node_count: {{ synchronous_node_count }} postgresql: use_pg_rewind: true - remove_data_directory_on_rewind_failure: true - remove_data_directory_on_diverged_timelines: true + remove_data_directory_on_rewind_failure: false + remove_data_directory_on_diverged_timelines: false parameters: synchronous_standby_names: "*" {%- if enable_pgbackrest_archiving %} diff --git a/tests/integration/test_charm.py b/tests/integration/test_charm.py index 743bbdb242..217116f9dc 100644 --- a/tests/integration/test_charm.py +++ b/tests/integration/test_charm.py @@ -154,8 +154,8 @@ async def test_settings_are_correct(ops_test: OpsTest, unit_id: int): # Validate each configuration related to Patroni assert settings["postgresql"]["use_pg_rewind"] is True - assert settings["postgresql"]["remove_data_directory_on_rewind_failure"] is True - assert settings["postgresql"]["remove_data_directory_on_diverged_timelines"] is True + assert settings["postgresql"]["remove_data_directory_on_rewind_failure"] is False + assert settings["postgresql"]["remove_data_directory_on_diverged_timelines"] is False assert settings["loop_wait"] == 10 assert settings["retry_timeout"] == 10 assert settings["maximum_lag_on_failover"] == 1048576 From 07f43a18b8d884ca5af3bc0b687f8ebcbf6e03d4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 25 Sep 2025 21:49:24 +0300 Subject: [PATCH 103/112] Lock file maintenance Python dependencies (#1176) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- poetry.lock | 397 ++++++++++++++++++++++++++----------------------- pyproject.toml | 8 +- 2 files changed, 219 insertions(+), 186 deletions(-) diff --git a/poetry.lock b/poetry.lock index 09b2ca2fbb..aa0878acf7 100644 --- a/poetry.lock +++ b/poetry.lock @@ -233,18 +233,18 @@ typecheck = ["mypy"] [[package]] name = "boto3" -version = "1.40.31" +version = "1.40.36" description = "The AWS SDK for Python" optional = false python-versions = ">=3.9" groups = ["main", "integration"] files = [ - {file = "boto3-1.40.31-py3-none-any.whl", hash = "sha256:61d5f9975c54ff919a24ff9d472c6c09c8a443a083fe56d30c04fc22d22ac42b"}, - {file = "boto3-1.40.31.tar.gz", hash = "sha256:8c5f1270f09431694412f326cfb5ac9786d41ea3bc6ac54cbb7161d40afc660d"}, + {file = "boto3-1.40.36-py3-none-any.whl", hash = "sha256:d7c1fe033f491f560cd26022a9dcf28baf877ae854f33bc64fffd0df3b9c98be"}, + {file = "boto3-1.40.36.tar.gz", hash = "sha256:bfc1f3d5c4f5d12b8458406b8972f8794ac57e2da1ee441469e143bc0440a5c3"}, ] [package.dependencies] -botocore = ">=1.40.31,<1.41.0" +botocore = ">=1.40.36,<1.41.0" jmespath = ">=0.7.1,<2.0.0" s3transfer = ">=0.14.0,<0.15.0" @@ -253,14 +253,14 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.40.31" +version = "1.40.36" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">=3.9" groups = ["main", "integration"] files = [ - {file = "botocore-1.40.31-py3-none-any.whl", hash = "sha256:4033a00f8c6a4b5c3acb30af9283963123917227a437e5fc165189d07bd3cf8a"}, - {file = "botocore-1.40.31.tar.gz", hash = "sha256:9496b91bbe40ed01d341dc8f6ff0492d7f546e80f1a862b00ec5bc9045fa3324"}, + {file = "botocore-1.40.36-py3-none-any.whl", hash = "sha256:d6edf75875e4013cb7078875a1d6c289afb4cc6675d99d80700c692d8d8e0b72"}, + {file = "botocore-1.40.36.tar.gz", hash = "sha256:93386a8dc54173267ddfc6cd8636c9171e021f7c032aa1df3af7de816e3df616"}, ] [package.dependencies] @@ -534,100 +534,116 @@ typing-extensions = "*" [[package]] name = "coverage" -version = "7.10.6" +version = "7.10.7" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.9" groups = ["unit"] files = [ - {file = "coverage-7.10.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:70e7bfbd57126b5554aa482691145f798d7df77489a177a6bef80de78860a356"}, - {file = "coverage-7.10.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e41be6f0f19da64af13403e52f2dec38bbc2937af54df8ecef10850ff8d35301"}, - {file = "coverage-7.10.6-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:c61fc91ab80b23f5fddbee342d19662f3d3328173229caded831aa0bd7595460"}, - {file = "coverage-7.10.6-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:10356fdd33a7cc06e8051413140bbdc6f972137508a3572e3f59f805cd2832fd"}, - {file = "coverage-7.10.6-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:80b1695cf7c5ebe7b44bf2521221b9bb8cdf69b1f24231149a7e3eb1ae5fa2fb"}, - {file = "coverage-7.10.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:2e4c33e6378b9d52d3454bd08847a8651f4ed23ddbb4a0520227bd346382bbc6"}, - {file = "coverage-7.10.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:c8a3ec16e34ef980a46f60dc6ad86ec60f763c3f2fa0db6d261e6e754f72e945"}, - {file = "coverage-7.10.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7d79dabc0a56f5af990cc6da9ad1e40766e82773c075f09cc571e2076fef882e"}, - {file = "coverage-7.10.6-cp310-cp310-win32.whl", hash = "sha256:86b9b59f2b16e981906e9d6383eb6446d5b46c278460ae2c36487667717eccf1"}, - {file = "coverage-7.10.6-cp310-cp310-win_amd64.whl", hash = "sha256:e132b9152749bd33534e5bd8565c7576f135f157b4029b975e15ee184325f528"}, - {file = "coverage-7.10.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c706db3cabb7ceef779de68270150665e710b46d56372455cd741184f3868d8f"}, - {file = "coverage-7.10.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8e0c38dc289e0508ef68ec95834cb5d2e96fdbe792eaccaa1bccac3966bbadcc"}, - {file = "coverage-7.10.6-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:752a3005a1ded28f2f3a6e8787e24f28d6abe176ca64677bcd8d53d6fe2ec08a"}, - {file = "coverage-7.10.6-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:689920ecfd60f992cafca4f5477d55720466ad2c7fa29bb56ac8d44a1ac2b47a"}, - {file = "coverage-7.10.6-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ec98435796d2624d6905820a42f82149ee9fc4f2d45c2c5bc5a44481cc50db62"}, - {file = "coverage-7.10.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b37201ce4a458c7a758ecc4efa92fa8ed783c66e0fa3c42ae19fc454a0792153"}, - {file = "coverage-7.10.6-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:2904271c80898663c810a6b067920a61dd8d38341244a3605bd31ab55250dad5"}, - {file = "coverage-7.10.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5aea98383463d6e1fa4e95416d8de66f2d0cb588774ee20ae1b28df826bcb619"}, - {file = "coverage-7.10.6-cp311-cp311-win32.whl", hash = "sha256:e3fb1fa01d3598002777dd259c0c2e6d9d5e10e7222976fc8e03992f972a2cba"}, - {file = "coverage-7.10.6-cp311-cp311-win_amd64.whl", hash = "sha256:f35ed9d945bece26553d5b4c8630453169672bea0050a564456eb88bdffd927e"}, - {file = "coverage-7.10.6-cp311-cp311-win_arm64.whl", hash = "sha256:99e1a305c7765631d74b98bf7dbf54eeea931f975e80f115437d23848ee8c27c"}, - {file = "coverage-7.10.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5b2dd6059938063a2c9fee1af729d4f2af28fd1a545e9b7652861f0d752ebcea"}, - {file = "coverage-7.10.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:388d80e56191bf846c485c14ae2bc8898aa3124d9d35903fef7d907780477634"}, - {file = "coverage-7.10.6-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:90cb5b1a4670662719591aa92d0095bb41714970c0b065b02a2610172dbf0af6"}, - {file = "coverage-7.10.6-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:961834e2f2b863a0e14260a9a273aff07ff7818ab6e66d2addf5628590c628f9"}, - {file = "coverage-7.10.6-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf9a19f5012dab774628491659646335b1928cfc931bf8d97b0d5918dd58033c"}, - {file = "coverage-7.10.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:99c4283e2a0e147b9c9cc6bc9c96124de9419d6044837e9799763a0e29a7321a"}, - {file = "coverage-7.10.6-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:282b1b20f45df57cc508c1e033403f02283adfb67d4c9c35a90281d81e5c52c5"}, - {file = "coverage-7.10.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8cdbe264f11afd69841bd8c0d83ca10b5b32853263ee62e6ac6a0ab63895f972"}, - {file = "coverage-7.10.6-cp312-cp312-win32.whl", hash = "sha256:a517feaf3a0a3eca1ee985d8373135cfdedfbba3882a5eab4362bda7c7cf518d"}, - {file = "coverage-7.10.6-cp312-cp312-win_amd64.whl", hash = "sha256:856986eadf41f52b214176d894a7de05331117f6035a28ac0016c0f63d887629"}, - {file = "coverage-7.10.6-cp312-cp312-win_arm64.whl", hash = "sha256:acf36b8268785aad739443fa2780c16260ee3fa09d12b3a70f772ef100939d80"}, - {file = "coverage-7.10.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ffea0575345e9ee0144dfe5701aa17f3ba546f8c3bb48db62ae101afb740e7d6"}, - {file = "coverage-7.10.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:95d91d7317cde40a1c249d6b7382750b7e6d86fad9d8eaf4fa3f8f44cf171e80"}, - {file = "coverage-7.10.6-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3e23dd5408fe71a356b41baa82892772a4cefcf758f2ca3383d2aa39e1b7a003"}, - {file = "coverage-7.10.6-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0f3f56e4cb573755e96a16501a98bf211f100463d70275759e73f3cbc00d4f27"}, - {file = "coverage-7.10.6-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:db4a1d897bbbe7339946ffa2fe60c10cc81c43fab8b062d3fcb84188688174a4"}, - {file = "coverage-7.10.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d8fd7879082953c156d5b13c74aa6cca37f6a6f4747b39538504c3f9c63d043d"}, - {file = "coverage-7.10.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:28395ca3f71cd103b8c116333fa9db867f3a3e1ad6a084aa3725ae002b6583bc"}, - {file = "coverage-7.10.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:61c950fc33d29c91b9e18540e1aed7d9f6787cc870a3e4032493bbbe641d12fc"}, - {file = "coverage-7.10.6-cp313-cp313-win32.whl", hash = "sha256:160c00a5e6b6bdf4e5984b0ef21fc860bc94416c41b7df4d63f536d17c38902e"}, - {file = "coverage-7.10.6-cp313-cp313-win_amd64.whl", hash = "sha256:628055297f3e2aa181464c3808402887643405573eb3d9de060d81531fa79d32"}, - {file = "coverage-7.10.6-cp313-cp313-win_arm64.whl", hash = "sha256:df4ec1f8540b0bcbe26ca7dd0f541847cc8a108b35596f9f91f59f0c060bfdd2"}, - {file = "coverage-7.10.6-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:c9a8b7a34a4de3ed987f636f71881cd3b8339f61118b1aa311fbda12741bff0b"}, - {file = "coverage-7.10.6-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:8dd5af36092430c2b075cee966719898f2ae87b636cefb85a653f1d0ba5d5393"}, - {file = "coverage-7.10.6-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:b0353b0f0850d49ada66fdd7d0c7cdb0f86b900bb9e367024fd14a60cecc1e27"}, - {file = "coverage-7.10.6-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:d6b9ae13d5d3e8aeca9ca94198aa7b3ebbc5acfada557d724f2a1f03d2c0b0df"}, - {file = "coverage-7.10.6-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:675824a363cc05781b1527b39dc2587b8984965834a748177ee3c37b64ffeafb"}, - {file = "coverage-7.10.6-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:692d70ea725f471a547c305f0d0fc6a73480c62fb0da726370c088ab21aed282"}, - {file = "coverage-7.10.6-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:851430a9a361c7a8484a36126d1d0ff8d529d97385eacc8dfdc9bfc8c2d2cbe4"}, - {file = "coverage-7.10.6-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:d9369a23186d189b2fc95cc08b8160ba242057e887d766864f7adf3c46b2df21"}, - {file = "coverage-7.10.6-cp313-cp313t-win32.whl", hash = "sha256:92be86fcb125e9bda0da7806afd29a3fd33fdf58fba5d60318399adf40bf37d0"}, - {file = "coverage-7.10.6-cp313-cp313t-win_amd64.whl", hash = "sha256:6b3039e2ca459a70c79523d39347d83b73f2f06af5624905eba7ec34d64d80b5"}, - {file = "coverage-7.10.6-cp313-cp313t-win_arm64.whl", hash = "sha256:3fb99d0786fe17b228eab663d16bee2288e8724d26a199c29325aac4b0319b9b"}, - {file = "coverage-7.10.6-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:6008a021907be8c4c02f37cdc3ffb258493bdebfeaf9a839f9e71dfdc47b018e"}, - {file = "coverage-7.10.6-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:5e75e37f23eb144e78940b40395b42f2321951206a4f50e23cfd6e8a198d3ceb"}, - {file = "coverage-7.10.6-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:0f7cb359a448e043c576f0da00aa8bfd796a01b06aa610ca453d4dde09cc1034"}, - {file = "coverage-7.10.6-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c68018e4fc4e14b5668f1353b41ccf4bc83ba355f0e1b3836861c6f042d89ac1"}, - {file = "coverage-7.10.6-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cd4b2b0707fc55afa160cd5fc33b27ccbf75ca11d81f4ec9863d5793fc6df56a"}, - {file = "coverage-7.10.6-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:4cec13817a651f8804a86e4f79d815b3b28472c910e099e4d5a0e8a3b6a1d4cb"}, - {file = "coverage-7.10.6-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:f2a6a8e06bbda06f78739f40bfb56c45d14eb8249d0f0ea6d4b3d48e1f7c695d"}, - {file = "coverage-7.10.6-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:081b98395ced0d9bcf60ada7661a0b75f36b78b9d7e39ea0790bb4ed8da14747"}, - {file = "coverage-7.10.6-cp314-cp314-win32.whl", hash = "sha256:6937347c5d7d069ee776b2bf4e1212f912a9f1f141a429c475e6089462fcecc5"}, - {file = "coverage-7.10.6-cp314-cp314-win_amd64.whl", hash = "sha256:adec1d980fa07e60b6ef865f9e5410ba760e4e1d26f60f7e5772c73b9a5b0713"}, - {file = "coverage-7.10.6-cp314-cp314-win_arm64.whl", hash = "sha256:a80f7aef9535442bdcf562e5a0d5a5538ce8abe6bb209cfbf170c462ac2c2a32"}, - {file = "coverage-7.10.6-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:0de434f4fbbe5af4fa7989521c655c8c779afb61c53ab561b64dcee6149e4c65"}, - {file = "coverage-7.10.6-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6e31b8155150c57e5ac43ccd289d079eb3f825187d7c66e755a055d2c85794c6"}, - {file = "coverage-7.10.6-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:98cede73eb83c31e2118ae8d379c12e3e42736903a8afcca92a7218e1f2903b0"}, - {file = "coverage-7.10.6-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f863c08f4ff6b64fa8045b1e3da480f5374779ef187f07b82e0538c68cb4ff8e"}, - {file = "coverage-7.10.6-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2b38261034fda87be356f2c3f42221fdb4171c3ce7658066ae449241485390d5"}, - {file = "coverage-7.10.6-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:0e93b1476b79eae849dc3872faeb0bf7948fd9ea34869590bc16a2a00b9c82a7"}, - {file = "coverage-7.10.6-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:ff8a991f70f4c0cf53088abf1e3886edcc87d53004c7bb94e78650b4d3dac3b5"}, - {file = "coverage-7.10.6-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ac765b026c9f33044419cbba1da913cfb82cca1b60598ac1c7a5ed6aac4621a0"}, - {file = "coverage-7.10.6-cp314-cp314t-win32.whl", hash = "sha256:441c357d55f4936875636ef2cfb3bee36e466dcf50df9afbd398ce79dba1ebb7"}, - {file = "coverage-7.10.6-cp314-cp314t-win_amd64.whl", hash = "sha256:073711de3181b2e204e4870ac83a7c4853115b42e9cd4d145f2231e12d670930"}, - {file = "coverage-7.10.6-cp314-cp314t-win_arm64.whl", hash = "sha256:137921f2bac5559334ba66122b753db6dc5d1cf01eb7b64eb412bb0d064ef35b"}, - {file = "coverage-7.10.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:90558c35af64971d65fbd935c32010f9a2f52776103a259f1dee865fe8259352"}, - {file = "coverage-7.10.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8953746d371e5695405806c46d705a3cd170b9cc2b9f93953ad838f6c1e58612"}, - {file = "coverage-7.10.6-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:c83f6afb480eae0313114297d29d7c295670a41c11b274e6bca0c64540c1ce7b"}, - {file = "coverage-7.10.6-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7eb68d356ba0cc158ca535ce1381dbf2037fa8cb5b1ae5ddfc302e7317d04144"}, - {file = "coverage-7.10.6-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5b15a87265e96307482746d86995f4bff282f14b027db75469c446da6127433b"}, - {file = "coverage-7.10.6-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:fc53ba868875bfbb66ee447d64d6413c2db91fddcfca57025a0e7ab5b07d5862"}, - {file = "coverage-7.10.6-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:efeda443000aa23f276f4df973cb82beca682fd800bb119d19e80504ffe53ec2"}, - {file = "coverage-7.10.6-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:9702b59d582ff1e184945d8b501ffdd08d2cee38d93a2206aa5f1365ce0b8d78"}, - {file = "coverage-7.10.6-cp39-cp39-win32.whl", hash = "sha256:2195f8e16ba1a44651ca684db2ea2b2d4b5345da12f07d9c22a395202a05b23c"}, - {file = "coverage-7.10.6-cp39-cp39-win_amd64.whl", hash = "sha256:f32ff80e7ef6a5b5b606ea69a36e97b219cd9dc799bcf2963018a4d8f788cfbf"}, - {file = "coverage-7.10.6-py3-none-any.whl", hash = "sha256:92c4ecf6bf11b2e85fd4d8204814dc26e6a19f0c9d938c207c5cb0eadfcabbe3"}, - {file = "coverage-7.10.6.tar.gz", hash = "sha256:f644a3ae5933a552a29dbb9aa2f90c677a875f80ebea028e5a52a4f429044b90"}, + {file = "coverage-7.10.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:fc04cc7a3db33664e0c2d10eb8990ff6b3536f6842c9590ae8da4c614b9ed05a"}, + {file = "coverage-7.10.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e201e015644e207139f7e2351980feb7040e6f4b2c2978892f3e3789d1c125e5"}, + {file = "coverage-7.10.7-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:240af60539987ced2c399809bd34f7c78e8abe0736af91c3d7d0e795df633d17"}, + {file = "coverage-7.10.7-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8421e088bc051361b01c4b3a50fd39a4b9133079a2229978d9d30511fd05231b"}, + {file = "coverage-7.10.7-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6be8ed3039ae7f7ac5ce058c308484787c86e8437e72b30bf5e88b8ea10f3c87"}, + {file = "coverage-7.10.7-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e28299d9f2e889e6d51b1f043f58d5f997c373cc12e6403b90df95b8b047c13e"}, + {file = "coverage-7.10.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c4e16bd7761c5e454f4efd36f345286d6f7c5fa111623c355691e2755cae3b9e"}, + {file = "coverage-7.10.7-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:b1c81d0e5e160651879755c9c675b974276f135558cf4ba79fee7b8413a515df"}, + {file = "coverage-7.10.7-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:606cc265adc9aaedcc84f1f064f0e8736bc45814f15a357e30fca7ecc01504e0"}, + {file = "coverage-7.10.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:10b24412692df990dbc34f8fb1b6b13d236ace9dfdd68df5b28c2e39cafbba13"}, + {file = "coverage-7.10.7-cp310-cp310-win32.whl", hash = "sha256:b51dcd060f18c19290d9b8a9dd1e0181538df2ce0717f562fff6cf74d9fc0b5b"}, + {file = "coverage-7.10.7-cp310-cp310-win_amd64.whl", hash = "sha256:3a622ac801b17198020f09af3eaf45666b344a0d69fc2a6ffe2ea83aeef1d807"}, + {file = "coverage-7.10.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a609f9c93113be646f44c2a0256d6ea375ad047005d7f57a5c15f614dc1b2f59"}, + {file = "coverage-7.10.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:65646bb0359386e07639c367a22cf9b5bf6304e8630b565d0626e2bdf329227a"}, + {file = "coverage-7.10.7-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5f33166f0dfcce728191f520bd2692914ec70fac2713f6bf3ce59c3deacb4699"}, + {file = "coverage-7.10.7-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:35f5e3f9e455bb17831876048355dca0f758b6df22f49258cb5a91da23ef437d"}, + {file = "coverage-7.10.7-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4da86b6d62a496e908ac2898243920c7992499c1712ff7c2b6d837cc69d9467e"}, + {file = "coverage-7.10.7-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6b8b09c1fad947c84bbbc95eca841350fad9cbfa5a2d7ca88ac9f8d836c92e23"}, + {file = "coverage-7.10.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4376538f36b533b46f8971d3a3e63464f2c7905c9800db97361c43a2b14792ab"}, + {file = "coverage-7.10.7-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:121da30abb574f6ce6ae09840dae322bef734480ceafe410117627aa54f76d82"}, + {file = "coverage-7.10.7-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:88127d40df529336a9836870436fc2751c339fbaed3a836d42c93f3e4bd1d0a2"}, + {file = "coverage-7.10.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ba58bbcd1b72f136080c0bccc2400d66cc6115f3f906c499013d065ac33a4b61"}, + {file = "coverage-7.10.7-cp311-cp311-win32.whl", hash = "sha256:972b9e3a4094b053a4e46832b4bc829fc8a8d347160eb39d03f1690316a99c14"}, + {file = "coverage-7.10.7-cp311-cp311-win_amd64.whl", hash = "sha256:a7b55a944a7f43892e28ad4bc0561dfd5f0d73e605d1aa5c3c976b52aea121d2"}, + {file = "coverage-7.10.7-cp311-cp311-win_arm64.whl", hash = "sha256:736f227fb490f03c6488f9b6d45855f8e0fd749c007f9303ad30efab0e73c05a"}, + {file = "coverage-7.10.7-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7bb3b9ddb87ef7725056572368040c32775036472d5a033679d1fa6c8dc08417"}, + {file = "coverage-7.10.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:18afb24843cbc175687225cab1138c95d262337f5473512010e46831aa0c2973"}, + {file = "coverage-7.10.7-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:399a0b6347bcd3822be369392932884b8216d0944049ae22925631a9b3d4ba4c"}, + {file = "coverage-7.10.7-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:314f2c326ded3f4b09be11bc282eb2fc861184bc95748ae67b360ac962770be7"}, + {file = "coverage-7.10.7-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c41e71c9cfb854789dee6fc51e46743a6d138b1803fab6cb860af43265b42ea6"}, + {file = "coverage-7.10.7-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc01f57ca26269c2c706e838f6422e2a8788e41b3e3c65e2f41148212e57cd59"}, + {file = "coverage-7.10.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a6442c59a8ac8b85812ce33bc4d05bde3fb22321fa8294e2a5b487c3505f611b"}, + {file = "coverage-7.10.7-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:78a384e49f46b80fb4c901d52d92abe098e78768ed829c673fbb53c498bef73a"}, + {file = "coverage-7.10.7-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:5e1e9802121405ede4b0133aa4340ad8186a1d2526de5b7c3eca519db7bb89fb"}, + {file = "coverage-7.10.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d41213ea25a86f69efd1575073d34ea11aabe075604ddf3d148ecfec9e1e96a1"}, + {file = "coverage-7.10.7-cp312-cp312-win32.whl", hash = "sha256:77eb4c747061a6af8d0f7bdb31f1e108d172762ef579166ec84542f711d90256"}, + {file = "coverage-7.10.7-cp312-cp312-win_amd64.whl", hash = "sha256:f51328ffe987aecf6d09f3cd9d979face89a617eacdaea43e7b3080777f647ba"}, + {file = "coverage-7.10.7-cp312-cp312-win_arm64.whl", hash = "sha256:bda5e34f8a75721c96085903c6f2197dc398c20ffd98df33f866a9c8fd95f4bf"}, + {file = "coverage-7.10.7-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:981a651f543f2854abd3b5fcb3263aac581b18209be49863ba575de6edf4c14d"}, + {file = "coverage-7.10.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:73ab1601f84dc804f7812dc297e93cd99381162da39c47040a827d4e8dafe63b"}, + {file = "coverage-7.10.7-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:a8b6f03672aa6734e700bbcd65ff050fd19cddfec4b031cc8cf1c6967de5a68e"}, + {file = "coverage-7.10.7-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:10b6ba00ab1132a0ce4428ff68cf50a25efd6840a42cdf4239c9b99aad83be8b"}, + {file = "coverage-7.10.7-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c79124f70465a150e89340de5963f936ee97097d2ef76c869708c4248c63ca49"}, + {file = "coverage-7.10.7-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:69212fbccdbd5b0e39eac4067e20a4a5256609e209547d86f740d68ad4f04911"}, + {file = "coverage-7.10.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7ea7c6c9d0d286d04ed3541747e6597cbe4971f22648b68248f7ddcd329207f0"}, + {file = "coverage-7.10.7-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b9be91986841a75042b3e3243d0b3cb0b2434252b977baaf0cd56e960fe1e46f"}, + {file = "coverage-7.10.7-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:b281d5eca50189325cfe1f365fafade89b14b4a78d9b40b05ddd1fc7d2a10a9c"}, + {file = "coverage-7.10.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:99e4aa63097ab1118e75a848a28e40d68b08a5e19ce587891ab7fd04475e780f"}, + {file = "coverage-7.10.7-cp313-cp313-win32.whl", hash = "sha256:dc7c389dce432500273eaf48f410b37886be9208b2dd5710aaf7c57fd442c698"}, + {file = "coverage-7.10.7-cp313-cp313-win_amd64.whl", hash = "sha256:cac0fdca17b036af3881a9d2729a850b76553f3f716ccb0360ad4dbc06b3b843"}, + {file = "coverage-7.10.7-cp313-cp313-win_arm64.whl", hash = "sha256:4b6f236edf6e2f9ae8fcd1332da4e791c1b6ba0dc16a2dc94590ceccb482e546"}, + {file = "coverage-7.10.7-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a0ec07fd264d0745ee396b666d47cef20875f4ff2375d7c4f58235886cc1ef0c"}, + {file = "coverage-7.10.7-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:dd5e856ebb7bfb7672b0086846db5afb4567a7b9714b8a0ebafd211ec7ce6a15"}, + {file = "coverage-7.10.7-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:f57b2a3c8353d3e04acf75b3fed57ba41f5c0646bbf1d10c7c282291c97936b4"}, + {file = "coverage-7.10.7-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:1ef2319dd15a0b009667301a3f84452a4dc6fddfd06b0c5c53ea472d3989fbf0"}, + {file = "coverage-7.10.7-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:83082a57783239717ceb0ad584de3c69cf581b2a95ed6bf81ea66034f00401c0"}, + {file = "coverage-7.10.7-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:50aa94fb1fb9a397eaa19c0d5ec15a5edd03a47bf1a3a6111a16b36e190cff65"}, + {file = "coverage-7.10.7-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:2120043f147bebb41c85b97ac45dd173595ff14f2a584f2963891cbcc3091541"}, + {file = "coverage-7.10.7-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:2fafd773231dd0378fdba66d339f84904a8e57a262f583530f4f156ab83863e6"}, + {file = "coverage-7.10.7-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:0b944ee8459f515f28b851728ad224fa2d068f1513ef6b7ff1efafeb2185f999"}, + {file = "coverage-7.10.7-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4b583b97ab2e3efe1b3e75248a9b333bd3f8b0b1b8e5b45578e05e5850dfb2c2"}, + {file = "coverage-7.10.7-cp313-cp313t-win32.whl", hash = "sha256:2a78cd46550081a7909b3329e2266204d584866e8d97b898cd7fb5ac8d888b1a"}, + {file = "coverage-7.10.7-cp313-cp313t-win_amd64.whl", hash = "sha256:33a5e6396ab684cb43dc7befa386258acb2d7fae7f67330ebb85ba4ea27938eb"}, + {file = "coverage-7.10.7-cp313-cp313t-win_arm64.whl", hash = "sha256:86b0e7308289ddde73d863b7683f596d8d21c7d8664ce1dee061d0bcf3fbb4bb"}, + {file = "coverage-7.10.7-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:b06f260b16ead11643a5a9f955bd4b5fd76c1a4c6796aeade8520095b75de520"}, + {file = "coverage-7.10.7-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:212f8f2e0612778f09c55dd4872cb1f64a1f2b074393d139278ce902064d5b32"}, + {file = "coverage-7.10.7-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3445258bcded7d4aa630ab8296dea4d3f15a255588dd535f980c193ab6b95f3f"}, + {file = "coverage-7.10.7-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:bb45474711ba385c46a0bfe696c695a929ae69ac636cda8f532be9e8c93d720a"}, + {file = "coverage-7.10.7-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:813922f35bd800dca9994c5971883cbc0d291128a5de6b167c7aa697fcf59360"}, + {file = "coverage-7.10.7-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:93c1b03552081b2a4423091d6fb3787265b8f86af404cff98d1b5342713bdd69"}, + {file = "coverage-7.10.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:cc87dd1b6eaf0b848eebb1c86469b9f72a1891cb42ac7adcfbce75eadb13dd14"}, + {file = "coverage-7.10.7-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:39508ffda4f343c35f3236fe8d1a6634a51f4581226a1262769d7f970e73bffe"}, + {file = "coverage-7.10.7-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:925a1edf3d810537c5a3abe78ec5530160c5f9a26b1f4270b40e62cc79304a1e"}, + {file = "coverage-7.10.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2c8b9a0636f94c43cd3576811e05b89aa9bc2d0a85137affc544ae5cb0e4bfbd"}, + {file = "coverage-7.10.7-cp314-cp314-win32.whl", hash = "sha256:b7b8288eb7cdd268b0304632da8cb0bb93fadcfec2fe5712f7b9cc8f4d487be2"}, + {file = "coverage-7.10.7-cp314-cp314-win_amd64.whl", hash = "sha256:1ca6db7c8807fb9e755d0379ccc39017ce0a84dcd26d14b5a03b78563776f681"}, + {file = "coverage-7.10.7-cp314-cp314-win_arm64.whl", hash = "sha256:097c1591f5af4496226d5783d036bf6fd6cd0cbc132e071b33861de756efb880"}, + {file = "coverage-7.10.7-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:a62c6ef0d50e6de320c270ff91d9dd0a05e7250cac2a800b7784bae474506e63"}, + {file = "coverage-7.10.7-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:9fa6e4dd51fe15d8738708a973470f67a855ca50002294852e9571cdbd9433f2"}, + {file = "coverage-7.10.7-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:8fb190658865565c549b6b4706856d6a7b09302c797eb2cf8e7fe9dabb043f0d"}, + {file = "coverage-7.10.7-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:affef7c76a9ef259187ef31599a9260330e0335a3011732c4b9effa01e1cd6e0"}, + {file = "coverage-7.10.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6e16e07d85ca0cf8bafe5f5d23a0b850064e8e945d5677492b06bbe6f09cc699"}, + {file = "coverage-7.10.7-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:03ffc58aacdf65d2a82bbeb1ffe4d01ead4017a21bfd0454983b88ca73af94b9"}, + {file = "coverage-7.10.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:1b4fd784344d4e52647fd7857b2af5b3fbe6c239b0b5fa63e94eb67320770e0f"}, + {file = "coverage-7.10.7-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:0ebbaddb2c19b71912c6f2518e791aa8b9f054985a0769bdb3a53ebbc765c6a1"}, + {file = "coverage-7.10.7-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:a2d9a3b260cc1d1dbdb1c582e63ddcf5363426a1a68faa0f5da28d8ee3c722a0"}, + {file = "coverage-7.10.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a3cc8638b2480865eaa3926d192e64ce6c51e3d29c849e09d5b4ad95efae5399"}, + {file = "coverage-7.10.7-cp314-cp314t-win32.whl", hash = "sha256:67f8c5cbcd3deb7a60b3345dffc89a961a484ed0af1f6f73de91705cc6e31235"}, + {file = "coverage-7.10.7-cp314-cp314t-win_amd64.whl", hash = "sha256:e1ed71194ef6dea7ed2d5cb5f7243d4bcd334bfb63e59878519be558078f848d"}, + {file = "coverage-7.10.7-cp314-cp314t-win_arm64.whl", hash = "sha256:7fe650342addd8524ca63d77b2362b02345e5f1a093266787d210c70a50b471a"}, + {file = "coverage-7.10.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fff7b9c3f19957020cac546c70025331113d2e61537f6e2441bc7657913de7d3"}, + {file = "coverage-7.10.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:bc91b314cef27742da486d6839b677b3f2793dfe52b51bbbb7cf736d5c29281c"}, + {file = "coverage-7.10.7-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:567f5c155eda8df1d3d439d40a45a6a5f029b429b06648235f1e7e51b522b396"}, + {file = "coverage-7.10.7-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2af88deffcc8a4d5974cf2d502251bc3b2db8461f0b66d80a449c33757aa9f40"}, + {file = "coverage-7.10.7-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c7315339eae3b24c2d2fa1ed7d7a38654cba34a13ef19fbcb9425da46d3dc594"}, + {file = "coverage-7.10.7-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:912e6ebc7a6e4adfdbb1aec371ad04c68854cd3bf3608b3514e7ff9062931d8a"}, + {file = "coverage-7.10.7-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:f49a05acd3dfe1ce9715b657e28d138578bc40126760efb962322c56e9ca344b"}, + {file = "coverage-7.10.7-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:cce2109b6219f22ece99db7644b9622f54a4e915dad65660ec435e89a3ea7cc3"}, + {file = "coverage-7.10.7-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:f3c887f96407cea3916294046fc7dab611c2552beadbed4ea901cbc6a40cc7a0"}, + {file = "coverage-7.10.7-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:635adb9a4507c9fd2ed65f39693fa31c9a3ee3a8e6dc64df033e8fdf52a7003f"}, + {file = "coverage-7.10.7-cp39-cp39-win32.whl", hash = "sha256:5a02d5a850e2979b0a014c412573953995174743a3f7fa4ea5a6e9a3c5617431"}, + {file = "coverage-7.10.7-cp39-cp39-win_amd64.whl", hash = "sha256:c134869d5ffe34547d14e174c866fd8fe2254918cc0a95e99052903bc1543e07"}, + {file = "coverage-7.10.7-py3-none-any.whl", hash = "sha256:f7941f6f2fe6dd6807a1208737b8a0cbcf1cc6d7b07d24998ad2d63590868260"}, + {file = "coverage-7.10.7.tar.gz", hash = "sha256:f4ab143ab113be368a3e9b795f9cd7906c5ef407d6173fe9675a902e1fffc239"}, ] [package.dependencies] @@ -638,62 +654,80 @@ toml = ["tomli ; python_full_version <= \"3.11.0a6\""] [[package]] name = "cryptography" -version = "45.0.7" +version = "46.0.1" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false -python-versions = "!=3.9.0,!=3.9.1,>=3.7" +python-versions = "!=3.9.0,!=3.9.1,>=3.8" groups = ["charm-libs", "integration"] files = [ - {file = "cryptography-45.0.7-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:3be4f21c6245930688bd9e162829480de027f8bf962ede33d4f8ba7d67a00cee"}, - {file = "cryptography-45.0.7-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:67285f8a611b0ebc0857ced2081e30302909f571a46bfa7a3cc0ad303fe015c6"}, - {file = "cryptography-45.0.7-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:577470e39e60a6cd7780793202e63536026d9b8641de011ed9d8174da9ca5339"}, - {file = "cryptography-45.0.7-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:4bd3e5c4b9682bc112d634f2c6ccc6736ed3635fc3319ac2bb11d768cc5a00d8"}, - {file = "cryptography-45.0.7-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:465ccac9d70115cd4de7186e60cfe989de73f7bb23e8a7aa45af18f7412e75bf"}, - {file = "cryptography-45.0.7-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:16ede8a4f7929b4b7ff3642eba2bf79aa1d71f24ab6ee443935c0d269b6bc513"}, - {file = "cryptography-45.0.7-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:8978132287a9d3ad6b54fcd1e08548033cc09dc6aacacb6c004c73c3eb5d3ac3"}, - {file = "cryptography-45.0.7-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:b6a0e535baec27b528cb07a119f321ac024592388c5681a5ced167ae98e9fff3"}, - {file = "cryptography-45.0.7-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:a24ee598d10befaec178efdff6054bc4d7e883f615bfbcd08126a0f4931c83a6"}, - {file = "cryptography-45.0.7-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:fa26fa54c0a9384c27fcdc905a2fb7d60ac6e47d14bc2692145f2b3b1e2cfdbd"}, - {file = "cryptography-45.0.7-cp311-abi3-win32.whl", hash = "sha256:bef32a5e327bd8e5af915d3416ffefdbe65ed975b646b3805be81b23580b57b8"}, - {file = "cryptography-45.0.7-cp311-abi3-win_amd64.whl", hash = "sha256:3808e6b2e5f0b46d981c24d79648e5c25c35e59902ea4391a0dcb3e667bf7443"}, - {file = "cryptography-45.0.7-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:bfb4c801f65dd61cedfc61a83732327fafbac55a47282e6f26f073ca7a41c3b2"}, - {file = "cryptography-45.0.7-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:81823935e2f8d476707e85a78a405953a03ef7b7b4f55f93f7c2d9680e5e0691"}, - {file = "cryptography-45.0.7-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3994c809c17fc570c2af12c9b840d7cea85a9fd3e5c0e0491f4fa3c029216d59"}, - {file = "cryptography-45.0.7-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:dad43797959a74103cb59c5dac71409f9c27d34c8a05921341fb64ea8ccb1dd4"}, - {file = "cryptography-45.0.7-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:ce7a453385e4c4693985b4a4a3533e041558851eae061a58a5405363b098fcd3"}, - {file = "cryptography-45.0.7-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:b04f85ac3a90c227b6e5890acb0edbaf3140938dbecf07bff618bf3638578cf1"}, - {file = "cryptography-45.0.7-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:48c41a44ef8b8c2e80ca4527ee81daa4c527df3ecbc9423c41a420a9559d0e27"}, - {file = "cryptography-45.0.7-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:f3df7b3d0f91b88b2106031fd995802a2e9ae13e02c36c1fc075b43f420f3a17"}, - {file = "cryptography-45.0.7-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:dd342f085542f6eb894ca00ef70236ea46070c8a13824c6bde0dfdcd36065b9b"}, - {file = "cryptography-45.0.7-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1993a1bb7e4eccfb922b6cd414f072e08ff5816702a0bdb8941c247a6b1b287c"}, - {file = "cryptography-45.0.7-cp37-abi3-win32.whl", hash = "sha256:18fcf70f243fe07252dcb1b268a687f2358025ce32f9f88028ca5c364b123ef5"}, - {file = "cryptography-45.0.7-cp37-abi3-win_amd64.whl", hash = "sha256:7285a89df4900ed3bfaad5679b1e668cb4b38a8de1ccbfc84b05f34512da0a90"}, - {file = "cryptography-45.0.7-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:de58755d723e86175756f463f2f0bddd45cc36fbd62601228a3f8761c9f58252"}, - {file = "cryptography-45.0.7-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:a20e442e917889d1a6b3c570c9e3fa2fdc398c20868abcea268ea33c024c4083"}, - {file = "cryptography-45.0.7-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:258e0dff86d1d891169b5af222d362468a9570e2532923088658aa866eb11130"}, - {file = "cryptography-45.0.7-pp310-pypy310_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:d97cf502abe2ab9eff8bd5e4aca274da8d06dd3ef08b759a8d6143f4ad65d4b4"}, - {file = "cryptography-45.0.7-pp310-pypy310_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:c987dad82e8c65ebc985f5dae5e74a3beda9d0a2a4daf8a1115f3772b59e5141"}, - {file = "cryptography-45.0.7-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c13b1e3afd29a5b3b2656257f14669ca8fa8d7956d509926f0b130b600b50ab7"}, - {file = "cryptography-45.0.7-pp311-pypy311_pp73-macosx_10_9_x86_64.whl", hash = "sha256:4a862753b36620af6fc54209264f92c716367f2f0ff4624952276a6bbd18cbde"}, - {file = "cryptography-45.0.7-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:06ce84dc14df0bf6ea84666f958e6080cdb6fe1231be2a51f3fc1267d9f3fb34"}, - {file = "cryptography-45.0.7-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:d0c5c6bac22b177bf8da7435d9d27a6834ee130309749d162b26c3105c0795a9"}, - {file = "cryptography-45.0.7-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:2f641b64acc00811da98df63df7d59fd4706c0df449da71cb7ac39a0732b40ae"}, - {file = "cryptography-45.0.7-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:f5414a788ecc6ee6bc58560e85ca624258a55ca434884445440a810796ea0e0b"}, - {file = "cryptography-45.0.7-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:1f3d56f73595376f4244646dd5c5870c14c196949807be39e79e7bd9bac3da63"}, - {file = "cryptography-45.0.7.tar.gz", hash = "sha256:4b1654dfc64ea479c242508eb8c724044f1e964a47d1d1cacc5132292d851971"}, + {file = "cryptography-46.0.1-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:1cd6d50c1a8b79af1a6f703709d8973845f677c8e97b1268f5ff323d38ce8475"}, + {file = "cryptography-46.0.1-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0ff483716be32690c14636e54a1f6e2e1b7bf8e22ca50b989f88fa1b2d287080"}, + {file = "cryptography-46.0.1-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9873bf7c1f2a6330bdfe8621e7ce64b725784f9f0c3a6a55c3047af5849f920e"}, + {file = "cryptography-46.0.1-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:0dfb7c88d4462a0cfdd0d87a3c245a7bc3feb59de101f6ff88194f740f72eda6"}, + {file = "cryptography-46.0.1-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e22801b61613ebdebf7deb18b507919e107547a1d39a3b57f5f855032dd7cfb8"}, + {file = "cryptography-46.0.1-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:757af4f6341ce7a1e47c326ca2a81f41d236070217e5fbbad61bbfe299d55d28"}, + {file = "cryptography-46.0.1-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f7a24ea78de345cfa7f6a8d3bde8b242c7fac27f2bd78fa23474ca38dfaeeab9"}, + {file = "cryptography-46.0.1-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:9e8776dac9e660c22241b6587fae51a67b4b0147daa4d176b172c3ff768ad736"}, + {file = "cryptography-46.0.1-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:9f40642a140c0c8649987027867242b801486865277cbabc8c6059ddef16dc8b"}, + {file = "cryptography-46.0.1-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:449ef2b321bec7d97ef2c944173275ebdab78f3abdd005400cc409e27cd159ab"}, + {file = "cryptography-46.0.1-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2dd339ba3345b908fa3141ddba4025568fa6fd398eabce3ef72a29ac2d73ad75"}, + {file = "cryptography-46.0.1-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:7411c910fb2a412053cf33cfad0153ee20d27e256c6c3f14d7d7d1d9fec59fd5"}, + {file = "cryptography-46.0.1-cp311-abi3-win32.whl", hash = "sha256:cbb8e769d4cac884bb28e3ff620ef1001b75588a5c83c9c9f1fdc9afbe7f29b0"}, + {file = "cryptography-46.0.1-cp311-abi3-win_amd64.whl", hash = "sha256:92e8cfe8bd7dd86eac0a677499894862cd5cc2fd74de917daa881d00871ac8e7"}, + {file = "cryptography-46.0.1-cp311-abi3-win_arm64.whl", hash = "sha256:db5597a4c7353b2e5fb05a8e6cb74b56a4658a2b7bf3cb6b1821ae7e7fd6eaa0"}, + {file = "cryptography-46.0.1-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:4c49eda9a23019e11d32a0eb51a27b3e7ddedde91e099c0ac6373e3aacc0d2ee"}, + {file = "cryptography-46.0.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:9babb7818fdd71394e576cf26c5452df77a355eac1a27ddfa24096665a27f8fd"}, + {file = "cryptography-46.0.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9f2c4cc63be3ef43c0221861177cee5d14b505cd4d4599a89e2cd273c4d3542a"}, + {file = "cryptography-46.0.1-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:41c281a74df173876da1dc9a9b6953d387f06e3d3ed9284e3baae3ab3f40883a"}, + {file = "cryptography-46.0.1-cp314-cp314t-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0a17377fa52563d730248ba1f68185461fff36e8bc75d8787a7dd2e20a802b7a"}, + {file = "cryptography-46.0.1-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:0d1922d9280e08cde90b518a10cd66831f632960a8d08cb3418922d83fce6f12"}, + {file = "cryptography-46.0.1-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:af84e8e99f1a82cea149e253014ea9dc89f75b82c87bb6c7242203186f465129"}, + {file = "cryptography-46.0.1-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:ef648d2c690703501714588b2ba640facd50fd16548133b11b2859e8655a69da"}, + {file = "cryptography-46.0.1-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:e94eb5fa32a8a9f9bf991f424f002913e3dd7c699ef552db9b14ba6a76a6313b"}, + {file = "cryptography-46.0.1-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:534b96c0831855e29fc3b069b085fd185aa5353033631a585d5cd4dd5d40d657"}, + {file = "cryptography-46.0.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:f9b55038b5c6c47559aa33626d8ecd092f354e23de3c6975e4bb205df128a2a0"}, + {file = "cryptography-46.0.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ec13b7105117dbc9afd023300fb9954d72ca855c274fe563e72428ece10191c0"}, + {file = "cryptography-46.0.1-cp314-cp314t-win32.whl", hash = "sha256:504e464944f2c003a0785b81668fe23c06f3b037e9cb9f68a7c672246319f277"}, + {file = "cryptography-46.0.1-cp314-cp314t-win_amd64.whl", hash = "sha256:c52fded6383f7e20eaf70a60aeddd796b3677c3ad2922c801be330db62778e05"}, + {file = "cryptography-46.0.1-cp314-cp314t-win_arm64.whl", hash = "sha256:9495d78f52c804b5ec8878b5b8c7873aa8e63db9cd9ee387ff2db3fffe4df784"}, + {file = "cryptography-46.0.1-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:d84c40bdb8674c29fa192373498b6cb1e84f882889d21a471b45d1f868d8d44b"}, + {file = "cryptography-46.0.1-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:9ed64e5083fa806709e74fc5ea067dfef9090e5b7a2320a49be3c9df3583a2d8"}, + {file = "cryptography-46.0.1-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:341fb7a26bc9d6093c1b124b9f13acc283d2d51da440b98b55ab3f79f2522ead"}, + {file = "cryptography-46.0.1-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:6ef1488967e729948d424d09c94753d0167ce59afba8d0f6c07a22b629c557b2"}, + {file = "cryptography-46.0.1-cp38-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7823bc7cdf0b747ecfb096d004cc41573c2f5c7e3a29861603a2871b43d3ef32"}, + {file = "cryptography-46.0.1-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:f736ab8036796f5a119ff8211deda416f8c15ce03776db704a7a4e17381cb2ef"}, + {file = "cryptography-46.0.1-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:e46710a240a41d594953012213ea8ca398cd2448fbc5d0f1be8160b5511104a0"}, + {file = "cryptography-46.0.1-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:84ef1f145de5aee82ea2447224dc23f065ff4cc5791bb3b506615957a6ba8128"}, + {file = "cryptography-46.0.1-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:9394c7d5a7565ac5f7d9ba38b2617448eba384d7b107b262d63890079fad77ca"}, + {file = "cryptography-46.0.1-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:ed957044e368ed295257ae3d212b95456bd9756df490e1ac4538857f67531fcc"}, + {file = "cryptography-46.0.1-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:f7de12fa0eee6234de9a9ce0ffcfa6ce97361db7a50b09b65c63ac58e5f22fc7"}, + {file = "cryptography-46.0.1-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:7fab1187b6c6b2f11a326f33b036f7168f5b996aedd0c059f9738915e4e8f53a"}, + {file = "cryptography-46.0.1-cp38-abi3-win32.whl", hash = "sha256:45f790934ac1018adeba46a0f7289b2b8fe76ba774a88c7f1922213a56c98bc1"}, + {file = "cryptography-46.0.1-cp38-abi3-win_amd64.whl", hash = "sha256:7176a5ab56fac98d706921f6416a05e5aff7df0e4b91516f450f8627cda22af3"}, + {file = "cryptography-46.0.1-cp38-abi3-win_arm64.whl", hash = "sha256:efc9e51c3e595267ff84adf56e9b357db89ab2279d7e375ffcaf8f678606f3d9"}, + {file = "cryptography-46.0.1-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:fd4b5e2ee4e60425711ec65c33add4e7a626adef79d66f62ba0acfd493af282d"}, + {file = "cryptography-46.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:48948940d0ae00483e85e9154bb42997d0b77c21e43a77b7773c8c80de532ac5"}, + {file = "cryptography-46.0.1-pp311-pypy311_pp73-macosx_10_9_x86_64.whl", hash = "sha256:b9c79af2c3058430d911ff1a5b2b96bbfe8da47d5ed961639ce4681886614e70"}, + {file = "cryptography-46.0.1-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:0ca4be2af48c24df689a150d9cd37404f689e2968e247b6b8ff09bff5bcd786f"}, + {file = "cryptography-46.0.1-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:13e67c4d3fb8b6bc4ef778a7ccdd8df4cd15b4bcc18f4239c8440891a11245cc"}, + {file = "cryptography-46.0.1-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:15b5fd9358803b0d1cc42505a18d8bca81dabb35b5cfbfea1505092e13a9d96d"}, + {file = "cryptography-46.0.1-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:e34da95e29daf8a71cb2841fd55df0511539a6cdf33e6f77c1e95e44006b9b46"}, + {file = "cryptography-46.0.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:34f04b7311174469ab3ac2647469743720f8b6c8b046f238e5cb27905695eb2a"}, + {file = "cryptography-46.0.1.tar.gz", hash = "sha256:ed570874e88f213437f5cf758f9ef26cbfc3f336d889b1e592ee11283bb8d1c7"}, ] [package.dependencies] -cffi = {version = ">=1.14", markers = "platform_python_implementation != \"PyPy\""} +cffi = {version = ">=2.0.0", markers = "python_full_version >= \"3.9.0\" and platform_python_implementation != \"PyPy\""} +typing-extensions = {version = ">=4.13.2", markers = "python_full_version < \"3.11.0\""} [package.extras] -docs = ["sphinx (>=5.3.0)", "sphinx-inline-tabs ; python_full_version >= \"3.8.0\"", "sphinx-rtd-theme (>=3.0.0) ; python_full_version >= \"3.8.0\""] +docs = ["sphinx (>=5.3.0)", "sphinx-inline-tabs", "sphinx-rtd-theme (>=3.0.0)"] docstest = ["pyenchant (>=3)", "readme-renderer (>=30.0)", "sphinxcontrib-spelling (>=7.3.1)"] -nox = ["nox (>=2024.4.15)", "nox[uv] (>=2024.3.2) ; python_full_version >= \"3.8.0\""] -pep8test = ["check-sdist ; python_full_version >= \"3.8.0\"", "click (>=8.0.1)", "mypy (>=1.4)", "ruff (>=0.3.6)"] +nox = ["nox[uv] (>=2024.4.15)"] +pep8test = ["check-sdist", "click (>=8.0.1)", "mypy (>=1.14)", "ruff (>=0.11.11)"] sdist = ["build (>=1.0.0)"] ssh = ["bcrypt (>=3.1.5)"] -test = ["certifi (>=2024)", "cryptography-vectors (==45.0.7)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"] +test = ["certifi (>=2024)", "cryptography-vectors (==46.0.1)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"] test-randomorder = ["pytest-randomly"] [[package]] @@ -1535,14 +1569,14 @@ testing = ["coverage", "pytest", "pytest-benchmark"] [[package]] name = "poetry-core" -version = "2.2.0" +version = "2.2.1" description = "Poetry PEP 517 Build Backend" optional = false python-versions = "<4.0,>=3.9" groups = ["charm-libs"] files = [ - {file = "poetry_core-2.2.0-py3-none-any.whl", hash = "sha256:0edea81d07e88cbd407369eef753c722da8ff1338f554788dc04636e756318fc"}, - {file = "poetry_core-2.2.0.tar.gz", hash = "sha256:b4033b71b99717a942030e074fec7e3082e5fde7a8ed10f02cd2413bdf940b1f"}, + {file = "poetry_core-2.2.1-py3-none-any.whl", hash = "sha256:bdfce710edc10bfcf9ab35041605c480829be4ab23f5bc01202cfe5db8f125ab"}, + {file = "poetry_core-2.2.1.tar.gz", hash = "sha256:97e50d8593c8729d3f49364b428583e044087ee3def1e010c6496db76bd65ac5"}, ] [[package]] @@ -1583,27 +1617,26 @@ files = [ [[package]] name = "psutil" -version = "7.0.0" -description = "Cross-platform lib for process and system monitoring in Python. NOTE: the syntax of this script MUST be kept compatible with Python 2.7." +version = "7.1.0" +description = "Cross-platform lib for process and system monitoring." optional = false python-versions = ">=3.6" groups = ["main"] files = [ - {file = "psutil-7.0.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:101d71dc322e3cffd7cea0650b09b3d08b8e7c4109dd6809fe452dfd00e58b25"}, - {file = "psutil-7.0.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:39db632f6bb862eeccf56660871433e111b6ea58f2caea825571951d4b6aa3da"}, - {file = "psutil-7.0.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fcee592b4c6f146991ca55919ea3d1f8926497a713ed7faaf8225e174581e91"}, - {file = "psutil-7.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b1388a4f6875d7e2aff5c4ca1cc16c545ed41dd8bb596cefea80111db353a34"}, - {file = "psutil-7.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5f098451abc2828f7dc6b58d44b532b22f2088f4999a937557b603ce72b1993"}, - {file = "psutil-7.0.0-cp36-cp36m-win32.whl", hash = "sha256:84df4eb63e16849689f76b1ffcb36db7b8de703d1bc1fe41773db487621b6c17"}, - {file = "psutil-7.0.0-cp36-cp36m-win_amd64.whl", hash = "sha256:1e744154a6580bc968a0195fd25e80432d3afec619daf145b9e5ba16cc1d688e"}, - {file = "psutil-7.0.0-cp37-abi3-win32.whl", hash = "sha256:ba3fcef7523064a6c9da440fc4d6bd07da93ac726b5733c29027d7dc95b39d99"}, - {file = "psutil-7.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:4cf3d4eb1aa9b348dec30105c55cd9b7d4629285735a102beb4441e38db90553"}, - {file = "psutil-7.0.0.tar.gz", hash = "sha256:7be9c3eba38beccb6495ea33afd982a44074b78f28c434a1f51cc07fd315c456"}, + {file = "psutil-7.1.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:76168cef4397494250e9f4e73eb3752b146de1dd950040b29186d0cce1d5ca13"}, + {file = "psutil-7.1.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:5d007560c8c372efdff9e4579c2846d71de737e4605f611437255e81efcca2c5"}, + {file = "psutil-7.1.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:22e4454970b32472ce7deaa45d045b34d3648ce478e26a04c7e858a0a6e75ff3"}, + {file = "psutil-7.1.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c70e113920d51e89f212dd7be06219a9b88014e63a4cec69b684c327bc474e3"}, + {file = "psutil-7.1.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7d4a113425c037300de3ac8b331637293da9be9713855c4fc9d2d97436d7259d"}, + {file = "psutil-7.1.0-cp37-abi3-win32.whl", hash = "sha256:09ad740870c8d219ed8daae0ad3b726d3bf9a028a198e7f3080f6a1888b99bca"}, + {file = "psutil-7.1.0-cp37-abi3-win_amd64.whl", hash = "sha256:57f5e987c36d3146c0dd2528cd42151cf96cd359b9d67cfff836995cc5df9a3d"}, + {file = "psutil-7.1.0-cp37-abi3-win_arm64.whl", hash = "sha256:6937cb68133e7c97b6cc9649a570c9a18ba0efebed46d8c5dae4c07fa1b67a07"}, + {file = "psutil-7.1.0.tar.gz", hash = "sha256:655708b3c069387c8b77b072fc429a57d0e214221d01c0a772df7dfedcb3bcd2"}, ] [package.extras] -dev = ["abi3audit", "black (==24.10.0)", "check-manifest", "coverage", "packaging", "pylint", "pyperf", "pypinfo", "pytest", "pytest-cov", "pytest-xdist", "requests", "rstcheck", "ruff", "setuptools", "sphinx", "sphinx_rtd_theme", "toml-sort", "twine", "virtualenv", "vulture", "wheel"] -test = ["pytest", "pytest-xdist", "setuptools"] +dev = ["abi3audit", "black", "check-manifest", "coverage", "packaging", "pylint", "pyperf", "pypinfo", "pyreadline ; os_name == \"nt\"", "pytest", "pytest-cov", "pytest-instafail", "pytest-subtests", "pytest-xdist", "pywin32 ; os_name == \"nt\" and platform_python_implementation != \"PyPy\"", "requests", "rstcheck", "ruff", "setuptools", "sphinx", "sphinx_rtd_theme", "toml-sort", "twine", "virtualenv", "vulture", "wheel", "wheel ; os_name == \"nt\" and platform_python_implementation != \"PyPy\"", "wmi ; os_name == \"nt\" and platform_python_implementation != \"PyPy\""] +test = ["pytest", "pytest-instafail", "pytest-subtests", "pytest-xdist", "pywin32 ; os_name == \"nt\" and platform_python_implementation != \"PyPy\"", "setuptools", "wheel ; os_name == \"nt\" and platform_python_implementation != \"PyPy\"", "wmi ; os_name == \"nt\" and platform_python_implementation != \"PyPy\""] [[package]] name = "psycopg2" @@ -2335,31 +2368,31 @@ pyasn1 = ">=0.1.3" [[package]] name = "ruff" -version = "0.13.0" +version = "0.13.1" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" groups = ["format"] files = [ - {file = "ruff-0.13.0-py3-none-linux_armv6l.whl", hash = "sha256:137f3d65d58ee828ae136a12d1dc33d992773d8f7644bc6b82714570f31b2004"}, - {file = "ruff-0.13.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:21ae48151b66e71fd111b7d79f9ad358814ed58c339631450c66a4be33cc28b9"}, - {file = "ruff-0.13.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:64de45f4ca5441209e41742d527944635a05a6e7c05798904f39c85bafa819e3"}, - {file = "ruff-0.13.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2b2c653ae9b9d46e0ef62fc6fbf5b979bda20a0b1d2b22f8f7eb0cde9f4963b8"}, - {file = "ruff-0.13.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4cec632534332062bc9eb5884a267b689085a1afea9801bf94e3ba7498a2d207"}, - {file = "ruff-0.13.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dcd628101d9f7d122e120ac7c17e0a0f468b19bc925501dbe03c1cb7f5415b24"}, - {file = "ruff-0.13.0-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:afe37db8e1466acb173bb2a39ca92df00570e0fd7c94c72d87b51b21bb63efea"}, - {file = "ruff-0.13.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0f96a8d90bb258d7d3358b372905fe7333aaacf6c39e2408b9f8ba181f4b6ef2"}, - {file = "ruff-0.13.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:94b5e3d883e4f924c5298e3f2ee0f3085819c14f68d1e5b6715597681433f153"}, - {file = "ruff-0.13.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03447f3d18479df3d24917a92d768a89f873a7181a064858ea90a804a7538991"}, - {file = "ruff-0.13.0-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:fbc6b1934eb1c0033da427c805e27d164bb713f8e273a024a7e86176d7f462cf"}, - {file = "ruff-0.13.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:a8ab6a3e03665d39d4a25ee199d207a488724f022db0e1fe4002968abdb8001b"}, - {file = "ruff-0.13.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:d2a5c62f8ccc6dd2fe259917482de7275cecc86141ee10432727c4816235bc41"}, - {file = "ruff-0.13.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:b7b85ca27aeeb1ab421bc787009831cffe6048faae08ad80867edab9f2760945"}, - {file = "ruff-0.13.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:79ea0c44a3032af768cabfd9616e44c24303af49d633b43e3a5096e009ebe823"}, - {file = "ruff-0.13.0-py3-none-win32.whl", hash = "sha256:4e473e8f0e6a04e4113f2e1de12a5039579892329ecc49958424e5568ef4f768"}, - {file = "ruff-0.13.0-py3-none-win_amd64.whl", hash = "sha256:48e5c25c7a3713eea9ce755995767f4dcd1b0b9599b638b12946e892123d1efb"}, - {file = "ruff-0.13.0-py3-none-win_arm64.whl", hash = "sha256:ab80525317b1e1d38614addec8ac954f1b3e662de9d59114ecbf771d00cf613e"}, - {file = "ruff-0.13.0.tar.gz", hash = "sha256:5b4b1ee7eb35afae128ab94459b13b2baaed282b1fb0f472a73c82c996c8ae60"}, + {file = "ruff-0.13.1-py3-none-linux_armv6l.whl", hash = "sha256:b2abff595cc3cbfa55e509d89439b5a09a6ee3c252d92020bd2de240836cf45b"}, + {file = "ruff-0.13.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:4ee9f4249bf7f8bb3984c41bfaf6a658162cdb1b22e3103eabc7dd1dc5579334"}, + {file = "ruff-0.13.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:5c5da4af5f6418c07d75e6f3224e08147441f5d1eac2e6ce10dcce5e616a3bae"}, + {file = "ruff-0.13.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:80524f84a01355a59a93cef98d804e2137639823bcee2931f5028e71134a954e"}, + {file = "ruff-0.13.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ff7f5ce8d7988767dd46a148192a14d0f48d1baea733f055d9064875c7d50389"}, + {file = "ruff-0.13.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c55d84715061f8b05469cdc9a446aa6c7294cd4bd55e86a89e572dba14374f8c"}, + {file = "ruff-0.13.1-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:ac57fed932d90fa1624c946dc67a0a3388d65a7edc7d2d8e4ca7bddaa789b3b0"}, + {file = "ruff-0.13.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c366a71d5b4f41f86a008694f7a0d75fe409ec298685ff72dc882f882d532e36"}, + {file = "ruff-0.13.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4ea9d1b5ad3e7a83ee8ebb1229c33e5fe771e833d6d3dcfca7b77d95b060d38"}, + {file = "ruff-0.13.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b0f70202996055b555d3d74b626406476cc692f37b13bac8828acff058c9966a"}, + {file = "ruff-0.13.1-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:f8cff7a105dad631085d9505b491db33848007d6b487c3c1979dd8d9b2963783"}, + {file = "ruff-0.13.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:9761e84255443316a258dd7dfbd9bfb59c756e52237ed42494917b2577697c6a"}, + {file = "ruff-0.13.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:3d376a88c3102ef228b102211ef4a6d13df330cb0f5ca56fdac04ccec2a99700"}, + {file = "ruff-0.13.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:cbefd60082b517a82c6ec8836989775ac05f8991715d228b3c1d86ccc7df7dae"}, + {file = "ruff-0.13.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:dd16b9a5a499fe73f3c2ef09a7885cb1d97058614d601809d37c422ed1525317"}, + {file = "ruff-0.13.1-py3-none-win32.whl", hash = "sha256:55e9efa692d7cb18580279f1fbb525146adc401f40735edf0aaeabd93099f9a0"}, + {file = "ruff-0.13.1-py3-none-win_amd64.whl", hash = "sha256:3a3fb595287ee556de947183489f636b9f76a72f0fa9c028bdcabf5bab2cc5e5"}, + {file = "ruff-0.13.1-py3-none-win_arm64.whl", hash = "sha256:c0bae9ffd92d54e03c2bf266f466da0a65e145f298ee5b5846ed435f6a00518a"}, + {file = "ruff-0.13.1.tar.gz", hash = "sha256:88074c3849087f153d4bb22e92243ad4c1b366d7055f98726bc19aa08dc12d51"}, ] [[package]] @@ -2548,14 +2581,14 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "wcwidth" -version = "0.2.13" +version = "0.2.14" description = "Measures the displayed width of unicode strings in a terminal" optional = false -python-versions = "*" +python-versions = ">=3.6" groups = ["integration"] files = [ - {file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"}, - {file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"}, + {file = "wcwidth-0.2.14-py2.py3-none-any.whl", hash = "sha256:a7bb560c8aee30f9957e5f9895805edd20602f2d7f720186dfd906e82b4982e1"}, + {file = "wcwidth-0.2.14.tar.gz", hash = "sha256:4d478375d31bc5395a3c55c40ccdf3354688364cd61c4f6adacaa9215d0b3605"}, ] [[package]] @@ -2768,4 +2801,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = "^3.10" -content-hash = "b9e4437b9bba14c8b3fa1450c50a21854cd7217576edaaf4e42b30a51cf7b7e5" +content-hash = "3c21c394d0452869cbaec1b341cfecee0e95647e04748d0d07018f8b0e8d4d23" diff --git a/pyproject.toml b/pyproject.toml index ea2e85c9cd..7453d8a448 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ requires-poetry = ">=2.0.0" [tool.poetry.dependencies] python = "^3.10" ops = "^2.23.1" -boto3 = "^1.40.31" +boto3 = "^1.40.36" pgconnstr = "^1.0.1" requests = "^2.32.5" tenacity = "^9.1.2" @@ -16,7 +16,7 @@ psycopg2 = "^2.9.10" pydantic = "^1.10.23" jinja2 = "^3.1.6" pysyncobj = "^0.3.14" -psutil = "^7.0.0" +psutil = "^7.1.0" [tool.poetry.group.charm-libs.dependencies] # data_platform_libs/v0/data_interfaces.py @@ -40,7 +40,7 @@ opentelemetry-exporter-otlp-proto-http = "1.21.0" optional = true [tool.poetry.group.format.dependencies] -ruff = "^0.13.0" +ruff = "^0.13.1" [tool.poetry.group.lint] optional = true @@ -52,7 +52,7 @@ codespell = "^2.4.1" optional = true [tool.poetry.group.unit.dependencies] -coverage = {extras = ["toml"], version = "^7.10.6"} +coverage = {extras = ["toml"], version = "^7.10.7"} pytest = "^8.4.2" pytest-asyncio = "*" parameterized = "^0.9.0" From c6280bc1e7981f106f29b1b1547567addba0f87c Mon Sep 17 00:00:00 2001 From: Dragomir Penev <6687393+dragomirp@users.noreply.github.com> Date: Fri, 26 Sep 2025 16:27:56 +0300 Subject: [PATCH 104/112] [DPE-8430][DPE-8427] Mute error message to debug and creation of access roles (#1186) * Mute error message to debug * Create access roles * Move setup of access roles to upgrade granted * Try to use mnt for storage * Skip disk cleanup --- .github/workflows/integration_test.yaml | 11 +---------- spread.yaml | 3 +++ src/cluster.py | 4 ++-- src/upgrade.py | 4 +++- tests/unit/test_upgrade.py | 1 + 5 files changed, 10 insertions(+), 13 deletions(-) diff --git a/.github/workflows/integration_test.yaml b/.github/workflows/integration_test.yaml index b730374b2b..54dcc04048 100644 --- a/.github/workflows/integration_test.yaml +++ b/.github/workflows/integration_test.yaml @@ -84,17 +84,8 @@ jobs: needs: - collect-integration-tests runs-on: ${{ matrix.job.runner }} - timeout-minutes: 226 # Sum of steps `timeout-minutes` + 5 + timeout-minutes: 216 # Sum of steps `timeout-minutes` + 5 steps: - - name: Free up disk space - timeout-minutes: 10 - run: | - printf '\nDisk usage before cleanup\n' - df --human-readable - # Based on https://github.com/actions/runner-images/issues/2840#issuecomment-790492173 - rm -r /opt/hostedtoolcache/ - printf '\nDisk usage after cleanup\n' - df --human-readable - name: Checkout timeout-minutes: 3 uses: actions/checkout@v5 diff --git a/spread.yaml b/spread.yaml index 9a2c7ed1b6..d9d600c4fa 100644 --- a/spread.yaml +++ b/spread.yaml @@ -82,6 +82,9 @@ backends: sudo passwd -d runner ADDRESS localhost + + sudo mkdir -p /var/snap/lxd/common/lxd/storage-pools + sudo mount --bind /mnt /var/snap/lxd/common/lxd/storage-pools # HACK: spread does not pass environment variables set on runner # Manually pass specific environment variables environment: diff --git a/src/cluster.py b/src/cluster.py index 1c582f0e43..056f093e3c 100644 --- a/src/cluster.py +++ b/src/cluster.py @@ -584,8 +584,8 @@ def are_replicas_up(self) -> dict[str, bool] | None: member["host"]: member["state"] in ["running", "streaming"] for member in response.json()["members"] } - except Exception: - logger.exception("Unable to get the state of the cluster") + except Exception as e: + logger.debug(f"Unable to get the state of the cluster: {e}") return def promote_standby_cluster(self) -> None: diff --git a/src/upgrade.py b/src/upgrade.py index ed430e0cf4..08dee25eaf 100644 --- a/src/upgrade.py +++ b/src/upgrade.py @@ -196,6 +196,8 @@ def _on_upgrade_granted(self, event: UpgradeGrantedEvent) -> None: self.charm.update_config() + self._set_up_new_access_roles_for_legacy() + self.set_unit_completed() # Ensures leader gets its own relation-changed when it upgrades @@ -258,7 +260,6 @@ def _prepare_upgrade_from_legacy(self) -> None: extra_user_roles="pg_monitor", ) self.charm.postgresql.set_up_database() - self._set_up_new_access_roles_for_legacy() def _set_up_new_access_roles_for_legacy(self) -> None: """Create missing access groups and their memberships.""" @@ -271,6 +272,7 @@ def _set_up_new_access_roles_for_legacy(self) -> None: self.charm.postgresql.create_access_groups() self.charm.postgresql.grant_internal_access_group_memberships() self.charm.postgresql.grant_relation_access_group_memberships() + logger.debug("Access roles created") @property def unit_upgrade_data(self) -> RelationDataContent: diff --git a/tests/unit/test_upgrade.py b/tests/unit/test_upgrade.py index 1baac2da9b..22a186cbdb 100644 --- a/tests/unit/test_upgrade.py +++ b/tests/unit/test_upgrade.py @@ -109,6 +109,7 @@ def test_on_upgrade_granted(harness): patch( "charm.PostgresqlOperatorCharm.updated_synchronous_node_count" ) as _updated_synchronous_node_count, + patch("upgrade.PostgreSQLUpgrade._set_up_new_access_roles_for_legacy"), ): # Test when the charm fails to start Patroni. mock_event = MagicMock() From 4066bfb67732592a3f3015e2129e23117e7d2898 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 30 Sep 2025 02:47:59 +0300 Subject: [PATCH 105/112] Update charmcraft.yaml build tools (#1142) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- charmcraft.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/charmcraft.yaml b/charmcraft.yaml index 3490a29ccf..15a1ea920a 100644 --- a/charmcraft.yaml +++ b/charmcraft.yaml @@ -27,7 +27,7 @@ parts: PIP_BREAK_SYSTEM_PACKAGES=true python3 -m pip install --user --upgrade pip==25.2 # renovate: charmcraft-pip-latest # Use uv to install poetry so that a newer version of Python can be installed if needed by poetry - curl --proto '=https' --tlsv1.2 -LsSf https://github.com/astral-sh/uv/releases/download/0.8.14/uv-installer.sh | sh # renovate: charmcraft-uv-latest + curl --proto '=https' --tlsv1.2 -LsSf https://github.com/astral-sh/uv/releases/download/0.8.22/uv-installer.sh | sh # renovate: charmcraft-uv-latest # poetry 2.0.0 requires Python >=3.9 if ! "$HOME/.local/bin/uv" python find '>=3.9' then @@ -35,7 +35,7 @@ parts: # (to reduce the number of Python versions we use) "$HOME/.local/bin/uv" python install 3.10.12 # renovate: charmcraft-python-ubuntu-22.04 fi - "$HOME/.local/bin/uv" tool install --no-python-downloads --python '>=3.9' poetry==2.1.4 --with poetry-plugin-export==1.9.0 # renovate: charmcraft-poetry-latest + "$HOME/.local/bin/uv" tool install --no-python-downloads --python '>=3.9' poetry==2.2.1 --with poetry-plugin-export==1.9.0 # renovate: charmcraft-poetry-latest ln -sf "$HOME/.local/bin/poetry" /usr/local/bin/poetry # "charm-poetry" part name is arbitrary; use for consistency @@ -75,7 +75,7 @@ parts: # rpds-py (Python package) >=0.19.0 requires rustc >=1.76, which is not available in the # Ubuntu 22.04 archive. Install rustc and cargo using rustup instead of the Ubuntu archive rustup set profile minimal - rustup default 1.89.0 # renovate: charmcraft-rust-latest + rustup default 1.90.0 # renovate: charmcraft-rust-latest craftctl default # Include requirements.txt in *.charm artifact for easier debugging From d6154c2ae3ea1ca27b2dfe7f9d53974b76b075d8 Mon Sep 17 00:00:00 2001 From: Alex Lutay <1928266+taurus-forever@users.noreply.github.com> Date: Fri, 3 Oct 2025 22:30:25 +0200 Subject: [PATCH 106/112] DPE-8470 Bump snap for Patroni to 3.3.8 (#1197) --- src/constants.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/constants.py b/src/constants.py index 29cecb93d0..df9cda3690 100644 --- a/src/constants.py +++ b/src/constants.py @@ -35,7 +35,7 @@ SNAP_PACKAGES = [ ( POSTGRESQL_SNAP_NAME, - {"revision": {"aarch64": "230", "x86_64": "229"}}, + {"revision": {"aarch64": "237", "x86_64": "238"}}, ) ] From 85c9d98b97fff0150e4292fcce8b0be9d3855751 Mon Sep 17 00:00:00 2001 From: Dragomir Penev <6687393+dragomirp@users.noreply.github.com> Date: Tue, 7 Oct 2025 13:03:00 +0300 Subject: [PATCH 107/112] [MISC] Set strict sync mode (#1196) * Set strict sync mode * Try bootstrapping with false strict mode * Move increase writes check * Try to cleanup only if the test didn't fail * Add checks for strict mode * Revert "Add checks for strict mode" This reverts commit 85b7f61535d74c0f94bfa7d48b5b6a01bc252299. * Try using env to detect test failure * Remove redundant arg * Try stopping instead of cleaning * Only set strict mode if there are multiple active units * Check sync units as well --- src/cluster.py | 8 +++++++- templates/patroni.yml.j2 | 1 + tests/integration/ha_tests/test_scaling.py | 10 +++++----- tests/integration/ha_tests/test_scaling_three_units.py | 6 +++--- .../ha_tests/test_scaling_three_units_async.py | 6 +++--- tests/integration/ha_tests/test_self_healing.py | 2 +- tests/unit/test_cluster.py | 2 +- 7 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/cluster.py b/src/cluster.py index 056f093e3c..41aeba34f5 100644 --- a/src/cluster.py +++ b/src/cluster.py @@ -5,6 +5,7 @@ """Helper class used to manage cluster lifecycle.""" import glob +import json import logging import os import pwd @@ -1057,11 +1058,16 @@ def _synchronous_node_count(self) -> int: def update_synchronous_node_count(self) -> None: """Update synchronous_node_count to the minority of the planned cluster.""" # Try to update synchronous_node_count. + member_units = json.loads(self.charm.app_peer_data.get("members_ips", "[]")) for attempt in Retrying(stop=stop_after_delay(60), wait=wait_fixed(3)): with attempt: r = requests.patch( f"{self._patroni_url}/config", - json={"synchronous_node_count": self._synchronous_node_count}, + json={ + "synchronous_node_count": self._synchronous_node_count, + "synchronous_mode_strict": len(member_units) > 1 + and self._synchronous_node_count > 0, + }, verify=self.verify, auth=self._patroni_auth, timeout=PATRONI_TIMEOUT, diff --git a/templates/patroni.yml.j2 b/templates/patroni.yml.j2 index b02995d4f1..01f420e34d 100644 --- a/templates/patroni.yml.j2 +++ b/templates/patroni.yml.j2 @@ -59,6 +59,7 @@ bootstrap: retry_timeout: 10 maximum_lag_on_failover: 1048576 synchronous_mode: true + synchronous_mode_strict: false synchronous_node_count: {{ synchronous_node_count }} postgresql: use_pg_rewind: true diff --git a/tests/integration/ha_tests/test_scaling.py b/tests/integration/ha_tests/test_scaling.py index 7ea2f6c90f..f5f7f0235f 100644 --- a/tests/integration/ha_tests/test_scaling.py +++ b/tests/integration/ha_tests/test_scaling.py @@ -12,8 +12,8 @@ CHARM_BASE, DATABASE_APP_NAME, ) -from .conftest import APPLICATION_NAME from .helpers import ( + APPLICATION_NAME, app_name, are_writes_increasing, check_writes, @@ -87,12 +87,12 @@ async def test_removing_stereo_primary(ops_test: OpsTest, continuous_writes) -> await ops_test.model.wait_for_idle(status="active", timeout=600, idle_period=45) - await are_writes_increasing(ops_test, primary) - logger.info("Scaling back up") await ops_test.model.applications[DATABASE_APP_NAME].add_unit(count=1) await ops_test.model.wait_for_idle(status="active", timeout=1500) + await are_writes_increasing(ops_test, primary) + new_roles = await get_cluster_roles( ops_test, ops_test.model.applications[DATABASE_APP_NAME].units[0].name ) @@ -121,12 +121,12 @@ async def test_removing_stereo_sync_standby(ops_test: OpsTest, continuous_writes await ops_test.model.wait_for_idle(status="active", timeout=600, idle_period=45) - await are_writes_increasing(ops_test, secondary) - logger.info("Scaling back up") await ops_test.model.applications[DATABASE_APP_NAME].add_unit(count=1) await ops_test.model.wait_for_idle(status="active", timeout=1500) + await are_writes_increasing(ops_test, secondary) + new_roles = await get_cluster_roles( ops_test, ops_test.model.applications[DATABASE_APP_NAME].units[0].name ) diff --git a/tests/integration/ha_tests/test_scaling_three_units.py b/tests/integration/ha_tests/test_scaling_three_units.py index e0407d2a2f..cb69becd15 100644 --- a/tests/integration/ha_tests/test_scaling_three_units.py +++ b/tests/integration/ha_tests/test_scaling_three_units.py @@ -10,12 +10,12 @@ from .. import markers from ..helpers import ( + APPLICATION_NAME, CHARM_BASE, DATABASE_APP_NAME, get_machine_from_unit, stop_machine, ) -from .conftest import APPLICATION_NAME from .helpers import ( app_name, are_writes_increasing, @@ -114,12 +114,12 @@ async def test_removing_unit(ops_test: OpsTest, roles: list[str], continuous_wri await ops_test.model.wait_for_idle(status="active", timeout=600, idle_period=45) - await are_writes_increasing(ops_test, units) - logger.info("Scaling back up") await ops_test.model.applications[DATABASE_APP_NAME].add_unit(count=len(roles)) await ops_test.model.wait_for_idle(status="active", timeout=1500) + await are_writes_increasing(ops_test, units) + new_roles = await get_cluster_roles( ops_test, ops_test.model.applications[DATABASE_APP_NAME].units[0].name ) diff --git a/tests/integration/ha_tests/test_scaling_three_units_async.py b/tests/integration/ha_tests/test_scaling_three_units_async.py index 07fa956af8..d213633dd2 100644 --- a/tests/integration/ha_tests/test_scaling_three_units_async.py +++ b/tests/integration/ha_tests/test_scaling_three_units_async.py @@ -10,12 +10,12 @@ from .. import markers from ..helpers import ( + APPLICATION_NAME, CHARM_BASE, DATABASE_APP_NAME, get_machine_from_unit, stop_machine, ) -from .conftest import APPLICATION_NAME from .helpers import ( app_name, are_writes_increasing, @@ -115,12 +115,12 @@ async def test_removing_unit(ops_test: OpsTest, roles: list[str], continuous_wri await ops_test.model.wait_for_idle(status="active", timeout=600, idle_period=45) - await are_writes_increasing(ops_test, units) - logger.info("Scaling back up") await ops_test.model.applications[DATABASE_APP_NAME].add_unit(count=len(roles)) await ops_test.model.wait_for_idle(status="active", timeout=1500) + await are_writes_increasing(ops_test, units) + new_roles = await get_cluster_roles( ops_test, ops_test.model.applications[DATABASE_APP_NAME].units[0].name ) diff --git a/tests/integration/ha_tests/test_self_healing.py b/tests/integration/ha_tests/test_self_healing.py index 1ec6141366..6db6052bf7 100644 --- a/tests/integration/ha_tests/test_self_healing.py +++ b/tests/integration/ha_tests/test_self_healing.py @@ -11,6 +11,7 @@ from .. import markers from ..helpers import ( + APPLICATION_NAME, CHARM_BASE, DATABASE_APP_NAME, db_connect, @@ -19,7 +20,6 @@ get_unit_address, run_command_on_unit, ) -from .conftest import APPLICATION_NAME from .helpers import ( METADATA, ORIGINAL_RESTART_CONDITION, diff --git a/tests/unit/test_cluster.py b/tests/unit/test_cluster.py index 9fc41363fa..c767bcbea2 100644 --- a/tests/unit/test_cluster.py +++ b/tests/unit/test_cluster.py @@ -532,7 +532,7 @@ def test_update_synchronous_node_count(peers_ips, patroni): _patch.assert_called_once_with( "http://1.1.1.1:8008/config", - json={"synchronous_node_count": 0}, + json={"synchronous_node_count": 0, "synchronous_mode_strict": False}, verify=True, auth=patroni._patroni_auth, timeout=PATRONI_TIMEOUT, From 605999e983fb70d48a104ecd6871902e623c0e90 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 7 Oct 2025 13:13:06 +0300 Subject: [PATCH 108/112] Update dependency ops to v3 (#1019) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- poetry.lock | 15 +++++++-------- pyproject.toml | 2 +- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/poetry.lock b/poetry.lock index aa0878acf7..668081854c 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1439,25 +1439,24 @@ files = [ [[package]] name = "ops" -version = "2.23.1" +version = "3.3.0" description = "The Python library behind great charms" optional = false -python-versions = ">=3.8" +python-versions = ">=3.10" groups = ["main", "charm-libs"] files = [ - {file = "ops-2.23.1-py3-none-any.whl", hash = "sha256:fdf58163beafd25180c12a4c7efaf1e76e5f8710508a97840c07055bb78b0c77"}, - {file = "ops-2.23.1.tar.gz", hash = "sha256:aecacd67ef7ca913f63f397e0330bfa93d70529a3ef71ed2d99e2bc232564ae3"}, + {file = "ops-3.3.0-py3-none-any.whl", hash = "sha256:4f03013dfe325690add181f989b571259cc4add8a8a5cafbd380ffcc2bbd7c1d"}, + {file = "ops-3.3.0.tar.gz", hash = "sha256:f89613def8b4a231218038ba5656927c522532e42b2dd8c06e12ff7a45bc647a"}, ] [package.dependencies] -importlib-metadata = "*" opentelemetry-api = ">=1.0,<2.0" PyYAML = "==6.*" websocket-client = "==1.*" [package.extras] -testing = ["ops-scenario (==7.23.1)"] -tracing = ["ops-tracing (==2.23.1)"] +testing = ["ops-scenario (==8.3.0)"] +tracing = ["ops-tracing (==3.3.0)"] [[package]] name = "packaging" @@ -2801,4 +2800,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = "^3.10" -content-hash = "3c21c394d0452869cbaec1b341cfecee0e95647e04748d0d07018f8b0e8d4d23" +content-hash = "b4a702830125a4ff438de0478f25a13d4377abc705c14db67ff95e62ad3ecd1b" diff --git a/pyproject.toml b/pyproject.toml index 7453d8a448..1c67cc7777 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,7 @@ requires-poetry = ">=2.0.0" [tool.poetry.dependencies] python = "^3.10" -ops = "^2.23.1" +ops = "^3.3.0" boto3 = "^1.40.36" pgconnstr = "^1.0.1" requests = "^2.32.5" From e6f46b524a3ca879b5f94dc684a46c5c295f3729 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 04:30:44 +0300 Subject: [PATCH 109/112] Lock file maintenance Python dependencies (#1203) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- poetry.lock | 730 ++++++++++++++++++++++++++----------------------- pyproject.toml | 8 +- 2 files changed, 395 insertions(+), 343 deletions(-) diff --git a/poetry.lock b/poetry.lock index 668081854c..7bc843158c 100644 --- a/poetry.lock +++ b/poetry.lock @@ -66,24 +66,16 @@ test = ["astroid (>=2,<4)", "pytest", "pytest-cov", "pytest-xdist"] [[package]] name = "attrs" -version = "25.3.0" +version = "25.4.0" description = "Classes Without Boilerplate" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["charm-libs", "integration", "unit"] files = [ - {file = "attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3"}, - {file = "attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b"}, + {file = "attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373"}, + {file = "attrs-25.4.0.tar.gz", hash = "sha256:16d5969b87f0859ef33a48b35d55ac1be6e42ae49d5e853b597db70c35c57e11"}, ] -[package.extras] -benchmark = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] -cov = ["cloudpickle ; platform_python_implementation == \"CPython\"", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] -dev = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pre-commit-uv", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] -docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier"] -tests = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] -tests-mypy = ["mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\""] - [[package]] name = "backoff" version = "2.2.1" @@ -168,63 +160,75 @@ files = [ [[package]] name = "bcrypt" -version = "4.3.0" +version = "5.0.0" description = "Modern password hashing for your software and your servers" optional = false python-versions = ">=3.8" groups = ["integration"] files = [ - {file = "bcrypt-4.3.0-cp313-cp313t-macosx_10_12_universal2.whl", hash = "sha256:f01e060f14b6b57bbb72fc5b4a83ac21c443c9a2ee708e04a10e9192f90a6281"}, - {file = "bcrypt-4.3.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5eeac541cefd0bb887a371ef73c62c3cd78535e4887b310626036a7c0a817bb"}, - {file = "bcrypt-4.3.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59e1aa0e2cd871b08ca146ed08445038f42ff75968c7ae50d2fdd7860ade2180"}, - {file = "bcrypt-4.3.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:0042b2e342e9ae3d2ed22727c1262f76cc4f345683b5c1715f0250cf4277294f"}, - {file = "bcrypt-4.3.0-cp313-cp313t-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74a8d21a09f5e025a9a23e7c0fd2c7fe8e7503e4d356c0a2c1486ba010619f09"}, - {file = "bcrypt-4.3.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:0142b2cb84a009f8452c8c5a33ace5e3dfec4159e7735f5afe9a4d50a8ea722d"}, - {file = "bcrypt-4.3.0-cp313-cp313t-manylinux_2_34_aarch64.whl", hash = "sha256:12fa6ce40cde3f0b899729dbd7d5e8811cb892d31b6f7d0334a1f37748b789fd"}, - {file = "bcrypt-4.3.0-cp313-cp313t-manylinux_2_34_x86_64.whl", hash = "sha256:5bd3cca1f2aa5dbcf39e2aa13dd094ea181f48959e1071265de49cc2b82525af"}, - {file = "bcrypt-4.3.0-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:335a420cfd63fc5bc27308e929bee231c15c85cc4c496610ffb17923abf7f231"}, - {file = "bcrypt-4.3.0-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:0e30e5e67aed0187a1764911af023043b4542e70a7461ad20e837e94d23e1d6c"}, - {file = "bcrypt-4.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:3b8d62290ebefd49ee0b3ce7500f5dbdcf13b81402c05f6dafab9a1e1b27212f"}, - {file = "bcrypt-4.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2ef6630e0ec01376f59a006dc72918b1bf436c3b571b80fa1968d775fa02fe7d"}, - {file = "bcrypt-4.3.0-cp313-cp313t-win32.whl", hash = "sha256:7a4be4cbf241afee43f1c3969b9103a41b40bcb3a3f467ab19f891d9bc4642e4"}, - {file = "bcrypt-4.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5c1949bf259a388863ced887c7861da1df681cb2388645766c89fdfd9004c669"}, - {file = "bcrypt-4.3.0-cp38-abi3-macosx_10_12_universal2.whl", hash = "sha256:f81b0ed2639568bf14749112298f9e4e2b28853dab50a8b357e31798686a036d"}, - {file = "bcrypt-4.3.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:864f8f19adbe13b7de11ba15d85d4a428c7e2f344bac110f667676a0ff84924b"}, - {file = "bcrypt-4.3.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3e36506d001e93bffe59754397572f21bb5dc7c83f54454c990c74a468cd589e"}, - {file = "bcrypt-4.3.0-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:842d08d75d9fe9fb94b18b071090220697f9f184d4547179b60734846461ed59"}, - {file = "bcrypt-4.3.0-cp38-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7c03296b85cb87db865d91da79bf63d5609284fc0cab9472fdd8367bbd830753"}, - {file = "bcrypt-4.3.0-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:62f26585e8b219cdc909b6a0069efc5e4267e25d4a3770a364ac58024f62a761"}, - {file = "bcrypt-4.3.0-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:beeefe437218a65322fbd0069eb437e7c98137e08f22c4660ac2dc795c31f8bb"}, - {file = "bcrypt-4.3.0-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:97eea7408db3a5bcce4a55d13245ab3fa566e23b4c67cd227062bb49e26c585d"}, - {file = "bcrypt-4.3.0-cp38-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:191354ebfe305e84f344c5964c7cd5f924a3bfc5d405c75ad07f232b6dffb49f"}, - {file = "bcrypt-4.3.0-cp38-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:41261d64150858eeb5ff43c753c4b216991e0ae16614a308a15d909503617732"}, - {file = "bcrypt-4.3.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:33752b1ba962ee793fa2b6321404bf20011fe45b9afd2a842139de3011898fef"}, - {file = "bcrypt-4.3.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:50e6e80a4bfd23a25f5c05b90167c19030cf9f87930f7cb2eacb99f45d1c3304"}, - {file = "bcrypt-4.3.0-cp38-abi3-win32.whl", hash = "sha256:67a561c4d9fb9465ec866177e7aebcad08fe23aaf6fbd692a6fab69088abfc51"}, - {file = "bcrypt-4.3.0-cp38-abi3-win_amd64.whl", hash = "sha256:584027857bc2843772114717a7490a37f68da563b3620f78a849bcb54dc11e62"}, - {file = "bcrypt-4.3.0-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:0d3efb1157edebfd9128e4e46e2ac1a64e0c1fe46fb023158a407c7892b0f8c3"}, - {file = "bcrypt-4.3.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:08bacc884fd302b611226c01014eca277d48f0a05187666bca23aac0dad6fe24"}, - {file = "bcrypt-4.3.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6746e6fec103fcd509b96bacdfdaa2fbde9a553245dbada284435173a6f1aef"}, - {file = "bcrypt-4.3.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:afe327968aaf13fc143a56a3360cb27d4ad0345e34da12c7290f1b00b8fe9a8b"}, - {file = "bcrypt-4.3.0-cp39-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d9af79d322e735b1fc33404b5765108ae0ff232d4b54666d46730f8ac1a43676"}, - {file = "bcrypt-4.3.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f1e3ffa1365e8702dc48c8b360fef8d7afeca482809c5e45e653af82ccd088c1"}, - {file = "bcrypt-4.3.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:3004df1b323d10021fda07a813fd33e0fd57bef0e9a480bb143877f6cba996fe"}, - {file = "bcrypt-4.3.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:531457e5c839d8caea9b589a1bcfe3756b0547d7814e9ce3d437f17da75c32b0"}, - {file = "bcrypt-4.3.0-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:17a854d9a7a476a89dcef6c8bd119ad23e0f82557afbd2c442777a16408e614f"}, - {file = "bcrypt-4.3.0-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:6fb1fd3ab08c0cbc6826a2e0447610c6f09e983a281b919ed721ad32236b8b23"}, - {file = "bcrypt-4.3.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e965a9c1e9a393b8005031ff52583cedc15b7884fce7deb8b0346388837d6cfe"}, - {file = "bcrypt-4.3.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:79e70b8342a33b52b55d93b3a59223a844962bef479f6a0ea318ebbcadf71505"}, - {file = "bcrypt-4.3.0-cp39-abi3-win32.whl", hash = "sha256:b4d4e57f0a63fd0b358eb765063ff661328f69a04494427265950c71b992a39a"}, - {file = "bcrypt-4.3.0-cp39-abi3-win_amd64.whl", hash = "sha256:e53e074b120f2877a35cc6c736b8eb161377caae8925c17688bd46ba56daaa5b"}, - {file = "bcrypt-4.3.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c950d682f0952bafcceaf709761da0a32a942272fad381081b51096ffa46cea1"}, - {file = "bcrypt-4.3.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:107d53b5c67e0bbc3f03ebf5b030e0403d24dda980f8e244795335ba7b4a027d"}, - {file = "bcrypt-4.3.0-pp310-pypy310_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:b693dbb82b3c27a1604a3dff5bfc5418a7e6a781bb795288141e5f80cf3a3492"}, - {file = "bcrypt-4.3.0-pp310-pypy310_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:b6354d3760fcd31994a14c89659dee887f1351a06e5dac3c1142307172a79f90"}, - {file = "bcrypt-4.3.0-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:a839320bf27d474e52ef8cb16449bb2ce0ba03ca9f44daba6d93fa1d8828e48a"}, - {file = "bcrypt-4.3.0-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:bdc6a24e754a555d7316fa4774e64c6c3997d27ed2d1964d55920c7c227bc4ce"}, - {file = "bcrypt-4.3.0-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:55a935b8e9a1d2def0626c4269db3fcd26728cbff1e84f0341465c31c4ee56d8"}, - {file = "bcrypt-4.3.0-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:57967b7a28d855313a963aaea51bf6df89f833db4320da458e5b3c5ab6d4c938"}, - {file = "bcrypt-4.3.0.tar.gz", hash = "sha256:3a3fd2204178b6d2adcf09cb4f6426ffef54762577a7c9b54c159008cb288c18"}, + {file = "bcrypt-5.0.0-cp313-cp313t-macosx_10_12_universal2.whl", hash = "sha256:f3c08197f3039bec79cee59a606d62b96b16669cff3949f21e74796b6e3cd2be"}, + {file = "bcrypt-5.0.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:200af71bc25f22006f4069060c88ed36f8aa4ff7f53e67ff04d2ab3f1e79a5b2"}, + {file = "bcrypt-5.0.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:baade0a5657654c2984468efb7d6c110db87ea63ef5a4b54732e7e337253e44f"}, + {file = "bcrypt-5.0.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:c58b56cdfb03202b3bcc9fd8daee8e8e9b6d7e3163aa97c631dfcfcc24d36c86"}, + {file = "bcrypt-5.0.0-cp313-cp313t-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4bfd2a34de661f34d0bda43c3e4e79df586e4716ef401fe31ea39d69d581ef23"}, + {file = "bcrypt-5.0.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:ed2e1365e31fc73f1825fa830f1c8f8917ca1b3ca6185773b349c20fd606cec2"}, + {file = "bcrypt-5.0.0-cp313-cp313t-manylinux_2_34_aarch64.whl", hash = "sha256:83e787d7a84dbbfba6f250dd7a5efd689e935f03dd83b0f919d39349e1f23f83"}, + {file = "bcrypt-5.0.0-cp313-cp313t-manylinux_2_34_x86_64.whl", hash = "sha256:137c5156524328a24b9fac1cb5db0ba618bc97d11970b39184c1d87dc4bf1746"}, + {file = "bcrypt-5.0.0-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:38cac74101777a6a7d3b3e3cfefa57089b5ada650dce2baf0cbdd9d65db22a9e"}, + {file = "bcrypt-5.0.0-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:d8d65b564ec849643d9f7ea05c6d9f0cd7ca23bdd4ac0c2dbef1104ab504543d"}, + {file = "bcrypt-5.0.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:741449132f64b3524e95cd30e5cd3343006ce146088f074f31ab26b94e6c75ba"}, + {file = "bcrypt-5.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:212139484ab3207b1f0c00633d3be92fef3c5f0af17cad155679d03ff2ee1e41"}, + {file = "bcrypt-5.0.0-cp313-cp313t-win32.whl", hash = "sha256:9d52ed507c2488eddd6a95bccee4e808d3234fa78dd370e24bac65a21212b861"}, + {file = "bcrypt-5.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:f6984a24db30548fd39a44360532898c33528b74aedf81c26cf29c51ee47057e"}, + {file = "bcrypt-5.0.0-cp313-cp313t-win_arm64.whl", hash = "sha256:9fffdb387abe6aa775af36ef16f55e318dcda4194ddbf82007a6f21da29de8f5"}, + {file = "bcrypt-5.0.0-cp314-cp314t-macosx_10_12_universal2.whl", hash = "sha256:4870a52610537037adb382444fefd3706d96d663ac44cbb2f37e3919dca3d7ef"}, + {file = "bcrypt-5.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:48f753100931605686f74e27a7b49238122aa761a9aefe9373265b8b7aa43ea4"}, + {file = "bcrypt-5.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f70aadb7a809305226daedf75d90379c397b094755a710d7014b8b117df1ebbf"}, + {file = "bcrypt-5.0.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:744d3c6b164caa658adcb72cb8cc9ad9b4b75c7db507ab4bc2480474a51989da"}, + {file = "bcrypt-5.0.0-cp314-cp314t-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a28bc05039bdf3289d757f49d616ab3efe8cf40d8e8001ccdd621cd4f98f4fc9"}, + {file = "bcrypt-5.0.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:7f277a4b3390ab4bebe597800a90da0edae882c6196d3038a73adf446c4f969f"}, + {file = "bcrypt-5.0.0-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:79cfa161eda8d2ddf29acad370356b47f02387153b11d46042e93a0a95127493"}, + {file = "bcrypt-5.0.0-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:a5393eae5722bcef046a990b84dff02b954904c36a194f6cfc817d7dca6c6f0b"}, + {file = "bcrypt-5.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7f4c94dec1b5ab5d522750cb059bb9409ea8872d4494fd152b53cca99f1ddd8c"}, + {file = "bcrypt-5.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0cae4cb350934dfd74c020525eeae0a5f79257e8a201c0c176f4b84fdbf2a4b4"}, + {file = "bcrypt-5.0.0-cp314-cp314t-win32.whl", hash = "sha256:b17366316c654e1ad0306a6858e189fc835eca39f7eb2cafd6aaca8ce0c40a2e"}, + {file = "bcrypt-5.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:92864f54fb48b4c718fc92a32825d0e42265a627f956bc0361fe869f1adc3e7d"}, + {file = "bcrypt-5.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:dd19cf5184a90c873009244586396a6a884d591a5323f0e8a5922560718d4993"}, + {file = "bcrypt-5.0.0-cp38-abi3-macosx_10_12_universal2.whl", hash = "sha256:fc746432b951e92b58317af8e0ca746efe93e66555f1b40888865ef5bf56446b"}, + {file = "bcrypt-5.0.0-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c2388ca94ffee269b6038d48747f4ce8df0ffbea43f31abfa18ac72f0218effb"}, + {file = "bcrypt-5.0.0-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:560ddb6ec730386e7b3b26b8b4c88197aaed924430e7b74666a586ac997249ef"}, + {file = "bcrypt-5.0.0-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d79e5c65dcc9af213594d6f7f1fa2c98ad3fc10431e7aa53c176b441943efbdd"}, + {file = "bcrypt-5.0.0-cp38-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2b732e7d388fa22d48920baa267ba5d97cca38070b69c0e2d37087b381c681fd"}, + {file = "bcrypt-5.0.0-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:0c8e093ea2532601a6f686edbc2c6b2ec24131ff5c52f7610dd64fa4553b5464"}, + {file = "bcrypt-5.0.0-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:5b1589f4839a0899c146e8892efe320c0fa096568abd9b95593efac50a87cb75"}, + {file = "bcrypt-5.0.0-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:89042e61b5e808b67daf24a434d89bab164d4de1746b37a8d173b6b14f3db9ff"}, + {file = "bcrypt-5.0.0-cp38-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:e3cf5b2560c7b5a142286f69bde914494b6d8f901aaa71e453078388a50881c4"}, + {file = "bcrypt-5.0.0-cp38-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:f632fd56fc4e61564f78b46a2269153122db34988e78b6be8b32d28507b7eaeb"}, + {file = "bcrypt-5.0.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:801cad5ccb6b87d1b430f183269b94c24f248dddbbc5c1f78b6ed231743e001c"}, + {file = "bcrypt-5.0.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:3cf67a804fc66fc217e6914a5635000259fbbbb12e78a99488e4d5ba445a71eb"}, + {file = "bcrypt-5.0.0-cp38-abi3-win32.whl", hash = "sha256:3abeb543874b2c0524ff40c57a4e14e5d3a66ff33fb423529c88f180fd756538"}, + {file = "bcrypt-5.0.0-cp38-abi3-win_amd64.whl", hash = "sha256:35a77ec55b541e5e583eb3436ffbbf53b0ffa1fa16ca6782279daf95d146dcd9"}, + {file = "bcrypt-5.0.0-cp38-abi3-win_arm64.whl", hash = "sha256:cde08734f12c6a4e28dc6755cd11d3bdfea608d93d958fffbe95a7026ebe4980"}, + {file = "bcrypt-5.0.0-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:0c418ca99fd47e9c59a301744d63328f17798b5947b0f791e9af3c1c499c2d0a"}, + {file = "bcrypt-5.0.0-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ddb4e1500f6efdd402218ffe34d040a1196c072e07929b9820f363a1fd1f4191"}, + {file = "bcrypt-5.0.0-cp39-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7aeef54b60ceddb6f30ee3db090351ecf0d40ec6e2abf41430997407a46d2254"}, + {file = "bcrypt-5.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:f0ce778135f60799d89c9693b9b398819d15f1921ba15fe719acb3178215a7db"}, + {file = "bcrypt-5.0.0-cp39-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a71f70ee269671460b37a449f5ff26982a6f2ba493b3eabdd687b4bf35f875ac"}, + {file = "bcrypt-5.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f8429e1c410b4073944f03bd778a9e066e7fad723564a52ff91841d278dfc822"}, + {file = "bcrypt-5.0.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:edfcdcedd0d0f05850c52ba3127b1fce70b9f89e0fe5ff16517df7e81fa3cbb8"}, + {file = "bcrypt-5.0.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:611f0a17aa4a25a69362dcc299fda5c8a3d4f160e2abb3831041feb77393a14a"}, + {file = "bcrypt-5.0.0-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:db99dca3b1fdc3db87d7c57eac0c82281242d1eabf19dcb8a6b10eb29a2e72d1"}, + {file = "bcrypt-5.0.0-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:5feebf85a9cefda32966d8171f5db7e3ba964b77fdfe31919622256f80f9cf42"}, + {file = "bcrypt-5.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:3ca8a166b1140436e058298a34d88032ab62f15aae1c598580333dc21d27ef10"}, + {file = "bcrypt-5.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:61afc381250c3182d9078551e3ac3a41da14154fbff647ddf52a769f588c4172"}, + {file = "bcrypt-5.0.0-cp39-abi3-win32.whl", hash = "sha256:64d7ce196203e468c457c37ec22390f1a61c85c6f0b8160fd752940ccfb3a683"}, + {file = "bcrypt-5.0.0-cp39-abi3-win_amd64.whl", hash = "sha256:64ee8434b0da054d830fa8e89e1c8bf30061d539044a39524ff7dec90481e5c2"}, + {file = "bcrypt-5.0.0-cp39-abi3-win_arm64.whl", hash = "sha256:f2347d3534e76bf50bca5500989d6c1d05ed64b440408057a37673282c654927"}, + {file = "bcrypt-5.0.0-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:7edda91d5ab52b15636d9c30da87d2cc84f426c72b9dba7a9b4fe142ba11f534"}, + {file = "bcrypt-5.0.0-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:046ad6db88edb3c5ece4369af997938fb1c19d6a699b9c1b27b0db432faae4c4"}, + {file = "bcrypt-5.0.0-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:dcd58e2b3a908b5ecc9b9df2f0085592506ac2d5110786018ee5e160f28e0911"}, + {file = "bcrypt-5.0.0-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:6b8f520b61e8781efee73cba14e3e8c9556ccfb375623f4f97429544734545b4"}, + {file = "bcrypt-5.0.0.tar.gz", hash = "sha256:f748f7c2d6fd375cc93d3fba7ef4a9e3a092421b8dbf34d8d4dc06be9492dfdd"}, ] [package.extras] @@ -233,18 +237,18 @@ typecheck = ["mypy"] [[package]] name = "boto3" -version = "1.40.36" +version = "1.40.46" description = "The AWS SDK for Python" optional = false python-versions = ">=3.9" groups = ["main", "integration"] files = [ - {file = "boto3-1.40.36-py3-none-any.whl", hash = "sha256:d7c1fe033f491f560cd26022a9dcf28baf877ae854f33bc64fffd0df3b9c98be"}, - {file = "boto3-1.40.36.tar.gz", hash = "sha256:bfc1f3d5c4f5d12b8458406b8972f8794ac57e2da1ee441469e143bc0440a5c3"}, + {file = "boto3-1.40.46-py3-none-any.whl", hash = "sha256:0dfdc13992ceac1ef36a3ab0ac281cd4a45210a53181dc9a71afabfc1db889fe"}, + {file = "boto3-1.40.46.tar.gz", hash = "sha256:3676767a03d84544b01b3390a2bbdc3b98479223661e90f0ba0b22f4d3f0cb9f"}, ] [package.dependencies] -botocore = ">=1.40.36,<1.41.0" +botocore = ">=1.40.46,<1.41.0" jmespath = ">=0.7.1,<2.0.0" s3transfer = ">=0.14.0,<0.15.0" @@ -253,14 +257,14 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.40.36" +version = "1.40.46" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">=3.9" groups = ["main", "integration"] files = [ - {file = "botocore-1.40.36-py3-none-any.whl", hash = "sha256:d6edf75875e4013cb7078875a1d6c289afb4cc6675d99d80700c692d8d8e0b72"}, - {file = "botocore-1.40.36.tar.gz", hash = "sha256:93386a8dc54173267ddfc6cd8636c9171e021f7c032aa1df3af7de816e3df616"}, + {file = "botocore-1.40.46-py3-none-any.whl", hash = "sha256:d2c8e0d9ba804d6fd9b942db0aa3e6cfbdd9aab86581b472ee97809b6e5103e0"}, + {file = "botocore-1.40.46.tar.gz", hash = "sha256:4b0c0efdba788117ef365bf930c0be7300fa052e5e195ea3ed53ab278fc6d7b1"}, ] [package.dependencies] @@ -273,26 +277,26 @@ crt = ["awscrt (==0.27.6)"] [[package]] name = "cachetools" -version = "5.5.2" +version = "6.2.0" description = "Extensible memoizing collections and decorators" optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" groups = ["integration"] files = [ - {file = "cachetools-5.5.2-py3-none-any.whl", hash = "sha256:d26a22bcc62eb95c3beabd9f1ee5e820d3d2704fe2967cbe350e20c8ffcd3f0a"}, - {file = "cachetools-5.5.2.tar.gz", hash = "sha256:1a661caa9175d26759571b2e19580f9d6393969e5dfca11fdb1f947a23e640d4"}, + {file = "cachetools-6.2.0-py3-none-any.whl", hash = "sha256:1c76a8960c0041fcc21097e357f882197c79da0dbff766e7317890a65d7d8ba6"}, + {file = "cachetools-6.2.0.tar.gz", hash = "sha256:38b328c0889450f05f5e120f56ab68c8abaf424e1275522b138ffc93253f7e32"}, ] [[package]] name = "certifi" -version = "2025.8.3" +version = "2025.10.5" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.7" groups = ["main", "charm-libs", "integration"] files = [ - {file = "certifi-2025.8.3-py3-none-any.whl", hash = "sha256:f6c12493cfb1b06ba2ff328595af9350c65d6644968e5d3a2ffd78699af217a5"}, - {file = "certifi-2025.8.3.tar.gz", hash = "sha256:e564105f78ded564e3ae7c923924435e1daa7463faeab5bb932bc53ffae63407"}, + {file = "certifi-2025.10.5-py3-none-any.whl", hash = "sha256:0f212c2744a9bb6de0c56639a6f68afe01ecd92d91f14ae897c4fe7bbeeef0de"}, + {file = "certifi-2025.10.5.tar.gz", hash = "sha256:47c09d31ccf2acf0be3f701ea53595ee7e0b8fa08801c6624be771df09ae7b43"}, ] [[package]] @@ -515,14 +519,14 @@ files = [ [[package]] name = "cosl" -version = "1.1.0" +version = "1.3.0" description = "Utils for COS Lite charms" optional = false python-versions = ">=3.8" groups = ["charm-libs"] files = [ - {file = "cosl-1.1.0-py3-none-any.whl", hash = "sha256:e5313e6753db057b32fd41a493735b9eb152d38d1e2f688e54ef0b974ba99934"}, - {file = "cosl-1.1.0.tar.gz", hash = "sha256:7a04e32c95cdc2d556bb43517eaadf6fc177bc8449bd9359989a24056b34c9aa"}, + {file = "cosl-1.3.0-py3-none-any.whl", hash = "sha256:6b4f7c8201a58f9e5d593e290e89d91a89db54d5c413d25dfaa799915913db09"}, + {file = "cosl-1.3.0.tar.gz", hash = "sha256:d602b22e46dbd2369bd1c88aadf699b1296e8853d8dd39c1e3f63b6839df00fd"}, ] [package.dependencies] @@ -654,66 +658,66 @@ toml = ["tomli ; python_full_version <= \"3.11.0a6\""] [[package]] name = "cryptography" -version = "46.0.1" +version = "46.0.2" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false python-versions = "!=3.9.0,!=3.9.1,>=3.8" groups = ["charm-libs", "integration"] files = [ - {file = "cryptography-46.0.1-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:1cd6d50c1a8b79af1a6f703709d8973845f677c8e97b1268f5ff323d38ce8475"}, - {file = "cryptography-46.0.1-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0ff483716be32690c14636e54a1f6e2e1b7bf8e22ca50b989f88fa1b2d287080"}, - {file = "cryptography-46.0.1-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9873bf7c1f2a6330bdfe8621e7ce64b725784f9f0c3a6a55c3047af5849f920e"}, - {file = "cryptography-46.0.1-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:0dfb7c88d4462a0cfdd0d87a3c245a7bc3feb59de101f6ff88194f740f72eda6"}, - {file = "cryptography-46.0.1-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e22801b61613ebdebf7deb18b507919e107547a1d39a3b57f5f855032dd7cfb8"}, - {file = "cryptography-46.0.1-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:757af4f6341ce7a1e47c326ca2a81f41d236070217e5fbbad61bbfe299d55d28"}, - {file = "cryptography-46.0.1-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f7a24ea78de345cfa7f6a8d3bde8b242c7fac27f2bd78fa23474ca38dfaeeab9"}, - {file = "cryptography-46.0.1-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:9e8776dac9e660c22241b6587fae51a67b4b0147daa4d176b172c3ff768ad736"}, - {file = "cryptography-46.0.1-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:9f40642a140c0c8649987027867242b801486865277cbabc8c6059ddef16dc8b"}, - {file = "cryptography-46.0.1-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:449ef2b321bec7d97ef2c944173275ebdab78f3abdd005400cc409e27cd159ab"}, - {file = "cryptography-46.0.1-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2dd339ba3345b908fa3141ddba4025568fa6fd398eabce3ef72a29ac2d73ad75"}, - {file = "cryptography-46.0.1-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:7411c910fb2a412053cf33cfad0153ee20d27e256c6c3f14d7d7d1d9fec59fd5"}, - {file = "cryptography-46.0.1-cp311-abi3-win32.whl", hash = "sha256:cbb8e769d4cac884bb28e3ff620ef1001b75588a5c83c9c9f1fdc9afbe7f29b0"}, - {file = "cryptography-46.0.1-cp311-abi3-win_amd64.whl", hash = "sha256:92e8cfe8bd7dd86eac0a677499894862cd5cc2fd74de917daa881d00871ac8e7"}, - {file = "cryptography-46.0.1-cp311-abi3-win_arm64.whl", hash = "sha256:db5597a4c7353b2e5fb05a8e6cb74b56a4658a2b7bf3cb6b1821ae7e7fd6eaa0"}, - {file = "cryptography-46.0.1-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:4c49eda9a23019e11d32a0eb51a27b3e7ddedde91e099c0ac6373e3aacc0d2ee"}, - {file = "cryptography-46.0.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:9babb7818fdd71394e576cf26c5452df77a355eac1a27ddfa24096665a27f8fd"}, - {file = "cryptography-46.0.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9f2c4cc63be3ef43c0221861177cee5d14b505cd4d4599a89e2cd273c4d3542a"}, - {file = "cryptography-46.0.1-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:41c281a74df173876da1dc9a9b6953d387f06e3d3ed9284e3baae3ab3f40883a"}, - {file = "cryptography-46.0.1-cp314-cp314t-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0a17377fa52563d730248ba1f68185461fff36e8bc75d8787a7dd2e20a802b7a"}, - {file = "cryptography-46.0.1-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:0d1922d9280e08cde90b518a10cd66831f632960a8d08cb3418922d83fce6f12"}, - {file = "cryptography-46.0.1-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:af84e8e99f1a82cea149e253014ea9dc89f75b82c87bb6c7242203186f465129"}, - {file = "cryptography-46.0.1-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:ef648d2c690703501714588b2ba640facd50fd16548133b11b2859e8655a69da"}, - {file = "cryptography-46.0.1-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:e94eb5fa32a8a9f9bf991f424f002913e3dd7c699ef552db9b14ba6a76a6313b"}, - {file = "cryptography-46.0.1-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:534b96c0831855e29fc3b069b085fd185aa5353033631a585d5cd4dd5d40d657"}, - {file = "cryptography-46.0.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:f9b55038b5c6c47559aa33626d8ecd092f354e23de3c6975e4bb205df128a2a0"}, - {file = "cryptography-46.0.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ec13b7105117dbc9afd023300fb9954d72ca855c274fe563e72428ece10191c0"}, - {file = "cryptography-46.0.1-cp314-cp314t-win32.whl", hash = "sha256:504e464944f2c003a0785b81668fe23c06f3b037e9cb9f68a7c672246319f277"}, - {file = "cryptography-46.0.1-cp314-cp314t-win_amd64.whl", hash = "sha256:c52fded6383f7e20eaf70a60aeddd796b3677c3ad2922c801be330db62778e05"}, - {file = "cryptography-46.0.1-cp314-cp314t-win_arm64.whl", hash = "sha256:9495d78f52c804b5ec8878b5b8c7873aa8e63db9cd9ee387ff2db3fffe4df784"}, - {file = "cryptography-46.0.1-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:d84c40bdb8674c29fa192373498b6cb1e84f882889d21a471b45d1f868d8d44b"}, - {file = "cryptography-46.0.1-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:9ed64e5083fa806709e74fc5ea067dfef9090e5b7a2320a49be3c9df3583a2d8"}, - {file = "cryptography-46.0.1-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:341fb7a26bc9d6093c1b124b9f13acc283d2d51da440b98b55ab3f79f2522ead"}, - {file = "cryptography-46.0.1-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:6ef1488967e729948d424d09c94753d0167ce59afba8d0f6c07a22b629c557b2"}, - {file = "cryptography-46.0.1-cp38-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7823bc7cdf0b747ecfb096d004cc41573c2f5c7e3a29861603a2871b43d3ef32"}, - {file = "cryptography-46.0.1-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:f736ab8036796f5a119ff8211deda416f8c15ce03776db704a7a4e17381cb2ef"}, - {file = "cryptography-46.0.1-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:e46710a240a41d594953012213ea8ca398cd2448fbc5d0f1be8160b5511104a0"}, - {file = "cryptography-46.0.1-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:84ef1f145de5aee82ea2447224dc23f065ff4cc5791bb3b506615957a6ba8128"}, - {file = "cryptography-46.0.1-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:9394c7d5a7565ac5f7d9ba38b2617448eba384d7b107b262d63890079fad77ca"}, - {file = "cryptography-46.0.1-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:ed957044e368ed295257ae3d212b95456bd9756df490e1ac4538857f67531fcc"}, - {file = "cryptography-46.0.1-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:f7de12fa0eee6234de9a9ce0ffcfa6ce97361db7a50b09b65c63ac58e5f22fc7"}, - {file = "cryptography-46.0.1-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:7fab1187b6c6b2f11a326f33b036f7168f5b996aedd0c059f9738915e4e8f53a"}, - {file = "cryptography-46.0.1-cp38-abi3-win32.whl", hash = "sha256:45f790934ac1018adeba46a0f7289b2b8fe76ba774a88c7f1922213a56c98bc1"}, - {file = "cryptography-46.0.1-cp38-abi3-win_amd64.whl", hash = "sha256:7176a5ab56fac98d706921f6416a05e5aff7df0e4b91516f450f8627cda22af3"}, - {file = "cryptography-46.0.1-cp38-abi3-win_arm64.whl", hash = "sha256:efc9e51c3e595267ff84adf56e9b357db89ab2279d7e375ffcaf8f678606f3d9"}, - {file = "cryptography-46.0.1-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:fd4b5e2ee4e60425711ec65c33add4e7a626adef79d66f62ba0acfd493af282d"}, - {file = "cryptography-46.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:48948940d0ae00483e85e9154bb42997d0b77c21e43a77b7773c8c80de532ac5"}, - {file = "cryptography-46.0.1-pp311-pypy311_pp73-macosx_10_9_x86_64.whl", hash = "sha256:b9c79af2c3058430d911ff1a5b2b96bbfe8da47d5ed961639ce4681886614e70"}, - {file = "cryptography-46.0.1-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:0ca4be2af48c24df689a150d9cd37404f689e2968e247b6b8ff09bff5bcd786f"}, - {file = "cryptography-46.0.1-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:13e67c4d3fb8b6bc4ef778a7ccdd8df4cd15b4bcc18f4239c8440891a11245cc"}, - {file = "cryptography-46.0.1-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:15b5fd9358803b0d1cc42505a18d8bca81dabb35b5cfbfea1505092e13a9d96d"}, - {file = "cryptography-46.0.1-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:e34da95e29daf8a71cb2841fd55df0511539a6cdf33e6f77c1e95e44006b9b46"}, - {file = "cryptography-46.0.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:34f04b7311174469ab3ac2647469743720f8b6c8b046f238e5cb27905695eb2a"}, - {file = "cryptography-46.0.1.tar.gz", hash = "sha256:ed570874e88f213437f5cf758f9ef26cbfc3f336d889b1e592ee11283bb8d1c7"}, + {file = "cryptography-46.0.2-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:f3e32ab7dd1b1ef67b9232c4cf5e2ee4cd517d4316ea910acaaa9c5712a1c663"}, + {file = "cryptography-46.0.2-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1fd1a69086926b623ef8126b4c33d5399ce9e2f3fac07c9c734c2a4ec38b6d02"}, + {file = "cryptography-46.0.2-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bb7fb9cd44c2582aa5990cf61a4183e6f54eea3172e54963787ba47287edd135"}, + {file = "cryptography-46.0.2-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:9066cfd7f146f291869a9898b01df1c9b0e314bfa182cef432043f13fc462c92"}, + {file = "cryptography-46.0.2-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:97e83bf4f2f2c084d8dd792d13841d0a9b241643151686010866bbd076b19659"}, + {file = "cryptography-46.0.2-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:4a766d2a5d8127364fd936572c6e6757682fc5dfcbdba1632d4554943199f2fa"}, + {file = "cryptography-46.0.2-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:fab8f805e9675e61ed8538f192aad70500fa6afb33a8803932999b1049363a08"}, + {file = "cryptography-46.0.2-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:1e3b6428a3d56043bff0bb85b41c535734204e599c1c0977e1d0f261b02f3ad5"}, + {file = "cryptography-46.0.2-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:1a88634851d9b8de8bb53726f4300ab191d3b2f42595e2581a54b26aba71b7cc"}, + {file = "cryptography-46.0.2-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:be939b99d4e091eec9a2bcf41aaf8f351f312cd19ff74b5c83480f08a8a43e0b"}, + {file = "cryptography-46.0.2-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9f13b040649bc18e7eb37936009b24fd31ca095a5c647be8bb6aaf1761142bd1"}, + {file = "cryptography-46.0.2-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:9bdc25e4e01b261a8fda4e98618f1c9515febcecebc9566ddf4a70c63967043b"}, + {file = "cryptography-46.0.2-cp311-abi3-win32.whl", hash = "sha256:8b9bf67b11ef9e28f4d78ff88b04ed0929fcd0e4f70bb0f704cfc32a5c6311ee"}, + {file = "cryptography-46.0.2-cp311-abi3-win_amd64.whl", hash = "sha256:758cfc7f4c38c5c5274b55a57ef1910107436f4ae842478c4989abbd24bd5acb"}, + {file = "cryptography-46.0.2-cp311-abi3-win_arm64.whl", hash = "sha256:218abd64a2e72f8472c2102febb596793347a3e65fafbb4ad50519969da44470"}, + {file = "cryptography-46.0.2-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:bda55e8dbe8533937956c996beaa20266a8eca3570402e52ae52ed60de1faca8"}, + {file = "cryptography-46.0.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e7155c0b004e936d381b15425273aee1cebc94f879c0ce82b0d7fecbf755d53a"}, + {file = "cryptography-46.0.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a61c154cc5488272a6c4b86e8d5beff4639cdb173d75325ce464d723cda0052b"}, + {file = "cryptography-46.0.2-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:9ec3f2e2173f36a9679d3b06d3d01121ab9b57c979de1e6a244b98d51fea1b20"}, + {file = "cryptography-46.0.2-cp314-cp314t-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2fafb6aa24e702bbf74de4cb23bfa2c3beb7ab7683a299062b69724c92e0fa73"}, + {file = "cryptography-46.0.2-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:0c7ffe8c9b1fcbb07a26d7c9fa5e857c2fe80d72d7b9e0353dcf1d2180ae60ee"}, + {file = "cryptography-46.0.2-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:5840f05518caa86b09d23f8b9405a7b6d5400085aa14a72a98fdf5cf1568c0d2"}, + {file = "cryptography-46.0.2-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:27c53b4f6a682a1b645fbf1cd5058c72cf2f5aeba7d74314c36838c7cbc06e0f"}, + {file = "cryptography-46.0.2-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:512c0250065e0a6b286b2db4bbcc2e67d810acd53eb81733e71314340366279e"}, + {file = "cryptography-46.0.2-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:07c0eb6657c0e9cca5891f4e35081dbf985c8131825e21d99b4f440a8f496f36"}, + {file = "cryptography-46.0.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:48b983089378f50cba258f7f7aa28198c3f6e13e607eaf10472c26320332ca9a"}, + {file = "cryptography-46.0.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e6f6775eaaa08c0eec73e301f7592f4367ccde5e4e4df8e58320f2ebf161ea2c"}, + {file = "cryptography-46.0.2-cp314-cp314t-win32.whl", hash = "sha256:e8633996579961f9b5a3008683344c2558d38420029d3c0bc7ff77c17949a4e1"}, + {file = "cryptography-46.0.2-cp314-cp314t-win_amd64.whl", hash = "sha256:48c01988ecbb32979bb98731f5c2b2f79042a6c58cc9a319c8c2f9987c7f68f9"}, + {file = "cryptography-46.0.2-cp314-cp314t-win_arm64.whl", hash = "sha256:8e2ad4d1a5899b7caa3a450e33ee2734be7cc0689010964703a7c4bcc8dd4fd0"}, + {file = "cryptography-46.0.2-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:a08e7401a94c002e79dc3bc5231b6558cd4b2280ee525c4673f650a37e2c7685"}, + {file = "cryptography-46.0.2-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d30bc11d35743bf4ddf76674a0a369ec8a21f87aaa09b0661b04c5f6c46e8d7b"}, + {file = "cryptography-46.0.2-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bca3f0ce67e5a2a2cf524e86f44697c4323a86e0fd7ba857de1c30d52c11ede1"}, + {file = "cryptography-46.0.2-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ff798ad7a957a5021dcbab78dfff681f0cf15744d0e6af62bd6746984d9c9e9c"}, + {file = "cryptography-46.0.2-cp38-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:cb5e8daac840e8879407acbe689a174f5ebaf344a062f8918e526824eb5d97af"}, + {file = "cryptography-46.0.2-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:3f37aa12b2d91e157827d90ce78f6180f0c02319468a0aea86ab5a9566da644b"}, + {file = "cryptography-46.0.2-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:5e38f203160a48b93010b07493c15f2babb4e0f2319bbd001885adb3f3696d21"}, + {file = "cryptography-46.0.2-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:d19f5f48883752b5ab34cff9e2f7e4a7f216296f33714e77d1beb03d108632b6"}, + {file = "cryptography-46.0.2-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:04911b149eae142ccd8c9a68892a70c21613864afb47aba92d8c7ed9cc001023"}, + {file = "cryptography-46.0.2-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:8b16c1ede6a937c291d41176934268e4ccac2c6521c69d3f5961c5a1e11e039e"}, + {file = "cryptography-46.0.2-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:747b6f4a4a23d5a215aadd1d0b12233b4119c4313df83ab4137631d43672cc90"}, + {file = "cryptography-46.0.2-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6b275e398ab3a7905e168c036aad54b5969d63d3d9099a0a66cc147a3cc983be"}, + {file = "cryptography-46.0.2-cp38-abi3-win32.whl", hash = "sha256:0b507c8e033307e37af61cb9f7159b416173bdf5b41d11c4df2e499a1d8e007c"}, + {file = "cryptography-46.0.2-cp38-abi3-win_amd64.whl", hash = "sha256:f9b2dc7668418fb6f221e4bf701f716e05e8eadb4f1988a2487b11aedf8abe62"}, + {file = "cryptography-46.0.2-cp38-abi3-win_arm64.whl", hash = "sha256:91447f2b17e83c9e0c89f133119d83f94ce6e0fb55dd47da0a959316e6e9cfa1"}, + {file = "cryptography-46.0.2-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:f25a41f5b34b371a06dad3f01799706631331adc7d6c05253f5bca22068c7a34"}, + {file = "cryptography-46.0.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:e12b61e0b86611e3f4c1756686d9086c1d36e6fd15326f5658112ad1f1cc8807"}, + {file = "cryptography-46.0.2-pp311-pypy311_pp73-macosx_10_9_x86_64.whl", hash = "sha256:1d3b3edd145953832e09607986f2bd86f85d1dc9c48ced41808b18009d9f30e5"}, + {file = "cryptography-46.0.2-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:fe245cf4a73c20592f0f48da39748b3513db114465be78f0a36da847221bd1b4"}, + {file = "cryptography-46.0.2-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:2b9cad9cf71d0c45566624ff76654e9bae5f8a25970c250a26ccfc73f8553e2d"}, + {file = "cryptography-46.0.2-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:9bd26f2f75a925fdf5e0a446c0de2714f17819bf560b44b7480e4dd632ad6c46"}, + {file = "cryptography-46.0.2-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:7282d8f092b5be7172d6472f29b0631f39f18512a3642aefe52c3c0e0ccfad5a"}, + {file = "cryptography-46.0.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:c4b93af7920cdf80f71650769464ccf1fb49a4b56ae0024173c24c48eb6b1612"}, + {file = "cryptography-46.0.2.tar.gz", hash = "sha256:21b6fc8c71a3f9a604f028a329e5560009cc4a3a828bfea5fcba8eb7647d88fe"}, ] [package.dependencies] @@ -727,7 +731,7 @@ nox = ["nox[uv] (>=2024.4.15)"] pep8test = ["check-sdist", "click (>=8.0.1)", "mypy (>=1.14)", "ruff (>=0.11.11)"] sdist = ["build (>=1.0.0)"] ssh = ["bcrypt (>=3.1.5)"] -test = ["certifi (>=2024)", "cryptography-vectors (==46.0.1)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"] +test = ["certifi (>=2024)", "cryptography-vectors (==46.0.2)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"] test-randomorder = ["pytest-randomly"] [[package]] @@ -796,18 +800,18 @@ tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipyth [[package]] name = "google-auth" -version = "2.40.3" +version = "2.41.1" description = "Google Authentication Library" optional = false python-versions = ">=3.7" groups = ["integration"] files = [ - {file = "google_auth-2.40.3-py2.py3-none-any.whl", hash = "sha256:1370d4593e86213563547f97a92752fc658456fe4514c809544f330fed45a7ca"}, - {file = "google_auth-2.40.3.tar.gz", hash = "sha256:500c3a29adedeb36ea9cf24b8d10858e152f2412e3ca37829b3fa18e33d63b77"}, + {file = "google_auth-2.41.1-py2.py3-none-any.whl", hash = "sha256:754843be95575b9a19c604a848a41be03f7f2afd8c019f716dc1f51ee41c639d"}, + {file = "google_auth-2.41.1.tar.gz", hash = "sha256:b76b7b1f9e61f0cb7e88870d14f6a94aeef248959ef6992670efee37709cbfd2"}, ] [package.dependencies] -cachetools = ">=2.0.0,<6.0" +cachetools = ">=2.0.0,<7.0" pyasn1-modules = ">=0.2.1" rsa = ">=3.1.4,<5" @@ -818,7 +822,7 @@ pyjwt = ["cryptography (<39.0.0) ; python_version < \"3.8\"", "cryptography (>=3 pyopenssl = ["cryptography (<39.0.0) ; python_version < \"3.8\"", "cryptography (>=38.0.3)", "pyopenssl (>=20.0.0)"] reauth = ["pyu2f (>=0.1.5)"] requests = ["requests (>=2.20.0,<3.0.0)"] -testing = ["aiohttp (<3.10.0)", "aiohttp (>=3.6.2,<4.0.0)", "aioresponses", "cryptography (<39.0.0) ; python_version < \"3.8\"", "cryptography (>=38.0.3)", "flask", "freezegun", "grpcio", "mock", "oauth2client", "packaging", "pyjwt (>=2.0)", "pyopenssl (<24.3.0)", "pyopenssl (>=20.0.0)", "pytest", "pytest-asyncio", "pytest-cov", "pytest-localserver", "pyu2f (>=0.1.5)", "requests (>=2.20.0,<3.0.0)", "responses", "urllib3"] +testing = ["aiohttp (<3.10.0)", "aiohttp (>=3.6.2,<4.0.0)", "aioresponses", "cryptography (<39.0.0) ; python_version < \"3.8\"", "cryptography (<39.0.0) ; python_version < \"3.8\"", "cryptography (>=38.0.3)", "cryptography (>=38.0.3)", "flask", "freezegun", "grpcio", "mock", "oauth2client", "packaging", "pyjwt (>=2.0)", "pyopenssl (<24.3.0)", "pyopenssl (>=20.0.0)", "pytest", "pytest-asyncio", "pytest-cov", "pytest-localserver", "pyu2f (>=0.1.5)", "requests (>=2.20.0,<3.0.0)", "responses", "urllib3"] urllib3 = ["packaging", "urllib3"] [[package]] @@ -975,15 +979,15 @@ test-extra = ["curio", "ipython[test]", "jupyter_ai", "matplotlib (!=3.2.0)", "n [[package]] name = "ipython" -version = "9.5.0" +version = "9.6.0" description = "IPython: Productive Interactive Computing" optional = false python-versions = ">=3.11" groups = ["integration"] markers = "platform_python_implementation != \"PyPy\" and python_version >= \"3.14\"" files = [ - {file = "ipython-9.5.0-py3-none-any.whl", hash = "sha256:88369ffa1d5817d609120daa523a6da06d02518e582347c29f8451732a9c5e72"}, - {file = "ipython-9.5.0.tar.gz", hash = "sha256:129c44b941fe6d9b82d36fc7a7c18127ddb1d6f02f78f867f402e2e3adde3113"}, + {file = "ipython-9.6.0-py3-none-any.whl", hash = "sha256:5f77efafc886d2f023442479b8149e7d86547ad0a979e9da9f045d252f648196"}, + {file = "ipython-9.6.0.tar.gz", hash = "sha256:5603d6d5d356378be5043e69441a072b50a5b33b4503428c77b04cb8ce7bc731"}, ] [package.dependencies] @@ -1001,10 +1005,10 @@ traitlets = ">=5.13.0" [package.extras] all = ["ipython[doc,matplotlib,test,test-extra]"] black = ["black"] -doc = ["docrepr", "exceptiongroup", "intersphinx_registry", "ipykernel", "ipython[test]", "matplotlib", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "sphinx_toml (==0.0.4)", "typing_extensions"] -matplotlib = ["matplotlib"] +doc = ["docrepr", "exceptiongroup", "intersphinx_registry", "ipykernel", "ipython[matplotlib,test]", "setuptools (>=61.2)", "sphinx (>=1.3)", "sphinx-rtd-theme", "sphinx_toml (==0.0.4)", "typing_extensions"] +matplotlib = ["matplotlib (>3.7)"] test = ["packaging", "pytest", "pytest-asyncio", "testpath"] -test-extra = ["curio", "ipykernel", "ipython[test]", "jupyter_ai", "matplotlib (!=3.2.0)", "nbclient", "nbformat", "numpy (>=1.23)", "pandas", "trio"] +test-extra = ["curio", "ipykernel", "ipython[matplotlib]", "ipython[test]", "jupyter_ai", "nbclient", "nbformat", "numpy (>=1.25)", "pandas (>2.0)", "trio"] [[package]] name = "ipython-pygments-lexers" @@ -1223,73 +1227,101 @@ testing = ["falcon (>1.4.1)", "httpx", "mailman (>=3.3.1)", "pytest", "pytest-se [[package]] name = "markupsafe" -version = "3.0.2" +version = "3.0.3" description = "Safely add untrusted strings to HTML/XML markup." optional = false python-versions = ">=3.9" groups = ["main", "integration"] files = [ - {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8"}, - {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158"}, - {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579"}, - {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d"}, - {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb"}, - {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b"}, - {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c"}, - {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171"}, - {file = "MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50"}, - {file = "MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a"}, - {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d"}, - {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93"}, - {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832"}, - {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84"}, - {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca"}, - {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798"}, - {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e"}, - {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4"}, - {file = "MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d"}, - {file = "MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b"}, - {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf"}, - {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225"}, - {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028"}, - {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8"}, - {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c"}, - {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557"}, - {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22"}, - {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48"}, - {file = "MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30"}, - {file = "MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87"}, - {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd"}, - {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430"}, - {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094"}, - {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396"}, - {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79"}, - {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a"}, - {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca"}, - {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c"}, - {file = "MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1"}, - {file = "MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f"}, - {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c"}, - {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb"}, - {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c"}, - {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d"}, - {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe"}, - {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5"}, - {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a"}, - {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9"}, - {file = "MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6"}, - {file = "MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f"}, - {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a"}, - {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff"}, - {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13"}, - {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144"}, - {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29"}, - {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0"}, - {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0"}, - {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178"}, - {file = "MarkupSafe-3.0.2-cp39-cp39-win32.whl", hash = "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f"}, - {file = "MarkupSafe-3.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a"}, - {file = "markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0"}, + {file = "markupsafe-3.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559"}, + {file = "markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419"}, + {file = "markupsafe-3.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ba88449deb3de88bd40044603fafffb7bc2b055d626a330323a9ed736661695"}, + {file = "markupsafe-3.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591"}, + {file = "markupsafe-3.0.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0c0b3ade1c0b13b936d7970b1d37a57acde9199dc2aecc4c336773e1d86049c"}, + {file = "markupsafe-3.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f"}, + {file = "markupsafe-3.0.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d2ee202e79d8ed691ceebae8e0486bd9a2cd4794cec4824e1c99b6f5009502f6"}, + {file = "markupsafe-3.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:177b5253b2834fe3678cb4a5f0059808258584c559193998be2601324fdeafb1"}, + {file = "markupsafe-3.0.3-cp310-cp310-win32.whl", hash = "sha256:2a15a08b17dd94c53a1da0438822d70ebcd13f8c3a95abe3a9ef9f11a94830aa"}, + {file = "markupsafe-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:c4ffb7ebf07cfe8931028e3e4c85f0357459a3f9f9490886198848f4fa002ec8"}, + {file = "markupsafe-3.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:e2103a929dfa2fcaf9bb4e7c091983a49c9ac3b19c9061b6d5427dd7d14d81a1"}, + {file = "markupsafe-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad"}, + {file = "markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a"}, + {file = "markupsafe-3.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50"}, + {file = "markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf"}, + {file = "markupsafe-3.0.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f"}, + {file = "markupsafe-3.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a"}, + {file = "markupsafe-3.0.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115"}, + {file = "markupsafe-3.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a"}, + {file = "markupsafe-3.0.3-cp311-cp311-win32.whl", hash = "sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19"}, + {file = "markupsafe-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01"}, + {file = "markupsafe-3.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c"}, + {file = "markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e"}, + {file = "markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce"}, + {file = "markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d"}, + {file = "markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d"}, + {file = "markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a"}, + {file = "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b"}, + {file = "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f"}, + {file = "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b"}, + {file = "markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d"}, + {file = "markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c"}, + {file = "markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f"}, + {file = "markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795"}, + {file = "markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219"}, + {file = "markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6"}, + {file = "markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676"}, + {file = "markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9"}, + {file = "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1"}, + {file = "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc"}, + {file = "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12"}, + {file = "markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed"}, + {file = "markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5"}, + {file = "markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485"}, + {file = "markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73"}, + {file = "markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37"}, + {file = "markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19"}, + {file = "markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025"}, + {file = "markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6"}, + {file = "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f"}, + {file = "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb"}, + {file = "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009"}, + {file = "markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354"}, + {file = "markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218"}, + {file = "markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287"}, + {file = "markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe"}, + {file = "markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026"}, + {file = "markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737"}, + {file = "markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97"}, + {file = "markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d"}, + {file = "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda"}, + {file = "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf"}, + {file = "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe"}, + {file = "markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9"}, + {file = "markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581"}, + {file = "markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4"}, + {file = "markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab"}, + {file = "markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175"}, + {file = "markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634"}, + {file = "markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50"}, + {file = "markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e"}, + {file = "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5"}, + {file = "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523"}, + {file = "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc"}, + {file = "markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d"}, + {file = "markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9"}, + {file = "markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa"}, + {file = "markupsafe-3.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:15d939a21d546304880945ca1ecb8a039db6b4dc49b2c5a400387cdae6a62e26"}, + {file = "markupsafe-3.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f71a396b3bf33ecaa1626c255855702aca4d3d9fea5e051b41ac59a9c1c41edc"}, + {file = "markupsafe-3.0.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f4b68347f8c5eab4a13419215bdfd7f8c9b19f2b25520968adfad23eb0ce60c"}, + {file = "markupsafe-3.0.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e8fc20152abba6b83724d7ff268c249fa196d8259ff481f3b1476383f8f24e42"}, + {file = "markupsafe-3.0.3-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:949b8d66bc381ee8b007cd945914c721d9aba8e27f71959d750a46f7c282b20b"}, + {file = "markupsafe-3.0.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:3537e01efc9d4dccdf77221fb1cb3b8e1a38d5428920e0657ce299b20324d758"}, + {file = "markupsafe-3.0.3-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:591ae9f2a647529ca990bc681daebdd52c8791ff06c2bfa05b65163e28102ef2"}, + {file = "markupsafe-3.0.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a320721ab5a1aba0a233739394eb907f8c8da5c98c9181d1161e77a0c8e36f2d"}, + {file = "markupsafe-3.0.3-cp39-cp39-win32.whl", hash = "sha256:df2449253ef108a379b8b5d6b43f4b1a8e81a061d6537becd5582fba5f9196d7"}, + {file = "markupsafe-3.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:7c3fb7d25180895632e5d3148dbdc29ea38ccb7fd210aa27acbd1201a1902c6e"}, + {file = "markupsafe-3.0.3-cp39-cp39-win_arm64.whl", hash = "sha256:38664109c14ffc9e7437e86b4dceb442b0096dfe3541d7864d9cbe1da4cf36c8"}, + {file = "markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698"}, ] [[package]] @@ -1805,62 +1837,62 @@ files = [ [[package]] name = "pydantic" -version = "1.10.23" +version = "1.10.24" description = "Data validation and settings management using python type hints" optional = false python-versions = ">=3.7" groups = ["main", "charm-libs"] files = [ - {file = "pydantic-1.10.23-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1ce178e49a471ebf867451872a3403b89da6194bc2c9761e78ce22f619794d0d"}, - {file = "pydantic-1.10.23-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d5f2ab29db92a2b11c7cd49466f68858583bf227165c42a3fae2b50042a1ab51"}, - {file = "pydantic-1.10.23-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8e84ece91eb806586ffa4f92c149308cb07b0fa14a7e1204e18cde01aac283f7"}, - {file = "pydantic-1.10.23-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:757c8a2f459311bf277f6ddb4891222f69ba93fb301eee095c985fc7239d5afd"}, - {file = "pydantic-1.10.23-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:50b4726ab72a027fb69da865e849ae16107bdbea01ff1670daf4560e078a1606"}, - {file = "pydantic-1.10.23-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:4ed07c43d5c3f6f391eceeef7ead84c8c54083e0a1b5fa009302191c07775a73"}, - {file = "pydantic-1.10.23-cp310-cp310-win_amd64.whl", hash = "sha256:bc5547c3be3b8494a444adf3703c037bdf2170e30af802f5d7bb14a232698106"}, - {file = "pydantic-1.10.23-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b2e9d81546af42331248bbffde26a441631c8823515ebf328ee2ec04d771cd73"}, - {file = "pydantic-1.10.23-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7e13f39ce65232a2826d1c32a9e2c6f9ca5451d6e51c6e5ea9fdebc285fc2980"}, - {file = "pydantic-1.10.23-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:041308bdb4804f0b387b02f870ebdf4e86020de344a969020de853f5ea8d5508"}, - {file = "pydantic-1.10.23-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed01648e2a469e2c35984bab9ff5080648c53af3b8b98312e1d7823eacd33d77"}, - {file = "pydantic-1.10.23-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:18056741c9febebeb043798414099ada8d8e74cc47ec2059d7fbdc7d091d0e7b"}, - {file = "pydantic-1.10.23-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7411a18deef02a6b7825edb3930b9ab0251f7b131ebb1cb1ffe0aadf74d60c6d"}, - {file = "pydantic-1.10.23-cp311-cp311-win_amd64.whl", hash = "sha256:890213289bf40481a715b1d8b3e8a602af9e481d9f0e0b2b00dc375a12b0cfbb"}, - {file = "pydantic-1.10.23-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:136b6428b644691d0ee2a3a7de395d0d1b01ce6388b747bd371bb9ca65b4cc32"}, - {file = "pydantic-1.10.23-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b47c210416606b7c8e236c7546647500856eaba0d01564d5cddacb30d1b5daec"}, - {file = "pydantic-1.10.23-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c9c436e12d81b7c3d3208f66a5d35b401c8ec25fafc9bff446c77f1072ed5f5"}, - {file = "pydantic-1.10.23-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edba6ac9bd6040daf3e876c284257624171884011e0729d90b90f5fe11f7217d"}, - {file = "pydantic-1.10.23-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:101ae7dcd77c23003d4766bcf23e08cd3d012173379ad549bdb2c898855b2a57"}, - {file = "pydantic-1.10.23-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9b05416d8dcf36fd291348bba8f565d015fce4c594577d2ef5bc0c5ec8f54a29"}, - {file = "pydantic-1.10.23-cp312-cp312-win_amd64.whl", hash = "sha256:0f309b3dd80ed4d3487b1219c69dfd9036e51a863aeaa41a3b67497b81c4cb8f"}, - {file = "pydantic-1.10.23-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a6aa6881a18657fe66b9249e0572a9690ebc6f0b37c32872beb06bc51bff738f"}, - {file = "pydantic-1.10.23-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c57bfade74111335062c8ac830d5a14004742ff5b037c52c410d9e9011258bf5"}, - {file = "pydantic-1.10.23-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:723cb7f6aca0b471bac9d7dceb42d151d26aabdca655bd4190be3a7de008a054"}, - {file = "pydantic-1.10.23-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1b81db6c9108c3f6509c897fcdf842e5993d7233e9140a7f1c4dc1c2f85b0a8d"}, - {file = "pydantic-1.10.23-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:9e9544d07d96df6c6405b64462fb3122e5d0af46a1c4ddf94c180b17ac29f047"}, - {file = "pydantic-1.10.23-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4dff5e26a14424f4e6cf44cbd45861b458f31e37d316e92a78bf99ec6d1ef2ee"}, - {file = "pydantic-1.10.23-cp313-cp313-win_amd64.whl", hash = "sha256:633235236c9af4a16e7cf47be3ffab15445552613a122b44a8946868c2ace426"}, - {file = "pydantic-1.10.23-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:33fdacc8ffadaa0efecb1f8fec8d1ba8653c644f1c6a946c64f3e5e9563ac040"}, - {file = "pydantic-1.10.23-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d6c46c8055833bce5786c5e66cb30208db0bd5534f007890c3b76556d2f24d11"}, - {file = "pydantic-1.10.23-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0bed91a634855400f5c3b180999d0437a3b418b0170222fc8f6294aa2a08848a"}, - {file = "pydantic-1.10.23-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:e812b0f2a708595227aed10c636a54df4d02a1b3a5c90555df108a5e1244b2e9"}, - {file = "pydantic-1.10.23-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:8a52b2eedc25215c9cc1d96340d8364f8c8b6787a7cf2cc202d058e73e06cbef"}, - {file = "pydantic-1.10.23-cp37-cp37m-win_amd64.whl", hash = "sha256:38549feff6fac3c7a9e73fef6f8a2599300b10d71813ff329854449deb458aa6"}, - {file = "pydantic-1.10.23-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f71590dcd1ff354107cecc1c26b85406dd11e6f87d9b8416c5defd3cf4d54a51"}, - {file = "pydantic-1.10.23-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:46b3cd6fb8edf973380ddf1ac7387cca5f0624c07579bf9d15121dd77986b57c"}, - {file = "pydantic-1.10.23-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89e9a801a538d056fd91edf0d01dec02abde1b325e3c019c5c06d75fcca86929"}, - {file = "pydantic-1.10.23-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7ee7fa1a9bfa45aad5652001efa552a79a40f9ea7a1b11185685dd047895d3a8"}, - {file = "pydantic-1.10.23-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:0db70ae0e58eed1ffd01fbfdd23f6c6e5ae5e1bf2cd50dfeb0a2853656766e68"}, - {file = "pydantic-1.10.23-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:d037210949ac9e837360239d91a834cab3cf02e84cf295ea66c6ff73137f3723"}, - {file = "pydantic-1.10.23-cp38-cp38-win_amd64.whl", hash = "sha256:aa8d57384c6305febd9724b4f8de6860b5ba5821b7948dbbd0ddf733d50d7677"}, - {file = "pydantic-1.10.23-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:cdb4c8fdf8344b912285ca85c99d44433bd3d877f44b9ffcfc79cefedbc08869"}, - {file = "pydantic-1.10.23-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:144f739a617f2c12fa8d135d2efe26b9cf16033a44f2fe5400d7d0e9d9c90dca"}, - {file = "pydantic-1.10.23-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3449e59f27a42ba2c35c2e92aea345794696e5dddba3b5d88d123155eac4ee83"}, - {file = "pydantic-1.10.23-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10e9d8259fab4599498c3246703b84a5e9500240544bf49c54fc57996c6d093a"}, - {file = "pydantic-1.10.23-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:08b576239a4acbbfd35365b603cbee5fee6d3c56323abba54f0142e7ad6ff406"}, - {file = "pydantic-1.10.23-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:0f20e4dfe6413ee79fc1b4ac9c9f4112ff9d4cf44a19577592422d09774ee085"}, - {file = "pydantic-1.10.23-cp39-cp39-win_amd64.whl", hash = "sha256:45fcc5ed6adde6703f9f22f898362a087d1d140a337ecc4caca2477f4d735390"}, - {file = "pydantic-1.10.23-py3-none-any.whl", hash = "sha256:6294bb84565c294a3a6408c52b26a42803f258d5ebfdb3ae896cd7cccfa07211"}, - {file = "pydantic-1.10.23.tar.gz", hash = "sha256:81ee80fe4bd69236aeb65c8beeb5150655b8a49b946fce6664a720d6cf5ec717"}, + {file = "pydantic-1.10.24-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:eef07ea2fba12f9188cfa2c50cb3eaa6516b56c33e2a8cc3cd288b4190ee6c0c"}, + {file = "pydantic-1.10.24-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5a42033fac69b9f1f867ecc3a2159f0e94dceb1abfc509ad57e9e88d49774683"}, + {file = "pydantic-1.10.24-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c626596c1b95dc6d45f7129f10b6743fbb50f29d942d25a22b2ceead670c067d"}, + {file = "pydantic-1.10.24-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8057172868b0d98f95e6fcddcc5f75d01570e85c6308702dd2c50ea673bc197b"}, + {file = "pydantic-1.10.24-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:82f951210ebcdb778b1d93075af43adcd04e9ebfd4f44b1baa8eeb21fbd71e36"}, + {file = "pydantic-1.10.24-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b66e4892d8ae005f436a5c5f1519ecf837574d8414b1c93860fb3c13943d9b37"}, + {file = "pydantic-1.10.24-cp310-cp310-win_amd64.whl", hash = "sha256:50d9f8a207c07f347d4b34806dc576872000d9a60fd481ed9eb78ea8512e0666"}, + {file = "pydantic-1.10.24-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:70152291488f8d2bbcf2027b5c28c27724c78a7949c91b466d28ad75d6d12702"}, + {file = "pydantic-1.10.24-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:956b30638272c51c85caaff76851b60db4b339022c0ee6eca677c41e3646255b"}, + {file = "pydantic-1.10.24-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bed9d6eea5fabbc6978c42e947190c7bd628ddaff3b56fc963fe696c3710ccd6"}, + {file = "pydantic-1.10.24-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:af8e2b3648128b8cadb1a71e2f8092a6f42d4ca123fad7a8d7ce6db8938b1db3"}, + {file = "pydantic-1.10.24-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:076fff9da02ca716e4c8299c68512fdfbeac32fdefc9c160e6f80bdadca0993d"}, + {file = "pydantic-1.10.24-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8f2447ca88a7e14fd4d268857521fb37535c53a367b594fa2d7c2551af905993"}, + {file = "pydantic-1.10.24-cp311-cp311-win_amd64.whl", hash = "sha256:58d42a7c344882c00e3bb7c6c8c6f62db2e3aafa671f307271c45ad96e8ccf7a"}, + {file = "pydantic-1.10.24-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:17e7610119483f03954569c18d4de16f4e92f1585f20975414033ac2d4a96624"}, + {file = "pydantic-1.10.24-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e24435a9970dcb2b35648f2cf57505d4bd414fcca1a404c82e28d948183fe0a6"}, + {file = "pydantic-1.10.24-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a9e92b9c78d7f3cfa085c21c110e7000894446e24a836d006aabfc6ae3f1813"}, + {file = "pydantic-1.10.24-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef14dfa7c98b314a3e449e92df6f1479cafe74c626952f353ff0176b075070de"}, + {file = "pydantic-1.10.24-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52219b4e70c1db185cfd103a804e416384e1c8950168a2d4f385664c7c35d21a"}, + {file = "pydantic-1.10.24-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5ce0986799248082e9a5a026c9b5d2f9fa2e24d2afb9b0eace9104334a58fdc1"}, + {file = "pydantic-1.10.24-cp312-cp312-win_amd64.whl", hash = "sha256:874a78e4ed821258295a472e325eee7de3d91ba7a61d0639ce1b0367a3c63d4c"}, + {file = "pydantic-1.10.24-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:265788a1120285c4955f8b3d52b3ea6a52c7a74db097c4c13a4d3567f0c6df3c"}, + {file = "pydantic-1.10.24-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d255bebd927e5f1e026b32605684f7b6fc36a13e62b07cb97b29027b91657def"}, + {file = "pydantic-1.10.24-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d6e45dbc79a44e34c2c83ef1fcb56ff663040474dcf4dfc452db24a1de0f7574"}, + {file = "pydantic-1.10.24-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:af31565b12a7db5bfa5fe8c3a4f8fda4d32f5c2929998b1b241f1c22e9ab6e69"}, + {file = "pydantic-1.10.24-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:9c377fc30d9ca40dbff5fd79c5a5e1f0d6fff040fa47a18851bb6b0bd040a5d8"}, + {file = "pydantic-1.10.24-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b644d6f14b2ce617d6def21622f9ba73961a16b7dffdba7f6692e2f66fa05d00"}, + {file = "pydantic-1.10.24-cp313-cp313-win_amd64.whl", hash = "sha256:0cbbf306124ae41cc153fdc2559b37faa1bec9a23ef7b082c1756d1315ceffe6"}, + {file = "pydantic-1.10.24-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7c8bbad6037a87effe9f3739bdf39851add6e0f7e101d103a601c504892ffa70"}, + {file = "pydantic-1.10.24-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f154a8a46a0d950c055254f8f010ba07e742ac4404a3b6e281a31913ac45ccd0"}, + {file = "pydantic-1.10.24-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6f25d2f792afcd874cc8339c1da1cc52739f4f3d52993ed1f6c263ef2afadc47"}, + {file = "pydantic-1.10.24-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:49a6f0178063f15eaea6cbcb2dba04db0b73db9834bc7b1e1c4dbea28c7cd22f"}, + {file = "pydantic-1.10.24-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:bb3df10be3c7d264947180615819aeec0916f19650f2ba7309ed1fe546ead0d2"}, + {file = "pydantic-1.10.24-cp37-cp37m-win_amd64.whl", hash = "sha256:fa0ebefc169439267e4b4147c7d458908788367640509ed32c90a91a63ebb579"}, + {file = "pydantic-1.10.24-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2d1a5ef77efeb54def2695f2b8f4301aae8c7aa2b334bd15f61c18ef54317621"}, + {file = "pydantic-1.10.24-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:02f7a25e8949d8ca568e4bcef2ffed7881d7843286e7c3488bdd3b67f092059c"}, + {file = "pydantic-1.10.24-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5da2775712dda8b89e701ed2a72d5d81d23dbc6af84089da8a0f61a0be439c8c"}, + {file = "pydantic-1.10.24-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:75259be0558ca3af09192ad7b18557f2e9033ad4cbd48c252131f5292f6374fd"}, + {file = "pydantic-1.10.24-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:1a1ae996daa3d43c530b8d0bacc7e2d9cb55e3991f0e6b7cc2cb61a0fb9f6667"}, + {file = "pydantic-1.10.24-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:34109b0afa63b36eec2f2b115694e48ae5ee52f7d3c1baa0be36f80e586bda52"}, + {file = "pydantic-1.10.24-cp38-cp38-win_amd64.whl", hash = "sha256:4d7336bfcdb8cb58411e6b498772ba2cff84a2ce92f389bae3a8f1bb2c840c49"}, + {file = "pydantic-1.10.24-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:25fb9a69a21d711deb5acefdab9ff8fb49e6cc77fdd46d38217d433bff2e3de2"}, + {file = "pydantic-1.10.24-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6af36a8fb3072526b5b38d3f341b12d8f423188e7d185f130c0079fe02cdec7f"}, + {file = "pydantic-1.10.24-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fc35569dfd15d3b3fc06a22abee0a45fdde0784be644e650a8769cd0b2abd94"}, + {file = "pydantic-1.10.24-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fac7fbcb65171959973f3136d0792c3d1668bc01fd414738f0898b01f692f1b4"}, + {file = "pydantic-1.10.24-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:fc3f4a6544517380658b63b144c7d43d5276a343012913b7e5d18d9fba2f12bb"}, + {file = "pydantic-1.10.24-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:415c638ca5fd57b915a62dd38c18c8e0afe5adf5527be6f8ce16b4636b616816"}, + {file = "pydantic-1.10.24-cp39-cp39-win_amd64.whl", hash = "sha256:a5bf94042efbc6ab56b18a5921f426ebbeefc04f554a911d76029e7be9057d01"}, + {file = "pydantic-1.10.24-py3-none-any.whl", hash = "sha256:093768eba26db55a88b12f3073017e3fdee319ef60d3aef5c6c04a4e484db193"}, + {file = "pydantic-1.10.24.tar.gz", hash = "sha256:7e6d1af1bd3d2312079f28c9baf2aafb4a452a06b50717526e5ac562e37baa53"}, ] [package.dependencies] @@ -2019,14 +2051,14 @@ testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy [[package]] name = "pytest-operator" -version = "0.43.1" +version = "0.43.2" description = "Fixtures for Charmed Operators" optional = false python-versions = ">=3.8" groups = ["integration"] files = [ - {file = "pytest_operator-0.43.1-py3-none-any.whl", hash = "sha256:092e010fef884ea6166c3f71ec4ca717ed9158cf09de67f28e23cfdd780c46fa"}, - {file = "pytest_operator-0.43.1.tar.gz", hash = "sha256:fd76c7e34c56624176405b47f981de3fe0c3efb71d7875109483cc01f221be99"}, + {file = "pytest_operator-0.43.2-py3-none-any.whl", hash = "sha256:d7d01ffe35d14b75577fd80a07c34f0a9f4835cfc6d373b8e2f995bcb4146bda"}, + {file = "pytest_operator-0.43.2.tar.gz", hash = "sha256:3db34dcd9c114a2e41a9bc61da72daf1264e7644fd5b92e855f250cb337e01c3"}, ] [package.dependencies] @@ -2066,65 +2098,85 @@ files = [ [[package]] name = "pyyaml" -version = "6.0.2" +version = "6.0.3" description = "YAML parser and emitter for Python" optional = false python-versions = ">=3.8" groups = ["main", "charm-libs", "integration"] files = [ - {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, - {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, - {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"}, - {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"}, - {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"}, - {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"}, - {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"}, - {file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"}, - {file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"}, - {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"}, - {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"}, - {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"}, - {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"}, - {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"}, - {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"}, - {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"}, - {file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"}, - {file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"}, - {file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"}, - {file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"}, - {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"}, - {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"}, - {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"}, - {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"}, - {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"}, - {file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"}, - {file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"}, - {file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"}, - {file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"}, - {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"}, - {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"}, - {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"}, - {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"}, - {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"}, - {file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"}, - {file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"}, - {file = "PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a"}, - {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5"}, - {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d"}, - {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083"}, - {file = "PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706"}, - {file = "PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a"}, - {file = "PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff"}, - {file = "PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d"}, - {file = "PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f"}, - {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290"}, - {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12"}, - {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19"}, - {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e"}, - {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725"}, - {file = "PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631"}, - {file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"}, - {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, + {file = "PyYAML-6.0.3-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:c2514fceb77bc5e7a2f7adfaa1feb2fb311607c9cb518dbc378688ec73d8292f"}, + {file = "PyYAML-6.0.3-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c57bb8c96f6d1808c030b1687b9b5fb476abaa47f0db9c0101f5e9f394e97f4"}, + {file = "PyYAML-6.0.3-cp38-cp38-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:efd7b85f94a6f21e4932043973a7ba2613b059c4a000551892ac9f1d11f5baf3"}, + {file = "PyYAML-6.0.3-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:22ba7cfcad58ef3ecddc7ed1db3409af68d023b7f940da23c6c2a1890976eda6"}, + {file = "PyYAML-6.0.3-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:6344df0d5755a2c9a276d4473ae6b90647e216ab4757f8426893b5dd2ac3f369"}, + {file = "PyYAML-6.0.3-cp38-cp38-win32.whl", hash = "sha256:3ff07ec89bae51176c0549bc4c63aa6202991da2d9a6129d7aef7f1407d3f295"}, + {file = "PyYAML-6.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:5cf4e27da7e3fbed4d6c3d8e797387aaad68102272f8f9752883bc32d61cb87b"}, + {file = "pyyaml-6.0.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b"}, + {file = "pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956"}, + {file = "pyyaml-6.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8"}, + {file = "pyyaml-6.0.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198"}, + {file = "pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b"}, + {file = "pyyaml-6.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0"}, + {file = "pyyaml-6.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69"}, + {file = "pyyaml-6.0.3-cp310-cp310-win32.whl", hash = "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e"}, + {file = "pyyaml-6.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c"}, + {file = "pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e"}, + {file = "pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824"}, + {file = "pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c"}, + {file = "pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00"}, + {file = "pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d"}, + {file = "pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a"}, + {file = "pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4"}, + {file = "pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b"}, + {file = "pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf"}, + {file = "pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196"}, + {file = "pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0"}, + {file = "pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28"}, + {file = "pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c"}, + {file = "pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc"}, + {file = "pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e"}, + {file = "pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea"}, + {file = "pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5"}, + {file = "pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b"}, + {file = "pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd"}, + {file = "pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8"}, + {file = "pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1"}, + {file = "pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c"}, + {file = "pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5"}, + {file = "pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6"}, + {file = "pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6"}, + {file = "pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be"}, + {file = "pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26"}, + {file = "pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c"}, + {file = "pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb"}, + {file = "pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac"}, + {file = "pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310"}, + {file = "pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7"}, + {file = "pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788"}, + {file = "pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5"}, + {file = "pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764"}, + {file = "pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35"}, + {file = "pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac"}, + {file = "pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3"}, + {file = "pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3"}, + {file = "pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba"}, + {file = "pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c"}, + {file = "pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702"}, + {file = "pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c"}, + {file = "pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065"}, + {file = "pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65"}, + {file = "pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9"}, + {file = "pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b"}, + {file = "pyyaml-6.0.3-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:b865addae83924361678b652338317d1bd7e79b1f4596f96b96c77a5a34b34da"}, + {file = "pyyaml-6.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c3355370a2c156cffb25e876646f149d5d68f5e0a3ce86a5084dd0b64a994917"}, + {file = "pyyaml-6.0.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3c5677e12444c15717b902a5798264fa7909e41153cdf9ef7ad571b704a63dd9"}, + {file = "pyyaml-6.0.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5ed875a24292240029e4483f9d4a4b8a1ae08843b9c54f43fcc11e404532a8a5"}, + {file = "pyyaml-6.0.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0150219816b6a1fa26fb4699fb7daa9caf09eb1999f3b70fb6e786805e80375a"}, + {file = "pyyaml-6.0.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:fa160448684b4e94d80416c0fa4aac48967a969efe22931448d853ada8baf926"}, + {file = "pyyaml-6.0.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:27c0abcb4a5dac13684a37f76e701e054692a9b2d3064b70f5e4eb54810553d7"}, + {file = "pyyaml-6.0.3-cp39-cp39-win32.whl", hash = "sha256:1ebe39cb5fc479422b83de611d14e2c0d3bb2a18bbcb01f229ab3cfbd8fee7a0"}, + {file = "pyyaml-6.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:2e71d11abed7344e42a8849600193d15b6def118602c4c176f748e4583246007"}, + {file = "pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f"}, ] [[package]] @@ -2367,31 +2419,31 @@ pyasn1 = ">=0.1.3" [[package]] name = "ruff" -version = "0.13.1" +version = "0.13.3" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" groups = ["format"] files = [ - {file = "ruff-0.13.1-py3-none-linux_armv6l.whl", hash = "sha256:b2abff595cc3cbfa55e509d89439b5a09a6ee3c252d92020bd2de240836cf45b"}, - {file = "ruff-0.13.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:4ee9f4249bf7f8bb3984c41bfaf6a658162cdb1b22e3103eabc7dd1dc5579334"}, - {file = "ruff-0.13.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:5c5da4af5f6418c07d75e6f3224e08147441f5d1eac2e6ce10dcce5e616a3bae"}, - {file = "ruff-0.13.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:80524f84a01355a59a93cef98d804e2137639823bcee2931f5028e71134a954e"}, - {file = "ruff-0.13.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ff7f5ce8d7988767dd46a148192a14d0f48d1baea733f055d9064875c7d50389"}, - {file = "ruff-0.13.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c55d84715061f8b05469cdc9a446aa6c7294cd4bd55e86a89e572dba14374f8c"}, - {file = "ruff-0.13.1-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:ac57fed932d90fa1624c946dc67a0a3388d65a7edc7d2d8e4ca7bddaa789b3b0"}, - {file = "ruff-0.13.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c366a71d5b4f41f86a008694f7a0d75fe409ec298685ff72dc882f882d532e36"}, - {file = "ruff-0.13.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4ea9d1b5ad3e7a83ee8ebb1229c33e5fe771e833d6d3dcfca7b77d95b060d38"}, - {file = "ruff-0.13.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b0f70202996055b555d3d74b626406476cc692f37b13bac8828acff058c9966a"}, - {file = "ruff-0.13.1-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:f8cff7a105dad631085d9505b491db33848007d6b487c3c1979dd8d9b2963783"}, - {file = "ruff-0.13.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:9761e84255443316a258dd7dfbd9bfb59c756e52237ed42494917b2577697c6a"}, - {file = "ruff-0.13.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:3d376a88c3102ef228b102211ef4a6d13df330cb0f5ca56fdac04ccec2a99700"}, - {file = "ruff-0.13.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:cbefd60082b517a82c6ec8836989775ac05f8991715d228b3c1d86ccc7df7dae"}, - {file = "ruff-0.13.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:dd16b9a5a499fe73f3c2ef09a7885cb1d97058614d601809d37c422ed1525317"}, - {file = "ruff-0.13.1-py3-none-win32.whl", hash = "sha256:55e9efa692d7cb18580279f1fbb525146adc401f40735edf0aaeabd93099f9a0"}, - {file = "ruff-0.13.1-py3-none-win_amd64.whl", hash = "sha256:3a3fb595287ee556de947183489f636b9f76a72f0fa9c028bdcabf5bab2cc5e5"}, - {file = "ruff-0.13.1-py3-none-win_arm64.whl", hash = "sha256:c0bae9ffd92d54e03c2bf266f466da0a65e145f298ee5b5846ed435f6a00518a"}, - {file = "ruff-0.13.1.tar.gz", hash = "sha256:88074c3849087f153d4bb22e92243ad4c1b366d7055f98726bc19aa08dc12d51"}, + {file = "ruff-0.13.3-py3-none-linux_armv6l.whl", hash = "sha256:311860a4c5e19189c89d035638f500c1e191d283d0cc2f1600c8c80d6dcd430c"}, + {file = "ruff-0.13.3-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:2bdad6512fb666b40fcadb65e33add2b040fc18a24997d2e47fee7d66f7fcae2"}, + {file = "ruff-0.13.3-py3-none-macosx_11_0_arm64.whl", hash = "sha256:fc6fa4637284708d6ed4e5e970d52fc3b76a557d7b4e85a53013d9d201d93286"}, + {file = "ruff-0.13.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c9e6469864f94a98f412f20ea143d547e4c652f45e44f369d7b74ee78185838"}, + {file = "ruff-0.13.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5bf62b705f319476c78891e0e97e965b21db468b3c999086de8ffb0d40fd2822"}, + {file = "ruff-0.13.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78cc1abed87ce40cb07ee0667ce99dbc766c9f519eabfd948ed87295d8737c60"}, + {file = "ruff-0.13.3-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:4fb75e7c402d504f7a9a259e0442b96403fa4a7310ffe3588d11d7e170d2b1e3"}, + {file = "ruff-0.13.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:17b951f9d9afb39330b2bdd2dd144ce1c1335881c277837ac1b50bfd99985ed3"}, + {file = "ruff-0.13.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6052f8088728898e0a449f0dde8fafc7ed47e4d878168b211977e3e7e854f662"}, + {file = "ruff-0.13.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc742c50f4ba72ce2a3be362bd359aef7d0d302bf7637a6f942eaa763bd292af"}, + {file = "ruff-0.13.3-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:8e5640349493b378431637019366bbd73c927e515c9c1babfea3e932f5e68e1d"}, + {file = "ruff-0.13.3-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:6b139f638a80eae7073c691a5dd8d581e0ba319540be97c343d60fb12949c8d0"}, + {file = "ruff-0.13.3-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:6b547def0a40054825de7cfa341039ebdfa51f3d4bfa6a0772940ed351d2746c"}, + {file = "ruff-0.13.3-py3-none-musllinux_1_2_i686.whl", hash = "sha256:9cc48a3564423915c93573f1981d57d101e617839bef38504f85f3677b3a0a3e"}, + {file = "ruff-0.13.3-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:1a993b17ec03719c502881cb2d5f91771e8742f2ca6de740034433a97c561989"}, + {file = "ruff-0.13.3-py3-none-win32.whl", hash = "sha256:f14e0d1fe6460f07814d03c6e32e815bff411505178a1f539a38f6097d3e8ee3"}, + {file = "ruff-0.13.3-py3-none-win_amd64.whl", hash = "sha256:621e2e5812b691d4f244638d693e640f188bacbb9bc793ddd46837cea0503dd2"}, + {file = "ruff-0.13.3-py3-none-win_arm64.whl", hash = "sha256:9e9e9d699841eaf4c2c798fa783df2fabc680b72059a02ca0ed81c460bc58330"}, + {file = "ruff-0.13.3.tar.gz", hash = "sha256:5b0ba0db740eefdfbcce4299f49e9eaefc643d4d007749d77d047c2bab19908e"}, ] [[package]] @@ -2800,4 +2852,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = "^3.10" -content-hash = "b4a702830125a4ff438de0478f25a13d4377abc705c14db67ff95e62ad3ecd1b" +content-hash = "117b2816b51664ce6ba78ad600a4a3f4347e845b32bf93698644c7cef4b253f0" diff --git a/pyproject.toml b/pyproject.toml index 1c67cc7777..883a942c8d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,12 +8,12 @@ requires-poetry = ">=2.0.0" [tool.poetry.dependencies] python = "^3.10" ops = "^3.3.0" -boto3 = "^1.40.36" +boto3 = "^1.40.46" pgconnstr = "^1.0.1" requests = "^2.32.5" tenacity = "^9.1.2" psycopg2 = "^2.9.10" -pydantic = "^1.10.23" +pydantic = "^1.10.24" jinja2 = "^3.1.6" pysyncobj = "^0.3.14" psutil = "^7.1.0" @@ -40,7 +40,7 @@ opentelemetry-exporter-otlp-proto-http = "1.21.0" optional = true [tool.poetry.group.format.dependencies] -ruff = "^0.13.1" +ruff = "^0.13.3" [tool.poetry.group.lint] optional = true @@ -63,7 +63,7 @@ optional = true [tool.poetry.group.integration.dependencies] pytest = "^8.4.2" -pytest-operator = "^0.43.1" +pytest-operator = "^0.43.2" # renovate caret doesn't work: https://github.com/renovatebot/renovate/issues/26940 juju = "<=3.6.1.3" boto3 = "*" From 27c5225f2f2e70616abe5d005603d502500f5da6 Mon Sep 17 00:00:00 2001 From: Marcelo Henrique Neppel Date: Wed, 8 Oct 2025 04:08:59 -0300 Subject: [PATCH 110/112] DPE-8395 Remove old revision of Juju Secret (#1195) * Remove old revision of secret Signed-off-by: Marcelo Henrique Neppel * Remove secrets' old revision on upgrade Signed-off-by: Marcelo Henrique Neppel * Remove all previous secret revisions Signed-off-by: Marcelo Henrique Neppel * Handle https://github.com/juju/juju/issues/20782 Signed-off-by: Marcelo Henrique Neppel * Revert "Handle https://github.com/juju/juju/issues/20782" This reverts commit 0e29e0e18b4718e5470a297f7771292c38b2fd0a. Signed-off-by: Marcelo Henrique Neppel * Reapply "Handle https://github.com/juju/juju/issues/20782" This reverts commit 0e23c96e5f6abd35e1e7ceb617dca502e07711b5. Signed-off-by: Marcelo Henrique Neppel * Handle https://github.com/juju/juju/issues/20794 Signed-off-by: Marcelo Henrique Neppel * Consider all secrets created by the charm Signed-off-by: Marcelo Henrique Neppel * Check for secrets support Signed-off-by: Marcelo Henrique Neppel * Remove upgrade logic Signed-off-by: Marcelo Henrique Neppel --------- Signed-off-by: Marcelo Henrique Neppel --- src/charm.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/charm.py b/src/charm.py index 87c8b5edf1..e90658cca1 100755 --- a/src/charm.py +++ b/src/charm.py @@ -46,6 +46,7 @@ InstallEvent, LeaderElectedEvent, RelationDepartedEvent, + SecretRemoveEvent, StartEvent, ) from ops.framework import EventBase @@ -201,6 +202,7 @@ def __init__(self, *args): self.framework.observe(self.on.set_password_action, self._on_set_password) self.framework.observe(self.on.promote_to_primary_action, self._on_promote_to_primary) self.framework.observe(self.on.update_status, self._on_update_status) + self.framework.observe(self.on.secret_remove, self._on_secret_remove) self.cluster_name = self.app.name self._member_name = self.unit.name.replace("/", "-") @@ -435,6 +437,17 @@ def get_hostname_by_unit(self, _) -> str: # the underlying provider (LXD, MAAS, etc.), the unit IP is returned. return self._unit_ip + def _on_secret_remove(self, event: SecretRemoveEvent) -> None: + # A secret removal (entire removal, not just a revision removal) causes + # https://github.com/juju/juju/issues/20794. This check is to avoid the + # errors that would happen if we tried to remove the revision in that case + # (in the revision removal, the label is present). + if event.secret.label is None: + logger.debug("Secret with no label cannot be removed") + return + logger.debug(f"Removing secret with label {event.secret.label} revision {event.revision}") + event.remove_revision() + def _on_get_primary(self, event: ActionEvent) -> None: """Get primary instance.""" try: From 5870ee71c9f6a091772ed8ddb0d92903ca2d8adf Mon Sep 17 00:00:00 2001 From: Dragomir Penev <6687393+dragomirp@users.noreply.github.com> Date: Wed, 8 Oct 2025 20:09:05 +0300 Subject: [PATCH 111/112] DPE-8470 Temporary revert to Ops 2 (#1208) Issue: Some tests start failing ops v3 (especially self-healing). It requires investigation, but 14/stable is long waited for PS6 fixes. Solution: Temporary reverting ops to previous version 2 to release the next 14/stable --- poetry.lock | 23 ++++++++++++----------- pyproject.toml | 2 +- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/poetry.lock b/poetry.lock index 7bc843158c..f36cafd3f9 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.1.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.2.1 and should not be changed by hand. [[package]] name = "allure-pytest" @@ -152,7 +152,7 @@ description = "Base class for creating enumerated constants that are also subcla optional = false python-versions = ">=3.8.6,<3.11" groups = ["integration"] -markers = "python_version < \"3.11\"" +markers = "python_version == \"3.10\"" files = [ {file = "backports_strenum-1.3.1-py3-none-any.whl", hash = "sha256:cdcfe36dc897e2615dc793b7d3097f54d359918fc448754a517e6f23044ccf83"}, {file = "backports_strenum-1.3.1.tar.gz", hash = "sha256:77c52407342898497714f0596e86188bb7084f89063226f4ba66863482f42414"}, @@ -771,7 +771,7 @@ description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" groups = ["integration", "unit"] -markers = "python_version < \"3.11\"" +markers = "python_version == \"3.10\"" files = [ {file = "exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10"}, {file = "exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88"}, @@ -1471,24 +1471,25 @@ files = [ [[package]] name = "ops" -version = "3.3.0" +version = "2.23.1" description = "The Python library behind great charms" optional = false -python-versions = ">=3.10" +python-versions = ">=3.8" groups = ["main", "charm-libs"] files = [ - {file = "ops-3.3.0-py3-none-any.whl", hash = "sha256:4f03013dfe325690add181f989b571259cc4add8a8a5cafbd380ffcc2bbd7c1d"}, - {file = "ops-3.3.0.tar.gz", hash = "sha256:f89613def8b4a231218038ba5656927c522532e42b2dd8c06e12ff7a45bc647a"}, + {file = "ops-2.23.1-py3-none-any.whl", hash = "sha256:fdf58163beafd25180c12a4c7efaf1e76e5f8710508a97840c07055bb78b0c77"}, + {file = "ops-2.23.1.tar.gz", hash = "sha256:aecacd67ef7ca913f63f397e0330bfa93d70529a3ef71ed2d99e2bc232564ae3"}, ] [package.dependencies] +importlib-metadata = "*" opentelemetry-api = ">=1.0,<2.0" PyYAML = "==6.*" websocket-client = "==1.*" [package.extras] -testing = ["ops-scenario (==8.3.0)"] -tracing = ["ops-tracing (==3.3.0)"] +testing = ["ops-scenario (==7.23.1)"] +tracing = ["ops-tracing (==2.23.1)"] [[package]] name = "packaging" @@ -2553,7 +2554,7 @@ files = [ {file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"}, {file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"}, ] -markers = {integration = "python_version < \"3.11\"", unit = "python_full_version <= \"3.11.0a6\""} +markers = {integration = "python_version == \"3.10\"", unit = "python_full_version <= \"3.11.0a6\""} [[package]] name = "toposort" @@ -2852,4 +2853,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = "^3.10" -content-hash = "117b2816b51664ce6ba78ad600a4a3f4347e845b32bf93698644c7cef4b253f0" +content-hash = "baa7c29eec2b9a19ce6350827d94f88308306442d3b70f97e61163f48feb869b" diff --git a/pyproject.toml b/pyproject.toml index 883a942c8d..db6e28c366 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,7 @@ requires-poetry = ">=2.0.0" [tool.poetry.dependencies] python = "^3.10" -ops = "^3.3.0" +ops = "^2.23.1" boto3 = "^1.40.46" pgconnstr = "^1.0.1" requests = "^2.32.5" From cbd0b8c2fffbed149e3c4edbf3d12a9ab1d3950d Mon Sep 17 00:00:00 2001 From: Dragomir Penev Date: Thu, 9 Oct 2025 15:11:48 +0300 Subject: [PATCH 112/112] Revert self healing 3 --- tests/integration/ha_tests/test_self_healing_3.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/integration/ha_tests/test_self_healing_3.py b/tests/integration/ha_tests/test_self_healing_3.py index a5161ff2ac..312727d05d 100644 --- a/tests/integration/ha_tests/test_self_healing_3.py +++ b/tests/integration/ha_tests/test_self_healing_3.py @@ -7,7 +7,6 @@ from pytest_operator.plugin import OpsTest from tenacity import Retrying, stop_after_delay, wait_fixed -from .. import markers from ..helpers import ( APPLICATION_NAME, CHARM_BASE, @@ -163,7 +162,6 @@ async def test_forceful_restart_without_data_and_transaction_logs( @pytest.mark.abort_on_fail -@markers.amd64_only async def test_network_cut(ops_test: OpsTest, continuous_writes, primary_start_timeout): """Completely cut and restore network.""" # Locate primary unit. @@ -252,7 +250,6 @@ async def test_network_cut(ops_test: OpsTest, continuous_writes, primary_start_t @pytest.mark.abort_on_fail -@markers.amd64_only async def test_network_cut_without_ip_change( ops_test: OpsTest, continuous_writes, primary_start_timeout ):

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 ## HLD (High Level Design) The charm design leverages on the SNAP “[charmed-postgresql](https://snapcraft.io/charmed-postgresql)” which is deployed by Juju on the specified VM/MAAS/bare-metal machine based on Ubuntu Jammy/22.04. SNAP allows to run PostgreSQL service(s) in a secure and isolated environment ([strict confinement](https://ubuntu.com/blog/demystifying-snap-confinement)). The installed SNAP: -``` +```text > juju ssh postgresql/0 snap list charmed-postgresql Name Version Rev Tracking Publisher Notes charmed-postgresql 14.9 70 latest/stable dataplatformbot held @@ -28,7 +27,7 @@ Versions of all the components above are carefully chosen to fit functionality o The Charmed PostgreSQL unit consisting of a several services which are enabled/activated accordingly to the setup: -``` +```text > juju ssh postgresql/0 snap services charmed-postgresql Service Startup Current Notes charmed-postgresql.patroni enabled active - @@ -39,39 +38,42 @@ charmed-postgresql.prometheus-postgres-exporter enabled active - The `patroni` snap service is a main PostgreSQL instance which is normally up and running right after the charm deployment. -The `pgbackrest` snap service is a backup framework for PostgreSQL. It is disabled if [Backup](/t/9683) is not configured. - -The `prometheus-postgres-exporter` service is activated after the relation with [COS Monitoring](/t/10600) only. +The `pgbackrest` snap service is a backup framework for PostgreSQL. It is disabled if [Backup](/how-to/back-up-and-restore/create-a-backup) is not configured. -> **:information_source: Note:** it is possible to star/stop/restart snap services manually but it is NOT recommended to avoid a split brain with a charm state machine! Do it with a caution!!! +The `prometheus-postgres-exporter` service is activated after the relation with [COS Monitoring](/how-to/monitoring-cos/enable-monitoring) only. -> **:warning: Important:** all snap resources must be executed under the special user `snapd_daemon` only! +```{caution} +It is possible to start/stop/restart snap services manually, but it is **not** recommended in order to avoid a split brain with a charm state machine. +``` The snap "charmed-postgresql" also ships list of tools used by charm: * `charmed-postgresql.psql` (alias `psq`) - is PostgreSQL interactive terminal. * `charmed-postgresql.patronictl` - a tool to monitor and manage Patroni. * `charmed-postgresql.pgbackrest` - a tool to backup/restore PostgreSQL DB. - +```{warning} +All snap resources must be executed under the special user `snapd_daemon` only! +``` + ## Integrations ### PgBouncer [PgBouncer](http://www.pgbouncer.org/) is a lightweight connection pooler for PostgreSQL that provides transparent routing between your application and back-end PostgreSQL Servers. The "[PgBouncer](https://charmhub.io/pgbouncer)" is an independent charm "Charmed PostgreSQL" can be related with. -### TLS Certificates Operator +### TLS certificates operator -[TLS Certificates](https://charmhub.io/tls-certificates-operator) charm responsible for distributing certificates through relationship. Certificates are provided by the operator through Juju configs. For the playground deployments, the [self-signed operator](https://charmhub.io/self-signed-certificates) is available as well. +The [TLS Certificates](https://charmhub.io/tls-certificates-operator) charm is responsible for distributing certificates through relationship. Certificates are provided by the operator through Juju configs. For the playground deployments, the [self-signed operator](https://charmhub.io/self-signed-certificates) is available as well. -### S3 Integrator +### S3 integrator [S3 Integrator](https://charmhub.io/s3-integrator) is an integrator charm for providing S3 credentials to Charmed PostgreSQL which seek to access shared S3 data. Store the credentials centrally in the integrator charm and relate consumer charms as needed. -### Data Integrator +### Data integrator [Data Integrator](https://charmhub.io/data-integrator) charm is a solution to request DB credentials for non-native Juju applications. Not all applications implement a data_interfaces relation but allow setting credentials via config. Also, some of the applications are run outside of juju. This integrator charm allows receiving credentials which can be passed into application config directly without implementing juju-native relation. -### PostgreSQL Test App +### PostgreSQL test app The charm "[PostgreSQL Test App](https://charmhub.io/postgresql-test-app)" is a Canonical test application to validate the charm installation / functionality and perform the basic performance tests. @@ -81,51 +83,51 @@ GLAuth is a secure, easy-to-use and open-sourced LDAP server which provides capa ### Grafana -Grafana is an open-source visualization tools that allows to query, visualize, alert on, and visualize metrics from mixed datasources in configurable dashboards for observability. This charms is shipped with its own Grafana dashboard and supports integration with the [Grafana Operator](https://charmhub.io/grafana-k8s) to simplify observability. Please follow [COS Monitoring](/t/10600) setup. +Grafana is an open-source visualization tools that allows to query, visualize, alert on, and visualize metrics from mixed datasources in configurable dashboards for observability. This charms is shipped with its own Grafana dashboard and supports integration with the [Grafana Operator](https://charmhub.io/grafana-k8s) to simplify observability. Please follow [COS Monitoring](/how-to/monitoring-cos/enable-monitoring) setup. ### Loki -Loki is an open-source fully-featured logging system. This charms is shipped with support for the [Loki Operator](https://charmhub.io/loki-k8s) to collect the generated logs. Please follow [COS Monitoring](/t/10600) setup. +Loki is an open-source fully-featured logging system. This charms is shipped with support for the [Loki Operator](https://charmhub.io/loki-k8s) to collect the generated logs. Please follow [COS Monitoring](/how-to/monitoring-cos/enable-monitoring) setup. ### Prometheus -Prometheus is an open-source systems monitoring and alerting toolkit with a dimensional data model, flexible query language, efficient time series database and modern alerting approach. This charm is shipped with a Prometheus exporters, alerts and support for integrating with the [Prometheus Operator](https://charmhub.io/prometheus-k8s) to automatically scrape the targets. Please follow [COS Monitoring](/t/10600) setup. +Prometheus is an open-source systems monitoring and alerting toolkit with a dimensional data model, flexible query language, efficient time series database and modern alerting approach. This charm is shipped with a Prometheus exporters, alerts and support for integrating with the [Prometheus Operator](https://charmhub.io/prometheus-k8s) to automatically scrape the targets. Please follow [COS Monitoring](/how-to/monitoring-cos/enable-monitoring) setup. - ## LLD (Low Level Design) -Please check the charm state machines displayed on [workflow diagrams](/t/9305). The low-level logic is mostly common for both VM and K8s charms. +Please check the charm state machines displayed in the [workflow diagrams](https://discourse.charmhub.io/t/charmed-postgresql-k8s-explanations-charm-flowcharts/9305). The low-level logic is mostly common for both VM and K8s charms. -### Juju Events +### Juju events Accordingly to the [Juju SDK](https://juju.is/docs/sdk/event): “an event is a data structure that encapsulates part of the execution context of a charm”. For this charm, the following events are observed: -1. [on_install](https://juju.is/docs/sdk/install-event): install the snap "charmed-postgresql" and perform basic preparations to bootstrap the cluster on the first leader (or join the already configured cluster). -2. [leader-elected](https://juju.is/docs/sdk/leader-elected-event): generate all the secrets to bootstrap the cluster. -3. [leader-settings-changed](https://juju.is/docs/sdk/leader-settings-changed-event): Handle the leader settings changed event. -4. [start](https://juju.is/docs/sdk/start-event): Init/setting up the cluster node. -5. [config_changed](https://juju.is/docs/sdk/config-changed-event): usually fired in response to a configuration change using the GUI or CLI. Create and set default cluster and cluster-set names in the peer relation databag (on the leader only). -6. [update-status](https://juju.is/docs/sdk/update-status-event): Takes care of workload health checks. +1. [`on_install`](https://juju.is/docs/sdk/install-event): install the snap "charmed-postgresql" and perform basic preparations to bootstrap the cluster on the first leader (or join the already configured cluster). +2. [`leader-elected`](https://juju.is/docs/sdk/leader-elected-event): generate all the secrets to bootstrap the cluster. +3. [`leader-settings-changed`](https://juju.is/docs/sdk/leader-settings-changed-event): Handle the leader settings changed event. +4. [`start`](https://juju.is/docs/sdk/start-event): Init/setting up the cluster node. +5. [`config_changed`](https://juju.is/docs/sdk/config-changed-event): usually fired in response to a configuration change using the GUI or CLI. Create and set default cluster and cluster-set names in the peer relation databag (on the leader only). +6. [`update-status`](https://juju.is/docs/sdk/update-status-event): Takes care of workload health checks. -### Charm Code Overview +### Charm code overview -The "[src/charm.py](https://github.com/canonical/postgresql-operator/blob/main/src/charm.py)" is the default entry point for a charm and has the `PostgresqlOperatorCharm` Python class which inherits from CharmBase. +[`src/charm.py`](https://github.com/canonical/postgresql-operator/blob/main/src/charm.py) is the default entry point for a charm and has the `PostgresqlOperatorCharm` Python class which inherits from CharmBase. -CharmBase is the base class from which all Charms are formed, defined by [Ops](https://juju.is/docs/sdk/ops) (Python framework for developing charms). See more information in [Charm](https://juju.is/docs/sdk/constructs#heading--charm). +CharmBase is the base class from which all Charms are formed, defined by [Ops](https://juju.is/docs/sdk/ops) (Python framework for developing charms). See more information in [Charm](https://juju.is/docs/sdk/constructs#charm). The `__init__` method guarantees that the charm observes all events relevant to its operation and handles them. The VM and K8s charm flavors shares the codebase via [charm libraries](https://juju.is/docs/sdk/libraries) in [lib/charms/postgresql_k8s/v0/](https://github.com/canonical/postgresql-k8s-operator/blob/main/lib/charms/postgresql_k8s/v0/postgresql.py) (of K8s flavor of the charm!): -``` +```text > charmcraft list-lib postgresql-k8s Library name API Patch postgresql 0 12 postgresql_tls 0 7 -``` \ No newline at end of file +``` + diff --git a/docs/explanation/e-connection-pooling.md b/docs/explanation/connection-pooling.md similarity index 80% rename from docs/explanation/e-connection-pooling.md rename to docs/explanation/connection-pooling.md index a8d1a99300..13fc4152a8 100644 --- a/docs/explanation/e-connection-pooling.md +++ b/docs/explanation/connection-pooling.md @@ -10,8 +10,8 @@ A way to achieve this with Charmed PostgreSQL is by integrating with the [PgBoun If using PgBouncer is not enough to handle the connections load of your application, you can increase the amount of connections that PostgreSQL can open via the [`experimental_max_connections` config parameter](https://charmhub.io/postgresql/configurations#experimental_max_connections). -[note type="caution"] -**Disclaimer:** Each connection opened by PostgreSQL spawns a new process, which is resource-intensive. Use this option as a last resort. +```{caution} +Each connection opened by PostgreSQL spawns a new process, which is resource-intensive. Use this option as a last resort. -[Contact us](/t/11863) for more guidance about your use-case. -[/note] \ No newline at end of file +[Contact us](/reference/contacts) for more guidance for your use-case. +``` diff --git a/docs/explanation/index.md b/docs/explanation/index.md new file mode 100644 index 0000000000..3218d9baff --- /dev/null +++ b/docs/explanation/index.md @@ -0,0 +1,53 @@ +# Explanation + +Additional context about key concepts behind the PostgreSQL charm, including design and legacy information. + +## Core concepts and design +* [Architecture] +* [Interfaces and endpoints] +* [Juju] +* [Legacy charm] + +## Operational concepts +* [Units] +* [Users] +* [Roles] +* [Logs] +* [Connection pooling] + +## Security and hardening +* [Security hardening guide][Security] + * [Cryptography] + + + + +[Architecture]: /explanation/architecture +[Interfaces and endpoints]: /explanation/interfaces-and-endpoints +[Units]: /explanation/units +[Users]: /explanation/users +[Roles]: /explanation/roles +[Logs]: /explanation/logs +[Juju]: /explanation/juju +[Legacy charm]: /explanation/legacy-charm +[Connection pooling]: /explanation/connection-pooling +[Security]: /explanation/security/index +[Cryptography]: /explanation/security/cryptography + + +```{toctree} +:titlesonly: +:maxdepth: 2 +:glob: +:hidden: + +Architecture +Interfaces and endpoints +Juju +Legacy charm +Units +Users +Roles +Logs +Connection pooling +Security diff --git a/docs/explanation/e-interfaces-endpoints.md b/docs/explanation/interfaces-and-endpoints.md similarity index 74% rename from docs/explanation/e-interfaces-endpoints.md rename to docs/explanation/interfaces-and-endpoints.md index 798986ff23..842cb2f3cc 100644 --- a/docs/explanation/e-interfaces-endpoints.md +++ b/docs/explanation/interfaces-and-endpoints.md @@ -2,7 +2,9 @@ The charm supports modern `postgresql_client` and legacy `pgsql` interfaces (in a backward compatible mode). -**Note:** do NOT relate both modern and legacy interfaces simultaneously! +```{caution} +Do **not** relate both modern and legacy interfaces simultaneously! +``` ## Modern interfaces @@ -12,7 +14,7 @@ This charm provides modern ['postgresql_client' interface](https://github.com/ca Adding a relation is accomplished with `juju relate` (or `juju integrate` for Juju 3.x) via endpoint `database`. Example: -```shell +```text # Deploy Charmed PostgreSQL cluster with 3 nodes juju deploy postgresql -n 3 --channel 14 @@ -30,19 +32,25 @@ juju status --relations # > postgresql:database mycharm:database postgresql_client regular ``` -Find all details about default and extra DB user roles in "[Charm Users explanations](/t/10798)". +Find all details about default and extra DB user roles in "[Charm Users explanations](/explanation/users)". ## Legacy interfaces -**Note:** Legacy relations are deprecated and will be discontinued on future releases. Usage should be avoided. Check the legacy interfaces implementation limitations in the "[Legacy charm](/t/10690)" document. +```{note} +Legacy relations are deprecated and will be discontinued on future releases. Their usage should be avoided. + +Check the legacy interfaces implementation limitations in [](/explanation/legacy-charm)" +``` ### Legacy `pgsql` interface (`db` and `db-admin` endpoints): This charm supports legacy interface `pgsql` from the previous [PostgreSQL charm](https://launchpad.net/postgresql-charm): -```shell +```text juju relate postgresql:db mailman3-core juju relate postgresql:db-admin landscape-server ``` -**Note:** The endpoint `db-admin` provides the same legacy interface `pgsql` with PostgreSQL admin-level privileges. It is NOT recommended to use it from security point of view. \ No newline at end of file +```{note} +The endpoint `db-admin` provides the same legacy interface `pgsql` with PostgreSQL admin-level privileges. It is NOT recommended to use it due to security limitations. +``` diff --git a/docs/explanation/e-juju-details.md b/docs/explanation/juju.md similarity index 76% rename from docs/explanation/e-juju-details.md rename to docs/explanation/juju.md index a8554674eb..0a40ae0069 100644 --- a/docs/explanation/e-juju-details.md +++ b/docs/explanation/juju.md @@ -7,7 +7,7 @@ ## Compatibility with PostgreSQL Current stable releases of this charm can still be deployed on Juju 2.9. However, newer features are not supported. -> See the [Releases page](/t/11875) for more information about the minimum Juju version required to operate the features of each revision. +> See the [Releases page](/reference/releases) for more information about the minimum Juju version required to operate the features of each revision. Additionally, there are limitations regarding integrations with other charms. For example, integration with [modern TLS charms](https://charmhub.io/topics/security-with-x-509-certificates) requires Juju 3.x. @@ -17,7 +17,7 @@ As this charm documentation is written for Juju 3.x, users of 2.9.x will encount Breaking changes have been introduced in the Juju client between versions 2.9.x and 3.x. These are caused by the renaming and re-purposing of several commands - functionality and command options remain unchanged. -In the context of this guide, the pertinent changes are as follows: +In the context of this documentation, the pertinent changes are as follows: | v2.9.x | v3.x | | --- | --- | @@ -26,20 +26,23 @@ In the context of this guide, the pertinent changes are as follows: |`run`|`exec`| |`run-action --wait`|`run`| -See the [Juju 3.0 release notes](https://juju.is/docs/juju/roadmap#heading--juju-3-0-0---22-oct-2022) for the comprehensive list of changes. +See the [Juju 3.0 release notes](https://juju.is/docs/juju/roadmap#juju-3-0-0---22-oct-2022) for the comprehensive list of changes. Example substitutions: ### Juju 3.x: -```shell + +```text juju integrate postgresql:database postgresql-test-app juju run postgresql/leader get-password ``` ### Juju 2.9.x: -```shell + +```text juju relate postgresql:database postgresql-test-app juju run-action --wait postgresql/leader get-password ``` -> :tipping_hand_man: [The document based on OpenStack guide.](https://docs.openstack.org/charm-guide/latest/project/support-notes.html#breaking-changes-between-juju-2-9-x-and-3-x) \ No newline at end of file +> This document is based on [this OpenStack guide](https://docs.openstack.org/charm-guide/latest/project/support-notes.html#breaking-changes-between-juju-2-9-x-and-3-x) + diff --git a/docs/explanation/e-legacy-charm.md b/docs/explanation/legacy-charm.md similarity index 68% rename from docs/explanation/e-legacy-charm.md rename to docs/explanation/legacy-charm.md index 0f0c76cc0e..6a1afbde03 100644 --- a/docs/explanation/e-legacy-charm.md +++ b/docs/explanation/legacy-charm.md @@ -1,25 +1,27 @@ -## Charm types: "legacy" vs "modern" -There are [two types of charms](https://juju.is/docs/sdk/charm-taxonomy#heading--charm-types-by-generation) stored under the same charm name `postgresql`: +# Legacy charm -1. [Reactive](https://juju.is/docs/sdk/charm-taxonomy#heading--reactive) charm in the channel `latest/stable` (called `legacy`) +There are [two types of charms](https://juju.is/docs/sdk/charm-taxonomy#charm-types-by-generation) stored under the same charm name `postgresql`: + +1. [Reactive](https://juju.is/docs/sdk/charm-taxonomy#reactive) charm in the channel `latest/stable` (called `legacy`) 2. [Ops-based](https://juju.is/docs/sdk/ops) charm in the channel `14/stable` (called `modern`) -The legacy charm provided endpoints `db` and `db-admin` (for the interface `pgsql`). The modern charm provides old endpoints as well + new endpoint `database` (for the interface `postgresql_client`). Read more details about the available [endpoints/interfaces](https://charmhub.io/postgresql/docs/e-interfaces). +The legacy charm provided endpoints `db` and `db-admin` (for the interface `pgsql`). The modern charm provides old endpoints as well + new endpoint `database` (for the interface `postgresql_client`). Read more details about the available [endpoints/interfaces](/explanation/interfaces-and-endpoints). -**Note**: Please choose one endpoint to use. No need to relate all of them simultaneously! +```{note} +Choose one endpoint to use, rather than relating both simultaneously. +``` ## The default track "latest" vs "14" The [default track](https://docs.openstack.org/charm-guide/yoga/project/charm-delivery.html) has been switched from the `latest` to `14`. It is [to ensure](https://discourse.charmhub.io/t/request-switch-default-track-from-latest-to-14-for-postgresql-k8s-charms/10314) all new deployments use a modern codebase. We strongly advise against using the latest track due to its implicit nature. In doing so, a future charm upgrade may result in a PostgreSQL version incompatible with an integrated application. Track 14 guarantees PostgreSQL 14 deployment only. The track `latest` will be closed after all applications migrated from Reactive to Ops-based charm. - ## How to migrate from "legacy" to "modern" charm The "modern" charm provides temporary support for the legacy interfaces: * **quick try**: relate the current application with new charm using endpoint `db` (set the channel to `14/stable`). No extra changes necessary: -``` +```text postgresql: charm: postgresql channel: 14/stable @@ -27,21 +29,32 @@ The "modern" charm provides temporary support for the legacy interfaces: * **proper migration**: migrate the application to the new interface "[postgresql_client](https://github.com/canonical/charm-relation-interfaces)". The application will connect PostgreSQL using "[data_interfaces](https://charmhub.io/data-platform-libs/libraries/data_interfaces)" library from "[data-platform-libs](https://github.com/canonical/data-platform-libs/)" via endpoint `database`. -**Warning**: NO in-place upgrades possible! Reactive charm cannot be upgraded to Operator-framework-based one. To move DB data, the second/modern DB application must be launched nearby and data should be copied from "legacy" application to the "modern" one. Canonical Data Platform team is preparing copy&paste guide right now. Please [contact us](https://chat.charmhub.io/charmhub/channels/data-platform) if you need migration instructions. -**Note**: the `trust` option must be enabled if [ Role Based Access Control (RBAC)](https://kubernetes.io/docs/concepts/security/rbac-good-practices/) is in use on your Kubernetes. +```{warning} +**In-place upgrades are not supported for this case.** -## How to deploy old "legacy" postgresql charm +Reactive charms cannot be upgraded to an operator-framework-based version. To move database data, the new DB application must be launched nearby, and data should be copied from "legacy" application to the "modern" one. + +Please [contact us](https://chat.charmhub.io/charmhub/channels/data-platform) if you need migration instructions. +``` + +## How to deploy old "legacy" PostgreSQL charm Deploy the charm using the channel `latest/stable`: -``` +```text postgresql: charm: postgresql channel: latest/stable ``` -**Note**: remove Charm store prefix `cs:` from the bundle. Otherwise the modern charm will be chosen by Juju (due to the default track pointing to `14/stable` and not `latest/stable`). The common error message is: `cannot deploy application "postgresql": unknown option "..."`. +```{caution} +Remove the charm store prefix `cs:` from the bundle. + +Otherwise, the modern charm will be chosen by Juju (due to the default track pointing to `14/stable` and not `latest/stable`). + +A common error message is: `cannot deploy application "postgresql": unknown option "..."`. +``` ## Config options supported by modern charm @@ -53,15 +66,15 @@ Feel free to [contact us](https://chat.charmhub.io/charmhub/channels/data-platfo The legacy charm provided plugins/extensions enabling through the relation (interface `pgsql`). It is NOT supported by the modern charm (neither `pgsql` nor `postgresql_client` interfaces). Please enable the necessary extensions using appropriate `plugin_*_enable` [config option](https://charmhub.io/postgresql/configure) of the modern charm. After enabling the modern charm, it will provide plugins support for both `pgsql` and `postgresql_client` interfaces. -Please find the list of supported PostgreSQL [Extensions](/t/10946) by modern charm. +Please find the list of supported PostgreSQL [Extensions](/reference/plugins-extensions) by modern charm. -Feel free to [contact us](/t/11863) with a list of required extensions. +Feel free to [contact us](/reference/contacts) with a list of required extensions. ## Roles supported by modern charm -In the legacy charm, the user could request roles by setting the `roles` field to a comma separated list of desired roles. It is NOT supported by the modern charm implementation of the legacy `pgsql` interface. The same functionality is provided via the modern `postgresql_client` using "[extra-user-roles](/t/10798#extra-user-roles)". +In the legacy charm, the user could request roles by setting the `roles` field to a comma separated list of desired roles. It is NOT supported by the modern charm implementation of the legacy `pgsql` interface. The same functionality is provided via the modern `postgresql_client` using "[extra-user-roles](/explanation/users)". -For more information about migrating the new interface, see [this guide](/t/11865). +For more information about migrating the new interface, see [this guide](/how-to/development/integrate-with-your-charm). ## Supported PostgreSQL versions by modern charm @@ -73,7 +86,12 @@ Please [contact us](https://chat.charmhub.io/charmhub/channels/data-platform) if Currently, the charm supports architecture `amd64` (all revisions) and `arm64` (from revision 396+). -See the technical details in [Supported architectures](/t/11743). +See the technical details in [Supported architectures](/reference/system-requirements). + +## Workload artifacts + +The legacy charm used to deploy PostgreSQL from APT/Debian packages, +while the modern charm installs and operates PostgreSQL snap "[charmed-postgresql](https://snapcraft.io/charmed-postgresql)". Check more details in [the modern charm architecture](/explanation/architecture). ## How to report issues and contact authors @@ -81,4 +99,5 @@ The "legacy charm" (from `latest/stable`) is stored on [Launchpad](https://git.l The "modern charm" (from `14/stable`) is stored on [GitHub](https://github.com/canonical/postgresql-operator), here is the link to report [modern charm issues](https://github.com/canonical/postgresql-operator/issues/new/choose). -Do you have questions? [Contact us](/t/11863)! \ No newline at end of file +Do you have questions? [Contact us](/reference/contacts)! + diff --git a/docs/explanation/e-logs.md b/docs/explanation/logs.md similarity index 97% rename from docs/explanation/e-logs.md rename to docs/explanation/logs.md index 247501667e..3bf4b00997 100644 --- a/docs/explanation/e-logs.md +++ b/docs/explanation/logs.md @@ -1,12 +1,14 @@ # Logs -The list of all the charm components are well described in the "[Architecture](/t/11857)". +The list of all the charm components are well described in [](/explanation/architecture). + It is a dedicated section to highlight logs for each component to simplify troubleshooting. ## Core logs PostgreSQL and Patroni logs can be found in `/var/snap/charmed-postgresql/common/var/log/postgresql` and `/var/snap/charmed-postgresql/common/var/log/patroni` respectively: -```shell + +```text > ls -alh /var/snap/charmed-postgresql/common/var/log/postgresql total 20K drwxr-xr-x 2 snap_daemon root 4.0K Oct 11 15:09 . @@ -17,7 +19,8 @@ drwxr-xr-x 6 snap_daemon root 4.0K Oct 11 15:04 .. -rw------- 1 snap_daemon snap_daemon 817 Oct 11 15:08 postgresql-3_1508.log -rw------- 1 snap_daemon snap_daemon 0 Oct 11 15:09 postgresql-3_1509.log ``` -```shell + +```text > ls -alh /var/snap/charmed-postgresql/common/var/log/patroni/ total 28K drwxr-xr-x 2 snap_daemon root 4.0K Oct 11 15:29 . @@ -28,8 +31,10 @@ drwxr-xr-x 6 snap_daemon root 4.0K Oct 11 15:25 .. -rw-r--r-- 1 snap_daemon snap_daemon 584 Oct 11 15:27 patroni.log.3 -rw-r--r-- 1 snap_daemon snap_daemon 464 Oct 11 15:27 patroni.log.4 ``` + The PostgreSQL log naming convention is `postgresql-_.log`. The log message format is `