From b99d18375d64e8cb2bd64e5b8582710c890a8c9d Mon Sep 17 00:00:00 2001 From: Dima Tisnek Date: Thu, 17 Oct 2024 13:53:18 +0900 Subject: [PATCH 1/7] ci: use fail-fast, not continue-on-error --- .github/workflows/test.yaml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 276005f6a..a9d092f56 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -97,6 +97,7 @@ jobs: timeout-minutes: 150 runs-on: ubuntu-latest strategy: + fail-fast: false matrix: python: # We will reduce the workload to 3.10 to @@ -114,7 +115,6 @@ jobs: # * test_ssh # * ... # - "3.6/beta" - continue-on-error: false # ultimately fail a run if one of the matrix combinations fails steps: - name: Check out code uses: actions/checkout@v4 @@ -158,7 +158,6 @@ jobs: - name: Run integration # Force one single concurrent test run: tox -e integration - continue-on-error: true # don't fail early, let other matrix combinations get tested integration-quarantine: name: Quarantined Integration Tests @@ -166,6 +165,7 @@ jobs: timeout-minutes: 150 runs-on: ubuntu-latest strategy: + fail-fast: false matrix: python: - "3.10" @@ -174,7 +174,6 @@ jobs: - "3.3/stable" - "3.4/stable" - "3.5/stable" - continue-on-error: false # ultimately fail the run if one of the matrix combinations fails steps: - name: Check out code uses: actions/checkout@v3 @@ -189,4 +188,3 @@ jobs: juju-channel: ${{ matrix.juju }} - name: Run integration run: tox -e integration-quarantine - continue-on-error: true # don't fail early, let other matrix combinations get tested From 4546acb690a74c516d8ab65135d3940e59ad33e7 Mon Sep 17 00:00:00 2001 From: Dima Tisnek Date: Fri, 18 Oct 2024 14:00:58 +0900 Subject: [PATCH 2/7] ci: bump forgotten action --- .github/workflows/test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index a9d092f56..80e619340 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -176,7 +176,7 @@ jobs: - "3.5/stable" steps: - name: Check out code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup Python uses: actions/setup-python@v5 with: From 37278bd682a296dbb9c55f889710a4acd9724b0b Mon Sep 17 00:00:00 2001 From: Dima Tisnek Date: Fri, 18 Oct 2024 15:41:46 +0900 Subject: [PATCH 3/7] ci: conditionally skip tests that require newer Juju --- tests/integration/test_crossmodel.py | 4 ++++ tests/integration/test_model.py | 20 ++++++++++++++++++++ tests/integration/test_secrets.py | 24 ++++++++++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/tests/integration/test_crossmodel.py b/tests/integration/test_crossmodel.py index c7e02c9d5..4c742dd2a 100644 --- a/tests/integration/test_crossmodel.py +++ b/tests/integration/test_crossmodel.py @@ -98,6 +98,10 @@ async def test_remove_saas(): async def test_relate_with_offer(): # pytest.skip('Revise: intermittent problem with the remove_saas call') async with base.CleanModel() as model_1: + assert model_1._info + if str(model_1._info.agent_version) < "3.4.3": + pytest.skip("postgresql charm requires Juju 3.4.3 or later") + application = await model_1.deploy( 'postgresql', application_name='postgresql', diff --git a/tests/integration/test_model.py b/tests/integration/test_model.py index 7350681d9..c59d16ebc 100644 --- a/tests/integration/test_model.py +++ b/tests/integration/test_model.py @@ -217,6 +217,10 @@ async def test_deploy_bundle_with_storage_constraint(): bundle_path = INTEGRATION_TEST_DIR / 'bundle' / 'bundle-with-storage-constraint.yaml' async with base.CleanModel() as model: + assert model._info + if str(model._info.agent_version) < "3.4.3": + pytest.skip("bundle/postgresql charm requires Juju 3.4.3 or later") + await model.deploy(bundle_path) await wait_for_bundle(model, bundle_path) storage = await model.list_storage() @@ -237,6 +241,10 @@ async def test_deploy_local_charm(): @base.bootstrapped async def test_deploy_charm_assumes(): async with base.CleanModel() as model: + assert model._info + if str(model._info.agent_version) < "3.4.3": + pytest.skip("postgresql charm requires Juju 3.4.3 or later") + await model.deploy('postgresql', channel='14/edge') @@ -298,6 +306,10 @@ async def test_deploy_bundle(): @pytest.mark.bundle async def test_deploy_local_bundle_with_overlay_multi(): async with base.CleanModel() as model: + assert model._info + if str(model._info.agent_version) < "3.4.3": + pytest.skip("bundle/postgresql charm requires Juju 3.4.3 or later") + bundle_with_overlay_path = OVERLAYS_DIR / 'bundle-with-overlay-multi.yaml' await model.deploy(bundle_with_overlay_path) @@ -312,6 +324,10 @@ async def test_deploy_local_bundle_with_overlay_multi(): @pytest.mark.skip("Always fails -- investigate bundle charms") async def test_deploy_bundle_with_overlay_as_argument(): async with base.CleanModel() as model: + assert model._info + if str(model._info.agent_version) < "3.4.3": + pytest.skip("bundle/postgresql charm requires Juju 3.4.3 or later") + overlay_path = OVERLAYS_DIR / 'test-overlay.yaml' await model.deploy('juju-qa-bundle-test', overlays=[overlay_path]) @@ -381,6 +397,10 @@ async def test_deploy_local_charm_folder_symlink(): @base.bootstrapped async def test_deploy_from_ch_channel_revision_success(): async with base.CleanModel() as model: + assert model._info + if str(model._info.agent_version) < "3.4.3": + pytest.skip("postgresql charm requires Juju 3.4.3 or later") + # Ensure we're able to resolve charm these with channel and revision, # or channel without revision (note that revision requires channel, # but not vice versa) diff --git a/tests/integration/test_secrets.py b/tests/integration/test_secrets.py index 7893ba8fc..9465b4188 100644 --- a/tests/integration/test_secrets.py +++ b/tests/integration/test_secrets.py @@ -10,6 +10,10 @@ @pytest.mark.bundle async def test_add_secret(): async with base.CleanModel() as model: + assert model._info + if str(model._info.agent_version) < "3.3.0": + pytest.skip("Juju too old, need Secrets API v2") + secret = await model.add_secret(name='my-apitoken', data_args=['token=34ae35facd4']) assert secret.startswith('secret:') @@ -28,6 +32,10 @@ async def test_list_secrets(): charm_path = TESTS_DIR / 'charm-secret/charm-secret_ubuntu-22.04-amd64.charm' async with base.CleanModel() as model: + assert model._info + if str(model._info.agent_version) < "3.3.0": + pytest.skip("Juju too old, need Secrets API v2") + await model.deploy(str(charm_path)) assert 'charm-secret' in model.applications await model.wait_for_idle(status="active") @@ -42,6 +50,10 @@ async def test_list_secrets(): @pytest.mark.bundle async def test_update_secret(): async with base.CleanModel() as model: + assert model._info + if str(model._info.agent_version) < "3.3.0": + pytest.skip("Juju too old, need Secrets API v2") + secret = await model.add_secret(name='my-apitoken', data_args=['token=34ae35facd4']) assert secret.startswith('secret:') @@ -56,6 +68,10 @@ async def test_update_secret(): @pytest.mark.bundle async def test_remove_secret(): async with base.CleanModel() as model: + assert model._info + if str(model._info.agent_version) < "3.3.0": + pytest.skip("Juju too old, need Secrets API v2") + secret = await model.add_secret(name='my-apitoken', data_args=['token=34ae35facd4']) assert secret.startswith('secret:') @@ -69,6 +85,10 @@ async def test_remove_secret(): @pytest.mark.bundle async def test_grant_secret(): async with base.CleanModel() as model: + assert model._info + if str(model._info.agent_version) < "3.3.0": + pytest.skip("Juju too old, need Secrets API v2") + secret = await model.add_secret(name='my-apitoken', data_args=['token=34ae35facd4']) assert secret.startswith('secret:') @@ -81,6 +101,10 @@ async def test_grant_secret(): @pytest.mark.bundle async def test_revoke_secret(): async with base.CleanModel() as model: + assert model._info + if str(model._info.agent_version) < "3.3.0": + pytest.skip("Juju too old, need Secrets API v2") + secret = await model.add_secret(name='my-apitoken', data_args=['token=34ae35facd4']) assert secret.startswith('secret:') await model.revoke_secret('my-apitoken', 'ubuntu') From 087ead2d1d1a594fb519ca8a1ffec41003c91344 Mon Sep 17 00:00:00 2001 From: Dima Tisnek Date: Fri, 18 Oct 2024 17:03:06 +0900 Subject: [PATCH 4/7] ci: conditionally skip more tests that require newer Juju --- tests/integration/test_model.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/integration/test_model.py b/tests/integration/test_model.py index c59d16ebc..0264119cf 100644 --- a/tests/integration/test_model.py +++ b/tests/integration/test_model.py @@ -349,6 +349,10 @@ async def test_deploy_bundle_with_overlay_as_argument(): @pytest.mark.bundle async def test_deploy_bundle_with_multi_overlay_as_argument(): async with base.CleanModel() as model: + assert model._info + if str(model._info.agent_version) < "3.4.3": + pytest.skip("bundle/postgresql charm requires Juju 3.4.3 or later") + overlay_path = OVERLAYS_DIR / 'test-multi-overlay.yaml' await model.deploy('juju-qa-bundle-test', overlays=[overlay_path]) From 11c38a9f76ef4f764011c9ca7d6c4de6dd647a0f Mon Sep 17 00:00:00 2001 From: Dima Tisnek Date: Fri, 18 Oct 2024 17:11:29 +0900 Subject: [PATCH 5/7] fix: supported series order --- juju/utils.py | 28 ++++++++++++++++------------ tests/unit/test_utils.py | 2 +- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/juju/utils.py b/juju/utils.py index c4f4780ac..57d7c2bec 100644 --- a/juju/utils.py +++ b/juju/utils.py @@ -6,6 +6,7 @@ from collections import defaultdict from functools import partial from pathlib import Path +from typing import Sequence import base64 from pyasn1.type import univ, char from pyasn1.codec.der.encoder import encode @@ -457,27 +458,30 @@ def get_base_from_origin_or_channel(origin_or_channel, series=None): return client.Base(channel=channel, name=os_name) -def series_for_charm(requested_series, supported_series): +def series_for_charm(requested_series: str, supported_series: Sequence[str]): """series_for_charm takes a requested series and a list of series supported by a charm and returns the series which is relevant. If the requested series is empty, then the first supported series is used, otherwise the requested series is validated against the supported series. + + supported_series follows Juju API convention (best first): + - LTS in reverse chronological order + - then regular releases in reverse chronological order """ if len(supported_series) == 1 and supported_series[0] == '': raise JujuError("invalid supported series reported by charm : ['']") - if len(supported_series) == 0: - if requested_series == '': - raise JujuError("missing series") + if not supported_series and requested_series: return requested_series + elif not requested_series: + raise JujuError("missing series") + elif not requested_series: + # use the charm default + return supported_series[0] - # use the charm default - if requested_series == '': - return supported_series[-1] - - for s in supported_series: - if requested_series == s: - return requested_series - raise JujuError(f'requested series {requested_series} is not among the supported series {supported_series}') + if requested_series in supported_series: + return requested_series + else: + raise JujuError(f'requested series {requested_series} is not among the supported series {supported_series}') def user_requested(series_arg, supported_series, force): diff --git a/tests/unit/test_utils.py b/tests/unit/test_utils.py index 84f7d214a..9ab9e4dcf 100644 --- a/tests/unit/test_utils.py +++ b/tests/unit/test_utils.py @@ -49,7 +49,7 @@ def test_model_config(self): assert series_selector(model_config=mconf, supported_series=['jammy']) == 'jammy' def test_charm_list_series(self): - assert series_selector(supported_series=['focal', 'jammy']) == 'jammy' + assert series_selector(supported_series=["jammy", "focal"]) == "jammy" def test_return_lts(self): assert series_selector() == DEFAULT_SUPPORTED_LTS From 0586dac6c48641ffff2ae7fb89b45c2b578bd1c8 Mon Sep 17 00:00:00 2001 From: Dima Tisnek Date: Fri, 18 Oct 2024 17:16:48 +0900 Subject: [PATCH 6/7] ci: re-enable Juju 3.6 --- .github/workflows/test.yaml | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 80e619340..99e7951c9 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -109,12 +109,7 @@ jobs: - "3.3/stable" - "3.4/stable" - "3.5/stable" - # A bunch of tests fail with juju.errors.JujuError: base: ubuntu@15.04/stable - # * test_subordinate_units - # * test_destroy_unit - # * test_ssh - # * ... - # - "3.6/beta" + - "3.6/beta" steps: - name: Check out code uses: actions/checkout@v4 @@ -174,6 +169,7 @@ jobs: - "3.3/stable" - "3.4/stable" - "3.5/stable" + - "3.6/beta" steps: - name: Check out code uses: actions/checkout@v4 From 807a6704028a73648e6f9bd9d0923e7f8020cc47 Mon Sep 17 00:00:00 2001 From: Dima Tisnek Date: Tue, 22 Oct 2024 15:30:07 +0900 Subject: [PATCH 7/7] chore: dump all traffic --- juju/client/connection.py | 1 + 1 file changed, 1 insertion(+) diff --git a/juju/client/connection.py b/juju/client/connection.py index f0d10597d..cc86c68f6 100644 --- a/juju/client/connection.py +++ b/juju/client/connection.py @@ -549,6 +549,7 @@ async def rpc(self, msg, encoder=None): log.error('RPC: Automatic reconnect failed') raise result = await self._recv(msg['request-id']) + log.warning("DUMP\n%s\n%s\n", outgoing, result) log.debug('connection id : {} <--- {}'.format(id(self), result)) if not result: