From 7655d6f5e667112247cce37fc336b2c30a424211 Mon Sep 17 00:00:00 2001 From: Teddy Andrieux Date: Fri, 9 Oct 2020 15:20:02 +0200 Subject: [PATCH 01/13] salt: In downgrade orchestrate use `metalk8s.cmp_sorted` With Python3 we can no longer use `cmp` in `sort` and `sorted` function so use our salt module `metalk8s.cmp_sorted` in Downgrade orchestrate if we are running with Python3, so that it works well with Python2 and Pyton3 Refs: #2203 --- salt/metalk8s/orchestrate/downgrade/precheck.sls | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/salt/metalk8s/orchestrate/downgrade/precheck.sls b/salt/metalk8s/orchestrate/downgrade/precheck.sls index 13262035ea..8c761c3905 100644 --- a/salt/metalk8s/orchestrate/downgrade/precheck.sls +++ b/salt/metalk8s/orchestrate/downgrade/precheck.sls @@ -4,8 +4,7 @@ {#- When downgrading saltenv should be the newest version #} {%- set nodes_versions = pillar.metalk8s.nodes.values() | map(attribute='version') | list %} -{%- do nodes_versions.sort(cmp=salt.pkg.version_cmp, reverse=True) %} -{%- set expected = nodes_versions | first %} +{%- set expected = salt.metalk8s.cmp_sorted(nodes_versions, cmp=salt.pkg.version_cmp, reverse=True) | first %} {%- if salt.pkg.version_cmp(saltenv | replace('metalk8s-', ''), expected) < 0 %} Invalid saltenv "{{ saltenv }}" consider using "metalk8s-{{ expected }}": From 6577d2cdadba4c5276ee62683f179433a6def126 Mon Sep 17 00:00:00 2001 From: Teddy Andrieux Date: Fri, 9 Oct 2020 15:49:16 +0200 Subject: [PATCH 02/13] tests,docs: Use `salt-ssh --raw-shell` command before expansions In the past a `salt-ssh` command was needed prior to start the expansions to accept the ssh key but it's not longer needed so remove it. Instead do a simple `salt-ssh --raw-shell` command to check that salt-ssh work properly --- docs/installation/expansion.rst | 21 ++++++++++++++++++--- tests/install/steps/test_expansion.py | 12 +++++++++--- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/docs/installation/expansion.rst b/docs/installation/expansion.rst index 9efdf21890..31a6eaec7f 100644 --- a/docs/installation/expansion.rst +++ b/docs/installation/expansion.rst @@ -237,11 +237,26 @@ Open a terminal in the Salt Master container using #. Check that SSH access from the Salt Master to the new node is properly configured (see :ref:`Bootstrap SSH Provisioning`). + .. note:: + + Salt SSH requires Python 3 to be installed on the remote host to run Salt + functions. It will be installed automatically when deploying the node, + though you can send raw shell commands before (using ``--raw-shell``) if + needed. + .. code-block:: shell - root@salt-master-bootstrap $ salt-ssh --roster kubernetes test.ping - : - True + root@salt-master-bootstrap $ salt-ssh --roster=kubernetes --raw-shell 'echo OK' + : + ---------- + retcode: + 0 + stderr: + Warning: Permanently added '' (ECDSA) to the list of known hosts. + stdout: + OK + + #. Start the node deployment. diff --git a/tests/install/steps/test_expansion.py b/tests/install/steps/test_expansion.py index 17ccaa7f87..a3f84a8c10 100644 --- a/tests/install/steps/test_expansion.py +++ b/tests/install/steps/test_expansion.py @@ -37,16 +37,22 @@ def declare_node( @when(parsers.parse('we deploy the node "{node_name}"')) def deploy_node(host, ssh_config, version, node_name): - accept_ssh_key = [ - 'salt-ssh', '-i', node_name, 'test.ping', '--roster=kubernetes' + test_ssh = [ + 'salt-ssh', '--roster=kubernetes', '-i', node_name, '--raw-shell', + '--out=json', 'echo OK' ] + test_ssh_ret = json.loads( + utils.run_salt_command(host, test_ssh, ssh_config).stdout + )[node_name] + assert test_ssh_ret['stdout'] == 'OK\n', \ + 'Unable to connect to {} with salt-ssh: {}'.format(node_name, test_ssh_ret['stderr']) + pillar = {'orchestrate': {'node_name': node_name}} deploy = [ 'salt-run', 'state.orchestrate', 'metalk8s.orchestrate.deploy_node', 'saltenv=metalk8s-{}'.format(version), "pillar='{}'".format(json.dumps(pillar)) ] - utils.run_salt_command(host, accept_ssh_key, ssh_config) utils.run_salt_command(host, deploy, ssh_config) From 5e4174d18f194b87a2909b915e153c189ea7bf31 Mon Sep 17 00:00:00 2001 From: Teddy Andrieux Date: Fri, 9 Oct 2020 15:51:03 +0200 Subject: [PATCH 03/13] salt: Add a `states` to execute a function on a minion with raw ssh Right now `salt.function` salt state module do not handle `roster` for ssh and `raw_shell`, create a custom salt state module to run a `saltutil.cmd` with all kwargs input so that we support `roster` and `raw_shell` Sees: https://github.com/saltstack/salt/issues/58662 --- salt/_states/metalk8s.py | 62 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/salt/_states/metalk8s.py b/salt/_states/metalk8s.py index 10a6d91dca..5e8f9dbf43 100644 --- a/salt/_states/metalk8s.py +++ b/salt/_states/metalk8s.py @@ -103,3 +103,65 @@ def module_run(name, attemps=1, sleep_time=10, **kwargs): time.sleep(sleep_time) return ret + + +def saltutil_cmd(name, **kwargs): + """Simple `saltutil.cmd` state as `salt.function` do not support roster and + raw ssh, https://github.com/saltstack/salt/issues/58662""" + ret = { + 'name': name, + 'changes': {}, + 'result': True, + 'comment': '' + } + + try: + cmd_ret = __salt__['saltutil.cmd'](fun=name, **kwargs) + except Exception as exc: # pylint: disable=broad-except + ret['result'] = False + ret['comment'] = str(exc) + return ret + + try: + ret['__jid__'] = cmd_ret[next(iter(cmd_ret))]['jid'] + except (StopIteration, KeyError): + pass + + fail = set() + + for minion, mdata in cmd_ret.items(): + m_ret = False + if mdata.get('retcode'): + ret['result'] = False + fail.add(minion) + if mdata.get('failed', False): + fail.add(minion) + else: + if 'return' in mdata and 'ret' not in mdata: + mdata['ret'] = mdata.pop('return') + if 'ret' in mdata: + m_ret = mdata['ret'] + if 'stderr' in mdata or 'stdout' in mdata: + m_ret = { + 'retcode': mdata.get('retcode'), + 'stderr': mdata.get('stderr'), + 'stdout': mdata.get('stdout') + } + if m_ret is False: + fail.add(minion) + + ret['changes'][minion] = m_ret + + if not cmd_ret: + ret['result'] = False + ret['comment'] = 'No minions responded' + else: + if fail: + ret['result'] = False + ret['comment'] = 'Running function {} failed on minions: {}'.format( + name, ', '.join(fail) + ) + else: + ret['comment'] = 'Function ran successfully' + + return ret From b53d936c0256b41cf8ad92e6f681041fc531f577 Mon Sep 17 00:00:00 2001 From: Teddy Andrieux Date: Fri, 9 Oct 2020 15:53:08 +0200 Subject: [PATCH 04/13] build,salt,script: Migrate to Salt Python3 Change salt-master image to use Python3 salt-master package and also install Python3 dependencies, embed Python3 salt-minion version instead of Python2. In order to install Python3 salt-minion we need: - to install python3 - to install python36-rpm as by default version comparaison for package installation is wrong - to install python3 on nodes for being able to use `salt-ssh` Sees: https://github.com/saltstack/salt/issues/58039 Sees: https://github.com/saltstack/salt/issues/57972 Fixes: #2203 --- buildchain/buildchain/salt_tree.py | 1 + buildchain/buildchain/versions.py | 1 + images/metalk8s-utils/configure-repos.sh | 4 ++-- images/salt-master/Dockerfile | 16 ++++++++-------- packages/debian/download_packages.py | 4 ++-- packages/redhat/yum_repositories/saltstack.repo | 4 ++-- salt/metalk8s/orchestrate/deploy_node.sls | 10 ++++++++++ salt/metalk8s/salt/minion/dependencies.sls | 17 +++++++++++++++++ salt/metalk8s/salt/minion/installed.sls | 2 +- scripts/bootstrap.sh.in | 1 + scripts/restore.sh.in | 1 + 11 files changed, 46 insertions(+), 15 deletions(-) create mode 100644 salt/metalk8s/salt/minion/dependencies.sls diff --git a/buildchain/buildchain/salt_tree.py b/buildchain/buildchain/salt_tree.py index 810858d504..a0b5e0a3d5 100644 --- a/buildchain/buildchain/salt_tree.py +++ b/buildchain/buildchain/salt_tree.py @@ -635,6 +635,7 @@ def _get_parts(self) -> Iterator[str]: Path('salt/metalk8s/salt/master/certs/salt-api.sls'), Path('salt/metalk8s/salt/minion/configured.sls'), + Path('salt/metalk8s/salt/minion/dependencies.sls'), Path('salt/metalk8s/salt/minion/files/minion-99-metalk8s.conf.j2'), Path('salt/metalk8s/salt/minion/init.sls'), Path('salt/metalk8s/salt/minion/installed.sls'), diff --git a/buildchain/buildchain/versions.py b/buildchain/buildchain/versions.py index b35eccfe13..90e540dffb 100644 --- a/buildchain/buildchain/versions.py +++ b/buildchain/buildchain/versions.py @@ -353,6 +353,7 @@ def deb_full_name(self) -> str: version=SHORT_VERSION, release='1.el7' ), + PackageVersion(name='python36-rpm'), PackageVersion(name='yum-plugin-versionlock'), PackageVersion(name='yum-utils'), ), diff --git a/images/metalk8s-utils/configure-repos.sh b/images/metalk8s-utils/configure-repos.sh index 7e5b3dc2e8..3f60d3f247 100755 --- a/images/metalk8s-utils/configure-repos.sh +++ b/images/metalk8s-utils/configure-repos.sh @@ -19,8 +19,8 @@ EOF cat > /etc/yum.repos.d/saltstack.repo << EOF [saltstack] name=SaltStack repo for RHEL/CentOS \$releasever -baseurl=https://repo.saltstack.com/yum/redhat/\$releasever/\$basearch/archive/$SALT_VERSION +baseurl=https://repo.saltstack.com/py3/redhat/\$releasever/\$basearch/archive/$SALT_VERSION enabled=1 gpgcheck=1 -gpgkey=https://repo.saltstack.com/yum/redhat/\$releasever/\$basearch/archive/$SALT_VERSION/SALTSTACK-GPG-KEY.pub +gpgkey=https://repo.saltstack.com/py3/redhat/\$releasever/\$basearch/archive/$SALT_VERSION/SALTSTACK-GPG-KEY.pub EOF diff --git a/images/salt-master/Dockerfile b/images/salt-master/Dockerfile index 4955f0f970..590d52701b 100644 --- a/images/salt-master/Dockerfile +++ b/images/salt-master/Dockerfile @@ -8,20 +8,20 @@ ARG SALT_VERSION=3000.5 # Install saltstack RUN printf "[saltstack-repo]\n\ name=SaltStack repo for RHEL/CentOS \$releasever\n\ -baseurl=https://repo.saltstack.com/yum/redhat/\$releasever/\$basearch/archive/%s\n\ +baseurl=https://repo.saltstack.com/py3/redhat/\$releasever/\$basearch/archive/%s\n\ enabled=1\n\ gpgcheck=1\n\ -gpgkey=https://repo.saltstack.com/yum/redhat/\$releasever/\$basearch/archive/%s/SALTSTACK-GPG-KEY.pub\n" ${SALT_VERSION} ${SALT_VERSION} >/etc/yum.repos.d/saltstack.repo \ - && rpm --import https://repo.saltstack.com/yum/redhat/7/x86_64/archive/${SALT_VERSION}/SALTSTACK-GPG-KEY.pub \ +gpgkey=https://repo.saltstack.com/py3/redhat/\$releasever/\$basearch/archive/%s/SALTSTACK-GPG-KEY.pub\n" ${SALT_VERSION} ${SALT_VERSION} >/etc/yum.repos.d/saltstack.repo \ + && rpm --import https://repo.saltstack.com/py3/redhat/7/x86_64/archive/${SALT_VERSION}/SALTSTACK-GPG-KEY.pub \ && yum clean expire-cache \ && yum install -y epel-release \ - && yum install -y python-pip \ - && pip install pip==20.1 \ - && pip install "etcd3 != 0.11.0" \ + && yum install -y python3-pip \ + && pip3 install pip==20.1 \ + && pip3 install "etcd3 != 0.11.0" \ && yum install -y git \ - && pip install "git+https://github.com/kubernetes-client/python.git@cef5e9bd10a6d5ca4d9c83da46ccfe2114cdaaf8#egg=kubernetes" \ + && pip3 install "git+https://github.com/kubernetes-client/python.git@cef5e9bd10a6d5ca4d9c83da46ccfe2114cdaaf8#egg=kubernetes" \ && yum remove -y git \ - && pip uninstall -y \ + && pip3 uninstall -y \ requests \ urllib3 \ && yum install -y salt-master salt-api salt-ssh openssh-clients \ diff --git a/packages/debian/download_packages.py b/packages/debian/download_packages.py index 322d53c348..4c4dfc2bb9 100755 --- a/packages/debian/download_packages.py +++ b/packages/debian/download_packages.py @@ -110,12 +110,12 @@ def add_external_repositories(salt_version: str) -> None: }, { 'name': 'saltstack', 'key': urllib.parse.urljoin( - 'https://repo.saltstack.com/apt/ubuntu/', + 'https://repo.saltstack.com/py3/ubuntu/', '18.04/amd64/archive/{}/SALTSTACK-GPG-KEY.pub'.format( salt_version ) ), - 'source': 'deb http://repo.saltstack.com/apt/ubuntu/'\ + 'source': 'deb http://repo.saltstack.com/py3/ubuntu/'\ '18.04/amd64/archive/{} bionic main'.format(salt_version) } ] diff --git a/packages/redhat/yum_repositories/saltstack.repo b/packages/redhat/yum_repositories/saltstack.repo index ef478a314a..dd48bca102 100644 --- a/packages/redhat/yum_repositories/saltstack.repo +++ b/packages/redhat/yum_repositories/saltstack.repo @@ -1,6 +1,6 @@ [saltstack] name=SaltStack repo for RHEL/CentOS $releasever -baseurl=https://repo.saltstack.com/yum/redhat/$releasever/$basearch/archive/@SALT_VERSION@ +baseurl=https://repo.saltstack.com/py3/redhat/$releasever/$basearch/archive/@SALT_VERSION@ enabled=1 gpgcheck=1 -gpgkey=https://repo.saltstack.com/yum/redhat/$releasever/$basearch/archive/@SALT_VERSION@/SALTSTACK-GPG-KEY.pub +gpgkey=https://repo.saltstack.com/py3/redhat/$releasever/$basearch/archive/@SALT_VERSION@/SALTSTACK-GPG-KEY.pub diff --git a/salt/metalk8s/orchestrate/deploy_node.sls b/salt/metalk8s/orchestrate/deploy_node.sls index 61c5e6061d..fcdbe945df 100644 --- a/salt/metalk8s/orchestrate/deploy_node.sls +++ b/salt/metalk8s/orchestrate/deploy_node.sls @@ -6,6 +6,16 @@ {%- set roles = pillar.get('metalk8s', {}).get('nodes', {}).get(node_name, {}).get('roles', []) %} {%- if node_name not in salt.saltutil.runner('manage.up') %} +# Salt-ssh need python3 to be installed on the destination host, so install it +# manually using raw ssh +Install python36: + metalk8s.saltutil_cmd: + - name: '[ "$EUID" -eq 0 ] && yum install -y python3 || sudo yum install -y python3' + - tgt: {{ node_name }} + - ssh: true + - raw_shell: true + - roster: kubernetes + Deploy salt-minion on a new node: salt.state: - ssh: true diff --git a/salt/metalk8s/salt/minion/dependencies.sls b/salt/metalk8s/salt/minion/dependencies.sls new file mode 100644 index 0000000000..f0bad34b3c --- /dev/null +++ b/salt/metalk8s/salt/minion/dependencies.sls @@ -0,0 +1,17 @@ +# Salt need `python36-rpm` to do proper version comparison and since we +# use salt-ssh to install salt the first time, we want this rpm to be installed +# before Salt-minion as salt-minion installation state will report a "failure" +# because of version comparaison + +# See: https://github.com/saltstack/salt/issues/58039 +# https://github.com/saltstack/salt/issues/57972 + +{%- from "metalk8s/macro.sls" import pkg_installed with context %} + +include: + - metalk8s.repo + +Install python36-rpm: + {{ pkg_installed('python36-rpm') }} + - require: + - test: Repositories configured diff --git a/salt/metalk8s/salt/minion/installed.sls b/salt/metalk8s/salt/minion/installed.sls index ea5e84a892..b96288ccea 100644 --- a/salt/metalk8s/salt/minion/installed.sls +++ b/salt/metalk8s/salt/minion/installed.sls @@ -1,7 +1,7 @@ {%- from "metalk8s/macro.sls" import pkg_installed with context %} include : - - metalk8s.repo + - .dependencies - .running Install salt-minion: diff --git a/scripts/bootstrap.sh.in b/scripts/bootstrap.sh.in index 953cb3fd02..9ebd43f1cd 100755 --- a/scripts/bootstrap.sh.in +++ b/scripts/bootstrap.sh.in @@ -58,6 +58,7 @@ SALT_CALL=${SALT_CALL:-salt-call} declare -a PACKAGES=( salt-minion-@@SALT_VERSION genisoimage + python36-rpm ) # shellcheck disable=SC1090 diff --git a/scripts/restore.sh.in b/scripts/restore.sh.in index d067b04ce4..7926cfaf2f 100755 --- a/scripts/restore.sh.in +++ b/scripts/restore.sh.in @@ -72,6 +72,7 @@ SALT_CALL=${SALT_CALL:-salt-call} declare -a PACKAGES=( salt-minion-@@SALT_VERSION genisoimage + python36-rpm ) # shellcheck disable=SC1090 From a7b51ea7326e9319f22c48f4b5677660dcd497d8 Mon Sep 17 00:00:00 2001 From: Guillaume Demonet Date: Mon, 16 Nov 2020 12:06:52 +0100 Subject: [PATCH 05/13] salt/unit-test: Migrate to Python 3 - removes `salttesting` dependency - migrates away from deprecated `TestCase` methods - migrates `Mock` objects call args checks --- salt/tests/requirements.in | 1 - salt/tests/requirements.txt | 249 ++++++------------ salt/tests/unit/mixins.py | 77 ++++++ salt/tests/unit/mocks/kubernetes.py | 2 +- .../files/test_metalk8s_kubernetes_utils.yaml | 2 +- salt/tests/unit/modules/test_containerd.py | 12 +- salt/tests/unit/modules/test_cri.py | 11 +- salt/tests/unit/modules/test_metalk8s.py | 26 +- .../unit/modules/test_metalk8s_checks.py | 14 +- .../unit/modules/test_metalk8s_cordon.py | 14 +- .../tests/unit/modules/test_metalk8s_drain.py | 42 +-- salt/tests/unit/modules/test_metalk8s_etcd.py | 21 +- .../unit/modules/test_metalk8s_grafana.py | 23 +- .../unit/modules/test_metalk8s_kubernetes.py | 47 ++-- .../modules/test_metalk8s_kubernetes_utils.py | 25 +- .../unit/modules/test_metalk8s_monitoring.py | 32 +-- .../unit/modules/test_metalk8s_network.py | 22 +- .../test_metalk8s_package_manager_yum.py | 18 +- .../test_metalk8s_service_configuration.py | 18 +- .../unit/modules/test_metalk8s_solutions.py | 32 ++- .../modules/test_metalk8s_solutions_k8s.py | 11 +- .../unit/modules/test_metalk8s_volumes.py | 29 +- salt/tests/unit/utils.py | 84 ++++++ tox.ini | 13 - 24 files changed, 438 insertions(+), 387 deletions(-) create mode 100644 salt/tests/unit/mixins.py diff --git a/salt/tests/requirements.in b/salt/tests/requirements.in index 848fc8f759..b834becf74 100644 --- a/salt/tests/requirements.in +++ b/salt/tests/requirements.in @@ -1,7 +1,6 @@ pytest pytest-cov salt == 3000.5 -salttesting == 2018.9.21 mock == 3.0.5 parameterized == 0.7.4 etcd3 != 0.11.0 diff --git a/salt/tests/requirements.txt b/salt/tests/requirements.txt index 6f79bb6f8a..97d521340a 100644 --- a/salt/tests/requirements.txt +++ b/salt/tests/requirements.txt @@ -2,44 +2,24 @@ # This file is autogenerated by pip-compile # To update, run: # -# tox -e pip-compile2 +# tox -e pip-compile # -atomicwrites==1.4.0 \ - --hash=sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197 \ - --hash=sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a \ - # via pytest attrs==20.3.0 \ --hash=sha256:31b2eced602aa8423c2aea9c76a724617ed67cf9513173fd3a4f03e3a929c7e6 \ --hash=sha256:832aa3cde19744e49938b91fea06d69ecb9e649c93ba974535d08ad92164f700 \ # via pytest -backports-abc==0.5 \ - --hash=sha256:033be54514a03e255df75c5aee8f9e672f663f93abb723444caec8fe43437bde \ - --hash=sha256:52089f97fe7a9aa0d3277b220c1d730a85aefd64e1b2664696fe35317c5470a7 \ - # via salt -backports.functools-lru-cache==1.6.1 \ - --hash=sha256:0bada4c2f8a43d533e4ecb7a12214d9420e66eb206d54bf2d682581ca4b80848 \ - --hash=sha256:8fde5f188da2d593bd5bc0be98d9abc46c95bb8a9dde93429570192ee6cc2d4a \ - # via wcwidth -cachetools==3.1.1 \ - --hash=sha256:428266a1c0d36dc5aca63a2d7c5942e88c2c898d72139fca0e97fdd2380517ae \ - --hash=sha256:8ea2d3ce97850f31e4a08b0e2b5e6c34997d7216a9d2c98e0f3978630d4da69a \ +cachetools==4.1.1 \ + --hash=sha256:513d4ff98dd27f85743a8dc0e92f55ddb1b49e060c2d5961512855cda2c01a98 \ + --hash=sha256:bbaa39c3dede00175df2dc2b03d0cf18dd2d32a7de7beb68072d13043c9edb20 \ # via google-auth -certifi==2020.6.20 \ - --hash=sha256:5930595817496dd21bb8dc35dad090f1c2cd0adfaf21204bf6732ca5d8ee34d3 \ - --hash=sha256:8fc0819f1f30ba15bdb34cceffb9ef04d99f420f68eb75d901e9560b8749fc41 \ +certifi==2020.11.8 \ + --hash=sha256:1f422849db327d534e3d0c5f02a263458c3955ec0aae4ff09b95f195c59f4edd \ + --hash=sha256:f05def092c44fbf25834a51509ef6e631dc19765ab8a57b4e7ab85531f0a9cf4 \ # via kubernetes, requests chardet==3.0.4 \ --hash=sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae \ --hash=sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691 \ # via requests -configparser==4.0.2 \ - --hash=sha256:254c1d9c79f60c45dfde850850883d5aaa7f19a23f13561243a050d5a7c3fe4c \ - --hash=sha256:c7d282687a5308319bf3d2e7706e575c635b0a470342641c93bea0ea3b5331df \ - # via importlib-metadata -contextlib2==0.6.0.post1 \ - --hash=sha256:01f490098c18b19d2bd5bb5dc445b2054d2fa97f09a4280ba2c5f3c394c8162e \ - --hash=sha256:3355078a159fbb44ee60ea80abd0d87b80b78c248643b49aa6d94673b413609b \ - # via importlib-metadata, zipp coverage==5.3 \ --hash=sha256:0203acd33d2298e19b57451ebb0bed0ab0c602e5cf5a818591b4918b1f97d516 \ --hash=sha256:0f313707cdecd5cd3e217fc68c78a960b616604b559e9ea60cc16795c4304259 \ @@ -76,21 +56,8 @@ coverage==5.3 \ --hash=sha256:cedb2f9e1f990918ea061f28a0f0077a07702e3819602d3507e2ff98c8d20636 \ --hash=sha256:e8caf961e1b1a945db76f1b5fa9c91498d15f545ac0ababbe575cfab185d3bd8 \ # via pytest-cov -enum34==1.1.10 \ - --hash=sha256:a98a201d6de3f2ab3db284e70a33b0f896fbf35f8086594e8c9e74b909058d53 \ - --hash=sha256:c3858660960c984d6ab0ebad691265180da2b43f07e061c0f8dca9ef3cffd328 \ - --hash=sha256:cce6a7477ed816bd2542d03d53db9f0db935dd013b70f336a95c73979289f248 \ - # via grpcio etcd3==0.12.0 \ --hash=sha256:89a704cb389bf0a010a1fa050ce19342d23bf6371ebda1c21cfe8ff3ed488726 -funcsigs==1.0.2 \ - --hash=sha256:330cc27ccbf7f1e992e69fef78261dc7c6569012cf397db8d3de0234e6c937ca \ - --hash=sha256:a7bb0f2cf3a3fd1ab2732cb49eba4252c2af4240442415b4abce3b87022a8f50 \ - # via mock, pytest -futures==3.3.0 \ - --hash=sha256:49b3f5b064b6e3afc3316421a3f25f66c137ae88f068abbf72830170033c5e16 \ - --hash=sha256:7e033af76a5e35f58e56da7a91e687706faf4e7bdfb2cbc3f2cca6b9bcda9794 \ - # via grpcio, salt, tenacity google-auth==1.23.0 \ --hash=sha256:5176db85f1e7e837a646cd9cede72c3c404ccf2e3373d9ee14b2db88febad440 \ --hash=sha256:b728625ff5dfce8f9e56a499c8a4eb51443a67f20f6d28b67d5774c310ec4b6b \ @@ -125,6 +92,7 @@ grpcio==1.33.2 \ --hash=sha256:7fda62846ef8d86caf06bd1ecfddcae2c7e59479a4ee28808120e170064d36cc \ --hash=sha256:85e56ab125b35b1373205b3802f58119e70ffedfe0d7e2821999126058f7c44f \ --hash=sha256:88f2a102cbc67e91f42b4323cec13348bf6255b25f80426088079872bd4f3c5c \ + --hash=sha256:89add4f4cda9546f61cb8a6988bc5b22101dd8ca4af610dff6f28105d1f78695 \ --hash=sha256:8cf67b8493bff50fa12b4bc30ab40ce1f1f216eb54145962b525852959b0ab3d \ --hash=sha256:a8c84db387907e8d800c383e4c92f39996343adedf635ae5206a684f94df8311 \ --hash=sha256:abaf30d18874310d4439a23a0afb6e4b5709c4266966401de7c4ae345cc810ee \ @@ -136,6 +104,7 @@ grpcio==1.33.2 \ --hash=sha256:c89510381cbf8c8317e14e747a8b53988ad226f0ed240824064a9297b65f921d \ --hash=sha256:d386630af995fd4de225d550b6806507ca09f5a650f227fddb29299335cda55e \ --hash=sha256:d51ddfb3d481a6a3439db09d4b08447fb9f6b60d862ab301238f37bea8f60a6d \ + --hash=sha256:dd47fac2878f6102efa211461eb6fa0a6dd7b4899cd1ade6cdcb9fa9748363eb \ --hash=sha256:eff55d318a114742ed2a06972f5daacfe3d5ad0c0c0d9146bcaf10acb427e6be \ --hash=sha256:f2673c51e8535401c68806d331faba614bcff3ee16373481158a2e74f510b7f6 \ --hash=sha256:fa78bd55ec652d4a88ba254c8dae623c9992e2ce647bd17ba1a37ca2b7b42222 \ @@ -149,17 +118,17 @@ importlib-metadata==2.0.0 \ --hash=sha256:77a540690e24b0305878c37ffd421785a6f7e53c8b5720d211b211de8d0e95da \ --hash=sha256:cefa1a2f919b866c5beb7c9f7b0ebb4061f30a8a9bf16d609b000e2dfaceb9c3 \ # via pluggy, pytest -ipaddress==1.0.23 \ - --hash=sha256:6e0f4a39e66cb5bb9a137b00276a2eff74f93b71dcbdad6f10ff7df9d3557fcc \ - --hash=sha256:b7f8e0369580bb4a24d5ba1d7cc29660a4a6987763faf1d8a8046830e020e7e2 \ - # via kubernetes +iniconfig==1.1.1 \ + --hash=sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3 \ + --hash=sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32 \ + # via pytest jinja2==2.11.2 \ --hash=sha256:89aab215427ef59c34ad58735269eb58b1a5808103067f7bb9d5836c651b3bb0 \ --hash=sha256:f0a4641d3cf955324a89c04f3d94663aa4d638abe8f733ecd3582848e1c37035 \ # via salt -kubernetes==12.0.0 \ - --hash=sha256:72f095a1cd593401ff26b3b8d71749340394ca6d8413770ea28ce18efd5bcf4c \ - --hash=sha256:9a339a32d6c79e6461cb6050c3662cb4e33058b508d8d34ee5d5206add395828 +kubernetes==12.0.1 \ + --hash=sha256:23c85d8571df8f56e773f1a413bc081537536dc47e2b5e8dc2e6262edb2c57ca \ + --hash=sha256:ec52ea01d52e2ec3da255992f7e859f3a76f2bdb51cf65ba8cd71dfc309d8daa markupsafe==1.1.1 \ --hash=sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473 \ --hash=sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161 \ @@ -198,15 +167,6 @@ markupsafe==1.1.1 \ mock==3.0.5 \ --hash=sha256:83657d894c90d5681d62155c82bda9c1187827525880eda8ff5df4ec813437c3 \ --hash=sha256:d157e52d4e5b938c550f39eb2fd15610db062441a9c2747d3dbfa9298211d0f8 -monotonic==1.5 \ - --hash=sha256:23953d55076df038541e648a53676fb24980f7a1be290cdda21300b3bc21dfb0 \ - --hash=sha256:552a91f381532e33cbd07c6a2655a21908088962bb8fa7239ecbcc6ad1140cc7 \ - # via tenacity -more-itertools==5.0.0 \ - --hash=sha256:38a936c0a6d98a38bcc2d03fdaaedaba9f412879461dd2ceff8d37564d6522e4 \ - --hash=sha256:c0a5785b1109a6bd7fac76d6837fd1feca158e54e521ccd2ae8bfe393cc9d4fc \ - --hash=sha256:fe7a7cae1ccb57d33952113ff4fa1bc5f879963600ed74918f1236e212ee50b9 \ - # via pytest msgpack==0.6.2 \ --hash=sha256:0cc7ca04e575ba34fea7cfcd76039f55def570e6950e4155a4174368142c8e1b \ --hash=sha256:187794cd1eb73acccd528247e3565f6760bd842d7dc299241f830024a7dd5610 \ @@ -241,47 +201,30 @@ packaging==20.4 \ parameterized==0.7.4 \ --hash=sha256:190f8cc7230eee0b56b30d7f074fd4d165f7c45e6077582d0813c8557e738490 \ --hash=sha256:59ab908e31c01505a987a2be78854e19cb1630c047bbab7848169c371d614d56 -pathlib2==2.3.5 \ - --hash=sha256:0ec8205a157c80d7acc301c0b18fbd5d44fe655968f5d947b6ecef5290fc35db \ - --hash=sha256:6cd9a47b597b37cc57de1c05e56fb1a1c9cc9fab04fe78c29acd090418529868 \ - # via importlib-metadata, pytest pluggy==0.13.1 \ --hash=sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0 \ --hash=sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d \ # via pytest -protobuf==3.13.0 \ - --hash=sha256:0bba42f439bf45c0f600c3c5993666fcb88e8441d011fad80a11df6f324eef33 \ - --hash=sha256:1e834076dfef9e585815757a2c7e4560c7ccc5962b9d09f831214c693a91b463 \ - --hash=sha256:339c3a003e3c797bc84499fa32e0aac83c768e67b3de4a5d7a5a9aa3b0da634c \ - --hash=sha256:361acd76f0ad38c6e38f14d08775514fbd241316cce08deb2ce914c7dfa1184a \ - --hash=sha256:3dee442884a18c16d023e52e32dd34a8930a889e511af493f6dc7d4d9bf12e4f \ - --hash=sha256:4d1174c9ed303070ad59553f435846a2f877598f59f9afc1b89757bdf846f2a7 \ - --hash=sha256:5db9d3e12b6ede5e601b8d8684a7f9d90581882925c96acf8495957b4f1b204b \ - --hash=sha256:6a82e0c8bb2bf58f606040cc5814e07715b2094caeba281e2e7d0b0e2e397db5 \ - --hash=sha256:8c35bcbed1c0d29b127c886790e9d37e845ffc2725cc1db4bd06d70f4e8359f4 \ - --hash=sha256:91c2d897da84c62816e2f473ece60ebfeab024a16c1751aaf31100127ccd93ec \ - --hash=sha256:9c2e63c1743cba12737169c447374fab3dfeb18111a460a8c1a000e35836b18c \ - --hash=sha256:9edfdc679a3669988ec55a989ff62449f670dfa7018df6ad7f04e8dbacb10630 \ - --hash=sha256:c0c5ab9c4b1eac0a9b838f1e46038c3175a95b0f2d944385884af72876bd6bc7 \ - --hash=sha256:c8abd7605185836f6f11f97b21200f8a864f9cb078a193fe3c9e235711d3ff1e \ - --hash=sha256:d69697acac76d9f250ab745b46c725edf3e98ac24763990b24d58c16c642947a \ - --hash=sha256:df3932e1834a64b46ebc262e951cd82c3cf0fa936a154f0a42231140d8237060 \ - --hash=sha256:e7662437ca1e0c51b93cadb988f9b353fa6b8013c0385d63a70c8a77d84da5f9 \ - --hash=sha256:f68eb9d03c7d84bd01c790948320b768de8559761897763731294e3bc316decb \ +protobuf==3.14.0 \ + --hash=sha256:0e247612fadda953047f53301a7b0407cb0c3cb4ae25a6fde661597a04039b3c \ + --hash=sha256:0fc96785262042e4863b3f3b5c429d4636f10d90061e1840fce1baaf59b1a836 \ + --hash=sha256:1c51fda1bbc9634246e7be6016d860be01747354ed7015ebe38acf4452f470d2 \ + --hash=sha256:1d63eb389347293d8915fb47bee0951c7b5dab522a4a60118b9a18f33e21f8ce \ + --hash=sha256:22bcd2e284b3b1d969c12e84dc9b9a71701ec82d8ce975fdda19712e1cfd4e00 \ + --hash=sha256:2a7e2fe101a7ace75e9327b9c946d247749e564a267b0515cf41dfe450b69bac \ + --hash=sha256:43b554b9e73a07ba84ed6cf25db0ff88b1e06be610b37656e292e3cbb5437472 \ + --hash=sha256:4b74301b30513b1a7494d3055d95c714b560fbb630d8fb9956b6f27992c9f980 \ + --hash=sha256:4e75105c9dfe13719b7293f75bd53033108f4ba03d44e71db0ec2a0e8401eafd \ + --hash=sha256:5b7a637212cc9b2bcf85dd828b1178d19efdf74dbfe1ddf8cd1b8e01fdaaa7f5 \ + --hash=sha256:5e9806a43232a1fa0c9cf5da8dc06f6910d53e4390be1fa06f06454d888a9142 \ + --hash=sha256:629b03fd3caae7f815b0c66b41273f6b1900a579e2ccb41ef4493a4f5fb84f3a \ + --hash=sha256:72230ed56f026dd664c21d73c5db73ebba50d924d7ba6b7c0d81a121e390406e \ + --hash=sha256:86a75477addde4918e9a1904e5c6af8d7b691f2a3f65587d73b16100fbe4c3b2 \ + --hash=sha256:8971c421dbd7aad930c9bd2694122f332350b6ccb5202a8b7b06f3f1a5c41ed5 \ + --hash=sha256:9616f0b65a30851e62f1713336c931fcd32c057202b7ff2cfbfca0fc7d5e3043 \ + --hash=sha256:b0d5d35faeb07e22a1ddf8dce620860c8fe145426c02d1a0ae2688c6e8ede36d \ + --hash=sha256:ecc33531a213eee22ad60e0e2aaea6c8ba0021f0cce35dbf0ab03dee6e2a23a1 \ # via etcd3 -psutil==5.7.3 \ - --hash=sha256:01bc82813fbc3ea304914581954979e637bcc7084e59ac904d870d6eb8bb2bc7 \ - --hash=sha256:1cd6a0c9fb35ece2ccf2d1dd733c1e165b342604c67454fd56a4c12e0a106787 \ - --hash=sha256:2cb55ef9591b03ef0104bedf67cc4edb38a3edf015cf8cf24007b99cb8497542 \ - --hash=sha256:56c85120fa173a5d2ad1d15a0c6e0ae62b388bfb956bb036ac231fbdaf9e4c22 \ - --hash=sha256:5d9106ff5ec2712e2f659ebbd112967f44e7d33f40ba40530c485cc5904360b8 \ - --hash=sha256:6a3e1fd2800ca45083d976b5478a2402dd62afdfb719b30ca46cd28bb25a2eb4 \ - --hash=sha256:ade6af32eb80a536eff162d799e31b7ef92ddcda707c27bbd077238065018df4 \ - --hash=sha256:af73f7bcebdc538eda9cc81d19db1db7bf26f103f91081d780bbacfcb620dee2 \ - --hash=sha256:e02c31b2990dcd2431f4524b93491941df39f99619b0d312dfe1d4d530b08b4b \ - --hash=sha256:fa38ac15dbf161ab1e941ff4ce39abd64b53fec5ddf60c23290daed2bc7d1157 \ - --hash=sha256:fbcac492cb082fa38d88587d75feb90785d05d7e12d4565cbf1ecc727aff71b7 \ - # via salttesting py==1.9.0 \ --hash=sha256:366389d1db726cd2fcfc79732e75410e5fe4d31db13692115529d34069a043c2 \ --hash=sha256:9ca6883ce56b4e8da7e79ac18787889fa5206c79dcc67fb065376cd2fe03f342 \ @@ -304,9 +247,9 @@ pyparsing==2.4.7 \ pytest-cov==2.10.1 \ --hash=sha256:45ec2d5182f89a81fc3eb29e3d1ed3113b9e9a873bcddb2a71faaab066110191 \ --hash=sha256:47bd0ce14056fdd79f93e1713f88fad7bdcc583dcd7783da86ef2f085a0bb88e -pytest==4.6.11 \ - --hash=sha256:50fa82392f2120cc3ec2ca0a75ee615be4c479e66669789771f1758332be4353 \ - --hash=sha256:a00a7d79cbbdfa9d21e7d0298392a8dd4123316bfac545075e6f8f24c94d8c97 +pytest==6.1.2 \ + --hash=sha256:4288fed0d9153d9646bfcdf0c0428197dba1ecb27a33bb6e031d002fa88653fe \ + --hash=sha256:c0a7e94a8cdbc5422a51ccdad8e6f1024795939cc89159a0ae7f0b316ad3823e python-dateutil==2.8.1 \ --hash=sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c \ --hash=sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a \ @@ -324,97 +267,69 @@ pyyaml==5.3.1 \ --hash=sha256:cc8955cfbfc7a115fa81d85284ee61147059a753344bc51098f3ccd69b0d7e0c \ --hash=sha256:d13155f591e6fcc1ec3b30685d50bf0711574e2c0dfffd7644babf8b5102ca1a \ # via kubernetes, salt -pyzmq==19.0.2 \ - --hash=sha256:00dca814469436455399660247d74045172955459c0bd49b54a540ce4d652185 \ - --hash=sha256:046b92e860914e39612e84fa760fc3f16054d268c11e0e25dcb011fb1bc6a075 \ - --hash=sha256:09d24a80ccb8cbda1af6ed8eb26b005b6743e58e9290566d2a6841f4e31fa8e0 \ - --hash=sha256:0a422fc290d03958899743db091f8154958410fc76ce7ee0ceb66150f72c2c97 \ - --hash=sha256:18189fc59ff5bf46b7ccf5a65c1963326dbfc85a2bc73e9f4a90a40322b992c8 \ - --hash=sha256:276ad604bffd70992a386a84bea34883e696a6b22e7378053e5d3227321d9702 \ - --hash=sha256:296540a065c8c21b26d63e3cea2d1d57902373b16e4256afe46422691903a438 \ - --hash=sha256:29d51279060d0a70f551663bc592418bcad7f4be4eea7b324f6dd81de05cb4c1 \ - --hash=sha256:36ab114021c0cab1a423fe6689355e8f813979f2c750968833b318c1fa10a0fd \ - --hash=sha256:3fa6debf4bf9412e59353defad1f8035a1e68b66095a94ead8f7a61ae90b2675 \ - --hash=sha256:5120c64646e75f6db20cc16b9a94203926ead5d633de9feba4f137004241221d \ - --hash=sha256:59f1e54627483dcf61c663941d94c4af9bf4163aec334171686cdaee67974fe5 \ - --hash=sha256:5d9fc809aa8d636e757e4ced2302569d6e60e9b9c26114a83f0d9d6519c40493 \ - --hash=sha256:654d3e06a4edc566b416c10293064732516cf8871a4522e0a2ba00cc2a2e600c \ - --hash=sha256:720d2b6083498a9281eaee3f2927486e9fe02cd16d13a844f2e95217f243efea \ - --hash=sha256:73483a2caaa0264ac717af33d6fb3f143d8379e60a422730ee8d010526ce1913 \ - --hash=sha256:8a6ada5a3f719bf46a04ba38595073df8d6b067316c011180102ba2a1925f5b5 \ - --hash=sha256:8b66b94fe6243d2d1d89bca336b2424399aac57932858b9a30309803ffc28112 \ - --hash=sha256:949a219493a861c263b75a16588eadeeeab08f372e25ff4a15a00f73dfe341f4 \ - --hash=sha256:99cc0e339a731c6a34109e5c4072aaa06d8e32c0b93dc2c2d90345dd45fa196c \ - --hash=sha256:a7e7f930039ee0c4c26e4dfee015f20bd6919cd8b97c9cd7afbde2923a5167b6 \ - --hash=sha256:ab0d01148d13854de716786ca73701012e07dff4dfbbd68c4e06d8888743526e \ - --hash=sha256:b1dd4cf4c5e09cbeef0aee83f3b8af1e9986c086a8927b261c042655607571e8 \ - --hash=sha256:c1a31cd42905b405530e92bdb70a8a56f048c8a371728b8acf9d746ecd4482c0 \ - --hash=sha256:c20dd60b9428f532bc59f2ef6d3b1029a28fc790d408af82f871a7db03e722ff \ - --hash=sha256:c36ffe1e5aa35a1af6a96640d723d0d211c5f48841735c2aa8d034204e87eb87 \ - --hash=sha256:c40fbb2b9933369e994b837ee72193d6a4c35dfb9a7c573257ef7ff28961272c \ - --hash=sha256:c6d653bab76b3925c65d4ac2ddbdffe09710f3f41cc7f177299e8c4498adb04a \ - --hash=sha256:d46fb17f5693244de83e434648b3dbb4f4b0fec88415d6cbab1c1452b6f2ae17 \ - --hash=sha256:e36f12f503511d72d9bdfae11cadbadca22ff632ff67c1b5459f69756a029c19 \ - --hash=sha256:f1a25a61495b6f7bb986accc5b597a3541d9bd3ef0016f50be16dbb32025b302 \ - --hash=sha256:fa411b1d8f371d3a49d31b0789eb6da2537dadbb2aef74a43aa99a78195c3f76 \ +pyzmq==20.0.0 \ + --hash=sha256:03638e46d486dd1c118e03c8bf9c634bdcae679600eac6573ae1e54906de7c2f \ + --hash=sha256:0af84f34f27b5c6a0e906c648bdf46d4caebf9c8e6e16db0728f30a58141cad6 \ + --hash=sha256:0e554fd390021edbe0330b67226325a820b0319c5b45e1b0a59bf22ccc36e793 \ + --hash=sha256:1e9b75a119606732023a305d1c214146c09a91f8116f6aff3e8b7d0a60b6f0ff \ + --hash=sha256:225774a48ed7414c0395335e7123ef8c418dbcbe172caabdc2496133b03254c2 \ + --hash=sha256:2742e380d186673eee6a570ef83d4568741945434ba36d92b98d36cdbfedbd44 \ + --hash=sha256:309d763d89ec1845c0e0fa14e1fb6558fd8c9ef05ed32baec27d7a8499cc7bb0 \ + --hash=sha256:46250789730489009fe139cbf576679557c070a6a3628077d09a4153d52fd381 \ + --hash=sha256:4d9259a5eb3f71abbaf61f165cacf42240bfeea3783bebd8255341abdfe206f1 \ + --hash=sha256:523d542823cabb94065178090e05347bd204365f6e7cb260f0071c995d392fc2 \ + --hash=sha256:5efe02bdcc5eafcac0aab531292294298f0ab8d28ed43be9e507d0e09173d1a4 \ + --hash=sha256:63ee08e35be72fdd7568065a249a5b5cf51a2e8ab6ee63cf9f73786fcb9e710b \ + --hash=sha256:6e24907857c80dc67692e31f5bf3ad5bf483ee0142cec95b3d47e2db8c43bdda \ + --hash=sha256:7113eb93dcd0a5750c65d123ed0099e036a3a3f2dcb48afedd025ffa125c983b \ + --hash=sha256:824ad5888331aadeac772bce27e1c2fbcab82fade92edbd234542c4e12f0dca9 \ + --hash=sha256:895695be380f0f85d2e3ec5ccf68a93c92d45bd298567525ad5633071589872c \ + --hash=sha256:b62113eeb9a0649cebed9b21fd578f3a0175ef214a2a91dcb7b31bbf55805295 \ + --hash=sha256:bc7dd697356b31389d5118b9bcdef3e8d8079e8181800c4e8d72dccd56e1ff68 \ + --hash=sha256:bf755905a7d30d2749079611b9a89924c1f2da2695dc09ce221f42122c9808e3 \ + --hash=sha256:c63fafd2556d218368c51d18588f8e6f8d86d09d493032415057faf6de869b34 \ + --hash=sha256:c95dda497a7c1b1e734b5e8353173ca5dd7b67784d8821d13413a97856588057 \ + --hash=sha256:cc09c5cd1a4332611c8564d65e6a432dc6db3e10793d0254da9fa1e31d9ffd6d \ + --hash=sha256:cfa54a162a7b32641665e99b2c12084555afe9fc8fe80ec8b2f71a57320d10e1 \ + --hash=sha256:d81184489369ec325bd50ba1c935361e63f31f578430b9ad95471899361a8253 \ + --hash=sha256:d92c7f41a53ece82b91703ea433c7d34143248cf0cead33aa11c5fc621c764bf \ + --hash=sha256:f0beef935efe78a63c785bb21ed56c1c24448511383e3994927c8bb2caf5e714 \ + --hash=sha256:f110a4d3f8f01209eec304ed542f6c8054cce9b0f16dfe3d571e57c290e4e133 \ # via salt requests-oauthlib==1.3.0 \ --hash=sha256:7f71572defaecd16372f9006f33c2ec8c077c3cfa6f5911a9a90202beb513f3d \ --hash=sha256:b4261601a71fd721a8bd6d7aa1cc1d6a8a93b4a9f5e96626f8e4d91e8beeaa6a \ # via kubernetes -requests==2.24.0 \ - --hash=sha256:b3559a131db72c33ee969480840fff4bb6dd111de7dd27c8ee1f820f4f00231b \ - --hash=sha256:fe75cc94a9443b9246fc7049224f75604b113c36acb93f87b80ed42c44cbb898 \ +requests==2.25.0 \ + --hash=sha256:7f1a0b932f4a60a1a65caa4263921bb7d9ee911957e0ae4a23a6dd08185ad5f8 \ + --hash=sha256:e786fa28d8c9154e6a4de5d46a1d921b8749f8b74e28bde23768e5e16eece998 \ # via kubernetes, requests-oauthlib, salt -rsa==4.5 \ - --hash=sha256:35c5b5f6675ac02120036d97cf96f1fde4d49670543db2822ba5015e21a18032 \ - --hash=sha256:4d409f5a7d78530a4a2062574c7bd80311bc3af29b364e293aa9b03eea77714f \ +rsa==4.6 \ + --hash=sha256:109ea5a66744dd859bf16fe904b8d8b627adafb9408753161e766a92e7d681fa \ + --hash=sha256:6166864e23d6b5195a5cfed6cd9fed0fe774e226d8f854fcb23b7bbef0350233 \ # via google-auth salt==3000.5 \ --hash=sha256:486310fca787eecbb0dd04d71af9ac0a163607f81719f815f8d4daa1c2b71bff -salttesting==2018.9.21 \ - --hash=sha256:57fce93298319bafd996a144dda39d686787e2f5236922c49b69a261960c518f -scandir==1.10.0 \ - --hash=sha256:2586c94e907d99617887daed6c1d102b5ca28f1085f90446554abf1faf73123e \ - --hash=sha256:2ae41f43797ca0c11591c0c35f2f5875fa99f8797cb1a1fd440497ec0ae4b022 \ - --hash=sha256:2b8e3888b11abb2217a32af0766bc06b65cc4a928d8727828ee68af5a967fa6f \ - --hash=sha256:2c712840c2e2ee8dfaf36034080108d30060d759c7b73a01a52251cc8989f11f \ - --hash=sha256:4d4631f6062e658e9007ab3149a9b914f3548cb38bfb021c64f39a025ce578ae \ - --hash=sha256:67f15b6f83e6507fdc6fca22fedf6ef8b334b399ca27c6b568cbfaa82a364173 \ - --hash=sha256:7d2d7a06a252764061a020407b997dd036f7bd6a175a5ba2b345f0a357f0b3f4 \ - --hash=sha256:8c5922863e44ffc00c5c693190648daa6d15e7c1207ed02d6f46a8dcc2869d32 \ - --hash=sha256:92c85ac42f41ffdc35b6da57ed991575bdbe69db895507af88b9f499b701c188 \ - --hash=sha256:b24086f2375c4a094a6b51e78b4cf7ca16c721dcee2eddd7aa6494b42d6d519d \ - --hash=sha256:cb925555f43060a1745d0a321cca94bcea927c50114b623d73179189a4e100ac \ - # via pathlib2 -singledispatch==3.4.0.3 \ - --hash=sha256:5b06af87df13818d14f08a028e42f566640aef80805c3b50c5056b086e3c2b9c \ - --hash=sha256:833b46966687b3de7f438c761ac475213e53b306740f1abfaa86e1d1aae56aa8 \ - # via salt six==1.15.0 \ --hash=sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259 \ --hash=sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced \ - # via etcd3, google-auth, grpcio, kubernetes, mock, more-itertools, packaging, pathlib2, protobuf, pytest, python-dateutil, salttesting, singledispatch, tenacity, websocket-client + # via etcd3, google-auth, grpcio, kubernetes, mock, packaging, protobuf, python-dateutil, tenacity, websocket-client tenacity==6.2.0 \ --hash=sha256:29ae90e7faf488a8628432154bb34ace1cca58244c6ea399fd33f066ac71339a \ --hash=sha256:5a5d3dcd46381abe8b4f82b5736b8726fd3160c6c7161f53f8af7f1eb9b82173 \ # via etcd3 -typing==3.7.4.3 \ - --hash=sha256:1187fb9c82fd670d10aa07bbb6cfcfe4bdda42d6fab8d5134f04e8c4d0b71cc9 \ - --hash=sha256:283d868f5071ab9ad873e5e52268d611e851c870a2ba354193026f2dfb29d8b5 \ - # via tenacity -urllib3==1.25.11 \ - --hash=sha256:8d7eaa5a82a1cac232164990f04874c594c9453ec55eef02eab885aa02fc17a2 \ - --hash=sha256:f5321fbe4bf3fefa0efd0bfe7fb14e90909eb62a48ccda331726b4319897dd5e -wcwidth==0.2.5 \ - --hash=sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784 \ - --hash=sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83 \ +toml==0.10.2 \ + --hash=sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b \ + --hash=sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f \ # via pytest +urllib3==1.26.2 \ + --hash=sha256:19188f96923873c92ccb987120ec4acaa12f0461fa9ce5d3d0772bc965a39e08 \ + --hash=sha256:d8ff90d979214d7b4f8ce956e80f4028fc6860e4431f731ea4a8c08f23f99473 websocket-client==0.57.0 \ --hash=sha256:0fc45c961324d79c781bab301359d5a1b00b13ad1b10415a4780229ef71a5549 \ --hash=sha256:d735b91d6d1692a6a181f2a8c9e0238e5f6373356f561bb9dc4c7af36f452010 \ # via kubernetes -zipp==1.2.0 \ - --hash=sha256:c70410551488251b0fee67b460fb9a536af8d6f9f008ad10ac51f615b6a521b1 \ - --hash=sha256:e0d9e63797e483a30d27e09fffd308c59a700d365ec34e93cc100844168bf921 \ +zipp==3.4.0 \ + --hash=sha256:102c24ef8f171fd729d46599845e95c7ab894a4cf45f5de11a44cc7444fb1108 \ + --hash=sha256:ed5eee1974372595f9e416cc7bbeeb12335201d8081ca8a0743c954d4446e5cb \ # via importlib-metadata diff --git a/salt/tests/unit/mixins.py b/salt/tests/unit/mixins.py new file mode 100644 index 0000000000..d182ff9f0b --- /dev/null +++ b/salt/tests/unit/mixins.py @@ -0,0 +1,77 @@ +# Copied from +# https://github.com/saltstack/salt-testing/blob/develop/salttesting/mixins.py + +import copy +from unittest.mock import patch + + +class _FixLoaderModuleMockMixinMroOrder(type): + ''' + This metaclass will make sure that LoaderModuleMockMixin will always come + as the first base class in order for LoaderModuleMockMixin.setUp to + actually run. + ''' + def __new__(mcs, cls_name, cls_bases, cls_dict): + if cls_name == 'LoaderModuleMockMixin': + return super(_FixLoaderModuleMockMixinMroOrder, mcs).__new__( + mcs, cls_name, cls_bases, cls_dict + ) + bases = list(cls_bases) + for idx, base in enumerate(bases): + if base.__name__ == 'LoaderModuleMockMixin': + bases.insert(0, bases.pop(idx)) + break + return super(_FixLoaderModuleMockMixinMroOrder, mcs).__new__( + mcs, cls_name, tuple(bases), cls_dict + ) + + +class LoaderModuleMockMixin(metaclass=_FixLoaderModuleMockMixinMroOrder): + def setUp(self): + loader_module = getattr(self, 'loader_module', None) + if loader_module is not None: + loader_module_name = loader_module.__name__ + loader_module_globals = getattr( + self, 'loader_module_globals', None + ) + loader_module_blacklisted_dunders = getattr( + self, 'loader_module_blacklisted_dunders', () + ) + if loader_module_globals is None: + loader_module_globals = {} + elif callable(loader_module_globals): + loader_module_globals = loader_module_globals() + else: + loader_module_globals = copy.deepcopy(loader_module_globals) + + salt_dunders = ( + '__opts__', '__salt__', '__runner__', '__context__', + '__utils__', '__ext_pillar__', '__thorium__', '__states__', + '__serializers__', '__ret__', '__grains__', '__pillar__', + '__sdb__', + # Proxy is commented out on purpose since some code in salt + # expects a NameError and is most of the time not a required + # dunder + # '__proxy__' + ) + for dunder_name in salt_dunders: + if dunder_name not in loader_module_globals: + if dunder_name in loader_module_blacklisted_dunders: + continue + loader_module_globals[dunder_name] = {} + + for key in loader_module_globals: + if not hasattr(loader_module, key): + if key in salt_dunders: + setattr(loader_module, key, {}) + else: + setattr(loader_module, key, None) + + if loader_module_globals: + patcher = patch.multiple( + loader_module_name, **loader_module_globals + ) + patcher.start() + self.addCleanup(patcher.stop) + + super(LoaderModuleMockMixin, self).setUp() diff --git a/salt/tests/unit/mocks/kubernetes.py b/salt/tests/unit/mocks/kubernetes.py index 907a6fb957..d886b93a7f 100644 --- a/salt/tests/unit/mocks/kubernetes.py +++ b/salt/tests/unit/mocks/kubernetes.py @@ -6,9 +6,9 @@ """ import contextlib import copy +from unittest.mock import MagicMock, patch from salt.utils import dictupdate -from salttesting.mock import MagicMock, patch from tests.unit import utils diff --git a/salt/tests/unit/modules/files/test_metalk8s_kubernetes_utils.yaml b/salt/tests/unit/modules/files/test_metalk8s_kubernetes_utils.yaml index 462274a67a..40cf3d9c8f 100644 --- a/salt/tests/unit/modules/files/test_metalk8s_kubernetes_utils.yaml +++ b/salt/tests/unit/modules/files/test_metalk8s_kubernetes_utils.yaml @@ -208,4 +208,4 @@ get_service_endpoints: uid: fad86410-00d9-43c2-b91c-8288b18b0337 subsets: null raises: True - result: "Unable to get kubernetes endpoints for my_service in namespace my_namespace:\n'NoneType' object has no attribute '__getitem__'" + result: "Unable to get kubernetes endpoints for my_service in namespace my_namespace:\n'NoneType' object is not subscriptable" diff --git a/salt/tests/unit/modules/test_containerd.py b/salt/tests/unit/modules/test_containerd.py index 169495f917..0b85e48bb3 100644 --- a/salt/tests/unit/modules/test_containerd.py +++ b/salt/tests/unit/modules/test_containerd.py @@ -1,15 +1,15 @@ +from unittest import TestCase +from unittest.mock import MagicMock, patch + from parameterized import parameterized -from salttesting.mixins import LoaderModuleMockMixin -from salttesting.unit import TestCase -from salttesting.mock import MagicMock, patch +import containerd +from tests.unit import mixins from tests.unit import utils -import containerd - -class ContainerdTestCase(TestCase, LoaderModuleMockMixin): +class ContainerdTestCase(TestCase, mixins.LoaderModuleMockMixin): """ TestCase for `containerd` module """ diff --git a/salt/tests/unit/modules/test_cri.py b/salt/tests/unit/modules/test_cri.py index a5d174202e..3528206307 100644 --- a/salt/tests/unit/modules/test_cri.py +++ b/salt/tests/unit/modules/test_cri.py @@ -1,15 +1,14 @@ import json +from unittest import TestCase +from unittest.mock import MagicMock, patch from parameterized import parameterized -from salttesting.mixins import LoaderModuleMockMixin -from salttesting.unit import TestCase -from salttesting.mock import MagicMock, patch +import cri +from tests.unit import mixins from tests.unit import utils -import cri - IMAGES_LIST = [{ "id": "sha256:da86e6ba6ca197bf6bc5e9d900febd906b133eaa4750e6bed647b0fbe50ed43e", @@ -62,7 +61,7 @@ }] -class CriTestCase(TestCase, LoaderModuleMockMixin): +class CriTestCase(TestCase, mixins.LoaderModuleMockMixin): """ TestCase for `cri` module """ diff --git a/salt/tests/unit/modules/test_metalk8s.py b/salt/tests/unit/modules/test_metalk8s.py index a541c20b8e..fc2fd4c400 100644 --- a/salt/tests/unit/modules/test_metalk8s.py +++ b/salt/tests/unit/modules/test_metalk8s.py @@ -1,18 +1,16 @@ import os.path -import yaml +from unittest import TestCase +from unittest.mock import MagicMock, mock_open, patch from parameterized import param, parameterized - from salt.exceptions import CommandExecutionError +import yaml -from salttesting.mixins import LoaderModuleMockMixin -from salttesting.unit import TestCase -from salttesting.mock import MagicMock, mock_open, patch +import metalk8s +from tests.unit import mixins from tests.unit import utils -import metalk8s - YAML_TESTS_FILE = os.path.join( os.path.dirname(os.path.abspath(__file__)), @@ -33,7 +31,7 @@ ''' -class Metalk8sTestCase(TestCase, LoaderModuleMockMixin): +class Metalk8sTestCase(TestCase, mixins.LoaderModuleMockMixin): """ TestCase for `metalk8s` module """ @@ -115,7 +113,7 @@ def test_minions_by_role(self, nodes, role, result, with patch.dict(metalk8s.__pillar__, pillar_dict): if raises: - self.assertRaisesRegexp( + self.assertRaisesRegex( CommandExecutionError, result, metalk8s.minions_by_role, @@ -143,7 +141,7 @@ def test_archive_info_from_tree(self, product, result, raises=False): with patch("os.path.isfile", is_file_mock), \ patch("salt.utils.files.fopen", open_file_mock): if raises: - self.assertRaisesRegexp( + self.assertRaisesRegex( CommandExecutionError, result, metalk8s.archive_info_from_tree, @@ -183,7 +181,7 @@ def test_archive_info_from_iso(self, product, result, raises=False): with patch.dict(metalk8s.__salt__, {'cmd.run_all': iso_info_cmd_mock}): if raises: - self.assertRaisesRegexp( + self.assertRaisesRegex( CommandExecutionError, result, metalk8s.archive_info_from_iso, @@ -228,7 +226,7 @@ def test_get_archives(self, archives, infos, result, patch("metalk8s.archive_info_from_iso", infos_mock), \ patch.dict(metalk8s.__pillar__, pillar_dict): if raises: - self.assertRaisesRegexp( + self.assertRaisesRegex( CommandExecutionError, result, metalk8s.get_archives, @@ -254,7 +252,7 @@ def test_check_pillar_keys(self, keys, result, raises=False, with patch("metalk8s.get_pillar", pillar_get_mock), \ patch.dict(metalk8s.__pillar__, pillar_content or {}): if raises: - self.assertRaisesRegexp( + self.assertRaisesRegex( CommandExecutionError, result, metalk8s.check_pillar_keys, @@ -296,7 +294,7 @@ def test_format_slots(self, data, result, slots_returns=None, with patch.dict(metalk8s.__salt__, salt_dict): if raises: - self.assertRaisesRegexp( + self.assertRaisesRegex( CommandExecutionError, result, metalk8s.format_slots, diff --git a/salt/tests/unit/modules/test_metalk8s_checks.py b/salt/tests/unit/modules/test_metalk8s_checks.py index 1717793213..c338df75fa 100644 --- a/salt/tests/unit/modules/test_metalk8s_checks.py +++ b/salt/tests/unit/modules/test_metalk8s_checks.py @@ -1,16 +1,14 @@ import os.path -import yaml +from unittest import TestCase +from unittest.mock import MagicMock, patch from parameterized import parameterized - from salt.exceptions import CheckError - -from salttesting.mixins import LoaderModuleMockMixin -from salttesting.unit import TestCase -from salttesting.mock import MagicMock, patch +import yaml import metalk8s_checks +from tests.unit import mixins from tests.unit import utils @@ -22,7 +20,7 @@ YAML_TESTS_CASES = yaml.safe_load(fd) -class Metalk8sChecksTestCase(TestCase, LoaderModuleMockMixin): +class Metalk8sChecksTestCase(TestCase, mixins.LoaderModuleMockMixin): """ TestCase for `metalk8s_checks` module """ @@ -47,7 +45,7 @@ def test_sysctl(self, params, data, result, raises=False): with patch.dict(metalk8s_checks.__salt__, patch_dict): if raises: - self.assertRaisesRegexp( + self.assertRaisesRegex( CheckError, result, metalk8s_checks.sysctl, diff --git a/salt/tests/unit/modules/test_metalk8s_cordon.py b/salt/tests/unit/modules/test_metalk8s_cordon.py index fdb42147de..6b2592c166 100644 --- a/salt/tests/unit/modules/test_metalk8s_cordon.py +++ b/salt/tests/unit/modules/test_metalk8s_cordon.py @@ -1,16 +1,16 @@ -from parameterized import parameterized +from unittest import TestCase +from unittest.mock import MagicMock, patch +from parameterized import parameterized import salt from salt.exceptions import CommandExecutionError -from salttesting.mixins import LoaderModuleMockMixin -from salttesting.unit import TestCase -from salttesting.mock import MagicMock, patch - import metalk8s_cordon +from tests.unit import mixins + -class Metalk8sCordonTestCase(TestCase, LoaderModuleMockMixin): +class Metalk8sCordonTestCase(TestCase, mixins.LoaderModuleMockMixin): """ TestCase for `metalk8s_cordon` module """ @@ -59,7 +59,7 @@ def test_check_deps_fail(self): Tests the unavailability of `metalk8s_kubernetes.update_object` module in salt """ - self.assertRaisesRegexp( + self.assertRaisesRegex( CommandExecutionError, "'metalk8s_kubernetes.update_object' is not available", metalk8s_cordon._check_deps) diff --git a/salt/tests/unit/modules/test_metalk8s_drain.py b/salt/tests/unit/modules/test_metalk8s_drain.py index 95628410d9..6d0dc076a2 100644 --- a/salt/tests/unit/modules/test_metalk8s_drain.py +++ b/salt/tests/unit/modules/test_metalk8s_drain.py @@ -1,7 +1,10 @@ # Standard library +from importlib import reload import json import logging import os.path +from unittest import TestCase +from unittest.mock import MagicMock, patch # Runtime dependencies from kubernetes.client.rest import ApiException @@ -10,10 +13,6 @@ # Test dependencies from parameterized import parameterized -from salttesting.mixins import LoaderModuleMockMixin -from salttesting.unit import TestCase -from salttesting.mock import MagicMock, patch -from salttesting.helpers import ForceImportErrorOn import yaml # Runtime modules @@ -21,8 +20,9 @@ # Test modules from tests.unit.log_utils import capture_logs, check_captured_logs -from tests.unit.utils import parameterized_from_cases +from tests.unit import mixins from tests.unit.mocks import kubernetes as mock_kubernetes +from tests.unit import utils YAML_TESTS_FILE = os.path.join( @@ -33,7 +33,7 @@ YAML_TESTS_CASES = yaml.safe_load(fd) -class Metalk8sDrainTestCase(TestCase, LoaderModuleMockMixin): +class Metalk8sDrainTestCase(TestCase, mixins.LoaderModuleMockMixin): """Tests for `metalk8s_drain` execution module.""" loader_module = metalk8s_drain @@ -59,7 +59,7 @@ def test_virtual_nominal(self): ]) def test_virtual_fail_import(self, _, package): """Behaviour for `__virtual__` on failed imports.""" - with ForceImportErrorOn(package): + with utils.ForceImportErrorOn(package): reload(metalk8s_drain) self.assertTupleEqual( metalk8s_drain.__virtual__(), @@ -83,7 +83,7 @@ def test_exception_formatting(self): "<> too slow!" ) - @parameterized_from_cases(YAML_TESTS_CASES['evict_pod']) + @utils.parameterized_from_cases(YAML_TESTS_CASES['evict_pod']) def test_evict_pod(self, result, raises=False, create_raises=False, create_error_status=None, create_error_body=None, log_lines=None, **kwargs): @@ -112,7 +112,7 @@ def _create_mock(*args, **kwargs): with patch.dict(metalk8s_drain.__utils__, utils_dict), \ capture_logs(metalk8s_drain.log, logging.DEBUG) as captured: if raises: - self.assertRaisesRegexp( + self.assertRaisesRegex( CommandExecutionError, result, metalk8s_drain.evict_pod, @@ -153,7 +153,7 @@ def test_node_drain(self, _, cordon_raises): with patch.dict(metalk8s_drain.__salt__, salt_dict), \ patch("metalk8s_drain.Drain", drain_cls_mock): if cordon_raises: - self.assertRaisesRegexp( + self.assertRaisesRegex( CommandExecutionError, result, metalk8s_drain.node_drain, @@ -167,7 +167,7 @@ def test_node_drain(self, _, cordon_raises): run_drain_mock.assert_called_once() -class DrainTestCase(TestCase, LoaderModuleMockMixin): +class DrainTestCase(TestCase, mixins.LoaderModuleMockMixin): """Tests for the `Drain` interface used by the `metalk8s_drain` module. These are split from the main execution module tests, as we can consider @@ -226,7 +226,7 @@ def seed_api_mock(self, dataset=None, events=None): self.api_mock.seed(YAML_TESTS_CASES['datasets'][dataset]) self.time_mock = self.api_mock.time_mock_from_events(events or {}) - @parameterized_from_cases(YAML_TESTS_CASES['drain']['nominal']) + @utils.parameterized_from_cases(YAML_TESTS_CASES['drain']['nominal']) def test_nominal(self, node_name, dataset, pods_to_evict, events=None, log_lines=None, **kwargs): self.seed_api_mock(dataset, events) @@ -244,7 +244,7 @@ def test_nominal(self, node_name, dataset, pods_to_evict, events=None, set(pods_to_evict) ) - @parameterized_from_cases(YAML_TESTS_CASES['drain']['dry-run']) + @utils.parameterized_from_cases(YAML_TESTS_CASES['drain']['dry-run']) def test_dry_run(self, node_name, dataset, pods_to_evict, **kwargs): self.seed_api_mock(dataset) drainer = metalk8s_drain.Drain(node_name, **kwargs) @@ -261,7 +261,7 @@ def test_dry_run(self, node_name, dataset, pods_to_evict, **kwargs): self.assertEqual(result, expected_result) self.evict_pod_mock.assert_not_called() - @parameterized_from_cases(YAML_TESTS_CASES['drain']['eviction-filters']) + @utils.parameterized_from_cases(YAML_TESTS_CASES['drain']['eviction-filters']) def test_eviction_filters(self, node_name, dataset, pods_to_evict, log_lines=None, raises=False, raise_msg=None, **kwargs): @@ -270,7 +270,7 @@ def test_eviction_filters(self, node_name, dataset, pods_to_evict, with capture_logs(metalk8s_drain.log, logging.WARNING) as captured: if raises: - self.assertRaisesRegexp( + self.assertRaisesRegex( CommandExecutionError, "The following are not deletable: {}".format(raise_msg), drainer.run_drain, @@ -287,7 +287,7 @@ def test_eviction_filters(self, node_name, dataset, pods_to_evict, check_captured_logs(captured, log_lines) - @parameterized_from_cases(YAML_TESTS_CASES['drain']['eviction-retry']) + @utils.parameterized_from_cases(YAML_TESTS_CASES['drain']['eviction-retry']) def test_eviction_retry(self, node_name, dataset, eviction_attempts, events=None, **kwargs): """Check that eviction temporary failures (429) will be retried.""" @@ -300,7 +300,7 @@ def test_eviction_retry(self, node_name, dataset, eviction_attempts, self.assertEqual(result, "Eviction complete.") self.assertEqual(self.evict_pod_mock.call_count, eviction_attempts) - @parameterized_from_cases( + @utils.parameterized_from_cases( YAML_TESTS_CASES['drain']['waiting-for-eviction'] ) def test_waiting_for_eviction(self, node_name, dataset, sleep_time, @@ -315,27 +315,27 @@ def test_waiting_for_eviction(self, node_name, dataset, sleep_time, self.assertEqual(result, "Eviction complete.") self.assertEqual(self.time_mock.time(), sleep_time) - @parameterized_from_cases(YAML_TESTS_CASES['drain']['timeout']) + @utils.parameterized_from_cases(YAML_TESTS_CASES['drain']['timeout']) def test_timeout(self, node_name, dataset, **kwargs): """Check different sources of timeout.""" self.seed_api_mock(dataset) drainer = metalk8s_drain.Drain(node_name, timeout=10, **kwargs) with self.time_mock.patch(): - self.assertRaisesRegexp( + self.assertRaisesRegex( CommandExecutionError, "Drain did not complete within 10 seconds", drainer.run_drain, ) - @parameterized_from_cases(YAML_TESTS_CASES['drain']['eviction-error']) + @utils.parameterized_from_cases(YAML_TESTS_CASES['drain']['eviction-error']) def test_eviction_error(self, node_name, dataset, **kwargs): """Check that errors when evicting are stopping the drain process.""" self.seed_api_mock(dataset) drainer = metalk8s_drain.Drain(node_name, **kwargs) with self.time_mock.patch(): - self.assertRaisesRegexp( + self.assertRaisesRegex( CommandExecutionError, "Failed to evict pod", drainer.run_drain, diff --git a/salt/tests/unit/modules/test_metalk8s_etcd.py b/salt/tests/unit/modules/test_metalk8s_etcd.py index 51cf42b12e..ed5a5920c9 100644 --- a/salt/tests/unit/modules/test_metalk8s_etcd.py +++ b/salt/tests/unit/modules/test_metalk8s_etcd.py @@ -1,14 +1,15 @@ -from parameterized import parameterized +from importlib import reload +from unittest import TestCase +from unittest.mock import MagicMock, patch +from parameterized import parameterized from salt.exceptions import CommandExecutionError -from salttesting.mixins import LoaderModuleMockMixin -from salttesting.unit import TestCase -from salttesting.mock import MagicMock, patch -from salttesting.helpers import ForceImportErrorOn - import metalk8s_etcd +from tests.unit import mixins +from tests.unit import utils + MEMBERS_LIST_DICT = [{ "client_urls": [ "https://10.11.12.13:2379" @@ -36,7 +37,7 @@ member.name = MEMBERS_LIST_DICT[i]["name"] -class Metalk8sEtcdTestCase(TestCase, LoaderModuleMockMixin): +class Metalk8sEtcdTestCase(TestCase, mixins.LoaderModuleMockMixin): """ TestCase for `metalk8s_etcd` module """ @@ -53,7 +54,7 @@ def test_virtual_fail_import(self): """ Tests the return of `__virtual__` function, unable to import etcd3 """ - with ForceImportErrorOn("etcd3"): + with utils.ForceImportErrorOn("etcd3"): reload(metalk8s_etcd) self.assertTupleEqual( metalk8s_etcd.__virtual__(), @@ -101,7 +102,7 @@ def _etcd_status(): patch("etcd3.client", etcd3_mock), \ patch("etcd3.exceptions.ConnectionFailedError", Exception): if raises: - self.assertRaisesRegexp( + self.assertRaisesRegex( Exception, result, metalk8s_etcd._get_endpoint_up, @@ -208,7 +209,7 @@ def _etcd_status(): MagicMock(return_value=endpoint)): minion_id = "minion1" if cp_ips else None if raises: - self.assertRaisesRegexp( + self.assertRaisesRegex( CommandExecutionError, result, metalk8s_etcd.check_etcd_health, diff --git a/salt/tests/unit/modules/test_metalk8s_grafana.py b/salt/tests/unit/modules/test_metalk8s_grafana.py index 408adca390..e29b442c29 100644 --- a/salt/tests/unit/modules/test_metalk8s_grafana.py +++ b/salt/tests/unit/modules/test_metalk8s_grafana.py @@ -1,15 +1,14 @@ import json import os.path -import yaml +from unittest import TestCase +from unittest.mock import MagicMock, patch from parameterized import param, parameterized - -from salttesting.mixins import LoaderModuleMockMixin -from salttesting.unit import TestCase -from salttesting.mock import MagicMock, patch +import yaml import metalk8s_grafana +from tests.unit import mixins from tests.unit import utils YAML_TESTS_FILE = os.path.join( @@ -20,7 +19,7 @@ YAML_TESTS_CASES = yaml.safe_load(fd) -class Metalk8sGrafanaTestCase(TestCase, LoaderModuleMockMixin): +class Metalk8sGrafanaTestCase(TestCase, mixins.LoaderModuleMockMixin): """ TestCase for `metalk8s_grafana` module """ @@ -45,7 +44,7 @@ def test_load_dashboard(self, dashboard, result, raises=False, **kwargs): } with patch.dict(metalk8s_grafana.__salt__, patch_dict): if raises: - self.assertRaisesRegexp( + self.assertRaisesRegex( AssertionError, result, metalk8s_grafana.load_dashboard, @@ -53,11 +52,9 @@ def test_load_dashboard(self, dashboard, result, raises=False, **kwargs): **kwargs ) else: - self.assertDictContainsSubset( - result, - metalk8s_grafana.load_dashboard( - path="my_dashboard.json", - **kwargs - ) + actual = metalk8s_grafana.load_dashboard( + path="my_dashboard.json", + **kwargs ) + self.assertEqual(dict(actual, **result), actual) diff --git a/salt/tests/unit/modules/test_metalk8s_kubernetes.py b/salt/tests/unit/modules/test_metalk8s_kubernetes.py index edb5e27788..ffbcefdd45 100644 --- a/salt/tests/unit/modules/test_metalk8s_kubernetes.py +++ b/salt/tests/unit/modules/test_metalk8s_kubernetes.py @@ -1,19 +1,17 @@ +from importlib import reload import os.path -import yaml - -from parameterized import param, parameterized +from unittest import TestCase +from unittest.mock import MagicMock, patch from kubernetes.client.rest import ApiException +from parameterized import param, parameterized from salt.utils import dictupdate, hashutils from salt.exceptions import CommandExecutionError - -from salttesting.mixins import LoaderModuleMockMixin -from salttesting.unit import TestCase -from salttesting.mock import MagicMock, patch -from salttesting.helpers import ForceImportErrorOn +import yaml import metalk8s_kubernetes +from tests.unit import mixins from tests.unit import utils @@ -25,7 +23,7 @@ YAML_TESTS_CASES = yaml.safe_load(fd) -class Metalk8sKubernetesTestCase(TestCase, LoaderModuleMockMixin): +class Metalk8sKubernetesTestCase(TestCase, mixins.LoaderModuleMockMixin): """ TestCase for `metalk8s_kubernetes` module """ @@ -107,6 +105,9 @@ def _hashutil_digest(instr, checksum="md5"): '__salt__': salt_obj } + def assertDictContainsSubset(self, subdict, maindict): + return self.assertEqual(dict(maindict, **subdict), maindict) + def test_virtual_success(self): """ Tests the return of `__virtual__` function, success @@ -125,7 +126,7 @@ def test_virtual_fail_import(self, import_error_on, dep_error=None): """ Tests the return of `__virtual__` function, fail import """ - with ForceImportErrorOn(import_error_on): + with utils.ForceImportErrorOn(import_error_on): reload(metalk8s_kubernetes) self.assertEqual( metalk8s_kubernetes.__virtual__(), @@ -200,7 +201,7 @@ def _create_mock(body, **_): with patch.dict(metalk8s_kubernetes.__utils__, utils_dict), \ patch.dict(metalk8s_kubernetes.__salt__, salt_dict): if raises: - self.assertRaisesRegexp( + self.assertRaisesRegex( Exception, result, metalk8s_kubernetes.create_object, @@ -215,7 +216,7 @@ def _create_mock(body, **_): if called_with: self.assertDictContainsSubset( called_with, - create_mock.call_args.kwargs + create_mock.call_args[1] ) @utils.parameterized_from_cases( @@ -273,7 +274,7 @@ def _delete_mock(name, **_): with patch.dict(metalk8s_kubernetes.__utils__, utils_dict), \ patch.dict(metalk8s_kubernetes.__salt__, salt_dict): if raises: - self.assertRaisesRegexp( + self.assertRaisesRegex( Exception, result, metalk8s_kubernetes.delete_object, @@ -288,7 +289,7 @@ def _delete_mock(name, **_): if called_with: self.assertDictContainsSubset( called_with, - delete_mock.call_args.kwargs + delete_mock.call_args[1] ) @utils.parameterized_from_cases( @@ -343,7 +344,7 @@ def _replace_mock(body, **_): with patch.dict(metalk8s_kubernetes.__utils__, utils_dict), \ patch.dict(metalk8s_kubernetes.__salt__, salt_dict): if raises: - self.assertRaisesRegexp( + self.assertRaisesRegex( Exception, result, metalk8s_kubernetes.replace_object, @@ -358,7 +359,7 @@ def _replace_mock(body, **_): if called_with: self.assertDictContainsSubset( called_with, - replace_mock.call_args.kwargs + replace_mock.call_args[1] ) @utils.parameterized_from_cases( @@ -416,7 +417,7 @@ def _retrieve_mock(name, **_): with patch.dict(metalk8s_kubernetes.__utils__, utils_dict), \ patch.dict(metalk8s_kubernetes.__salt__, salt_dict): if raises: - self.assertRaisesRegexp( + self.assertRaisesRegex( Exception, result, metalk8s_kubernetes.get_object, @@ -431,7 +432,7 @@ def _retrieve_mock(name, **_): if called_with: self.assertDictContainsSubset( called_with, - retrieve_mock.call_args.kwargs + retrieve_mock.call_args[1] ) @utils.parameterized_from_cases( @@ -485,7 +486,7 @@ def _update_mock(body, **_): with patch.dict(metalk8s_kubernetes.__utils__, utils_dict), \ patch.dict(metalk8s_kubernetes.__salt__, salt_dict): if raises: - self.assertRaisesRegexp( + self.assertRaisesRegex( Exception, result, metalk8s_kubernetes.update_object, @@ -500,7 +501,7 @@ def _update_mock(body, **_): if called_with: self.assertDictContainsSubset( called_with, - update_mock.call_args.kwargs + update_mock.call_args[1] ) @parameterized.expand([ @@ -565,7 +566,7 @@ def _list_mock(**_): } with patch.dict(metalk8s_kubernetes.__utils__, utils_dict): if raises: - self.assertRaisesRegexp( + self.assertRaisesRegex( Exception, result, metalk8s_kubernetes.list_objects, @@ -580,7 +581,7 @@ def _list_mock(**_): if called_with: self.assertDictContainsSubset( called_with, - list_mock.call_args.kwargs + list_mock.call_args[1] ) @parameterized.expand( @@ -596,7 +597,7 @@ def test_get_object_digest(self, obj, result, raises=False, with patch("metalk8s_kubernetes.get_object", get_obj_mock): if raises: - self.assertRaisesRegexp( + self.assertRaisesRegex( Exception, result, metalk8s_kubernetes.get_object_digest, diff --git a/salt/tests/unit/modules/test_metalk8s_kubernetes_utils.py b/salt/tests/unit/modules/test_metalk8s_kubernetes_utils.py index e885312fed..b860346fe5 100644 --- a/salt/tests/unit/modules/test_metalk8s_kubernetes_utils.py +++ b/salt/tests/unit/modules/test_metalk8s_kubernetes_utils.py @@ -1,19 +1,16 @@ +from importlib import reload import os.path -import yaml - -from parameterized import param, parameterized +from unittest import TestCase +from unittest.mock import MagicMock, mock_open, patch from kubernetes.client.rest import ApiException - +from parameterized import param, parameterized from salt.exceptions import CommandExecutionError - -from salttesting.mixins import LoaderModuleMockMixin -from salttesting.unit import TestCase -from salttesting.mock import MagicMock, mock_open, patch -from salttesting.helpers import ForceImportErrorOn +import yaml import metalk8s_kubernetes_utils +from tests.unit import mixins from tests.unit import utils @@ -25,7 +22,7 @@ YAML_TESTS_CASES = yaml.safe_load(fd) -class Metalk8sKubernetesUtilsTestCase(TestCase, LoaderModuleMockMixin): +class Metalk8sKubernetesUtilsTestCase(TestCase, mixins.LoaderModuleMockMixin): """ TestCase for `metalk8s_kubernetes_utils` module """ @@ -50,7 +47,7 @@ def test_virtual_fail_import(self, import_error_on, dep_error=None): """ Tests the return of `__virtual__` function, fail import """ - with ForceImportErrorOn(import_error_on): + with utils.ForceImportErrorOn(import_error_on): reload(metalk8s_kubernetes_utils) self.assertTupleEqual( metalk8s_kubernetes_utils.__virtual__(), @@ -120,7 +117,7 @@ def test_get_version_info( "kubernetes.config.new_client_from_config", MagicMock() ), patch("kubernetes.client.VersionApi", api_instance_mock): if raises: - self.assertRaisesRegexp( + self.assertRaisesRegex( CommandExecutionError, result, metalk8s_kubernetes_utils.get_version_info @@ -192,7 +189,7 @@ def test_read_and_render_yaml_file( patch.dict(metalk8s_kubernetes_utils.__salt__, patch_dict), \ patch("salt.utils.files.fopen", open_file_mock): if raises: - self.assertRaisesRegexp( + self.assertRaisesRegex( CommandExecutionError, result, metalk8s_kubernetes_utils.read_and_render_yaml_file, @@ -233,7 +230,7 @@ def test_get_service_endpoints(self, obj, result, raises=False): with patch.dict(metalk8s_kubernetes_utils.__salt__, salt_dict): if raises: - self.assertRaisesRegexp( + self.assertRaisesRegex( CommandExecutionError, result, metalk8s_kubernetes_utils.get_service_endpoints, diff --git a/salt/tests/unit/modules/test_metalk8s_monitoring.py b/salt/tests/unit/modules/test_metalk8s_monitoring.py index 15e20cb762..1411f88b33 100644 --- a/salt/tests/unit/modules/test_metalk8s_monitoring.py +++ b/salt/tests/unit/modules/test_metalk8s_monitoring.py @@ -1,17 +1,19 @@ from datetime import datetime +from importlib import reload import os.path +from unittest.mock import MagicMock, patch +from unittest import TestCase -from salt.exceptions import CommandExecutionError from parameterized import param, parameterized -from salttesting.helpers import ForceImportErrorOn -from salttesting.mixins import LoaderModuleMockMixin -from salttesting.mock import MagicMock, patch -from salttesting.unit import TestCase +from salt.exceptions import CommandExecutionError import yaml import metalk8s_monitoring +from tests.unit import mixins +from tests.unit import utils + YAML_TESTS_FILE = os.path.join( os.path.dirname(os.path.abspath(__file__)), @@ -28,7 +30,7 @@ def _custom_name_func(testcase_func, _, param): ) -class Metalk8sMonitoringTestCase(TestCase, LoaderModuleMockMixin): +class Metalk8sMonitoringTestCase(TestCase, mixins.LoaderModuleMockMixin): """Tests for `metalk8s_monitoring` module.""" loader_module = metalk8s_monitoring @@ -42,7 +44,7 @@ def test_virtual_nominal(self): def test_virtual_missing_deps(self): """Test the behaviour of `__virtual__` when missing dependencies.""" - with ForceImportErrorOn("requests"): + with utils.ForceImportErrorOn("requests"): reload(metalk8s_monitoring) self.assertTupleEqual( metalk8s_monitoring.__virtual__(), @@ -87,7 +89,7 @@ def test_alertmanager_api_helper( with patch.dict(metalk8s_monitoring.__utils__, utils_mocks), \ patch.dict(metalk8s_monitoring.__salt__, salt_mocks): if raises: - self.assertRaisesRegexp( + self.assertRaisesRegex( CommandExecutionError, result, metalk8s_monitoring._requests_alertmanager_api, @@ -104,9 +106,9 @@ def test_alertmanager_api_helper( session_mock.request.assert_called_once() if called_with: - call = session_mock.request.call_args - self.assertEqual(call.args, tuple(called_with['args'])) - self.assertEqual(call.kwargs, called_with.get('kwargs', {})) + args, kwargs = session_mock.request.call_args + self.assertEqual(args, tuple(called_with['args'])) + self.assertEqual(kwargs, called_with.get('kwargs', {})) @parameterized.expand([ param.explicit(kwargs=test_case) @@ -138,9 +140,9 @@ def test_add_silence(self, _id, value, call_body, now_mock=None, **kwargs): ) request_mock.assert_called_once() - self.assertDictContainsSubset( - call_body, request_mock.call_args.kwargs['json'] - ) + _, call_kwargs = request_mock.call_args + actual_body = call_kwargs['json'] + self.assertEqual(dict(actual_body, **call_body), actual_body) def test_delete_silence(self): silence_id = 'd287796c-cf59-4d10-8e5b-d5cc3ff51b9c' @@ -152,7 +154,7 @@ def test_delete_silence(self): request_mock.assert_called_once() self.assertEqual( - request_mock.call_args.args, + request_mock.call_args[0], ('api/v1/silence/d287796c-cf59-4d10-8e5b-d5cc3ff51b9c', 'DELETE'), ) diff --git a/salt/tests/unit/modules/test_metalk8s_network.py b/salt/tests/unit/modules/test_metalk8s_network.py index 43a7c3b917..4404073a73 100644 --- a/salt/tests/unit/modules/test_metalk8s_network.py +++ b/salt/tests/unit/modules/test_metalk8s_network.py @@ -1,15 +1,15 @@ -from parameterized import parameterized +from unittest import TestCase +from unittest.mock import MagicMock, patch +from parameterized import parameterized from salt.exceptions import CommandExecutionError -from salttesting.mixins import LoaderModuleMockMixin -from salttesting.unit import TestCase -from salttesting.mock import MagicMock, patch - import metalk8s_network +from tests.unit import mixins + -class Metalk8sNetworkTestCase(TestCase, LoaderModuleMockMixin): +class Metalk8sNetworkTestCase(TestCase, mixins.LoaderModuleMockMixin): """ TestCase for `metalk8s_network` module """ @@ -51,7 +51,7 @@ def test_get_kubernetes_service_ip_raise(self, service_ip, error_msg): with patch.dict( metalk8s_network.__pillar__, {'networks': {'service': service_ip}}): - self.assertRaisesRegexp( + self.assertRaisesRegex( CommandExecutionError, error_msg, metalk8s_network.get_kubernetes_service_ip @@ -77,7 +77,7 @@ def test_get_cluster_dns_ip_raise(self, service_ip, error_msg): with patch.dict( metalk8s_network.__pillar__, {'networks': {'service': service_ip}}): - self.assertRaisesRegexp( + self.assertRaisesRegex( CommandExecutionError, error_msg, metalk8s_network.get_cluster_dns_ip @@ -103,7 +103,7 @@ def test_get_oidc_service_ip_raise(self, service_ip, error_msg): with patch.dict( metalk8s_network.__pillar__, {'networks': {'service': service_ip}}): - self.assertRaisesRegexp( + self.assertRaisesRegex( CommandExecutionError, error_msg, metalk8s_network.get_oidc_service_ip @@ -143,7 +143,7 @@ def _get_ip_addrs(cidr): with patch.dict(metalk8s_network.__salt__, salt_dict): if raises: - self.assertRaisesRegexp( + self.assertRaisesRegex( CommandExecutionError, result, metalk8s_network.get_ip_from_cidrs, @@ -183,7 +183,7 @@ def _read_mtu_file(path): with patch.dict(metalk8s_network.__salt__, salt_dict): if raises: - self.assertRaisesRegexp( + self.assertRaisesRegex( CommandExecutionError, result, metalk8s_network.get_mtu_from_ip, diff --git a/salt/tests/unit/modules/test_metalk8s_package_manager_yum.py b/salt/tests/unit/modules/test_metalk8s_package_manager_yum.py index a644ed3a14..433c9241e4 100644 --- a/salt/tests/unit/modules/test_metalk8s_package_manager_yum.py +++ b/salt/tests/unit/modules/test_metalk8s_package_manager_yum.py @@ -1,19 +1,17 @@ +from importlib import reload import os.path -import yaml +from unittest import TestCase +from unittest.mock import MagicMock, patch from parameterized import param, parameterized - from salt.exceptions import CommandExecutionError +import yaml -from salttesting.mixins import LoaderModuleMockMixin -from salttesting.unit import TestCase -from salttesting.mock import MagicMock, patch -from salttesting.helpers import ForceImportErrorOn +import metalk8s_package_manager_yum +from tests.unit import mixins from tests.unit import utils -import metalk8s_package_manager_yum - YAML_TESTS_FILE = os.path.join( os.path.dirname(os.path.abspath(__file__)), @@ -23,7 +21,7 @@ YAML_TESTS_CASES = yaml.safe_load(fd) -class Metalk8sPackageManagerYumTestCase(TestCase, LoaderModuleMockMixin): +class Metalk8sPackageManagerYumTestCase(TestCase, mixins.LoaderModuleMockMixin): """ TestCase for `metalk8s_package_manager_yum` module """ @@ -165,7 +163,7 @@ def _yum_install_cmd(command): with patch.dict(metalk8s_package_manager_yum.__salt__, salt_dict): if raise_msg: - self.assertRaisesRegexp( + self.assertRaisesRegex( CommandExecutionError, raise_msg, metalk8s_package_manager_yum.check_pkg_availability, diff --git a/salt/tests/unit/modules/test_metalk8s_service_configuration.py b/salt/tests/unit/modules/test_metalk8s_service_configuration.py index dbea76aab3..fad74fc60a 100644 --- a/salt/tests/unit/modules/test_metalk8s_service_configuration.py +++ b/salt/tests/unit/modules/test_metalk8s_service_configuration.py @@ -1,16 +1,16 @@ import os.path -import yaml +from unittest import TestCase +from unittest.mock import MagicMock, patch from parameterized import param, parameterized - from salt.exceptions import CommandExecutionError - -from salttesting.mixins import LoaderModuleMockMixin -from salttesting.unit import TestCase -from salttesting.mock import MagicMock, patch +import yaml import metalk8s_service_configuration +from tests.unit import mixins + + YAML_TESTS_FILE = os.path.join( os.path.dirname(os.path.abspath(__file__)), "files", "test_metalk8s_service_configuration.yaml" @@ -19,7 +19,9 @@ YAML_TESTS_CASES = yaml.safe_load(fd) -class Metalk8sServiceConfigurationTestCase(TestCase, LoaderModuleMockMixin): +class Metalk8sServiceConfigurationTestCase( + TestCase, mixins.LoaderModuleMockMixin +): """ TestCase for `metalk8s_service_configuration` module """ @@ -69,7 +71,7 @@ def test_get_service_conf( with patch.dict(metalk8s_service_configuration.__salt__, salt_dict): if raises: - self.assertRaisesRegexp( + self.assertRaisesRegex( CommandExecutionError, result, metalk8s_service_configuration.get_service_conf, diff --git a/salt/tests/unit/modules/test_metalk8s_solutions.py b/salt/tests/unit/modules/test_metalk8s_solutions.py index 43657445f1..00b758f339 100644 --- a/salt/tests/unit/modules/test_metalk8s_solutions.py +++ b/salt/tests/unit/modules/test_metalk8s_solutions.py @@ -1,17 +1,15 @@ import errno import os.path -import yaml +from unittest import TestCase +from unittest.mock import MagicMock, mock_open, patch from parameterized import param, parameterized - from salt.exceptions import CommandExecutionError - -from salttesting.mixins import LoaderModuleMockMixin -from salttesting.unit import TestCase -from salttesting.mock import MagicMock, mock_open, patch +import yaml import metalk8s_solutions +from tests.unit import mixins from tests.unit import utils @@ -23,7 +21,7 @@ YAML_TESTS_CASES = yaml.safe_load(fd) -class Metalk8sSolutionsTestCase(TestCase, LoaderModuleMockMixin): +class Metalk8sSolutionsTestCase(TestCase, mixins.LoaderModuleMockMixin): """ TestCase for `metalk8s_solutions` module """ @@ -52,7 +50,7 @@ def test_read_config(self, create=False, config=None, result=None, with patch("metalk8s_solutions.open", open_mock), \ patch("metalk8s_solutions._write_config_file", MagicMock()): if raises: - self.assertRaisesRegexp( + self.assertRaisesRegex( CommandExecutionError, result, metalk8s_solutions.read_config @@ -89,7 +87,7 @@ def _write_config_file_mock(new_config): patch("metalk8s_solutions._write_config_file", write_config_file_mock): if raises: - self.assertRaisesRegexp( + self.assertRaisesRegex( CommandExecutionError, "Failed to write Solutions config file", metalk8s_solutions.configure_archive, @@ -124,7 +122,7 @@ def _yaml_safe_dump_mock(data, _): patch("metalk8s_solutions.open", mock_open()), \ patch("yaml.safe_dump", yaml_safe_dump_mock): if raises: - self.assertRaisesRegexp( + self.assertRaisesRegex( CommandExecutionError, result, metalk8s_solutions.activate_solution, @@ -165,7 +163,7 @@ def _yaml_safe_dump_mock(data, _): patch("yaml.safe_dump", yaml_safe_dump_mock), \ patch("metalk8s_solutions.open", mock_open()): if raises: - self.assertRaisesRegexp( + self.assertRaisesRegex( CommandExecutionError, "Failed to write Solutions config file", metalk8s_solutions.deactivate_solution, @@ -216,14 +214,14 @@ def _listdir_mock(path): with patch("os.path.isdir", path_isdir_mock), \ patch("os.listdir", listdir_mock): if raises: - self.assertRaisesRegexp( + self.assertRaisesRegex( CommandExecutionError, result, metalk8s_solutions.list_solution_images, mountpoint ) else: - self.assertItemsEqual( + self.assertEqual( metalk8s_solutions.list_solution_images(mountpoint), result ) @@ -244,7 +242,7 @@ def test_read_solution_manifest(self, manifest=None, result=None, patch("metalk8s_solutions.list_solution_images", list_solution_images_mock): if raises: - self.assertRaisesRegexp( + self.assertRaisesRegex( CommandExecutionError, result, metalk8s_solutions.read_solution_manifest, @@ -272,7 +270,7 @@ def _cmd_run_all_mock(**_): path = '/tmp/my-solution.iso' with patch.dict(metalk8s_solutions.__salt__, patch_dict): if raises: - self.assertRaisesRegexp( + self.assertRaisesRegex( CommandExecutionError, result, metalk8s_solutions.manifest_from_iso, @@ -302,7 +300,7 @@ def test_list_available(self, mountpoints=None, archive_infos=None, patch("metalk8s_solutions.read_solution_manifest", read_solution_manifest_mock): if raises: - self.assertRaisesRegexp( + self.assertRaisesRegex( Exception, 'Path has no "product.txt"', metalk8s_solutions.list_available @@ -328,7 +326,7 @@ def test_operator_roles_from_manifest(self, manifest=None, result=None, with patch("os.path.isfile", path_isfile_mock), \ patch("salt.utils.files.fopen", fopen_mock): if raises: - self.assertRaisesRegexp( + self.assertRaisesRegex( CommandExecutionError, result, metalk8s_solutions.operator_roles_from_manifest, diff --git a/salt/tests/unit/modules/test_metalk8s_solutions_k8s.py b/salt/tests/unit/modules/test_metalk8s_solutions_k8s.py index 6dc704945f..fab641c427 100644 --- a/salt/tests/unit/modules/test_metalk8s_solutions_k8s.py +++ b/salt/tests/unit/modules/test_metalk8s_solutions_k8s.py @@ -1,14 +1,13 @@ import os.path -import yaml +from unittest import TestCase +from unittest.mock import MagicMock, patch from parameterized import param, parameterized - -from salttesting.mixins import LoaderModuleMockMixin -from salttesting.unit import TestCase -from salttesting.mock import MagicMock, patch +import yaml import metalk8s_solutions_k8s +from tests.unit import mixins from tests.unit import utils @@ -20,7 +19,7 @@ YAML_TESTS_CASES = yaml.safe_load(fd) -class Metalk8sSolutionsK8sTestCase(TestCase, LoaderModuleMockMixin): +class Metalk8sSolutionsK8sTestCase(TestCase, mixins.LoaderModuleMockMixin): """ TestCase for `metalk8s_solutions_k8s` module """ diff --git a/salt/tests/unit/modules/test_metalk8s_volumes.py b/salt/tests/unit/modules/test_metalk8s_volumes.py index 21f1f09374..65a98447d4 100644 --- a/salt/tests/unit/modules/test_metalk8s_volumes.py +++ b/salt/tests/unit/modules/test_metalk8s_volumes.py @@ -1,17 +1,16 @@ import os.path -import yaml +from unittest import TestCase +from unittest.mock import MagicMock, patch +from parameterized import param, parameterized from salt.exceptions import CommandExecutionError +import yaml -from parameterized import param, parameterized -from salttesting.mixins import LoaderModuleMockMixin -from salttesting.unit import TestCase -from salttesting.mock import MagicMock, patch +import metalk8s_volumes +from tests.unit import mixins from tests.unit import utils -import metalk8s_volumes - YAML_TESTS_FILE = os.path.join( os.path.dirname(os.path.abspath(__file__)), @@ -23,7 +22,7 @@ def device_name_mock(path): return {'success': True, 'result': os.path.basename(path)} -class Metalk8sVolumesTestCase(TestCase, LoaderModuleMockMixin): +class Metalk8sVolumesTestCase(TestCase, mixins.LoaderModuleMockMixin): """ TestCase for `metalk8s_volumes` module """ @@ -64,7 +63,7 @@ def test_exists(self, name, result, raises=False, pillar_volumes=None, patch("os.path.isfile", is_file_mock), \ patch("os.path.getsize", get_size_mock): if raises: - self.assertRaisesRegexp( + self.assertRaisesRegex( ValueError, result, metalk8s_volumes.exists, @@ -102,7 +101,7 @@ def test_create(self, name, raise_msg=None, pillar_volumes=None, patch("os.unlink", MagicMock()), \ patch("os.ftruncate", ftruncate_mock): if raise_msg: - self.assertRaisesRegexp( + self.assertRaisesRegex( Exception, raise_msg, metalk8s_volumes.create, @@ -152,7 +151,7 @@ def _device_name(path): patch("metalk8s_volumes.device_name", _device_name), \ patch("glob.glob", glob_mock): if raises: - self.assertRaisesRegexp( + self.assertRaisesRegex( Exception, result, metalk8s_volumes.is_prepared, @@ -212,7 +211,7 @@ def test_prepare(self, name, raise_msg=False, patch("metalk8s_volumes.device_name", device_name_mock), \ patch("glob.glob", glob_mock): if raise_msg: - self.assertRaisesRegexp( + self.assertRaisesRegex( Exception, raise_msg, metalk8s_volumes.prepare, @@ -243,7 +242,7 @@ def test_is_cleaned_up(self, name, result, raises=False, patch("metalk8s_volumes.device_name", device_name_mock), \ patch("glob.glob", glob_mock): if raises: - self.assertRaisesRegexp( + self.assertRaisesRegex( Exception, result, metalk8s_volumes.is_cleaned_up, @@ -277,7 +276,7 @@ def test_clean_up(self, name, raise_msg=False, pillar_volumes=None, patch("metalk8s_volumes.device_name", device_name_mock), \ patch("os.remove", remove_mock): if raise_msg: - self.assertRaisesRegexp( + self.assertRaisesRegex( Exception, raise_msg, metalk8s_volumes.clean_up, @@ -333,7 +332,7 @@ def test_device_info(self, name, result, raises=False, patch("metalk8s_volumes.device_name", device_name_mock), \ patch("glob.glob", glob_mock): if raises: - self.assertRaisesRegexp( + self.assertRaisesRegex( Exception, result, metalk8s_volumes.device_info, diff --git a/salt/tests/unit/utils.py b/salt/tests/unit/utils.py index fa5598a103..1333487192 100644 --- a/salt/tests/unit/utils.py +++ b/salt/tests/unit/utils.py @@ -1,6 +1,7 @@ """ Utils, helpers for testing """ +import builtins import functools import operator @@ -36,3 +37,86 @@ def get_dict_element(data, path, delimiter="."): return functools.reduce( operator.getitem, split_path(path, delimiter), data ) + + +# Copied from +# https://github.com/saltstack/salt-testing/blob/develop/salttesting/helpers.py +class ForceImportErrorOn(object): + ''' + This class is meant to be used in mock'ed test cases which require an + ``ImportError`` to be raised. + >>> import os.path + >>> with ForceImportErrorOn('os.path'): + ... import os.path + ... + Traceback (most recent call last): + File "", line 2, in + File "salttesting/helpers.py", line 263, in __import__ + 'Forced ImportError raised for {0!r}'.format(name) + ImportError: Forced ImportError raised for 'os.path' + >>> + >>> with ForceImportErrorOn(('os', 'path')): + ... import os.path + ... sys.modules.pop('os', None) + ... from os import path + ... + + Traceback (most recent call last): + File "", line 4, in + File "salttesting/helpers.py", line 288, in __fake_import__ + name, ', '.join(fromlist) + ImportError: Forced ImportError raised for 'from os import path' + >>> + >>> with ForceImportErrorOn(('os', 'path'), 'os.path'): + ... import os.path + ... sys.modules.pop('os', None) + ... from os import path + ... + Traceback (most recent call last): + File "", line 2, in + File "salttesting/helpers.py", line 281, in __fake_import__ + 'Forced ImportError raised for {0!r}'.format(name) + ImportError: Forced ImportError raised for 'os.path' + >>> + ''' + def __init__(self, *module_names): + self.__module_names = {} + for entry in module_names: + if isinstance(entry, (list, tuple)): + modname = entry[0] + self.__module_names[modname] = set(entry[1:]) + else: + self.__module_names[entry] = None + + def patch_import_function(self): + self.__original_import = builtins.__import__ + builtins.__import__ = self.__fake_import__ + + def restore_import_funtion(self): + builtins.__import__ = self.__original_import + + def __fake_import__(self, name, globals_, locals_, fromlist, level=-1): + if name in self.__module_names: + importerror_fromlist = self.__module_names.get(name) + if importerror_fromlist is None: + raise ImportError( + 'Forced ImportError raised for {0!r}'.format(name) + ) + + if importerror_fromlist.intersection(set(fromlist)): + raise ImportError( + 'Forced ImportError raised for {0!r}'.format( + 'from {0} import {1}'.format( + name, ', '.join(fromlist) + ) + ) + ) + + return self.__original_import(name, globals_, locals_, fromlist, level) + + def __enter__(self): + self.patch_import_function() + return self + + def __exit__(self, exc_type, exc_value, traceback): + self.restore_import_funtion() diff --git a/tox.ini b/tox.ini index 636cbc349b..fa8c0afa5c 100644 --- a/tox.ini +++ b/tox.ini @@ -40,18 +40,6 @@ commands = {posargs:--upgrade} \ -o "{toxinidir}/tests/requirements.txt" \ "{toxinidir}/tests/requirements.in" - -[testenv:pip-compile2] -basepython = python2 -description = - Update the requirements.txt files for python2. -skip_install = true -deps = - pip==19.0.3 - pip-tools==3.6.0 -setenv = - CUSTOM_COMPILE_COMMAND = tox -e pip-compile2 -commands = pip-compile \ --index --emit-trusted-host --annotate --generate-hashes \ {posargs:--upgrade} \ @@ -79,7 +67,6 @@ omit = salt/_modules/metalk8s_package_manager_apt.py [testenv:unit-tests] -basepython = python2 description = Run Python unit tests. deps = From e7359475830520e5137cce2147bc73b874121d92 Mon Sep 17 00:00:00 2001 From: Guillaume Demonet Date: Mon, 16 Nov 2020 14:26:49 +0100 Subject: [PATCH 06/13] salt: Prevent invalid escape sequence warnings We need to pass `\;` to the `isoinfo` binary for reading file contents from an ISO archive, but this escape sequence is not valid in Python, and Python 3 warns about it. We could have escaped the backslash, but instead rely on the raw string notation for Python 3 (`r'my \escaped sequence'`). --- salt/_modules/metalk8s.py | 2 +- salt/_modules/metalk8s_solutions.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/salt/_modules/metalk8s.py b/salt/_modules/metalk8s.py index f905485451..0eddc39028 100644 --- a/salt/_modules/metalk8s.py +++ b/salt/_modules/metalk8s.py @@ -171,7 +171,7 @@ def archive_info_from_iso(path): cmd = ' '.join([ 'isoinfo', - '-x', '/PRODUCT.TXT\;1', + '-x', r'/PRODUCT.TXT\;1', '-i', '"{}"'.format(path), ]) result = __salt__['cmd.run_all'](cmd=cmd) diff --git a/salt/_modules/metalk8s_solutions.py b/salt/_modules/metalk8s_solutions.py index ac7556426c..ef8e7aeb10 100644 --- a/salt/_modules/metalk8s_solutions.py +++ b/salt/_modules/metalk8s_solutions.py @@ -302,7 +302,7 @@ def manifest_from_iso(path): cmd = ' '.join([ 'isoinfo', - '-x', '/{}\;1'.format(SOLUTION_MANIFEST.upper()), + '-x', r'/{}\;1'.format(SOLUTION_MANIFEST.upper()), '-i', '"{}"'.format(path), ]) result = __salt__['cmd.run_all'](cmd=cmd) From cf5df11c666d80d35906e6c852615f86217f29f5 Mon Sep 17 00:00:00 2001 From: Teddy Andrieux Date: Mon, 16 Nov 2020 15:33:06 +0100 Subject: [PATCH 07/13] build,tests: Bump salt to `3002.2` --- buildchain/buildchain/versions.py | 2 +- images/salt-master/Dockerfile | 2 +- salt/tests/requirements.in | 2 +- salt/tests/requirements.txt | 89 ++++++++++++++++++++++--------- 4 files changed, 66 insertions(+), 29 deletions(-) diff --git a/buildchain/buildchain/versions.py b/buildchain/buildchain/versions.py index 90e540dffb..68a9e452ff 100644 --- a/buildchain/buildchain/versions.py +++ b/buildchain/buildchain/versions.py @@ -19,7 +19,7 @@ CALICO_VERSION : str = '3.16.1' K8S_VERSION : str = '1.18.12' -SALT_VERSION : str = '3000.5' +SALT_VERSION : str = '3002.2' CONTAINERD_VERSION : str = '1.4.1' CONTAINERD_RELEASE : str = '1.el7' diff --git a/images/salt-master/Dockerfile b/images/salt-master/Dockerfile index 590d52701b..4fb0c0868c 100644 --- a/images/salt-master/Dockerfile +++ b/images/salt-master/Dockerfile @@ -3,7 +3,7 @@ FROM centos:7.6.1810 MAINTAINER moonshot-platform # Versions to use -ARG SALT_VERSION=3000.5 +ARG SALT_VERSION=3002.2 # Install saltstack RUN printf "[saltstack-repo]\n\ diff --git a/salt/tests/requirements.in b/salt/tests/requirements.in index b834becf74..459d2a9f0b 100644 --- a/salt/tests/requirements.in +++ b/salt/tests/requirements.in @@ -1,6 +1,6 @@ pytest pytest-cov -salt == 3000.5 +salt == 3002.2 mock == 3.0.5 parameterized == 0.7.4 etcd3 != 0.11.0 diff --git a/salt/tests/requirements.txt b/salt/tests/requirements.txt index 97d521340a..1dbdc1588d 100644 --- a/salt/tests/requirements.txt +++ b/salt/tests/requirements.txt @@ -56,6 +56,10 @@ coverage==5.3 \ --hash=sha256:cedb2f9e1f990918ea061f28a0f0077a07702e3819602d3507e2ff98c8d20636 \ --hash=sha256:e8caf961e1b1a945db76f1b5fa9c91498d15f545ac0ababbe575cfab185d3bd8 \ # via pytest-cov +distro==1.5.0 \ + --hash=sha256:0e58756ae38fbd8fc3020d54badb8eae17c5b9dcbed388b17bb55b8a5928df92 \ + --hash=sha256:df74eed763e18d10d0da624258524ae80486432cd17392d9c3d96f5e83cd2799 \ + # via salt etcd3==0.12.0 \ --hash=sha256:89a704cb389bf0a010a1fa050ce19342d23bf6371ebda1c21cfe8ff3ed488726 google-auth==1.23.0 \ @@ -167,28 +171,25 @@ markupsafe==1.1.1 \ mock==3.0.5 \ --hash=sha256:83657d894c90d5681d62155c82bda9c1187827525880eda8ff5df4ec813437c3 \ --hash=sha256:d157e52d4e5b938c550f39eb2fd15610db062441a9c2747d3dbfa9298211d0f8 -msgpack==0.6.2 \ - --hash=sha256:0cc7ca04e575ba34fea7cfcd76039f55def570e6950e4155a4174368142c8e1b \ - --hash=sha256:187794cd1eb73acccd528247e3565f6760bd842d7dc299241f830024a7dd5610 \ - --hash=sha256:1904b7cb65342d0998b75908304a03cb004c63ef31e16c8c43fee6b989d7f0d7 \ - --hash=sha256:229a0ccdc39e9b6c6d1033cd8aecd9c296823b6c87f0de3943c59b8bc7c64bee \ - --hash=sha256:24149a75643aeaa81ece4259084d11b792308a6cf74e796cbb35def94c89a25a \ - --hash=sha256:30b88c47e0cdb6062daed88ca283b0d84fa0d2ad6c273aa0788152a1c643e408 \ - --hash=sha256:32fea0ea3cd1ef820286863a6202dcfd62a539b8ec3edcbdff76068a8c2cc6ce \ - --hash=sha256:355f7fd0f90134229eaeefaee3cf42e0afc8518e8f3cd4b25f541a7104dcb8f9 \ - --hash=sha256:4abdb88a9b67e64810fb54b0c24a1fd76b12297b4f7a1467d85a14dd8367191a \ - --hash=sha256:757bd71a9b89e4f1db0622af4436d403e742506dbea978eba566815dc65ec895 \ - --hash=sha256:76df51492bc6fa6cc8b65d09efdb67cbba3cbfe55004c3afc81352af92b4a43c \ - --hash=sha256:774f5edc3475917cd95fe593e625d23d8580f9b48b570d8853d06cac171cd170 \ - --hash=sha256:8a3ada8401736df2bf497f65589293a86c56e197a80ae7634ec2c3150a2f5082 \ - --hash=sha256:a06efd0482a1942aad209a6c18321b5e22d64eb531ea20af138b28172d8f35ba \ - --hash=sha256:b24afc52e18dccc8c175de07c1d680bdf315844566f4952b5bedb908894bec79 \ - --hash=sha256:b8b4bd3dafc7b92608ae5462add1c8cc881851c2d4f5d8977fdea5b081d17f21 \ - --hash=sha256:c6e5024fc0cdf7f83b6624850309ddd7e06c48a75fa0d1c5173de4d93300eb19 \ - --hash=sha256:db7ff14abc73577b0bcbcf73ecff97d3580ecaa0fc8724babce21fdf3fe08ef6 \ - --hash=sha256:dedf54d72d9e7b6d043c244c8213fe2b8bbfe66874b9a65b39c4cc892dd99dd4 \ - --hash=sha256:ea3c2f859346fcd55fc46e96885301d9c2f7a36d453f5d8f2967840efa1e1830 \ - --hash=sha256:f0f47bafe9c9b8ed03e19a100a743662dd8c6d0135e684feea720a0d0046d116 \ +msgpack==1.0.0 \ + --hash=sha256:002a0d813e1f7b60da599bdf969e632074f9eec1b96cbed8fb0973a63160a408 \ + --hash=sha256:25b3bc3190f3d9d965b818123b7752c5dfb953f0d774b454fd206c18fe384fb8 \ + --hash=sha256:271b489499a43af001a2e42f42d876bb98ccaa7e20512ff37ca78c8e12e68f84 \ + --hash=sha256:39c54fdebf5fa4dda733369012c59e7d085ebdfe35b6cf648f09d16708f1be5d \ + --hash=sha256:4233b7f86c1208190c78a525cd3828ca1623359ef48f78a6fea4b91bb995775a \ + --hash=sha256:5bea44181fc8e18eed1d0cd76e355073f00ce232ff9653a0ae88cb7d9e643322 \ + --hash=sha256:5dba6d074fac9b24f29aaf1d2d032306c27f04187651511257e7831733293ec2 \ + --hash=sha256:7a22c965588baeb07242cb561b63f309db27a07382825fc98aecaf0827c1538e \ + --hash=sha256:908944e3f038bca67fcfedb7845c4a257c7749bf9818632586b53bcf06ba4b97 \ + --hash=sha256:9534d5cc480d4aff720233411a1f765be90885750b07df772380b34c10ecb5c0 \ + --hash=sha256:aa5c057eab4f40ec47ea6f5a9825846be2ff6bf34102c560bad5cad5a677c5be \ + --hash=sha256:b3758dfd3423e358bbb18a7cccd1c74228dffa7a697e5be6cb9535de625c0dbf \ + --hash=sha256:c901e8058dd6653307906c5f157f26ed09eb94a850dddd989621098d347926ab \ + --hash=sha256:cec8bf10981ed70998d98431cd814db0ecf3384e6b113366e7f36af71a0fca08 \ + --hash=sha256:db685187a415f51d6b937257474ca72199f393dad89534ebbdd7d7a3b000080e \ + --hash=sha256:e35b051077fc2f3ce12e7c6a34cf309680c63a842db3a0616ea6ed25ad20d272 \ + --hash=sha256:e7bbdd8e2b277b77782f3ce34734b0dfde6cbe94ddb74de8d733d603c7f9e2b1 \ + --hash=sha256:ea41c9219c597f1d2bf6b374d951d310d58684b5de9dc4bd2976db9e1e22c140 \ # via salt oauthlib==3.1.0 \ --hash=sha256:bee41cc35fcca6e988463cacc3bcb8a96224f470ca547e697b604cc697b2f889 \ @@ -237,8 +238,42 @@ pyasn1==0.4.8 \ --hash=sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d \ --hash=sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba \ # via pyasn1-modules, rsa -pycrypto==2.6.1 \ - --hash=sha256:f2ce1e989b272cfcb677616763e0a2e7ec659effa67a88aa92b3a65528f60a3c \ +pycryptodomex==3.9.9 \ + --hash=sha256:15c03ffdac17731b126880622823d30d0a3cc7203cd219e6b9814140a44e7fab \ + --hash=sha256:20fb7f4efc494016eab1bc2f555bc0a12dd5ca61f35c95df8061818ffb2c20a3 \ + --hash=sha256:28ee3bcb4d609aea3040cad995a8e2c9c6dc57c12183dadd69e53880c35333b9 \ + --hash=sha256:305e3c46f20d019cd57543c255e7ba49e432e275d7c0de8913b6dbe57a851bc8 \ + --hash=sha256:3547b87b16aad6afb28c9b3a9cd870e11b5e7b5ac649b74265258d96d8de1130 \ + --hash=sha256:3642252d7bfc4403a42050e18ba748bedebd5a998a8cba89665a4f42aea4c380 \ + --hash=sha256:404faa3e518f8bea516aae2aac47d4d960397199a15b4bd6f66cad97825469a0 \ + --hash=sha256:42669638e4f7937b7141044a2fbd1019caca62bd2cdd8b535f731426ab07bde1 \ + --hash=sha256:4632d55a140b28e20be3cd7a3057af52fb747298ff0fd3290d4e9f245b5004ba \ + --hash=sha256:4a88c9383d273bdce3afc216020282c9c5c39ec0bd9462b1a206af6afa377cf0 \ + --hash=sha256:4ce1fc1e6d2fd2d6dc197607153327989a128c093e0e94dca63408f506622c3e \ + --hash=sha256:55cf4e99b3ba0122dee570dc7661b97bf35c16aab3e2ccb5070709d282a1c7ab \ + --hash=sha256:5e486cab2dfcfaec934dd4f5d5837f4a9428b690f4d92a3b020fd31d1497ca64 \ + --hash=sha256:65ec88c8271448d2ea109d35c1f297b09b872c57214ab7e832e413090d3469a9 \ + --hash=sha256:6c95a3361ce70068cf69526a58751f73ddac5ba27a3c2379b057efa2f5338c8c \ + --hash=sha256:73240335f4a1baf12880ebac6df66ab4d3a9212db9f3efe809c36a27280d16f8 \ + --hash=sha256:7651211e15109ac0058a49159265d9f6e6423c8a81c65434d3c56d708417a05b \ + --hash=sha256:7b5b7c5896f8172ea0beb283f7f9428e0ab88ec248ce0a5b8c98d73e26267d51 \ + --hash=sha256:836fe39282e75311ce4c38468be148f7fac0df3d461c5de58c5ff1ddb8966bac \ + --hash=sha256:871852044f55295449fbf225538c2c4118525093c32f0a6c43c91bed0452d7e3 \ + --hash=sha256:892e93f3e7e10c751d6c17fa0dc422f7984cfd5eb6690011f9264dc73e2775fc \ + --hash=sha256:934e460c5058346c6f1d62fdf3db5680fbdfbfd212722d24d8277bf47cd9ebdc \ + --hash=sha256:9736f3f3e1761024200637a080a4f922f5298ad5d780e10dbb5634fe8c65b34c \ + --hash=sha256:a1d38a96da57e6103423a446079ead600b450cf0f8ebf56a231895abf77e7ffc \ + --hash=sha256:a385fceaa0cdb97f0098f1c1e9ec0b46cc09186ddf60ec23538e871b1dddb6dc \ + --hash=sha256:a7cf1c14e47027d9fb9d26aa62e5d603994227bd635e58a8df4b1d2d1b6a8ed7 \ + --hash=sha256:a9aac1a30b00b5038d3d8e48248f3b58ea15c827b67325c0d18a447552e30fc8 \ + --hash=sha256:b696876ee583d15310be57311e90e153a84b7913ac93e6b99675c0c9867926d0 \ + --hash=sha256:bef9e9d39393dc7baec39ba4bac6c73826a4db02114cdeade2552a9d6afa16e2 \ + --hash=sha256:c885fe4d5f26ce8ca20c97d02e88f5fdd92c01e1cc771ad0951b21e1641faf6d \ + --hash=sha256:d2d1388595cb5d27d9220d5cbaff4f37c6ec696a25882eb06d224d241e6e93fb \ + --hash=sha256:d2e853e0f9535e693fade97768cf7293f3febabecc5feb1e9b2ffdfe1044ab96 \ + --hash=sha256:d62fbab185a6b01c5469eda9f0795f3d1a5bba24f5a5813f362e4b73a3c4dc70 \ + --hash=sha256:f20a62397e09704049ce9007bea4f6bad965ba9336a760c6f4ef1b4192e12d6d \ + --hash=sha256:f81f7311250d9480e36dec819127897ae772e7e8de07abfabe931b8566770b8e \ # via salt pyparsing==2.4.7 \ --hash=sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1 \ @@ -258,11 +293,13 @@ pyyaml==5.3.1 \ --hash=sha256:06a0d7ba600ce0b2d2fe2e78453a470b5a6e000a985dd4a4e54e436cc36b0e97 \ --hash=sha256:240097ff019d7c70a4922b6869d8a86407758333f02203e0fc6ff79c5dcede76 \ --hash=sha256:4f4b913ca1a7319b33cfb1369e91e50354d6f07a135f3b901aca02aa95940bd2 \ + --hash=sha256:6034f55dab5fea9e53f436aa68fa3ace2634918e8b5994d82f3621c04ff5ed2e \ --hash=sha256:69f00dca373f240f842b2931fb2c7e14ddbacd1397d57157a9b005a6a9942648 \ --hash=sha256:73f099454b799e05e5ab51423c7bcf361c58d3206fa7b0d555426b1f4d9a3eaf \ --hash=sha256:74809a57b329d6cc0fdccee6318f44b9b8649961fa73144a98735b0aaf029f1f \ --hash=sha256:7739fc0fa8205b3ee8808aea45e968bc90082c10aef6ea95e855e10abf4a37b2 \ --hash=sha256:95f71d2af0ff4227885f7a6605c37fd53d3a106fcab511b8860ecca9fcf400ee \ + --hash=sha256:ad9c67312c84def58f3c04504727ca879cb0013b2517c85a9a253f0cb6380c0a \ --hash=sha256:b8eac752c5e14d3eca0e6dd9199cd627518cb5ec06add0de9d32baeee6fe645d \ --hash=sha256:cc8955cfbfc7a115fa81d85284ee61147059a753344bc51098f3ccd69b0d7e0c \ --hash=sha256:d13155f591e6fcc1ec3b30685d50bf0711574e2c0dfffd7644babf8b5102ca1a \ @@ -308,8 +345,8 @@ rsa==4.6 \ --hash=sha256:109ea5a66744dd859bf16fe904b8d8b627adafb9408753161e766a92e7d681fa \ --hash=sha256:6166864e23d6b5195a5cfed6cd9fed0fe774e226d8f854fcb23b7bbef0350233 \ # via google-auth -salt==3000.5 \ - --hash=sha256:486310fca787eecbb0dd04d71af9ac0a163607f81719f815f8d4daa1c2b71bff +salt==3002.2 \ + --hash=sha256:bd6d29621ce8e099412777cd396af35474aa112bb0999b5da804387d87290075 six==1.15.0 \ --hash=sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259 \ --hash=sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced \ From 561d0cb11a388f36aa00fc974879c79d3514d647 Mon Sep 17 00:00:00 2001 From: Teddy Andrieux Date: Fri, 20 Nov 2020 10:50:37 +0100 Subject: [PATCH 08/13] salt: Add a `migrate_salt` state for Upgrade/Downgrade Since we migrate from Python2 to Python3 a "classic" salt states cannot handle it properly as the Python version change during the state execution. Add a dedicated orchestrate that handle the migration from Salt Python2 to Salt Python3 and also the migration from Salt Python3 to Salt Python2, call this new orchestrate during Upgrade and Downgrade if needed Refs: #2203 --- buildchain/buildchain/salt_tree.py | 1 + salt/metalk8s/orchestrate/downgrade/init.sls | 18 +++++++++++++++ salt/metalk8s/orchestrate/migrate_salt.sls | 24 ++++++++++++++++++++ salt/metalk8s/orchestrate/upgrade/init.sls | 16 +++++++++++++ 4 files changed, 59 insertions(+) create mode 100644 salt/metalk8s/orchestrate/migrate_salt.sls diff --git a/buildchain/buildchain/salt_tree.py b/buildchain/buildchain/salt_tree.py index a0b5e0a3d5..9c5e6d5a2b 100644 --- a/buildchain/buildchain/salt_tree.py +++ b/buildchain/buildchain/salt_tree.py @@ -563,6 +563,7 @@ def _get_parts(self) -> Iterator[str]: Path('salt/metalk8s/orchestrate/apiserver.sls'), Path('salt/metalk8s/orchestrate/deploy_node.sls'), Path('salt/metalk8s/orchestrate/etcd.sls'), + Path('salt/metalk8s/orchestrate/migrate_salt.sls'), Path('salt/metalk8s/orchestrate/register_etcd.sls'), Path('salt/metalk8s/orchestrate/bootstrap/init.sls'), diff --git a/salt/metalk8s/orchestrate/downgrade/init.sls b/salt/metalk8s/orchestrate/downgrade/init.sls index af6e7c6f3b..f82eaaba50 100644 --- a/salt/metalk8s/orchestrate/downgrade/init.sls +++ b/salt/metalk8s/orchestrate/downgrade/init.sls @@ -55,6 +55,24 @@ Set node {{ node }} version to {{ dest_version }}: - require: - http: Wait for API server to be available on {{ node }} +{%- if salt.pkg.version_cmp(dest_version, '2.7.0') == -1 %} +# We need a new step to upgrade salt-minion as if we downgrade to 2.6.x +# we have to migrate salt from Python3 to Python2 +# NOTE: This can be removed in `development/2.8` +Upgrade salt-minion on {{ node }}: + salt.runner: + - name: state.orchestrate + - mods: + - metalk8s.orchestrate.migrate_salt + - pillar: + orchestrate: + node_name: {{ node }} + - require: + - metalk8s_kubernetes: Set node {{ node }} version to {{ dest_version }} + - require_in: + - salt: Deploy node {{ node }} +{%- endif %} + Deploy node {{ node }}: salt.runner: - name: state.orchestrate diff --git a/salt/metalk8s/orchestrate/migrate_salt.sls b/salt/metalk8s/orchestrate/migrate_salt.sls new file mode 100644 index 0000000000..557c5f000e --- /dev/null +++ b/salt/metalk8s/orchestrate/migrate_salt.sls @@ -0,0 +1,24 @@ +# This state is used for Salt migration: +# - for upgrade from 2.6.x to 2.7.x (migration from Python2 to Python3) +# - for downgrade from 2.7.x to 2.6.x (migration from Python3 to Python2) +# +# Salt migration cannot be done automatically by a salt state because of the +# change between Python2 and Python3 +# +# NOTE: This orchestrate can be removed in `developement/2.8` + +{%- set node_name = pillar.orchestrate.node_name %} +{%- set version = pillar.metalk8s.nodes[node_name].version %} + +# Just retry on the salt minion state since this state only manage +# salt-minion package it's "ok" to just retry here +Install Salt-minion: + salt.state: + - tgt: {{ node_name }} + - saltenv: metalk8s-{{ version }} + - sls: + - metalk8s.salt.minion.installed + - timeout: 200 + - retry: + attempts: 3 + interval: 60 diff --git a/salt/metalk8s/orchestrate/upgrade/init.sls b/salt/metalk8s/orchestrate/upgrade/init.sls index 2c8be95e6e..e524480de6 100644 --- a/salt/metalk8s/orchestrate/upgrade/init.sls +++ b/salt/metalk8s/orchestrate/upgrade/init.sls @@ -79,6 +79,22 @@ Set node {{ node }} version to {{ dest_version }}: - require: - http: Wait for API server to be available on {{ node }} +# We need a new step to upgrade salt-minion as if we come from 2.6.x +# we have to migrate salt from Python2 to Python3 +# NOTE: This can be removed in `development/2.8` +Upgrade salt-minion on {{ node }}: + salt.runner: + - name: state.orchestrate + - mods: + - metalk8s.orchestrate.migrate_salt + - pillar: + orchestrate: + node_name: {{ node }} + - require: + - metalk8s_kubernetes: Set node {{ node }} version to {{ dest_version }} + - require_in: + - salt: Deploy node {{ node }} + Deploy node {{ node }}: salt.runner: - name: state.orchestrate From 280d3e574fc312fc7c20c1a6d9e8e5a59e4d10bd Mon Sep 17 00:00:00 2001 From: Teddy Andrieux Date: Fri, 20 Nov 2020 10:58:24 +0100 Subject: [PATCH 09/13] salt: Use `loop.previtem` in Upgrade and Downgrade orchestrate Since we migrate to Salt Python3 we have Jinja 2.11 so we can use `loop.previtem` instead of ugly hack using a jinja variable. NOTE: This hack is still needed in downgrade orchestrate when we downgrade to `2.6.x` as we are running with Salt master metalk8s-2.6.x that use Salt Python2 and Jinja 2.7 Refs: #2203 --- salt/metalk8s/orchestrate/downgrade/init.sls | 13 ++++++++++--- salt/metalk8s/orchestrate/upgrade/init.sls | 9 +++------ 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/salt/metalk8s/orchestrate/downgrade/init.sls b/salt/metalk8s/orchestrate/downgrade/init.sls index f82eaaba50..d16aedf118 100644 --- a/salt/metalk8s/orchestrate/downgrade/init.sls +++ b/salt/metalk8s/orchestrate/downgrade/init.sls @@ -39,7 +39,11 @@ Wait for API server to be available on {{ node }}: - verify_ssl: false - require: - salt: Execute the downgrade prechecks - {%- if previous_node is defined %} + {%- if loop.previtem is defined %} + - salt: Deploy node {{ loop.previtem }} + {%- endif %} + {#- NOTE: This can be removed in `development/2.8` #} + {%- if salt.pkg.version_cmp(dest_version, '2.7.0') == -1 and previous_node is defined %} - salt: Deploy node {{ previous_node }} {%- endif %} @@ -97,8 +101,11 @@ Deploy node {{ node }}: - require_in: - salt: Downgrade etcd cluster - {#- Ugly but needed since we have jinja2.7 (`loop.previtem` added in 2.10) #} - {%- set previous_node = node %} + {#- NOTE: This can be removed in `development/2.8` #} + {%- if salt.pkg.version_cmp(dest_version, '2.7.0') == -1 %} + {#- Ugly but needed since we have jinja2.7 (`loop.previtem` added in 2.10) #} + {%- set previous_node = node %} + {%- endif %} {%- endif %} diff --git a/salt/metalk8s/orchestrate/upgrade/init.sls b/salt/metalk8s/orchestrate/upgrade/init.sls index e524480de6..1c05648a6f 100644 --- a/salt/metalk8s/orchestrate/upgrade/init.sls +++ b/salt/metalk8s/orchestrate/upgrade/init.sls @@ -45,6 +45,9 @@ Check pillar on {{ node }} before installing apiserver-proxy: attempts: 5 - require: - salt: Execute the upgrade prechecks + {%- if loop.previtem is defined %} + - salt: Deploy node {{ loop.previtem }} + {%- endif %} Install apiserver-proxy on {{ node }}: salt.state: @@ -63,9 +66,6 @@ Wait for API server to be available on {{ node }}: - verify_ssl: false - require: - salt: Install apiserver-proxy on {{ node }} - {%- if previous_node is defined %} - - salt: Deploy node {{ previous_node }} - {%- endif %} Set node {{ node }} version to {{ dest_version }}: metalk8s_kubernetes.object_updated: @@ -113,9 +113,6 @@ Deploy node {{ node }}: - require_in: - salt: Deploy Kubernetes service config objects - {#- Ugly but needed since we have jinja2.7 (`loop.previtem` added in 2.10) #} - {%- set previous_node = node %} - {%- endif %} {%- endfor %} From 334a7f57a68fa8a95c89be383f05ae39a9b75ea1 Mon Sep 17 00:00:00 2001 From: Teddy Andrieux Date: Fri, 20 Nov 2020 11:01:28 +0100 Subject: [PATCH 10/13] salt: Do not call etcd state if Salt upgrade/downgrade failed In `deploy_node` orchestrate, before this commit, during upgrade and downgrade the `Install etcd node` state is called even if the Salt upgrade/downgrade failed. This commit just add a require on this etcd state --- salt/metalk8s/orchestrate/deploy_node.sls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/metalk8s/orchestrate/deploy_node.sls b/salt/metalk8s/orchestrate/deploy_node.sls index fcdbe945df..2e8e60b9e7 100644 --- a/salt/metalk8s/orchestrate/deploy_node.sls +++ b/salt/metalk8s/orchestrate/deploy_node.sls @@ -150,6 +150,7 @@ Check pillar before etcd deployment: attempts: 5 - require: - salt: Sync module on the node + - salt: Wait minion available Install etcd node: salt.state: @@ -253,4 +254,3 @@ Kill kube-controller-manager on all master nodes: pattern: kube-controller-manager - require: - salt: Run the highstate - From 10d08d827b13c83323c7f1ee58e0ac74d29a45e8 Mon Sep 17 00:00:00 2001 From: Teddy Andrieux Date: Mon, 23 Nov 2020 17:15:36 +0100 Subject: [PATCH 11/13] salt: Remove non-breaking space characters from Solutions Solutions YAML files contains some non-breaking space characters inside some Jinja formula `{{ }}` that make Salt Python3 rendering fail. NOTE: Those non-breaking space characters did not break Jinja2.7 used by Salt in Python2 that's why we didn't see any issue because of this before --- .../solutions/files/operator/configmap.yaml | 6 +++--- .../solutions/files/operator/deployment.yaml | 12 ++++++------ .../solutions/files/operator/role_binding.yaml | 6 +++--- .../solutions/files/operator/service_account.yaml | 6 +++--- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/salt/metalk8s/orchestrate/solutions/files/operator/configmap.yaml b/salt/metalk8s/orchestrate/solutions/files/operator/configmap.yaml index 695766f515..0edf5ae1aa 100644 --- a/salt/metalk8s/orchestrate/solutions/files/operator/configmap.yaml +++ b/salt/metalk8s/orchestrate/solutions/files/operator/configmap.yaml @@ -5,11 +5,11 @@ metadata: namespace: {{ namespace }} labels: app: {{ solution }}-operator - app.kubernetes.io/name: {{ solution }}-operator - app.kubernetes.io/instance: {{ solution }}-operator + app.kubernetes.io/name: {{ solution }}-operator + app.kubernetes.io/instance: {{ solution }}-operator app.kubernetes.io/version: {{ version }} app.kubernetes.io/component: operator - app.kubernetes.io/part-of: {{ solution }} + app.kubernetes.io/part-of: {{ solution }} data: operator.yaml: | apiVersion: solutions.metalk8s.scality.com/v1alpha1 diff --git a/salt/metalk8s/orchestrate/solutions/files/operator/deployment.yaml b/salt/metalk8s/orchestrate/solutions/files/operator/deployment.yaml index 7e2db3d20d..588fca991b 100644 --- a/salt/metalk8s/orchestrate/solutions/files/operator/deployment.yaml +++ b/salt/metalk8s/orchestrate/solutions/files/operator/deployment.yaml @@ -5,11 +5,11 @@ metadata: namespace: {{ namespace }} labels: app: {{ solution }}-operator - app.kubernetes.io/name: {{ solution }}-operator - app.kubernetes.io/instance: {{ solution }}-operator + app.kubernetes.io/name: {{ solution }}-operator + app.kubernetes.io/instance: {{ solution }}-operator app.kubernetes.io/version: {{ version }} app.kubernetes.io/component: operator - app.kubernetes.io/part-of: {{ solution }} + app.kubernetes.io/part-of: {{ solution }} spec: replicas: 1 selector: @@ -19,11 +19,11 @@ spec: metadata: labels: app: {{ solution }}-operator - app.kubernetes.io/name: {{ solution }}-operator - app.kubernetes.io/instance: {{ solution }}-operator + app.kubernetes.io/name: {{ solution }}-operator + app.kubernetes.io/instance: {{ solution }}-operator app.kubernetes.io/version: {{ version }} app.kubernetes.io/component: operator - app.kubernetes.io/part-of: {{ solution }} + app.kubernetes.io/part-of: {{ solution }} app.kubernetes.io/managed-by: salt heritage: salt spec: diff --git a/salt/metalk8s/orchestrate/solutions/files/operator/role_binding.yaml b/salt/metalk8s/orchestrate/solutions/files/operator/role_binding.yaml index d9403ce001..4a139d1597 100644 --- a/salt/metalk8s/orchestrate/solutions/files/operator/role_binding.yaml +++ b/salt/metalk8s/orchestrate/solutions/files/operator/role_binding.yaml @@ -8,11 +8,11 @@ metadata: namespace: {{ namespace }} labels: app: {{ solution }}-operator - app.kubernetes.io/name: {{ solution }}-operator - app.kubernetes.io/instance: {{ solution }}-operator + app.kubernetes.io/name: {{ solution }}-operator + app.kubernetes.io/instance: {{ solution }}-operator app.kubernetes.io/version: {{ version }} app.kubernetes.io/component: operator - app.kubernetes.io/part-of: {{ solution }} + app.kubernetes.io/part-of: {{ solution }} subjects: - kind: ServiceAccount name: {{ solution }}-operator diff --git a/salt/metalk8s/orchestrate/solutions/files/operator/service_account.yaml b/salt/metalk8s/orchestrate/solutions/files/operator/service_account.yaml index fef6ecec74..1ee89d83dc 100644 --- a/salt/metalk8s/orchestrate/solutions/files/operator/service_account.yaml +++ b/salt/metalk8s/orchestrate/solutions/files/operator/service_account.yaml @@ -5,8 +5,8 @@ metadata: namespace: {{ namespace }} labels: app: {{ solution }}-operator - app.kubernetes.io/name: {{ solution }}-operator - app.kubernetes.io/instance: {{ solution }}-operator + app.kubernetes.io/name: {{ solution }}-operator + app.kubernetes.io/instance: {{ solution }}-operator app.kubernetes.io/version: {{ version }} app.kubernetes.io/component: operator - app.kubernetes.io/part-of: {{ solution }} + app.kubernetes.io/part-of: {{ solution }} From ea228957e4e724b0f5448cf42818eca209de61ad Mon Sep 17 00:00:00 2001 From: Teddy Andrieux Date: Thu, 26 Nov 2020 14:18:20 +0100 Subject: [PATCH 12/13] changelog: Add entry for Python3 migration Add an entry in changelog file about Salt migration to Python3 and bump to Salt version 3002.2 Refs: #2203 --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0739607d93..12b7d62e5d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,9 @@ - Bump `coredns` version to 1.6.7 (PR [#2816](https://github.com/scality/metalk8s/pull/2816)) +- [#2203](https://github.com/scality/metalk8s/issues/2203) - Migrate Salt to Python3 + and bump to version 3002.2 (PR [#2839](https://github.com/scality/metalk8s/pull/2839)) + ### Bug fixes - [#2908](https://github.com/scality/metalk8s/issues/2908) - Make upgrade script From 0d1cb8472bf3a91393fb9b2fdb833870c36dbfec Mon Sep 17 00:00:00 2001 From: Guillaume Demonet Date: Thu, 26 Nov 2020 16:58:47 +0100 Subject: [PATCH 13/13] salt: Migrate sparse volume cleanup to Python3 See: #2726 See: #2936 --- .../volumes/prepared/files/sparse_volume_cleanup.py | 2 +- salt/metalk8s/volumes/prepared/init.sls | 2 +- salt/metalk8s/volumes/prepared/installed.sls | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/salt/metalk8s/volumes/prepared/files/sparse_volume_cleanup.py b/salt/metalk8s/volumes/prepared/files/sparse_volume_cleanup.py index 4ce907a5af..2aae85a38b 100755 --- a/salt/metalk8s/volumes/prepared/files/sparse_volume_cleanup.py +++ b/salt/metalk8s/volumes/prepared/files/sparse_volume_cleanup.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 """Script for cleaning up MetalK8s sparse loop volumes. Handle discovery of the device through a Volume's UUID, and then detach the diff --git a/salt/metalk8s/volumes/prepared/init.sls b/salt/metalk8s/volumes/prepared/init.sls index 17701ad2d8..65b92fb0f3 100644 --- a/salt/metalk8s/volumes/prepared/init.sls +++ b/salt/metalk8s/volumes/prepared/init.sls @@ -69,7 +69,7 @@ Provision backing storage for {{ volume_name }}: - require: - metalk8s_volumes: Prepare backing storage for {{ volume_name }} - file: Set up systemd template unit for sparse loop device provisioning - - test: Ensure Python 2 is available + - test: Ensure Python 3 is available {%- endif %} - require_in: - module: Update pillar after volume provisioning diff --git a/salt/metalk8s/volumes/prepared/installed.sls b/salt/metalk8s/volumes/prepared/installed.sls index eb583713ab..397245302c 100644 --- a/salt/metalk8s/volumes/prepared/installed.sls +++ b/salt/metalk8s/volumes/prepared/installed.sls @@ -19,7 +19,7 @@ Install gdisk: - test: Repositories configured # Needed by the sparse volume cleanup script -Ensure Python 2 is available: +Ensure Python 3 is available: test.fail_without_changes: - - comment: Could not find a working Python 2 installation - - unless: /usr/bin/env python2 --version + - comment: Could not find a working Python 3 installation + - unless: /usr/bin/env python3 --version