diff --git a/poetry.lock b/poetry.lock index 62816cf3..244dd55d 100644 --- a/poetry.lock +++ b/poetry.lock @@ -135,17 +135,17 @@ uvloop = ["uvloop (>=0.15.2)"] [[package]] name = "boto3" -version = "1.35.16" +version = "1.35.19" description = "The AWS SDK for Python" optional = false python-versions = ">=3.8" files = [ - {file = "boto3-1.35.16-py3-none-any.whl", hash = "sha256:9c5b0ce4a25bb78d659478d1c552f1dbb7ff275aab3263bb41cdbef8bca28693"}, - {file = "boto3-1.35.16.tar.gz", hash = "sha256:9b96c210678cf430b16b49dee87db30f46044602bb9a605a465e1900f468a43f"}, + {file = "boto3-1.35.19-py3-none-any.whl", hash = "sha256:84b3fe1727945bc3cada832d969ddb3dc0d08fce1677064ca8bdc13a89c1a143"}, + {file = "boto3-1.35.19.tar.gz", hash = "sha256:9979fe674780a0b7100eae9156d74ee374cd1638a9f61c77277e3ce712f3e496"}, ] [package.dependencies] -botocore = ">=1.35.16,<1.36.0" +botocore = ">=1.35.19,<1.36.0" jmespath = ">=0.7.1,<2.0.0" s3transfer = ">=0.10.0,<0.11.0" @@ -154,13 +154,13 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "boto3-stubs" -version = "1.35.16" -description = "Type annotations for boto3 1.35.16 generated with mypy-boto3-builder 8.0.1" +version = "1.35.19" +description = "Type annotations for boto3 1.35.19 generated with mypy-boto3-builder 8.0.1" optional = false python-versions = ">=3.8" files = [ - {file = "boto3_stubs-1.35.16-py3-none-any.whl", hash = "sha256:7dee283bd3a5272fe759a43e22fc0658b5ee35679cb4932e33ad0c602f559b61"}, - {file = "boto3_stubs-1.35.16.tar.gz", hash = "sha256:39b77ede4914704c2ee5e97fd3486d6af26745cbedf6bc06f33c0ffadd0fb2c9"}, + {file = "boto3_stubs-1.35.19-py3-none-any.whl", hash = "sha256:6adace32995ae7b88675cf0bbde3b4f31876cbf57520db1ec1f392ac32660b4c"}, + {file = "boto3_stubs-1.35.19.tar.gz", hash = "sha256:c5842cd82d4a1570613f178831c2b6d1b60f511b87f56cc014f2a216c03ecf5a"}, ] [package.dependencies] @@ -212,7 +212,7 @@ bedrock-agent = ["mypy-boto3-bedrock-agent (>=1.35.0,<1.36.0)"] bedrock-agent-runtime = ["mypy-boto3-bedrock-agent-runtime (>=1.35.0,<1.36.0)"] bedrock-runtime = ["mypy-boto3-bedrock-runtime (>=1.35.0,<1.36.0)"] billingconductor = ["mypy-boto3-billingconductor (>=1.35.0,<1.36.0)"] -boto3 = ["boto3 (==1.35.16)", "botocore (==1.35.16)"] +boto3 = ["boto3 (==1.35.19)", "botocore (==1.35.19)"] braket = ["mypy-boto3-braket (>=1.35.0,<1.36.0)"] budgets = ["mypy-boto3-budgets (>=1.35.0,<1.36.0)"] ce = ["mypy-boto3-ce (>=1.35.0,<1.36.0)"] @@ -562,13 +562,13 @@ xray = ["mypy-boto3-xray (>=1.35.0,<1.36.0)"] [[package]] name = "botocore" -version = "1.35.16" +version = "1.35.19" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">=3.8" files = [ - {file = "botocore-1.35.16-py3-none-any.whl", hash = "sha256:3564a980d95ff2861a6ca74313173d8778aa659125c63cf49c93ad23896c63b1"}, - {file = "botocore-1.35.16.tar.gz", hash = "sha256:1b48c94e8a4bbe23143f3d1c21a32b9ffc7476b651ef42371ab45d678f6dbfbc"}, + {file = "botocore-1.35.19-py3-none-any.whl", hash = "sha256:c83f7f0cacfe7c19b109b363ebfa8736e570d24922f16ed371681f58ebab44a9"}, + {file = "botocore-1.35.19.tar.gz", hash = "sha256:42d6d8db7250cbd7899f786f9861e02cab17dc238f64d6acb976098ed9809625"}, ] [package.dependencies] @@ -581,13 +581,13 @@ crt = ["awscrt (==0.21.5)"] [[package]] name = "botocore-stubs" -version = "1.35.16" +version = "1.35.19" description = "Type annotations and code completion for botocore" optional = false python-versions = ">=3.8" files = [ - {file = "botocore_stubs-1.35.16-py3-none-any.whl", hash = "sha256:7181c2edf169a4dc89f9932cbd8eb82fb6b54ac59784685058f4c6ad180fce92"}, - {file = "botocore_stubs-1.35.16.tar.gz", hash = "sha256:bfdabe90607dbcb923042da5886eecdcc5839e7c976ccc2ccbd091dc690a633f"}, + {file = "botocore_stubs-1.35.19-py3-none-any.whl", hash = "sha256:91d258c78de2b7359ad6633ee8bc6d4f8d9b746da4d5726f986551e426699fdd"}, + {file = "botocore_stubs-1.35.19.tar.gz", hash = "sha256:ff95ead38bcaf614b0f24c42205441cf04a8cbe22c74bc73f28b2c0a6a0556e0"}, ] [package.dependencies] @@ -840,13 +840,13 @@ files = [ [[package]] name = "cosl" -version = "0.0.32" +version = "0.0.33" description = "Utils for COS Lite charms" optional = false python-versions = ">=3.8" files = [ - {file = "cosl-0.0.32-py3-none-any.whl", hash = "sha256:7c5acc5d45d4affe24db743a9b5a78137c4b8d8ee2a16996550e9cc57c9747d3"}, - {file = "cosl-0.0.32.tar.gz", hash = "sha256:c9b1eb11a7ef87be04c43bd824ffb911124279666224169a3cb492a890b9e97c"}, + {file = "cosl-0.0.33-py3-none-any.whl", hash = "sha256:c8a522af9829e6058d08afc28038bde7b2ccbab6a034a9d609ee6f683e589cef"}, + {file = "cosl-0.0.33.tar.gz", hash = "sha256:00d682049976737b0012718c071f15f2e492c1b71e231f8b7e3c74da365d9814"}, ] [package.dependencies] @@ -1131,15 +1131,18 @@ parser = ["pyhcl (>=0.4.4,<0.5.0)"] [[package]] name = "idna" -version = "3.8" +version = "3.10" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.6" files = [ - {file = "idna-3.8-py3-none-any.whl", hash = "sha256:050b4e5baadcd44d760cedbd2b8e639f2ff89bbc7a5730fcc662954303377aac"}, - {file = "idna-3.8.tar.gz", hash = "sha256:d838c2c0ed6fced7693d5e8ab8e734d5f8fda53a039c0164afb0b82e771e3603"}, + {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, + {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, ] +[package.extras] +all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] + [[package]] name = "iniconfig" version = "2.0.0" @@ -1380,13 +1383,13 @@ dev = ["pytest", "pytest-asyncio (<0.17.0)", "respx"] [[package]] name = "lightkube-models" -version = "1.30.0.8" +version = "1.31.1.8" description = "Models and Resources for lightkube module" optional = false python-versions = "*" files = [ - {file = "lightkube-models-1.30.0.8.tar.gz", hash = "sha256:d1fe87b6680a04d27440bb746f2bf2fb665e1515bab12efc3ace65118ecb7eac"}, - {file = "lightkube_models-1.30.0.8-py3-none-any.whl", hash = "sha256:34c43ae4824214eb8bc5e219da57c319ba411a51f503f79510d8c1ae6966ecb5"}, + {file = "lightkube-models-1.31.1.8.tar.gz", hash = "sha256:14fbfa990b4d3393fa4ac3e9e46d67514c4d659508e296b30f1a5d254eecc097"}, + {file = "lightkube_models-1.31.1.8-py3-none-any.whl", hash = "sha256:50c0e2dd2c125cd9b50e93269e2d212bcbec19f7b00de91aa66a5ec320772fae"}, ] [[package]] @@ -1598,13 +1601,13 @@ docs = ["canonical-sphinx-extensions", "furo", "linkify-it-py", "myst-parser", " [[package]] name = "ops-scenario" -version = "7.0.1" +version = "7.0.2" description = "Python library providing a state-transition testing API for Operator Framework charms." optional = false python-versions = ">=3.8" files = [ - {file = "ops_scenario-7.0.1-py3-none-any.whl", hash = "sha256:c642724fd89175a8c9ad82a8a750ada212333ce686bc9a9752c974026a7079d3"}, - {file = "ops_scenario-7.0.1.tar.gz", hash = "sha256:de4127cc6801e8d0ead429f1aa5133e8c35cf1de8e9b4d73ab9ecae2cfc1eb00"}, + {file = "ops_scenario-7.0.2-py3-none-any.whl", hash = "sha256:51988b8a5725865c8dff2b5a3a7173ff83f8469ccc3d8893ab69f1fa2b6a05a2"}, + {file = "ops_scenario-7.0.2.tar.gz", hash = "sha256:a2a177f836f1746a3a332548b1c15280fb8103d6c9c2b4d3454d2043e76ffa09"}, ] [package.dependencies] @@ -1627,13 +1630,13 @@ files = [ [[package]] name = "paramiko" -version = "3.4.1" +version = "3.5.0" description = "SSH2 protocol library" optional = false python-versions = ">=3.6" files = [ - {file = "paramiko-3.4.1-py3-none-any.whl", hash = "sha256:8e49fd2f82f84acf7ffd57c64311aa2b30e575370dc23bdb375b10262f7eac32"}, - {file = "paramiko-3.4.1.tar.gz", hash = "sha256:8b15302870af7f6652f2e038975c1d2973f06046cb5d7d65355668b3ecbece0c"}, + {file = "paramiko-3.5.0-py3-none-any.whl", hash = "sha256:1fedf06b085359051cd7d0d270cebe19e755a8a921cc2ddbfa647fb0cd7d68f9"}, + {file = "paramiko-3.5.0.tar.gz", hash = "sha256:ad11e540da4f55cedda52931f1a3f812a8238a7af7f62a60de538cd80bb28124"}, ] [package.dependencies] @@ -1688,13 +1691,13 @@ ptyprocess = ">=0.5" [[package]] name = "platformdirs" -version = "4.3.2" +version = "4.3.3" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false python-versions = ">=3.8" files = [ - {file = "platformdirs-4.3.2-py3-none-any.whl", hash = "sha256:eb1c8582560b34ed4ba105009a4badf7f6f85768b30126f351328507b2beb617"}, - {file = "platformdirs-4.3.2.tar.gz", hash = "sha256:9e5e27a08aa095dd127b9f2e764d74254f482fef22b0970773bfba79d091ab8c"}, + {file = "platformdirs-4.3.3-py3-none-any.whl", hash = "sha256:50a5450e2e84f44539718293cbb1da0a0885c9d14adf21b77bae4e66fc99d9b5"}, + {file = "platformdirs-4.3.3.tar.gz", hash = "sha256:d4e0b7d8ec176b341fb03cb11ca12d0276faa8c485f9cd218f613840463fc2c0"}, ] [package.extras] @@ -1733,22 +1736,22 @@ wcwidth = "*" [[package]] name = "protobuf" -version = "5.28.0" +version = "5.28.1" description = "" optional = false python-versions = ">=3.8" files = [ - {file = "protobuf-5.28.0-cp310-abi3-win32.whl", hash = "sha256:66c3edeedb774a3508ae70d87b3a19786445fe9a068dd3585e0cefa8a77b83d0"}, - {file = "protobuf-5.28.0-cp310-abi3-win_amd64.whl", hash = "sha256:6d7cc9e60f976cf3e873acb9a40fed04afb5d224608ed5c1a105db4a3f09c5b6"}, - {file = "protobuf-5.28.0-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:532627e8fdd825cf8767a2d2b94d77e874d5ddb0adefb04b237f7cc296748681"}, - {file = "protobuf-5.28.0-cp38-abi3-manylinux2014_aarch64.whl", hash = "sha256:018db9056b9d75eb93d12a9d35120f97a84d9a919bcab11ed56ad2d399d6e8dd"}, - {file = "protobuf-5.28.0-cp38-abi3-manylinux2014_x86_64.whl", hash = "sha256:6206afcb2d90181ae8722798dcb56dc76675ab67458ac24c0dd7d75d632ac9bd"}, - {file = "protobuf-5.28.0-cp38-cp38-win32.whl", hash = "sha256:eef7a8a2f4318e2cb2dee8666d26e58eaf437c14788f3a2911d0c3da40405ae8"}, - {file = "protobuf-5.28.0-cp38-cp38-win_amd64.whl", hash = "sha256:d001a73c8bc2bf5b5c1360d59dd7573744e163b3607fa92788b7f3d5fefbd9a5"}, - {file = "protobuf-5.28.0-cp39-cp39-win32.whl", hash = "sha256:dde9fcaa24e7a9654f4baf2a55250b13a5ea701493d904c54069776b99a8216b"}, - {file = "protobuf-5.28.0-cp39-cp39-win_amd64.whl", hash = "sha256:853db610214e77ee817ecf0514e0d1d052dff7f63a0c157aa6eabae98db8a8de"}, - {file = "protobuf-5.28.0-py3-none-any.whl", hash = "sha256:510ed78cd0980f6d3218099e874714cdf0d8a95582e7b059b06cabad855ed0a0"}, - {file = "protobuf-5.28.0.tar.gz", hash = "sha256:dde74af0fa774fa98892209992295adbfb91da3fa98c8f67a88afe8f5a349add"}, + {file = "protobuf-5.28.1-cp310-abi3-win32.whl", hash = "sha256:fc063acaf7a3d9ca13146fefb5b42ac94ab943ec6e978f543cd5637da2d57957"}, + {file = "protobuf-5.28.1-cp310-abi3-win_amd64.whl", hash = "sha256:4c7f5cb38c640919791c9f74ea80c5b82314c69a8409ea36f2599617d03989af"}, + {file = "protobuf-5.28.1-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:4304e4fceb823d91699e924a1fdf95cde0e066f3b1c28edb665bda762ecde10f"}, + {file = "protobuf-5.28.1-cp38-abi3-manylinux2014_aarch64.whl", hash = "sha256:0dfd86d2b5edf03d91ec2a7c15b4e950258150f14f9af5f51c17fa224ee1931f"}, + {file = "protobuf-5.28.1-cp38-abi3-manylinux2014_x86_64.whl", hash = "sha256:51f09caab818707ab91cf09cc5c156026599cf05a4520779ccbf53c1b352fb25"}, + {file = "protobuf-5.28.1-cp38-cp38-win32.whl", hash = "sha256:1b04bde117a10ff9d906841a89ec326686c48ececeb65690f15b8cabe7149495"}, + {file = "protobuf-5.28.1-cp38-cp38-win_amd64.whl", hash = "sha256:cabfe43044ee319ad6832b2fda332646f9ef1636b0130186a3ae0a52fc264bb4"}, + {file = "protobuf-5.28.1-cp39-cp39-win32.whl", hash = "sha256:4b4b9a0562a35773ff47a3df823177ab71a1f5eb1ff56d8f842b7432ecfd7fd2"}, + {file = "protobuf-5.28.1-cp39-cp39-win_amd64.whl", hash = "sha256:f24e5d70e6af8ee9672ff605d5503491635f63d5db2fffb6472be78ba62efd8f"}, + {file = "protobuf-5.28.1-py3-none-any.whl", hash = "sha256:c529535e5c0effcf417682563719e5d8ac8d2b93de07a56108b4c2d436d7a29a"}, + {file = "protobuf-5.28.1.tar.gz", hash = "sha256:42597e938f83bb7f3e4b35f03aa45208d49ae8d5bcb4bc10b9fc825e0ab5e423"}, ] [[package]] @@ -2386,29 +2389,29 @@ pyasn1 = ">=0.1.3" [[package]] name = "ruff" -version = "0.6.4" +version = "0.6.5" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.6.4-py3-none-linux_armv6l.whl", hash = "sha256:c4b153fc152af51855458e79e835fb6b933032921756cec9af7d0ba2aa01a258"}, - {file = "ruff-0.6.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:bedff9e4f004dad5f7f76a9d39c4ca98af526c9b1695068198b3bda8c085ef60"}, - {file = "ruff-0.6.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d02a4127a86de23002e694d7ff19f905c51e338c72d8e09b56bfb60e1681724f"}, - {file = "ruff-0.6.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7862f42fc1a4aca1ea3ffe8a11f67819d183a5693b228f0bb3a531f5e40336fc"}, - {file = "ruff-0.6.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eebe4ff1967c838a1a9618a5a59a3b0a00406f8d7eefee97c70411fefc353617"}, - {file = "ruff-0.6.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:932063a03bac394866683e15710c25b8690ccdca1cf192b9a98260332ca93408"}, - {file = "ruff-0.6.4-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:50e30b437cebef547bd5c3edf9ce81343e5dd7c737cb36ccb4fe83573f3d392e"}, - {file = "ruff-0.6.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c44536df7b93a587de690e124b89bd47306fddd59398a0fb12afd6133c7b3818"}, - {file = "ruff-0.6.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ea086601b22dc5e7693a78f3fcfc460cceabfdf3bdc36dc898792aba48fbad6"}, - {file = "ruff-0.6.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b52387d3289ccd227b62102c24714ed75fbba0b16ecc69a923a37e3b5e0aaaa"}, - {file = "ruff-0.6.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:0308610470fcc82969082fc83c76c0d362f562e2f0cdab0586516f03a4e06ec6"}, - {file = "ruff-0.6.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:803b96dea21795a6c9d5bfa9e96127cc9c31a1987802ca68f35e5c95aed3fc0d"}, - {file = "ruff-0.6.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:66dbfea86b663baab8fcae56c59f190caba9398df1488164e2df53e216248baa"}, - {file = "ruff-0.6.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:34d5efad480193c046c86608dbba2bccdc1c5fd11950fb271f8086e0c763a5d1"}, - {file = "ruff-0.6.4-py3-none-win32.whl", hash = "sha256:f0f8968feea5ce3777c0d8365653d5e91c40c31a81d95824ba61d871a11b8523"}, - {file = "ruff-0.6.4-py3-none-win_amd64.whl", hash = "sha256:549daccee5227282289390b0222d0fbee0275d1db6d514550d65420053021a58"}, - {file = "ruff-0.6.4-py3-none-win_arm64.whl", hash = "sha256:ac4b75e898ed189b3708c9ab3fc70b79a433219e1e87193b4f2b77251d058d14"}, - {file = "ruff-0.6.4.tar.gz", hash = "sha256:ac3b5bfbee99973f80aa1b7cbd1c9cbce200883bdd067300c22a6cc1c7fba212"}, + {file = "ruff-0.6.5-py3-none-linux_armv6l.whl", hash = "sha256:7e4e308f16e07c95fc7753fc1aaac690a323b2bb9f4ec5e844a97bb7fbebd748"}, + {file = "ruff-0.6.5-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:932cd69eefe4daf8c7d92bd6689f7e8182571cb934ea720af218929da7bd7d69"}, + {file = "ruff-0.6.5-py3-none-macosx_11_0_arm64.whl", hash = "sha256:3a8d42d11fff8d3143ff4da41742a98f8f233bf8890e9fe23077826818f8d680"}, + {file = "ruff-0.6.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a50af6e828ee692fb10ff2dfe53f05caecf077f4210fae9677e06a808275754f"}, + {file = "ruff-0.6.5-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:794ada3400a0d0b89e3015f1a7e01f4c97320ac665b7bc3ade24b50b54cb2972"}, + {file = "ruff-0.6.5-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:381413ec47f71ce1d1c614f7779d88886f406f1fd53d289c77e4e533dc6ea200"}, + {file = "ruff-0.6.5-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:52e75a82bbc9b42e63c08d22ad0ac525117e72aee9729a069d7c4f235fc4d276"}, + {file = "ruff-0.6.5-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09c72a833fd3551135ceddcba5ebdb68ff89225d30758027280968c9acdc7810"}, + {file = "ruff-0.6.5-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:800c50371bdcb99b3c1551d5691e14d16d6f07063a518770254227f7f6e8c178"}, + {file = "ruff-0.6.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8e25ddd9cd63ba1f3bd51c1f09903904a6adf8429df34f17d728a8fa11174253"}, + {file = "ruff-0.6.5-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:7291e64d7129f24d1b0c947ec3ec4c0076e958d1475c61202497c6aced35dd19"}, + {file = "ruff-0.6.5-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:9ad7dfbd138d09d9a7e6931e6a7e797651ce29becd688be8a0d4d5f8177b4b0c"}, + {file = "ruff-0.6.5-py3-none-musllinux_1_2_i686.whl", hash = "sha256:005256d977021790cc52aa23d78f06bb5090dc0bfbd42de46d49c201533982ae"}, + {file = "ruff-0.6.5-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:482c1e6bfeb615eafc5899127b805d28e387bd87db38b2c0c41d271f5e58d8cc"}, + {file = "ruff-0.6.5-py3-none-win32.whl", hash = "sha256:cf4d3fa53644137f6a4a27a2b397381d16454a1566ae5335855c187fbf67e4f5"}, + {file = "ruff-0.6.5-py3-none-win_amd64.whl", hash = "sha256:3e42a57b58e3612051a636bc1ac4e6b838679530235520e8f095f7c44f706ff9"}, + {file = "ruff-0.6.5-py3-none-win_arm64.whl", hash = "sha256:51935067740773afdf97493ba9b8231279e9beef0f2a8079188c4776c25688e0"}, + {file = "ruff-0.6.5.tar.gz", hash = "sha256:4d32d87fab433c0cf285c3683dd4dae63be05fd7a1d65b3f5bf7cdd05a6b96fb"}, ] [[package]] @@ -2571,13 +2574,13 @@ typing-extensions = ">=3.7.4" [[package]] name = "urllib3" -version = "2.2.2" +version = "2.2.3" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.8" files = [ - {file = "urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472"}, - {file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"}, + {file = "urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac"}, + {file = "urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"}, ] [package.extras] diff --git a/pyproject.toml b/pyproject.toml index 2ebf2286..0b08cb62 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -118,7 +118,7 @@ mccabe.max-complexity = 10 [tool.pyright] include = ["src"] -extraPaths = ["./lib", "src"] +extraPaths = ["./lib"] pythonVersion = "3.10" pythonPlatform = "All" typeCheckingMode = "basic" diff --git a/requirements.txt b/requirements.txt index 14856693..d720d0aa 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,24 +1,24 @@ anyio==4.4.0 ; python_version >= "3.10" and python_version < "4.0" -boto3-stubs[s3]==1.35.15 ; python_version >= "3.10" and python_version < "4.0" -boto3==1.35.15 ; python_version >= "3.10" and python_version < "4.0" -botocore-stubs==1.35.15 ; python_version >= "3.10" and python_version < "4.0" -botocore==1.35.15 ; python_version >= "3.10" and python_version < "4.0" +boto3-stubs[s3]==1.35.19 ; python_version >= "3.10" and python_version < "4.0" +boto3==1.35.19 ; python_version >= "3.10" and python_version < "4.0" +botocore-stubs==1.35.19 ; python_version >= "3.10" and python_version < "4.0" +botocore==1.35.19 ; python_version >= "3.10" and python_version < "4.0" certifi==2024.8.30 ; python_version >= "3.10" and python_version < "4.0" cffi==1.17.1 ; python_version >= "3.10" and python_version < "4.0" and platform_python_implementation != "PyPy" -cosl==0.0.32 ; python_version >= "3.10" and python_version < "4.0" +cosl==0.0.33 ; python_version >= "3.10" and python_version < "4.0" cryptography==43.0.1 ; python_version >= "3.10" and python_version < "4.0" exceptiongroup==1.2.2 ; python_version >= "3.10" and python_version < "3.11" h11==0.14.0 ; python_version >= "3.10" and python_version < "4.0" httpcore==1.0.5 ; python_version >= "3.10" and python_version < "4.0" httpx==0.27.2 ; python_version >= "3.10" and python_version < "4.0" -idna==3.8 ; python_version >= "3.10" and python_version < "4.0" +idna==3.10 ; python_version >= "3.10" and python_version < "4.0" jmespath==1.0.1 ; python_version >= "3.10" and python_version < "4.0" kazoo==2.9.0 ; python_version >= "3.10" and python_version < "4.0" -lightkube-models==1.30.0.8 ; python_version >= "3.10" and python_version < "4.0" +lightkube-models==1.31.1.8 ; python_version >= "3.10" and python_version < "4.0" lightkube==0.15.4 ; python_version >= "3.10" and python_version < "4.0" markdown-it-py==3.0.0 ; python_version >= "3.10" and python_version < "4.0" mdurl==0.1.2 ; python_version >= "3.10" and python_version < "4.0" -mypy-boto3-s3==1.35.2 ; python_version >= "3.10" and python_version < "4.0" +mypy-boto3-s3==1.35.16 ; python_version >= "3.10" and python_version < "4.0" ops==2.16.1 ; python_version >= "3.10" and python_version < "4.0" pure-sasl==0.6.2 ; python_version >= "3.10" and python_version < "4.0" pycparser==2.22 ; python_version >= "3.10" and python_version < "4.0" and platform_python_implementation != "PyPy" @@ -36,5 +36,5 @@ tenacity==9.0.0 ; python_version >= "3.10" and python_version < "4.0" types-awscrt==0.21.5 ; python_version >= "3.10" and python_version < "4.0" types-s3transfer==0.10.2 ; python_version >= "3.10" and python_version < "4.0" typing-extensions==4.12.2 ; python_version >= "3.10" and python_version < "4.0" -urllib3==2.2.2 ; python_version >= "3.10" and python_version < "4.0" +urllib3==2.2.3 ; python_version >= "3.10" and python_version < "4.0" websocket-client==1.8.0 ; python_version >= "3.10" and python_version < "4.0" diff --git a/src/workload.py b/src/workload.py index d4ec73e0..895e4977 100644 --- a/src/workload.py +++ b/src/workload.py @@ -5,20 +5,18 @@ """Implementation of WorkloadBase for running on VMs.""" import logging import os -import re import secrets import shutil import string import subprocess -from subprocess import CalledProcessError +import httpx from charms.operator_libs_linux.v1 import snap -from ops.pebble import ExecError from tenacity import retry, retry_if_result, stop_after_attempt, wait_fixed from typing_extensions import override from core.workload import WorkloadBase -from literals import CHARMED_ZOOKEEPER_SNAP_REVISION, CLIENT_PORT +from literals import ADMIN_SERVER_PORT, CHARMED_ZOOKEEPER_SNAP_REVISION logger = logging.getLogger(__name__) @@ -109,27 +107,14 @@ def healthy(self) -> bool: if not self.alive: return False - # netcat isn't a default utility, so can't guarantee it's on the charm containers - # this ugly hack avoids needing netcat - bash_netcat = ( - f"echo '4lw' | (exec 3<>/dev/tcp/localhost/{CLIENT_PORT}; cat >&3; cat <&3; exec 3<&-)" - ) - ruok = [bash_netcat.replace("4lw", "ruok")] - srvr = [bash_netcat.replace("4lw", "srvr")] + try: + response = httpx.get(f"http://localhost:{ADMIN_SERVER_PORT}/commands/ruok", timeout=10) + response.raise_for_status() - # timeout needed as it can sometimes hang forever if there's a problem - # for example when the endpoint is unreachable - timeout = ["timeout", "10s", "bash", "-c"] + except httpx.HTTPError: + return False - try: - ruok_response = self.exec(command=timeout + ruok) - if not ruok_response or "imok" not in ruok_response: - return False - - srvr_response = self.exec(command=timeout + srvr) - if not srvr_response or "not currently serving requests" in srvr_response: - return False - except (ExecError, CalledProcessError): + if response.json().get("error", None): return False return True @@ -152,7 +137,7 @@ def install(self) -> bool: self.zookeeper.hold() return True - except (snap.SnapError) as e: + except snap.SnapError as e: logger.error(str(e)) return False @@ -170,21 +155,14 @@ def get_version(self) -> str: if not self.healthy: return "" - stat = [ - "bash", - "-c", - f"echo 'stat' | (exec 3<>/dev/tcp/localhost/{CLIENT_PORT}; cat >&3; cat <&3; exec 3<&-; )", - ] - try: - stat_response = self.exec(command=stat) - if not stat_response: - return "" + response = httpx.get(f"http://localhost:{ADMIN_SERVER_PORT}/commands/srvr", timeout=10) + response.raise_for_status() - matcher = re.search(r"(?P\d\.\d\.\d)", stat_response) - version = matcher.group("version") if matcher else "" - - except (ExecError, CalledProcessError): + except httpx.HTTPError: return "" - return version + if not (full_version := response.json().get("version", "")): + return full_version + else: + return full_version.split("-")[0] diff --git a/tests/integration/ha/helpers.py b/tests/integration/ha/helpers.py index e2f84491..85ecbb37 100644 --- a/tests/integration/ha/helpers.py +++ b/tests/integration/ha/helpers.py @@ -4,7 +4,6 @@ import json import logging -import re import subprocess from pathlib import Path from typing import Dict, Optional @@ -14,6 +13,8 @@ from pytest_operator.plugin import OpsTest from tenacity import RetryError, Retrying, retry, stop_after_attempt, wait_fixed +from literals import ADMIN_SERVER_PORT + logger = logging.getLogger(__name__) METADATA = yaml.safe_load(Path("./metadata.yaml").read_text()) @@ -50,28 +51,26 @@ async def wait_idle(ops_test, apps: list[str] = [APP_NAME], units: int = 3) -> N stop=stop_after_attempt(60), reraise=True, ) -def srvr(host: str) -> dict: - """Calls srvr 4lw command to specified host. +def srvr(model_full_name: str, unit: str) -> dict: + """Calls srvr 4lw command to specified unit. Args: - host: ZooKeeper address and port to issue srvr 4lw command to + model_full_name: Current test model + unit: ZooKeeper unit to issue srvr 4lw command to Returns: Dict of srvr command output key/values """ response = subprocess.check_output( - f"echo srvr | nc {host} 2181", stderr=subprocess.PIPE, shell=True, universal_newlines=True + f"JUJU_MODEL={model_full_name} juju ssh {unit} sudo -i 'curl localhost:{ADMIN_SERVER_PORT}/commands/srvr -m 10'", + stderr=subprocess.PIPE, + shell=True, + universal_newlines=True, ) assert response, "ZooKeeper not running" - result = {} - for item in response.splitlines(): - k = re.split(": ", item)[0] - v = re.split(": ", item)[1] - result[k] = v - - return result + return json.loads(response) def get_hosts_from_status( @@ -176,13 +175,17 @@ def get_leader_name(ops_test: OpsTest, hosts: str, app_name: str = APP_NAME) -> String of unit name of the ZooKeeper quorum leader """ for host in hosts.split(","): + unit_name = get_unit_name_from_host(ops_test, host, app_name) try: - mode = srvr(host.split(":")[0])["Mode"] + mode = ( + srvr(ops_test.model_full_name, unit_name) + .get("server_stats", {}) + .get("server_state", "") + ) except subprocess.CalledProcessError: # unit is down continue if mode == "leader": - leader_name = get_unit_name_from_host(ops_test, host, app_name) - return leader_name + return unit_name return "" @@ -481,8 +484,12 @@ def ping_servers(ops_test: OpsTest) -> bool: True if all units are in quorum. Otherwise False """ for unit in ops_test.model.applications[APP_NAME].units: - host = unit.public_address - mode = srvr(host)["Mode"] + srvr_response = srvr(ops_test.model_full_name, unit.name) + + if srvr_response.get("error", None): + return False + + mode = srvr_response.get("server_stats", {}).get("server_state", "") if mode not in ["leader", "follower"]: return False diff --git a/tests/integration/helpers.py b/tests/integration/helpers.py index d3f0fb5d..52dcfc62 100644 --- a/tests/integration/helpers.py +++ b/tests/integration/helpers.py @@ -14,6 +14,7 @@ from pytest_operator.plugin import OpsTest from core.workload import ZKPaths +from literals import ADMIN_SERVER_PORT METADATA = yaml.safe_load(Path("./metadata.yaml").read_text()) APP_NAME = METADATA["name"] @@ -131,31 +132,32 @@ def check_key(host: str, password: str, username: str = "super") -> None: raise KeyError -def srvr(host: str) -> Dict: +def srvr(model_full_name: str, unit: str) -> dict: """Retrieves attributes returned from the 'srvr' 4lw command. Specifically for this test, we are interested in the "Mode" of the ZK server, which allows checking quorum leadership and follower active status. """ response = check_output( - f"echo srvr | nc {host} 2181", stderr=PIPE, shell=True, universal_newlines=True + f"JUJU_MODEL={model_full_name} juju ssh {unit} sudo -i 'curl localhost:{ADMIN_SERVER_PORT}/commands/srvr -m 10'", + stderr=PIPE, + shell=True, + universal_newlines=True, ) assert response, "ZooKeeper not running" - result = {} - for item in response.splitlines(): - k = re.split(": ", item)[0] - v = re.split(": ", item)[1] - result[k] = v - - return result + return json.loads(response) async def ping_servers(ops_test: OpsTest) -> bool: for unit in ops_test.model.applications[APP_NAME].units: - host = unit.public_address - mode = srvr(host)["Mode"] + srvr_response = srvr(ops_test.model_full_name, unit.name) + + if srvr_response.get("error", None): + return False + + mode = srvr_response.get("server_stats", {}).get("server_state", "") if mode not in ["leader", "follower"]: return False @@ -164,8 +166,9 @@ async def ping_servers(ops_test: OpsTest) -> bool: async def correct_version_running(ops_test: OpsTest, expected_version: str) -> bool: for unit in ops_test.model.applications[APP_NAME].units: - host = unit.public_address - if expected_version not in srvr(host)["Zookeeper version"]: + srvr_response = srvr(ops_test.model_full_name, unit.name) + + if expected_version not in srvr_response.get("version", ""): return False return True diff --git a/tests/unit/test_charm.py b/tests/unit/test_charm.py index 815b8c6a..8c25dc70 100644 --- a/tests/unit/test_charm.py +++ b/tests/unit/test_charm.py @@ -8,6 +8,7 @@ from pathlib import Path from unittest.mock import DEFAULT, Mock, PropertyMock, patch +import httpx import pytest import yaml from charms.rolling_ops.v0.rollingops import WaitingStatus @@ -1055,16 +1056,18 @@ def test_update_relation_data(harness): def test_workload_version_is_setted(harness, monkeypatch): - output_install = ( - "Zookeeper version: 3.8.1-ubuntu0-${mvngit.commit.id}, built on 2023-11-21 15:33 UTC" - ) - output_changed = ( - "Zookeeper version: 3.8.2-ubuntu0-${mvngit.commit.id}, built on 2023-11-21 15:33 UTC" - ) + output_install = { + "version": "3.8.1-ubuntu0-${mvngit.commit.id}, built on 2023-11-21 15:33 UTC" + } + output_changed = { + "version": "3.8.2-ubuntu0-${mvngit.commit.id}, built on 2023-11-21 15:33 UTC" + } + response_mock = Mock() + response_mock.return_value.json.side_effect = [output_install, output_changed] monkeypatch.setattr( - harness.charm.workload, - "exec", - Mock(side_effect=[output_install, output_changed]), + httpx, + "get", + response_mock, ) monkeypatch.setattr(harness.charm.workload, "install", Mock(return_value=True)) monkeypatch.setattr(harness.charm.workload, "healthy", Mock(return_value=True))