From 8dc71ca969692b77e27349537f0151dd99a09656 Mon Sep 17 00:00:00 2001 From: Alexandre Allard Date: Wed, 3 Feb 2021 11:04:11 +0100 Subject: [PATCH 1/9] scripts: get archive absolute path We need the absolute path to put it in the bootstrap.yaml configuration file, otherwise Salt will not be able to retrieve the archive when called. --- scripts/iso-manager.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/iso-manager.sh b/scripts/iso-manager.sh index 639e129e3b..54405c4863 100755 --- a/scripts/iso-manager.sh +++ b/scripts/iso-manager.sh @@ -25,7 +25,7 @@ ARCHIVES=() while (( "$#" )); do case "$1" in -a|--archive) - ARCHIVES+=("$2") + ARCHIVES+=("$(readlink -f "$2")") shift 2 ;; -d|--dry-run) From e13099a04dd2aa415dde3cce5299aa92107a7e21 Mon Sep 17 00:00:00 2001 From: Alexandre Allard Date: Wed, 3 Feb 2021 11:08:47 +0100 Subject: [PATCH 2/9] scripts: use common library functions Instead of redeclaring some functions, use the common.sh library --- scripts/iso-manager.sh | 66 ++---------------------------------------- 1 file changed, 3 insertions(+), 63 deletions(-) diff --git a/scripts/iso-manager.sh b/scripts/iso-manager.sh index 54405c4863..38b46d18d5 100755 --- a/scripts/iso-manager.sh +++ b/scripts/iso-manager.sh @@ -65,70 +65,10 @@ cleanup() { trap cleanup EXIT +BASE_DIR=$(dirname "$(readlink -f "${BASH_SOURCE[0]}")") -run_quiet() { - local name=$1 - shift 1 - - echo -n "> ${name}..." - local start - start=$(date +%s) - set +e - "$@" 2>&1 | tee -ia "${LOGFILE}" > "${TMPFILES}/out" - local RC=$? - set -e - local end - end=$(date +%s) - - local duration=$(( end - start )) - - if [ $RC -eq 0 ]; then - echo " done [${duration}s]" - else - echo " fail [${duration}s]" - cat >/dev/stderr << EOM - -Failure while running step '${name}' - -Command: $@ - -Output: - -<< BEGIN >> -EOM - cat "${TMPFILES}/out" > /dev/stderr - - cat >/dev/stderr << EOM -<< END >> - -This script will now exit - -EOM - - exit 1 - fi -} - -run_verbose() { - local name=$1 - shift 1 - - echo "> ${name}..." - "$@" -} - -run() { - if [ "$VERBOSE" -eq 1 ]; then - run_verbose "${@}" - else - run_quiet "${@}" - fi -} - -die() { - echo 1>&2 "$@" - return 1 -} +# shellcheck disable=SC1090 +. "$BASE_DIR"/common.sh # helper function to set the current saltenv _set_env() { From 665a1adf87f317afd89a63362805f0f194ca364c Mon Sep 17 00:00:00 2001 From: Alexandre Allard Date: Wed, 3 Feb 2021 15:18:08 +0100 Subject: [PATCH 3/9] salt: Add function to add/remove archive from bootstrap config Refs: #3079 --- salt/_modules/metalk8s.py | 95 +++++++++++++++++++++++++++++++-------- 1 file changed, 76 insertions(+), 19 deletions(-) diff --git a/salt/_modules/metalk8s.py b/salt/_modules/metalk8s.py index 0fe7b2264f..be62065eb3 100644 --- a/salt/_modules/metalk8s.py +++ b/salt/_modules/metalk8s.py @@ -25,6 +25,8 @@ __virtualname__ = "metalk8s" +BOOTSTRAP_CONFIG = "/etc/metalk8s/bootstrap.yaml" + def __virtual__(): return __virtualname__ @@ -146,6 +148,28 @@ def _get_archive_info(info): return {"version": _get_archive_version(info), "name": _get_archive_name(info)} +def archive_info_from_product_txt(archive): + if os.path.isdir(archive): + info = archive_info_from_tree(archive) + info.update({ + 'iso': None, + 'path': archive, + }) + elif os.path.isfile(archive): + info = archive_info_from_iso(archive) + info.update({ + 'iso': archive, + 'path': '/srv/scality/metalk8s-{0}'.format(info['version']), + }) + else: + raise CommandExecutionError( + 'Invalid archive path {0}, should be an iso or a directory.' + .format(archive) + ) + + return info + + def archive_info_from_tree(path): """Extract archive information from a directory @@ -210,25 +234,8 @@ def get_archives(archives=None): res = {} for archive in archives: - if os.path.isdir(archive): - iso = None - info = archive_info_from_tree(archive) - path = archive - version = info["version"] - elif os.path.isfile(archive): - iso = archive - info = archive_info_from_iso(archive) - version = info["version"] - path = "/srv/scality/metalk8s-{0}".format(version) - else: - log.warning( - "Skip, invalid archive path %s, should be an iso or a " "directory.", - archive, - ) - continue - - info.update({"path": path, "iso": iso}) - env_name = "metalk8s-{0}".format(version) + info = archive_info_from_product_txt(archive) + env_name = 'metalk8s-{0}'.format(info['version']) # Warn if we have 2 archives with the same version if env_name in res: @@ -625,3 +632,53 @@ def get_from_map(value, saltenv=None): input_data=tmplstr, saltenv=saltenv, ) + + +def _read_bootstrap_config(): + try: + with salt.utils.files.fopen(BOOTSTRAP_CONFIG, 'r') as fd: + config = salt.utils.yaml.safe_load(fd) + except IOError as exc: + msg = 'Failed to load bootstrap config file at "{}"'.format( + BOOTSTRAP_CONFIG + ) + raise CommandExecutionError(message=msg) from exc + + return config + + +def _write_bootstrap_config(config): + try: + with salt.utils.files.fopen(BOOTSTRAP_CONFIG, 'w') as fd: + salt.utils.yaml.safe_dump(config, fd, default_flow_style=False) + except Exception as exc: + msg = 'Failed to write bootstrap config file at "{}"'.format( + BOOTSTRAP_CONFIG + ) + raise CommandExecutionError(message=msg) from exc + + +def configure_archive(archive, remove=False): + """Add (or remove) a MetalK8s archive in the bootstrap config file.""" + # raise if the archive does not exist or is invalid + archive_info_from_product_txt(archive) + config = _read_bootstrap_config() + + if remove: + try: + config['archives'].remove(archive) + msg = "removed from bootstrap configuration" + except ValueError: + msg = "already absent in bootstrap configuration" + else: + if archive in config['archives']: + msg = "already present in bootstrap configuration" + else: + config['archives'].append(archive) + msg = "added to bootstrap configuration" + + _write_bootstrap_config(config) + + msg = "Archive '{0}' {1}".format(archive, msg) + log.info(msg) + return msg From e16262cd18864aab278af481e53ee50cc699c2c8 Mon Sep 17 00:00:00 2001 From: Alexandre Allard Date: Wed, 3 Feb 2021 15:22:52 +0100 Subject: [PATCH 4/9] scripts: Use salt function to add archive to bootstrap config This way we get rid of shell logic and we can check for archive validity. Refs: #3079 --- scripts/iso-manager.sh | 47 +++++------------------------------------- 1 file changed, 5 insertions(+), 42 deletions(-) diff --git a/scripts/iso-manager.sh b/scripts/iso-manager.sh index 38b46d18d5..57377d520f 100755 --- a/scripts/iso-manager.sh +++ b/scripts/iso-manager.sh @@ -3,7 +3,6 @@ set -e set -u set -o pipefail -BOOTSTRAP_CONFIG="/etc/metalk8s/bootstrap.yaml" VERBOSE=${VERBOSE:-0} LOGFILE="/var/log/metalk8s/iso-manager.log" SALT_CALL=${SALT_CALL:-salt-call} @@ -79,48 +78,10 @@ _set_env() { fi } -# helper function to check for element in array -containsElement () { - local element match="$1" - shift - for element in "$@"; do - [[ "$element" == "$match" ]] && return 0; - done - return 1 -} - _add_archives() { - # Skip adding archive if None passed - [ $# -lt 1 ] && return 0 - # Use salt file.serialize merge require having full list - # salt-call output example: - # local: ["/srv/scality/metalk8s-2.0.0/", "/tmp/metalk8s-2.1.0.iso"] - # parsed archives: - # ("/srv/scality/metalk8s-2.0.0/" "/tmp/metalk8s-2.1.0.iso") - IFS=" " read -r -a \ - archives <<< "$(salt-call pillar.get metalk8s:archives \ - --out txt | cut -d' ' -f2- | tr -d '[],')" - for archive in "$@"; do - if ! containsElement "'$archive'" "${archives[@]}"; then - archives+=("'$archive'") - fi + for archive; do + $SALT_CALL metalk8s.configure_archive "$archive" done - echo "Collecting archives..." - echo "${archives[@]}" - # build archive list - archive_list=${archives[0]} - for i in "${archives[@]:1}"; do - archive_list+=,$i - done - echo "Updating bootstrap.yaml" - $SALT_CALL state.single file.serialize "$BOOTSTRAP_CONFIG" \ - dataset="{'archives': [$archive_list]}" \ - merge_if_exists=True \ - formatter=yaml \ - show_changes=True \ - test="$DRY_RUN" \ - --retcode-passthrough - return $? } _configure_archives() { @@ -161,5 +122,7 @@ _configure_archives() { _set_env [ -z "$SALTENV" ] && die "saltenv not set" -run "Add archives" _add_archives ${ARCHIVES[@]+"${ARCHIVES[@]}"} +if (( ${#ARCHIVES[@]} )); then + run "Add archives" _add_archives "${ARCHIVES[@]}" +fi run "Configure archives" _configure_archives From 155f3c7942de8f16d337736600b613bc11022b01 Mon Sep 17 00:00:00 2001 From: Alexandre Allard Date: Fri, 5 Feb 2021 11:55:33 +0100 Subject: [PATCH 5/9] scripts: Check bootstrap config archives in iso-manager Check that all configured archives are valid path pointing to valid MetalK8s archives, to fail early. Refs: #3079 --- scripts/iso-manager.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/scripts/iso-manager.sh b/scripts/iso-manager.sh index 57377d520f..b9546409ec 100755 --- a/scripts/iso-manager.sh +++ b/scripts/iso-manager.sh @@ -117,11 +117,18 @@ _configure_archives() { --retcode-passthrough } +_check_config() { + # This call will fail if there is any invalid archive + # configured in the bootstrap configuration file. + $SALT_CALL metalk8s.get_archives +} + # Main _set_env [ -z "$SALTENV" ] && die "saltenv not set" +run "Check bootstrap configuration file" _check_config if (( ${#ARCHIVES[@]} )); then run "Add archives" _add_archives "${ARCHIVES[@]}" fi From bfc9766526577f3b8475ac0f7d462b9a62a464e2 Mon Sep 17 00:00:00 2001 From: Alexandre Allard Date: Thu, 4 Feb 2021 12:06:53 +0100 Subject: [PATCH 6/9] salt: Raise if we have duplicated MetalK8s archive versions --- salt/_modules/metalk8s.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/salt/_modules/metalk8s.py b/salt/_modules/metalk8s.py index be62065eb3..7b20336d2b 100644 --- a/salt/_modules/metalk8s.py +++ b/salt/_modules/metalk8s.py @@ -237,11 +237,20 @@ def get_archives(archives=None): info = archive_info_from_product_txt(archive) env_name = 'metalk8s-{0}'.format(info['version']) - # Warn if we have 2 archives with the same version + # Raise if we have 2 archives with the same version if env_name in res: - archive = res[env_name] - log.warning( - "Archives have the same version: %s is overridden by %s.", archive, info + error_msg = [] + for dup_version in (res[env_name], info): + if dup_version['iso']: + path = dup_version['iso'] + kind = 'ISO' + else: + path = dup_version['path'] + kind = 'directory' + error_msg.append("{0} ({1})".format(path, kind)) + raise CommandExecutionError( + 'Two archives have the same version "{0}":\n- {1}' + .format(info['version'], "\n- ".join(error_msg)) ) res.update({env_name: info}) From d6f19cbf10940ff03a911a984608a3a972e60e77 Mon Sep 17 00:00:00 2001 From: Alexandre Allard Date: Thu, 4 Feb 2021 16:16:49 +0100 Subject: [PATCH 7/9] salt: fix assertDictContainsSubset deprecation warning --- salt/tests/unit/modules/test_metalk8s.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/salt/tests/unit/modules/test_metalk8s.py b/salt/tests/unit/modules/test_metalk8s.py index b836a03518..40711f5202 100644 --- a/salt/tests/unit/modules/test_metalk8s.py +++ b/salt/tests/unit/modules/test_metalk8s.py @@ -525,6 +525,10 @@ def test_get_from_map( ), patch("salt.template.compile_template", compile_template_mock): metalk8s.get_from_map("my-key", saltenv=saltenv) compile_template_mock.assert_called_once() - self.assertDictContainsSubset( - expected_args, compile_template_mock.call_args[1] + self.assertEqual( + dict( + compile_template_mock.call_args[1], + **expected_args, + ), + compile_template_mock.call_args[1] ) From 7b3dcd03e9c09f6ea926b25a1f21dddeb1541bb8 Mon Sep 17 00:00:00 2001 From: Alexandre Allard Date: Thu, 4 Feb 2021 16:58:59 +0100 Subject: [PATCH 8/9] salt: Add unit tests for `metalk8s.configure_archive` Refs: #3079 --- .../unit/modules/files/test_metalk8s.yaml | 228 +++++++++--------- salt/tests/unit/modules/test_metalk8s.py | 148 ++++++++++-- 2 files changed, 230 insertions(+), 146 deletions(-) diff --git a/salt/tests/unit/modules/files/test_metalk8s.yaml b/salt/tests/unit/modules/files/test_metalk8s.yaml index 7e0be0fb8f..4bb1e8ac3a 100644 --- a/salt/tests/unit/modules/files/test_metalk8s.yaml +++ b/salt/tests/unit/modules/files/test_metalk8s.yaml @@ -1,144 +1,72 @@ get_archives: - - archives: "/my/path/iso" - infos: {"version": "2.5.0", "name": "MetalK8s"} - is_files: True - result: { - "metalk8s-2.5.0": { - "iso": "/my/path/iso", - "version": "2.5.0", - "name": "MetalK8s", - "path": "/srv/scality/metalk8s-2.5.0" - } - } + # 0. Ok - 1 existing ISO passed as argument + - archives: /my/path/iso + infos: &get_archives_infos_iso + version: 2.5.0 + name: MetalK8s + iso: /my/path/iso + path: /srv/scality/metalk8s-2.5.0 + result: + metalk8s-2.5.0: *get_archives_infos_iso + # 1. Ok - 1 existing ISO from pillar entries - archives: null pillar_archives: - "/my/path/iso" - infos: {"version": "2.5.0", "name": "MetalK8s"} - is_files: True - result: { - "metalk8s-2.5.0": { - "iso": "/my/path/iso", - "version": "2.5.0", - "name": "MetalK8s", - "path": "/srv/scality/metalk8s-2.5.0" - } - } + infos: *get_archives_infos_iso + result: + metalk8s-2.5.0: *get_archives_infos_iso + # 2. Ok - 1 existing directory passed as argument - archives: "/my/path" - infos: {"version": "2.5.0", "name": "MetalK8s"} - is_dirs: True - result: { - "metalk8s-2.5.0": { - "iso": null, - "version": "2.5.0", - "name": "MetalK8s", - "path": "/my/path" - } - } + infos: &get_archives_infos_dir + <<: *get_archives_infos_iso + iso: null + path: /my/path + result: + metalk8s-2.5.0: *get_archives_infos_dir + # 3. Nok - 1 ISO and 1 directory with the same version - archives: - "/my/path" - "/my/path/iso" - infos: {"version": "2.5.0", "name": "MetalK8s"} - is_dirs: - - True - - False - is_files: True - result: { - "metalk8s-2.5.0": { - "iso": "/my/path/iso", - "version": "2.5.0", - "name": "MetalK8s", - "path": "/srv/scality/metalk8s-2.5.0" - } - } + infos: + - <<: *get_archives_infos_iso + iso: null + - *get_archives_infos_iso + raises: True + result: Two archives have the same version .* + # 4. Ok - 2 ISOs with different versions - archives: - "/my/path/iso" - - "/my/path" - infos: {"version": "2.5.0", "name": "MetalK8s"} - is_dirs: - - False - - True - is_files: True - result: { - "metalk8s-2.5.0": { - "iso": null, - "version": "2.5.0", - "name": "MetalK8s", - "path": "/my/path" - } - } - - archives: - - "/my/first/iso" - "/my/second/iso" infos: - - {"version": "2.5.0", "name": "MetalK8s"} - - {"version": "2.5.1", "name": "MetalK8s"} - is_files: True - result: { - "metalk8s-2.5.0": { - "iso": "/my/first/iso", - "version": "2.5.0", - "name": "MetalK8s", - "path": "/srv/scality/metalk8s-2.5.0" - }, - "metalk8s-2.5.1": { - "iso": "/my/second/iso", - "version": "2.5.1", - "name": "MetalK8s", - "path": "/srv/scality/metalk8s-2.5.1" - } - } + - *get_archives_infos_dir + - version: 2.5.1 + name: MetalK8s + iso: /my/second/iso + path: /srv/scality/metalk8s-2.5.1 + result: + metalk8s-2.5.0: *get_archives_infos_dir + metalk8s-2.5.1: + iso: /my/second/iso + version: 2.5.1 + name: MetalK8s + path: /srv/scality/metalk8s-2.5.1 + # 5. Nok - Archive path that does not exist - archives: - - "/my/path/does/not/exists" + - "/my/path/does/not/exist" infos: null - result: {} + invalid_path: True + raises: True + result: Invalid archive path + # 6. Ok - No archives - archives: null infos: null result: {} + # 7. Nok - Invalid `archives` argument - archives: {"invalid": "archives", "style": "123"} infos: null raises: True result: "Invalid archives: list or string expected, got .*" - - archives: - - "/my/first/iso" - - "/my/first/path" - - "/my/path/does/not/exists" - - "/my/second/path" - - "/my/second/iso" - infos: - - {"version": "2.5.1", "name": "MetalK8s"} - - {"version": "2.5.0", "name": "MetalK8s"} - - {"version": "2.5.1", "name": "MetalK8s"} - - {"version": "2.5.2", "name": "MetalK8s"} - is_dirs: - - False - - True - - False - - True - - False - is_files: - - True - - False - - True - result: { - "metalk8s-2.5.0": { - "iso": null, - "version": "2.5.0", - "name": "MetalK8s", - "path": "/my/first/path" - }, - "metalk8s-2.5.1": { - "iso": null, - "version": "2.5.1", - "name": "MetalK8s", - "path": "/my/second/path" - }, - "metalk8s-2.5.2": { - "iso": "/my/second/iso", - "version": "2.5.2", - "name": "MetalK8s", - "path": "/srv/scality/metalk8s-2.5.2" - } - } + check_pillar_keys: - keys: "my-simple-key" pillar_content: { @@ -437,3 +365,63 @@ manage_static_pod_manifest: atomic_copy_raises: Could not copy! error: >- Failed to commit change: Could not copy! + +archive_info_from_product_txt: + # 0. Ok - A valid ISO archive + - archive: /my/iso + is_file: True + info: + version: 2.8.0 + name: MetalK8s + result: + version: 2.8.0 + name: MetalK8s + iso: /my/iso + path: /srv/scality/metalk8s-2.8.0 + # 1. Ok - A valid directory archive + - archive: /my/directory + is_dir: True + info: + version: 2.8.0 + name: MetalK8s + result: + version: 2.8.0 + name: MetalK8s + iso: null + path: /my/directory + # 2. Nok - Invalid path + - archive: /my/invalid + info: null + raises: True + result: Invalid archive path /my/invalid, should be an iso or a directory. + +configure_archive: + # 0. Ok - + - archive: /my/archive + config: + archives: [] + result: Archive '/my/archive' added to bootstrap configuration + # 1. Ok - + - archive: /my/archive + remove: True + config: + archives: + - /my/archive + result: Archive '/my/archive' removed from bootstrap configuration + # 2. Ok - + - archive: /my/archive + config: + archives: + - /my/archive + result: Archive '/my/archive' already present in bootstrap configuration + # 3. Ok - + - archive: /my/archive + remove: True + config: + archives: [] + result: Archive '/my/archive' already absent in bootstrap configuration + # 4. Nok - + - archive: /my/archive + invalid_path: True + raises: True + result: Invalid archive path diff --git a/salt/tests/unit/modules/test_metalk8s.py b/salt/tests/unit/modules/test_metalk8s.py index 40711f5202..3fedd9762c 100644 --- a/salt/tests/unit/modules/test_metalk8s.py +++ b/salt/tests/unit/modules/test_metalk8s.py @@ -222,42 +222,35 @@ def test_get_archives( archives, infos, result, - is_dirs=False, - is_files=False, + invalid_path=False, raises=False, - pillar_archives=None, + pillar_archives=None ): """ Tests the return of `get_archives` function """ - infos_mock = MagicMock() - is_dirs_mock = MagicMock() - is_files_mock = MagicMock() - - for mock, var in [ - (infos_mock, infos), - (is_dirs_mock, is_dirs), - (is_files_mock, is_files), - ]: - if isinstance(var, list): - mock.side_effect = var - else: - mock.return_value = var + if invalid_path: + infos_mock = MagicMock( + side_effect=CommandExecutionError("Invalid archive path") + ) + elif isinstance(infos, list): + infos_mock = MagicMock(side_effect=infos) + else: + infos_mock = MagicMock(return_value=infos) pillar_dict = {"metalk8s": {}} if pillar_archives is not None: - pillar_dict["metalk8s"]["archives"] = pillar_archives - - with patch("os.path.isdir", is_dirs_mock), patch( - "os.path.isfile", is_files_mock - ), patch("metalk8s.archive_info_from_tree", infos_mock), patch( - "metalk8s.archive_info_from_iso", infos_mock - ), patch.dict( - metalk8s.__pillar__, pillar_dict - ): + pillar_dict['metalk8s']['archives'] = pillar_archives + + with patch( + "metalk8s.archive_info_from_product_txt", infos_mock + ), patch.dict(metalk8s.__pillar__, pillar_dict): if raises: self.assertRaisesRegex( - CommandExecutionError, result, metalk8s.get_archives, archives + CommandExecutionError, + result, + metalk8s.get_archives, + archives ) else: self.assertEqual(metalk8s.get_archives(archives), result) @@ -532,3 +525,106 @@ def test_get_from_map( ), compile_template_mock.call_args[1] ) + + @utils.parameterized_from_cases( + YAML_TESTS_CASES["archive_info_from_product_txt"] + ) + def test_archive_info_from_product_txt(self, archive, info, result, + is_file=False, is_dir=False, raises=False): + info_mock = MagicMock(return_value=info) + + with patch("os.path.isdir", MagicMock(return_value=is_dir)), \ + patch("os.path.isfile", MagicMock(return_value=is_file)), \ + patch("metalk8s.archive_info_from_tree", info_mock), \ + patch("metalk8s.archive_info_from_iso", info_mock): + if raises: + self.assertRaisesRegex( + CommandExecutionError, + result, + metalk8s.archive_info_from_product_txt, + archive + ) + else: + self.assertEqual( + metalk8s.archive_info_from_product_txt(archive), + result + ) + + + @utils.parameterized_from_cases(YAML_TESTS_CASES["configure_archive"]) + def test_configure_archive(self, archive, result, remove=None, config=None, + invalid_path=False, raises=False): + """ + Tests the return of `configure_archive` function + """ + info_mock = MagicMock() + if invalid_path: + info_mock.side_effect = CommandExecutionError( + "Invalid archive path" + ) + + with patch("metalk8s.archive_info_from_product_txt", info_mock), \ + patch("metalk8s._read_bootstrap_config", MagicMock(return_value=config)), \ + patch("metalk8s._write_bootstrap_config", MagicMock()): + if raises: + self.assertRaisesRegex( + CommandExecutionError, + result, + metalk8s.configure_archive, + archive, + remove, + ) + else: + self.assertEqual( + metalk8s.configure_archive( + archive, remove=remove + ), + result + ) + + @parameterized.expand([ + param(), + param(True, "Failed to write bootstrap config file") + ]) + def test__write_bootstrap_config(self, raises=False, result=None): + open_mock = mock_open() + if raises: + open_mock.side_effect = Exception( + "A wild exception appears!" + ) + + with patch("salt.utils.files.fopen", open_mock): + if raises: + self.assertRaisesRegex( + CommandExecutionError, + result, + metalk8s._write_bootstrap_config, + None + ) + else: + self.assertEqual( + metalk8s._write_bootstrap_config(None), + None, + ) + + @parameterized.expand([ + param(), + param(True, "Failed to load bootstrap config file") + ]) + def test__read_bootstrap_config(self, raises=False, result=None): + open_mock = mock_open(read_data="config") + if raises: + open_mock.side_effect = IOError("Weird I/O error!") + + with patch("salt.utils.files.fopen", open_mock): + if raises: + self.assertRaisesRegex( + CommandExecutionError, + result, + metalk8s._read_bootstrap_config, + ) + else: + self.assertEqual( + metalk8s._read_bootstrap_config(), + "config", + ) From 0ac063464ac6f31cecb6eadf472c81adbcb202a4 Mon Sep 17 00:00:00 2001 From: Alexandre Allard Date: Fri, 5 Feb 2021 11:51:10 +0100 Subject: [PATCH 9/9] Add changelog entry for iso-manager hardening --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 07fb25ff33..b99ecdf28f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -52,6 +52,11 @@ (PR [#3076](https://github.com/scality/metalk8s/pull/3076)) ### Bug fixes + +- [#3079](https://github.com/scality/metalk8s/issues/3079) - Ensure configured + archives are valid in the iso-manager script + (PR [#3081](https://github.com/scality/metalk8s/pull/3081)) + - [#3022](https://github.com/scality/metalk8s/issues/3022) - Ensure salt-master container can start at reboot even if local salt-minion is down (PR [#3041](https://github.com/scality/metalk8s/pull/3041))