diff --git a/2019.2.0-pr-54196-backport-173.patch b/2019.2.0-pr-54196-backport-173.patch deleted file mode 100644 index aade746..0000000 --- a/2019.2.0-pr-54196-backport-173.patch +++ /dev/null @@ -1,224 +0,0 @@ -From c9e39c7af97180414205a8ad752f86f579e75a58 Mon Sep 17 00:00:00 2001 -From: Cedric Bosdonnat -Date: Tue, 3 Sep 2019 15:16:30 +0200 -Subject: [PATCH] 2019.2.0 PR 54196 backport (#173) - -* virt.network_define doesn't have vport as positional argument - -virt.network_running state calls virt.network_define with vport as a -positional argument resulting in an error at runtime. Fix the state to -use the vport named argument instead. - -* Fix virt.pool_running state documentation - -virt.pool_running needs the source to be a dictionary, which the -documentation was not reflecting. Along the same lines the source hosts -need to be a list, adjust the example to show it. - -* Get virt.pool_running to start the pool after creating it - -Commit 25b96815 is wrong in assuming the pool build also starts it. The -pool needs to be stopped before building it, but we still need to start -it after the build: libvirt won't do it automagically for us. - -* Fix states to match virt.{network,pool}_infos return - -virt.network_infos and virt.pool_infos return the infos as a dictionary -with the network or pool name as a key even when there is only one -value. Adapt the network_running and pool_running states to this. - -* Fix virt.running use of virt.vm_state - -vm_state return a dictionary with the VM name as a key. Fix virt.running -state and its tests to match this. See issue #53107. ---- - salt/states/virt.py | 26 ++++++++++++++++---------- - tests/unit/states/test_virt.py | 27 +++++++++++++++------------ - 2 files changed, 31 insertions(+), 22 deletions(-) - -diff --git a/salt/states/virt.py b/salt/states/virt.py -index d411f864cd..32a9e31ae5 100644 ---- a/salt/states/virt.py -+++ b/salt/states/virt.py -@@ -389,8 +389,8 @@ def running(name, - - try: - try: -- __salt__['virt.vm_state'](name) -- if __salt__['virt.vm_state'](name) != 'running': -+ domain_state = __salt__['virt.vm_state'](name) -+ if domain_state.get(name, None) != 'running': - action_msg = 'started' - if update: - status = __salt__['virt.update'](name, -@@ -670,7 +670,7 @@ def network_running(name, - try: - info = __salt__['virt.network_info'](name, connection=connection, username=username, password=password) - if info: -- if info['active']: -+ if info[name]['active']: - ret['comment'] = 'Network {0} exists and is running'.format(name) - else: - __salt__['virt.network_start'](name, connection=connection, username=username, password=password) -@@ -680,7 +680,7 @@ def network_running(name, - __salt__['virt.network_define'](name, - bridge, - forward, -- vport, -+ vport=vport, - tag=tag, - autostart=autostart, - start=True, -@@ -744,11 +744,11 @@ def pool_running(name, - - owner: 1000 - - group: 100 - - source: -- - dir: samba_share -- - hosts: -- one.example.com -- two.example.com -- - format: cifs -+ dir: samba_share -+ hosts: -+ - one.example.com -+ - two.example.com -+ format: cifs - - autostart: True - - ''' -@@ -761,7 +761,7 @@ def pool_running(name, - try: - info = __salt__['virt.pool_info'](name, connection=connection, username=username, password=password) - if info: -- if info['state'] == 'running': -+ if info[name]['state'] == 'running': - ret['comment'] = 'Pool {0} exists and is running'.format(name) - else: - __salt__['virt.pool_start'](name, connection=connection, username=username, password=password) -@@ -795,6 +795,12 @@ def pool_running(name, - connection=connection, - username=username, - password=password) -+ -+ __salt__['virt.pool_start'](name, -+ connection=connection, -+ username=username, -+ password=password) -+ - ret['changes'][name] = 'Pool defined and started' - ret['comment'] = 'Pool {0} defined and started'.format(name) - except libvirt.libvirtError as err: -diff --git a/tests/unit/states/test_virt.py b/tests/unit/states/test_virt.py -index 8022989937..2904fa224d 100644 ---- a/tests/unit/states/test_virt.py -+++ b/tests/unit/states/test_virt.py -@@ -229,7 +229,7 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin): - 'result': True, - 'comment': 'myvm is running'} - with patch.dict(virt.__salt__, { # pylint: disable=no-member -- 'virt.vm_state': MagicMock(return_value='stopped'), -+ 'virt.vm_state': MagicMock(return_value={'myvm': 'stopped'}), - 'virt.start': MagicMock(return_value=0), - }): - ret.update({'changes': {'myvm': 'Domain started'}, -@@ -322,7 +322,7 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin): - password='supersecret') - - with patch.dict(virt.__salt__, { # pylint: disable=no-member -- 'virt.vm_state': MagicMock(return_value='stopped'), -+ 'virt.vm_state': MagicMock(return_value={'myvm': 'stopped'}), - 'virt.start': MagicMock(side_effect=[self.mock_libvirt.libvirtError('libvirt error msg')]) - }): - ret.update({'changes': {}, 'result': False, 'comment': 'libvirt error msg'}) -@@ -330,7 +330,7 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin): - - # Working update case when running - with patch.dict(virt.__salt__, { # pylint: disable=no-member -- 'virt.vm_state': MagicMock(return_value='running'), -+ 'virt.vm_state': MagicMock(return_value={'myvm': 'running'}), - 'virt.update': MagicMock(return_value={'definition': True, 'cpu': True}) - }): - ret.update({'changes': {'myvm': {'definition': True, 'cpu': True}}, -@@ -340,7 +340,7 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin): - - # Working update case when stopped - with patch.dict(virt.__salt__, { # pylint: disable=no-member -- 'virt.vm_state': MagicMock(return_value='stopped'), -+ 'virt.vm_state': MagicMock(return_value={'myvm': 'stopped'}), - 'virt.start': MagicMock(return_value=0), - 'virt.update': MagicMock(return_value={'definition': True}) - }): -@@ -351,7 +351,7 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin): - - # Failed live update case - with patch.dict(virt.__salt__, { # pylint: disable=no-member -- 'virt.vm_state': MagicMock(return_value='running'), -+ 'virt.vm_state': MagicMock(return_value={'myvm': 'running'}), - 'virt.update': MagicMock(return_value={'definition': True, 'cpu': False, 'errors': ['some error']}) - }): - ret.update({'changes': {'myvm': {'definition': True, 'cpu': False, 'errors': ['some error']}}, -@@ -361,7 +361,7 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin): - - # Failed definition update case - with patch.dict(virt.__salt__, { # pylint: disable=no-member -- 'virt.vm_state': MagicMock(return_value='running'), -+ 'virt.vm_state': MagicMock(return_value={'myvm': 'running'}), - 'virt.update': MagicMock(side_effect=[self.mock_libvirt.libvirtError('error message')]) - }): - ret.update({'changes': {}, -@@ -573,7 +573,7 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin): - define_mock.assert_called_with('mynet', - 'br2', - 'bridge', -- 'openvswitch', -+ vport='openvswitch', - tag=180, - autostart=False, - start=True, -@@ -582,7 +582,7 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin): - password='secret') - - with patch.dict(virt.__salt__, { # pylint: disable=no-member -- 'virt.network_info': MagicMock(return_value={'active': True}), -+ 'virt.network_info': MagicMock(return_value={'mynet': {'active': True}}), - 'virt.network_define': define_mock, - }): - ret.update({'changes': {}, 'comment': 'Network mynet exists and is running'}) -@@ -590,7 +590,7 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin): - - start_mock = MagicMock(return_value=True) - with patch.dict(virt.__salt__, { # pylint: disable=no-member -- 'virt.network_info': MagicMock(return_value={'active': False}), -+ 'virt.network_info': MagicMock(return_value={'mynet': {'active': False}}), - 'virt.network_start': start_mock, - 'virt.network_define': define_mock, - }): -@@ -666,10 +666,13 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin): - connection='myconnection', - username='user', - password='secret') -- mocks['start'].assert_not_called() -+ mocks['start'].assert_called_with('mypool', -+ connection='myconnection', -+ username='user', -+ password='secret') - - with patch.dict(virt.__salt__, { # pylint: disable=no-member -- 'virt.pool_info': MagicMock(return_value={'state': 'running'}), -+ 'virt.pool_info': MagicMock(return_value={'mypool': {'state': 'running'}}), - }): - ret.update({'changes': {}, 'comment': 'Pool mypool exists and is running'}) - self.assertDictEqual(virt.pool_running('mypool', -@@ -680,7 +683,7 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin): - for mock in mocks: - mocks[mock].reset_mock() - with patch.dict(virt.__salt__, { # pylint: disable=no-member -- 'virt.pool_info': MagicMock(return_value={'state': 'stopped'}), -+ 'virt.pool_info': MagicMock(return_value={'mypool': {'state': 'stopped'}}), - 'virt.pool_build': mocks['build'], - 'virt.pool_start': mocks['start'] - }): --- -2.16.4 - - diff --git a/_lastrevision b/_lastrevision index c037a44..3162bf6 100644 --- a/_lastrevision +++ b/_lastrevision @@ -1 +1 @@ -eb41abdc4d70c344f2d84dc6d693b9fb9cb4c247 \ No newline at end of file +c96fc684a059121ecc7baf013768b1b611777d73 \ No newline at end of file diff --git a/_service b/_service index 6140808..4501e52 100644 --- a/_service +++ b/_service @@ -3,7 +3,7 @@ https://github.com/openSUSE/salt-packaging.git salt package - 2019.2.3 + 3000 git @@ -12,8 +12,8 @@ codeload.github.com - openSUSE/salt/tar.gz/v2019.2.3-suse - v2019.2.3.tar.gz + openSUSE/salt/tar.gz/v3000-suse + v3000.tar.gz diff --git a/accumulated-changes-from-yomi-167.patch b/accumulated-changes-from-yomi-167.patch index 77ac394..48ea668 100644 --- a/accumulated-changes-from-yomi-167.patch +++ b/accumulated-changes-from-yomi-167.patch @@ -1,4 +1,4 @@ -From bfaac404ffa334157f4408b312b12a59b059df69 Mon Sep 17 00:00:00 2001 +From 63f28a891449889fa3d7139470266162b10e88f2 Mon Sep 17 00:00:00 2001 From: Alberto Planas Date: Tue, 22 Oct 2019 11:02:33 +0200 Subject: [PATCH] Accumulated changes from Yomi (#167) @@ -17,17 +17,17 @@ This patch ignore this kind of issue during the grains creation. (cherry picked from commit b865491b74679140f7a71c5ba50d482db47b600f) --- - salt/grains/core.py | 4 ++++ - salt/modules/zypperpkg.py | 30 ++++++++++++++++-------- - tests/unit/grains/test_core.py | 45 ++++++++++++++++++++++++++++++++++++ - tests/unit/modules/test_zypperpkg.py | 26 +++++++++++++++++++++ - 4 files changed, 96 insertions(+), 9 deletions(-) + salt/grains/core.py | 4 +++ + salt/modules/zypperpkg.py | 30 +++++++++++----- + tests/unit/grains/test_core.py | 68 ++++++++++++++++++++++++++++++++++++ + tests/unit/modules/test_zypperpkg.py | 26 ++++++++++++++ + 4 files changed, 119 insertions(+), 9 deletions(-) diff --git a/salt/grains/core.py b/salt/grains/core.py -index e1d08b76cf..6b1f2d2223 100644 +index 77ae99590f..68c43482d3 100644 --- a/salt/grains/core.py +++ b/salt/grains/core.py -@@ -987,6 +987,10 @@ def _virtual(osdata): +@@ -997,6 +997,10 @@ def _virtual(osdata): grains['virtual'] = 'gce' elif 'BHYVE' in output: grains['virtual'] = 'bhyve' @@ -39,10 +39,10 @@ index e1d08b76cf..6b1f2d2223 100644 pass elif osdata['kernel'] == 'FreeBSD': diff --git a/salt/modules/zypperpkg.py b/salt/modules/zypperpkg.py -index da1953b2a5..a87041aa70 100644 +index f7158e0810..5f3b6d6855 100644 --- a/salt/modules/zypperpkg.py +++ b/salt/modules/zypperpkg.py -@@ -861,23 +861,35 @@ def list_pkgs(versions_as_list=False, root=None, includes=None, **kwargs): +@@ -863,23 +863,35 @@ def list_pkgs(versions_as_list=False, root=None, includes=None, **kwargs): _ret[pkgname] = sorted(ret[pkgname], key=lambda d: d['version']) for include in includes: @@ -88,13 +88,14 @@ index da1953b2a5..a87041aa70 100644 'install_date_time_t': None, }] diff --git a/tests/unit/grains/test_core.py b/tests/unit/grains/test_core.py -index 09e197a2e4..7153a078f4 100644 +index 60914204b0..c4731f667a 100644 --- a/tests/unit/grains/test_core.py +++ b/tests/unit/grains/test_core.py -@@ -1317,6 +1317,51 @@ class CoreGrainsTestCase(TestCase, LoaderModuleMockMixin): - 'uuid': '' - }) +@@ -1543,3 +1543,71 @@ class CoreGrainsTestCase(TestCase, LoaderModuleMockMixin): + self.assertIn('osfullname', os_grains) + self.assertEqual(os_grains.get('osfullname'), 'FreeBSD') ++ + @skipIf(not salt.utils.platform.is_linux(), 'System is not Linux') + def test_kernelparams_return(self): + expectations = [ @@ -140,14 +141,33 @@ index 09e197a2e4..7153a078f4 100644 + 'uuid': '' + }) + - @skipIf(not salt.utils.platform.is_linux(), 'System is not Linux') - @skipIf(six.PY2, 'UnicodeDecodeError is throw in Python 3') - @patch('os.path.exists') ++ @skipIf(not salt.utils.platform.is_linux(), 'System is not Linux') ++ @skipIf(six.PY2, 'UnicodeDecodeError is throw in Python 3') ++ @patch('os.path.exists') ++ @patch('salt.utils.platform.is_proxy') ++ def test__hw_data_linux_unicode_error(self, is_proxy, exists): ++ def _fopen(*args): ++ class _File(object): ++ def __enter__(self): ++ return self ++ ++ def __exit__(self, *args): ++ pass ++ ++ def read(self): ++ raise UnicodeDecodeError('enconding', b'', 1, 2, 'reason') ++ ++ return _File() ++ ++ is_proxy.return_value = False ++ exists.return_value = True ++ with patch('salt.utils.files.fopen', _fopen): ++ self.assertEqual(core._hw_data({'kernel': 'Linux'}), {}) diff --git a/tests/unit/modules/test_zypperpkg.py b/tests/unit/modules/test_zypperpkg.py -index 695d982ca6..7617113401 100644 +index 6102043384..76937cc358 100644 --- a/tests/unit/modules/test_zypperpkg.py +++ b/tests/unit/modules/test_zypperpkg.py -@@ -943,6 +943,32 @@ Repository 'DUMMY' not found by its alias, number, or URI. +@@ -944,6 +944,32 @@ Repository 'DUMMY' not found by its alias, number, or URI. with self.assertRaisesRegex(CommandExecutionError, '^Advisory id "SUSE-PATCH-XXX" not found$'): zypper.install(advisory_ids=['SUSE-PATCH-XXX']) diff --git a/accumulated-changes-required-for-yomi-165.patch b/accumulated-changes-required-for-yomi-165.patch index d013af6..000ee98 100644 --- a/accumulated-changes-required-for-yomi-165.patch +++ b/accumulated-changes-required-for-yomi-165.patch @@ -1,4 +1,4 @@ -From 78f5d1bd931f5329792d0e430c75025b45c14041 Mon Sep 17 00:00:00 2001 +From 9f29577b75cac1e79ec7c30a5dff0dff0ab9da3a Mon Sep 17 00:00:00 2001 From: Alberto Planas Date: Tue, 30 Jul 2019 11:23:12 +0200 Subject: [PATCH] Accumulated changes required for Yomi (#165) @@ -58,133 +58,17 @@ so the cached data will be separated too. (cherry picked from commit 9c54bb3e8c93ba21fc583bdefbcadbe53cbcd7b5) --- - salt/modules/chroot.py | 36 +++++++++++---------- - salt/modules/cmdmod.py | 12 +++++-- - salt/modules/freezer.py | 20 ++++++++---- - salt/modules/zypperpkg.py | 13 ++++++-- - tests/unit/modules/test_chroot.py | 36 +++++++++++++++++++-- - tests/unit/modules/test_cmdmod.py | 50 +++++++++++++++++++++++++++++ - tests/unit/modules/test_freezer.py | 62 ++++++++++++++++++++++++++++++++---- - tests/unit/modules/test_zypperpkg.py | 21 ++++++++++++ - 8 files changed, 214 insertions(+), 36 deletions(-) + salt/modules/cmdmod.py | 12 +++++++++--- + salt/modules/zypperpkg.py | 13 ++++++++++--- + tests/unit/modules/test_cmdmod.py | 16 ++++++++++++++++ + tests/unit/modules/test_zypperpkg.py | 21 +++++++++++++++++++++ + 4 files changed, 56 insertions(+), 6 deletions(-) -diff --git a/salt/modules/chroot.py b/salt/modules/chroot.py -index 6e4705b67e..17b5890d8c 100644 ---- a/salt/modules/chroot.py -+++ b/salt/modules/chroot.py -@@ -50,16 +50,17 @@ def __virtual__(): - return (False, 'Module chroot requires the command chroot') - - --def exist(name): -+def exist(root): - ''' - Return True if the chroot environment is present. - ''' -- dev = os.path.join(name, 'dev') -- proc = os.path.join(name, 'proc') -- return all(os.path.isdir(i) for i in (name, dev, proc)) -+ dev = os.path.join(root, 'dev') -+ proc = os.path.join(root, 'proc') -+ sys = os.path.join(root, 'sys') -+ return all(os.path.isdir(i) for i in (root, dev, proc, sys)) - - --def create(name): -+def create(root): - ''' - Create a basic chroot environment. - -@@ -67,7 +68,7 @@ def create(name): - install the minimal required binaries, including Python if - chroot.call is called. - -- name -+ root - Path to the chroot environment - - CLI Example: -@@ -77,26 +78,28 @@ def create(name): - salt myminion chroot.create /chroot - - ''' -- if not exist(name): -- dev = os.path.join(name, 'dev') -- proc = os.path.join(name, 'proc') -+ if not exist(root): -+ dev = os.path.join(root, 'dev') -+ proc = os.path.join(root, 'proc') -+ sys = os.path.join(root, 'sys') - try: - os.makedirs(dev, mode=0o755) - os.makedirs(proc, mode=0o555) -+ os.makedirs(sys, mode=0o555) - except OSError as e: - log.error('Error when trying to create chroot directories: %s', e) - return False - return True - - --def call(name, function, *args, **kwargs): -+def call(root, function, *args, **kwargs): - ''' - Executes a Salt function inside a chroot environment. - - The chroot does not need to have Salt installed, but Python is - required. - -- name -+ root - Path to the chroot environment - - function -@@ -107,18 +110,19 @@ def call(name, function, *args, **kwargs): - .. code-block:: bash - - salt myminion chroot.call /chroot test.ping -+ salt myminion chroot.call /chroot ssh.set_auth_key user key=mykey - - ''' - - if not function: - raise CommandExecutionError('Missing function parameter') - -- if not exist(name): -+ if not exist(root): - raise CommandExecutionError('Chroot environment not found') - - # Create a temporary directory inside the chroot where we can - # untar salt-thin -- thin_dest_path = tempfile.mkdtemp(dir=name) -+ thin_dest_path = tempfile.mkdtemp(dir=root) - thin_path = __utils__['thin.gen_thin']( - __opts__['cachedir'], - extra_mods=__salt__['config.option']('thin_extra_mods', ''), -@@ -130,7 +134,7 @@ def call(name, function, *args, **kwargs): - return {'result': False, 'comment': stdout} - - chroot_path = os.path.join(os.path.sep, -- os.path.relpath(thin_dest_path, name)) -+ os.path.relpath(thin_dest_path, root)) - try: - safe_kwargs = clean_kwargs(**kwargs) - salt_argv = [ -@@ -144,8 +148,8 @@ def call(name, function, *args, **kwargs): - '-l', 'quiet', - '--', - function -- ] + list(args) + ['{}={}'.format(k, v) for (k, v) in safe_kwargs] -- ret = __salt__['cmd.run_chroot'](name, [str(x) for x in salt_argv]) -+ ] + list(args) + ['{}={}'.format(k, v) for (k, v) in safe_kwargs.items()] -+ ret = __salt__['cmd.run_chroot'](root, [str(x) for x in salt_argv]) - if ret['retcode'] != EX_OK: - raise CommandExecutionError(ret['stderr']) - diff --git a/salt/modules/cmdmod.py b/salt/modules/cmdmod.py -index 1801147f57..a7e1553ec3 100644 +index eed7656a6d..0d2f720bbb 100644 --- a/salt/modules/cmdmod.py +++ b/salt/modules/cmdmod.py -@@ -3079,13 +3079,19 @@ def run_chroot(root, +@@ -3094,13 +3094,19 @@ def run_chroot(root, if isinstance(cmd, (list, tuple)): cmd = ' '.join([six.text_type(i) for i in cmd]) @@ -207,69 +91,8 @@ index 1801147f57..a7e1553ec3 100644 cwd=cwd, stdin=stdin, shell=shell, -diff --git a/salt/modules/freezer.py b/salt/modules/freezer.py -index 786dfe4515..85adbfeb82 100644 ---- a/salt/modules/freezer.py -+++ b/salt/modules/freezer.py -@@ -151,7 +151,7 @@ def freeze(name=None, force=False, **kwargs): - states_path = _states_path() - - try: -- os.makedirs(states_path) -+ os.makedirs(states_path, exist_ok=True) - except OSError as e: - msg = 'Error when trying to create the freezer storage %s: %s' - log.error(msg, states_path, e) -@@ -163,13 +163,13 @@ def freeze(name=None, force=False, **kwargs): - safe_kwargs = clean_kwargs(**kwargs) - pkgs = __salt__['pkg.list_pkgs'](**safe_kwargs) - repos = __salt__['pkg.list_repos'](**safe_kwargs) -- for name, content in zip(_paths(name), (pkgs, repos)): -- with fopen(name, 'w') as fp: -+ for fname, content in zip(_paths(name), (pkgs, repos)): -+ with fopen(fname, 'w') as fp: - json.dump(content, fp) - return True - - --def restore(name=None, **kwargs): -+def restore(name=None, clean=False, **kwargs): - ''' - Make sure that the system contains the packages and repos from a - frozen state. -@@ -190,6 +190,9 @@ def restore(name=None, **kwargs): - name - Name of the frozen state. Optional. - -+ clean -+ In True remove the frozen information YAML from the cache -+ - CLI Example: - - .. code-block:: bash -@@ -203,8 +206,8 @@ def restore(name=None, **kwargs): - - frozen_pkgs = {} - frozen_repos = {} -- for name, content in zip(_paths(name), (frozen_pkgs, frozen_repos)): -- with fopen(name) as fp: -+ for fname, content in zip(_paths(name), (frozen_pkgs, frozen_repos)): -+ with fopen(fname) as fp: - content.update(json.load(fp)) - - # The ordering of removing or adding packages and repos can be -@@ -291,4 +294,9 @@ def restore(name=None, **kwargs): - log.error(msg, repo, e) - res['comment'].append(msg % (repo, e)) - -+ # Clean the cached YAML files -+ if clean and not res['comment']: -+ for fname in _paths(name): -+ os.remove(fname) -+ - return res diff --git a/salt/modules/zypperpkg.py b/salt/modules/zypperpkg.py -index 6bc7211f59..f71d6aac9e 100644 +index 3760b525e7..8179cd8c1d 100644 --- a/salt/modules/zypperpkg.py +++ b/salt/modules/zypperpkg.py @@ -449,8 +449,14 @@ def _clean_cache(): @@ -288,7 +111,7 @@ index 6bc7211f59..f71d6aac9e 100644 def list_upgrades(refresh=True, root=None, **kwargs): -@@ -809,9 +815,10 @@ def list_pkgs(versions_as_list=False, root=None, includes=None, **kwargs): +@@ -811,9 +817,10 @@ def list_pkgs(versions_as_list=False, root=None, includes=None, **kwargs): includes = includes if includes else [] @@ -301,64 +124,11 @@ index 6bc7211f59..f71d6aac9e 100644 if contextkey not in __context__: ret = {} cmd = ['rpm'] -diff --git a/tests/unit/modules/test_chroot.py b/tests/unit/modules/test_chroot.py -index 7181dd7e50..0e65a26606 100644 ---- a/tests/unit/modules/test_chroot.py -+++ b/tests/unit/modules/test_chroot.py -@@ -63,10 +63,10 @@ class ChrootTestCase(TestCase, LoaderModuleMockMixin): - ''' - Test if the chroot environment exist. - ''' -- isdir.side_effect = (True, True, True) -+ isdir.side_effect = (True, True, True, True) - self.assertTrue(chroot.exist('/chroot')) - -- isdir.side_effect = (True, True, False) -+ isdir.side_effect = (True, True, True, False) - self.assertFalse(chroot.exist('/chroot')) - - @patch('os.makedirs') -@@ -182,3 +182,35 @@ class ChrootTestCase(TestCase, LoaderModuleMockMixin): - salt_mock['archive.tar'].assert_called_once() - salt_mock['cmd.run_chroot'].assert_called_once() - utils_mock['files.rm_rf'].assert_called_once() -+ -+ @patch('salt.modules.chroot.exist') -+ @patch('tempfile.mkdtemp') -+ def test_call_success_parameters(self, mkdtemp, exist): -+ ''' -+ Test execution of Salt functions in chroot with parameters. -+ ''' -+ # Success test -+ exist.return_value = True -+ mkdtemp.return_value = '/chroot/tmp01' -+ utils_mock = { -+ 'thin.gen_thin': MagicMock(return_value='/salt-thin.tgz'), -+ 'files.rm_rf': MagicMock(), -+ 'json.find_json': MagicMock(return_value={'return': 'result'}) -+ } -+ salt_mock = { -+ 'archive.tar': MagicMock(return_value=''), -+ 'config.option': MagicMock(), -+ 'cmd.run_chroot': MagicMock(return_value={ -+ 'retcode': 0, -+ 'stdout': '', -+ }), -+ } -+ with patch.dict(chroot.__utils__, utils_mock), \ -+ patch.dict(chroot.__salt__, salt_mock): -+ self.assertEqual(chroot.call('/chroot', 'ssh.set_auth_key', -+ user='user', key='key'), 'result') -+ utils_mock['thin.gen_thin'].assert_called_once() -+ salt_mock['config.option'].assert_called() -+ salt_mock['archive.tar'].assert_called_once() -+ salt_mock['cmd.run_chroot'].assert_called_once() -+ utils_mock['files.rm_rf'].assert_called_once() diff --git a/tests/unit/modules/test_cmdmod.py b/tests/unit/modules/test_cmdmod.py -index a20afaca0f..6f3964f7aa 100644 +index f8fba59294..8d763435f8 100644 --- a/tests/unit/modules/test_cmdmod.py +++ b/tests/unit/modules/test_cmdmod.py -@@ -312,6 +312,22 @@ class CMDMODTestCase(TestCase, LoaderModuleMockMixin): +@@ -371,6 +371,22 @@ class CMDMODTestCase(TestCase, LoaderModuleMockMixin): else: raise RuntimeError @@ -381,161 +151,11 @@ index a20afaca0f..6f3964f7aa 100644 def test_run_all_binary_replace(self): ''' Test for failed decoding of binary data, for instance when doing -@@ -401,3 +417,37 @@ class CMDMODTestCase(TestCase, LoaderModuleMockMixin): - ret = cmdmod.run_all('some command', output_encoding='latin1') - - self.assertEqual(ret['stdout'], stdout) -+ -+ def test_run_chroot_runas(self): -+ ''' -+ Test run_chroot when a runas parameter is provided -+ ''' -+ with patch.dict(cmdmod.__salt__, {'mount.mount': MagicMock(), -+ 'mount.umount': MagicMock()}): -+ with patch('salt.modules.cmdmod.run_all') as run_all_mock: -+ cmdmod.run_chroot('/mnt', 'ls', runas='foobar') -+ run_all_mock.assert_called_with( -+ 'chroot --userspec foobar: /mnt /bin/sh -c ls', -+ bg=False, -+ clean_env=False, -+ cwd=None, -+ env=None, -+ ignore_retcode=False, -+ log_callback=None, -+ output_encoding=None, -+ output_loglevel='quiet', -+ pillar=None, -+ pillarenv=None, -+ python_shell=True, -+ reset_system_locale=True, -+ rstrip=True, -+ saltenv='base', -+ shell='/bin/bash', -+ stdin=None, -+ success_retcodes=None, -+ success_stderr=None, -+ success_stdout=None, -+ template=None, -+ timeout=None, -+ umask=None, -+ use_vt=False) -diff --git a/tests/unit/modules/test_freezer.py b/tests/unit/modules/test_freezer.py -index f6cf2f374f..70d315c17a 100644 ---- a/tests/unit/modules/test_freezer.py -+++ b/tests/unit/modules/test_freezer.py -@@ -112,6 +112,30 @@ class FreezerTestCase(TestCase, LoaderModuleMockMixin): - self.assertRaises(CommandExecutionError, freezer.freeze) - makedirs.assert_called_once() - -+ @patch('salt.utils.json.dump') -+ @patch('salt.modules.freezer.fopen') -+ @patch('salt.modules.freezer.status') -+ @patch('os.makedirs') -+ def test_freeze_success_two_freeze(self, makedirs, status, fopen, dump): -+ ''' -+ Test to freeze a current installation -+ ''' -+ # Freeze the current new state -+ status.return_value = False -+ salt_mock = { -+ 'pkg.list_pkgs': MagicMock(return_value={}), -+ 'pkg.list_repos': MagicMock(return_value={}), -+ } -+ with patch.dict(freezer.__salt__, salt_mock): -+ self.assertTrue(freezer.freeze('one')) -+ self.assertTrue(freezer.freeze('two')) -+ -+ self.assertEqual(makedirs.call_count, 2) -+ self.assertEqual(salt_mock['pkg.list_pkgs'].call_count, 2) -+ self.assertEqual(salt_mock['pkg.list_repos'].call_count, 2) -+ fopen.assert_called() -+ dump.assert_called() -+ - @patch('salt.utils.json.dump') - @patch('salt.modules.freezer.fopen') - @patch('salt.modules.freezer.status') -@@ -132,7 +156,7 @@ class FreezerTestCase(TestCase, LoaderModuleMockMixin): - salt_mock['pkg.list_pkgs'].assert_called_once() - salt_mock['pkg.list_repos'].assert_called_once() - fopen.assert_called() -- dump.asster_called() -+ dump.assert_called() - - @patch('salt.utils.json.dump') - @patch('salt.modules.freezer.fopen') -@@ -154,7 +178,7 @@ class FreezerTestCase(TestCase, LoaderModuleMockMixin): - salt_mock['pkg.list_pkgs'].assert_called_once() - salt_mock['pkg.list_repos'].assert_called_once() - fopen.assert_called() -- dump.asster_called() -+ dump.assert_called() - - @patch('salt.modules.freezer.status') - def test_restore_fails_missing_state(self, status): -@@ -190,7 +214,7 @@ class FreezerTestCase(TestCase, LoaderModuleMockMixin): - salt_mock['pkg.list_repos'].assert_called() - salt_mock['pkg.mod_repo'].assert_called_once() - fopen.assert_called() -- load.asster_called() -+ load.assert_called() - - @patch('salt.utils.json.load') - @patch('salt.modules.freezer.fopen') -@@ -217,7 +241,7 @@ class FreezerTestCase(TestCase, LoaderModuleMockMixin): - salt_mock['pkg.list_repos'].assert_called() - salt_mock['pkg.install'].assert_called_once() - fopen.assert_called() -- load.asster_called() -+ load.assert_called() - - @patch('salt.utils.json.load') - @patch('salt.modules.freezer.fopen') -@@ -244,7 +268,7 @@ class FreezerTestCase(TestCase, LoaderModuleMockMixin): - salt_mock['pkg.list_repos'].assert_called() - salt_mock['pkg.remove'].assert_called_once() - fopen.assert_called() -- load.asster_called() -+ load.assert_called() - - @patch('salt.utils.json.load') - @patch('salt.modules.freezer.fopen') -@@ -271,4 +295,30 @@ class FreezerTestCase(TestCase, LoaderModuleMockMixin): - salt_mock['pkg.list_repos'].assert_called() - salt_mock['pkg.del_repo'].assert_called_once() - fopen.assert_called() -- load.asster_called() -+ load.assert_called() -+ -+ @patch('os.remove') -+ @patch('salt.utils.json.load') -+ @patch('salt.modules.freezer.fopen') -+ @patch('salt.modules.freezer.status') -+ def test_restore_clean_yml(self, status, fopen, load, remove): -+ ''' -+ Test to restore an old state -+ ''' -+ status.return_value = True -+ salt_mock = { -+ 'pkg.list_pkgs': MagicMock(return_value={}), -+ 'pkg.list_repos': MagicMock(return_value={}), -+ 'pkg.install': MagicMock(), -+ } -+ with patch.dict(freezer.__salt__, salt_mock): -+ self.assertEqual(freezer.restore(clean=True), { -+ 'pkgs': {'add': [], 'remove': []}, -+ 'repos': {'add': [], 'remove': []}, -+ 'comment': [], -+ }) -+ salt_mock['pkg.list_pkgs'].assert_called() -+ salt_mock['pkg.list_repos'].assert_called() -+ fopen.assert_called() -+ load.assert_called() -+ self.assertEqual(remove.call_count, 2) diff --git a/tests/unit/modules/test_zypperpkg.py b/tests/unit/modules/test_zypperpkg.py -index 0a3053680f..695d982ca6 100644 +index 12c22bfcb2..6102043384 100644 --- a/tests/unit/modules/test_zypperpkg.py +++ b/tests/unit/modules/test_zypperpkg.py -@@ -570,6 +570,7 @@ Repository 'DUMMY' not found by its alias, number, or URI. +@@ -571,6 +571,7 @@ Repository 'DUMMY' not found by its alias, number, or URI. patch.dict(zypper.__salt__, {'pkg_resource.stringify': MagicMock()}): pkgs = zypper.list_pkgs(versions_as_list=True) self.assertFalse(pkgs.get('gpg-pubkey', False)) @@ -543,7 +163,7 @@ index 0a3053680f..695d982ca6 100644 for pkg_name, pkg_version in { 'jakarta-commons-discovery': ['0.4-129.686'], 'yast2-ftp-server': ['3.1.8-8.1'], -@@ -612,6 +613,7 @@ Repository 'DUMMY' not found by its alias, number, or URI. +@@ -613,6 +614,7 @@ Repository 'DUMMY' not found by its alias, number, or URI. patch.dict(pkg_resource.__salt__, {'pkg.parse_arch_from_name': zypper.parse_arch_from_name}): pkgs = zypper.list_pkgs(attr=['epoch', 'release', 'arch', 'install_date_time_t']) self.assertFalse(pkgs.get('gpg-pubkey', False)) @@ -551,7 +171,7 @@ index 0a3053680f..695d982ca6 100644 for pkg_name, pkg_attr in { 'jakarta-commons-discovery': [{ 'version': '0.4', -@@ -1455,3 +1457,22 @@ pattern() = package-c'''), +@@ -1456,3 +1458,22 @@ pattern() = package-c'''), 'summary': 'description b', }, } diff --git a/activate-all-beacons-sources-config-pillar-grains.patch b/activate-all-beacons-sources-config-pillar-grains.patch index ef9a2e5..bce3d30 100644 --- a/activate-all-beacons-sources-config-pillar-grains.patch +++ b/activate-all-beacons-sources-config-pillar-grains.patch @@ -1,4 +1,4 @@ -From 45b3ee6c8255c2daa6ed291a430a6325155ef29c Mon Sep 17 00:00:00 2001 +From 6df4cef549665aad5b9e2af50eb06124a2bb0997 Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Tue, 17 Oct 2017 16:52:33 +0200 Subject: [PATCH] Activate all beacons sources: config/pillar/grains @@ -8,10 +8,10 @@ Subject: [PATCH] Activate all beacons sources: config/pillar/grains 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/minion.py b/salt/minion.py -index 6912d9587f..c5f637eaa6 100644 +index 6a77d90185..457f485b0a 100644 --- a/salt/minion.py +++ b/salt/minion.py -@@ -484,7 +484,7 @@ class MinionBase(object): +@@ -483,7 +483,7 @@ class MinionBase(object): the pillar or grains changed ''' if 'config.merge' in functions: diff --git a/add-all_versions-parameter-to-include-all-installed-.patch b/add-all_versions-parameter-to-include-all-installed-.patch index 3d4faa2..e7045c0 100644 --- a/add-all_versions-parameter-to-include-all-installed-.patch +++ b/add-all_versions-parameter-to-include-all-installed-.patch @@ -1,4 +1,4 @@ -From 56c38610b083997cebf00070efe781d114fc33b6 Mon Sep 17 00:00:00 2001 +From cd66b1e6636013440577a38a5a68729fec2f3f99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?= Date: Mon, 14 May 2018 11:33:13 +0100 @@ -23,10 +23,10 @@ Allow removing only specific package versions with zypper and yum 1 file changed, 21 insertions(+) diff --git a/salt/states/pkg.py b/salt/states/pkg.py -index 0aca1e0af8..2034262b23 100644 +index a13d418400..c0fa2f6b69 100644 --- a/salt/states/pkg.py +++ b/salt/states/pkg.py -@@ -455,6 +455,16 @@ def _find_remove_targets(name=None, +@@ -450,6 +450,16 @@ def _find_remove_targets(name=None, if __grains__['os'] == 'FreeBSD' and origin: cver = [k for k, v in six.iteritems(cur_pkgs) if v['origin'] == pkgname] @@ -43,7 +43,7 @@ index 0aca1e0af8..2034262b23 100644 else: cver = cur_pkgs.get(pkgname, []) -@@ -861,6 +871,17 @@ def _verify_install(desired, new_pkgs, ignore_epoch=False, new_caps=None): +@@ -856,6 +866,17 @@ def _verify_install(desired, new_pkgs, ignore_epoch=False, new_caps=None): cver = new_pkgs.get(pkgname.split('%')[0]) elif __grains__['os_family'] == 'Debian': cver = new_pkgs.get(pkgname.split('=')[0]) diff --git a/add-astra-linux-common-edition-to-the-os-family-list.patch b/add-astra-linux-common-edition-to-the-os-family-list.patch index 483868b..5d99070 100644 --- a/add-astra-linux-common-edition-to-the-os-family-list.patch +++ b/add-astra-linux-common-edition-to-the-os-family-list.patch @@ -1,4 +1,4 @@ -From 27770ed415e010055fea3a2cf599b56cd4aedf5e Mon Sep 17 00:00:00 2001 +From acf0b24353d831dcc2c5b292f99480938f5ecd93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julio=20Gonz=C3=A1lez=20Gil?= Date: Wed, 12 Feb 2020 10:05:45 +0100 @@ -11,10 +11,10 @@ Subject: [PATCH] Add Astra Linux Common Edition to the OS Family list 2 files changed, 21 insertions(+) diff --git a/salt/grains/core.py b/salt/grains/core.py -index 31ed8a77aa..67e263d37b 100644 +index 20950988d9..f410985198 100644 --- a/salt/grains/core.py +++ b/salt/grains/core.py -@@ -1508,6 +1508,7 @@ _OS_FAMILY_MAP = { +@@ -1523,6 +1523,7 @@ _OS_FAMILY_MAP = { 'Funtoo': 'Gentoo', 'AIX': 'AIX', 'TurnKey': 'Debian', @@ -23,7 +23,7 @@ index 31ed8a77aa..67e263d37b 100644 # Matches any possible format: diff --git a/tests/unit/grains/test_core.py b/tests/unit/grains/test_core.py -index 09e197a2e4..700eac2b08 100644 +index b4ed9379e5..c276dee9f3 100644 --- a/tests/unit/grains/test_core.py +++ b/tests/unit/grains/test_core.py @@ -605,6 +605,26 @@ class CoreGrainsTestCase(TestCase, LoaderModuleMockMixin): @@ -54,6 +54,6 @@ index 09e197a2e4..700eac2b08 100644 def test_windows_platform_data(self): ''' -- -2.23.0 +2.16.4 diff --git a/add-batch_presence_ping_timeout-and-batch_presence_p.patch b/add-batch_presence_ping_timeout-and-batch_presence_p.patch index 6695653..4fa802a 100644 --- a/add-batch_presence_ping_timeout-and-batch_presence_p.patch +++ b/add-batch_presence_ping_timeout-and-batch_presence_p.patch @@ -1,4 +1,4 @@ -From 669a03b26870a7109c3f4b327dd2b5a4ec4fa1ba Mon Sep 17 00:00:00 2001 +From 376a7d2eeb6b3b215fac9322f1baee4497bdb339 Mon Sep 17 00:00:00 2001 From: Marcelo Chiaradia Date: Thu, 4 Apr 2019 13:57:38 +0200 Subject: [PATCH] Add 'batch_presence_ping_timeout' and diff --git a/add-cpe_name-for-osversion-grain-parsing-u-49946.patch b/add-cpe_name-for-osversion-grain-parsing-u-49946.patch index 7d429dc..23a7e7c 100644 --- a/add-cpe_name-for-osversion-grain-parsing-u-49946.patch +++ b/add-cpe_name-for-osversion-grain-parsing-u-49946.patch @@ -1,4 +1,4 @@ -From 2c4676963dfb4646ae0d2ad8aedba0aa83d266e9 Mon Sep 17 00:00:00 2001 +From a90f35bc03b477a63aae20c58f8957c075569465 Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Tue, 9 Oct 2018 14:08:50 +0200 Subject: [PATCH] Add CPE_NAME for osversion* grain parsing (U#49946) @@ -29,10 +29,10 @@ Fix proper part name in the string-bound CPE 1 file changed, 28 insertions(+) diff --git a/salt/grains/core.py b/salt/grains/core.py -index cd7ee39d2f..f59eeb5780 100644 +index 9c1b5d930e..7b7e328520 100644 --- a/salt/grains/core.py +++ b/salt/grains/core.py -@@ -1623,6 +1623,34 @@ def _parse_cpe_name(cpe): +@@ -1642,6 +1642,34 @@ def _parse_cpe_name(cpe): return ret diff --git a/add-custom-suse-capabilities-as-grains.patch b/add-custom-suse-capabilities-as-grains.patch index 4834b74..1051ce0 100644 --- a/add-custom-suse-capabilities-as-grains.patch +++ b/add-custom-suse-capabilities-as-grains.patch @@ -1,4 +1,4 @@ -From a96d99e4bf7a43c99037aee6b6e030cdc46ab542 Mon Sep 17 00:00:00 2001 +From e57dd3c2ae655422f0f6939825154ce5827d43c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?= Date: Thu, 21 Jun 2018 11:57:57 +0100 @@ -9,7 +9,7 @@ Subject: [PATCH] Add custom SUSE capabilities as Grains 1 file changed, 7 insertions(+) diff --git a/salt/grains/extra.py b/salt/grains/extra.py -index fff70e9f5b..4fb58674bf 100644 +index 9ce644b766..1082b05dba 100644 --- a/salt/grains/extra.py +++ b/salt/grains/extra.py @@ -75,3 +75,10 @@ def config(): diff --git a/add-environment-variable-to-know-if-yum-is-invoked-f.patch b/add-environment-variable-to-know-if-yum-is-invoked-f.patch index ce47f3f..ac344a6 100644 --- a/add-environment-variable-to-know-if-yum-is-invoked-f.patch +++ b/add-environment-variable-to-know-if-yum-is-invoked-f.patch @@ -1,4 +1,4 @@ -From 960c7f29239a23c3d46c31692d2e881735f4d2a7 Mon Sep 17 00:00:00 2001 +From 874b1229babf5244debac141cd260f695ccc1e9d Mon Sep 17 00:00:00 2001 From: Marcelo Chiaradia Date: Thu, 7 Jun 2018 10:29:41 +0200 Subject: [PATCH] Add environment variable to know if yum is invoked from @@ -9,10 +9,10 @@ Subject: [PATCH] Add environment variable to know if yum is invoked from 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/salt/modules/yumpkg.py b/salt/modules/yumpkg.py -index c250b94f0e..a56a2e8366 100644 +index f7e4ac9753..c89d321a1b 100644 --- a/salt/modules/yumpkg.py +++ b/salt/modules/yumpkg.py -@@ -887,7 +887,8 @@ def list_repo_pkgs(*args, **kwargs): +@@ -913,7 +913,8 @@ def list_repo_pkgs(*args, **kwargs): yum_version = None if _yum() != 'yum' else _LooseVersion( __salt__['cmd.run']( ['yum', '--version'], @@ -22,7 +22,7 @@ index c250b94f0e..a56a2e8366 100644 ).splitlines()[0].strip() ) # Really old version of yum; does not even have --showduplicates option -@@ -2298,7 +2299,8 @@ def list_holds(pattern=__HOLD_PATTERN, full=True): +@@ -2324,7 +2325,8 @@ def list_holds(pattern=__HOLD_PATTERN, full=True): _check_versionlock() out = __salt__['cmd.run']([_yum(), 'versionlock', 'list'], @@ -32,7 +32,7 @@ index c250b94f0e..a56a2e8366 100644 ret = [] for line in salt.utils.itertools.split(out, '\n'): match = _get_hold(line, pattern=pattern, full=full) -@@ -2364,7 +2366,8 @@ def group_list(): +@@ -2390,7 +2392,8 @@ def group_list(): out = __salt__['cmd.run_stdout']( [_yum(), 'grouplist', 'hidden'], output_loglevel='trace', @@ -42,7 +42,7 @@ index c250b94f0e..a56a2e8366 100644 ) key = None for line in salt.utils.itertools.split(out, '\n'): -@@ -2431,7 +2434,8 @@ def group_info(name, expand=False): +@@ -2457,7 +2460,8 @@ def group_info(name, expand=False): out = __salt__['cmd.run_stdout']( cmd, output_loglevel='trace', @@ -52,7 +52,7 @@ index c250b94f0e..a56a2e8366 100644 ) g_info = {} -@@ -3100,7 +3104,8 @@ def download(*packages): +@@ -3134,7 +3138,8 @@ def download(*packages): __salt__['cmd.run']( cmd, output_loglevel='trace', @@ -62,7 +62,7 @@ index c250b94f0e..a56a2e8366 100644 ) ret = {} for dld_result in os.listdir(CACHE_DIR): -@@ -3175,7 +3180,8 @@ def _get_patches(installed_only=False): +@@ -3209,7 +3214,8 @@ def _get_patches(installed_only=False): cmd = [_yum(), '--quiet', 'updateinfo', 'list', 'all'] ret = __salt__['cmd.run_stdout']( cmd, diff --git a/add-hold-unhold-functions.patch b/add-hold-unhold-functions.patch index 8287c6a..dbb61a3 100644 --- a/add-hold-unhold-functions.patch +++ b/add-hold-unhold-functions.patch @@ -1,4 +1,4 @@ -From 1a98027d94dc7491182a16eef2e6134c2d8423b6 Mon Sep 17 00:00:00 2001 +From 666f62917bbc48cbee2ed0aa319a61afd1b1fcb2 Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Thu, 6 Dec 2018 16:26:23 +0100 Subject: [PATCH] Add hold/unhold functions @@ -11,7 +11,7 @@ Add warnings 1 file changed, 87 insertions(+), 1 deletion(-) diff --git a/salt/modules/zypperpkg.py b/salt/modules/zypperpkg.py -index 001b852fc4..0c26e2214c 100644 +index 50279ccbd1..08a9c2ed4d 100644 --- a/salt/modules/zypperpkg.py +++ b/salt/modules/zypperpkg.py @@ -41,6 +41,7 @@ import salt.utils.pkg @@ -22,7 +22,7 @@ index 001b852fc4..0c26e2214c 100644 from salt.utils.versions import LooseVersion import salt.utils.environment from salt.exceptions import CommandExecutionError, MinionError, SaltInvocationError -@@ -1742,7 +1743,7 @@ def clean_locks(): +@@ -1771,7 +1772,7 @@ def clean_locks(): return out @@ -31,7 +31,7 @@ index 001b852fc4..0c26e2214c 100644 ''' Remove specified package lock. -@@ -1754,7 +1755,47 @@ def remove_lock(packages, **kwargs): # pylint: disable=unused-argument +@@ -1783,7 +1784,47 @@ def remove_lock(packages, **kwargs): # pylint: disable=unused-argument salt '*' pkg.remove_lock ,, salt '*' pkg.remove_lock pkgs='["foo", "bar"]' ''' @@ -79,7 +79,7 @@ index 001b852fc4..0c26e2214c 100644 locks = list_locks() try: packages = list(__salt__['pkg_resource.parse_targets'](packages)[0].keys()) -@@ -1775,6 +1816,50 @@ def remove_lock(packages, **kwargs): # pylint: disable=unused-argument +@@ -1804,6 +1845,50 @@ def remove_lock(packages, **kwargs): # pylint: disable=unused-argument return {'removed': len(removed), 'not_found': missing} @@ -130,7 +130,7 @@ index 001b852fc4..0c26e2214c 100644 def add_lock(packages, **kwargs): # pylint: disable=unused-argument ''' Add a package lock. Specify packages to lock by exact name. -@@ -1787,6 +1872,7 @@ def add_lock(packages, **kwargs): # pylint: disable=unused-argument +@@ -1816,6 +1901,7 @@ def add_lock(packages, **kwargs): # pylint: disable=unused-argument salt '*' pkg.add_lock ,, salt '*' pkg.add_lock pkgs='["foo", "bar"]' ''' diff --git a/add-missing-_utils-at-loader-grains_func.patch b/add-missing-_utils-at-loader-grains_func.patch new file mode 100644 index 0000000..f422eea --- /dev/null +++ b/add-missing-_utils-at-loader-grains_func.patch @@ -0,0 +1,26 @@ +From 082fa07e5301414b5b834b731aaa96bd5d966de7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?= + +Date: Tue, 10 Mar 2020 13:16:05 +0000 +Subject: [PATCH] Add missing _utils at loader grains_func + +--- + salt/loader.py | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/salt/loader.py b/salt/loader.py +index c68562988d..742b2f8e22 100644 +--- a/salt/loader.py ++++ b/salt/loader.py +@@ -683,6 +683,7 @@ def grain_funcs(opts, proxy=None): + __opts__ = salt.config.minion_config('/etc/salt/minion') + grainfuncs = salt.loader.grain_funcs(__opts__) + ''' ++ _utils = utils(opts) + ret = LazyLoader( + _module_dirs( + opts, +-- +2.23.0 + + diff --git a/add-missing-fun-for-returns-from-wfunc-executions.patch b/add-missing-fun-for-returns-from-wfunc-executions.patch index 5a97c36..585f69a 100644 --- a/add-missing-fun-for-returns-from-wfunc-executions.patch +++ b/add-missing-fun-for-returns-from-wfunc-executions.patch @@ -1,4 +1,4 @@ -From 3ae0b949dacc7ac597dc94a5141d2f4c23d6efc5 Mon Sep 17 00:00:00 2001 +From 5c25babafd4e4bbe55626713851ea5d6345c43d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?= Date: Wed, 9 Oct 2019 13:03:33 +0100 @@ -9,7 +9,7 @@ Subject: [PATCH] Add missing 'fun' for returns from wfunc executions 1 file changed, 4 insertions(+) diff --git a/salt/client/ssh/__init__.py b/salt/client/ssh/__init__.py -index 1453430e73..0df918d634 100644 +index 4881540837..1373274739 100644 --- a/salt/client/ssh/__init__.py +++ b/salt/client/ssh/__init__.py @@ -682,6 +682,8 @@ class SSH(object): diff --git a/add-multi-file-support-and-globbing-to-the-filetree-.patch b/add-multi-file-support-and-globbing-to-the-filetree-.patch index 4a3c7cf..04c883b 100644 --- a/add-multi-file-support-and-globbing-to-the-filetree-.patch +++ b/add-multi-file-support-and-globbing-to-the-filetree-.patch @@ -1,4 +1,4 @@ -From ddc5439536e8d7a0b2fca1fcb9db0b18ed961d54 Mon Sep 17 00:00:00 2001 +From 0a6b5e92a4a74dee94eb33a939600f8c2e429c01 Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Fri, 12 Oct 2018 16:20:40 +0200 Subject: [PATCH] Add multi-file support and globbing to the filetree diff --git a/add-new-custom-suse-capability-for-saltutil-state-mo.patch b/add-new-custom-suse-capability-for-saltutil-state-mo.patch index edfd837..1428332 100644 --- a/add-new-custom-suse-capability-for-saltutil-state-mo.patch +++ b/add-new-custom-suse-capability-for-saltutil-state-mo.patch @@ -1,4 +1,4 @@ -From 4a8c36db7ece51efdd04caa37c79b0cb6a22ecf6 Mon Sep 17 00:00:00 2001 +From ad1323b4f83fa8f2954c0a965f4acaf91575a59b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?= Date: Thu, 26 Mar 2020 13:08:16 +0000 @@ -10,7 +10,7 @@ Subject: [PATCH] Add new custom SUSE capability for saltutil state 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/salt/grains/extra.py b/salt/grains/extra.py -index 4fb58674bf04d44ada1cb1620384aba7d3a76bad..e78cc64e0dedc728cbef68942b8767c526daa1a8 100644 +index 1082b05dba7830ee53078cff86b5183b5eea2829..b30ab0091fee7cda8f74b861e9e9f95f8ad85b39 100644 --- a/salt/grains/extra.py +++ b/salt/grains/extra.py @@ -80,5 +80,6 @@ def config(): diff --git a/add-ppc64le-as-a-valid-rpm-package-architecture.patch b/add-ppc64le-as-a-valid-rpm-package-architecture.patch deleted file mode 100644 index 3b122dc..0000000 --- a/add-ppc64le-as-a-valid-rpm-package-architecture.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 27e882ff23e24ec26339503e727e5dec0507b55f Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?= - -Date: Fri, 24 May 2019 16:27:07 +0100 -Subject: [PATCH] Add 'ppc64le' as a valid RPM package architecture - ---- - salt/utils/pkg/rpm.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/salt/utils/pkg/rpm.py b/salt/utils/pkg/rpm.py -index 828b0cecda..cb85eb99fe 100644 ---- a/salt/utils/pkg/rpm.py -+++ b/salt/utils/pkg/rpm.py -@@ -21,7 +21,7 @@ log = logging.getLogger(__name__) - # These arches compiled from the rpmUtils.arch python module source - ARCHES_64 = ('x86_64', 'athlon', 'amd64', 'ia32e', 'ia64', 'geode') - ARCHES_32 = ('i386', 'i486', 'i586', 'i686') --ARCHES_PPC = ('ppc', 'ppc64', 'ppc64iseries', 'ppc64pseries') -+ARCHES_PPC = ('ppc', 'ppc64', 'ppc64le', 'ppc64iseries', 'ppc64pseries') - ARCHES_S390 = ('s390', 's390x') - ARCHES_SPARC = ( - 'sparc', 'sparcv8', 'sparcv9', 'sparcv9v', 'sparc64', 'sparc64v' --- -2.16.4 - - diff --git a/add-saltssh-multi-version-support-across-python-inte.patch b/add-saltssh-multi-version-support-across-python-inte.patch index cb5458c..c09d327 100644 --- a/add-saltssh-multi-version-support-across-python-inte.patch +++ b/add-saltssh-multi-version-support-across-python-inte.patch @@ -1,4 +1,4 @@ -From ee67c569786f5381fa0fb34c64f6796ecef5b21f Mon Sep 17 00:00:00 2001 +From 369567107fa18187f8cbc5040728037d0774287b Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Mon, 12 Mar 2018 12:01:39 +0100 Subject: [PATCH] Add SaltSSH multi-version support across Python @@ -466,7 +466,7 @@ index cd7549a178..95b3931a32 100644 if __name__ == '__main__': sys.exit(main(sys.argv)) diff --git a/salt/utils/thin.py b/salt/utils/thin.py -index 3c8ffec8af..b6fa90abae 100644 +index 8496db9569..0ff31cef39 100644 --- a/salt/utils/thin.py +++ b/salt/utils/thin.py @@ -9,6 +9,7 @@ from __future__ import absolute_import, print_function, unicode_literals diff --git a/add-standalone-configuration-file-for-enabling-packa.patch b/add-standalone-configuration-file-for-enabling-packa.patch index d654e54..a6634a5 100644 --- a/add-standalone-configuration-file-for-enabling-packa.patch +++ b/add-standalone-configuration-file-for-enabling-packa.patch @@ -1,4 +1,4 @@ -From d150fed197f47d17227f1801b29357ab509ebbd4 Mon Sep 17 00:00:00 2001 +From 717c9bc6cb81994c5f23de87cfa91112fa7bf89c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?= Date: Wed, 22 May 2019 13:00:46 +0100 diff --git a/add-supportconfig-module-for-remote-calls-and-saltss.patch b/add-supportconfig-module-for-remote-calls-and-saltss.patch index 459bc04..45e7eb0 100644 --- a/add-supportconfig-module-for-remote-calls-and-saltss.patch +++ b/add-supportconfig-module-for-remote-calls-and-saltss.patch @@ -1,4 +1,4 @@ -From 4bf9567fd28470085ee501e5e17c75a932b5dde5 Mon Sep 17 00:00:00 2001 +From f4388ef82b5053e9996272b182c29a2da21a6258 Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Fri, 19 Oct 2018 15:44:47 +0200 Subject: [PATCH] Add supportconfig module for remote calls and SaltSSH @@ -267,10 +267,10 @@ index a4343297b6..cbae189aea 100644 archive_path = self.collector.archive_path diff --git a/salt/loader.py b/salt/loader.py -index 0cff0c72bb..d494c452ed 100644 +index 428fb338c9..860162b791 100644 --- a/salt/loader.py +++ b/salt/loader.py -@@ -1687,8 +1687,10 @@ class LazyLoader(salt.utils.lazy.LazyDict): +@@ -1727,8 +1727,10 @@ class LazyLoader(salt.utils.lazy.LazyDict): )) for attr in getattr(mod, '__load__', dir(mod)): @@ -671,10 +671,10 @@ index 0000000000..750b2655d6 + + return __virtualname__ diff --git a/salt/state.py b/salt/state.py -index dfa9c6de58..c3119b6a33 100644 +index 1db1c35c52..bc5277554e 100644 --- a/salt/state.py +++ b/salt/state.py -@@ -1358,8 +1358,9 @@ class State(object): +@@ -1406,8 +1406,9 @@ class State(object): names = [] if state.startswith('__'): continue @@ -686,7 +686,7 @@ index dfa9c6de58..c3119b6a33 100644 if orchestration_jid is not None: chunk['__orchestration_jid__'] = orchestration_jid if '__sls__' in body: -@@ -1929,8 +1930,12 @@ class State(object): +@@ -1977,8 +1978,12 @@ class State(object): ret = self.call_parallel(cdata, low) else: self.format_slots(cdata) @@ -701,7 +701,7 @@ index dfa9c6de58..c3119b6a33 100644 self.states.inject_globals = {} if 'check_cmd' in low and '{0[state]}.mod_run_check_cmd'.format(low) not in self.states: ret.update(self._run_check_cmd(low)) -@@ -2762,10 +2767,31 @@ class State(object): +@@ -2882,10 +2887,31 @@ class State(object): running.update(errors) return running @@ -946,7 +946,7 @@ index 0000000000..f245f7f137 + ''' + return __virtualname__ diff --git a/salt/utils/args.py b/salt/utils/args.py -index 57dbf5861a..1f4d5d2e0f 100644 +index 8cc0f35196..666a502498 100644 --- a/salt/utils/args.py +++ b/salt/utils/args.py @@ -20,9 +20,7 @@ import salt.utils.data @@ -970,10 +970,10 @@ index 57dbf5861a..1f4d5d2e0f 100644 aspec = get_function_argspec(fun, is_class_method=is_class_method) diff --git a/salt/utils/decorators/__init__.py b/salt/utils/decorators/__init__.py -index a6da91447a..7529013a8e 100644 +index 45d69072c7..b2abb15425 100644 --- a/salt/utils/decorators/__init__.py +++ b/salt/utils/decorators/__init__.py -@@ -671,3 +671,27 @@ def ensure_unicode_args(function): +@@ -690,3 +690,27 @@ def ensure_unicode_args(function): else: return function(*args, **kwargs) return wrapped diff --git a/add-virt.all_capabilities.patch b/add-virt.all_capabilities.patch index 42573d6..a5dd125 100644 --- a/add-virt.all_capabilities.patch +++ b/add-virt.all_capabilities.patch @@ -1,4 +1,4 @@ -From fdc0a1f4adc40d9e5b5f7164f750e4580b9cd3f4 Mon Sep 17 00:00:00 2001 +From 82ddc9d93f6c0d6bc1e8dc6ebd30d6809d9f4d8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Bosdonnat?= Date: Thu, 18 Oct 2018 13:32:59 +0200 Subject: [PATCH] Add virt.all_capabilities @@ -15,10 +15,10 @@ virt.all_capabilities call. 2 files changed, 134 insertions(+), 29 deletions(-) diff --git a/salt/modules/virt.py b/salt/modules/virt.py -index 8d63b6ff4c..195da49296 100644 +index a2412bb745..3889238ecd 100644 --- a/salt/modules/virt.py +++ b/salt/modules/virt.py -@@ -4097,37 +4097,10 @@ def _parse_caps_loader(node): +@@ -4254,37 +4254,10 @@ def _parse_caps_loader(node): return result @@ -58,7 +58,7 @@ index 8d63b6ff4c..195da49296 100644 result = { 'emulator': caps.find('path').text if caps.find('path') is not None else None, 'domain': caps.find('domain').text if caps.find('domain') is not None else None, -@@ -4167,6 +4140,82 @@ def domain_capabilities(emulator=None, arch=None, machine=None, domain=None, **k +@@ -4324,6 +4297,82 @@ def domain_capabilities(emulator=None, arch=None, machine=None, domain=None, **k return result @@ -142,10 +142,10 @@ index 8d63b6ff4c..195da49296 100644 ''' Return the optimal 'custom' CPU baseline config for VM's on this minion diff --git a/tests/unit/modules/test_virt.py b/tests/unit/modules/test_virt.py -index 6546a0467c..36fcf0d4c0 100644 +index 32f4302e5f..94372c6d72 100644 --- a/tests/unit/modules/test_virt.py +++ b/tests/unit/modules/test_virt.py -@@ -2204,6 +2204,62 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin): +@@ -2216,6 +2216,62 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(expected, caps) diff --git a/add-virt.network_get_xml-function.patch b/add-virt.network_get_xml-function.patch deleted file mode 100644 index d44e1e4..0000000 --- a/add-virt.network_get_xml-function.patch +++ /dev/null @@ -1,123 +0,0 @@ -From a5072a8e834127c9633c1af78631dcef6db0e6cb Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?C=C3=A9dric=20Bosdonnat?= -Date: Mon, 30 Dec 2019 17:28:50 +0100 -Subject: [PATCH] Add virt.network_get_xml function - -Users may want to see the full XML definition of a network. - -Add virt.pool_get_xml function - -Users may want to see the full XML definition of a virtual storage pool. ---- - salt/modules/virt.py | 48 +++++++++++++++++++++++++++++++++++++++++ - tests/unit/modules/test_virt.py | 20 +++++++++++++++++ - 2 files changed, 68 insertions(+) - -diff --git a/salt/modules/virt.py b/salt/modules/virt.py -index 44c7e78ef0..339760ead4 100644 ---- a/salt/modules/virt.py -+++ b/salt/modules/virt.py -@@ -4633,6 +4633,30 @@ def network_info(name=None, **kwargs): - return result - - -+def network_get_xml(name, **kwargs): -+ ''' -+ Return the XML definition of a virtual network -+ -+ :param name: libvirt network name -+ :param connection: libvirt connection URI, overriding defaults -+ :param username: username to connect with, overriding defaults -+ :param password: password to connect with, overriding defaults -+ -+ .. versionadded:: Neon -+ -+ CLI Example: -+ -+ .. code-block:: bash -+ -+ salt '*' virt.network_get_xml default -+ ''' -+ conn = __get_conn(**kwargs) -+ try: -+ return conn.networkLookupByName(name).XMLDesc() -+ finally: -+ conn.close() -+ -+ - def network_start(name, **kwargs): - ''' - Start a defined virtual network. -@@ -5377,6 +5401,30 @@ def pool_info(name=None, **kwargs): - return result - - -+def pool_get_xml(name, **kwargs): -+ ''' -+ Return the XML definition of a virtual storage pool -+ -+ :param name: libvirt storage pool name -+ :param connection: libvirt connection URI, overriding defaults -+ :param username: username to connect with, overriding defaults -+ :param password: password to connect with, overriding defaults -+ -+ .. versionadded:: Neon -+ -+ CLI Example: -+ -+ .. code-block:: bash -+ -+ salt '*' virt.pool_get_xml default -+ ''' -+ conn = __get_conn(**kwargs) -+ try: -+ return conn.storagePoolLookupByName(name).XMLDesc() -+ finally: -+ conn.close() -+ -+ - def pool_start(name, **kwargs): - ''' - Start a defined libvirt storage pool. -diff --git a/tests/unit/modules/test_virt.py b/tests/unit/modules/test_virt.py -index 698e1922fc..719f97a724 100644 ---- a/tests/unit/modules/test_virt.py -+++ b/tests/unit/modules/test_virt.py -@@ -2404,6 +2404,16 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin): - net = virt.network_info('foo') - self.assertEqual({}, net) - -+ def test_network_get_xml(self): -+ ''' -+ Test virt.network_get_xml -+ ''' -+ network_mock = MagicMock() -+ network_mock.XMLDesc.return_value = 'Raw XML' -+ self.mock_conn.networkLookupByName.return_value = network_mock -+ -+ self.assertEqual('Raw XML', virt.network_get_xml('default')) -+ - def test_pool(self): - ''' - Test virt._gen_pool_xml() -@@ -2806,6 +2816,16 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin): - } - }, pool) - -+ def test_pool_get_xml(self): -+ ''' -+ Test virt.pool_get_xml -+ ''' -+ pool_mock = MagicMock() -+ pool_mock.XMLDesc.return_value = 'Raw XML' -+ self.mock_conn.storagePoolLookupByName.return_value = pool_mock -+ -+ self.assertEqual('Raw XML', virt.pool_get_xml('default')) -+ - def test_pool_list_volumes(self): - ''' - Test virt.pool_list_volumes --- -2.16.4 - - diff --git a/add-virt.volume_infos-and-virt.volume_delete.patch b/add-virt.volume_infos-and-virt.volume_delete.patch deleted file mode 100644 index 0c2aa82..0000000 --- a/add-virt.volume_infos-and-virt.volume_delete.patch +++ /dev/null @@ -1,358 +0,0 @@ -From 3bb798795f89e1af5132c6a97ddb0cf414912265 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?C=C3=A9dric=20Bosdonnat?= -Date: Fri, 15 Feb 2019 17:28:00 +0100 -Subject: [PATCH] Add virt.volume_infos() and virt.volume_delete() - -Expose more functions to handle libvirt storage volumes. - -virt.volume_infos() expose informations of the volumes, either for one or -all the volumes. Among the provided data, this function exposes the -names of the virtual machines using the volumes of file type. - -virt.volume_delete() allows removing a given volume. ---- - salt/modules/virt.py | 126 ++++++++++++++++++++++++++ - tests/unit/modules/test_virt.py | 195 ++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 321 insertions(+) - -diff --git a/salt/modules/virt.py b/salt/modules/virt.py -index 195da49296..9bb3636bd1 100644 ---- a/salt/modules/virt.py -+++ b/salt/modules/virt.py -@@ -4991,3 +4991,129 @@ def pool_list_volumes(name, **kwargs): - return pool.listVolumes() - finally: - conn.close() -+ -+ -+def _get_storage_vol(conn, pool, vol): -+ ''' -+ Helper function getting a storage volume. Will throw a libvirtError -+ if the pool or the volume couldn't be found. -+ ''' -+ pool_obj = conn.storagePoolLookupByName(pool) -+ return pool_obj.storageVolLookupByName(vol) -+ -+ -+def _is_valid_volume(vol): -+ ''' -+ Checks whether a volume is valid for further use since those may have disappeared since -+ the last pool refresh. -+ ''' -+ try: -+ # Getting info on an invalid volume raises error -+ vol.info() -+ return True -+ except libvirt.libvirtError as err: -+ return False -+ -+ -+def _get_all_volumes_paths(conn): -+ ''' -+ Extract the path and backing stores path of all volumes. -+ -+ :param conn: libvirt connection to use -+ ''' -+ volumes = [vol for l in [obj.listAllVolumes() for obj in conn.listAllStoragePools()] for vol in l] -+ return {vol.path(): [path.text for path in ElementTree.fromstring(vol.XMLDesc()).findall('.//backingStore/path')] -+ for vol in volumes if _is_valid_volume(vol)} -+ -+ -+def volume_infos(pool=None, volume=None, **kwargs): -+ ''' -+ Provide details on a storage volume. If no volume name is provided, the infos -+ all the volumes contained in the pool are provided. If no pool is provided, -+ the infos of the volumes of all pools are output. -+ -+ :param pool: libvirt storage pool name (default: ``None``) -+ :param volume: name of the volume to get infos from (default: ``None``) -+ :param connection: libvirt connection URI, overriding defaults -+ :param username: username to connect with, overriding defaults -+ :param password: password to connect with, overriding defaults -+ -+ .. versionadded:: Neon -+ -+ CLI Example: -+ -+ .. code-block:: bash -+ -+ salt "*" virt.volume_infos -+ ''' -+ result = {} -+ conn = __get_conn(**kwargs) -+ try: -+ backing_stores = _get_all_volumes_paths(conn) -+ disks = {domain.name(): -+ {node.get('file') for node -+ in ElementTree.fromstring(domain.XMLDesc(0)).findall('.//disk/source/[@file]')} -+ for domain in _get_domain(conn)} -+ -+ def _volume_extract_infos(vol): -+ ''' -+ Format the volume info dictionary -+ -+ :param vol: the libvirt storage volume object. -+ ''' -+ types = ['file', 'block', 'dir', 'network', 'netdir', 'ploop'] -+ infos = vol.info() -+ -+ # If we have a path, check its use. -+ used_by = [] -+ if vol.path(): -+ as_backing_store = {path for (path, all_paths) in backing_stores.items() if vol.path() in all_paths} -+ used_by = [vm_name for (vm_name, vm_disks) in disks.items() -+ if vm_disks & as_backing_store or vol.path() in vm_disks] -+ -+ return { -+ 'type': types[infos[0]] if infos[0] < len(types) else 'unknown', -+ 'key': vol.key(), -+ 'path': vol.path(), -+ 'capacity': infos[1], -+ 'allocation': infos[2], -+ 'used_by': used_by, -+ } -+ -+ pools = [obj for obj in conn.listAllStoragePools() if pool is None or obj.name() == pool] -+ vols = {pool_obj.name(): {vol.name(): _volume_extract_infos(vol) -+ for vol in pool_obj.listAllVolumes() -+ if (volume is None or vol.name() == volume) and _is_valid_volume(vol)} -+ for pool_obj in pools} -+ return {pool_name: volumes for (pool_name, volumes) in vols.items() if volumes} -+ except libvirt.libvirtError as err: -+ log.debug('Silenced libvirt error: %s', str(err)) -+ finally: -+ conn.close() -+ return result -+ -+ -+def volume_delete(pool, volume, **kwargs): -+ ''' -+ Delete a libvirt managed volume. -+ -+ :param pool: libvirt storage pool name -+ :param volume: name of the volume to delete -+ :param connection: libvirt connection URI, overriding defaults -+ :param username: username to connect with, overriding defaults -+ :param password: password to connect with, overriding defaults -+ -+ .. versionadded:: Neon -+ -+ CLI Example: -+ -+ .. code-block:: bash -+ -+ salt "*" virt.volume_delete -+ ''' -+ conn = __get_conn(**kwargs) -+ try: -+ vol = _get_storage_vol(conn, pool, volume) -+ return not bool(vol.delete()) -+ finally: -+ conn.close() -diff --git a/tests/unit/modules/test_virt.py b/tests/unit/modules/test_virt.py -index 36fcf0d4c0..6f9eea241a 100644 ---- a/tests/unit/modules/test_virt.py -+++ b/tests/unit/modules/test_virt.py -@@ -2698,3 +2698,198 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin): - self.mock_conn.storagePoolLookupByName.return_value = mock_pool - # pylint: enable=no-member - self.assertEqual(names, virt.pool_list_volumes('default')) -+ -+ def test_volume_infos(self): -+ ''' -+ Test virt.volume_infos -+ ''' -+ vms_disks = [ -+ ''' -+ -+ -+ -+ -+ -+ ''', -+ ''' -+ -+ -+ -+ -+ -+ ''', -+ ''' -+ -+ -+ -+ -+ -+ ''' -+ ] -+ mock_vms = [] -+ for idx, disk in enumerate(vms_disks): -+ vm = MagicMock() -+ # pylint: disable=no-member -+ vm.name.return_value = 'vm{0}'.format(idx) -+ vm.XMLDesc.return_value = ''' -+ -+ vm{0} -+ {1} -+ -+ '''.format(idx, disk) -+ # pylint: enable=no-member -+ mock_vms.append(vm) -+ -+ mock_pool_data = [ -+ { -+ 'name': 'pool0', -+ 'volumes': [ -+ { -+ 'key': '/key/of/vol0', -+ 'name': 'vol0', -+ 'path': '/path/to/vol0.qcow2', -+ 'info': [0, 123456789, 123456], -+ 'backingStore': None -+ } -+ ] -+ }, -+ { -+ 'name': 'pool1', -+ 'volumes': [ -+ { -+ 'key': '/key/of/vol0bad', -+ 'name': 'vol0bad', -+ 'path': '/path/to/vol0bad.qcow2', -+ 'info': None, -+ 'backingStore': None -+ }, -+ { -+ 'key': '/key/of/vol1', -+ 'name': 'vol1', -+ 'path': '/path/to/vol1.qcow2', -+ 'info': [0, 12345, 1234], -+ 'backingStore': None -+ }, -+ { -+ 'key': '/key/of/vol2', -+ 'name': 'vol2', -+ 'path': '/path/to/vol2.qcow2', -+ 'info': [0, 12345, 1234], -+ 'backingStore': '/path/to/vol0.qcow2' -+ }, -+ ], -+ } -+ ] -+ mock_pools = [] -+ for pool_data in mock_pool_data: -+ mock_pool = MagicMock() -+ mock_pool.name.return_value = pool_data['name'] # pylint: disable=no-member -+ mock_volumes = [] -+ for vol_data in pool_data['volumes']: -+ mock_volume = MagicMock() -+ # pylint: disable=no-member -+ mock_volume.name.return_value = vol_data['name'] -+ mock_volume.key.return_value = vol_data['key'] -+ mock_volume.path.return_value = '/path/to/{0}.qcow2'.format(vol_data['name']) -+ if vol_data['info']: -+ mock_volume.info.return_value = vol_data['info'] -+ backing_store = ''' -+ -+ qcow2 -+ {0} -+ -+ '''.format(vol_data['backingStore']) if vol_data['backingStore'] else '' -+ mock_volume.XMLDesc.return_value = ''' -+ -+ {0} -+ -+ qcow2 -+ /path/to/{0}.qcow2 -+ -+ {1} -+ -+ '''.format(vol_data['name'], backing_store) -+ else: -+ mock_volume.info.side_effect = self.mock_libvirt.libvirtError('No such volume') -+ mock_volume.XMLDesc.side_effect = self.mock_libvirt.libvirtError('No such volume') -+ mock_volumes.append(mock_volume) -+ # pylint: enable=no-member -+ mock_pool.listAllVolumes.return_value = mock_volumes # pylint: disable=no-member -+ mock_pools.append(mock_pool) -+ -+ self.mock_conn.listAllStoragePools.return_value = mock_pools # pylint: disable=no-member -+ -+ with patch('salt.modules.virt._get_domain', MagicMock(return_value=mock_vms)): -+ actual = virt.volume_infos('pool0', 'vol0') -+ self.assertEqual(1, len(actual.keys())) -+ self.assertEqual(1, len(actual['pool0'].keys())) -+ self.assertEqual(['vm0', 'vm2'], sorted(actual['pool0']['vol0']['used_by'])) -+ self.assertEqual('/path/to/vol0.qcow2', actual['pool0']['vol0']['path']) -+ self.assertEqual('file', actual['pool0']['vol0']['type']) -+ self.assertEqual('/key/of/vol0', actual['pool0']['vol0']['key']) -+ self.assertEqual(123456789, actual['pool0']['vol0']['capacity']) -+ self.assertEqual(123456, actual['pool0']['vol0']['allocation']) -+ -+ self.assertEqual(virt.volume_infos('pool1', None), { -+ 'pool1': { -+ 'vol1': { -+ 'type': 'file', -+ 'key': '/key/of/vol1', -+ 'path': '/path/to/vol1.qcow2', -+ 'capacity': 12345, -+ 'allocation': 1234, -+ 'used_by': [], -+ }, -+ 'vol2': { -+ 'type': 'file', -+ 'key': '/key/of/vol2', -+ 'path': '/path/to/vol2.qcow2', -+ 'capacity': 12345, -+ 'allocation': 1234, -+ 'used_by': ['vm2'], -+ } -+ } -+ }) -+ -+ self.assertEqual(virt.volume_infos(None, 'vol2'), { -+ 'pool1': { -+ 'vol2': { -+ 'type': 'file', -+ 'key': '/key/of/vol2', -+ 'path': '/path/to/vol2.qcow2', -+ 'capacity': 12345, -+ 'allocation': 1234, -+ 'used_by': ['vm2'], -+ } -+ } -+ }) -+ -+ def test_volume_delete(self): -+ ''' -+ Test virt.volume_delete -+ ''' -+ mock_delete = MagicMock(side_effect=[0, 1]) -+ mock_volume = MagicMock() -+ mock_volume.delete = mock_delete # pylint: disable=no-member -+ mock_pool = MagicMock() -+ # pylint: disable=no-member -+ mock_pool.storageVolLookupByName.side_effect = [ -+ mock_volume, -+ mock_volume, -+ self.mock_libvirt.libvirtError("Missing volume"), -+ mock_volume, -+ ] -+ self.mock_conn.storagePoolLookupByName.side_effect = [ -+ mock_pool, -+ mock_pool, -+ mock_pool, -+ self.mock_libvirt.libvirtError("Missing pool"), -+ ] -+ -+ # pylint: enable=no-member -+ self.assertTrue(virt.volume_delete('default', 'test_volume')) -+ self.assertFalse(virt.volume_delete('default', 'test_volume')) -+ with self.assertRaises(self.mock_libvirt.libvirtError): -+ virt.volume_delete('default', 'missing') -+ virt.volume_delete('missing', 'test_volume') -+ self.assertEqual(mock_delete.call_count, 2) --- -2.16.4 - - diff --git a/adds-explicit-type-cast-for-port.patch b/adds-explicit-type-cast-for-port.patch new file mode 100644 index 0000000..abb13cb --- /dev/null +++ b/adds-explicit-type-cast-for-port.patch @@ -0,0 +1,33 @@ +From 2182f2cbc835fee8a95101ce0c722d582b7456aa Mon Sep 17 00:00:00 2001 +From: Jochen Breuer +Date: Wed, 1 Apr 2020 16:13:23 +0200 +Subject: [PATCH] Adds explicit type cast for port + +If a port was passed as a string, the execution logic was broken +and a wrong set of remotes was returned. + +The type casting to int solves this issue. +--- + salt/utils/network.py | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/salt/utils/network.py b/salt/utils/network.py +index d6543ff160..def997f3dc 100644 +--- a/salt/utils/network.py ++++ b/salt/utils/network.py +@@ -1457,9 +1457,9 @@ def _netlink_tool_remote_on(port, which_end): + local_host, local_port = chunks[3].rsplit(':', 1) + remote_host, remote_port = chunks[4].rsplit(':', 1) + +- if which_end == 'remote_port' and int(remote_port) != port: ++ if which_end == 'remote_port' and int(remote_port) != int(port): + continue +- if which_end == 'local_port' and int(local_port) != port: ++ if which_end == 'local_port' and int(local_port) != int(port): + continue + remotes.add(remote_host.strip("[]")) + +-- +2.16.4 + + diff --git a/adds-the-possibility-to-also-use-downloadonly-in-kwa.patch b/adds-the-possibility-to-also-use-downloadonly-in-kwa.patch deleted file mode 100644 index abff5c0..0000000 --- a/adds-the-possibility-to-also-use-downloadonly-in-kwa.patch +++ /dev/null @@ -1,88 +0,0 @@ -From 812709918226b98cccdcb388863ce68b6cf076b6 Mon Sep 17 00:00:00 2001 -From: Jochen Breuer -Date: Fri, 27 Sep 2019 11:33:47 +0200 -Subject: [PATCH] Adds the possibility to also use downloadonly in kwargs - -The download_only parameter in the apt module is not in line with -the yum and zypper modules. Both of them use downloadonly without -the underline. - -With this change apt now additionally supports the downloadonly -parameter. - -Fixes #54790 ---- - salt/modules/aptpkg.py | 7 ++++--- - tests/unit/modules/test_aptpkg.py | 30 ++++++++++++++++++++++++++++++ - 2 files changed, 34 insertions(+), 3 deletions(-) - -diff --git a/salt/modules/aptpkg.py b/salt/modules/aptpkg.py -index a11bb51c16..1a60255a1d 100644 ---- a/salt/modules/aptpkg.py -+++ b/salt/modules/aptpkg.py -@@ -1054,8 +1054,9 @@ def upgrade(refresh=True, dist_upgrade=False, **kwargs): - Skip refreshing the package database if refresh has already occurred within - seconds - -- download_only -- Only download the packages, don't unpack or install them -+ download_only (or downloadonly) -+ Only download the packages, don't unpack or install them. Use -+ downloadonly to be in line with yum and zypper module. - - .. versionadded:: 2018.3.0 - -@@ -1086,7 +1087,7 @@ def upgrade(refresh=True, dist_upgrade=False, **kwargs): - cmd.append('--force-yes') - if kwargs.get('skip_verify', False): - cmd.append('--allow-unauthenticated') -- if kwargs.get('download_only', False): -+ if kwargs.get('download_only', False) or kwargs.get('downloadonly', False): - cmd.append('--download-only') - - cmd.append('dist-upgrade' if dist_upgrade else 'upgrade') -diff --git a/tests/unit/modules/test_aptpkg.py b/tests/unit/modules/test_aptpkg.py -index 85360da181..d3fac5902a 100644 ---- a/tests/unit/modules/test_aptpkg.py -+++ b/tests/unit/modules/test_aptpkg.py -@@ -393,6 +393,36 @@ class AptPkgTestCase(TestCase, LoaderModuleMockMixin): - with patch.multiple(aptpkg, **patch_kwargs): - self.assertEqual(aptpkg.upgrade(), dict()) - -+ def test_upgrade_downloadonly(self): -+ ''' -+ Tests the download-only options for upgrade. -+ ''' -+ with patch('salt.utils.pkg.clear_rtag', MagicMock()): -+ with patch('salt.modules.aptpkg.list_pkgs', -+ MagicMock(return_value=UNINSTALL)): -+ mock_cmd = MagicMock(return_value={ -+ 'retcode': 0, -+ 'stdout': UPGRADE -+ }) -+ patch_kwargs = { -+ '__salt__': { -+ 'config.get': MagicMock(return_value=True), -+ 'cmd.run_all': mock_cmd -+ }, -+ } -+ with patch.multiple(aptpkg, **patch_kwargs): -+ aptpkg.upgrade() -+ args_matching = [True for args in patch_kwargs['__salt__']['cmd.run_all'].call_args.args if "--download-only" in args] -+ self.assertFalse(any(args_matching)) -+ -+ aptpkg.upgrade(downloadonly=True) -+ args_matching = [True for args in patch_kwargs['__salt__']['cmd.run_all'].call_args.args if "--download-only" in args] -+ self.assertTrue(any(args_matching)) -+ -+ aptpkg.upgrade(download_only=True) -+ args_matching = [True for args in patch_kwargs['__salt__']['cmd.run_all'].call_args.args if "--download-only" in args] -+ self.assertTrue(any(args_matching)) -+ - def test_show(self): - ''' - Test that the pkg.show function properly parses apt-cache show output. --- -2.16.4 - - diff --git a/align-virt-full-info-fixes-with-upstream-192.patch b/align-virt-full-info-fixes-with-upstream-192.patch deleted file mode 100644 index c059e3a..0000000 --- a/align-virt-full-info-fixes-with-upstream-192.patch +++ /dev/null @@ -1,116 +0,0 @@ -From d569054ebc63718e62fe5799685b0623910f7e1f Mon Sep 17 00:00:00 2001 -From: Cedric Bosdonnat -Date: Mon, 9 Dec 2019 17:27:41 +0100 -Subject: [PATCH] Align virt full info fixes with upstream (#192) - -* Porting PR #52574 to 2019.2.1 - -* Partly revert 4ce0bc544174fdb00482db4653fb4b0ef411e78b to match upstream's fix ---- - salt/modules/virt.py | 12 +++++++----- - tests/unit/modules/test_virt.py | 23 ++++++++++++++++++++++- - 2 files changed, 29 insertions(+), 6 deletions(-) - -diff --git a/salt/modules/virt.py b/salt/modules/virt.py -index 3abc140a00..5e26964449 100644 ---- a/salt/modules/virt.py -+++ b/salt/modules/virt.py -@@ -331,7 +331,7 @@ def _get_uuid(dom): - - salt '*' virt.get_uuid - ''' -- return ElementTree.fromstring(dom.XMLDesc(0)).find('uuid').text -+ return ElementTree.fromstring(get_xml(dom)).find('uuid').text - - - def _get_on_poweroff(dom): -@@ -344,7 +344,7 @@ def _get_on_poweroff(dom): - - salt '*' virt.get_on_restart - ''' -- node = ElementTree.fromstring(dom.XMLDesc(0)).find('on_poweroff') -+ node = ElementTree.fromstring(get_xml(dom)).find('on_poweroff') - return node.text if node is not None else '' - - -@@ -358,7 +358,7 @@ def _get_on_reboot(dom): - - salt '*' virt.get_on_reboot - ''' -- node = ElementTree.fromstring(dom.XMLDesc(0)).find('on_reboot') -+ node = ElementTree.fromstring(get_xml(dom)).find('on_reboot') - return node.text if node is not None else '' - - -@@ -372,7 +372,7 @@ def _get_on_crash(dom): - - salt '*' virt.get_on_crash - ''' -- node = ElementTree.fromstring(dom.XMLDesc(0)).find('on_crash') -+ node = ElementTree.fromstring(get_xml(dom)).find('on_crash') - return node.text if node is not None else '' - - -@@ -2435,7 +2435,9 @@ def get_xml(vm_, **kwargs): - salt '*' virt.get_xml - ''' - conn = __get_conn(**kwargs) -- xml_desc = _get_domain(conn, vm_).XMLDesc(0) -+ xml_desc = vm_.XMLDesc(0) if isinstance( -+ vm_, libvirt.virDomain -+ ) else _get_domain(conn, vm_).XMLDesc(0) - conn.close() - return xml_desc - -diff --git a/tests/unit/modules/test_virt.py b/tests/unit/modules/test_virt.py -index b95f51807f..d8efafc063 100644 ---- a/tests/unit/modules/test_virt.py -+++ b/tests/unit/modules/test_virt.py -@@ -38,6 +38,10 @@ class LibvirtMock(MagicMock): # pylint: disable=too-many-ancestors - ''' - Libvirt library mock - ''' -+ class virDomain(MagicMock): -+ ''' -+ virDomain mock -+ ''' - - class libvirtError(Exception): - ''' -@@ -76,7 +80,7 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin): - Define VM to use in tests - ''' - self.mock_conn.listDefinedDomains.return_value = [name] # pylint: disable=no-member -- mock_domain = MagicMock() -+ mock_domain = self.mock_libvirt.virDomain() - self.mock_conn.lookupByName.return_value = mock_domain # pylint: disable=no-member - mock_domain.XMLDesc.return_value = xml # pylint: disable=no-member - -@@ -1396,6 +1400,23 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin): - re.match('^([0-9A-F]{2}[:-]){5}([0-9A-F]{2})$', - interface_attrs['mac'], re.I)) - -+ def test_get_xml(self): -+ ''' -+ Test virt.get_xml() -+ ''' -+ xml = ''' -+ test-vm -+ -+ -+ -+ -+ -+ -+ ''' -+ domain = self.set_mock_vm("test-vm", xml) -+ self.assertEqual(xml, virt.get_xml('test-vm')) -+ self.assertEqual(xml, virt.get_xml(domain)) -+ - def test_parse_qemu_img_info(self): - ''' - Make sure that qemu-img info output is properly parsed --- -2.23.0 - - diff --git a/allow-passing-kwargs-to-pkg.list_downloaded-bsc-1140.patch b/allow-passing-kwargs-to-pkg.list_downloaded-bsc-1140.patch index a7f6609..f3ccc21 100644 --- a/allow-passing-kwargs-to-pkg.list_downloaded-bsc-1140.patch +++ b/allow-passing-kwargs-to-pkg.list_downloaded-bsc-1140.patch @@ -1,4 +1,4 @@ -From eadcab9b1b03041360d27421e5e8204f2a463e61 Mon Sep 17 00:00:00 2001 +From 206a2f7c4c1104f2f35dfa2c0b775bef4adc5b91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?= Date: Wed, 3 Jul 2019 09:34:50 +0100 @@ -12,10 +12,10 @@ Add unit test for pkg.list_downloaded with kwargs 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/salt/modules/zypperpkg.py b/salt/modules/zypperpkg.py -index 9d0407e674..6bc7211f59 100644 +index 582caffb59..3760b525e7 100644 --- a/salt/modules/zypperpkg.py +++ b/salt/modules/zypperpkg.py -@@ -2553,7 +2553,7 @@ def download(*packages, **kwargs): +@@ -2557,7 +2557,7 @@ def download(*packages, **kwargs): ) @@ -25,10 +25,10 @@ index 9d0407e674..6bc7211f59 100644 .. versionadded:: 2017.7.0 diff --git a/tests/unit/modules/test_zypperpkg.py b/tests/unit/modules/test_zypperpkg.py -index d2ae06a98e..0a3053680f 100644 +index 3a6466f061..12c22bfcb2 100644 --- a/tests/unit/modules/test_zypperpkg.py +++ b/tests/unit/modules/test_zypperpkg.py -@@ -766,6 +766,33 @@ Repository 'DUMMY' not found by its alias, number, or URI. +@@ -767,6 +767,33 @@ Repository 'DUMMY' not found by its alias, number, or URI. self.assertEqual(len(list_patches), 3) self.assertDictEqual(list_patches, PATCHES_RET) diff --git a/apply-patch-from-upstream-to-support-python-3.8.patch b/apply-patch-from-upstream-to-support-python-3.8.patch index 382ff0d..9d7c67e 100644 --- a/apply-patch-from-upstream-to-support-python-3.8.patch +++ b/apply-patch-from-upstream-to-support-python-3.8.patch @@ -1,4 +1,4 @@ -From 41a0d937511356dc75f4f041a08c1458b4e0ccf4 Mon Sep 17 00:00:00 2001 +From b8226467e665650a0587b8fd64242faefb805e13 Mon Sep 17 00:00:00 2001 From: Steve Kowalik Date: Mon, 17 Feb 2020 15:34:00 +1100 Subject: [PATCH] Apply patch from upstream to support Python 3.8 @@ -35,10 +35,10 @@ index e3e678af3b..0f6a9bc012 100644 # requirements/opt.txt (not all) Recommends: python-MySQL-python diff --git a/salt/config/__init__.py b/salt/config/__init__.py -index 658128dac0..a372200892 100644 +index 0ebe1181dd..f484d94e7e 100644 --- a/salt/config/__init__.py +++ b/salt/config/__init__.py -@@ -3276,7 +3276,9 @@ def apply_cloud_providers_config(overrides, defaults=None): +@@ -3196,7 +3196,9 @@ def apply_cloud_providers_config(overrides, defaults=None): # Merge provided extends keep_looping = False for alias, entries in six.iteritems(providers.copy()): @@ -50,7 +50,7 @@ index 658128dac0..a372200892 100644 if 'extends' not in details: # Extends resolved or non existing, continue! diff --git a/salt/grains/core.py b/salt/grains/core.py -index 67e263d37b..0017c0f472 100644 +index f410985198..358b66fdb0 100644 --- a/salt/grains/core.py +++ b/salt/grains/core.py @@ -40,20 +40,20 @@ except ImportError: @@ -81,7 +81,7 @@ index 67e263d37b..0017c0f472 100644 except ImportError: from distro import linux_distribution -@@ -1961,7 +1961,7 @@ def os_data(): +@@ -1976,7 +1976,7 @@ def os_data(): ) (osname, osrelease, oscodename) = \ [x.strip('"').strip("'") for x in @@ -91,7 +91,7 @@ index 67e263d37b..0017c0f472 100644 # be more accurate than what python gets from /etc/DISTRO-release. # It's worth noting that Ubuntu has patched their Python distribution diff --git a/salt/renderers/stateconf.py b/salt/renderers/stateconf.py -index 8cd0235c99..2ce888d5f3 100644 +index cfce9e6926..5c8a8322ed 100644 --- a/salt/renderers/stateconf.py +++ b/salt/renderers/stateconf.py @@ -224,10 +224,10 @@ def render(input, saltenv='base', sls='', argline='', **kws): @@ -110,7 +110,7 @@ index 8cd0235c99..2ce888d5f3 100644 tmplctx = {} diff --git a/tests/unit/modules/test_virt.py b/tests/unit/modules/test_virt.py -index 719f97a724..3079657a9b 100644 +index 94372c6d72..d762dcc479 100644 --- a/tests/unit/modules/test_virt.py +++ b/tests/unit/modules/test_virt.py @@ -1256,7 +1256,7 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin): diff --git a/async-batch-implementation.patch b/async-batch-implementation.patch index 5b90c91..a09f68b 100644 --- a/async-batch-implementation.patch +++ b/async-batch-implementation.patch @@ -1,4 +1,4 @@ -From 6dea5186842285588ee02b66701cc91a4a2c4fa9 Mon Sep 17 00:00:00 2001 +From 9b47e4497ca16ec3671dd9da838895820ea9b0af Mon Sep 17 00:00:00 2001 From: Mihai Dinca Date: Fri, 16 Nov 2018 17:05:29 +0100 Subject: [PATCH] Async batch implementation @@ -26,20 +26,20 @@ Pass only metadata not all **kwargs Add separate batch presence_ping timeout --- salt/auth/__init__.py | 4 +- - salt/cli/batch.py | 91 ++++++-- - salt/cli/batch_async.py | 227 +++++++++++++++++++ - salt/client/__init__.py | 44 +--- - salt/master.py | 25 ++ + salt/cli/batch.py | 91 ++++++++-- + salt/cli/batch_async.py | 227 ++++++++++++++++++++++++ + salt/client/__init__.py | 41 +---- + salt/master.py | 25 +++ salt/netapi/__init__.py | 3 +- - salt/transport/ipc.py | 9 +- + salt/transport/ipc.py | 13 +- salt/utils/event.py | 8 +- - tests/unit/cli/test_batch_async.py | 351 +++++++++++++++++++++++++++++ - 9 files changed, 703 insertions(+), 59 deletions(-) + tests/unit/cli/test_batch_async.py | 351 +++++++++++++++++++++++++++++++++++++ + 9 files changed, 703 insertions(+), 60 deletions(-) create mode 100644 salt/cli/batch_async.py create mode 100644 tests/unit/cli/test_batch_async.py diff --git a/salt/auth/__init__.py b/salt/auth/__init__.py -index d43c57338c..e44c94fb37 100644 +index ecbd1c808c..ba9dbad509 100644 --- a/salt/auth/__init__.py +++ b/salt/auth/__init__.py @@ -52,7 +52,9 @@ AUTH_INTERNAL_KEYWORDS = frozenset([ @@ -396,10 +396,10 @@ index 0000000000..3160d46d8b + self.event.io_loop.call_later(self.opts['timeout'], self.find_job, set(next_batch)) + self.active = self.active.union(next_batch) diff --git a/salt/client/__init__.py b/salt/client/__init__.py -index 6a62e53fdc..8b37422cbf 100644 +index 08fbe191d4..3bbc7f9de7 100644 --- a/salt/client/__init__.py +++ b/salt/client/__init__.py -@@ -531,45 +531,14 @@ class LocalClient(object): +@@ -529,45 +529,14 @@ class LocalClient(object): {'dave': {...}} {'stewart': {...}} ''' @@ -450,21 +450,11 @@ index 6a62e53fdc..8b37422cbf 100644 batch = salt.cli.batch.Batch(opts, eauth=eauth, quiet=True) for ret in batch.run(): yield ret -@@ -1732,7 +1701,8 @@ class LocalClient(object): - if listen and not self.event.connect_pub(timeout=timeout): - raise SaltReqTimeoutError() - payload = channel.send(payload_kwargs, timeout=timeout) -- except SaltReqTimeoutError: -+ except SaltReqTimeoutError as err: -+ log.error(err) - raise SaltReqTimeoutError( - 'Salt request timed out. The master is not responding. You ' - 'may need to run your command with `--async` in order to ' diff --git a/salt/master.py b/salt/master.py -index 606be7319c..ee968410f7 100644 +index fb2e0c35bf..5e2277ba76 100644 --- a/salt/master.py +++ b/salt/master.py -@@ -32,6 +32,7 @@ import tornado.gen # pylint: disable=F0401 +@@ -31,6 +31,7 @@ import salt.ext.tornado.gen # pylint: disable=F0401 # Import salt libs import salt.crypt @@ -511,10 +501,10 @@ index 606be7319c..ee968410f7 100644 if jid is None: return {'enc': 'clear', diff --git a/salt/netapi/__init__.py b/salt/netapi/__init__.py -index 95f6384889..43b6e943a7 100644 +index 88d550f27f..31a24bb420 100644 --- a/salt/netapi/__init__.py +++ b/salt/netapi/__init__.py -@@ -88,7 +88,8 @@ class NetapiClient(object): +@@ -93,7 +93,8 @@ class NetapiClient(object): :return: job ID ''' local = salt.client.get_local_client(mopts=self.opts) @@ -525,45 +515,48 @@ index 95f6384889..43b6e943a7 100644 def local(self, *args, **kwargs): ''' diff --git a/salt/transport/ipc.py b/salt/transport/ipc.py -index dbcba18e5c..d0e1639b6e 100644 +index 89fb31fb4f..d2b295a633 100644 --- a/salt/transport/ipc.py +++ b/salt/transport/ipc.py -@@ -615,6 +615,7 @@ class IPCMessageSubscriber(IPCClient): +@@ -618,6 +618,7 @@ class IPCMessageSubscriber(IPCClient): self._read_stream_future = None self._saved_data = [] self._read_in_progress = Lock() + self.callbacks = set() - @tornado.gen.coroutine + @salt.ext.tornado.gen.coroutine def _read(self, timeout, callback=None): -@@ -689,8 +690,12 @@ class IPCMessageSubscriber(IPCClient): +@@ -692,8 +693,12 @@ class IPCMessageSubscriber(IPCClient): return self._saved_data.pop(0) return self.io_loop.run_sync(lambda: self._read(timeout)) +- @salt.ext.tornado.gen.coroutine +- def read_async(self, callback): + def __run_callbacks(self, raw): + for callback in self.callbacks: + self.io_loop.spawn_callback(callback, raw) + - @tornado.gen.coroutine -- def read_async(self, callback): ++ @tornado.gen.coroutine + def read_async(self): ''' Asynchronously read messages and invoke a callback when they are ready. -@@ -705,7 +710,7 @@ class IPCMessageSubscriber(IPCClient): - except Exception as exc: +@@ -707,8 +712,8 @@ class IPCMessageSubscriber(IPCClient): + yield salt.ext.tornado.gen.sleep(1) + except Exception as exc: # pylint: disable=broad-except log.error('Exception occurred while Subscriber connecting: %s', exc) - yield tornado.gen.sleep(1) +- yield salt.ext.tornado.gen.sleep(1) - yield self._read(None, callback) ++ yield tornado.gen.sleep(1) + yield self._read(None, self.__run_callbacks) def close(self): ''' diff --git a/salt/utils/event.py b/salt/utils/event.py -index 0b877980aa..ad9c85b576 100644 +index 0a3074a6f7..19e5db070d 100644 --- a/salt/utils/event.py +++ b/salt/utils/event.py -@@ -858,6 +858,10 @@ class SaltEvent(object): +@@ -857,6 +857,10 @@ class SaltEvent(object): # Minion fired a bad retcode, fire an event self._fire_ret_load_specific_fun(load) @@ -574,7 +567,7 @@ index 0b877980aa..ad9c85b576 100644 def set_event_handler(self, event_handler): ''' Invoke the event_handler callback each time an event arrives. -@@ -866,8 +870,10 @@ class SaltEvent(object): +@@ -865,8 +869,10 @@ class SaltEvent(object): if not self.cpub: self.connect_pub() @@ -584,8 +577,8 @@ index 0b877980aa..ad9c85b576 100644 - return self.subscriber.read_async(event_handler) + return self.subscriber.read_async() + # pylint: disable=W1701 def __del__(self): - # skip exceptions in destroy-- since destroy() doesn't cover interpreter diff --git a/tests/unit/cli/test_batch_async.py b/tests/unit/cli/test_batch_async.py new file mode 100644 index 0000000000..f65b6a06c3 @@ -944,6 +937,6 @@ index 0000000000..f65b6a06c3 + (self.batch.find_job, {'foo'}) + ) -- -2.23.0 +2.16.4 diff --git a/avoid-excessive-syslogging-by-watchdog-cronjob-58.patch b/avoid-excessive-syslogging-by-watchdog-cronjob-58.patch index 2a29f57..4dc6978 100644 --- a/avoid-excessive-syslogging-by-watchdog-cronjob-58.patch +++ b/avoid-excessive-syslogging-by-watchdog-cronjob-58.patch @@ -1,4 +1,4 @@ -From 47adf8fbd8ff1baeef83b2ba8f525dfd5eaef123 Mon Sep 17 00:00:00 2001 +From 638ad2baa04e96f744f97c97f3840151937e8aac Mon Sep 17 00:00:00 2001 From: Hubert Mantel Date: Mon, 27 Nov 2017 13:55:13 +0100 Subject: [PATCH] avoid excessive syslogging by watchdog cronjob (#58) diff --git a/avoid-traceback-when-http.query-request-cannot-be-pe.patch b/avoid-traceback-when-http.query-request-cannot-be-pe.patch index c210136..a82a4e9 100644 --- a/avoid-traceback-when-http.query-request-cannot-be-pe.patch +++ b/avoid-traceback-when-http.query-request-cannot-be-pe.patch @@ -1,4 +1,4 @@ -From 58504344b62fd577c0ef9c8d55378ea668a57912 Mon Sep 17 00:00:00 2001 +From e45658e074fbf8c038816dc56b86c3daf33d6ebc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?= Date: Mon, 29 Jul 2019 11:17:53 +0100 @@ -11,11 +11,11 @@ Improve error logging when http.query cannot be performed 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/salt/utils/http.py b/salt/utils/http.py -index c75ca73a85..ced01e110f 100644 +index dee0563679..c2fdffb266 100644 --- a/salt/utils/http.py +++ b/salt/utils/http.py -@@ -567,11 +567,13 @@ def query(url, - except tornado.httpclient.HTTPError as exc: +@@ -580,11 +580,13 @@ def query(url, + except salt.ext.tornado.httpclient.HTTPError as exc: ret['status'] = exc.code ret['error'] = six.text_type(exc) + log.error("Cannot perform 'http.query': {0} - {1}".format(url_full, ret['error'])) diff --git a/backport-saltutil-state-module-to-2019.2-codebase.patch b/backport-saltutil-state-module-to-2019.2-codebase.patch deleted file mode 100644 index 9d4dd70..0000000 --- a/backport-saltutil-state-module-to-2019.2-codebase.patch +++ /dev/null @@ -1,465 +0,0 @@ -From d99badeda9818ba54a3af1d0145c5278fe0edee1 Mon Sep 17 00:00:00 2001 -From: Christian McHugh -Date: Wed, 24 Oct 2018 15:49:58 +0100 -Subject: [PATCH] Backport "saltutil" state module to 2019.2 codebase - -add individual syncers and release note - -add individual syncers - -adjust state comment output and cleanup tests ---- - salt/states/saltutil.py | 311 +++++++++++++++++++++++++++++ - tests/unit/states/test_saltutil.py | 121 +++++++++++ - 2 files changed, 432 insertions(+) - create mode 100644 salt/states/saltutil.py - create mode 100644 tests/unit/states/test_saltutil.py - -diff --git a/salt/states/saltutil.py b/salt/states/saltutil.py -new file mode 100644 -index 0000000000000000000000000000000000000000..99952a1b7d1b8a70bac940ec083eb75776c146c6 ---- /dev/null -+++ b/salt/states/saltutil.py -@@ -0,0 +1,311 @@ -+# -*- coding: utf-8 -*- -+''' -+Saltutil State -+============== -+ -+This state wraps the saltutil execution modules to make them easier to run -+from a states. Rather than needing to to use ``module.run`` this state allows for -+improved change detection. -+ -+ .. versionadded: Neon -+''' -+from __future__ import absolute_import, unicode_literals, print_function -+ -+import logging -+ -+# Define the module's virtual name -+__virtualname__ = 'saltutil' -+ -+log = logging.getLogger(__name__) -+ -+ -+def __virtual__(): -+ ''' -+ Named saltutil -+ ''' -+ return __virtualname__ -+ -+ -+def _sync_single(name, module, **kwargs): -+ ret = {'name': name, 'changes': {}, 'result': True, 'comment': ''} -+ -+ if __opts__['test']: -+ ret['result'] = None -+ ret['comment'] = "saltutil.sync_{0} would have been run".format(module) -+ return ret -+ -+ try: -+ sync_status = __salt__['saltutil.sync_{0}'.format(module)](**kwargs) -+ if sync_status: -+ ret['changes'][module] = sync_status -+ ret['comment'] = "Updated {0}.".format(module) -+ except Exception as e: -+ log.error("Failed to run saltutil.sync_%s: %s", module, e) -+ ret['result'] = False -+ ret['comment'] = "Failed to run sync_{0}: {1}".format(module, e) -+ return ret -+ -+ if not ret['changes']: -+ ret['comment'] = "No updates to sync" -+ -+ return ret -+ -+ -+def sync_all(name, **kwargs): -+ ''' -+ Performs the same task as saltutil.sync_all module -+ See :mod:`saltutil module for full list of options ` -+ -+ .. code-block:: yaml -+ -+ sync_everything: -+ saltutil.sync_all: -+ - refresh: True -+ ''' -+ ret = {'name': name, 'changes': {}, 'result': True, 'comment': ''} -+ -+ if __opts__['test']: -+ ret['result'] = None -+ ret['comment'] = "saltutil.sync_all would have been run" -+ return ret -+ -+ try: -+ sync_status = __salt__['saltutil.sync_all'](**kwargs) -+ for key, value in sync_status.items(): -+ if value: -+ ret['changes'][key] = value -+ ret['comment'] = "Sync performed" -+ except Exception as e: -+ log.error("Failed to run saltutil.sync_all: %s", e) -+ ret['result'] = False -+ ret['comment'] = "Failed to run sync_all: {0}".format(e) -+ return ret -+ -+ if not ret['changes']: -+ ret['comment'] = "No updates to sync" -+ -+ return ret -+ -+ -+def sync_beacons(name, **kwargs): -+ ''' -+ Performs the same task as saltutil.sync_beacons module -+ See :mod:`saltutil module for full list of options ` -+ -+ .. code-block:: yaml -+ -+ sync_everything: -+ saltutil.sync_beacons: -+ - refresh: True -+ ''' -+ return _sync_single(name, "beacons", **kwargs) -+ -+ -+def sync_clouds(name, **kwargs): -+ ''' -+ Performs the same task as saltutil.sync_clouds module -+ See :mod:`saltutil module for full list of options ` -+ -+ .. code-block:: yaml -+ -+ sync_everything: -+ saltutil.sync_clouds: -+ - refresh: True -+ ''' -+ return _sync_single(name, "clouds", **kwargs) -+ -+ -+def sync_engines(name, **kwargs): -+ ''' -+ Performs the same task as saltutil.sync_engines module -+ See :mod:`saltutil module for full list of options ` -+ -+ .. code-block:: yaml -+ -+ sync_everything: -+ saltutil.sync_engines: -+ - refresh: True -+ ''' -+ return _sync_single(name, "engines", **kwargs) -+ -+ -+def sync_grains(name, **kwargs): -+ ''' -+ Performs the same task as saltutil.sync_grains module -+ See :mod:`saltutil module for full list of options ` -+ -+ .. code-block:: yaml -+ -+ sync_everything: -+ saltutil.sync_grains: -+ - refresh: True -+ ''' -+ return _sync_single(name, "grains", **kwargs) -+ -+ -+def sync_log_handlers(name, **kwargs): -+ ''' -+ Performs the same task as saltutil.sync_log_handlers module -+ See :mod:`saltutil module for full list of options ` -+ -+ .. code-block:: yaml -+ -+ sync_everything: -+ saltutil.sync_log_handlers: -+ - refresh: True -+ ''' -+ return _sync_single(name, "log_handlers", **kwargs) -+ -+ -+def sync_modules(name, **kwargs): -+ ''' -+ Performs the same task as saltutil.sync_modules module -+ See :mod:`saltutil module for full list of options ` -+ -+ .. code-block:: yaml -+ -+ sync_everything: -+ saltutil.sync_modules: -+ - refresh: True -+ ''' -+ return _sync_single(name, "modules", **kwargs) -+ -+ -+def sync_output(name, **kwargs): -+ ''' -+ Performs the same task as saltutil.sync_output module -+ See :mod:`saltutil module for full list of options ` -+ -+ .. code-block:: yaml -+ -+ sync_everything: -+ saltutil.sync_output: -+ - refresh: True -+ ''' -+ return _sync_single(name, "output", **kwargs) -+ -+ -+def sync_outputters(name, **kwargs): -+ ''' -+ Performs the same task as saltutil.sync_outputters module -+ See :mod:`saltutil module for full list of options ` -+ -+ .. code-block:: yaml -+ -+ sync_everything: -+ saltutil.sync_outputters: -+ - refresh: True -+ ''' -+ return _sync_single(name, "outputters", **kwargs) -+ -+ -+def sync_pillar(name, **kwargs): -+ ''' -+ Performs the same task as saltutil.sync_pillar module -+ See :mod:`saltutil module for full list of options ` -+ -+ .. code-block:: yaml -+ -+ sync_everything: -+ saltutil.sync_pillar: -+ - refresh: True -+ ''' -+ return _sync_single(name, "pillar", **kwargs) -+ -+ -+def sync_proxymodules(name, **kwargs): -+ ''' -+ Performs the same task as saltutil.sync_proxymodules module -+ See :mod:`saltutil module for full list of options ` -+ -+ .. code-block:: yaml -+ -+ sync_everything: -+ saltutil.sync_proxymodules: -+ - refresh: True -+ ''' -+ return _sync_single(name, "proxymodules", **kwargs) -+ -+ -+def sync_renderers(name, **kwargs): -+ ''' -+ Performs the same task as saltutil.sync_renderers module -+ See :mod:`saltutil module for full list of options ` -+ -+ .. code-block:: yaml -+ -+ sync_everything: -+ saltutil.sync_renderers: -+ - refresh: True -+ ''' -+ return _sync_single(name, "renderers", **kwargs) -+ -+ -+def sync_returners(name, **kwargs): -+ ''' -+ Performs the same task as saltutil.sync_returners module -+ See :mod:`saltutil module for full list of options ` -+ -+ .. code-block:: yaml -+ -+ sync_everything: -+ saltutil.sync_returners: -+ - refresh: True -+ ''' -+ return _sync_single(name, "returners", **kwargs) -+ -+ -+def sync_sdb(name, **kwargs): -+ ''' -+ Performs the same task as saltutil.sync_sdb module -+ See :mod:`saltutil module for full list of options ` -+ -+ .. code-block:: yaml -+ -+ sync_everything: -+ saltutil.sync_sdb: -+ - refresh: True -+ ''' -+ return _sync_single(name, "sdb", **kwargs) -+ -+ -+def sync_states(name, **kwargs): -+ ''' -+ Performs the same task as saltutil.sync_states module -+ See :mod:`saltutil module for full list of options ` -+ -+ .. code-block:: yaml -+ -+ sync_everything: -+ saltutil.sync_states: -+ - refresh: True -+ ''' -+ return _sync_single(name, "states", **kwargs) -+ -+ -+def sync_thorium(name, **kwargs): -+ ''' -+ Performs the same task as saltutil.sync_thorium module -+ See :mod:`saltutil module for full list of options ` -+ -+ .. code-block:: yaml -+ -+ sync_everything: -+ saltutil.sync_thorium: -+ - refresh: True -+ ''' -+ return _sync_single(name, "thorium", **kwargs) -+ -+ -+def sync_utils(name, **kwargs): -+ ''' -+ Performs the same task as saltutil.sync_utils module -+ See :mod:`saltutil module for full list of options ` -+ -+ .. code-block:: yaml -+ -+ sync_everything: -+ saltutil.sync_utils: -+ - refresh: True -+ ''' -+ return _sync_single(name, "utils", **kwargs) -diff --git a/tests/unit/states/test_saltutil.py b/tests/unit/states/test_saltutil.py -new file mode 100644 -index 0000000000000000000000000000000000000000..707201e9e2d3c285ed497e7f497158907a1834eb ---- /dev/null -+++ b/tests/unit/states/test_saltutil.py -@@ -0,0 +1,121 @@ -+# -*- coding: utf-8 -*- -+''' -+ Tests for the saltutil state -+''' -+# Import Python libs -+from __future__ import absolute_import, print_function, unicode_literals -+ -+# Import Salt Testing Libs -+from tests.support.mixins import LoaderModuleMockMixin -+from tests.support.unit import skipIf, TestCase -+from tests.support.mock import ( -+ NO_MOCK, -+ NO_MOCK_REASON, -+ MagicMock, -+ patch -+) -+ -+# Import Salt Libs -+import salt.states.saltutil as saltutil -+ -+ -+@skipIf(NO_MOCK, NO_MOCK_REASON) -+class Saltutil(TestCase, LoaderModuleMockMixin): -+ ''' -+ Test cases for salt.states.saltutil -+ ''' -+ def setup_loader_modules(self): -+ return {saltutil: {'__opts__': {'test': False}}} -+ -+ def test_saltutil_sync_all_nochange(self): -+ sync_output = { -+ "clouds": [], -+ "engines": [], -+ "grains": [], -+ "beacons": [], -+ "utils": [], -+ "returners": [], -+ "modules": [], -+ "renderers": [], -+ "log_handlers": [], -+ "thorium": [], -+ "states": [], -+ "sdb": [], -+ "proxymodules": [], -+ "output": [], -+ "pillar": [] -+ } -+ state_id = 'somename' -+ state_result = {'changes': {}, -+ 'comment': 'No updates to sync', -+ 'name': 'somename', -+ 'result': True -+ } -+ -+ mock_moduleout = MagicMock(return_value=sync_output) -+ with patch.dict(saltutil.__salt__, {'saltutil.sync_all': mock_moduleout}): -+ result = saltutil.sync_all(state_id, refresh=True) -+ self.assertEqual(result, state_result) -+ -+ def test_saltutil_sync_all_test(self): -+ sync_output = { -+ "clouds": [], -+ "engines": [], -+ "grains": [], -+ "beacons": [], -+ "utils": [], -+ "returners": [], -+ "modules": [], -+ "renderers": [], -+ "log_handlers": [], -+ "thorium": [], -+ "states": [], -+ "sdb": [], -+ "proxymodules": [], -+ "output": [], -+ "pillar": [] -+ } -+ state_id = 'somename' -+ state_result = {'changes': {}, -+ 'comment': 'saltutil.sync_all would have been run', -+ 'name': 'somename', -+ 'result': None -+ } -+ -+ mock_moduleout = MagicMock(return_value=sync_output) -+ with patch.dict(saltutil.__salt__, {'saltutil.sync_all': mock_moduleout}): -+ with patch.dict(saltutil.__opts__, {"test": True}): -+ result = saltutil.sync_all(state_id, refresh=True) -+ self.assertEqual(result, state_result) -+ -+ -+ def test_saltutil_sync_all_change(self): -+ sync_output = { -+ "clouds": [], -+ "engines": [], -+ "grains": [], -+ "beacons": [], -+ "utils": [], -+ "returners": [], -+ "modules": ["modules.file"], -+ "renderers": [], -+ "log_handlers": [], -+ "thorium": [], -+ "states": ["states.saltutil", "states.ssh_auth"], -+ "sdb": [], -+ "proxymodules": [], -+ "output": [], -+ "pillar": [] -+ } -+ state_id = 'somename' -+ state_result = {'changes': {'modules': ['modules.file'], -+ 'states': ['states.saltutil', 'states.ssh_auth']}, -+ 'comment': 'Sync performed', -+ 'name': 'somename', -+ 'result': True -+ } -+ -+ mock_moduleout = MagicMock(return_value=sync_output) -+ with patch.dict(saltutil.__salt__, {'saltutil.sync_all': mock_moduleout}): -+ result = saltutil.sync_all(state_id, refresh=True) -+ self.assertEqual(result, state_result) --- -2.23.0 - - diff --git a/batch-async-catch-exceptions-and-safety-unregister-a.patch b/batch-async-catch-exceptions-and-safety-unregister-a.patch index bb5bc74..c87e6bc 100644 --- a/batch-async-catch-exceptions-and-safety-unregister-a.patch +++ b/batch-async-catch-exceptions-and-safety-unregister-a.patch @@ -1,9 +1,9 @@ -From cd0e4240e11dfe8a656de1c8d8f1c7f5c6655311 Mon Sep 17 00:00:00 2001 +From c5edf396ffd66b6ac1479aa01367aae3eff7683d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?= Date: Fri, 28 Feb 2020 15:11:53 +0000 -Subject: [PATCH] Batch Async: Catch exceptions and safety unregister - and close instances +Subject: [PATCH] Batch Async: Catch exceptions and safety unregister and + close instances --- salt/cli/batch_async.py | 156 +++++++++++++++++++++++----------------- diff --git a/batch.py-avoid-exception-when-minion-does-not-respon.patch b/batch.py-avoid-exception-when-minion-does-not-respon.patch index 971bd90..c7e4ea0 100644 --- a/batch.py-avoid-exception-when-minion-does-not-respon.patch +++ b/batch.py-avoid-exception-when-minion-does-not-respon.patch @@ -1,4 +1,4 @@ -From b7e1ff5b0d023fef1f86fa970323dc01bfaabd41 Mon Sep 17 00:00:00 2001 +From bbd2e622f7e165a6e16fd5edf5f4596764748208 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?= Date: Wed, 5 Jun 2019 15:15:04 +0100 diff --git a/batch_async-avoid-using-fnmatch-to-match-event-217.patch b/batch_async-avoid-using-fnmatch-to-match-event-217.patch index 1429c4d..b26a2d6 100644 --- a/batch_async-avoid-using-fnmatch-to-match-event-217.patch +++ b/batch_async-avoid-using-fnmatch-to-match-event-217.patch @@ -1,8 +1,7 @@ -From 885940513b7a5c800fcc33dd47f2e92e864ec230 Mon Sep 17 00:00:00 2001 +From bd20cd2655a1141fe9ea892e974e40988c3fb83c Mon Sep 17 00:00:00 2001 From: Silvio Moioli Date: Mon, 2 Mar 2020 11:23:59 +0100 -Subject: [PATCH] batch_async: avoid using fnmatch to match event - (#217) +Subject: [PATCH] batch_async: avoid using fnmatch to match event (#217) --- salt/cli/batch_async.py | 2 +- diff --git a/bugfix-any-unicode-string-of-length-16-will-raise-ty.patch b/bugfix-any-unicode-string-of-length-16-will-raise-ty.patch deleted file mode 100644 index 1f5e760..0000000 --- a/bugfix-any-unicode-string-of-length-16-will-raise-ty.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 160103e536cfb5c956d64ed13b9c633153fb7a2e Mon Sep 17 00:00:00 2001 -From: Bo Maryniuk -Date: Fri, 5 Oct 2018 12:02:08 +0200 -Subject: [PATCH] Bugfix: any unicode string of length 16 will raise - TypeError instead of ValueError - ---- - salt/_compat.py | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/salt/_compat.py b/salt/_compat.py -index 61842b4bf3..42153f2395 100644 ---- a/salt/_compat.py -+++ b/salt/_compat.py -@@ -190,8 +190,8 @@ class IPv6AddressScoped(ipaddress.IPv6Address): - packed = False - if isinstance(data, bytes) and len(data) == 16 and b':' not in data: - try: -- packed = bool(int(binascii.hexlify(data), 16)) -- except ValueError: -+ packed = bool(int(str(bytearray(data)).encode('hex'), 16)) -+ except (ValueError, TypeError): - pass - - return packed --- -2.16.4 - - diff --git a/calculate-fqdns-in-parallel-to-avoid-blockings-bsc-1.patch b/calculate-fqdns-in-parallel-to-avoid-blockings-bsc-1.patch index 8902b16..9ac3008 100644 --- a/calculate-fqdns-in-parallel-to-avoid-blockings-bsc-1.patch +++ b/calculate-fqdns-in-parallel-to-avoid-blockings-bsc-1.patch @@ -1,4 +1,4 @@ -From e27ccce1429fa604137df35d8dabbc8016c2b5c9 Mon Sep 17 00:00:00 2001 +From 07f5a1d984b5a86c24620503f5e373ea0f11484a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?= Date: Fri, 12 Apr 2019 16:47:03 +0100 @@ -11,7 +11,7 @@ Fix pylint issue 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/salt/grains/core.py b/salt/grains/core.py -index 7d75d48bb5..ac66a437fd 100644 +index 309e4c9c4a..4600f055dd 100644 --- a/salt/grains/core.py +++ b/salt/grains/core.py @@ -20,12 +20,15 @@ import platform @@ -30,7 +30,7 @@ index 7d75d48bb5..ac66a437fd 100644 # pylint: disable=import-error try: import dateutil.tz -@@ -2255,13 +2258,10 @@ def fqdns(): +@@ -2275,13 +2278,10 @@ def fqdns(): grains = {} fqdns = set() @@ -44,9 +44,9 @@ index 7d75d48bb5..ac66a437fd 100644 - fqdns.update([socket.getfqdn(name)] + [als for als in aliaslist if salt.utils.network.is_fqdn(als)]) + return [socket.getfqdn(name)] + [als for als in aliaslist if salt.utils.network.is_fqdn(als)] except socket.herror as err: - if err.errno == 0: + if err.errno in (0, HOST_NOT_FOUND, NO_DATA): # No FQDN for this IP address, so we don't need to know this all the time. -@@ -2271,6 +2271,27 @@ def fqdns(): +@@ -2291,6 +2291,27 @@ def fqdns(): except (socket.error, socket.gaierror, socket.timeout) as err: log.error(err_message, ip, err) diff --git a/changed-imports-to-vendored-tornado.patch b/changed-imports-to-vendored-tornado.patch new file mode 100644 index 0000000..0226156 --- /dev/null +++ b/changed-imports-to-vendored-tornado.patch @@ -0,0 +1,274 @@ +From 0cf1a655aa9353b22ae011e492a33aa52d780f83 Mon Sep 17 00:00:00 2001 +From: Jochen Breuer +Date: Tue, 10 Mar 2020 14:02:17 +0100 +Subject: [PATCH] Changed imports to vendored Tornado + +--- + salt/cli/batch_async.py | 26 ++++++++++++------------ + salt/master.py | 2 +- + salt/transport/ipc.py | 4 ++-- + tests/unit/cli/test_batch_async.py | 32 +++++++++++++++--------------- + 4 files changed, 32 insertions(+), 32 deletions(-) + +diff --git a/salt/cli/batch_async.py b/salt/cli/batch_async.py +index b8f272ed67..08eeb34f1c 100644 +--- a/salt/cli/batch_async.py ++++ b/salt/cli/batch_async.py +@@ -6,7 +6,7 @@ Execute a job on the targeted minions by using a moving window of fixed size `ba + # Import python libs + from __future__ import absolute_import, print_function, unicode_literals + import gc +-import tornado ++import salt.ext.tornado + + # Import salt libs + import salt.client +@@ -50,7 +50,7 @@ class BatchAsync(object): + } + ''' + def __init__(self, parent_opts, jid_gen, clear_load): +- ioloop = tornado.ioloop.IOLoop.current() ++ ioloop = salt.ext.tornado.ioloop.IOLoop.current() + self.local = salt.client.get_local_client(parent_opts['conf_file'], io_loop=ioloop) + if 'gather_job_timeout' in clear_load['kwargs']: + clear_load['gather_job_timeout'] = clear_load['kwargs'].pop('gather_job_timeout') +@@ -152,7 +152,7 @@ class BatchAsync(object): + self.find_job_returned = self.find_job_returned.difference(running) + self.event.io_loop.spawn_callback(self.find_job, running) + +- @tornado.gen.coroutine ++ @salt.ext.tornado.gen.coroutine + def find_job(self, minions): + if self.event: + not_done = minions.difference(self.done_minions).difference(self.timedout_minions) +@@ -170,7 +170,7 @@ class BatchAsync(object): + gather_job_timeout=self.opts['gather_job_timeout'], + jid=jid, + **self.eauth) +- yield tornado.gen.sleep(self.opts['gather_job_timeout']) ++ yield salt.ext.tornado.gen.sleep(self.opts['gather_job_timeout']) + if self.event: + self.event.io_loop.spawn_callback( + self.check_find_job, +@@ -180,7 +180,7 @@ class BatchAsync(object): + log.error("Exception occured handling batch async: {}. Aborting execution.".format(ex)) + self.close_safe() + +- @tornado.gen.coroutine ++ @salt.ext.tornado.gen.coroutine + def start(self): + if self.event: + self.__set_event_handler() +@@ -198,11 +198,11 @@ class BatchAsync(object): + **self.eauth) + self.targeted_minions = set(ping_return['minions']) + #start batching even if not all minions respond to ping +- yield tornado.gen.sleep(self.batch_presence_ping_timeout or self.opts['gather_job_timeout']) ++ yield salt.ext.tornado.gen.sleep(self.batch_presence_ping_timeout or self.opts['gather_job_timeout']) + if self.event: + self.event.io_loop.spawn_callback(self.start_batch) + +- @tornado.gen.coroutine ++ @salt.ext.tornado.gen.coroutine + def start_batch(self): + if not self.initialized: + self.batch_size = get_bnum(self.opts, self.minions, True) +@@ -216,7 +216,7 @@ class BatchAsync(object): + if self.event: + self.event.io_loop.spawn_callback(self.run_next) + +- @tornado.gen.coroutine ++ @salt.ext.tornado.gen.coroutine + def end_batch(self): + left = self.minions.symmetric_difference(self.done_minions.union(self.timedout_minions)) + if not left and not self.ended: +@@ -232,7 +232,7 @@ class BatchAsync(object): + + # release to the IOLoop to allow the event to be published + # before closing batch async execution +- yield tornado.gen.sleep(1) ++ yield salt.ext.tornado.gen.sleep(1) + self.close_safe() + + def close_safe(self): +@@ -245,16 +245,16 @@ class BatchAsync(object): + del self + gc.collect() + +- @tornado.gen.coroutine ++ @salt.ext.tornado.gen.coroutine + def schedule_next(self): + if not self.scheduled: + self.scheduled = True + # call later so that we maybe gather more returns +- yield tornado.gen.sleep(self.batch_delay) ++ yield salt.ext.tornado.gen.sleep(self.batch_delay) + if self.event: + self.event.io_loop.spawn_callback(self.run_next) + +- @tornado.gen.coroutine ++ @salt.ext.tornado.gen.coroutine + def run_next(self): + self.scheduled = False + next_batch = self._get_next() +@@ -272,7 +272,7 @@ class BatchAsync(object): + jid=self.batch_jid, + metadata=self.metadata) + +- yield tornado.gen.sleep(self.opts['timeout']) ++ yield salt.ext.tornado.gen.sleep(self.opts['timeout']) + + # The batch can be done already at this point, which means no self.event + if self.event: +diff --git a/salt/master.py b/salt/master.py +index 3abf7ae60b..3a9d12999d 100644 +--- a/salt/master.py ++++ b/salt/master.py +@@ -2049,7 +2049,7 @@ class ClearFuncs(object): + functools.partial(self._prep_jid, clear_load, {}), + batch_load + ) +- ioloop = tornado.ioloop.IOLoop.current() ++ ioloop = salt.ext.tornado.ioloop.IOLoop.current() + ioloop.add_callback(batch.start) + + return { +diff --git a/salt/transport/ipc.py b/salt/transport/ipc.py +index d2b295a633..33ee3d4182 100644 +--- a/salt/transport/ipc.py ++++ b/salt/transport/ipc.py +@@ -697,7 +697,7 @@ class IPCMessageSubscriber(IPCClient): + for callback in self.callbacks: + self.io_loop.spawn_callback(callback, raw) + +- @tornado.gen.coroutine ++ @salt.ext.tornado.gen.coroutine + def read_async(self): + ''' + Asynchronously read messages and invoke a callback when they are ready. +@@ -712,7 +712,7 @@ class IPCMessageSubscriber(IPCClient): + yield salt.ext.tornado.gen.sleep(1) + except Exception as exc: # pylint: disable=broad-except + log.error('Exception occurred while Subscriber connecting: %s', exc) +- yield tornado.gen.sleep(1) ++ yield salt.ext.tornado.gen.sleep(1) + yield self._read(None, self.__run_callbacks) + + def close(self): +diff --git a/tests/unit/cli/test_batch_async.py b/tests/unit/cli/test_batch_async.py +index e1ce60859b..635dc689a8 100644 +--- a/tests/unit/cli/test_batch_async.py ++++ b/tests/unit/cli/test_batch_async.py +@@ -5,8 +5,8 @@ from __future__ import absolute_import + # Import Salt Libs + from salt.cli.batch_async import BatchAsync + +-import tornado +-from tornado.testing import AsyncTestCase ++import salt.ext.tornado ++from salt.ext.tornado.testing import AsyncTestCase + from tests.support.unit import skipIf, TestCase + from tests.support.mock import MagicMock, patch, NO_MOCK, NO_MOCK_REASON + +@@ -59,10 +59,10 @@ class AsyncBatchTestCase(AsyncTestCase, TestCase): + self.batch.start_batch() + self.assertEqual(self.batch.batch_size, 2) + +- @tornado.testing.gen_test ++ @salt.ext.tornado.testing.gen_test + def test_batch_start_on_batch_presence_ping_timeout(self): + self.batch.event = MagicMock() +- future = tornado.gen.Future() ++ future = salt.ext.tornado.gen.Future() + future.set_result({'minions': ['foo', 'bar']}) + self.batch.local.run_job_async.return_value = future + ret = self.batch.start() +@@ -78,10 +78,10 @@ class AsyncBatchTestCase(AsyncTestCase, TestCase): + # assert targeted_minions == all minions matched by tgt + self.assertEqual(self.batch.targeted_minions, set(['foo', 'bar'])) + +- @tornado.testing.gen_test ++ @salt.ext.tornado.testing.gen_test + def test_batch_start_on_gather_job_timeout(self): + self.batch.event = MagicMock() +- future = tornado.gen.Future() ++ future = salt.ext.tornado.gen.Future() + future.set_result({'minions': ['foo', 'bar']}) + self.batch.local.run_job_async.return_value = future + self.batch.batch_presence_ping_timeout = None +@@ -109,7 +109,7 @@ class AsyncBatchTestCase(AsyncTestCase, TestCase): + ) + ) + +- @tornado.testing.gen_test ++ @salt.ext.tornado.testing.gen_test + def test_start_batch_calls_next(self): + self.batch.run_next = MagicMock(return_value=MagicMock()) + self.batch.event = MagicMock() +@@ -165,14 +165,14 @@ class AsyncBatchTestCase(AsyncTestCase, TestCase): + self.assertEqual( + len(event.remove_event_handler.mock_calls), 1) + +- @tornado.testing.gen_test ++ @salt.ext.tornado.testing.gen_test + def test_batch_next(self): + self.batch.event = MagicMock() + self.batch.opts['fun'] = 'my.fun' + self.batch.opts['arg'] = [] + self.batch._get_next = MagicMock(return_value={'foo', 'bar'}) + self.batch.batch_size = 2 +- future = tornado.gen.Future() ++ future = salt.ext.tornado.gen.Future() + future.set_result({'minions': ['foo', 'bar']}) + self.batch.local.run_job_async.return_value = future + self.batch.run_next() +@@ -284,38 +284,38 @@ class AsyncBatchTestCase(AsyncTestCase, TestCase): + self.batch._BatchAsync__event_handler(MagicMock()) + self.assertEqual(self.batch.find_job_returned, {'foo'}) + +- @tornado.testing.gen_test ++ @salt.ext.tornado.testing.gen_test + def test_batch_run_next_end_batch_when_no_next(self): + self.batch.end_batch = MagicMock() + self.batch._get_next = MagicMock(return_value={}) + self.batch.run_next() + self.assertEqual(len(self.batch.end_batch.mock_calls), 1) + +- @tornado.testing.gen_test ++ @salt.ext.tornado.testing.gen_test + def test_batch_find_job(self): + self.batch.event = MagicMock() +- future = tornado.gen.Future() ++ future = salt.ext.tornado.gen.Future() + future.set_result({}) + self.batch.local.run_job_async.return_value = future + self.batch.minions = set(['foo', 'bar']) + self.batch.jid_gen = MagicMock(return_value="1234") +- tornado.gen.sleep = MagicMock(return_value=future) ++ salt.ext.tornado.gen.sleep = MagicMock(return_value=future) + self.batch.find_job({'foo', 'bar'}) + self.assertEqual( + self.batch.event.io_loop.spawn_callback.call_args[0], + (self.batch.check_find_job, {'foo', 'bar'}, "1234") + ) + +- @tornado.testing.gen_test ++ @salt.ext.tornado.testing.gen_test + def test_batch_find_job_with_done_minions(self): + self.batch.done_minions = {'bar'} + self.batch.event = MagicMock() +- future = tornado.gen.Future() ++ future = salt.ext.tornado.gen.Future() + future.set_result({}) + self.batch.local.run_job_async.return_value = future + self.batch.minions = set(['foo', 'bar']) + self.batch.jid_gen = MagicMock(return_value="1234") +- tornado.gen.sleep = MagicMock(return_value=future) ++ salt.ext.tornado.gen.sleep = MagicMock(return_value=future) + self.batch.find_job({'foo', 'bar'}) + self.assertEqual( + self.batch.event.io_loop.spawn_callback.call_args[0], +-- +2.23.0 + + diff --git a/checking-for-jid-before-returning-data.patch b/checking-for-jid-before-returning-data.patch deleted file mode 100644 index 94e419f..0000000 --- a/checking-for-jid-before-returning-data.patch +++ /dev/null @@ -1,35 +0,0 @@ -From d1e016a5deb8f79adc8473b02171b5661cb93ea8 Mon Sep 17 00:00:00 2001 -From: Jochen Breuer -Date: Tue, 9 Apr 2019 16:32:46 +0200 -Subject: [PATCH] Checking for jid before returning data - -Seems raw can have returns for the same minion, but an other job. In -order to not return resutls from the wrong job, we need to check for the -jid. ---- - salt/client/__init__.py | 8 ++++++-- - 1 file changed, 6 insertions(+), 2 deletions(-) - -diff --git a/salt/client/__init__.py b/salt/client/__init__.py -index 8b37422cbf..aff354a021 100644 ---- a/salt/client/__init__.py -+++ b/salt/client/__init__.py -@@ -1560,8 +1560,12 @@ class LocalClient(object): - if 'minions' in raw.get('data', {}): - continue - try: -- found.add(raw['id']) -- ret = {raw['id']: {'ret': raw['return']}} -+ # There might be two jobs for the same minion, so we have to check for the jid -+ if jid == raw['jid']: -+ found.add(raw['id']) -+ ret = {raw['id']: {'ret': raw['return']}} -+ else: -+ continue - except KeyError: - # Ignore other erroneous messages - continue --- -2.16.4 - - diff --git a/debian-info_installed-compatibility-50453.patch b/debian-info_installed-compatibility-50453.patch index 925eb13..dbb7665 100644 --- a/debian-info_installed-compatibility-50453.patch +++ b/debian-info_installed-compatibility-50453.patch @@ -1,4 +1,4 @@ -From f7ae2b3ebe7d78ca60ada7fd2bb30f3cdbd75427 Mon Sep 17 00:00:00 2001 +From 068eecfba4b2a14b334ff17a295d4005d17491f3 Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Tue, 20 Nov 2018 16:06:31 +0100 Subject: [PATCH] Debian info_installed compatibility (#50453) @@ -51,15 +51,15 @@ Fix wrong Git merge: missing function signature --- salt/modules/aptpkg.py | 20 ++++- salt/modules/dpkg_lowpkg.py | 93 +++++++++++++++++--- - tests/unit/modules/test_aptpkg.py | 151 +++++++++++++++++++++------------ - tests/unit/modules/test_dpkg_lowpkg.py | 69 +++++++++++++++ - 4 files changed, 267 insertions(+), 66 deletions(-) + tests/unit/modules/test_aptpkg.py | 153 +++++++++++++++++++++------------ + tests/unit/modules/test_dpkg_lowpkg.py | 127 ++++++++++++++------------- + 4 files changed, 263 insertions(+), 130 deletions(-) diff --git a/salt/modules/aptpkg.py b/salt/modules/aptpkg.py -index 6b3a921a82..64620647c2 100644 +index 8f4d95a195..4ec9158476 100644 --- a/salt/modules/aptpkg.py +++ b/salt/modules/aptpkg.py -@@ -2776,6 +2776,15 @@ def info_installed(*names, **kwargs): +@@ -2825,6 +2825,15 @@ def info_installed(*names, **kwargs): .. versionadded:: 2016.11.3 @@ -75,7 +75,7 @@ index 6b3a921a82..64620647c2 100644 CLI example: .. code-block:: bash -@@ -2786,11 +2795,15 @@ def info_installed(*names, **kwargs): +@@ -2835,11 +2844,15 @@ def info_installed(*names, **kwargs): ''' kwargs = salt.utils.args.clean_kwargs(**kwargs) failhard = kwargs.pop('failhard', True) @@ -90,9 +90,9 @@ index 6b3a921a82..64620647c2 100644 - for pkg_name, pkg_nfo in __salt__['lowpkg.info'](*names, failhard=failhard).items(): + for pkg_name, pkg_nfo in __salt__['lowpkg.info'](*names, failhard=failhard, attr=attr).items(): t_nfo = dict() - # Translate dpkg-specific keys to a common structure - for key, value in pkg_nfo.items(): -@@ -2807,7 +2820,10 @@ def info_installed(*names, **kwargs): + if pkg_nfo.get('status', 'ii')[1] != 'i': + continue # return only packages that are really installed +@@ -2860,7 +2873,10 @@ def info_installed(*names, **kwargs): else: t_nfo[key] = value @@ -105,7 +105,7 @@ index 6b3a921a82..64620647c2 100644 return ret diff --git a/salt/modules/dpkg_lowpkg.py b/salt/modules/dpkg_lowpkg.py -index 03be5f821a..26ca5dcf5a 100644 +index 4ac8efd2f2..b78e844830 100644 --- a/salt/modules/dpkg_lowpkg.py +++ b/salt/modules/dpkg_lowpkg.py @@ -252,6 +252,38 @@ def file_dict(*packages): @@ -156,7 +156,7 @@ index 03be5f821a..26ca5dcf5a 100644 "maintainer:${Maintainer}\\n" \ "summary:${Summary}\\n" \ "source:${source:Package}\\n" \ -@@ -307,9 +339,14 @@ def _get_pkg_info(*packages, **kwargs): +@@ -308,9 +340,14 @@ def _get_pkg_info(*packages, **kwargs): key, value = pkg_info_line.split(":", 1) if value: pkg_data[key] = value @@ -174,7 +174,7 @@ index 03be5f821a..26ca5dcf5a 100644 pkg_data['description'] = pkg_descr.split(":", 1)[-1] ret.append(pkg_data) -@@ -335,19 +372,32 @@ def _get_pkg_license(pkg): +@@ -336,19 +373,32 @@ def _get_pkg_license(pkg): return ", ".join(sorted(licenses)) @@ -213,7 +213,7 @@ index 03be5f821a..26ca5dcf5a 100644 def _get_pkg_ds_avail(): -@@ -397,6 +447,15 @@ def info(*packages, **kwargs): +@@ -398,6 +448,15 @@ def info(*packages, **kwargs): .. versionadded:: 2016.11.3 @@ -229,7 +229,7 @@ index 03be5f821a..26ca5dcf5a 100644 CLI example: .. code-block:: bash -@@ -411,6 +470,10 @@ def info(*packages, **kwargs): +@@ -412,6 +471,10 @@ def info(*packages, **kwargs): kwargs = salt.utils.args.clean_kwargs(**kwargs) failhard = kwargs.pop('failhard', True) @@ -240,7 +240,7 @@ index 03be5f821a..26ca5dcf5a 100644 if kwargs: salt.utils.args.invalid_kwargs(kwargs) -@@ -430,6 +493,14 @@ def info(*packages, **kwargs): +@@ -431,6 +494,14 @@ def info(*packages, **kwargs): lic = _get_pkg_license(pkg['package']) if lic: pkg['license'] = lic @@ -257,10 +257,10 @@ index 03be5f821a..26ca5dcf5a 100644 return ret diff --git a/tests/unit/modules/test_aptpkg.py b/tests/unit/modules/test_aptpkg.py -index 1e963ee5db..580b840197 100644 +index e1b6602df5..10e960f090 100644 --- a/tests/unit/modules/test_aptpkg.py +++ b/tests/unit/modules/test_aptpkg.py -@@ -20,6 +20,8 @@ from tests.support.mock import Mock, MagicMock, patch, NO_MOCK, NO_MOCK_REASON +@@ -20,6 +20,8 @@ from tests.support.mock import Mock, MagicMock, patch from salt.ext import six from salt.exceptions import CommandExecutionError, SaltInvocationError import salt.modules.aptpkg as aptpkg @@ -269,7 +269,7 @@ index 1e963ee5db..580b840197 100644 try: import pytest -@@ -148,51 +150,39 @@ class AptPkgTestCase(TestCase, LoaderModuleMockMixin): +@@ -166,51 +168,39 @@ class AptPkgTestCase(TestCase, LoaderModuleMockMixin): def setup_loader_modules(self): return {aptpkg: {}} @@ -334,7 +334,7 @@ index 1e963ee5db..580b840197 100644 def test_get_repo_keys(self): ''' -@@ -205,35 +195,31 @@ class AptPkgTestCase(TestCase, LoaderModuleMockMixin): +@@ -223,35 +213,31 @@ class AptPkgTestCase(TestCase, LoaderModuleMockMixin): with patch.dict(aptpkg.__salt__, {'cmd.run_all': mock}): self.assertEqual(aptpkg.get_repo_keys(), REPO_KEYS) @@ -381,13 +381,15 @@ index 1e963ee5db..580b840197 100644 def test_info_installed(self): ''' Test - Return the information of the named package(s) installed on the system. -@@ -249,19 +235,72 @@ class AptPkgTestCase(TestCase, LoaderModuleMockMixin): +@@ -267,21 +253,72 @@ class AptPkgTestCase(TestCase, LoaderModuleMockMixin): if installed['wget'].get(names[name], False): installed['wget'][name] = installed['wget'].pop(names[name]) - mock = MagicMock(return_value=LOWPKG_INFO) - with patch.dict(aptpkg.__salt__, {'lowpkg.info': mock}): +- del installed['wget']['status'] - self.assertEqual(aptpkg.info_installed('wget'), installed) +- self.assertEqual(len(aptpkg.info_installed()), 1) + assert aptpkg.info_installed('wget') == installed + + @patch('salt.modules.aptpkg.__salt__', {'lowpkg.info': MagicMock(return_value=LOWPKG_INFO)}) @@ -461,7 +463,7 @@ index 1e963ee5db..580b840197 100644 def test_refresh_db(self): ''' Test - Updates the APT database to latest packages based upon repositories. -@@ -281,6 +320,10 @@ class AptPkgTestCase(TestCase, LoaderModuleMockMixin): +@@ -301,6 +338,10 @@ class AptPkgTestCase(TestCase, LoaderModuleMockMixin): with patch.dict(aptpkg.__salt__, {'cmd.run_all': mock, 'config.get': MagicMock(return_value=False)}): self.assertEqual(aptpkg.refresh_db(), refresh_db) @@ -472,7 +474,7 @@ index 1e963ee5db..580b840197 100644 def test_refresh_db_failed(self): ''' Test - Update the APT database using unreachable repositories. -@@ -312,22 +355,24 @@ class AptPkgTestCase(TestCase, LoaderModuleMockMixin): +@@ -332,22 +373,24 @@ class AptPkgTestCase(TestCase, LoaderModuleMockMixin): assert aptpkg.autoremove(list_only=True) == [] assert aptpkg.autoremove(list_only=True, purge=True) == [] @@ -504,10 +506,10 @@ index 1e963ee5db..580b840197 100644 ''' Test - Upgrades all packages. diff --git a/tests/unit/modules/test_dpkg_lowpkg.py b/tests/unit/modules/test_dpkg_lowpkg.py -index bdcb7eec89..d16ce3cc1a 100644 +index 6c07a75417..a0b3346f9d 100644 --- a/tests/unit/modules/test_dpkg_lowpkg.py +++ b/tests/unit/modules/test_dpkg_lowpkg.py -@@ -25,6 +25,30 @@ class DpkgTestCase(TestCase, LoaderModuleMockMixin): +@@ -23,6 +23,30 @@ class DpkgTestCase(TestCase, LoaderModuleMockMixin): ''' Test cases for salt.modules.dpkg ''' @@ -538,19 +540,80 @@ index bdcb7eec89..d16ce3cc1a 100644 def setup_loader_modules(self): return {dpkg: {}} -@@ -102,3 +126,48 @@ class DpkgTestCase(TestCase, LoaderModuleMockMixin): - 'stdout': 'Salt'}) +@@ -101,68 +125,47 @@ class DpkgTestCase(TestCase, LoaderModuleMockMixin): with patch.dict(dpkg.__salt__, {'cmd.run_all': mock}): self.assertEqual(dpkg.file_dict('httpd'), 'Error: error') -+ + + @patch('salt.modules.dpkg._get_pkg_ds_avail', MagicMock(return_value=dselect_pkg)) + @patch('salt.modules.dpkg._get_pkg_info', MagicMock(return_value=pkgs_info)) + @patch('salt.modules.dpkg._get_pkg_license', MagicMock(return_value='BSD v3')) -+ def test_info(self): -+ ''' + def test_info(self): + ''' +- Test package info + Test info + :return: -+ ''' + ''' +- mock = MagicMock(return_value={'retcode': 0, +- 'stderr': '', +- 'stdout': +- os.linesep.join([ +- 'package:bash', +- 'revision:', +- 'architecture:amd64', +- 'maintainer:Ubuntu Developers ', +- 'summary:', +- 'source:bash', +- 'version:4.4.18-2ubuntu1', +- 'section:shells', +- 'installed_size:1588', +- 'size:', +- 'MD5:', +- 'SHA1:', +- 'SHA256:', +- 'origin:', +- 'homepage:http://tiswww.case.edu/php/chet/bash/bashtop.html', +- 'status:ii ', +- '======', +- 'description:GNU Bourne Again SHell', +- ' Bash is an sh-compatible command language interpreter that executes', +- ' commands read from the standard input or from a file. Bash also', +- ' incorporates useful features from the Korn and C shells (ksh and csh).', +- ' .', +- ' Bash is ultimately intended to be a conformant implementation of the', +- ' IEEE POSIX Shell and Tools specification (IEEE Working Group 1003.2).', +- ' .', +- ' The Programmable Completion Code, by Ian Macdonald, is now found in', +- ' the bash-completion package.', +- '------' +- ])}) +- +- with patch.dict(dpkg.__salt__, {'cmd.run_all': mock}), \ +- patch.dict(dpkg.__grains__, {'os': 'Ubuntu', 'osrelease_info': (18, 4)}), \ +- patch('salt.utils.path.which', MagicMock(return_value=False)), \ +- patch('os.path.exists', MagicMock(return_value=False)),\ +- patch('os.path.getmtime', MagicMock(return_value=1560199259.0)): +- self.assertDictEqual(dpkg.info('bash'), +- {'bash': {'architecture': 'amd64', +- 'description': os.linesep.join([ +- 'GNU Bourne Again SHell', +- ' Bash is an sh-compatible command language interpreter that executes', +- ' commands read from the standard input or from a file. Bash also', +- ' incorporates useful features from the Korn and C shells (ksh and csh).', +- ' .', +- ' Bash is ultimately intended to be a conformant implementation of the', +- ' IEEE POSIX Shell and Tools specification (IEEE Working Group 1003.2).', +- ' .', +- ' The Programmable Completion Code, by Ian Macdonald, is now found in', +- ' the bash-completion package.' + os.linesep +- ]), +- 'homepage': 'http://tiswww.case.edu/php/chet/bash/bashtop.html', +- 'maintainer': 'Ubuntu Developers ' +- '', +- 'package': 'bash', +- 'section': 'shells', +- 'source': 'bash', +- 'status': 'ii', +- 'version': '4.4.18-2ubuntu1'}}) + ret = dpkg.info('emacs') + + assert isinstance(ret, dict) diff --git a/decide-if-the-source-should-be-actually-skipped.patch b/decide-if-the-source-should-be-actually-skipped.patch index d25756f..3f625c4 100644 --- a/decide-if-the-source-should-be-actually-skipped.patch +++ b/decide-if-the-source-should-be-actually-skipped.patch @@ -1,4 +1,4 @@ -From 263c8c98a5601179a53c00523a1579883e705f1f Mon Sep 17 00:00:00 2001 +From 615a8f8dfa8ef12eeb4c387e48309cc466b8597d Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Tue, 4 Dec 2018 16:39:08 +0100 Subject: [PATCH] Decide if the source should be actually skipped @@ -8,10 +8,10 @@ Subject: [PATCH] Decide if the source should be actually skipped 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/salt/modules/aptpkg.py b/salt/modules/aptpkg.py -index 64620647c2..4a331444c9 100644 +index 4ec9158476..3b0d8423db 100644 --- a/salt/modules/aptpkg.py +++ b/salt/modules/aptpkg.py -@@ -1574,6 +1574,27 @@ def list_repo_pkgs(*args, **kwargs): # pylint: disable=unused-import +@@ -1620,6 +1620,27 @@ def list_repo_pkgs(*args, **kwargs): # pylint: disable=unused-import return ret @@ -39,7 +39,7 @@ index 64620647c2..4a331444c9 100644 def list_repos(): ''' Lists all repos in the sources.list (and sources.lists.d) files -@@ -1589,7 +1610,7 @@ def list_repos(): +@@ -1635,7 +1656,7 @@ def list_repos(): repos = {} sources = sourceslist.SourcesList() for source in sources.list: diff --git a/do-not-break-repo-files-with-multiple-line-values-on.patch b/do-not-break-repo-files-with-multiple-line-values-on.patch index f90f8e6..cf5bd69 100644 --- a/do-not-break-repo-files-with-multiple-line-values-on.patch +++ b/do-not-break-repo-files-with-multiple-line-values-on.patch @@ -1,4 +1,4 @@ -From a8f289c4eb03c051d8ffc60eed28985f3b49d921 Mon Sep 17 00:00:00 2001 +From f81a5b92d691c1d511a814f9344104dd37466bc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?= Date: Wed, 29 May 2019 11:03:16 +0100 @@ -6,51 +6,14 @@ Subject: [PATCH] Do not break repo files with multiple line values on yumpkg (bsc#1135360) --- - salt/modules/yumpkg.py | 16 +++++++++--- tests/integration/modules/test_pkg.py | 48 +++++++++++++++++++++++++++++++++++ - 2 files changed, 60 insertions(+), 4 deletions(-) + 1 file changed, 48 insertions(+) -diff --git a/salt/modules/yumpkg.py b/salt/modules/yumpkg.py -index 5ec3835574..3a4fe47a45 100644 ---- a/salt/modules/yumpkg.py -+++ b/salt/modules/yumpkg.py -@@ -2763,7 +2763,12 @@ def del_repo(repo, basedir=None, **kwargs): # pylint: disable=W0613 - del filerepos[stanza]['comments'] - content += '\n[{0}]'.format(stanza) - for line in filerepos[stanza]: -- content += '\n{0}={1}'.format(line, filerepos[stanza][line]) -+ # A whitespace is needed at the begining of the new line in order -+ # to avoid breaking multiple line values allowed on repo files. -+ value = filerepos[stanza][line] -+ if isinstance(value, six.string_types) and '\n' in value: -+ value = '\n '.join(value.split('\n')) -+ content += '\n{0}={1}'.format(line, value) - content += '\n{0}\n'.format(comments) - - with salt.utils.files.fopen(repofile, 'w') as fileout: -@@ -2898,11 +2903,14 @@ def mod_repo(repo, basedir=None, **kwargs): - ) - content += '[{0}]\n'.format(stanza) - for line in six.iterkeys(filerepos[stanza]): -+ # A whitespace is needed at the begining of the new line in order -+ # to avoid breaking multiple line values allowed on repo files. -+ value = filerepos[stanza][line] -+ if isinstance(value, six.string_types) and '\n' in value: -+ value = '\n '.join(value.split('\n')) - content += '{0}={1}\n'.format( - line, -- filerepos[stanza][line] -- if not isinstance(filerepos[stanza][line], bool) -- else _bool_to_str(filerepos[stanza][line]) -+ value if not isinstance(value, bool) else _bool_to_str(value) - ) - content += comments + '\n' - diff --git a/tests/integration/modules/test_pkg.py b/tests/integration/modules/test_pkg.py -index 66ac3cfb61..7204428eca 100644 +index e8374db2c0..61748f9477 100644 --- a/tests/integration/modules/test_pkg.py +++ b/tests/integration/modules/test_pkg.py -@@ -136,6 +136,54 @@ class PkgModuleTest(ModuleCase, SaltReturnAssertsMixin): +@@ -182,6 +182,54 @@ class PkgModuleTest(ModuleCase, SaltReturnAssertsMixin): if repo is not None: self.run_function('pkg.del_repo', [repo]) diff --git a/do-not-crash-when-there-are-ipv6-established-connect.patch b/do-not-crash-when-there-are-ipv6-established-connect.patch index 4ad9713..5c10d80 100644 --- a/do-not-crash-when-there-are-ipv6-established-connect.patch +++ b/do-not-crash-when-there-are-ipv6-established-connect.patch @@ -1,4 +1,4 @@ -From c6c8ce93bb0be6fe22fb5d65517a002595a9eb7b Mon Sep 17 00:00:00 2001 +From bfee3a7c47786bb860663de97fca26725101f1d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?= Date: Tue, 7 May 2019 15:33:51 +0100 @@ -7,75 +7,28 @@ Subject: [PATCH] Do not crash when there are IPv6 established Add unit test for '_netlink_tool_remote_on' --- - salt/utils/network.py | 5 +++-- - tests/unit/utils/test_network.py | 16 ++++++++++++++++ - 2 files changed, 19 insertions(+), 2 deletions(-) + salt/utils/network.py | 5 +++++ + 1 file changed, 5 insertions(+) diff --git a/salt/utils/network.py b/salt/utils/network.py -index a183c9776a..a3fd6e848e 100644 +index 2ae2e213b7..307cab885f 100644 --- a/salt/utils/network.py +++ b/salt/utils/network.py -@@ -1457,7 +1457,7 @@ def _parse_tcp_line(line): - - def _netlink_tool_remote_on(port, which_end): - ''' -- Returns set of ipv4 host addresses of remote established connections -+ Returns set of IPv4/IPv6 host addresses of remote established connections - on local or remote tcp port. - - Parses output of shell 'ss' to get connections -@@ -1467,6 +1467,7 @@ def _netlink_tool_remote_on(port, which_end): - LISTEN 0 511 *:80 *:* - LISTEN 0 128 *:22 *:* - ESTAB 0 0 127.0.0.1:56726 127.0.0.1:4505 -+ ESTAB 0 0 [::ffff:127.0.0.1]:41323 [::ffff:127.0.0.1]:4505 - ''' - remotes = set() - valid = False -@@ -1493,7 +1494,7 @@ def _netlink_tool_remote_on(port, which_end): +@@ -1442,8 +1442,13 @@ def _netlink_tool_remote_on(port, which_end): + elif 'ESTAB' not in line: continue - if which_end == 'local_port' and int(local_port) != port: - continue -- remotes.add(remote_host) -+ remotes.add(remote_host.strip("[]")) + chunks = line.split() ++ local_host, local_port = chunks[3].rsplit(':', 1) + remote_host, remote_port = chunks[4].rsplit(':', 1) + ++ if which_end == 'remote_port' and int(remote_port) != port: ++ continue ++ if which_end == 'local_port' and int(local_port) != port: ++ continue + remotes.add(remote_host.strip("[]")) if valid is False: - remotes = None -diff --git a/tests/unit/utils/test_network.py b/tests/unit/utils/test_network.py -index f4c849d124..06e3aea6ea 100644 ---- a/tests/unit/utils/test_network.py -+++ b/tests/unit/utils/test_network.py -@@ -128,6 +128,14 @@ ESTAB 0 0 127.0.0.1:56726 127.0. - ESTAB 0 0 ::ffff:1.2.3.4:5678 ::ffff:1.2.3.4:4505 - ''' - -+LINUX_NETLINK_SS_OUTPUT = '''\ -+State Recv-Q Send-Q Local Address:Port Peer Address:Port -+TIME-WAIT 0 0 [::1]:8009 [::1]:40368 -+LISTEN 0 128 127.0.0.1:5903 0.0.0.0:* -+ESTAB 0 0 [::ffff:127.0.0.1]:4506 [::ffff:127.0.0.1]:32315 -+ESTAB 0 0 192.168.122.1:4506 192.168.122.177:24545 -+''' -+ - IPV4_SUBNETS = {True: ('10.10.0.0/24',), - False: ('10.10.0.0', '10.10.0.0/33', 'FOO', 9, '0.9.800.1000/24')} - IPV6_SUBNETS = {True: ('::1/128',), -@@ -491,6 +499,14 @@ class NetworkTestCase(TestCase): - remotes = network._freebsd_remotes_on('4506', 'remote') - self.assertEqual(remotes, set(['127.0.0.1'])) - -+ def test_netlink_tool_remote_on(self): -+ with patch('salt.utils.platform.is_sunos', lambda: False): -+ with patch('salt.utils.platform.is_linux', lambda: True): -+ with patch('subprocess.check_output', -+ return_value=LINUX_NETLINK_SS_OUTPUT): -+ remotes = network._netlink_tool_remote_on('4506', 'local') -+ self.assertEqual(remotes, set(['192.168.122.177', '::ffff:127.0.0.1'])) -+ - def test_generate_minion_id_distinct(self): - ''' - Test if minion IDs are distinct in the pool. -- -2.16.4 +2.23.0 diff --git a/do-not-load-pip-state-if-there-is-no-3rd-party-depen.patch b/do-not-load-pip-state-if-there-is-no-3rd-party-depen.patch index 09019a6..a1a4cce 100644 --- a/do-not-load-pip-state-if-there-is-no-3rd-party-depen.patch +++ b/do-not-load-pip-state-if-there-is-no-3rd-party-depen.patch @@ -1,4 +1,4 @@ -From 016e0c30718dac2a144090f82a2c35d5ce13bb8c Mon Sep 17 00:00:00 2001 +From b1c96bdaec9723fd76a6dd5d72cf7fbfd681566f Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Fri, 21 Sep 2018 17:31:39 +0200 Subject: [PATCH] Do not load pip state if there is no 3rd party @@ -10,10 +10,10 @@ Safe import 3rd party dependency 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/salt/modules/pip.py b/salt/modules/pip.py -index eac40c719c..988ae695a7 100644 +index ffdb73aefa..ff0836c35f 100644 --- a/salt/modules/pip.py +++ b/salt/modules/pip.py -@@ -79,7 +79,10 @@ from __future__ import absolute_import, print_function, unicode_literals +@@ -82,7 +82,10 @@ from __future__ import absolute_import, print_function, unicode_literals # Import python libs import logging import os @@ -25,7 +25,7 @@ index eac40c719c..988ae695a7 100644 import re import shutil import sys -@@ -116,7 +119,12 @@ def __virtual__(): +@@ -119,7 +122,12 @@ def __virtual__(): entire filesystem. If it's not installed in a conventional location, the user is required to provide the location of pip each time it is used. ''' diff --git a/do-not-make-ansiblegate-to-crash-on-python3-minions.patch b/do-not-make-ansiblegate-to-crash-on-python3-minions.patch index bcd99dc..6725766 100644 --- a/do-not-make-ansiblegate-to-crash-on-python3-minions.patch +++ b/do-not-make-ansiblegate-to-crash-on-python3-minions.patch @@ -1,4 +1,4 @@ -From ee69f252a71b950377987d7fad3515082e09abff Mon Sep 17 00:00:00 2001 +From 235cca81be2f64ed3feb48ed42bfa3f9196bff39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?= Date: Fri, 28 Jun 2019 15:17:56 +0100 @@ -13,11 +13,11 @@ Add unit test for ansible caller salt/modules/ansiblegate.py | 14 +++++++++--- tests/support/mock.py | 31 +++++++++++++++++++++++++ tests/unit/modules/test_ansiblegate.py | 41 ++++++++++++++++++++++++++++++++++ - tests/unit/modules/test_cmdmod.py | 34 +--------------------------- - 4 files changed, 84 insertions(+), 36 deletions(-) + tests/unit/modules/test_cmdmod.py | 35 ++--------------------------- + 4 files changed, 85 insertions(+), 36 deletions(-) diff --git a/salt/modules/ansiblegate.py b/salt/modules/ansiblegate.py -index 771db6d6aa..88e8147573 100644 +index 6b903c2b94..8e28fcafa3 100644 --- a/salt/modules/ansiblegate.py +++ b/salt/modules/ansiblegate.py @@ -147,6 +147,10 @@ class AnsibleModuleCaller(object): @@ -57,10 +57,10 @@ index 771db6d6aa..88e8147573 100644 for arg in args: info = doc.get(arg) diff --git a/tests/support/mock.py b/tests/support/mock.py -index 38b68bd5c4..4b44c112ee 100644 +index 805a60377c..67ecb4838a 100644 --- a/tests/support/mock.py +++ b/tests/support/mock.py -@@ -510,6 +510,37 @@ class MockOpen(object): +@@ -461,6 +461,37 @@ class MockOpen(object): ret.extend(fh_.writelines_calls) return ret @@ -99,26 +99,24 @@ index 38b68bd5c4..4b44c112ee 100644 # reimplement mock_open to support multiple filehandles mock_open = MockOpen diff --git a/tests/unit/modules/test_ansiblegate.py b/tests/unit/modules/test_ansiblegate.py -index 1fbb083eb7..70b47f8bc2 100644 +index 5613a0e79b..b7b43efda4 100644 --- a/tests/unit/modules/test_ansiblegate.py +++ b/tests/unit/modules/test_ansiblegate.py -@@ -29,6 +29,7 @@ from tests.support.unit import TestCase, skipIf +@@ -29,11 +29,13 @@ from tests.support.unit import TestCase, skipIf from tests.support.mock import ( patch, MagicMock, + MockTimedProc, - NO_MOCK, - NO_MOCK_REASON ) -@@ -36,6 +37,7 @@ from tests.support.mock import ( + import salt.modules.ansiblegate as ansible import salt.utils.platform from salt.exceptions import LoaderError +from salt.ext import six - @skipIf(NO_MOCK, NO_MOCK_REASON) -@@ -137,3 +139,42 @@ description: + @skipIf(NO_PYTEST, False) +@@ -134,3 +136,42 @@ description: ''' with patch('salt.modules.ansiblegate.ansible', None): assert ansible.__virtual__() == 'ansible' @@ -162,18 +160,18 @@ index 1fbb083eb7..70b47f8bc2 100644 + proc.assert_any_call(['python', 'foofile'], stdin=ANSIBLE_MODULE_ARGS, stdout=-1, timeout=1200) + assert ret == {"completed": True, "timeout": 1200} diff --git a/tests/unit/modules/test_cmdmod.py b/tests/unit/modules/test_cmdmod.py -index 8da672dd22..a20afaca0f 100644 +index 8170a56b4e..f8fba59294 100644 --- a/tests/unit/modules/test_cmdmod.py +++ b/tests/unit/modules/test_cmdmod.py -@@ -24,6 +24,7 @@ from tests.support.paths import FILES +@@ -26,6 +26,7 @@ from tests.support.helpers import TstSuiteLoggingHandler from tests.support.mock import ( mock_open, Mock, + MockTimedProc, MagicMock, - NO_MOCK, - NO_MOCK_REASON, -@@ -36,39 +37,6 @@ MOCK_SHELL_FILE = '# List of acceptable shells\n' \ + patch + ) +@@ -36,39 +37,7 @@ MOCK_SHELL_FILE = '# List of acceptable shells\n' \ '/bin/bash\n' @@ -210,9 +208,10 @@ index 8da672dd22..a20afaca0f 100644 - return self._stderr - - - @skipIf(NO_MOCK, NO_MOCK_REASON) ++@skipIf(NO_MOCK, NO_MOCK_REASON) class CMDMODTestCase(TestCase, LoaderModuleMockMixin): ''' + Unit tests for the salt.modules.cmdmod module -- 2.16.4 diff --git a/do-not-report-patches-as-installed-when-not-all-the-.patch b/do-not-report-patches-as-installed-when-not-all-the-.patch index a39c354..aaa0af0 100644 --- a/do-not-report-patches-as-installed-when-not-all-the-.patch +++ b/do-not-report-patches-as-installed-when-not-all-the-.patch @@ -1,4 +1,4 @@ -From 3c39b7ae5e4a0cd11a77241abde9407a8e1b3f07 Mon Sep 17 00:00:00 2001 +From 7e9adda8dfd53050756d0ac0cf64570b76ce7365 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?= Date: Wed, 13 Mar 2019 16:14:07 +0000 @@ -7,38 +7,25 @@ Subject: [PATCH] Do not report patches as installed when not all the Co-authored-by: Mihai Dinca --- - salt/modules/yumpkg.py | 18 ++++++++++++------ - 1 file changed, 12 insertions(+), 6 deletions(-) + salt/modules/yumpkg.py | 4 ++++ + 1 file changed, 4 insertions(+) diff --git a/salt/modules/yumpkg.py b/salt/modules/yumpkg.py -index 4f26a41670..5ec3835574 100644 +index b1257d0de0..3ddf989511 100644 --- a/salt/modules/yumpkg.py +++ b/salt/modules/yumpkg.py -@@ -3212,12 +3212,18 @@ def _get_patches(installed_only=False): +@@ -3220,7 +3220,11 @@ def _get_patches(installed_only=False): for line in salt.utils.itertools.split(ret, os.linesep): inst, advisory_id, sev, pkg = re.match(r'([i|\s]) ([^\s]+) +([^\s]+) +([^\s]+)', line).groups() -- if inst != 'i' and installed_only: -- continue -- patches[advisory_id] = { -- 'installed': True if inst == 'i' else False, -- 'summary': pkg -- } ++<<<<<<< HEAD + if advisory_id not in patches: ++======= + if not advisory_id in patches: -+ patches[advisory_id] = { -+ 'installed': True if inst == 'i' else False, -+ 'summary': [pkg] -+ } -+ else: -+ patches[advisory_id]['summary'].append(pkg) -+ if inst != 'i': -+ patches[advisory_id]['installed'] = False -+ -+ if installed_only: -+ patches = {k: v for k, v in patches.items() if v['installed']} - return patches - - ++>>>>>>> Do not report patches as installed when not all the related packages are installed (bsc#1128061) + patches[advisory_id] = { + 'installed': True if inst == 'i' else False, + 'summary': [pkg] -- 2.16.4 diff --git a/don-t-call-zypper-with-more-than-one-no-refresh.patch b/don-t-call-zypper-with-more-than-one-no-refresh.patch index 5b8eec9..0929110 100644 --- a/don-t-call-zypper-with-more-than-one-no-refresh.patch +++ b/don-t-call-zypper-with-more-than-one-no-refresh.patch @@ -1,4 +1,4 @@ -From a2e40158ad3b92a20ec9c12f7cd75edb4a01c2fc Mon Sep 17 00:00:00 2001 +From c1f5e6332bf025394b81868bf1edc6ae44944a7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Bosdonnat?= Date: Tue, 29 Jan 2019 09:44:03 +0100 Subject: [PATCH] Don't call zypper with more than one --no-refresh @@ -11,7 +11,7 @@ passed twice. Make sure we won't hit this. 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/salt/modules/zypperpkg.py b/salt/modules/zypperpkg.py -index 92e7052020..7ac0df26c6 100644 +index 04a6a6872d..37428cf67c 100644 --- a/salt/modules/zypperpkg.py +++ b/salt/modules/zypperpkg.py @@ -282,7 +282,7 @@ class _Zypper(object): @@ -24,10 +24,10 @@ index 92e7052020..7ac0df26c6 100644 self.__cmd.extend(args) diff --git a/tests/unit/modules/test_zypperpkg.py b/tests/unit/modules/test_zypperpkg.py -index f586c23fd0..5c5091a570 100644 +index b3162f10cd..956902eab3 100644 --- a/tests/unit/modules/test_zypperpkg.py +++ b/tests/unit/modules/test_zypperpkg.py -@@ -138,7 +138,7 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin): +@@ -135,7 +135,7 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(zypper.__zypper__.call('foo'), stdout_xml_snippet) self.assertEqual(len(sniffer.calls), 1) diff --git a/early-feature-support-config.patch b/early-feature-support-config.patch index 7bd25fa..db7592a 100644 --- a/early-feature-support-config.patch +++ b/early-feature-support-config.patch @@ -1,4 +1,4 @@ -From 0e4ac6001d552e649f8ab9d6c04b18bd531e4240 Mon Sep 17 00:00:00 2001 +From 33a85b16a4740f3dd803fd0e47e26819afeecdd7 Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Tue, 10 Jul 2018 12:06:33 +0200 Subject: [PATCH] early feature: support-config @@ -291,24 +291,24 @@ Remove development stub. Ughh... Removed blacklist of pkg_resources --- - salt/cli/support/__init__.py | 65 ++++ - salt/cli/support/collector.py | 495 ++++++++++++++++++++++++++++++ - salt/cli/support/console.py | 165 ++++++++++ - salt/cli/support/intfunc.py | 42 +++ + salt/cli/support/__init__.py | 65 +++ + salt/cli/support/collector.py | 495 ++++++++++++++++++++++ + salt/cli/support/console.py | 165 ++++++++ + salt/cli/support/intfunc.py | 42 ++ salt/cli/support/localrunner.py | 34 ++ - salt/cli/support/profiles/default.yml | 71 +++++ + salt/cli/support/profiles/default.yml | 71 ++++ salt/cli/support/profiles/jobs-active.yml | 3 + salt/cli/support/profiles/jobs-last.yml | 3 + salt/cli/support/profiles/jobs-trace.yml | 7 + salt/cli/support/profiles/network.yml | 27 ++ salt/cli/support/profiles/postgres.yml | 11 + salt/cli/support/profiles/salt.yml | 9 + - salt/cli/support/profiles/users.yml | 22 ++ + salt/cli/support/profiles/users.yml | 22 + salt/scripts.py | 14 + - salt/utils/parsers.py | 65 ++++ + salt/utils/parsers.py | 65 +++ scripts/salt-support | 11 + setup.py | 2 + - tests/unit/cli/test_support.py | 477 ++++++++++++++++++++++++++++ + tests/unit/cli/test_support.py | 477 +++++++++++++++++++++ 18 files changed, 1523 insertions(+) create mode 100644 salt/cli/support/__init__.py create mode 100644 salt/cli/support/collector.py @@ -328,7 +328,7 @@ Removed blacklist of pkg_resources diff --git a/salt/cli/support/__init__.py b/salt/cli/support/__init__.py new file mode 100644 -index 0000000000..6a98a2d656 +index 0000000000000000000000000000000000000000..6a98a2d65656c0ad89d921b6842067a7399eab2c --- /dev/null +++ b/salt/cli/support/__init__.py @@ -0,0 +1,65 @@ @@ -399,7 +399,7 @@ index 0000000000..6a98a2d656 + return sorted(profiles) diff --git a/salt/cli/support/collector.py b/salt/cli/support/collector.py new file mode 100644 -index 0000000000..478d07e13b +index 0000000000000000000000000000000000000000..478d07e13bf264b5d0caacd487cc45441ff259fb --- /dev/null +++ b/salt/cli/support/collector.py @@ -0,0 +1,495 @@ @@ -900,7 +900,7 @@ index 0000000000..478d07e13b + sys.exit(exit_code) diff --git a/salt/cli/support/console.py b/salt/cli/support/console.py new file mode 100644 -index 0000000000..fb6992d657 +index 0000000000000000000000000000000000000000..fb6992d657e21a6b933e81135d812f7bd3720a9e --- /dev/null +++ b/salt/cli/support/console.py @@ -0,0 +1,165 @@ @@ -1071,7 +1071,7 @@ index 0000000000..fb6992d657 + return wrapper.wrap(txt) diff --git a/salt/cli/support/intfunc.py b/salt/cli/support/intfunc.py new file mode 100644 -index 0000000000..2727cd6394 +index 0000000000000000000000000000000000000000..2727cd6394c364e35c99403b75e7fd23856187c6 --- /dev/null +++ b/salt/cli/support/intfunc.py @@ -0,0 +1,42 @@ @@ -1119,7 +1119,7 @@ index 0000000000..2727cd6394 + filetree(collector, fname) diff --git a/salt/cli/support/localrunner.py b/salt/cli/support/localrunner.py new file mode 100644 -index 0000000000..26deb883bc +index 0000000000000000000000000000000000000000..26deb883bccc98079201d26deba01008cca72921 --- /dev/null +++ b/salt/cli/support/localrunner.py @@ -0,0 +1,34 @@ @@ -1159,7 +1159,7 @@ index 0000000000..26deb883bc + return self.low(fun, low, print_event=False, full_return=False) diff --git a/salt/cli/support/profiles/default.yml b/salt/cli/support/profiles/default.yml new file mode 100644 -index 0000000000..01d9a26193 +index 0000000000000000000000000000000000000000..01d9a261933333a6246e932556cdd88f3adf1f82 --- /dev/null +++ b/salt/cli/support/profiles/default.yml @@ -0,0 +1,71 @@ @@ -1236,7 +1236,7 @@ index 0000000000..01d9a26193 + diff --git a/salt/cli/support/profiles/jobs-active.yml b/salt/cli/support/profiles/jobs-active.yml new file mode 100644 -index 0000000000..508c54ece7 +index 0000000000000000000000000000000000000000..508c54ece79087c98ba2dd4bd0ee265b09520296 --- /dev/null +++ b/salt/cli/support/profiles/jobs-active.yml @@ -0,0 +1,3 @@ @@ -1245,7 +1245,7 @@ index 0000000000..508c54ece7 + info: List of all actively running jobs diff --git a/salt/cli/support/profiles/jobs-last.yml b/salt/cli/support/profiles/jobs-last.yml new file mode 100644 -index 0000000000..e3b719f552 +index 0000000000000000000000000000000000000000..e3b719f552d2288d15dc5af4d6c320e0386ed7d0 --- /dev/null +++ b/salt/cli/support/profiles/jobs-last.yml @@ -0,0 +1,3 @@ @@ -1254,7 +1254,7 @@ index 0000000000..e3b719f552 + info: List all detectable jobs and associated functions diff --git a/salt/cli/support/profiles/jobs-trace.yml b/salt/cli/support/profiles/jobs-trace.yml new file mode 100644 -index 0000000000..00b28e0502 +index 0000000000000000000000000000000000000000..00b28e0502e2e6dbd9fe3e990750cbc1f9a94a30 --- /dev/null +++ b/salt/cli/support/profiles/jobs-trace.yml @@ -0,0 +1,7 @@ @@ -1267,7 +1267,7 @@ index 0000000000..00b28e0502 + {% endfor %} diff --git a/salt/cli/support/profiles/network.yml b/salt/cli/support/profiles/network.yml new file mode 100644 -index 0000000000..268f02e61f +index 0000000000000000000000000000000000000000..268f02e61fbe9b5f0870569a9343da6e778a7017 --- /dev/null +++ b/salt/cli/support/profiles/network.yml @@ -0,0 +1,27 @@ @@ -1300,7 +1300,7 @@ index 0000000000..268f02e61f + info: ARP table diff --git a/salt/cli/support/profiles/postgres.yml b/salt/cli/support/profiles/postgres.yml new file mode 100644 -index 0000000000..2238752c7a +index 0000000000000000000000000000000000000000..2238752c7a90a09bddc9cd3cbf27acbbf2a85c1c --- /dev/null +++ b/salt/cli/support/profiles/postgres.yml @@ -0,0 +1,11 @@ @@ -1317,7 +1317,7 @@ index 0000000000..2238752c7a + - /etc/postgresql diff --git a/salt/cli/support/profiles/salt.yml b/salt/cli/support/profiles/salt.yml new file mode 100644 -index 0000000000..4b18d98870 +index 0000000000000000000000000000000000000000..4b18d9887002f9a9efdd6f54870db4b74384a19e --- /dev/null +++ b/salt/cli/support/profiles/salt.yml @@ -0,0 +1,9 @@ @@ -1332,7 +1332,7 @@ index 0000000000..4b18d98870 + - {{salt('config.get', 'log_file')}} diff --git a/salt/cli/support/profiles/users.yml b/salt/cli/support/profiles/users.yml new file mode 100644 -index 0000000000..391acdb606 +index 0000000000000000000000000000000000000000..391acdb606d2ebb35ac7cff10844fffd84d96915 --- /dev/null +++ b/salt/cli/support/profiles/users.yml @@ -0,0 +1,22 @@ @@ -1359,13 +1359,13 @@ index 0000000000..391acdb606 + info: List of all available groups + output: table diff --git a/salt/scripts.py b/salt/scripts.py -index 71120366e0..c789df4e39 100644 +index 5e623a578e8363b51e10af247b325069741064d5..401ec2055303dd3b342110ddbab155e30d5b4e31 100644 --- a/salt/scripts.py +++ b/salt/scripts.py -@@ -539,3 +539,17 @@ def salt_extend(extension, name, description, salt_dir, merge): - description=description, - salt_dir=salt_dir, - merge=merge) +@@ -579,3 +579,17 @@ def salt_unity(): + sys.argv.pop(1) + s_fun = getattr(sys.modules[__name__], 'salt_{0}'.format(cmd)) + s_fun() + + +def salt_support(): @@ -1381,10 +1381,10 @@ index 71120366e0..c789df4e39 100644 + _install_signal_handlers(client) + client.run() diff --git a/salt/utils/parsers.py b/salt/utils/parsers.py -index 1e652a845e..aa13310d5a 100644 +index fb9b0987a65ce1607de63f6f83ce96f6987800aa..83dfe717f6a66305ad1c2505da5d3aa380495171 100644 --- a/salt/utils/parsers.py +++ b/salt/utils/parsers.py -@@ -20,6 +20,7 @@ import getpass +@@ -21,6 +21,7 @@ import getpass import logging import optparse import traceback @@ -1392,15 +1392,15 @@ index 1e652a845e..aa13310d5a 100644 from functools import partial -@@ -34,6 +35,7 @@ import salt.utils.data +@@ -34,6 +35,7 @@ import salt.utils.args + import salt.utils.data import salt.utils.files import salt.utils.jid - import salt.utils.kinds as kinds +import salt.utils.network import salt.utils.platform import salt.utils.process import salt.utils.stringutils -@@ -1902,6 +1904,69 @@ class SyndicOptionParser(six.with_metaclass(OptionParserMeta, +@@ -1913,6 +1915,69 @@ class SyndicOptionParser(six.with_metaclass(OptionParserMeta, self.get_config_file_path('minion')) @@ -1472,7 +1472,7 @@ index 1e652a845e..aa13310d5a 100644 ConfigDirMixIn, diff --git a/scripts/salt-support b/scripts/salt-support new file mode 100755 -index 0000000000..48ce141c67 +index 0000000000000000000000000000000000000000..48ce141c673aa390174f88f0e18b857c561ab6f5 --- /dev/null +++ b/scripts/salt-support @@ -0,0 +1,11 @@ @@ -1488,10 +1488,10 @@ index 0000000000..48ce141c67 +if __name__ == '__main__': + salt_support() diff --git a/setup.py b/setup.py -index 3e930df8db..25e06a42f6 100755 +index 788664e14e1e93ffe51e9ace4409b48e9b4afeaf..06374647df5e82a21fc39b08d41c596f0483ff0c 100755 --- a/setup.py +++ b/setup.py -@@ -1051,6 +1051,7 @@ class SaltDistribution(distutils.dist.Distribution): +@@ -1058,6 +1058,7 @@ class SaltDistribution(distutils.dist.Distribution): 'scripts/salt-master', 'scripts/salt-minion', 'scripts/salt-proxy', @@ -1499,7 +1499,7 @@ index 3e930df8db..25e06a42f6 100755 'scripts/salt-ssh', 'scripts/salt-syndic', 'scripts/salt-unity', -@@ -1086,6 +1087,7 @@ class SaltDistribution(distutils.dist.Distribution): +@@ -1093,6 +1094,7 @@ class SaltDistribution(distutils.dist.Distribution): 'salt-key = salt.scripts:salt_key', 'salt-master = salt.scripts:salt_master', 'salt-minion = salt.scripts:salt_minion', @@ -1509,7 +1509,7 @@ index 3e930df8db..25e06a42f6 100755 'salt-unity = salt.scripts:salt_unity', diff --git a/tests/unit/cli/test_support.py b/tests/unit/cli/test_support.py new file mode 100644 -index 0000000000..85ea957d79 +index 0000000000000000000000000000000000000000..85ea957d7921257d9ebfff3c136438524008c7cd --- /dev/null +++ b/tests/unit/cli/test_support.py @@ -0,0 +1,477 @@ @@ -1991,6 +1991,6 @@ index 0000000000..85ea957d79 + assert jobs_trace['jobs-details'][0]['run:jobs.list_job']['info'] == 'Details on JID 0000' + assert jobs_trace['jobs-details'][0]['run:jobs.list_job']['args'] == [0] -- -2.16.4 +2.23.0 diff --git a/enable-passing-a-unix_socket-for-mysql-returners-bsc.patch b/enable-passing-a-unix_socket-for-mysql-returners-bsc.patch index 4003199..9c17720 100644 --- a/enable-passing-a-unix_socket-for-mysql-returners-bsc.patch +++ b/enable-passing-a-unix_socket-for-mysql-returners-bsc.patch @@ -1,4 +1,4 @@ -From 7482f815a80c2c789bc09e2c72c522e6eb091fa3 Mon Sep 17 00:00:00 2001 +From cc3bd759bc0e4cc3414ccc5a2928c593fa2eee04 Mon Sep 17 00:00:00 2001 From: Maximilian Meister Date: Thu, 3 May 2018 15:52:23 +0200 Subject: [PATCH] enable passing a unix_socket for mysql returners @@ -19,7 +19,7 @@ Signed-off-by: Maximilian Meister 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/salt/returners/mysql.py b/salt/returners/mysql.py -index fbaaacfe0d..06b249e664 100644 +index 69599ec36a..ff9d380843 100644 --- a/salt/returners/mysql.py +++ b/salt/returners/mysql.py @@ -18,6 +18,7 @@ config. These are the defaults: diff --git a/enable-passing-grains-to-start-event-based-on-start_.patch b/enable-passing-grains-to-start-event-based-on-start_.patch deleted file mode 100644 index bbd6ebe..0000000 --- a/enable-passing-grains-to-start-event-based-on-start_.patch +++ /dev/null @@ -1,132 +0,0 @@ -From 79f566ba99f48d60e4948c9b8df9c6b6f497eced Mon Sep 17 00:00:00 2001 -From: Abid Mehmood -Date: Thu, 1 Aug 2019 13:14:22 +0200 -Subject: [PATCH] enable passing grains to start event based on - 'start_event_grains' configuration parameter - -unit tests ---- - conf/minion | 5 +++++ - doc/ref/configuration/minion.rst | 15 +++++++++++++++ - salt/config/__init__.py | 1 + - salt/minion.py | 5 +++++ - tests/unit/test_minion.py | 32 ++++++++++++++++++++++++++++++++ - 5 files changed, 58 insertions(+) - -diff --git a/conf/minion b/conf/minion -index f2b6655932..cc7e962120 100644 ---- a/conf/minion -+++ b/conf/minion -@@ -548,6 +548,11 @@ - # - edit.vim - # - hyper - # -+# List of grains to pass in start event when minion starts up: -+#start_event_grains: -+# - machine_id -+# - uuid -+# - # Top file to execute if startup_states is 'top': - #top_file: '' - -diff --git a/doc/ref/configuration/minion.rst b/doc/ref/configuration/minion.rst -index 30343ebd8e..fe556ef9ce 100644 ---- a/doc/ref/configuration/minion.rst -+++ b/doc/ref/configuration/minion.rst -@@ -2000,6 +2000,21 @@ List of states to run when the minion starts up if ``startup_states`` is set to - - edit.vim - - hyper - -+.. conf_minion:: start_event_grains -+ -+``start_event_grains`` -+---------------------- -+ -+Default: ``[]`` -+ -+List of grains to pass in start event when minion starts up. -+ -+.. code-block:: yaml -+ -+ start_event_grains: -+ - machine_id -+ - uuid -+ - .. conf_minion:: top_file - - ``top_file`` -diff --git a/salt/config/__init__.py b/salt/config/__init__.py -index ee90eb3120..788128b903 100644 ---- a/salt/config/__init__.py -+++ b/salt/config/__init__.py -@@ -1283,6 +1283,7 @@ DEFAULT_MINION_OPTS = { - 'state_top_saltenv': None, - 'startup_states': '', - 'sls_list': [], -+ 'start_event_grains': [], - 'top_file': '', - 'thoriumenv': None, - 'thorium_top': 'top.sls', -diff --git a/salt/minion.py b/salt/minion.py -index 2c0a18604e..2b53da4f18 100644 ---- a/salt/minion.py -+++ b/salt/minion.py -@@ -1456,6 +1456,11 @@ class Minion(MinionBase): - else: - return - -+ if self.opts['start_event_grains']: -+ grains_to_add = dict( -+ [(k, v) for k, v in six.iteritems(self.opts.get('grains', {})) if k in self.opts['start_event_grains']]) -+ load['grains'] = grains_to_add -+ - if sync: - try: - self._send_req_sync(load, timeout) -diff --git a/tests/unit/test_minion.py b/tests/unit/test_minion.py -index b78e0f6abd..83215151ee 100644 ---- a/tests/unit/test_minion.py -+++ b/tests/unit/test_minion.py -@@ -305,6 +305,38 @@ class MinionTestCase(TestCase, AdaptedConfigurationTestCaseMixin): - finally: - minion.destroy() - -+ def test_when_passed_start_event_grains(self): -+ mock_opts = self.get_config('minion', from_scratch=True) -+ mock_opts['start_event_grains'] = ["os"] -+ io_loop = tornado.ioloop.IOLoop() -+ io_loop.make_current() -+ minion = salt.minion.Minion(mock_opts, io_loop=io_loop) -+ try: -+ minion.tok = MagicMock() -+ minion._send_req_sync = MagicMock() -+ minion._fire_master('Minion has started', 'minion_start') -+ load = minion._send_req_sync.call_args[0][0] -+ -+ self.assertTrue('grains' in load) -+ self.assertTrue('os' in load['grains']) -+ finally: -+ minion.destroy() -+ -+ def test_when_not_passed_start_event_grains(self): -+ mock_opts = self.get_config('minion', from_scratch=True) -+ io_loop = tornado.ioloop.IOLoop() -+ io_loop.make_current() -+ minion = salt.minion.Minion(mock_opts, io_loop=io_loop) -+ try: -+ minion.tok = MagicMock() -+ minion._send_req_sync = MagicMock() -+ minion._fire_master('Minion has started', 'minion_start') -+ load = minion._send_req_sync.call_args[0][0] -+ -+ self.assertTrue('grains' not in load) -+ finally: -+ minion.destroy() -+ - def test_minion_retry_dns_count(self): - ''' - Tests that the resolve_dns will retry dns look ups for a maximum of --- -2.16.4 - - diff --git a/fall-back-to-pymysql.patch b/fall-back-to-pymysql.patch index 4e43100..4f3c55b 100644 --- a/fall-back-to-pymysql.patch +++ b/fall-back-to-pymysql.patch @@ -1,4 +1,4 @@ -From 37a3628e3a3cd2d1f18e7834a151efab21b10433 Mon Sep 17 00:00:00 2001 +From f0098b4b9e5abaaca7bbc6c17f5a60bb2129dda5 Mon Sep 17 00:00:00 2001 From: Maximilian Meister Date: Thu, 5 Apr 2018 13:23:23 +0200 Subject: [PATCH] fall back to PyMySQL @@ -11,7 +11,7 @@ Signed-off-by: Maximilian Meister 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/salt/modules/mysql.py b/salt/modules/mysql.py -index 94f4b4acce..7e8e6026b3 100644 +index 87e2361e28..e785e5219c 100644 --- a/salt/modules/mysql.py +++ b/salt/modules/mysql.py @@ -58,7 +58,7 @@ try: diff --git a/fix-a-wrong-rebase-in-test_core.py-180.patch b/fix-a-wrong-rebase-in-test_core.py-180.patch index dc940f3..30be30c 100644 --- a/fix-a-wrong-rebase-in-test_core.py-180.patch +++ b/fix-a-wrong-rebase-in-test_core.py-180.patch @@ -1,4 +1,4 @@ -From 3812df3a2776e745160ef406dae85aa8acdf2333 Mon Sep 17 00:00:00 2001 +From 6418d9ebc3b269a0246262f79c0bab367e39cc52 Mon Sep 17 00:00:00 2001 From: Alberto Planas Date: Fri, 25 Oct 2019 15:43:16 +0200 Subject: [PATCH] Fix a wrong rebase in test_core.py (#180) @@ -22,10 +22,10 @@ This patch ignore this kind of issue during the grains creation. 2 files changed, 2 insertions(+), 47 deletions(-) diff --git a/salt/grains/core.py b/salt/grains/core.py -index 6b1f2d2223..31ed8a77aa 100644 +index 68c43482d3..20950988d9 100644 --- a/salt/grains/core.py +++ b/salt/grains/core.py -@@ -990,7 +990,7 @@ def _virtual(osdata): +@@ -1000,7 +1000,7 @@ def _virtual(osdata): except UnicodeDecodeError: # Some firmwares provide non-valid 'product_name' # files, ignore them @@ -34,7 +34,7 @@ index 6b1f2d2223..31ed8a77aa 100644 except IOError: pass elif osdata['kernel'] == 'FreeBSD': -@@ -2545,7 +2545,7 @@ def _hw_data(osdata): +@@ -2568,7 +2568,7 @@ def _hw_data(osdata): except UnicodeDecodeError: # Some firmwares provide non-valid 'product_name' # files, ignore them @@ -44,12 +44,12 @@ index 6b1f2d2223..31ed8a77aa 100644 # PermissionError is new to Python 3, but corresponds to the EACESS and # EPERM error numbers. Use those instead here for PY2 compatibility. diff --git a/tests/unit/grains/test_core.py b/tests/unit/grains/test_core.py -index 7153a078f4..09e197a2e4 100644 +index c4731f667a..b4ed9379e5 100644 --- a/tests/unit/grains/test_core.py +++ b/tests/unit/grains/test_core.py -@@ -1317,51 +1317,6 @@ class CoreGrainsTestCase(TestCase, LoaderModuleMockMixin): - 'uuid': '' - }) +@@ -1544,51 +1544,6 @@ class CoreGrainsTestCase(TestCase, LoaderModuleMockMixin): + self.assertIn('osfullname', os_grains) + self.assertEqual(os_grains.get('osfullname'), 'FreeBSD') - @skipIf(not salt.utils.platform.is_linux(), 'System is not Linux') - def test_kernelparams_return(self): diff --git a/fix-aptpkg-systemd-call-bsc-1143301.patch b/fix-aptpkg-systemd-call-bsc-1143301.patch index 604e33d..8ef7ab3 100644 --- a/fix-aptpkg-systemd-call-bsc-1143301.patch +++ b/fix-aptpkg-systemd-call-bsc-1143301.patch @@ -1,4 +1,4 @@ -From db65ebf356238c151af7798ed34684847ed4a5c0 Mon Sep 17 00:00:00 2001 +From c2989e749f04aa8477130df649e550f5349a9a1f Mon Sep 17 00:00:00 2001 From: Mihai Dinca Date: Wed, 31 Jul 2019 15:29:03 +0200 Subject: [PATCH] Fix aptpkg systemd call (bsc#1143301) @@ -9,10 +9,10 @@ Subject: [PATCH] Fix aptpkg systemd call (bsc#1143301) 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/salt/modules/aptpkg.py b/salt/modules/aptpkg.py -index e537f5b007..b7c1a342ef 100644 +index 13484c96bc..a5b039fc79 100644 --- a/salt/modules/aptpkg.py +++ b/salt/modules/aptpkg.py -@@ -165,7 +165,7 @@ def _call_apt(args, scope=True, **kwargs): +@@ -168,7 +168,7 @@ def _call_apt(args, scope=True, **kwargs): ''' cmd = [] if scope and salt.utils.systemd.has_scope(__context__) and __salt__['config.get']('systemd.scope', True): @@ -22,10 +22,10 @@ index e537f5b007..b7c1a342ef 100644 params = {'output_loglevel': 'trace', diff --git a/tests/unit/modules/test_aptpkg.py b/tests/unit/modules/test_aptpkg.py -index 580b840197..06f3a9f6aa 100644 +index 10e960f090..88eed062c4 100644 --- a/tests/unit/modules/test_aptpkg.py +++ b/tests/unit/modules/test_aptpkg.py -@@ -544,7 +544,7 @@ class AptUtilsTestCase(TestCase, LoaderModuleMockMixin): +@@ -645,7 +645,7 @@ class AptUtilsTestCase(TestCase, LoaderModuleMockMixin): with patch.dict(aptpkg.__salt__, {'cmd.run_all': MagicMock(), 'config.get': MagicMock(return_value=True)}): aptpkg._call_apt(['apt-get', 'purge', 'vim']) # pylint: disable=W0106 aptpkg.__salt__['cmd.run_all'].assert_called_once_with( diff --git a/fix-async-batch-multiple-done-events.patch b/fix-async-batch-multiple-done-events.patch index 25fad70..633c571 100644 --- a/fix-async-batch-multiple-done-events.patch +++ b/fix-async-batch-multiple-done-events.patch @@ -1,4 +1,4 @@ -From 2fe38d075efce89dd94c1088ab8c97656e589c8f Mon Sep 17 00:00:00 2001 +From 42d7e1de2c69d82447e73eab483e5d3c299d55f7 Mon Sep 17 00:00:00 2001 From: Mihai Dinca Date: Tue, 7 May 2019 12:24:35 +0200 Subject: [PATCH] Fix async-batch multiple done events diff --git a/fix-async-batch-race-conditions.patch b/fix-async-batch-race-conditions.patch index ee25943..6a114d2 100644 --- a/fix-async-batch-race-conditions.patch +++ b/fix-async-batch-race-conditions.patch @@ -1,4 +1,4 @@ -From 2c1311f544950fe417fb8609aa3a30da32656637 Mon Sep 17 00:00:00 2001 +From dc001cb47fd88a8e8a1bd82a1457325822d1220b Mon Sep 17 00:00:00 2001 From: Mihai Dinca Date: Thu, 11 Apr 2019 15:57:59 +0200 Subject: [PATCH] Fix async batch race conditions diff --git a/fix-batch_async-obsolete-test.patch b/fix-batch_async-obsolete-test.patch index f41f596..d6e4544 100644 --- a/fix-batch_async-obsolete-test.patch +++ b/fix-batch_async-obsolete-test.patch @@ -1,4 +1,4 @@ -From 78b466b0d45de8b7edace542dd3815ca852def40 Mon Sep 17 00:00:00 2001 +From 49780d409630fe18293a077e767aabfd183ff823 Mon Sep 17 00:00:00 2001 From: Mihai Dinca Date: Tue, 3 Dec 2019 11:22:42 +0100 Subject: [PATCH] Fix batch_async obsolete test @@ -28,6 +28,6 @@ index 12dfe543bc..f1d36a81fb 100644 @tornado.testing.gen_test def test_batch_next(self): -- -2.23.0 +2.16.4 diff --git a/fix-bsc-1065792.patch b/fix-bsc-1065792.patch index cca1881..9994949 100644 --- a/fix-bsc-1065792.patch +++ b/fix-bsc-1065792.patch @@ -1,4 +1,4 @@ -From bff330bce4b6e8a848400417c5858ece1dc7b5cf Mon Sep 17 00:00:00 2001 +From 4acbe70851e3ef7a04fc5ad0dc9a2519f6989c66 Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Thu, 14 Dec 2017 16:21:40 +0100 Subject: [PATCH] Fix bsc#1065792 @@ -8,7 +8,7 @@ Subject: [PATCH] Fix bsc#1065792 1 file changed, 1 insertion(+) diff --git a/salt/states/service.py b/salt/states/service.py -index a0e553ead9..1fdcf126ff 100644 +index de7718ea49..987e37cd42 100644 --- a/salt/states/service.py +++ b/salt/states/service.py @@ -80,6 +80,7 @@ def __virtual__(): diff --git a/fix-failing-unit-tests-for-batch-async.patch b/fix-failing-unit-tests-for-batch-async.patch index b621600..852eddb 100644 --- a/fix-failing-unit-tests-for-batch-async.patch +++ b/fix-failing-unit-tests-for-batch-async.patch @@ -1,4 +1,4 @@ -From 927cef6dfa547bf2410740a8c8b41a97492510f0 Mon Sep 17 00:00:00 2001 +From e6f6b38c75027c4c4f6395117b734dce6fb7433e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?= Date: Fri, 4 Oct 2019 15:00:50 +0100 diff --git a/fix-for-log-checking-in-x509-test.patch b/fix-for-log-checking-in-x509-test.patch index 7a96246..567ba7b 100644 --- a/fix-for-log-checking-in-x509-test.patch +++ b/fix-for-log-checking-in-x509-test.patch @@ -1,4 +1,4 @@ -From f114484307a2b8a3cf72bef28febe44e73b498ed Mon Sep 17 00:00:00 2001 +From e0ca0d0d2a62f18e2712223e130af5faa8e0fe05 Mon Sep 17 00:00:00 2001 From: Jochen Breuer Date: Thu, 28 Nov 2019 15:23:36 +0100 Subject: [PATCH] Fix for log checking in x509 test @@ -9,10 +9,10 @@ We are logging in debug and not in trace mode here. 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/unit/modules/test_x509.py b/tests/unit/modules/test_x509.py -index 7030f96484..143abe82bf 100644 +index 624a927bec..976af634c7 100644 --- a/tests/unit/modules/test_x509.py +++ b/tests/unit/modules/test_x509.py -@@ -71,9 +71,9 @@ class X509TestCase(TestCase, LoaderModuleMockMixin): +@@ -68,9 +68,9 @@ class X509TestCase(TestCase, LoaderModuleMockMixin): subj = FakeSubject() x509._parse_subject(subj) diff --git a/fix-for-older-mock-module.patch b/fix-for-older-mock-module.patch deleted file mode 100644 index 6eb0c0a..0000000 --- a/fix-for-older-mock-module.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 56dde3e54715bd488e4110955ca066d9661512bf Mon Sep 17 00:00:00 2001 -From: Jochen Breuer -Date: Fri, 25 Oct 2019 16:18:58 +0200 -Subject: [PATCH] Fix for older mock module - -Seems like args is not working with older mock modules. ---- - tests/unit/modules/test_aptpkg.py | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/tests/unit/modules/test_aptpkg.py b/tests/unit/modules/test_aptpkg.py -index d3fac5902a..bc6b610d86 100644 ---- a/tests/unit/modules/test_aptpkg.py -+++ b/tests/unit/modules/test_aptpkg.py -@@ -412,15 +412,15 @@ class AptPkgTestCase(TestCase, LoaderModuleMockMixin): - } - with patch.multiple(aptpkg, **patch_kwargs): - aptpkg.upgrade() -- args_matching = [True for args in patch_kwargs['__salt__']['cmd.run_all'].call_args.args if "--download-only" in args] -+ args_matching = [True for args in patch_kwargs['__salt__']['cmd.run_all'].call_args[0] if "--download-only" in args] - self.assertFalse(any(args_matching)) - - aptpkg.upgrade(downloadonly=True) -- args_matching = [True for args in patch_kwargs['__salt__']['cmd.run_all'].call_args.args if "--download-only" in args] -+ args_matching = [True for args in patch_kwargs['__salt__']['cmd.run_all'].call_args[0] if "--download-only" in args] - self.assertTrue(any(args_matching)) - - aptpkg.upgrade(download_only=True) -- args_matching = [True for args in patch_kwargs['__salt__']['cmd.run_all'].call_args.args if "--download-only" in args] -+ args_matching = [True for args in patch_kwargs['__salt__']['cmd.run_all'].call_args[0] if "--download-only" in args] - self.assertTrue(any(args_matching)) - - def test_show(self): --- -2.16.4 - - diff --git a/fix-for-suse-expanded-support-detection.patch b/fix-for-suse-expanded-support-detection.patch index 51b2033..8a72ce9 100644 --- a/fix-for-suse-expanded-support-detection.patch +++ b/fix-for-suse-expanded-support-detection.patch @@ -1,4 +1,4 @@ -From 0c16dd5a3c7bef0fe980ac8517f099a8e034c6c9 Mon Sep 17 00:00:00 2001 +From 16d656744d2e7d915757d6f2ae26b57ad8230b0b Mon Sep 17 00:00:00 2001 From: Jochen Breuer Date: Thu, 6 Sep 2018 17:15:18 +0200 Subject: [PATCH] Fix for SUSE Expanded Support detection @@ -14,10 +14,10 @@ This change also adds a check for redhat-release and then marks the 1 file changed, 9 insertions(+) diff --git a/salt/grains/core.py b/salt/grains/core.py -index 04c1ae91b5..82cd3fb657 100644 +index 9b244def9c..2851809472 100644 --- a/salt/grains/core.py +++ b/salt/grains/core.py -@@ -1873,6 +1873,15 @@ def os_data(): +@@ -1892,6 +1892,15 @@ def os_data(): log.trace('Parsing distrib info from /etc/centos-release') # CentOS Linux grains['lsb_distrib_id'] = 'CentOS' diff --git a/fix-for-temp-folder-definition-in-loader-unit-test.patch b/fix-for-temp-folder-definition-in-loader-unit-test.patch new file mode 100644 index 0000000..86fb7cd --- /dev/null +++ b/fix-for-temp-folder-definition-in-loader-unit-test.patch @@ -0,0 +1,42 @@ +From dd01a0fc594f024eee2267bed2f698f5a6c729bf Mon Sep 17 00:00:00 2001 +From: Jochen Breuer +Date: Mon, 16 Mar 2020 15:25:42 +0100 +Subject: [PATCH] Fix for temp folder definition in loader unit test + +--- + tests/unit/test_loader.py | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/tests/unit/test_loader.py b/tests/unit/test_loader.py +index fe11cd0681..7e369f2c3b 100644 +--- a/tests/unit/test_loader.py ++++ b/tests/unit/test_loader.py +@@ -152,12 +152,12 @@ class LazyLoaderUtilsTest(TestCase): + def setUpClass(cls): + cls.opts = salt.config.minion_config(None) + cls.opts['grains'] = salt.loader.grains(cls.opts) +- if not os.path.isdir(TMP): +- os.makedirs(TMP) ++ if not os.path.isdir(RUNTIME_VARS.TMP): ++ os.makedirs(RUNTIME_VARS.TMP) + + def setUp(self): + # Setup the module +- self.module_dir = tempfile.mkdtemp(dir=TMP) ++ self.module_dir = tempfile.mkdtemp(dir=RUNTIME_VARS.TMP) + self.module_file = os.path.join(self.module_dir, + '{}.py'.format(self.module_name)) + with salt.utils.files.fopen(self.module_file, 'w') as fh: +@@ -165,7 +165,7 @@ class LazyLoaderUtilsTest(TestCase): + fh.flush() + os.fsync(fh.fileno()) + +- self.utils_dir = tempfile.mkdtemp(dir=TMP) ++ self.utils_dir = tempfile.mkdtemp(dir=RUNTIME_VARS.TMP) + self.utils_file = os.path.join(self.utils_dir, + '{}.py'.format(self.utils_name)) + with salt.utils.files.fopen(self.utils_file, 'w') as fh: +-- +2.16.4 + + diff --git a/fix-for-unless-requisite-when-pip-is-not-installed.patch b/fix-for-unless-requisite-when-pip-is-not-installed.patch new file mode 100644 index 0000000..922deca --- /dev/null +++ b/fix-for-unless-requisite-when-pip-is-not-installed.patch @@ -0,0 +1,50 @@ +From f8b490c26be8e7f76947cc07f606f95c133805a7 Mon Sep 17 00:00:00 2001 +From: "Daniel A. Wozniak" +Date: Thu, 20 Feb 2020 21:07:07 +0000 +Subject: [PATCH] Fix for unless requisite when pip is not installed + +Only remove pip relasted modules +--- + salt/states/pip_state.py | 17 ++--------------- + 1 file changed, 2 insertions(+), 15 deletions(-) + +diff --git a/salt/states/pip_state.py b/salt/states/pip_state.py +index 0f762752d02bf5ced17928a4c7fd2a3f027b66d5..11e466389fc46574923e2a71d8ca06f2c411f369 100644 +--- a/salt/states/pip_state.py ++++ b/salt/states/pip_state.py +@@ -51,7 +51,7 @@ def purge_pip(): + return + pip_related_entries = [ + (k, v) for (k, v) in sys.modules.items() +- or getattr(v, '__module__', '').startswith('pip.') ++ if getattr(v, '__module__', '').startswith('pip.') + or (isinstance(v, types.ModuleType) and v.__name__.startswith('pip.')) + ] + for name, entry in pip_related_entries: +@@ -96,21 +96,8 @@ try: + HAS_PIP = True + except ImportError: + HAS_PIP = False +- # Remove references to the loaded pip module above so reloading works +- import sys +- pip_related_entries = [ +- (k, v) for (k, v) in sys.modules.items() +- or getattr(v, '__module__', '').startswith('pip.') +- or (isinstance(v, types.ModuleType) and v.__name__.startswith('pip.')) +- ] +- for name, entry in pip_related_entries: +- sys.modules.pop(name) +- del entry ++ purge_pip() + +- del pip +- sys_modules_pip = sys.modules.pop('pip', None) +- if sys_modules_pip is not None: +- del sys_modules_pip + + if HAS_PIP is True: + if not hasattr(purge_pip, '__pip_ver__'): +-- +2.23.0 + + diff --git a/fix-git_pillar-merging-across-multiple-__env__-repos.patch b/fix-git_pillar-merging-across-multiple-__env__-repos.patch index 7ea6e8a..9dca7fb 100644 --- a/fix-git_pillar-merging-across-multiple-__env__-repos.patch +++ b/fix-git_pillar-merging-across-multiple-__env__-repos.patch @@ -1,4 +1,4 @@ -From 31b9186f48ac37e2b814b8db61ec1d5a5868659f Mon Sep 17 00:00:00 2001 +From 900d63bc5e85496e16373025457561b405f2329f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?= Date: Tue, 6 Nov 2018 16:38:54 +0000 @@ -15,10 +15,10 @@ Remove unicode references 1 file changed, 45 insertions(+) diff --git a/tests/integration/pillar/test_git_pillar.py b/tests/integration/pillar/test_git_pillar.py -index 9ade88840b..ab3b1a89cf 100644 +index 2e549f3948..d417a7ebc3 100644 --- a/tests/integration/pillar/test_git_pillar.py +++ b/tests/integration/pillar/test_git_pillar.py -@@ -1388,6 +1388,51 @@ class TestPygit2SSH(GitPillarSSHTestBase): +@@ -1382,6 +1382,51 @@ class TestPygit2SSH(GitPillarSSHTestBase): 'nested_dict': {'master': True}}} ) diff --git a/fix-ipv6-scope-bsc-1108557.patch b/fix-ipv6-scope-bsc-1108557.patch index 28e2119..b29edfb 100644 --- a/fix-ipv6-scope-bsc-1108557.patch +++ b/fix-ipv6-scope-bsc-1108557.patch @@ -1,4 +1,4 @@ -From 682964fe1cb3fc859eb72da524beaeb2a85ff610 Mon Sep 17 00:00:00 2001 +From 2cb7515f83e2c358b84724e4eb581daa78012fdf Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Fri, 28 Sep 2018 15:22:33 +0200 Subject: [PATCH] Fix IPv6 scope (bsc#1108557) @@ -73,10 +73,10 @@ Reverse skipping tests: if no ipaddress 1 file changed, 74 insertions(+) diff --git a/salt/_compat.py b/salt/_compat.py -index ed6f4a38ea..61842b4bf3 100644 +index e999605d2c..965bb90da3 100644 --- a/salt/_compat.py +++ b/salt/_compat.py -@@ -229,7 +229,81 @@ class IPv6InterfaceScoped(ipaddress.IPv6Interface, IPv6AddressScoped): +@@ -230,7 +230,81 @@ class IPv6InterfaceScoped(ipaddress.IPv6Interface, IPv6AddressScoped): self.hostmask = self.network.hostmask diff --git a/fix-issue-2068-test.patch b/fix-issue-2068-test.patch index 2d6b81d..d0a00ee 100644 --- a/fix-issue-2068-test.patch +++ b/fix-issue-2068-test.patch @@ -1,4 +1,4 @@ -From f81e6022b51b10406e52401fc75d7ef1ae93c55d Mon Sep 17 00:00:00 2001 +From bfdd7f946d56d799e89b33f7e3b72426732b0195 Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Wed, 9 Jan 2019 16:08:19 +0100 Subject: [PATCH] Fix issue #2068 test @@ -13,7 +13,7 @@ Minor update: more correct is-dict check. 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/salt/state.py b/salt/state.py -index c3119b6a33..6af1b89037 100644 +index bc5277554e..2fa5f64ca5 100644 --- a/salt/state.py +++ b/salt/state.py @@ -25,6 +25,7 @@ import traceback @@ -24,7 +24,7 @@ index c3119b6a33..6af1b89037 100644 # Import salt libs import salt.loader -@@ -2776,16 +2777,18 @@ class State(object): +@@ -2896,16 +2897,18 @@ class State(object): ''' for chunk in high: state = high[chunk] diff --git a/fix-load-cached-grain-osrelease_info.patch b/fix-load-cached-grain-osrelease_info.patch deleted file mode 100644 index 86df1ed..0000000 --- a/fix-load-cached-grain-osrelease_info.patch +++ /dev/null @@ -1,129 +0,0 @@ -From 14f7acde30ea99abed535ab9491e9881ce609fdf Mon Sep 17 00:00:00 2001 -From: Sergey Yurchik -Date: Fri, 10 Jan 2020 12:19:54 +0300 -Subject: [PATCH] Fix load cached grain "osrelease_info" - -Before fix the module `loader._load_cached_grains` loaded `osrelease_info` grain as list. -But everythere it expects `tuple`. -Now we force `osrelease_info` type and it works as expected. - -Fixes #54908 - -Sanitize grains loaded from roster_grains.json - -Ensure _format_cached_grains is called on state.pkg test ---- - salt/loader.py | 13 ++++++++++++- - salt/modules/state.py | 3 ++- - tests/unit/modules/test_state.py | 4 +++- - tests/unit/test_loader.py | 28 ++++++++++++++++++++++++++++ - 4 files changed, 45 insertions(+), 3 deletions(-) - -diff --git a/salt/loader.py b/salt/loader.py -index 26b44de511d77dd498a1db655a44144f6e9fbf0a..984d80758ba8bd733a211f42d89e2d4e4fb25341 100644 ---- a/salt/loader.py -+++ b/salt/loader.py -@@ -689,6 +689,17 @@ def grain_funcs(opts, proxy=None): - return ret - - -+def _format_cached_grains(cached_grains): -+ """ -+ Returns cached grains with fixed types, like tuples. -+ """ -+ if cached_grains.get('osrelease_info'): -+ osrelease_info = cached_grains['osrelease_info'] -+ if isinstance(osrelease_info, list): -+ cached_grains['osrelease_info'] = tuple(osrelease_info) -+ return cached_grains -+ -+ - def _load_cached_grains(opts, cfn): - ''' - Returns the grains cached in cfn, or None if the cache is too old or is -@@ -721,7 +732,7 @@ def _load_cached_grains(opts, cfn): - log.debug('Cached grains are empty, cache might be corrupted. Refreshing.') - return None - -- return cached_grains -+ return _format_cached_grains(cached_grains) - except (IOError, OSError): - return None - -diff --git a/salt/modules/state.py b/salt/modules/state.py -index a757e401d4f5c8fff33ad4b0f30f2882631fab80..197d69e1ff53e759ab268b9d562e6eb54f828e4c 100644 ---- a/salt/modules/state.py -+++ b/salt/modules/state.py -@@ -42,6 +42,7 @@ import salt.defaults.exitcodes - from salt.exceptions import CommandExecutionError, SaltInvocationError - from salt.runners.state import orchestrate as _orchestrate - from salt.utils.odict import OrderedDict -+from salt.loader import _format_cached_grains - - # Import 3rd-party libs - from salt.ext import six -@@ -2177,7 +2178,7 @@ def pkg(pkg_path, - roster_grains_json = os.path.join(root, 'roster_grains.json') - if os.path.isfile(roster_grains_json): - with salt.utils.files.fopen(roster_grains_json, 'r') as fp_: -- roster_grains = salt.utils.json.load(fp_) -+ roster_grains = _format_cached_grains(salt.utils.json.load(fp_)) - - if os.path.isfile(roster_grains_json): - popts['grains'] = roster_grains -diff --git a/tests/unit/modules/test_state.py b/tests/unit/modules/test_state.py -index 0d15458be0a9b187efc7b2963612ea4bb078918e..8fc90d33bf22bf37a9597ecd1c6ff7ad43a60b6d 100644 ---- a/tests/unit/modules/test_state.py -+++ b/tests/unit/modules/test_state.py -@@ -1164,8 +1164,10 @@ class StateTestCase(TestCase, LoaderModuleMockMixin): - - MockTarFile.path = "" - with patch('salt.utils.files.fopen', mock_open()), \ -- patch.object(salt.utils.json, 'loads', mock_json_loads_true): -+ patch.object(salt.utils.json, 'loads', mock_json_loads_true), \ -+ patch.object(state, '_format_cached_grains', MagicMock()): - self.assertEqual(state.pkg(tar_file, 0, "md5"), True) -+ state._format_cached_grains.assert_called_once() - - MockTarFile.path = "" - if six.PY2: -diff --git a/tests/unit/test_loader.py b/tests/unit/test_loader.py -index 38dcb181090c61935835f14dd780bad2aa02d9e8..4c2c1b44af2d2931505ddcbb4339e087be88b4fc 100644 ---- a/tests/unit/test_loader.py -+++ b/tests/unit/test_loader.py -@@ -1334,3 +1334,31 @@ class LazyLoaderOptimizationOrderTest(TestCase): - basename = os.path.basename(filename) - expected = 'lazyloadertest.py' if six.PY3 else 'lazyloadertest.pyc' - assert basename == expected, basename -+ -+ -+class LoaderLoadCachedGrainsTest(TestCase): -+ ''' -+ Test how the loader works with cached grains -+ ''' -+ -+ @classmethod -+ def setUpClass(cls): -+ cls.opts = salt.config.minion_config(None) -+ if not os.path.isdir(RUNTIME_VARS.TMP): -+ os.makedirs(RUNTIME_VARS.TMP) -+ -+ def setUp(self): -+ self.cache_dir = tempfile.mkdtemp(dir=RUNTIME_VARS.TMP) -+ self.addCleanup(shutil.rmtree, self.cache_dir, ignore_errors=True) -+ -+ self.opts['cachedir'] = self.cache_dir -+ self.opts['grains_cache'] = True -+ self.opts['grains'] = salt.loader.grains(self.opts) -+ -+ def test_osrelease_info_has_correct_type(self): -+ ''' -+ Make sure osrelease_info is tuple after caching -+ ''' -+ grains = salt.loader.grains(self.opts) -+ osrelease_info = grains['osrelease_info'] -+ assert isinstance(osrelease_info, tuple), osrelease_info --- -2.23.0 - - diff --git a/fix-memory-leak-produced-by-batch-async-find_jobs-me.patch b/fix-memory-leak-produced-by-batch-async-find_jobs-me.patch index 1ce9570..b41b086 100644 --- a/fix-memory-leak-produced-by-batch-async-find_jobs-me.patch +++ b/fix-memory-leak-produced-by-batch-async-find_jobs-me.patch @@ -1,4 +1,4 @@ -From d6432f9ebaba32f75a476a6d4a2989d54d149731 Mon Sep 17 00:00:00 2001 +From 77d53d9567b7aec045a8fffd29afcb76a8405caf Mon Sep 17 00:00:00 2001 From: Mihai Dinca Date: Mon, 16 Sep 2019 11:27:30 +0200 Subject: [PATCH] Fix memory leak produced by batch async find_jobs @@ -153,10 +153,10 @@ index 8c8f481e34..8a67331102 100644 self.scheduled = False + yield diff --git a/salt/client/__init__.py b/salt/client/__init__.py -index aff354a021..0bb6d2b111 100644 +index 3bbc7f9de7..a48d79ef8d 100644 --- a/salt/client/__init__.py +++ b/salt/client/__init__.py -@@ -1624,6 +1624,7 @@ class LocalClient(object): +@@ -1622,6 +1622,7 @@ class LocalClient(object): 'key': self.key, 'tgt_type': tgt_type, 'ret': ret, @@ -165,7 +165,7 @@ index aff354a021..0bb6d2b111 100644 # if kwargs are passed, pack them. diff --git a/salt/master.py b/salt/master.py -index ee968410f7..224725a1ba 100644 +index 5e2277ba76..3abf7ae60b 100644 --- a/salt/master.py +++ b/salt/master.py @@ -2044,7 +2044,6 @@ class ClearFuncs(object): diff --git a/fix-regression-in-service-states-with-reload-argumen.patch b/fix-regression-in-service-states-with-reload-argumen.patch new file mode 100644 index 0000000..22c514d --- /dev/null +++ b/fix-regression-in-service-states-with-reload-argumen.patch @@ -0,0 +1,131 @@ +From 1a3e69af7c69a4893642dd1e9a9c4d3eb99cf874 Mon Sep 17 00:00:00 2001 +From: Erik Johnson +Date: Mon, 17 Feb 2020 18:43:06 -0600 +Subject: [PATCH] Fix regression in service states with reload argument + +Add functional test + +Fix failing test + +Add __opts__ and __grains__ just in case + +Skip on OSX for now +--- + salt/states/service.py | 2 +- + tests/unit/states/test_service.py | 79 +++++++++++++++++++++++++++++-- + 2 files changed, 75 insertions(+), 6 deletions(-) + +diff --git a/salt/states/service.py b/salt/states/service.py +index 987e37cd421713313c41db4459b85019c041d549..89afa0dfa625e9ee3d9ecd7566232452d79ca99c 100644 +--- a/salt/states/service.py ++++ b/salt/states/service.py +@@ -488,7 +488,7 @@ def running(name, + time.sleep(init_delay) + + # only force a change state if we have explicitly detected them +- after_toggle_status = __salt__['service.status'](name, sig, **kwargs) ++ after_toggle_status = __salt__['service.status'](name, sig, **status_kwargs) + if 'service.enabled' in __salt__: + after_toggle_enable_status = __salt__['service.enabled'](name) + else: +diff --git a/tests/unit/states/test_service.py b/tests/unit/states/test_service.py +index 30c716025495f537efddf69bf6df8c68bc938e2e..3eead4c3576eefdd8d96eec4cc113edf194ebbc6 100644 +--- a/tests/unit/states/test_service.py ++++ b/tests/unit/states/test_service.py +@@ -7,14 +7,15 @@ + from __future__ import absolute_import, print_function, unicode_literals + + # Import Salt Testing Libs ++from tests.support.helpers import destructiveTest + from tests.support.mixins import LoaderModuleMockMixin +-from tests.support.unit import TestCase +-from tests.support.mock import ( +- MagicMock, +- patch, +-) ++from tests.support.unit import TestCase, skipIf ++from tests.support.mock import MagicMock, patch + + # Import Salt Libs ++import salt.utils.platform ++import salt.config ++import salt.loader + import salt.states.service as service + + +@@ -251,3 +252,71 @@ class ServiceTestCase(TestCase, LoaderModuleMockMixin): + ret[3]) + + self.assertDictEqual(service.mod_watch("salt", "stack"), ret[1]) ++ ++ ++@destructiveTest ++@skipIf(salt.utils.platform.is_darwin(), "service.running is currently failing on OSX") ++class ServiceTestCaseFunctional(TestCase, LoaderModuleMockMixin): ++ ''' ++ Validate the service state ++ ''' ++ def setup_loader_modules(self): ++ self.opts = salt.config.DEFAULT_MINION_OPTS.copy() ++ self.opts['grains'] = salt.loader.grains(self.opts) ++ self.utils = salt.loader.utils(self.opts) ++ self.modules = salt.loader.minion_mods(self.opts, utils=self.utils) ++ ++ self.service_name = 'cron' ++ cmd_name = 'crontab' ++ os_family = self.opts['grains']['os_family'] ++ os_release = self.opts['grains']['osrelease'] ++ if os_family == 'RedHat': ++ self.service_name = 'crond' ++ elif os_family == 'Arch': ++ self.service_name = 'sshd' ++ cmd_name = 'systemctl' ++ elif os_family == 'MacOS': ++ self.service_name = 'org.ntp.ntpd' ++ if int(os_release.split('.')[1]) >= 13: ++ self.service_name = 'com.openssh.sshd' ++ elif os_family == 'Windows': ++ self.service_name = 'Spooler' ++ ++ if os_family != 'Windows' and salt.utils.path.which(cmd_name) is None: ++ self.skipTest('{0} is not installed'.format(cmd_name)) ++ ++ return { ++ service: { ++ '__grains__': self.opts['grains'], ++ '__opts__': self.opts, ++ '__salt__': self.modules, ++ '__utils__': self.utils, ++ }, ++ } ++ ++ def setUp(self): ++ self.pre_srv_enabled = True if self.service_name in self.modules['service.get_enabled']() else False ++ self.post_srv_disable = False ++ if not self.pre_srv_enabled: ++ self.modules['service.enable'](self.service_name) ++ self.post_srv_disable = True ++ ++ def tearDown(self): ++ if self.post_srv_disable: ++ self.modules['service.disable'](self.service_name) ++ ++ def test_running_with_reload(self): ++ with patch.dict(service.__opts__, {'test': False}): ++ service.dead(self.service_name, enable=False) ++ result = service.running(name=self.service_name, enable=True, reload=False) ++ ++ expected = { ++ 'changes': { ++ self.service_name: True ++ }, ++ 'comment': 'Service {0} has been enabled, and is ' ++ 'running'.format(self.service_name), ++ 'name': self.service_name, ++ 'result': True ++ } ++ self.assertDictEqual(result, expected) +-- +2.23.0 + + diff --git a/fix-typo-on-msgpack-version-when-sanitizing-msgpack-.patch b/fix-typo-on-msgpack-version-when-sanitizing-msgpack-.patch new file mode 100644 index 0000000..083a27e --- /dev/null +++ b/fix-typo-on-msgpack-version-when-sanitizing-msgpack-.patch @@ -0,0 +1,28 @@ +From 5a2c7671be0fcdf03050049ac4a1bbf4929abf1e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?= + +Date: Fri, 27 Mar 2020 15:58:40 +0000 +Subject: [PATCH] Fix typo on msgpack version when sanitizing msgpack + kwargs (bsc#1167437) + +--- + salt/utils/msgpack.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/salt/utils/msgpack.py b/salt/utils/msgpack.py +index 1d02aa96ba8b659eb4038f00563c9cfc31a568e5..4b5a256513a524a33d7d42773644567a0970a46b 100644 +--- a/salt/utils/msgpack.py ++++ b/salt/utils/msgpack.py +@@ -61,7 +61,7 @@ def _sanitize_msgpack_kwargs(kwargs): + assert isinstance(kwargs, dict) + if version < (0, 6, 0) and kwargs.pop('strict_map_key', None) is not None: + log.info('removing unsupported `strict_map_key` argument from msgpack call') +- if version < (0, 5, 5) and kwargs.pop('raw', None) is not None: ++ if version < (0, 5, 2) and kwargs.pop('raw', None) is not None: + log.info('removing unsupported `raw` argument from msgpack call') + if version < (0, 4, 0) and kwargs.pop('use_bin_type', None) is not None: + log.info('removing unsupported `use_bin_type` argument from msgpack call') +-- +2.23.0 + + diff --git a/fix-unit-test-for-grains-core.patch b/fix-unit-test-for-grains-core.patch index 91b030f..1d78938 100644 --- a/fix-unit-test-for-grains-core.patch +++ b/fix-unit-test-for-grains-core.patch @@ -1,4 +1,4 @@ -From 91a864f7613927e47b9271bf0f947cf96a3bbfbf Mon Sep 17 00:00:00 2001 +From 6bb7b6c4a530abb7e831449545a35ee5ede49dcb Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Thu, 11 Oct 2018 16:20:40 +0200 Subject: [PATCH] Fix unit test for grains core @@ -8,7 +8,7 @@ Subject: [PATCH] Fix unit test for grains core 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/tests/unit/grains/test_core.py b/tests/unit/grains/test_core.py -index 8c45ee194a..c85225e959 100644 +index b31f5dcddd..c40595eb3f 100644 --- a/tests/unit/grains/test_core.py +++ b/tests/unit/grains/test_core.py @@ -68,11 +68,10 @@ class CoreGrainsTestCase(TestCase, LoaderModuleMockMixin): diff --git a/fix-unit-tests-for-batch-async-after-refactor.patch b/fix-unit-tests-for-batch-async-after-refactor.patch index f3e2604..1a58e4a 100644 --- a/fix-unit-tests-for-batch-async-after-refactor.patch +++ b/fix-unit-tests-for-batch-async-after-refactor.patch @@ -1,4 +1,4 @@ -From 357865060d439e7bf54e5971deb68c0d70cfe91b Mon Sep 17 00:00:00 2001 +From e9f2af1256a52d58a7c8e6dd0122eb6d5cc47dd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?= Date: Wed, 4 Mar 2020 10:13:43 +0000 diff --git a/fix-virt-states-to-not-fail-on-vms-already-stopped.-.patch b/fix-virt-states-to-not-fail-on-vms-already-stopped.-.patch deleted file mode 100644 index 8c4d445..0000000 --- a/fix-virt-states-to-not-fail-on-vms-already-stopped.-.patch +++ /dev/null @@ -1,217 +0,0 @@ -From 46aeb732ed61051d436ac748bd95a50c6379682a Mon Sep 17 00:00:00 2001 -From: Cedric Bosdonnat -Date: Mon, 16 Dec 2019 11:27:49 +0100 -Subject: [PATCH] Fix virt states to not fail on VMs already stopped. - (#195) - -The virt.stopped and virt.powered_off states need to do nothing and -not fail if one of the targeted VMs is already in shutdown state. ---- - salt/states/virt.py | 45 ++++++++++++++++++++-------------- - tests/unit/states/test_virt.py | 36 +++++++++++++++++++++++++++ - 2 files changed, 63 insertions(+), 18 deletions(-) - -diff --git a/salt/states/virt.py b/salt/states/virt.py -index 32a9e31ae5..68e9ac6fb6 100644 ---- a/salt/states/virt.py -+++ b/salt/states/virt.py -@@ -145,35 +145,45 @@ def keys(name, basepath='/etc/pki', **kwargs): - return ret - - --def _virt_call(domain, function, section, comment, -+def _virt_call(domain, function, section, comment, state=None, - connection=None, username=None, password=None, **kwargs): - ''' - Helper to call the virt functions. Wildcards supported. - -- :param domain: -- :param function: -- :param section: -- :param comment: -- :return: -+ :param domain: the domain to apply the function on. Can contain wildcards. -+ :param function: virt function to call -+ :param section: key for the changed domains in the return changes dictionary -+ :param comment: comment to return -+ :param state: the expected final state of the VM. If None the VM state won't be checked. -+ :return: the salt state return - ''' - ret = {'name': domain, 'changes': {}, 'result': True, 'comment': ''} - targeted_domains = fnmatch.filter(__salt__['virt.list_domains'](), domain) - changed_domains = list() - ignored_domains = list() -+ noaction_domains = list() - for targeted_domain in targeted_domains: - try: -- response = __salt__['virt.{0}'.format(function)](targeted_domain, -- connection=connection, -- username=username, -- password=password, -- **kwargs) -- if isinstance(response, dict): -- response = response['name'] -- changed_domains.append({'domain': targeted_domain, function: response}) -+ action_needed = True -+ # If a state has been provided, use it to see if we have something to do -+ if state is not None: -+ domain_state = __salt__['virt.vm_state'](targeted_domain) -+ action_needed = domain_state.get(targeted_domain) != state -+ if action_needed: -+ response = __salt__['virt.{0}'.format(function)](targeted_domain, -+ connection=connection, -+ username=username, -+ password=password, -+ **kwargs) -+ if isinstance(response, dict): -+ response = response['name'] -+ changed_domains.append({'domain': targeted_domain, function: response}) -+ else: -+ noaction_domains.append(targeted_domain) - except libvirt.libvirtError as err: - ignored_domains.append({'domain': targeted_domain, 'issue': six.text_type(err)}) - if not changed_domains: -- ret['result'] = False -+ ret['result'] = not ignored_domains and bool(targeted_domains) - ret['comment'] = 'No changes had happened' - if ignored_domains: - ret['changes'] = {'ignored': ignored_domains} -@@ -206,7 +216,7 @@ def stopped(name, connection=None, username=None, password=None): - virt.stopped - ''' - -- return _virt_call(name, 'shutdown', 'stopped', "Machine has been shut down", -+ return _virt_call(name, 'shutdown', 'stopped', 'Machine has been shut down', state='shutdown', - connection=connection, username=username, password=password) - - -@@ -231,8 +241,7 @@ def powered_off(name, connection=None, username=None, password=None): - domain_name: - virt.stopped - ''' -- -- return _virt_call(name, 'stop', 'unpowered', 'Machine has been powered off', -+ return _virt_call(name, 'stop', 'unpowered', 'Machine has been powered off', state='shutdown', - connection=connection, username=username, password=password) - - -diff --git a/tests/unit/states/test_virt.py b/tests/unit/states/test_virt.py -index 2904fa224d..2af5caca1b 100644 ---- a/tests/unit/states/test_virt.py -+++ b/tests/unit/states/test_virt.py -@@ -378,8 +378,11 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin): - 'result': True} - - shutdown_mock = MagicMock(return_value=True) -+ -+ # Normal case - with patch.dict(virt.__salt__, { # pylint: disable=no-member - 'virt.list_domains': MagicMock(return_value=['myvm', 'vm1']), -+ 'virt.vm_state': MagicMock(return_value={'myvm': 'running'}), - 'virt.shutdown': shutdown_mock - }): - ret.update({'changes': { -@@ -389,8 +392,10 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin): - self.assertDictEqual(virt.stopped('myvm'), ret) - shutdown_mock.assert_called_with('myvm', connection=None, username=None, password=None) - -+ # Normal case with user-provided connection parameters - with patch.dict(virt.__salt__, { # pylint: disable=no-member - 'virt.list_domains': MagicMock(return_value=['myvm', 'vm1']), -+ 'virt.vm_state': MagicMock(return_value={'myvm': 'running'}), - 'virt.shutdown': shutdown_mock, - }): - self.assertDictEqual(virt.stopped('myvm', -@@ -399,8 +404,10 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin): - password='secret'), ret) - shutdown_mock.assert_called_with('myvm', connection='myconnection', username='user', password='secret') - -+ # Case where an error occurred during the shutdown - with patch.dict(virt.__salt__, { # pylint: disable=no-member - 'virt.list_domains': MagicMock(return_value=['myvm', 'vm1']), -+ 'virt.vm_state': MagicMock(return_value={'myvm': 'running'}), - 'virt.shutdown': MagicMock(side_effect=self.mock_libvirt.libvirtError('Some error')) - }): - ret.update({'changes': {'ignored': [{'domain': 'myvm', 'issue': 'Some error'}]}, -@@ -408,10 +415,21 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin): - 'comment': 'No changes had happened'}) - self.assertDictEqual(virt.stopped('myvm'), ret) - -+ # Case there the domain doesn't exist - with patch.dict(virt.__salt__, {'virt.list_domains': MagicMock(return_value=[])}): # pylint: disable=no-member - ret.update({'changes': {}, 'result': False, 'comment': 'No changes had happened'}) - self.assertDictEqual(virt.stopped('myvm'), ret) - -+ # Case where the domain is already stopped -+ with patch.dict(virt.__salt__, { # pylint: disable=no-member -+ 'virt.list_domains': MagicMock(return_value=['myvm', 'vm1']), -+ 'virt.vm_state': MagicMock(return_value={'myvm': 'shutdown'}) -+ }): -+ ret.update({'changes': {}, -+ 'result': True, -+ 'comment': 'No changes had happened'}) -+ self.assertDictEqual(virt.stopped('myvm'), ret) -+ - def test_powered_off(self): - ''' - powered_off state test cases. -@@ -421,8 +439,11 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin): - 'result': True} - - stop_mock = MagicMock(return_value=True) -+ -+ # Normal case - with patch.dict(virt.__salt__, { # pylint: disable=no-member - 'virt.list_domains': MagicMock(return_value=['myvm', 'vm1']), -+ 'virt.vm_state': MagicMock(return_value={'myvm': 'running'}), - 'virt.stop': stop_mock - }): - ret.update({'changes': { -@@ -432,8 +453,10 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin): - self.assertDictEqual(virt.powered_off('myvm'), ret) - stop_mock.assert_called_with('myvm', connection=None, username=None, password=None) - -+ # Normal case with user-provided connection parameters - with patch.dict(virt.__salt__, { # pylint: disable=no-member - 'virt.list_domains': MagicMock(return_value=['myvm', 'vm1']), -+ 'virt.vm_state': MagicMock(return_value={'myvm': 'running'}), - 'virt.stop': stop_mock, - }): - self.assertDictEqual(virt.powered_off('myvm', -@@ -442,8 +465,10 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin): - password='secret'), ret) - stop_mock.assert_called_with('myvm', connection='myconnection', username='user', password='secret') - -+ # Case where an error occurred during the poweroff - with patch.dict(virt.__salt__, { # pylint: disable=no-member - 'virt.list_domains': MagicMock(return_value=['myvm', 'vm1']), -+ 'virt.vm_state': MagicMock(return_value={'myvm': 'running'}), - 'virt.stop': MagicMock(side_effect=self.mock_libvirt.libvirtError('Some error')) - }): - ret.update({'changes': {'ignored': [{'domain': 'myvm', 'issue': 'Some error'}]}, -@@ -451,10 +476,21 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin): - 'comment': 'No changes had happened'}) - self.assertDictEqual(virt.powered_off('myvm'), ret) - -+ # Case there the domain doesn't exist - with patch.dict(virt.__salt__, {'virt.list_domains': MagicMock(return_value=[])}): # pylint: disable=no-member - ret.update({'changes': {}, 'result': False, 'comment': 'No changes had happened'}) - self.assertDictEqual(virt.powered_off('myvm'), ret) - -+ # Case where the domain is already stopped -+ with patch.dict(virt.__salt__, { # pylint: disable=no-member -+ 'virt.list_domains': MagicMock(return_value=['myvm', 'vm1']), -+ 'virt.vm_state': MagicMock(return_value={'myvm': 'shutdown'}) -+ }): -+ ret.update({'changes': {}, -+ 'result': True, -+ 'comment': 'No changes had happened'}) -+ self.assertDictEqual(virt.powered_off('myvm'), ret) -+ - def test_snapshot(self): - ''' - snapshot state test cases. --- -2.23.0 - - diff --git a/fix-virt.full_info-176.patch b/fix-virt.full_info-176.patch deleted file mode 100644 index 2623db3..0000000 --- a/fix-virt.full_info-176.patch +++ /dev/null @@ -1,374 +0,0 @@ -From ab55daa8b642f7b7fde589f971bb078eea098059 Mon Sep 17 00:00:00 2001 -From: Cedric Bosdonnat -Date: Tue, 3 Sep 2019 15:18:04 +0200 -Subject: [PATCH] Fix virt.full_info (#176) - -* virt.get_xml doesn't take a domain object - -In some places in the virt module, the get_xml function was called with -a domain object, leading to runtime errors like the following one: - -'ERROR: The VM "" is not present' - -* qemu-img info needs -U flag on running VMs - -When getting VM disks informations on a running VM, the following error -occured: - - The minion function caused an exception: Traceback (most recent call last): - File "/usr/lib/python3.6/site-packages/salt/minion.py", line 1673, in _thread_return - return_data = minion_instance.executors[fname](opts, data, func, args, kwargs) - File "/usr/lib/python3.6/site-packages/salt/executors/direct_call.py", line 12, in execute - return func(*args, **kwargs) - File "/usr/lib/python3.6/site-packages/salt/modules/virt.py", line 2411, in full_info - 'vm_info': vm_info()} - File "/usr/lib/python3.6/site-packages/salt/modules/virt.py", line 2020, in vm_info - info[domain.name()] = _info(domain) - File "/usr/lib/python3.6/site-packages/salt/modules/virt.py", line 2004, in _info - 'disks': _get_disks(dom), - File "/usr/lib/python3.6/site-packages/salt/modules/virt.py", line 465, in _get_disks - output = _parse_qemu_img_info(qemu_output) - File "/usr/lib/python3.6/site-packages/salt/modules/virt.py", line 287, in _parse_qemu_img_info - raw_infos = salt.utils.json.loads(info) - File "/usr/lib/python3.6/site-packages/salt/utils/json.py", line 92, in loads - return json_module.loads(s, **kwargs) - File "/usr/lib64/python3.6/json/__init__.py", line 354, in loads - return _default_decoder.decode(s) - File "/usr/lib64/python3.6/json/decoder.py", line 339, in decode - obj, end = self.raw_decode(s, idx=_w(s, 0).end()) - File "/usr/lib64/python3.6/json/decoder.py", line 357, in raw_decode - raise JSONDecodeError("Expecting value", s, err.value) from None - json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0) - -This is due to the fact that qemu-img can't get infos on a disk that is -already used like by a running VM. Using the qemu-img -U flag gets it -running in all cases. ---- - salt/modules/virt.py | 10 +- - tests/unit/modules/test_virt.py | 242 +++++++++++++++++++++------------------- - 2 files changed, 132 insertions(+), 120 deletions(-) - -diff --git a/salt/modules/virt.py b/salt/modules/virt.py -index 96c17bd60b..d01b6c3f1e 100644 ---- a/salt/modules/virt.py -+++ b/salt/modules/virt.py -@@ -331,7 +331,7 @@ def _get_uuid(dom): - - salt '*' virt.get_uuid - ''' -- return ElementTree.fromstring(get_xml(dom)).find('uuid').text -+ return ElementTree.fromstring(dom.XMLDesc(0)).find('uuid').text - - - def _get_on_poweroff(dom): -@@ -344,7 +344,7 @@ def _get_on_poweroff(dom): - - salt '*' virt.get_on_restart - ''' -- node = ElementTree.fromstring(get_xml(dom)).find('on_poweroff') -+ node = ElementTree.fromstring(dom.XMLDesc(0)).find('on_poweroff') - return node.text if node is not None else '' - - -@@ -358,7 +358,7 @@ def _get_on_reboot(dom): - - salt '*' virt.get_on_reboot - ''' -- node = ElementTree.fromstring(get_xml(dom)).find('on_reboot') -+ node = ElementTree.fromstring(dom.XMLDesc(0)).find('on_reboot') - return node.text if node is not None else '' - - -@@ -372,7 +372,7 @@ def _get_on_crash(dom): - - salt '*' virt.get_on_crash - ''' -- node = ElementTree.fromstring(get_xml(dom)).find('on_crash') -+ node = ElementTree.fromstring(dom.XMLDesc(0)).find('on_crash') - return node.text if node is not None else '' - - -@@ -458,7 +458,7 @@ def _get_disks(dom): - if driver is not None and driver.get('type') == 'qcow2': - try: - stdout = subprocess.Popen( -- ['qemu-img', 'info', '--output', 'json', '--backing-chain', disk['file']], -+ ['qemu-img', 'info', '-U', '--output', 'json', '--backing-chain', disk['file']], - shell=False, - stdout=subprocess.PIPE).communicate()[0] - qemu_output = salt.utils.stringutils.to_str(stdout) -diff --git a/tests/unit/modules/test_virt.py b/tests/unit/modules/test_virt.py -index e644e62452..4d20e998d8 100644 ---- a/tests/unit/modules/test_virt.py -+++ b/tests/unit/modules/test_virt.py -@@ -81,7 +81,9 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin): - mock_domain.XMLDesc.return_value = xml # pylint: disable=no-member - - # Return state as shutdown -- mock_domain.info.return_value = [4, 0, 0, 0] # pylint: disable=no-member -+ mock_domain.info.return_value = [4, 2048 * 1024, 1024 * 1024, 2, 1234] # pylint: disable=no-member -+ mock_domain.ID.return_value = 1 -+ mock_domain.name.return_value = name - return mock_domain - - def test_disk_profile_merge(self): -@@ -1394,49 +1396,6 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin): - re.match('^([0-9A-F]{2}[:-]){5}([0-9A-F]{2})$', - interface_attrs['mac'], re.I)) - -- def test_get_graphics(self): -- ''' -- Test virt.get_graphics() -- ''' -- xml = ''' -- test-vm -- -- -- -- -- -- -- ''' -- self.set_mock_vm("test-vm", xml) -- -- graphics = virt.get_graphics('test-vm') -- self.assertEqual('vnc', graphics['type']) -- self.assertEqual('5900', graphics['port']) -- self.assertEqual('0.0.0.0', graphics['listen']) -- -- def test_get_nics(self): -- ''' -- Test virt.get_nics() -- ''' -- xml = ''' -- test-vm -- -- -- -- -- --
-- -- -- -- ''' -- self.set_mock_vm("test-vm", xml) -- -- nics = virt.get_nics('test-vm') -- nic = nics[list(nics)[0]] -- self.assertEqual('bridge', nic['type']) -- self.assertEqual('ac:de:48:b6:8b:59', nic['mac']) -- - def test_parse_qemu_img_info(self): - ''' - Make sure that qemu-img info output is properly parsed -@@ -1558,77 +1517,6 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin): - ], - }, virt._parse_qemu_img_info(qemu_infos)) - -- def test_get_disks(self): -- ''' -- Test virt.get_disks() -- ''' -- xml = ''' -- test-vm -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- ''' -- self.set_mock_vm("test-vm", xml) -- -- qemu_infos = '''[{ -- "virtual-size": 25769803776, -- "filename": "/disks/test.qcow2", -- "cluster-size": 65536, -- "format": "qcow2", -- "actual-size": 217088, -- "format-specific": { -- "type": "qcow2", -- "data": { -- "compat": "1.1", -- "lazy-refcounts": false, -- "refcount-bits": 16, -- "corrupt": false -- } -- }, -- "full-backing-filename": "/disks/mybacking.qcow2", -- "backing-filename": "mybacking.qcow2", -- "dirty-flag": false -- }, -- { -- "virtual-size": 25769803776, -- "filename": "/disks/mybacking.qcow2", -- "cluster-size": 65536, -- "format": "qcow2", -- "actual-size": 393744384, -- "format-specific": { -- "type": "qcow2", -- "data": { -- "compat": "1.1", -- "lazy-refcounts": false, -- "refcount-bits": 16, -- "corrupt": false -- } -- }, -- "dirty-flag": false -- }]''' -- -- self.mock_popen.communicate.return_value = [qemu_infos] # pylint: disable=no-member -- disks = virt.get_disks('test-vm') -- disk = disks.get('vda') -- self.assertEqual('/disks/test.qcow2', disk['file']) -- self.assertEqual('disk', disk['type']) -- self.assertEqual('/disks/mybacking.qcow2', disk['backing file']['file']) -- cdrom = disks.get('hda') -- self.assertEqual('/disks/test-cdrom.iso', cdrom['file']) -- self.assertEqual('cdrom', cdrom['type']) -- self.assertFalse('backing file' in cdrom.keys()) -- - @patch('salt.modules.virt.stop', return_value=True) - @patch('salt.modules.virt.undefine') - @patch('os.remove') -@@ -2994,3 +2882,127 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin): - virt.volume_delete('default', 'missing') - virt.volume_delete('missing', 'test_volume') - self.assertEqual(mock_delete.call_count, 2) -+ -+ def test_full_info(self): -+ ''' -+ Test virt.full_info -+ ''' -+ xml = ''' -+ 28deee33-4859-4f23-891c-ee239cffec94 -+ test-vm -+ destroy -+ restart -+ destroy -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+
-+ -+ -+ -+ -+ -+ -+ ''' -+ self.set_mock_vm("test-vm", xml) -+ -+ qemu_infos = '''[{ -+ "virtual-size": 25769803776, -+ "filename": "/disks/test.qcow2", -+ "cluster-size": 65536, -+ "format": "qcow2", -+ "actual-size": 217088, -+ "format-specific": { -+ "type": "qcow2", -+ "data": { -+ "compat": "1.1", -+ "lazy-refcounts": false, -+ "refcount-bits": 16, -+ "corrupt": false -+ } -+ }, -+ "full-backing-filename": "/disks/mybacking.qcow2", -+ "backing-filename": "mybacking.qcow2", -+ "dirty-flag": false -+ }, -+ { -+ "virtual-size": 25769803776, -+ "filename": "/disks/mybacking.qcow2", -+ "cluster-size": 65536, -+ "format": "qcow2", -+ "actual-size": 393744384, -+ "format-specific": { -+ "type": "qcow2", -+ "data": { -+ "compat": "1.1", -+ "lazy-refcounts": false, -+ "refcount-bits": 16, -+ "corrupt": false -+ } -+ }, -+ "dirty-flag": false -+ }]''' -+ -+ self.mock_popen.communicate.return_value = [qemu_infos] # pylint: disable=no-member -+ -+ self.mock_conn.getInfo = MagicMock(return_value=['x86_64', 4096, 8, 2712, 1, 2, 4, 2]) -+ -+ actual = virt.full_info() -+ -+ # Test the hypervisor infos -+ self.assertEqual(2816, actual['freemem']) -+ self.assertEqual(6, actual['freecpu']) -+ self.assertEqual(4, actual['node_info']['cpucores']) -+ self.assertEqual(2712, actual['node_info']['cpumhz']) -+ self.assertEqual('x86_64', actual['node_info']['cpumodel']) -+ self.assertEqual(8, actual['node_info']['cpus']) -+ self.assertEqual(2, actual['node_info']['cputhreads']) -+ self.assertEqual(1, actual['node_info']['numanodes']) -+ self.assertEqual(4096, actual['node_info']['phymemory']) -+ self.assertEqual(2, actual['node_info']['sockets']) -+ -+ # Test the vm_info output: -+ self.assertEqual(2, actual['vm_info']['test-vm']['cpu']) -+ self.assertEqual(1234, actual['vm_info']['test-vm']['cputime']) -+ self.assertEqual(1024 * 1024, actual['vm_info']['test-vm']['mem']) -+ self.assertEqual(2048 * 1024, actual['vm_info']['test-vm']['maxMem']) -+ self.assertEqual('shutdown', actual['vm_info']['test-vm']['state']) -+ self.assertEqual('28deee33-4859-4f23-891c-ee239cffec94', actual['vm_info']['test-vm']['uuid']) -+ self.assertEqual('destroy', actual['vm_info']['test-vm']['on_crash']) -+ self.assertEqual('restart', actual['vm_info']['test-vm']['on_reboot']) -+ self.assertEqual('destroy', actual['vm_info']['test-vm']['on_poweroff']) -+ -+ # Test the nics -+ nic = actual['vm_info']['test-vm']['nics']['ac:de:48:b6:8b:59'] -+ self.assertEqual('bridge', nic['type']) -+ self.assertEqual('ac:de:48:b6:8b:59', nic['mac']) -+ -+ # Test the disks -+ disks = actual['vm_info']['test-vm']['disks'] -+ disk = disks.get('vda') -+ self.assertEqual('/disks/test.qcow2', disk['file']) -+ self.assertEqual('disk', disk['type']) -+ self.assertEqual('/disks/mybacking.qcow2', disk['backing file']['file']) -+ cdrom = disks.get('hda') -+ self.assertEqual('/disks/test-cdrom.iso', cdrom['file']) -+ self.assertEqual('cdrom', cdrom['type']) -+ self.assertFalse('backing file' in cdrom.keys()) -+ -+ # Test the graphics -+ graphics = actual['vm_info']['test-vm']['graphics'] -+ self.assertEqual('vnc', graphics['type']) -+ self.assertEqual('5900', graphics['port']) -+ self.assertEqual('0.0.0.0', graphics['listen']) --- -2.16.4 - - diff --git a/fix-virt.get_hypervisor-188.patch b/fix-virt.get_hypervisor-188.patch deleted file mode 100644 index 0690c11..0000000 --- a/fix-virt.get_hypervisor-188.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 4e315730c1cf91c8c3efb1aad3c6370953c78459 Mon Sep 17 00:00:00 2001 -From: Cedric Bosdonnat -Date: Tue, 10 Dec 2019 10:27:26 +0100 -Subject: [PATCH] Fix virt.get_hypervisor() (#188) - -virt.get_hypervisor resulted in: - - AttributeError: module 'salt.loader.dev-srv.tf.local.int.module.virt' has no attribute '_is_{}_hyper' - -This was due to missplaced parenthese. ---- - salt/modules/virt.py | 2 +- - tests/unit/modules/test_virt.py | 14 ++++++++++++++ - 2 files changed, 15 insertions(+), 1 deletion(-) - -diff --git a/salt/modules/virt.py b/salt/modules/virt.py -index 5e26964449..dedcf8cb6f 100644 ---- a/salt/modules/virt.py -+++ b/salt/modules/virt.py -@@ -3309,7 +3309,7 @@ def get_hypervisor(): - # To add a new 'foo' hypervisor, add the _is_foo_hyper function, - # add 'foo' to the list below and add it to the docstring with a .. versionadded:: - hypervisors = ['kvm', 'xen'] -- result = [hyper for hyper in hypervisors if getattr(sys.modules[__name__], '_is_{}_hyper').format(hyper)()] -+ result = [hyper for hyper in hypervisors if getattr(sys.modules[__name__], '_is_{}_hyper'.format(hyper))()] - return result[0] if result else None - - -diff --git a/tests/unit/modules/test_virt.py b/tests/unit/modules/test_virt.py -index d8efafc063..6f594a8ff3 100644 ---- a/tests/unit/modules/test_virt.py -+++ b/tests/unit/modules/test_virt.py -@@ -3044,3 +3044,17 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin): - # Shouldn't be called with another parameter so far since those are not implemented - # and thus throwing exceptions. - mock_pool.delete.assert_called_once_with(self.mock_libvirt.VIR_STORAGE_POOL_DELETE_NORMAL) -+ -+ @patch('salt.modules.virt._is_kvm_hyper', return_value=True) -+ @patch('salt.modules.virt._is_xen_hyper', return_value=False) -+ def test_get_hypervisor(self, isxen_mock, iskvm_mock): -+ ''' -+ test the virt.get_hypervisor() function -+ ''' -+ self.assertEqual('kvm', virt.get_hypervisor()) -+ -+ iskvm_mock.return_value = False -+ self.assertIsNone(virt.get_hypervisor()) -+ -+ isxen_mock.return_value = True -+ self.assertEqual('xen', virt.get_hypervisor()) --- -2.23.0 - - diff --git a/fix-wrong-test_mod_del_repo_multiline_values-test-af.patch b/fix-wrong-test_mod_del_repo_multiline_values-test-af.patch new file mode 100644 index 0000000..d29f694 --- /dev/null +++ b/fix-wrong-test_mod_del_repo_multiline_values-test-af.patch @@ -0,0 +1,97 @@ +From a8f0a15e4067ec278c8a2d690e3bf815523286ca Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?= + +Date: Thu, 12 Mar 2020 13:26:51 +0000 +Subject: [PATCH] Fix wrong test_mod_del_repo_multiline_values test after + rebase + +--- + tests/integration/modules/test_pkg.py | 56 +++------------------------ + 1 file changed, 6 insertions(+), 50 deletions(-) + +diff --git a/tests/integration/modules/test_pkg.py b/tests/integration/modules/test_pkg.py +index 6f3767bfbd272848277b877d1fe640caf8f349f6..0f4c5c9d459c56bb485408f943c1dee49c46cd21 100644 +--- a/tests/integration/modules/test_pkg.py ++++ b/tests/integration/modules/test_pkg.py +@@ -134,6 +134,10 @@ class PkgModuleTest(ModuleCase, SaltReturnAssertsMixin): + if repo is not None: + self.run_function('pkg.del_repo', [repo]) + ++ @destructiveTest ++ @requires_salt_modules('pkg.mod_repo', 'pkg.del_repo', 'pkg.get_repo') ++ @requires_network() ++ @requires_system_grains + def test_mod_del_repo_multiline_values(self): + ''' + test modifying and deleting a software repository defined with multiline values +@@ -141,8 +145,9 @@ class PkgModuleTest(ModuleCase, SaltReturnAssertsMixin): + os_grain = self.run_function('grains.item', ['os'])['os'] + repo = None + try: +- if os_grain in ['CentOS', 'RedHat']: ++ if os_grain in ['CentOS', 'RedHat', 'SUSE']: + my_baseurl = 'http://my.fake.repo/foo/bar/\n http://my.fake.repo.alt/foo/bar/' ++ expected_get_repo_baseurl_zypp = 'http://my.fake.repo/foo/bar/%0A%20http://my.fake.repo.alt/foo/bar/' + expected_get_repo_baseurl = 'http://my.fake.repo/foo/bar/\nhttp://my.fake.repo.alt/foo/bar/' + major_release = int( + self.run_function( +@@ -189,55 +194,6 @@ class PkgModuleTest(ModuleCase, SaltReturnAssertsMixin): + if repo is not None: + self.run_function('pkg.del_repo', [repo]) + +- def test_mod_del_repo_multiline_values(self): +- ''' +- test modifying and deleting a software repository defined with multiline values +- ''' +- os_grain = self.run_function('grains.item', ['os'])['os'] +- repo = None +- try: +- if os_grain in ['CentOS', 'RedHat', 'SUSE']: +- my_baseurl = 'http://my.fake.repo/foo/bar/\n http://my.fake.repo.alt/foo/bar/' +- expected_get_repo_baseurl_zypp = 'http://my.fake.repo/foo/bar/%0A%20http://my.fake.repo.alt/foo/bar/' +- expected_get_repo_baseurl = 'http://my.fake.repo/foo/bar/\nhttp://my.fake.repo.alt/foo/bar/' +- major_release = int( +- self.run_function( +- 'grains.item', +- ['osmajorrelease'] +- )['osmajorrelease'] +- ) +- repo = 'fakerepo' +- name = 'Fake repo for RHEL/CentOS/SUSE' +- baseurl = my_baseurl +- gpgkey = 'https://my.fake.repo/foo/bar/MY-GPG-KEY.pub' +- failovermethod = 'priority' +- gpgcheck = 1 +- enabled = 1 +- ret = self.run_function( +- 'pkg.mod_repo', +- [repo], +- name=name, +- baseurl=baseurl, +- gpgkey=gpgkey, +- gpgcheck=gpgcheck, +- enabled=enabled, +- failovermethod=failovermethod, +- ) +- # return data from pkg.mod_repo contains the file modified at +- # the top level, so use next(iter(ret)) to get that key +- self.assertNotEqual(ret, {}) +- repo_info = ret[next(iter(ret))] +- self.assertIn(repo, repo_info) +- self.assertEqual(repo_info[repo]['baseurl'], my_baseurl) +- ret = self.run_function('pkg.get_repo', [repo]) +- self.assertEqual(ret['baseurl'], expected_get_repo_baseurl) +- self.run_function('pkg.mod_repo', [repo]) +- ret = self.run_function('pkg.get_repo', [repo]) +- self.assertEqual(ret['baseurl'], expected_get_repo_baseurl) +- finally: +- if repo is not None: +- self.run_function('pkg.del_repo', [repo]) +- + @requires_salt_modules('pkg.owner') + def test_owner(self): + ''' +-- +2.23.0 + + diff --git a/fix-zypper-pkg.list_pkgs-expectation-and-dpkg-mockin.patch b/fix-zypper-pkg.list_pkgs-expectation-and-dpkg-mockin.patch index 7239a2b..ffbbc22 100644 --- a/fix-zypper-pkg.list_pkgs-expectation-and-dpkg-mockin.patch +++ b/fix-zypper-pkg.list_pkgs-expectation-and-dpkg-mockin.patch @@ -1,18 +1,17 @@ -From 10c3c47a4c6ae173e2831d4256b8d8af6b33cf5a Mon Sep 17 00:00:00 2001 +From eb51734ad93b1fa0c6bc8fde861fdabfe3e0d6b0 Mon Sep 17 00:00:00 2001 From: Mihai Dinca Date: Thu, 13 Jun 2019 17:48:55 +0200 Subject: [PATCH] Fix zypper pkg.list_pkgs expectation and dpkg mocking --- tests/unit/modules/test_dpkg_lowpkg.py | 12 ++++++------ - tests/unit/modules/test_zypperpkg.py | 2 +- - 2 files changed, 7 insertions(+), 7 deletions(-) + 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/unit/modules/test_dpkg_lowpkg.py b/tests/unit/modules/test_dpkg_lowpkg.py -index d16ce3cc1a..98557a1d10 100644 +index a0b3346f9d..bc564f080a 100644 --- a/tests/unit/modules/test_dpkg_lowpkg.py +++ b/tests/unit/modules/test_dpkg_lowpkg.py -@@ -127,9 +127,9 @@ class DpkgTestCase(TestCase, LoaderModuleMockMixin): +@@ -125,9 +125,9 @@ class DpkgTestCase(TestCase, LoaderModuleMockMixin): with patch.dict(dpkg.__salt__, {'cmd.run_all': mock}): self.assertEqual(dpkg.file_dict('httpd'), 'Error: error') @@ -25,7 +24,7 @@ index d16ce3cc1a..98557a1d10 100644 def test_info(self): ''' Test info -@@ -154,9 +154,9 @@ class DpkgTestCase(TestCase, LoaderModuleMockMixin): +@@ -152,9 +152,9 @@ class DpkgTestCase(TestCase, LoaderModuleMockMixin): assert pkg_data['maintainer'] == 'Simpsons Developers ' assert pkg_data['license'] == 'BSD v3' @@ -38,19 +37,6 @@ index d16ce3cc1a..98557a1d10 100644 def test_info_attr(self): ''' Test info with 'attr' parameter -diff --git a/tests/unit/modules/test_zypperpkg.py b/tests/unit/modules/test_zypperpkg.py -index 5c5091a570..a7063e47c6 100644 ---- a/tests/unit/modules/test_zypperpkg.py -+++ b/tests/unit/modules/test_zypperpkg.py -@@ -659,7 +659,7 @@ Repository 'DUMMY' not found by its alias, number, or URI. - 'install_date_time_t': 1503572639, - 'epoch': None, - }], -- 'perseus-dummy.i586': [{ -+ 'perseus-dummy': [{ - 'version': '1.1', - 'release': '1.1', - 'arch': 'i586', -- 2.16.4 diff --git a/fix-zypper.list_pkgs-to-be-aligned-with-pkg-state.patch b/fix-zypper.list_pkgs-to-be-aligned-with-pkg-state.patch index bb39f3a..0cda954 100644 --- a/fix-zypper.list_pkgs-to-be-aligned-with-pkg-state.patch +++ b/fix-zypper.list_pkgs-to-be-aligned-with-pkg-state.patch @@ -1,4 +1,4 @@ -From 3b85fa4cadc10881f2408e95700f7a6dae35ce21 Mon Sep 17 00:00:00 2001 +From 0612549b3acfeb15e0b499b6f469d64062d6ae2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?= Date: Mon, 25 Jun 2018 13:06:40 +0100 @@ -14,10 +14,10 @@ Fix '_find_remove_targets' after aligning Zypper with pkg state 1 file changed, 21 deletions(-) diff --git a/salt/states/pkg.py b/salt/states/pkg.py -index 2034262b23..0aca1e0af8 100644 +index c0fa2f6b69..a13d418400 100644 --- a/salt/states/pkg.py +++ b/salt/states/pkg.py -@@ -455,16 +455,6 @@ def _find_remove_targets(name=None, +@@ -450,16 +450,6 @@ def _find_remove_targets(name=None, if __grains__['os'] == 'FreeBSD' and origin: cver = [k for k, v in six.iteritems(cur_pkgs) if v['origin'] == pkgname] @@ -34,7 +34,7 @@ index 2034262b23..0aca1e0af8 100644 else: cver = cur_pkgs.get(pkgname, []) -@@ -871,17 +861,6 @@ def _verify_install(desired, new_pkgs, ignore_epoch=False, new_caps=None): +@@ -866,17 +856,6 @@ def _verify_install(desired, new_pkgs, ignore_epoch=False, new_caps=None): cver = new_pkgs.get(pkgname.split('%')[0]) elif __grains__['os_family'] == 'Debian': cver = new_pkgs.get(pkgname.split('=')[0]) diff --git a/fixes-cve-2018-15750-cve-2018-15751.patch b/fixes-cve-2018-15750-cve-2018-15751.patch index 2213783..771b633 100644 --- a/fixes-cve-2018-15750-cve-2018-15751.patch +++ b/fixes-cve-2018-15750-cve-2018-15751.patch @@ -1,4 +1,4 @@ -From b9185139c688999c10ed90ca96120c6dad597666 Mon Sep 17 00:00:00 2001 +From 9ec54e8c1394ab678c6129d98f07c6eafd446399 Mon Sep 17 00:00:00 2001 From: Erik Johnson Date: Fri, 24 Aug 2018 10:35:55 -0500 Subject: [PATCH] Fixes: CVE-2018-15750, CVE-2018-15751 @@ -16,10 +16,10 @@ Update tornado test to correct authentication message 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/salt/netapi/rest_cherrypy/app.py b/salt/netapi/rest_cherrypy/app.py -index 82615afb29..d230d822cd 100644 +index fa1b540e5f..f8b500482b 100644 --- a/salt/netapi/rest_cherrypy/app.py +++ b/salt/netapi/rest_cherrypy/app.py -@@ -1174,13 +1174,6 @@ class LowDataAdapter(object): +@@ -1176,13 +1176,6 @@ class LowDataAdapter(object): except (TypeError, ValueError): raise cherrypy.HTTPError(401, 'Invalid token') @@ -34,10 +34,10 @@ index 82615afb29..d230d822cd 100644 chunk['client'] = client diff --git a/tests/integration/netapi/rest_tornado/test_app.py b/tests/integration/netapi/rest_tornado/test_app.py -index 2c348a679d..40cf1ce580 100644 +index 10ec29f7fa..4102b5645a 100644 --- a/tests/integration/netapi/rest_tornado/test_app.py +++ b/tests/integration/netapi/rest_tornado/test_app.py -@@ -276,8 +276,8 @@ class TestSaltAPIHandler(_SaltnadoIntegrationTestCase): +@@ -282,8 +282,8 @@ class TestSaltAPIHandler(_SaltnadoIntegrationTestCase): self.assertIn('jid', ret[0]) # the first 2 are regular returns self.assertIn('jid', ret[1]) self.assertIn('Failed to authenticate', ret[2]) # bad auth diff --git a/fixing-streamclosed-issue.patch b/fixing-streamclosed-issue.patch index 1a688ae..510f565 100644 --- a/fixing-streamclosed-issue.patch +++ b/fixing-streamclosed-issue.patch @@ -1,4 +1,4 @@ -From 11d5623a4b9b8ac40f29adb79f203ab8bbfdd8fc Mon Sep 17 00:00:00 2001 +From 9a5f007a5baa4ba1d28b0e6708bac8b134e4891c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mihai=20Dinc=C4=83?= Date: Tue, 26 Nov 2019 18:26:31 +0100 Subject: [PATCH] Fixing StreamClosed issue @@ -28,6 +28,6 @@ index 754c257b36..c4545e3ebc 100644 self.ioloop = None gc.collect() -- -2.23.0 +2.16.4 diff --git a/get-os_arch-also-without-rpm-package-installed.patch b/get-os_arch-also-without-rpm-package-installed.patch index 7a4b5ff..b94bfed 100644 --- a/get-os_arch-also-without-rpm-package-installed.patch +++ b/get-os_arch-also-without-rpm-package-installed.patch @@ -1,4 +1,4 @@ -From 9fc2217cd12d313f87d4db0e408e5b68b23c2330 Mon Sep 17 00:00:00 2001 +From 98f3bd70aaa145b88e8bd4b947b578435e2b1e57 Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Wed, 14 Nov 2018 17:36:23 +0100 Subject: [PATCH] Get os_arch also without RPM package installed @@ -17,80 +17,29 @@ Add UT for OS arch detection when no CPU arch or machine can be determined Remove unsupported testcase --- - salt/utils/pkg/rpm.py | 18 +++++--- - tests/unit/utils/test_pkg.py | 105 ++++++++++++++++++++++++++----------------- - 2 files changed, 77 insertions(+), 46 deletions(-) + tests/unit/utils/test_pkg.py | 48 ++++++++------------------------------------ + 1 file changed, 8 insertions(+), 40 deletions(-) -diff --git a/salt/utils/pkg/rpm.py b/salt/utils/pkg/rpm.py -index 94e231da4b..bb8c3fb589 100644 ---- a/salt/utils/pkg/rpm.py -+++ b/salt/utils/pkg/rpm.py -@@ -9,7 +9,9 @@ import collections - import datetime - import logging - import subprocess -+import platform - import salt.utils.stringutils -+import salt.utils.path - - # Import 3rd-party libs - from salt.ext import six -@@ -42,12 +44,16 @@ def get_osarch(): - ''' - Get the os architecture using rpm --eval - ''' -- ret = subprocess.Popen( -- 'rpm --eval "%{_host_cpu}"', -- shell=True, -- close_fds=True, -- stdout=subprocess.PIPE, -- stderr=subprocess.PIPE).communicate()[0] -+ if salt.utils.path.which('rpm'): -+ ret = subprocess.Popen( -+ 'rpm --eval "%{_host_cpu}"', -+ shell=True, -+ close_fds=True, -+ stdout=subprocess.PIPE, -+ stderr=subprocess.PIPE).communicate()[0] -+ else: -+ ret = ''.join(list(filter(None, platform.uname()[-2:]))[-1:]) -+ - return salt.utils.stringutils.to_str(ret).strip() or 'unknown' - - diff --git a/tests/unit/utils/test_pkg.py b/tests/unit/utils/test_pkg.py -index c293852058..361e0bf92f 100644 +index e8b19bef14..361e0bf92f 100644 --- a/tests/unit/utils/test_pkg.py +++ b/tests/unit/utils/test_pkg.py -@@ -1,47 +1,72 @@ - # -*- coding: utf-8 -*- +@@ -2,51 +2,19 @@ --# Import Python libs --from __future__ import absolute_import --# Import Salt Libs -+from __future__ import absolute_import, unicode_literals, print_function -+ + from __future__ import absolute_import, unicode_literals, print_function + +-from tests.support.unit import TestCase +-from tests.support.mock import MagicMock, patch +from tests.support.unit import TestCase, skipIf +from tests.support.mock import Mock, MagicMock, patch, NO_MOCK, NO_MOCK_REASON import salt.utils.pkg --# Import Salt Testing Libs --from tests.support.unit import TestCase -+from salt.utils.pkg import rpm -+ -+try: -+ import pytest -+except ImportError: -+ pytest = None - + from salt.utils.pkg import rpm +- -class PkgUtilsTestCase(TestCase): -+@skipIf(NO_MOCK, NO_MOCK_REASON) -+@skipIf(pytest is None, 'PyTest is missing') -+class PkgRPMTestCase(TestCase): - ''' +- ''' - TestCase for salt.utils.pkg module -+ Test case for pkg.rpm utils - ''' +- ''' - test_parameters = [ - ("16.0.0.49153-0+f1", "", "16.0.0.49153-0+f1"), - ("> 15.0.0", ">", "15.0.0"), @@ -124,57 +73,17 @@ index c293852058..361e0bf92f 100644 - oper, verstr = salt.utils.pkg.split_comparison(test_parameter[0]) - self.assertEqual(test_parameter[1], oper) - self.assertEqual(test_parameter[2], verstr) -+ -+ @patch('salt.utils.path.which', MagicMock(return_value=True)) -+ def test_get_osarch_by_rpm(self): -+ ''' -+ Get os_arch if RPM package is installed. -+ :return: -+ ''' -+ subprocess_mock = MagicMock() -+ subprocess_mock.Popen = MagicMock() -+ subprocess_mock.Popen().communicate = MagicMock(return_value=['Z80']) -+ with patch('salt.utils.pkg.rpm.subprocess', subprocess_mock): -+ assert rpm.get_osarch() == 'Z80' -+ assert subprocess_mock.Popen.call_count == 2 # One within the mock -+ assert subprocess_mock.Popen.call_args[1]['close_fds'] -+ assert subprocess_mock.Popen.call_args[1]['shell'] -+ assert len(subprocess_mock.Popen.call_args_list) == 2 -+ assert subprocess_mock.Popen.call_args[0][0] == 'rpm --eval "%{_host_cpu}"' -+ -+ @patch('salt.utils.path.which', MagicMock(return_value=False)) -+ @patch('salt.utils.pkg.rpm.subprocess', MagicMock(return_value=False)) -+ @patch('salt.utils.pkg.rpm.platform.uname', MagicMock( -+ return_value=('Sinclair BASIC', 'motophone', '1982 Sinclair Research Ltd', '1.0', 'ZX81', 'Z80'))) -+ def test_get_osarch_by_platform(self): -+ ''' -+ Get os_arch if RPM package is not installed (inird image, for example). -+ :return: -+ ''' -+ assert rpm.get_osarch() == 'Z80' -+ -+ @patch('salt.utils.path.which', MagicMock(return_value=False)) -+ @patch('salt.utils.pkg.rpm.subprocess', MagicMock(return_value=False)) -+ @patch('salt.utils.pkg.rpm.platform.uname', MagicMock( -+ return_value=('Sinclair BASIC', 'motophone', '1982 Sinclair Research Ltd', '1.0', 'ZX81', ''))) -+ def test_get_osarch_by_platform_no_cpu_arch(self): -+ ''' -+ Get os_arch if RPM package is not installed (inird image, for example) but cpu arch cannot be determined. -+ :return: -+ ''' -+ assert rpm.get_osarch() == 'ZX81' -+ -+ @patch('salt.utils.path.which', MagicMock(return_value=False)) -+ @patch('salt.utils.pkg.rpm.subprocess', MagicMock(return_value=False)) -+ @patch('salt.utils.pkg.rpm.platform.uname', MagicMock( -+ return_value=('Sinclair BASIC', 'motophone', '1982 Sinclair Research Ltd', '1.0', '', ''))) -+ def test_get_osarch_by_platform_no_cpu_arch_no_machine(self): -+ ''' -+ Get os_arch if RPM package is not installed (inird image, for example) -+ where both cpu arch and machine cannot be determined. -+ :return: -+ ''' -+ assert rpm.get_osarch() == 'unknown' ++try: ++ import pytest ++except ImportError: ++ pytest = None + + ++@skipIf(NO_MOCK, NO_MOCK_REASON) ++@skipIf(pytest is None, 'PyTest is missing') + class PkgRPMTestCase(TestCase): + ''' + Test case for pkg.rpm utils -- 2.16.4 diff --git a/implement-network.fqdns-module-function-bsc-1134860-.patch b/implement-network.fqdns-module-function-bsc-1134860-.patch index 05f0f60..9feae9e 100644 --- a/implement-network.fqdns-module-function-bsc-1134860-.patch +++ b/implement-network.fqdns-module-function-bsc-1134860-.patch @@ -1,4 +1,4 @@ -From a94e1316565a30e166a5a846404fd2c2bd85e2ca Mon Sep 17 00:00:00 2001 +From a11587a1209cd198f421fafdb43510b6d651f4b2 Mon Sep 17 00:00:00 2001 From: EricS <54029547+ESiebigteroth@users.noreply.github.com> Date: Tue, 3 Sep 2019 11:22:53 +0200 Subject: [PATCH] Implement network.fqdns module function (bsc#1134860) @@ -15,11 +15,11 @@ Co-authored-by: Eric Siebigteroth salt/grains/core.py | 66 +++++------------------------------------- salt/modules/network.py | 60 ++++++++++++++++++++++++++++++++++++++ salt/utils/network.py | 12 ++++++++ - tests/unit/grains/test_core.py | 64 +++++++++++++++++++++++++++++++--------- - 4 files changed, 131 insertions(+), 71 deletions(-) + tests/unit/grains/test_core.py | 63 +++++++++++++++++++++++++++++++--------- + 4 files changed, 130 insertions(+), 71 deletions(-) diff --git a/salt/grains/core.py b/salt/grains/core.py -index 30eba0ce99..e1d08b76cf 100644 +index 0f3ccd9b92..77ae99590f 100644 --- a/salt/grains/core.py +++ b/salt/grains/core.py @@ -26,8 +26,9 @@ from errno import EACCES, EPERM @@ -49,7 +49,7 @@ index 30eba0ce99..e1d08b76cf 100644 # Possible value for h_errno defined in netdb.h HOST_NOT_FOUND = 1 -@@ -1538,17 +1539,6 @@ def _linux_bin_exists(binary): +@@ -1553,17 +1554,6 @@ def _linux_bin_exists(binary): return False @@ -67,7 +67,7 @@ index 30eba0ce99..e1d08b76cf 100644 def _parse_lsb_release(): ret = {} try: -@@ -2255,52 +2245,12 @@ def fqdns(): +@@ -2271,52 +2261,12 @@ def fqdns(): ''' Return all known FQDNs for the system by enumerating all interfaces and then trying to reverse resolve them (excluding 'lo' interface). @@ -126,7 +126,7 @@ index 30eba0ce99..e1d08b76cf 100644 def ip_fqdn(): diff --git a/salt/modules/network.py b/salt/modules/network.py -index 8b4dfcead4..2f1b1c09e0 100644 +index 38e2bc326e..880f4f8d5f 100644 --- a/salt/modules/network.py +++ b/salt/modules/network.py @@ -11,6 +11,10 @@ import logging @@ -202,11 +202,11 @@ index 8b4dfcead4..2f1b1c09e0 100644 + return {"fqdns": sorted(list(fqdns))} \ No newline at end of file diff --git a/salt/utils/network.py b/salt/utils/network.py -index a3fd6e848e..3c8178eeb4 100644 +index 74536cc143..4cc8a05c4a 100644 --- a/salt/utils/network.py +++ b/salt/utils/network.py -@@ -55,6 +55,18 @@ except (ImportError, OSError, AttributeError, TypeError): - # pylint: disable=C0103 +@@ -50,6 +50,18 @@ except (ImportError, OSError, AttributeError, TypeError): + pass +_INTERFACES = {} @@ -225,18 +225,18 @@ index a3fd6e848e..3c8178eeb4 100644 ''' Sanitize host string. diff --git a/tests/unit/grains/test_core.py b/tests/unit/grains/test_core.py -index af9d27dd0e..09e197a2e4 100644 +index ac03b57226..60914204b0 100644 --- a/tests/unit/grains/test_core.py +++ b/tests/unit/grains/test_core.py -@@ -34,6 +34,7 @@ import salt.utils.network - import salt.utils.platform - import salt.utils.path +@@ -35,6 +35,7 @@ import salt.utils.path + import salt.modules.cmdmod + import salt.modules.smbios import salt.grains.core as core +import salt.modules.network # Import 3rd-party libs from salt.ext import six -@@ -976,6 +977,40 @@ class CoreGrainsTestCase(TestCase, LoaderModuleMockMixin): +@@ -1029,6 +1030,40 @@ class CoreGrainsTestCase(TestCase, LoaderModuleMockMixin): with patch.object(salt.utils.dns, 'parse_resolv', MagicMock(return_value=resolv_mock)): assert core.dns() == ret @@ -275,9 +275,9 @@ index af9d27dd0e..09e197a2e4 100644 + + @skipIf(not salt.utils.platform.is_linux(), 'System is not Linux') - @patch.object(salt.utils, 'is_windows', MagicMock(return_value=False)) @patch('salt.utils.network.ip_addrs', MagicMock(return_value=['1.2.3.4', '5.6.7.8'])) -@@ -992,11 +1027,12 @@ class CoreGrainsTestCase(TestCase, LoaderModuleMockMixin): + @patch('salt.utils.network.ip_addrs6', +@@ -1044,11 +1079,12 @@ class CoreGrainsTestCase(TestCase, LoaderModuleMockMixin): ('foo.bar.baz', [], ['fe80::a8b2:93ff:fe00:0']), ('bluesniff.foo.bar', [], ['fe80::a8b2:93ff:dead:beef'])] ret = {'fqdns': ['bluesniff.foo.bar', 'foo.bar.baz', 'rinzler.evil-corp.com']} @@ -294,8 +294,8 @@ index af9d27dd0e..09e197a2e4 100644 + assert set(fqdns['fqdns']) == set(ret['fqdns']) @skipIf(not salt.utils.platform.is_linux(), 'System is not Linux') - @patch.object(salt.utils.platform, 'is_windows', MagicMock(return_value=False)) -@@ -1012,14 +1048,16 @@ class CoreGrainsTestCase(TestCase, LoaderModuleMockMixin): + @patch('salt.utils.network.ip_addrs', MagicMock(return_value=['1.2.3.4'])) +@@ -1094,14 +1130,15 @@ class CoreGrainsTestCase(TestCase, LoaderModuleMockMixin): ('rinzler.evil-corp.com', ["false-hostname", "badaliass"], ['5.6.7.8']), ('foo.bar.baz', [], ['fe80::a8b2:93ff:fe00:0']), ('bluesniff.foo.bar', ["alias.bluesniff.foo.bar"], ['fe80::a8b2:93ff:dead:beef'])] @@ -316,10 +316,9 @@ index af9d27dd0e..09e197a2e4 100644 + + for alias in ["throwmeaway", "false-hostname", "badaliass"]: + assert alias not in fqdns["fqdns"] -+ + def test_core_virtual(self): ''' - test virtual grain with cmd virt-what -- 2.16.4 diff --git a/improve-batch_async-to-release-consumed-memory-bsc-1.patch b/improve-batch_async-to-release-consumed-memory-bsc-1.patch index 0c7889e..c12f42a 100644 --- a/improve-batch_async-to-release-consumed-memory-bsc-1.patch +++ b/improve-batch_async-to-release-consumed-memory-bsc-1.patch @@ -1,4 +1,4 @@ -From c54cdb24f09abf990fc23aa35a763c1ec3bd122a Mon Sep 17 00:00:00 2001 +From 65e33acaf10fdd838c0cdf34ec93df3a2ed1f0d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?= Date: Thu, 26 Sep 2019 10:41:06 +0100 diff --git a/include-aliases-in-the-fqdns-grains.patch b/include-aliases-in-the-fqdns-grains.patch index e17e10a..7823d00 100644 --- a/include-aliases-in-the-fqdns-grains.patch +++ b/include-aliases-in-the-fqdns-grains.patch @@ -1,4 +1,4 @@ -From 83fa749ca09eb8eb5eb29aaa30f8565106ee3c65 Mon Sep 17 00:00:00 2001 +From 512b189808ea0d7b333587689d7e7eb52d16b189 Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Tue, 29 Jan 2019 11:11:38 +0100 Subject: [PATCH] Include aliases in the fqdns grains @@ -18,14 +18,14 @@ Leverage cached interfaces, if any. salt/grains/core.py | 14 ++++++-------- salt/utils/network.py | 12 ++++++++++++ tests/unit/grains/test_core.py | 28 +++++++++++++++++++++++++--- - tests/unit/utils/test_network.py | 19 +++++++++++++++++++ - 4 files changed, 62 insertions(+), 11 deletions(-) + tests/unit/utils/test_network.py | 24 ++++++++++++++++++++++++ + 4 files changed, 67 insertions(+), 11 deletions(-) diff --git a/salt/grains/core.py b/salt/grains/core.py -index f59eeb5780..7d75d48bb5 100644 +index 7b7e328520..309e4c9c4a 100644 --- a/salt/grains/core.py +++ b/salt/grains/core.py -@@ -2255,14 +2255,13 @@ def fqdns(): +@@ -2275,14 +2275,13 @@ def fqdns(): grains = {} fqdns = set() @@ -43,9 +43,9 @@ index f59eeb5780..7d75d48bb5 100644 + name, aliaslist, addresslist = socket.gethostbyaddr(ip) + fqdns.update([socket.getfqdn(name)] + [als for als in aliaslist if salt.utils.network.is_fqdn(als)]) except socket.herror as err: - if err.errno == 0: + if err.errno in (0, HOST_NOT_FOUND, NO_DATA): # No FQDN for this IP address, so we don't need to know this all the time. -@@ -2272,8 +2271,7 @@ def fqdns(): +@@ -2292,8 +2291,7 @@ def fqdns(): except (socket.error, socket.gaierror, socket.timeout) as err: log.error(err_message, ip, err) @@ -56,10 +56,10 @@ index f59eeb5780..7d75d48bb5 100644 def ip_fqdn(): diff --git a/salt/utils/network.py b/salt/utils/network.py -index d6fc6a98c6..a183c9776a 100644 +index 906d1cb3bc..2ae2e213b7 100644 --- a/salt/utils/network.py +++ b/salt/utils/network.py -@@ -2007,3 +2007,15 @@ def parse_host_port(host_port): +@@ -1958,3 +1958,15 @@ def parse_host_port(host_port): raise ValueError('bad hostname: "{}"'.format(host)) return host, port @@ -76,10 +76,10 @@ index d6fc6a98c6..a183c9776a 100644 + compliant = re.compile(r"(?!-)[A-Z\d\-\_]{1,63}(? Date: Thu, 30 Aug 2018 06:07:08 -0600 Subject: [PATCH] Integration of MSI authentication with azurearm cloud @@ -9,7 +9,7 @@ Subject: [PATCH] Integration of MSI authentication with azurearm cloud 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/salt/cloud/clouds/azurearm.py b/salt/cloud/clouds/azurearm.py -index a422feca4f..9948dedc6c 100644 +index 047fdac0a9..2c1fa04ae8 100644 --- a/salt/cloud/clouds/azurearm.py +++ b/salt/cloud/clouds/azurearm.py @@ -58,6 +58,9 @@ The Azure ARM cloud module is used to control access to Microsoft Azure Resource diff --git a/let-salt-ssh-use-platform-python-binary-in-rhel8-191.patch b/let-salt-ssh-use-platform-python-binary-in-rhel8-191.patch index ef336ed..fc103b0 100644 --- a/let-salt-ssh-use-platform-python-binary-in-rhel8-191.patch +++ b/let-salt-ssh-use-platform-python-binary-in-rhel8-191.patch @@ -1,4 +1,4 @@ -From 43cdd24d035ff21c946f6de0a973f5db0e50c8a5 Mon Sep 17 00:00:00 2001 +From 2b5903d2429607a3f46d648520e24c357a56aea6 Mon Sep 17 00:00:00 2001 From: Can Bulut Bayburt <1103552+cbbayburt@users.noreply.github.com> Date: Wed, 4 Dec 2019 15:59:46 +0100 Subject: [PATCH] Let salt-ssh use 'platform-python' binary in RHEL8 @@ -14,7 +14,7 @@ creating the sh shim. 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/client/ssh/__init__.py b/salt/client/ssh/__init__.py -index 0df918d634..d5bc6e5c27 100644 +index 1373274739..d9e91b0f50 100644 --- a/salt/client/ssh/__init__.py +++ b/salt/client/ssh/__init__.py @@ -147,7 +147,7 @@ elif [ "$SUDO" ] && [ -n "$SUDO_USER" ] @@ -27,6 +27,6 @@ index 0df918d634..d5bc6e5c27 100644 do if command -v "$py_cmd" >/dev/null 2>&1 && "$py_cmd" -c "import sys; sys.exit(not (sys.version_info >= (2, 6)));" -- -2.23.0 +2.16.4 diff --git a/list_downloaded-for-apt-module.patch b/list_downloaded-for-apt-module.patch deleted file mode 100644 index e460538..0000000 --- a/list_downloaded-for-apt-module.patch +++ /dev/null @@ -1,162 +0,0 @@ -From a1e0904a640d01d4bab0871db1ab8ea653335443 Mon Sep 17 00:00:00 2001 -From: Jochen Breuer -Date: Thu, 9 Jan 2020 10:11:13 +0100 -Subject: [PATCH] list_downloaded for apt Module - ---- - salt/modules/aptpkg.py | 41 +++++++++++++++++++++++++++++++++++++++ - salt/states/pkg.py | 4 ++-- - tests/unit/modules/test_aptpkg.py | 29 +++++++++++++++++++++++++++ - 3 files changed, 72 insertions(+), 2 deletions(-) - -diff --git a/salt/modules/aptpkg.py b/salt/modules/aptpkg.py -index 1a60255a1d..023049b2af 100644 ---- a/salt/modules/aptpkg.py -+++ b/salt/modules/aptpkg.py -@@ -18,6 +18,9 @@ import os - import re - import logging - import time -+import fnmatch -+import datetime -+ - - # Import third party libs - # pylint: disable=no-name-in-module,import-error,redefined-builtin -@@ -422,6 +425,7 @@ def install(name=None, - pkgs=None, - sources=None, - reinstall=False, -+ downloadonly=False, - ignore_epoch=False, - **kwargs): - ''' -@@ -768,6 +772,9 @@ def install(name=None, - cmd.extend(downgrade) - cmds.append(cmd) - -+ if downloadonly: -+ cmd.append("--download-only") -+ - if to_reinstall: - all_pkgs.extend(to_reinstall) - cmd = copy.deepcopy(cmd_prefix) -@@ -2917,3 +2924,37 @@ def _get_http_proxy_url(): - ) - - return http_proxy_url -+ -+ -+def list_downloaded(root=None, **kwargs): -+ ''' -+ .. versionadded:: 3000? -+ -+ List prefetched packages downloaded by apt in the local disk. -+ -+ root -+ operate on a different root directory. -+ -+ CLI example: -+ -+ .. code-block:: bash -+ -+ salt '*' pkg.list_downloaded -+ ''' -+ CACHE_DIR = '/var/cache/apt' -+ if root: -+ CACHE_DIR = os.path.join(root, os.path.relpath(CACHE_DIR, os.path.sep)) -+ -+ ret = {} -+ for root, dirnames, filenames in salt.utils.path.os_walk(CACHE_DIR): -+ for filename in fnmatch.filter(filenames, '*.deb'): -+ package_path = os.path.join(root, filename) -+ pkg_info = __salt__['lowpkg.bin_pkg_info'](package_path) -+ pkg_timestamp = int(os.path.getctime(package_path)) -+ ret.setdefault(pkg_info['name'], {})[pkg_info['version']] = { -+ 'path': package_path, -+ 'size': os.path.getsize(package_path), -+ 'creation_date_time_t': pkg_timestamp, -+ 'creation_date_time': datetime.datetime.utcfromtimestamp(pkg_timestamp).isoformat(), -+ } -+ return ret -diff --git a/salt/states/pkg.py b/salt/states/pkg.py -index 22a97fe98c..be00498135 100644 ---- a/salt/states/pkg.py -+++ b/salt/states/pkg.py -@@ -1975,7 +1975,7 @@ def downloaded(name, - (if specified). - - Currently supported for the following pkg providers: -- :mod:`yumpkg ` and :mod:`zypper ` -+ :mod:`yumpkg `, :mod:`zypper ` and :mod:`zypper ` - - :param str name: - The name of the package to be downloaded. This parameter is ignored if -@@ -2114,7 +2114,7 @@ def downloaded(name, - - if not ret['changes'] and not ret['comment']: - ret['result'] = True -- ret['comment'] = 'Packages are already downloaded: ' \ -+ ret['comment'] = 'Packages downloaded: ' \ - '{0}'.format(', '.join(targets)) - - return ret -diff --git a/tests/unit/modules/test_aptpkg.py b/tests/unit/modules/test_aptpkg.py -index bc6b610d86..5c7e38eae7 100644 ---- a/tests/unit/modules/test_aptpkg.py -+++ b/tests/unit/modules/test_aptpkg.py -@@ -413,14 +413,17 @@ class AptPkgTestCase(TestCase, LoaderModuleMockMixin): - with patch.multiple(aptpkg, **patch_kwargs): - aptpkg.upgrade() - args_matching = [True for args in patch_kwargs['__salt__']['cmd.run_all'].call_args[0] if "--download-only" in args] -+ # Here we shouldn't see the parameter and args_matching should be empty. - self.assertFalse(any(args_matching)) - - aptpkg.upgrade(downloadonly=True) - args_matching = [True for args in patch_kwargs['__salt__']['cmd.run_all'].call_args[0] if "--download-only" in args] -+ # --download-only should be in the args list and we should have at least on True in the list. - self.assertTrue(any(args_matching)) - - aptpkg.upgrade(download_only=True) - args_matching = [True for args in patch_kwargs['__salt__']['cmd.run_all'].call_args[0] if "--download-only" in args] -+ # --download-only should be in the args list and we should have at least on True in the list. - self.assertTrue(any(args_matching)) - - def test_show(self): -@@ -545,6 +548,32 @@ class AptPkgTestCase(TestCase, LoaderModuleMockMixin): - self.assert_called_once(refresh_mock) - refresh_mock.reset_mock() - -+ @patch('salt.utils.path.os_walk', MagicMock(return_value=[('test', 'test', 'test')])) -+ @patch('os.path.getsize', MagicMock(return_value=123456)) -+ @patch('os.path.getctime', MagicMock(return_value=1234567890.123456)) -+ @patch('fnmatch.filter', MagicMock(return_value=['/var/cache/apt/archive/test_package.rpm'])) -+ def test_list_downloaded(self): -+ ''' -+ Test downloaded packages listing. -+ :return: -+ ''' -+ DOWNLOADED_RET = { -+ 'test-package': { -+ '1.0': { -+ 'path': '/var/cache/apt/archive/test_package.rpm', -+ 'size': 123456, -+ 'creation_date_time_t': 1234567890, -+ 'creation_date_time': '2009-02-13T23:31:30', -+ } -+ } -+ } -+ -+ with patch.dict(aptpkg.__salt__, {'lowpkg.bin_pkg_info': MagicMock(return_value={'name': 'test-package', -+ 'version': '1.0'})}): -+ list_downloaded = aptpkg.list_downloaded() -+ self.assertEqual(len(list_downloaded), 1) -+ self.assertDictEqual(list_downloaded, DOWNLOADED_RET) -+ - - @skipIf(pytest is None, 'PyTest is missing') - class AptUtilsTestCase(TestCase, LoaderModuleMockMixin): --- -2.16.4 - - diff --git a/loader-invalidate-the-import-cachefor-extra-modules.patch b/loader-invalidate-the-import-cachefor-extra-modules.patch index 33f2b2d..de72b97 100644 --- a/loader-invalidate-the-import-cachefor-extra-modules.patch +++ b/loader-invalidate-the-import-cachefor-extra-modules.patch @@ -1,4 +1,4 @@ -From 3d92c4e096dca27b95e485b70594186151e40092 Mon Sep 17 00:00:00 2001 +From 444e00c6601b878444923f573fdb5f000342be9a Mon Sep 17 00:00:00 2001 From: Alberto Planas Date: Thu, 12 Mar 2020 16:39:42 +0100 Subject: [PATCH] loader: invalidate the import cachefor extra modules @@ -14,10 +14,10 @@ extra_module_dirs 1 file changed, 12 insertions(+) diff --git a/salt/loader.py b/salt/loader.py -index 52cb4cfcb5..26b44de511 100644 +index 742b2f8e22..5bd4773645 100644 --- a/salt/loader.py +++ b/salt/loader.py -@@ -1506,9 +1506,11 @@ class LazyLoader(salt.utils.lazy.LazyDict): +@@ -1544,9 +1544,11 @@ class LazyLoader(salt.utils.lazy.LazyDict): self._clean_module_dirs.append(directory) def __clean_sys_path(self): @@ -29,7 +29,7 @@ index 52cb4cfcb5..26b44de511 100644 self._clean_module_dirs = [] # Be sure that sys.path_importer_cache do not contains any -@@ -1516,6 +1518,16 @@ class LazyLoader(salt.utils.lazy.LazyDict): +@@ -1554,6 +1556,16 @@ class LazyLoader(salt.utils.lazy.LazyDict): if USE_IMPORTLIB: importlib.invalidate_caches() diff --git a/loop-fix-variable-names-for-until_no_eval.patch b/loop-fix-variable-names-for-until_no_eval.patch new file mode 100644 index 0000000..4a7e1d6 --- /dev/null +++ b/loop-fix-variable-names-for-until_no_eval.patch @@ -0,0 +1,32 @@ +From 2670f83fd1309fbf9fdc98f15f9a6e6a3ecc038d Mon Sep 17 00:00:00 2001 +From: Alberto Planas +Date: Tue, 24 Mar 2020 17:46:23 +0100 +Subject: [PATCH] loop: fix variable names for until_no_eval + +--- + salt/states/loop.py | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/salt/states/loop.py b/salt/states/loop.py +index 726c8c80165803f3b2d98bf7a197013c53f3ebc8..b631e6c8f62416c04b458a595dc31393987eb904 100644 +--- a/salt/states/loop.py ++++ b/salt/states/loop.py +@@ -185,10 +185,10 @@ def until_no_eval( + ''.format(name, expected)) + if ret['comment']: + return ret +- if not m_args: +- m_args = [] +- if not m_kwargs: +- m_kwargs = {} ++ if not args: ++ args = [] ++ if not kwargs: ++ kwargs = {} + + if init_wait: + time.sleep(init_wait) +-- +2.23.0 + + diff --git a/loosen-azure-sdk-dependencies-in-azurearm-cloud-driv.patch b/loosen-azure-sdk-dependencies-in-azurearm-cloud-driv.patch index 9ef0f32..3b1f943 100644 --- a/loosen-azure-sdk-dependencies-in-azurearm-cloud-driv.patch +++ b/loosen-azure-sdk-dependencies-in-azurearm-cloud-driv.patch @@ -1,4 +1,4 @@ -From 0cd0d8d50c500f3d8948470c2ecd5344f9c494a5 Mon Sep 17 00:00:00 2001 +From c9538180f4dd8875ab57dfa3f51ff59608d2481b Mon Sep 17 00:00:00 2001 From: Joachim Gleissner Date: Tue, 18 Sep 2018 15:07:13 +0200 Subject: [PATCH] loosen azure sdk dependencies in azurearm cloud driver @@ -12,7 +12,7 @@ remove unused import from azurearm driver 1 file changed, 6 insertions(+) diff --git a/salt/cloud/clouds/azurearm.py b/salt/cloud/clouds/azurearm.py -index 9948dedc6c..5f0d4b7e6f 100644 +index 2c1fa04ae8..d5757c6d28 100644 --- a/salt/cloud/clouds/azurearm.py +++ b/salt/cloud/clouds/azurearm.py @@ -104,6 +104,7 @@ import time diff --git a/make-aptpkg.list_repos-compatible-on-enabled-disable.patch b/make-aptpkg.list_repos-compatible-on-enabled-disable.patch index 7831067..99c22b9 100644 --- a/make-aptpkg.list_repos-compatible-on-enabled-disable.patch +++ b/make-aptpkg.list_repos-compatible-on-enabled-disable.patch @@ -1,4 +1,4 @@ -From 9e543a835c870eaea424735fb8e52a82480dce90 Mon Sep 17 00:00:00 2001 +From 93f69a227b7f8c3d4625c0699ab3923d4a0b3127 Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Fri, 16 Nov 2018 10:54:12 +0100 Subject: [PATCH] Make aptpkg.list_repos compatible on enabled/disabled @@ -9,10 +9,10 @@ Subject: [PATCH] Make aptpkg.list_repos compatible on enabled/disabled 1 file changed, 1 insertion(+) diff --git a/salt/modules/aptpkg.py b/salt/modules/aptpkg.py -index ead7c6391e..6b3a921a82 100644 +index b5503f0b10..8f4d95a195 100644 --- a/salt/modules/aptpkg.py +++ b/salt/modules/aptpkg.py -@@ -1595,6 +1595,7 @@ def list_repos(): +@@ -1641,6 +1641,7 @@ def list_repos(): repo['file'] = source.file repo['comps'] = getattr(source, 'comps', []) repo['disabled'] = source.disabled diff --git a/make-profiles-a-package.patch b/make-profiles-a-package.patch index d6ab8fd..58f3855 100644 --- a/make-profiles-a-package.patch +++ b/make-profiles-a-package.patch @@ -1,4 +1,4 @@ -From 117d2af99095cce3c0ab7222d7333334b73aa971 Mon Sep 17 00:00:00 2001 +From 2aeefa07ff52048e2db5c8c4ebb1cde6efe87cee Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Mon, 8 Oct 2018 17:52:07 +0200 Subject: [PATCH] Make profiles a package. diff --git a/make-salt.ext.tornado.gen-to-use-salt.ext.backports_.patch b/make-salt.ext.tornado.gen-to-use-salt.ext.backports_.patch new file mode 100644 index 0000000..7c0f22c --- /dev/null +++ b/make-salt.ext.tornado.gen-to-use-salt.ext.backports_.patch @@ -0,0 +1,35 @@ +From 023d1256106319d042233021c0f200bcdc0cd1f0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?= + +Date: Fri, 13 Mar 2020 13:01:57 +0000 +Subject: [PATCH] Make salt.ext.tornado.gen to use salt.ext.backports_abc + on Python 2 + +--- + salt/ext/tornado/gen.py | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/salt/ext/tornado/gen.py b/salt/ext/tornado/gen.py +index 6cb19730bf1ef3893a4626e9e144eac1c6fa9683..72f422ce28fa43132782a7a0d61b31acd32d138b 100644 +--- a/salt/ext/tornado/gen.py ++++ b/salt/ext/tornado/gen.py +@@ -115,13 +115,13 @@ try: + # py35+ + from collections.abc import Generator as GeneratorType # type: ignore + except ImportError: +- from backports_abc import Generator as GeneratorType # type: ignore ++ from salt.ext.backports_abc import Generator as GeneratorType # type: ignore + + try: + # py35+ + from inspect import isawaitable # type: ignore + except ImportError: +- from backports_abc import isawaitable ++ from salt.ext.backports_abc import isawaitable + except ImportError: + if 'APPENGINE_RUNTIME' not in os.environ: + raise +-- +2.23.0 + + diff --git a/make-setup.py-script-to-not-require-setuptools-9.1.patch b/make-setup.py-script-to-not-require-setuptools-9.1.patch new file mode 100644 index 0000000..ee1761f --- /dev/null +++ b/make-setup.py-script-to-not-require-setuptools-9.1.patch @@ -0,0 +1,34 @@ +From 39b88fd0a3f882e0b33973665bbbacdd60c26a9b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?= + +Date: Wed, 25 Mar 2020 13:09:52 +0000 +Subject: [PATCH] Make setup.py script to not require setuptools > 9.1 + +--- + setup.py | 9 --------- + 1 file changed, 9 deletions(-) + +diff --git a/setup.py b/setup.py +index 06374647df5e82a21fc39b08d41c596f0483ff0c..67a915c64ce5d774e8f89ff3502e85b6bc04b82f 100755 +--- a/setup.py ++++ b/setup.py +@@ -700,15 +700,6 @@ class Install(install): + install.finalize_options(self) + + def run(self): +- from distutils.version import StrictVersion +- if StrictVersion(setuptools.__version__) < StrictVersion('9.1'): +- sys.stderr.write( +- '\n\nInstalling Salt requires setuptools >= 9.1\n' +- 'Available setuptools version is {}\n\n'.format(setuptools.__version__) +- ) +- sys.stderr.flush() +- sys.exit(1) +- + # Let's set the running_salt_install attribute so we can add + # _version.py in the build command + self.distribution.running_salt_install = True +-- +2.23.0 + + diff --git a/move-server_id-deprecation-warning-to-reduce-log-spa.patch b/move-server_id-deprecation-warning-to-reduce-log-spa.patch index 80505ac..4000a59 100644 --- a/move-server_id-deprecation-warning-to-reduce-log-spa.patch +++ b/move-server_id-deprecation-warning-to-reduce-log-spa.patch @@ -1,4 +1,4 @@ -From 10df6dcff22785962dc372064c899b942f3c1ff9 Mon Sep 17 00:00:00 2001 +From c375d1e25e8b5c77b6a8f89855f17df6e49db9f2 Mon Sep 17 00:00:00 2001 From: Mihai Dinca Date: Fri, 14 Jun 2019 15:13:12 +0200 Subject: [PATCH] Move server_id deprecation warning to reduce log @@ -10,10 +10,10 @@ Subject: [PATCH] Move server_id deprecation warning to reduce log 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/salt/grains/core.py b/salt/grains/core.py -index ab37a4dd44..30eba0ce99 100644 +index b58c29dbc3..0f3ccd9b92 100644 --- a/salt/grains/core.py +++ b/salt/grains/core.py -@@ -2867,10 +2867,6 @@ def get_server_id(): +@@ -2890,10 +2890,6 @@ def get_server_id(): if bool(use_crc): id_hash = getattr(zlib, use_crc, zlib.adler32)(__opts__.get('id', '').encode()) & 0xffffffff else: @@ -25,18 +25,18 @@ index ab37a4dd44..30eba0ce99 100644 server_id = {'server_id': id_hash} diff --git a/salt/minion.py b/salt/minion.py -index c5f637eaa6..2c0a18604e 100644 +index 457f485b0a..4730f68b87 100644 --- a/salt/minion.py +++ b/salt/minion.py -@@ -102,6 +102,7 @@ from salt.utils.odict import OrderedDict +@@ -97,6 +97,7 @@ from salt.utils.odict import OrderedDict from salt.utils.process import (default_signals, - SignalHandlingMultiprocessingProcess, + SignalHandlingProcess, ProcessManager) +from salt.utils.versions import warn_until from salt.exceptions import ( CommandExecutionError, CommandNotFoundError, -@@ -993,6 +994,14 @@ class MinionManager(MinionBase): +@@ -1002,6 +1003,14 @@ class MinionManager(MinionBase): if (self.opts['master_type'] in ('failover', 'distributed')) or not isinstance(self.opts['master'], list): masters = [masters] diff --git a/open-suse-2019.2.3-virt-defined-states-219.patch b/opensuse-3000-virt-defined-states-222.patch similarity index 98% rename from open-suse-2019.2.3-virt-defined-states-219.patch rename to opensuse-3000-virt-defined-states-222.patch index 2dc062a..7721acf 100644 --- a/open-suse-2019.2.3-virt-defined-states-219.patch +++ b/opensuse-3000-virt-defined-states-222.patch @@ -1,7 +1,7 @@ -From 66e635ecf9643053c0fdb54718f63782ed998f2f Mon Sep 17 00:00:00 2001 +From e5d42c6313ba051f22f83cbde3da9410fd7fc3b9 Mon Sep 17 00:00:00 2001 From: Cedric Bosdonnat -Date: Fri, 13 Mar 2020 16:38:46 +0100 -Subject: [PATCH] Open suse 2019.2.3 virt defined states (#219) +Date: Fri, 13 Mar 2020 16:38:08 +0100 +Subject: [PATCH] openSUSE-3000 virt-defined-states (#222) * Create virt.pool_defined state out of virt.pool_running @@ -45,13 +45,13 @@ parameters. This was not handled in _gen_xml(). Also add some more tests cases matching this for virt.update. --- salt/modules/virt.py | 16 +- - salt/states/virt.py | 675 +++++++++++++++----- + salt/states/virt.py | 673 +++++++++++++++----- tests/unit/modules/test_virt.py | 26 + tests/unit/states/test_virt.py | 1346 ++++++++++++++++++++++++++++++++------- - 4 files changed, 1666 insertions(+), 397 deletions(-) + 4 files changed, 1665 insertions(+), 396 deletions(-) diff --git a/salt/modules/virt.py b/salt/modules/virt.py -index 339760ead4..b44d1a65bf 100644 +index 3889238ecd..f0820e8825 100644 --- a/salt/modules/virt.py +++ b/salt/modules/virt.py @@ -1783,6 +1783,7 @@ def update(name, @@ -64,7 +64,7 @@ index 339760ead4..b44d1a65bf 100644 Update the definition of an existing domain. @@ -1835,6 +1836,10 @@ def update(name, - .. versionadded:: neon + .. versionadded:: 3000 + :param test: run in dry-run mode if set to True + @@ -109,7 +109,7 @@ index 339760ead4..b44d1a65bf 100644 if device_type in ['cpu', 'mem']: status[device_type] = not bool(ret) diff --git a/salt/states/virt.py b/salt/states/virt.py -index d1c9191a29..8932496b76 100644 +index 55a9ad2616..819776d707 100644 --- a/salt/states/virt.py +++ b/salt/states/virt.py @@ -14,6 +14,7 @@ for the generation and signing of certificates for systems running libvirt: @@ -320,7 +320,7 @@ index d1c9191a29..8932496b76 100644 :param connection: libvirt connection URI, overriding defaults .. versionadded:: 2019.2.0 -@@ -407,93 +590,74 @@ def running(name, +@@ -424,93 +607,74 @@ def running(name, address: 192.168.0.125 ''' @@ -385,7 +385,7 @@ index d1c9191a29..8932496b76 100644 + changed = ret['changes'][name].get('definition', False) try: domain_state = __salt__['virt.vm_state'](name) -- if domain_state.get(name, None) != 'running': + if domain_state.get(name) != 'running': - action_msg = 'started' - if update: - status = __salt__['virt.update'](name, @@ -462,7 +462,6 @@ index d1c9191a29..8932496b76 100644 - # Something bad happened when starting / updating the VM, report it - ret['comment'] = six.text_type(err) - ret['result'] = False -+ if domain_state.get(name) != 'running': + if not __opts__['test']: + __salt__['virt.start'](name, connection=connection, username=username, password=password) + comment = 'Domain {} started'.format(name) @@ -480,7 +479,7 @@ index d1c9191a29..8932496b76 100644 return ret -@@ -653,6 +817,106 @@ def reverted(name, snapshot=None, cleanup=False): # pylint: disable=redefined-o +@@ -670,6 +834,106 @@ def reverted(name, snapshot=None, cleanup=False): # pylint: disable=redefined-o return ret @@ -587,7 +586,7 @@ index d1c9191a29..8932496b76 100644 def network_running(name, bridge, forward, -@@ -698,13 +962,13 @@ def network_running(name, +@@ -715,13 +979,13 @@ def network_running(name, .. code-block:: yaml @@ -604,7 +603,7 @@ index d1c9191a29..8932496b76 100644 - bridge: main - forward: bridge - vport: openvswitch -@@ -714,7 +978,7 @@ def network_running(name, +@@ -731,7 +995,7 @@ def network_running(name, .. code-block:: yaml network_name: @@ -613,7 +612,7 @@ index d1c9191a29..8932496b76 100644 - bridge: natted - forward: nat - ipv4_config: -@@ -727,44 +991,46 @@ def network_running(name, +@@ -744,44 +1008,46 @@ def network_running(name, - autostart: True ''' @@ -693,7 +692,7 @@ index d1c9191a29..8932496b76 100644 ptype=None, target=None, permissions=None, -@@ -775,9 +1041,9 @@ def pool_running(name, +@@ -792,9 +1058,9 @@ def pool_running(name, username=None, password=None): ''' @@ -705,7 +704,7 @@ index d1c9191a29..8932496b76 100644 :param ptype: libvirt pool type :param target: full path to the target device or folder. (Default: ``None``) -@@ -799,12 +1065,7 @@ def pool_running(name, +@@ -816,12 +1082,7 @@ def pool_running(name, .. code-block:: yaml pool_name: @@ -719,7 +718,7 @@ index d1c9191a29..8932496b76 100644 - ptype: netfs - target: /mnt/cifs - permissions: -@@ -867,29 +1128,19 @@ def pool_running(name, +@@ -884,29 +1145,19 @@ def pool_running(name, username=username, password=password) @@ -758,7 +757,7 @@ index d1c9191a29..8932496b76 100644 else: needs_autostart = autostart if not __opts__['test']: -@@ -915,17 +1166,12 @@ def pool_running(name, +@@ -932,17 +1183,12 @@ def pool_running(name, connection=connection, username=username, password=password) @@ -780,7 +779,7 @@ index d1c9191a29..8932496b76 100644 if needs_autostart: if not __opts__['test']: -@@ -941,6 +1187,117 @@ def pool_running(name, +@@ -958,6 +1204,117 @@ def pool_running(name, return ret @@ -899,7 +898,7 @@ index d1c9191a29..8932496b76 100644 purge=False, connection=None, diff --git a/tests/unit/modules/test_virt.py b/tests/unit/modules/test_virt.py -index 3079657a9b..2d3417ce91 100644 +index d762dcc479..8690154662 100644 --- a/tests/unit/modules/test_virt.py +++ b/tests/unit/modules/test_virt.py @@ -1272,6 +1272,32 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin): @@ -936,10 +935,10 @@ index 3079657a9b..2d3417ce91 100644 setvcpus_mock = MagicMock(return_value=0) domain_mock.setVcpusFlags = setvcpus_mock diff --git a/tests/unit/states/test_virt.py b/tests/unit/states/test_virt.py -index 334c33b7d0..38a732b50c 100644 +index c50c04b8ab..6727704494 100644 --- a/tests/unit/states/test_virt.py +++ b/tests/unit/states/test_virt.py -@@ -220,6 +220,243 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin): +@@ -217,6 +217,243 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin): organization='SaltStack', expiration_days=700), ret) @@ -1183,7 +1182,7 @@ index 334c33b7d0..38a732b50c 100644 def test_running(self): ''' running state test cases. -@@ -228,163 +465,369 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin): +@@ -225,163 +462,369 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin): 'changes': {}, 'result': True, 'comment': 'myvm is running'} @@ -1701,7 +1700,7 @@ index 334c33b7d0..38a732b50c 100644 def test_stopped(self): ''' -@@ -602,92 +1045,506 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin): +@@ -599,92 +1042,506 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin): ret.update({'changes': {}, 'result': False, 'comment': 'No changes had happened'}) self.assertDictEqual(virt.rebooted('myvm'), ret) @@ -2284,7 +2283,7 @@ index 334c33b7d0..38a732b50c 100644 def test_pool_running(self): ''' -@@ -697,14 +1554,14 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin): +@@ -694,14 +1551,14 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin): mocks = {mock: MagicMock(return_value=True) for mock in ['define', 'autostart', 'build', 'start', 'stop']} with patch.dict(virt.__opts__, {'test': False}): with patch.dict(virt.__salt__, { # pylint: disable=no-member @@ -2302,7 +2301,7 @@ index 334c33b7d0..38a732b50c 100644 self.assertDictEqual(virt.pool_running('mypool', ptype='logical', target='/dev/base', -@@ -757,7 +1614,7 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin): +@@ -754,7 +1611,7 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin): 'virt.pool_info': MagicMock(return_value={'mypool': {'state': 'running', 'autostart': True}}), 'virt.pool_update': MagicMock(return_value=False), }): @@ -2311,7 +2310,7 @@ index 334c33b7d0..38a732b50c 100644 self.assertDictEqual(virt.pool_running('mypool', ptype='logical', target='/dev/base', -@@ -800,8 +1657,8 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin): +@@ -797,8 +1654,8 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin): 'virt.pool_build': mocks['build'], 'virt.pool_start': mocks['start'] }): @@ -2322,7 +2321,7 @@ index 334c33b7d0..38a732b50c 100644 'result': True}) self.assertDictEqual(virt.pool_running('mypool', ptype='logical', -@@ -845,8 +1702,8 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin): +@@ -842,8 +1699,8 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin): 'virt.pool_start': mocks['start'], 'virt.pool_stop': mocks['stop'] }): @@ -2333,7 +2332,7 @@ index 334c33b7d0..38a732b50c 100644 'result': True}) self.assertDictEqual(virt.pool_running('mypool', ptype='logical', -@@ -885,7 +1742,7 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin): +@@ -882,7 +1739,7 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin): 'virt.pool_info': MagicMock(return_value={'mypool': {'state': 'running', 'autostart': True}}), 'virt.pool_update': MagicMock(return_value=False), }): @@ -2342,7 +2341,7 @@ index 334c33b7d0..38a732b50c 100644 'result': True}) self.assertDictEqual(virt.pool_running('mypool', ptype='logical', -@@ -908,6 +1765,29 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin): +@@ -905,6 +1762,29 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin): target='/dev/base', source={'devices': [{'path': '/dev/sda'}]}), ret) diff --git a/preserve-already-defined-destructive_tests-and-expen.patch b/preserve-already-defined-destructive_tests-and-expen.patch deleted file mode 100644 index ad0940e..0000000 --- a/preserve-already-defined-destructive_tests-and-expen.patch +++ /dev/null @@ -1,34 +0,0 @@ -From a83a3a01e3bb16ec7bf4463dea1b4770c4b2955c Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?= - -Date: Mon, 3 Jun 2019 11:38:36 +0100 -Subject: [PATCH] Preserve already defined DESTRUCTIVE_TESTS and - EXPENSIVE_TESTS env variables - ---- - tests/support/parser/__init__.py | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/tests/support/parser/__init__.py b/tests/support/parser/__init__.py -index a188f8945f..2802b20c62 100644 ---- a/tests/support/parser/__init__.py -+++ b/tests/support/parser/__init__.py -@@ -598,12 +598,12 @@ class SaltTestingParser(optparse.OptionParser): - - self.validate_options() - -- if self.support_destructive_tests_selection: -+ if self.support_destructive_tests_selection and not os.environ.get('DESTRUCTIVE_TESTS', None): - # Set the required environment variable in order to know if - # destructive tests should be executed or not. - os.environ['DESTRUCTIVE_TESTS'] = str(self.options.run_destructive) - -- if self.support_expensive_tests_selection: -+ if self.support_expensive_tests_selection and not os.environ.get('EXPENSIVE_TESTS', None): - # Set the required environment variable in order to know if - # expensive tests should be executed or not. - os.environ['EXPENSIVE_TESTS'] = str(self.options.run_expensive) --- -2.16.4 - - diff --git a/preserving-signature-in-module.run-state-u-50049.patch b/preserving-signature-in-module.run-state-u-50049.patch deleted file mode 100644 index baa316b..0000000 --- a/preserving-signature-in-module.run-state-u-50049.patch +++ /dev/null @@ -1,89 +0,0 @@ -From ae46bb899f3c7d70af62081b2ae0473f07a2a7b9 Mon Sep 17 00:00:00 2001 -From: Bo Maryniuk -Date: Mon, 15 Oct 2018 17:26:16 +0200 -Subject: [PATCH] Preserving signature in "module.run" state (U#50049) - -Add unit test for _call_function on signature aligning named arguments - -Add unit test for _call_function routine for unnamed positional arguments - -Remove redundant docstrings - -Add different test function signature with the same outcome - -Replace standalone function with lambda-proxy for signatures only ---- - salt/states/module.py | 7 +++++-- - tests/unit/states/test_module.py | 27 +++++++++++++++++++++++++++ - 2 files changed, 32 insertions(+), 2 deletions(-) - -diff --git a/salt/states/module.py b/salt/states/module.py -index 9968529ffd..a6096ba35b 100644 ---- a/salt/states/module.py -+++ b/salt/states/module.py -@@ -324,7 +324,7 @@ def _call_function(name, returner=None, **kwargs): - - # func_args is initialized to a list of positional arguments that the function to be run accepts - func_args = argspec.args[:len(argspec.args or []) - len(argspec.defaults or [])] -- arg_type, na_type, kw_type = [], {}, False -+ arg_type, kw_to_arg_type, na_type, kw_type = [], {}, {}, False - for funcset in reversed(kwargs.get('func_args') or []): - if not isinstance(funcset, dict): - # We are just receiving a list of args to the function to be run, so just append -@@ -335,13 +335,16 @@ def _call_function(name, returner=None, **kwargs): - # We are going to pass in a keyword argument. The trick here is to make certain - # that if we find that in the *args* list that we pass it there and not as a kwarg - if kwarg_key in func_args: -- arg_type.append(funcset[kwarg_key]) -+ kw_to_arg_type[kwarg_key] = funcset[kwarg_key] - continue - else: - # Otherwise, we're good and just go ahead and pass the keyword/value pair into - # the kwargs list to be run. - func_kw.update(funcset) - arg_type.reverse() -+ for arg in func_args: -+ if arg in kw_to_arg_type: -+ arg_type.append(kw_to_arg_type[arg]) - _exp_prm = len(argspec.args or []) - len(argspec.defaults or []) - _passed_prm = len(arg_type) - missing = [] -diff --git a/tests/unit/states/test_module.py b/tests/unit/states/test_module.py -index b505e85b90..2aff53eeaf 100644 ---- a/tests/unit/states/test_module.py -+++ b/tests/unit/states/test_module.py -@@ -324,3 +324,30 @@ class ModuleStateTest(TestCase, LoaderModuleMockMixin): - self.assertIn(comment, ret['comment']) - self.assertIn('world', ret['comment']) - self.assertIn('hello', ret['comment']) -+ -+ def test_call_function_named_args(self): -+ ''' -+ Test _call_function routine when params are named. Their position ordering should not matter. -+ -+ :return: -+ ''' -+ with patch.dict(module.__salt__, -+ {'testfunc': lambda a, b, c, *args, **kwargs: (a, b, c, args, kwargs)}, clear=True): -+ assert module._call_function('testfunc', func_args=[{'a': 1}, {'b': 2}, {'c': 3}]) == (1, 2, 3, (), {}) -+ assert module._call_function('testfunc', func_args=[{'c': 3}, {'a': 1}, {'b': 2}]) == (1, 2, 3, (), {}) -+ -+ with patch.dict(module.__salt__, -+ {'testfunc': lambda c, a, b, *args, **kwargs: (a, b, c, args, kwargs)}, clear=True): -+ assert module._call_function('testfunc', func_args=[{'a': 1}, {'b': 2}, {'c': 3}]) == (1, 2, 3, (), {}) -+ assert module._call_function('testfunc', func_args=[{'c': 3}, {'a': 1}, {'b': 2}]) == (1, 2, 3, (), {}) -+ -+ def test_call_function_ordered_args(self): -+ ''' -+ Test _call_function routine when params are not named. Their position should matter. -+ -+ :return: -+ ''' -+ with patch.dict(module.__salt__, -+ {'testfunc': lambda a, b, c, *args, **kwargs: (a, b, c, args, kwargs)}, clear=True): -+ assert module._call_function('testfunc', func_args=[1, 2, 3]) == (1, 2, 3, (), {}) -+ assert module._call_function('testfunc', func_args=[3, 1, 2]) == (3, 1, 2, (), {}) --- -2.16.4 - - diff --git a/prevent-ansiblegate-unit-tests-to-fail-on-ubuntu.patch b/prevent-ansiblegate-unit-tests-to-fail-on-ubuntu.patch index 0594d0e..d620afc 100644 --- a/prevent-ansiblegate-unit-tests-to-fail-on-ubuntu.patch +++ b/prevent-ansiblegate-unit-tests-to-fail-on-ubuntu.patch @@ -1,4 +1,4 @@ -From 32691d82e32dbc70adec03bee214b971c82a73cd Mon Sep 17 00:00:00 2001 +From 73afbe5fe00c47427a032f8d94c113e1375e32ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?= Date: Mon, 8 Jul 2019 14:46:10 +0100 @@ -9,10 +9,10 @@ Subject: [PATCH] Prevent ansiblegate unit tests to fail on Ubuntu 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/unit/modules/test_ansiblegate.py b/tests/unit/modules/test_ansiblegate.py -index 70b47f8bc2..2a24d6f147 100644 +index b7b43efda4..05dff4a4fa 100644 --- a/tests/unit/modules/test_ansiblegate.py +++ b/tests/unit/modules/test_ansiblegate.py -@@ -172,9 +172,11 @@ description: +@@ -169,9 +169,11 @@ description: with patch('salt.utils.timed_subprocess.TimedProc', proc): ret = _ansible_module_caller.call("one.two.three", "arg_1", kwarg1="foobar") if six.PY3: diff --git a/prevent-systemd-run-description-issue-when-running-a.patch b/prevent-systemd-run-description-issue-when-running-a.patch index c0d0bca..89ba6f8 100644 --- a/prevent-systemd-run-description-issue-when-running-a.patch +++ b/prevent-systemd-run-description-issue-when-running-a.patch @@ -1,4 +1,4 @@ -From 03bf4718a82fe73e54c907bfcf9a315eee07feee Mon Sep 17 00:00:00 2001 +From 29316e1e73972d7c30a7b125a27198fefc6b2fd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?= Date: Mon, 30 Sep 2019 12:06:08 +0100 @@ -11,10 +11,10 @@ Subject: [PATCH] Prevent systemd-run description issue when running 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/salt/modules/aptpkg.py b/salt/modules/aptpkg.py -index d49a48310e..a11bb51c16 100644 +index bafad40efe..2835d32263 100644 --- a/salt/modules/aptpkg.py +++ b/salt/modules/aptpkg.py -@@ -165,7 +165,7 @@ def _call_apt(args, scope=True, **kwargs): +@@ -168,7 +168,7 @@ def _call_apt(args, scope=True, **kwargs): ''' cmd = [] if scope and salt.utils.systemd.has_scope(__context__) and __salt__['config.get']('systemd.scope', True): @@ -24,10 +24,10 @@ index d49a48310e..a11bb51c16 100644 params = {'output_loglevel': 'trace', diff --git a/tests/unit/modules/test_aptpkg.py b/tests/unit/modules/test_aptpkg.py -index 06f3a9f6aa..85360da181 100644 +index 88eed062c4..2224aba9a1 100644 --- a/tests/unit/modules/test_aptpkg.py +++ b/tests/unit/modules/test_aptpkg.py -@@ -544,7 +544,7 @@ class AptUtilsTestCase(TestCase, LoaderModuleMockMixin): +@@ -645,7 +645,7 @@ class AptUtilsTestCase(TestCase, LoaderModuleMockMixin): with patch.dict(aptpkg.__salt__, {'cmd.run_all': MagicMock(), 'config.get': MagicMock(return_value=True)}): aptpkg._call_apt(['apt-get', 'purge', 'vim']) # pylint: disable=W0106 aptpkg.__salt__['cmd.run_all'].assert_called_once_with( diff --git a/prevent-test_mod_del_repo_multiline_values-to-fail.patch b/prevent-test_mod_del_repo_multiline_values-to-fail.patch index 1c8eeb1..af6aae0 100644 --- a/prevent-test_mod_del_repo_multiline_values-to-fail.patch +++ b/prevent-test_mod_del_repo_multiline_values-to-fail.patch @@ -1,4 +1,4 @@ -From 13eaa8b2bb57eb1774b43e2437c5e1fd0de9cb93 Mon Sep 17 00:00:00 2001 +From c820b9e652474b4866fe099a709b52fe3b715ce9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?= Date: Wed, 27 Nov 2019 15:41:57 +0000 @@ -9,18 +9,10 @@ Subject: [PATCH] Prevent test_mod_del_repo_multiline_values to fail 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/tests/integration/modules/test_pkg.py b/tests/integration/modules/test_pkg.py -index 7204428eca..9a2cbc7bfc 100644 +index 61748f9477..6f3767bfbd 100644 --- a/tests/integration/modules/test_pkg.py +++ b/tests/integration/modules/test_pkg.py -@@ -145,6 +145,7 @@ class PkgModuleTest(ModuleCase, SaltReturnAssertsMixin): - try: - if os_grain in ['CentOS', 'RedHat', 'SUSE']: - my_baseurl = 'http://my.fake.repo/foo/bar/\n http://my.fake.repo.alt/foo/bar/' -+ expected_get_repo_baseurl_zypp = 'http://my.fake.repo/foo/bar/%0A%20http://my.fake.repo.alt/foo/bar/' - expected_get_repo_baseurl = 'http://my.fake.repo/foo/bar/\nhttp://my.fake.repo.alt/foo/bar/' - major_release = int( - self.run_function( -@@ -169,17 +170,24 @@ class PkgModuleTest(ModuleCase, SaltReturnAssertsMixin): +@@ -167,17 +167,24 @@ class PkgModuleTest(ModuleCase, SaltReturnAssertsMixin): enabled=enabled, failovermethod=failovermethod, ) @@ -51,7 +43,15 @@ index 7204428eca..9a2cbc7bfc 100644 finally: if repo is not None: self.run_function('pkg.del_repo', [repo]) +@@ -191,6 +198,7 @@ class PkgModuleTest(ModuleCase, SaltReturnAssertsMixin): + try: + if os_grain in ['CentOS', 'RedHat', 'SUSE']: + my_baseurl = 'http://my.fake.repo/foo/bar/\n http://my.fake.repo.alt/foo/bar/' ++ expected_get_repo_baseurl_zypp = 'http://my.fake.repo/foo/bar/%0A%20http://my.fake.repo.alt/foo/bar/' + expected_get_repo_baseurl = 'http://my.fake.repo/foo/bar/\nhttp://my.fake.repo.alt/foo/bar/' + major_release = int( + self.run_function( -- -2.23.0 +2.16.4 diff --git a/provide-the-missing-features-required-for-yomi-yet-o.patch b/provide-the-missing-features-required-for-yomi-yet-o.patch index f342809..5111adf 100644 --- a/provide-the-missing-features-required-for-yomi-yet-o.patch +++ b/provide-the-missing-features-required-for-yomi-yet-o.patch @@ -1,4 +1,4 @@ -From d16606a95d316848e15006ef45c11dadfaa0e410 Mon Sep 17 00:00:00 2001 +From d8e0602b36fcfc8b6a446ef56726eae08726e5ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?= Date: Thu, 20 Jun 2019 12:52:45 +0100 @@ -8,87 +8,55 @@ Subject: [PATCH] Provide the missing features required for Yomi (Yet one --- doc/ref/modules/all/index.rst | 1 + doc/ref/modules/all/salt.modules.kubeadm.rst | 5 + - salt/grains/core.py | 30 +- - salt/loader.py | 49 +- + salt/grains/core.py | 4 + + salt/loader.py | 44 +- salt/modules/aixpkg.py | 2 +- salt/modules/apkpkg.py | 12 +- salt/modules/aptpkg.py | 14 +- - salt/modules/btrfs.py | 496 +++++++++- - salt/modules/chroot.py | 165 ++++ - salt/modules/cmdmod.py | 44 +- - salt/modules/disk.py | 26 +- salt/modules/dpkg_lowpkg.py | 6 +- salt/modules/ebuildpkg.py | 8 +- salt/modules/freebsdpkg.py | 6 +- - salt/modules/freezer.py | 294 ++++++ - salt/modules/groupadd.py | 177 +++- salt/modules/kubeadm.py | 1265 ++++++++++++++++++++++++++ - salt/modules/linux_lvm.py | 36 +- salt/modules/mac_brew_pkg.py | 8 +- salt/modules/mac_portspkg.py | 6 +- - salt/modules/mdadm_raid.py | 14 +- - salt/modules/mount.py | 43 +- salt/modules/openbsdpkg.py | 2 +- salt/modules/pacmanpkg.py | 10 +- - salt/modules/parted_partition.py | 91 +- salt/modules/pkgin.py | 8 +- salt/modules/pkgng.py | 4 +- salt/modules/rpm_lowpkg.py | 101 +- - salt/modules/shadow.py | 300 ++++-- salt/modules/solarisipspkg.py | 4 +- salt/modules/solarispkg.py | 2 +- - salt/modules/systemd_service.py | 264 ++++-- - salt/modules/useradd.py | 390 ++++++-- + salt/modules/systemd_service.py | 55 ++ salt/modules/xbpspkg.py | 12 +- salt/modules/yumpkg.py | 34 +- - salt/modules/zypperpkg.py | 503 +++++++--- - salt/states/blockdev.py | 3 +- + salt/modules/zypperpkg.py | 501 +++++++--- salt/states/btrfs.py | 385 ++++++++ - salt/states/cmd.py | 18 +- salt/states/file.py | 6 +- salt/states/loop.py | 4 + - salt/states/lvm.py | 16 +- - salt/states/mdadm_raid.py | 2 +- - salt/states/mount.py | 305 +++++++ - salt/states/pkg.py | 28 +- + salt/states/pkg.py | 26 +- salt/states/pkgrepo.py | 14 +- salt/utils/oset.py | 7 +- - salt/utils/path.py | 7 +- - tests/conftest.py | 10 +- - tests/unit/grains/test_core.py | 39 + - tests/unit/modules/test_btrfs.py | 370 +++++++- - tests/unit/modules/test_chroot.py | 184 ++++ - tests/unit/modules/test_freezer.py | 274 ++++++ - tests/unit/modules/test_groupadd.py | 16 +- tests/unit/modules/test_kubeadm.py | 1144 +++++++++++++++++++++++ - tests/unit/modules/test_mount.py | 118 ++- - tests/unit/modules/test_parted_partition.py | 17 + - tests/unit/modules/test_rpm_lowpkg.py | 92 +- - tests/unit/modules/test_systemd_service.py | 57 +- - tests/unit/modules/test_useradd.py | 5 +- + tests/unit/modules/test_rpm_lowpkg.py | 87 +- + tests/unit/modules/test_systemd_service.py | 53 ++ tests/unit/modules/test_zypperpkg.py | 100 +- tests/unit/states/test_btrfs.py | 782 ++++++++++++++++ - tests/unit/states/test_mount.py | 605 ++++++++++++ tests/unit/states/test_pkg.py | 7 +- tests/unit/test_loader.py | 96 +- - 65 files changed, 8503 insertions(+), 640 deletions(-) + 37 files changed, 4550 insertions(+), 275 deletions(-) create mode 100644 doc/ref/modules/all/salt.modules.kubeadm.rst - create mode 100644 salt/modules/chroot.py - create mode 100644 salt/modules/freezer.py create mode 100644 salt/modules/kubeadm.py create mode 100644 salt/states/btrfs.py - create mode 100644 tests/unit/modules/test_chroot.py - create mode 100644 tests/unit/modules/test_freezer.py create mode 100644 tests/unit/modules/test_kubeadm.py create mode 100644 tests/unit/states/test_btrfs.py diff --git a/doc/ref/modules/all/index.rst b/doc/ref/modules/all/index.rst -index f1a85d2c71..8d165a033b 100644 +index 359af7e1e0..8e1bf2ecf1 100644 --- a/doc/ref/modules/all/index.rst +++ b/doc/ref/modules/all/index.rst -@@ -212,6 +212,7 @@ execution modules - keystone +@@ -214,6 +214,7 @@ execution modules keystoneng + keystore kmod + kubeadm kubernetesmod @@ -106,30 +74,10 @@ index 0000000000..137c779da2 +.. automodule:: salt.modules.kubeadm + :members: diff --git a/salt/grains/core.py b/salt/grains/core.py -index 38b82b7f7c..ab37a4dd44 100644 +index f1e3ebe9d2..b58c29dbc3 100644 --- a/salt/grains/core.py +++ b/salt/grains/core.py -@@ -109,6 +109,10 @@ if not hasattr(os, 'uname'): - - _INTERFACES = {} - -+# Possible value for h_errno defined in netdb.h -+HOST_NOT_FOUND = 1 -+NO_DATA = 4 -+ - - def _windows_cpudata(): - ''' -@@ -2263,7 +2267,7 @@ def fqdns(): - name, aliaslist, addresslist = socket.gethostbyaddr(ip) - return [socket.getfqdn(name)] + [als for als in aliaslist if salt.utils.network.is_fqdn(als)] - except socket.herror as err: -- if err.errno == 0: -+ if err.errno in (0, HOST_NOT_FOUND, NO_DATA): - # No FQDN for this IP address, so we don't need to know this all the time. - log.debug("Unable to resolve address %s: %s", ip, err) - else: -@@ -2584,6 +2588,10 @@ def _hw_data(osdata): +@@ -2611,6 +2611,10 @@ def _hw_data(osdata): grains[key] = salt.utils.stringutils.to_unicode(ifile.read().strip(), errors='replace') if key == 'uuid': grains['uuid'] = grains['uuid'].lower() @@ -140,38 +88,11 @@ index 38b82b7f7c..ab37a4dd44 100644 except (IOError, OSError) as err: # PermissionError is new to Python 3, but corresponds to the EACESS and # EPERM error numbers. Use those instead here for PY2 compatibility. -@@ -2815,26 +2823,6 @@ def _hw_data(osdata): - else: - log.error('The \'prtconf\' binary was not found in $PATH.') - -- elif osdata['kernel'] == 'AIX': -- cmd = salt.utils.path.which('prtconf') -- if data: -- data = __salt__['cmd.run']('{0}'.format(cmd)) + os.linesep -- for dest, regstring in (('serialnumber', r'(?im)^\s*Machine\s+Serial\s+Number:\s+(\S+)'), -- ('systemfirmware', r'(?im)^\s*Firmware\s+Version:\s+(.*)')): -- for regex in [re.compile(r) for r in [regstring]]: -- res = regex.search(data) -- if res and len(res.groups()) >= 1: -- grains[dest] = res.group(1).strip().replace("'", '') -- -- product_regexes = [re.compile(r'(?im)^\s*System\s+Model:\s+(\S+)')] -- for regex in product_regexes: -- res = regex.search(data) -- if res and len(res.groups()) >= 1: -- grains['manufacturer'], grains['productname'] = res.group(1).strip().replace("'", "").split(",") -- break -- else: -- log.error('The \'prtconf\' binary was not found in $PATH.') -- - return grains - - diff --git a/salt/loader.py b/salt/loader.py -index d494c452ed..52cb4cfcb5 100644 +index 860162b791..c68562988d 100644 --- a/salt/loader.py +++ b/salt/loader.py -@@ -253,6 +253,7 @@ def minion_mods( +@@ -254,6 +254,7 @@ def minion_mods( whitelist=whitelist, loaded_base_name=loaded_base_name, static_modules=static_modules, @@ -179,7 +100,7 @@ index d494c452ed..52cb4cfcb5 100644 ) ret.pack['__salt__'] = ret -@@ -346,6 +347,7 @@ def engines(opts, functions, runners, utils, proxy=None): +@@ -347,6 +348,7 @@ def engines(opts, functions, runners, utils, proxy=None): opts, tag='engines', pack=pack, @@ -187,7 +108,7 @@ index d494c452ed..52cb4cfcb5 100644 ) -@@ -358,6 +360,7 @@ def proxy(opts, functions=None, returners=None, whitelist=None, utils=None): +@@ -359,6 +361,7 @@ def proxy(opts, functions=None, returners=None, whitelist=None, utils=None): opts, tag='proxy', pack={'__salt__': functions, '__ret__': returners, '__utils__': utils}, @@ -195,7 +116,7 @@ index d494c452ed..52cb4cfcb5 100644 ) ret.pack['__proxy__'] = ret -@@ -395,12 +398,14 @@ def pillars(opts, functions, context=None): +@@ -396,12 +399,14 @@ def pillars(opts, functions, context=None): ''' Returns the pillars modules ''' @@ -211,7 +132,7 @@ index d494c452ed..52cb4cfcb5 100644 ret.pack['__ext_pillar__'] = ret return FilterDictWrapper(ret, '.ext_pillar') -@@ -500,11 +505,13 @@ def fileserver(opts, backends): +@@ -501,11 +506,13 @@ def fileserver(opts, backends): ''' Returns the file server modules ''' @@ -226,7 +147,7 @@ index d494c452ed..52cb4cfcb5 100644 def roster(opts, runner=None, utils=None, whitelist=None): -@@ -520,6 +527,7 @@ def roster(opts, runner=None, utils=None, whitelist=None): +@@ -521,6 +528,7 @@ def roster(opts, runner=None, utils=None, whitelist=None): '__runner__': runner, '__utils__': utils, }, @@ -234,7 +155,7 @@ index d494c452ed..52cb4cfcb5 100644 ) -@@ -558,6 +566,7 @@ def states(opts, functions, utils, serializers, whitelist=None, proxy=None): +@@ -562,6 +570,7 @@ def states(opts, functions, utils, serializers, whitelist=None, proxy=None, cont tag='states', pack={'__salt__': functions, '__proxy__': proxy or {}}, whitelist=whitelist, @@ -242,28 +163,15 @@ index d494c452ed..52cb4cfcb5 100644 ) ret.pack['__states__'] = ret ret.pack['__utils__'] = utils -@@ -664,7 +673,8 @@ def grain_funcs(opts, proxy=None): - __opts__ = salt.config.minion_config('/etc/salt/minion') - grainfuncs = salt.loader.grain_funcs(__opts__) - ''' -- return LazyLoader( -+ _utils = utils(opts, proxy=proxy) -+ ret = LazyLoader( - _module_dirs( - opts, - 'grains', -@@ -673,7 +683,10 @@ def grain_funcs(opts, proxy=None): +@@ -683,6 +692,7 @@ def grain_funcs(opts, proxy=None): ), opts, tag='grains', + extra_module_dirs=_utils.module_dirs, ) -+ ret.pack['__utils__'] = _utils -+ return ret - - - def _load_cached_grains(opts, cfn): -@@ -907,6 +920,7 @@ def runner(opts, utils=None, context=None, whitelist=None): + ret.pack['__utils__'] = utils(opts, proxy=proxy) + return ret +@@ -947,6 +957,7 @@ def runner(opts, utils=None, context=None, whitelist=None): tag='runners', pack={'__utils__': utils, '__context__': context}, whitelist=whitelist, @@ -271,15 +179,15 @@ index d494c452ed..52cb4cfcb5 100644 ) # TODO: change from __salt__ to something else, we overload __salt__ too much ret.pack['__salt__'] = ret -@@ -942,6 +956,7 @@ def sdb(opts, functions=None, whitelist=None, utils=None): - '__salt__': minion_mods(opts, utils), +@@ -982,6 +993,7 @@ def sdb(opts, functions=None, whitelist=None, utils=None): + '__salt__': minion_mods(opts, utils=utils), }, whitelist=whitelist, + extra_module_dirs=utils.module_dirs if utils else None, ) -@@ -983,6 +998,7 @@ def clouds(opts): +@@ -1023,6 +1035,7 @@ def clouds(opts): ''' Return the cloud functions ''' @@ -287,7 +195,7 @@ index d494c452ed..52cb4cfcb5 100644 # Let's bring __active_provider_name__, defaulting to None, to all cloud # drivers. This will get temporarily updated/overridden with a context # manager when needed. -@@ -994,8 +1010,9 @@ def clouds(opts): +@@ -1034,8 +1047,9 @@ def clouds(opts): int_type='clouds'), opts, tag='clouds', @@ -298,7 +206,7 @@ index d494c452ed..52cb4cfcb5 100644 ) for funcname in LIBCLOUD_FUNCS_NOT_SUPPORTED: log.trace( -@@ -1109,6 +1126,7 @@ class LazyLoader(salt.utils.lazy.LazyDict): +@@ -1149,6 +1163,7 @@ class LazyLoader(salt.utils.lazy.LazyDict): :param bool virtual_enable: Whether or not to respect the __virtual__ function when loading modules. :param str virtual_funcs: The name of additional functions in the module to call to verify its functionality. If not true, the module will not load. @@ -306,7 +214,7 @@ index d494c452ed..52cb4cfcb5 100644 :returns: A LazyLoader object which functions as a dictionary. Keys are 'module.function' and values are function references themselves which are loaded on-demand. # TODO: -@@ -1130,6 +1148,7 @@ class LazyLoader(salt.utils.lazy.LazyDict): +@@ -1170,6 +1185,7 @@ class LazyLoader(salt.utils.lazy.LazyDict): static_modules=None, proxy=None, virtual_funcs=None, @@ -314,7 +222,7 @@ index d494c452ed..52cb4cfcb5 100644 ): # pylint: disable=W0231 ''' In pack, if any of the values are None they will be replaced with an -@@ -1171,6 +1190,9 @@ class LazyLoader(salt.utils.lazy.LazyDict): +@@ -1211,6 +1227,9 @@ class LazyLoader(salt.utils.lazy.LazyDict): virtual_funcs = [] self.virtual_funcs = virtual_funcs @@ -324,7 +232,7 @@ index d494c452ed..52cb4cfcb5 100644 self.disabled = set( self.opts.get( 'disable_{0}{1}'.format( -@@ -1477,12 +1499,30 @@ class LazyLoader(salt.utils.lazy.LazyDict): +@@ -1517,12 +1536,30 @@ class LazyLoader(salt.utils.lazy.LazyDict): reload_module(submodule) self._reload_submodules(submodule) @@ -355,7 +263,7 @@ index d494c452ed..52cb4cfcb5 100644 sys.path.append(fpath_dirname) if suffix == '.pyx': mod = pyximport.load_module(name, fpath, tempfile.gettempdir()) -@@ -1605,6 +1645,7 @@ class LazyLoader(salt.utils.lazy.LazyDict): +@@ -1645,6 +1682,7 @@ class LazyLoader(salt.utils.lazy.LazyDict): return False finally: sys.path.remove(fpath_dirname) @@ -435,10 +343,10 @@ index 2e9a2a952e..4f84642e02 100644 Return the name of the package that owns the file. Multiple file paths can be passed. Like :mod:`pkg.version pkg2. Return None if there was a problem -@@ -1633,7 +1633,7 @@ def _skip_source(source): +@@ -1641,7 +1641,7 @@ def _skip_source(source): return False @@ -474,7 +382,7 @@ index f51b6958e5..e537f5b007 100644 ''' Lists all repos in the sources.list (and sources.lists.d) files -@@ -2400,7 +2400,7 @@ def mod_repo(repo, saltenv='base', **kwargs): +@@ -2411,7 +2411,7 @@ def mod_repo(repo, saltenv='base', **kwargs): } @@ -483,7 +391,7 @@ index f51b6958e5..e537f5b007 100644 ''' List the files that belong to a package. Not specifying any packages will return a list of _every_ file on the system's package database (not -@@ -2417,7 +2417,7 @@ def file_list(*packages): +@@ -2428,7 +2428,7 @@ def file_list(*packages): return __salt__['lowpkg.file_list'](*packages) @@ -492,7 +400,7 @@ index f51b6958e5..e537f5b007 100644 ''' List the files that belong to a package, grouped by package. Not specifying any packages will return a list of _every_ file on the system's -@@ -2701,7 +2701,7 @@ def _resolve_deps(name, pkgs, **kwargs): +@@ -2712,7 +2712,7 @@ def _resolve_deps(name, pkgs, **kwargs): return @@ -501,860 +409,8 @@ index f51b6958e5..e537f5b007 100644 ''' .. versionadded:: 2014.7.0 -diff --git a/salt/modules/btrfs.py b/salt/modules/btrfs.py -index 36bfaeb12e..6fd2ac58a4 100644 ---- a/salt/modules/btrfs.py -+++ b/salt/modules/btrfs.py -@@ -20,11 +20,11 @@ Module for managing BTRFS file systems. - - # Import Python libs - from __future__ import absolute_import, print_function, unicode_literals -+import itertools - import os - import re - import uuid - -- - # Import Salt libs - import salt.utils.fsutils - import salt.utils.platform -@@ -673,3 +673,497 @@ def properties(obj, type=None, set=None): - ret[prop]['value'] = value and value.split("=")[-1] or "N/A" - - return ret -+ -+ -+def subvolume_exists(path): -+ ''' -+ Check if a subvolume is present in the filesystem. -+ -+ path -+ Mount point for the subvolume (full path) -+ -+ CLI Example: -+ -+ .. code-block:: bash -+ -+ salt '*' btrfs.subvolume_exists /mnt/var -+ -+ ''' -+ cmd = ['btrfs', 'subvolume', 'show', path] -+ return __salt__['cmd.retcode'](cmd, ignore_retcode=True) == 0 -+ -+ -+def subvolume_create(name, dest=None, qgroupids=None): -+ ''' -+ Create subvolume `name` in `dest`. -+ -+ Return True if the subvolume is created, False is the subvolume is -+ already there. -+ -+ name -+ Name of the new subvolume -+ -+ dest -+ If not given, the subvolume will be created in the current -+ directory, if given will be in /dest/name -+ -+ qgroupids -+ Add the newly created subcolume to a qgroup. This parameter -+ is a list -+ -+ CLI Example: -+ -+ .. code-block:: bash -+ -+ salt '*' btrfs.subvolume_create var -+ salt '*' btrfs.subvolume_create var dest=/mnt -+ salt '*' btrfs.subvolume_create var qgroupids='[200]' -+ -+ ''' -+ if qgroupids and type(qgroupids) is not list: -+ raise CommandExecutionError('Qgroupids parameter must be a list') -+ -+ if dest: -+ name = os.path.join(dest, name) -+ -+ # If the subvolume is there, we are done -+ if subvolume_exists(name): -+ return False -+ -+ cmd = ['btrfs', 'subvolume', 'create'] -+ if type(qgroupids) is list: -+ cmd.append('-i') -+ cmd.extend(qgroupids) -+ cmd.append(name) -+ -+ res = __salt__['cmd.run_all'](cmd) -+ salt.utils.fsutils._verify_run(res) -+ return True -+ -+ -+def subvolume_delete(name=None, names=None, commit=None): -+ ''' -+ Delete the subvolume(s) from the filesystem -+ -+ The user can remove one single subvolume (name) or multiple of -+ then at the same time (names). One of the two parameters needs to -+ specified. -+ -+ Please, refer to the documentation to understand the implication -+ on the transactions, and when the subvolume is really deleted. -+ -+ Return True if the subvolume is deleted, False is the subvolume -+ was already missing. -+ -+ name -+ Name of the subvolume to remove -+ -+ names -+ List of names of subvolumes to remove -+ -+ commit -+ * 'after': Wait for transaction commit at the end -+ * 'each': Wait for transaction commit after each delete -+ -+ CLI Example: -+ -+ .. code-block:: bash -+ -+ salt '*' btrfs.subvolume_delete /var/volumes/tmp -+ salt '*' btrfs.subvolume_delete /var/volumes/tmp commit=after -+ -+ ''' -+ if not name and not (names and type(names) is list): -+ raise CommandExecutionError('Provide a value for the name parameter') -+ -+ if commit and commit not in ('after', 'each'): -+ raise CommandExecutionError('Value for commit not recognized') -+ -+ # Filter the names and take the ones that are still there -+ names = [n for n in itertools.chain([name], names or []) -+ if n and subvolume_exists(n)] -+ -+ # If the subvolumes are gone, we are done -+ if not names: -+ return False -+ -+ cmd = ['btrfs', 'subvolume', 'delete'] -+ if commit == 'after': -+ cmd.append('--commit-after') -+ elif commit == 'each': -+ cmd.append('--commit-each') -+ cmd.extend(names) -+ -+ res = __salt__['cmd.run_all'](cmd) -+ salt.utils.fsutils._verify_run(res) -+ return True -+ -+ -+def subvolume_find_new(name, last_gen): -+ ''' -+ List the recently modified files in a subvolume -+ -+ name -+ Name of the subvolume -+ -+ last_gen -+ Last transid marker from where to compare -+ -+ CLI Example: -+ -+ .. code-block:: bash -+ -+ salt '*' btrfs.subvolume_find_new /var/volumes/tmp 1024 -+ -+ ''' -+ cmd = ['btrfs', 'subvolume', 'find-new', name, last_gen] -+ -+ res = __salt__['cmd.run_all'](cmd) -+ salt.utils.fsutils._verify_run(res) -+ -+ lines = res['stdout'].splitlines() -+ # Filenames are at the end of each inode line -+ files = [l.split()[-1] for l in lines if l.startswith('inode')] -+ # The last transid is in the last line -+ transid = lines[-1].split()[-1] -+ return { -+ 'files': files, -+ 'transid': transid, -+ } -+ -+ -+def subvolume_get_default(path): -+ ''' -+ Get the default subvolume of the filesystem path -+ -+ path -+ Mount point for the subvolume -+ -+ CLI Example: -+ -+ .. code-block:: bash -+ -+ salt '*' btrfs.subvolume_get_default /var/volumes/tmp -+ -+ ''' -+ cmd = ['btrfs', 'subvolume', 'get-default', path] -+ -+ res = __salt__['cmd.run_all'](cmd) -+ salt.utils.fsutils._verify_run(res) -+ -+ line = res['stdout'].strip() -+ # The ID is the second parameter, and the name the last one, or -+ # '(FS_TREE)' -+ # -+ # When the default one is set: -+ # ID 5 (FS_TREE) -+ # -+ # When we manually set a different one (var): -+ # ID 257 gen 8 top level 5 path var -+ # -+ id_ = line.split()[1] -+ name = line.split()[-1] -+ return { -+ 'id': id_, -+ 'name': name, -+ } -+ -+ -+def _pop(line, key, use_rest): -+ ''' -+ Helper for the line parser. -+ -+ If key is a prefix of line, will remove ir from the line and will -+ extract the value (space separation), and the rest of the line. -+ -+ If use_rest is True, the value will be the rest of the line. -+ -+ Return a tuple with the value and the rest of the line. -+ ''' -+ value = None -+ if line.startswith(key): -+ line = line[len(key):].strip() -+ if use_rest: -+ value = line -+ line = '' -+ else: -+ value, line = line.split(' ', 1) -+ return value, line.strip() -+ -+ -+def subvolume_list(path, parent_id=False, absolute=False, -+ ogeneration=False, generation=False, -+ subvolumes=False, uuid=False, parent_uuid=False, -+ sent_subvolume_uuid=False, snapshots=False, -+ readonly=False, deleted=False, generation_cmp=None, -+ ogeneration_cmp=None, sort=None): -+ ''' -+ List the subvolumes present in the filesystem. -+ -+ path -+ Mount point for the subvolume -+ -+ parent_id -+ Print parent ID -+ -+ absolute -+ Print all the subvolumes in the filesystem and distinguish -+ between absolute and relative path with respect to the given -+ -+ -+ ogeneration -+ Print the ogeneration of the subvolume -+ -+ generation -+ Print the generation of the subvolume -+ -+ subvolumes -+ Print only subvolumes below specified -+ -+ uuid -+ Print the UUID of the subvolume -+ -+ parent_uuid -+ Print the parent uuid of subvolumes (and snapshots) -+ -+ sent_subvolume_uuid -+ Print the UUID of the sent subvolume, where the subvolume is -+ the result of a receive operation -+ -+ snapshots -+ Only snapshot subvolumes in the filesystem will be listed -+ -+ readonly -+ Only readonly subvolumes in the filesystem will be listed -+ -+ deleted -+ Only deleted subvolumens that are ye not cleaned -+ -+ generation_cmp -+ List subvolumes in the filesystem that its generation is >=, -+ <= or = value. '+' means >= value, '-' means <= value, If -+ there is neither '+' nor '-', it means = value -+ -+ ogeneration_cmp -+ List subvolumes in the filesystem that its ogeneration is >=, -+ <= or = value -+ -+ sort -+ List subvolumes in order by specified items. Possible values: -+ * rootid -+ * gen -+ * ogen -+ * path -+ You can add '+' or '-' in front of each items, '+' means -+ ascending, '-' means descending. The default is ascending. You -+ can combite it in a list. -+ -+ CLI Example: -+ -+ .. code-block:: bash -+ -+ salt '*' btrfs.subvolume_list /var/volumes/tmp -+ salt '*' btrfs.subvolume_list /var/volumes/tmp path=True -+ salt '*' btrfs.subvolume_list /var/volumes/tmp sort='[-rootid]' -+ -+ ''' -+ if sort and type(sort) is not list: -+ raise CommandExecutionError('Sort parameter must be a list') -+ -+ valid_sorts = [ -+ ''.join((order, attrib)) for order, attrib in itertools.product( -+ ('-', '', '+'), ('rootid', 'gen', 'ogen', 'path')) -+ ] -+ if sort and not all(s in valid_sorts for s in sort): -+ raise CommandExecutionError('Value for sort not recognized') -+ -+ cmd = ['btrfs', 'subvolume', 'list'] -+ -+ params = ((parent_id, '-p'), -+ (absolute, '-a'), -+ (ogeneration, '-c'), -+ (generation, '-g'), -+ (subvolumes, '-o'), -+ (uuid, '-u'), -+ (parent_uuid, '-q'), -+ (sent_subvolume_uuid, '-R'), -+ (snapshots, '-s'), -+ (readonly, '-r'), -+ (deleted, '-d')) -+ cmd.extend(p[1] for p in params if p[0]) -+ -+ if generation_cmp: -+ cmd.extend(['-G', generation_cmp]) -+ -+ if ogeneration_cmp: -+ cmd.extend(['-C', ogeneration_cmp]) -+ -+ # We already validated the content of the list -+ if sort: -+ cmd.append('--sort={}'.format(','.join(sort))) -+ -+ cmd.append(path) -+ -+ res = __salt__['cmd.run_all'](cmd) -+ salt.utils.fsutils._verify_run(res) -+ -+ # Parse the output. ID and gen are always at the begining, and -+ # path is always at the end. There is only one column that -+ # contains space (top level), and the path value can also have -+ # spaces. The issue is that we do not know how many spaces do we -+ # have in the path name, so any classic solution based on split -+ # will fail. -+ # -+ # This list is in order. -+ columns = ('ID', 'gen', 'cgen', 'parent', 'top level', 'otime', -+ 'parent_uuid', 'received_uuid', 'uuid', 'path') -+ result = [] -+ for line in res['stdout'].splitlines(): -+ table = {} -+ for key in columns: -+ value, line = _pop(line, key, key == 'path') -+ if value: -+ table[key.lower()] = value -+ # If line is not empty here, we are not able to parse it -+ if not line: -+ result.append(table) -+ -+ return result -+ -+ -+def subvolume_set_default(subvolid, path): -+ ''' -+ Set the subvolume as default -+ -+ subvolid -+ ID of the new default subvolume -+ -+ path -+ Mount point for the filesystem -+ -+ CLI Example: -+ -+ .. code-block:: bash -+ -+ salt '*' btrfs.subvolume_set_default 257 /var/volumes/tmp -+ -+ ''' -+ cmd = ['btrfs', 'subvolume', 'set-default', subvolid, path] -+ -+ res = __salt__['cmd.run_all'](cmd) -+ salt.utils.fsutils._verify_run(res) -+ return True -+ -+ -+def subvolume_show(path): -+ ''' -+ Show information of a given subvolume -+ -+ path -+ Mount point for the filesystem -+ -+ CLI Example: -+ -+ .. code-block:: bash -+ -+ salt '*' btrfs.subvolume_show /var/volumes/tmp -+ -+ ''' -+ cmd = ['btrfs', 'subvolume', 'show', path] -+ -+ res = __salt__['cmd.run_all'](cmd) -+ salt.utils.fsutils._verify_run(res) -+ -+ result = {} -+ table = {} -+ # The real name is the first line, later there is a table of -+ # values separated with colon. -+ stdout = res['stdout'].splitlines() -+ key = stdout.pop(0) -+ result[key.strip()] = table -+ -+ for line in stdout: -+ key, value = line.split(':', 1) -+ table[key.lower().strip()] = value.strip() -+ return result -+ -+ -+def subvolume_snapshot(source, dest=None, name=None, read_only=False): -+ ''' -+ Create a snapshot of a source subvolume -+ -+ source -+ Source subvolume from where to create the snapshot -+ -+ dest -+ If only dest is given, the subvolume will be named as the -+ basename of the source -+ -+ name -+ Name of the snapshot -+ -+ read_only -+ Create a read only snapshot -+ -+ CLI Example: -+ -+ .. code-block:: bash -+ -+ salt '*' btrfs.subvolume_snapshot /var/volumes/tmp dest=/.snapshots -+ salt '*' btrfs.subvolume_snapshot /var/volumes/tmp name=backup -+ -+ ''' -+ if not dest and not name: -+ raise CommandExecutionError('Provide parameter dest, name, or both') -+ -+ cmd = ['btrfs', 'subvolume', 'snapshot'] -+ if read_only: -+ cmd.append('-r') -+ if dest and not name: -+ cmd.append(dest) -+ if dest and name: -+ name = os.path.join(dest, name) -+ if name: -+ cmd.append(name) -+ -+ res = __salt__['cmd.run_all'](cmd) -+ salt.utils.fsutils._verify_run(res) -+ return True -+ -+ -+def subvolume_sync(path, subvolids=None, sleep=None): -+ ''' -+ Wait until given subvolume are completely removed from the -+ filesystem after deletion. -+ -+ path -+ Mount point for the filesystem -+ -+ subvolids -+ List of IDs of subvolumes to wait for -+ -+ sleep -+ Sleep N seconds betwenn checks (default: 1) -+ -+ CLI Example: -+ -+ .. code-block:: bash -+ -+ salt '*' btrfs.subvolume_sync /var/volumes/tmp -+ salt '*' btrfs.subvolume_sync /var/volumes/tmp subvolids='[257]' -+ -+ ''' -+ if subvolids and type(subvolids) is not list: -+ raise CommandExecutionError('Subvolids parameter must be a list') -+ -+ cmd = ['btrfs', 'subvolume', 'sync'] -+ if sleep: -+ cmd.extend(['-s', sleep]) -+ -+ cmd.append(path) -+ if subvolids: -+ cmd.extend(subvolids) -+ -+ res = __salt__['cmd.run_all'](cmd) -+ salt.utils.fsutils._verify_run(res) -+ return True -diff --git a/salt/modules/chroot.py b/salt/modules/chroot.py -new file mode 100644 -index 0000000000..6e4705b67e ---- /dev/null -+++ b/salt/modules/chroot.py -@@ -0,0 +1,165 @@ -+# -*- coding: utf-8 -*- -+# -+# Author: Alberto Planas -+# -+# Copyright 2018 SUSE LINUX GmbH, Nuernberg, Germany. -+# -+# Licensed to the Apache Software Foundation (ASF) under one -+# or more contributor license agreements. See the NOTICE file -+# distributed with this work for additional information -+# regarding copyright ownership. The ASF licenses this file -+# to you under the Apache License, Version 2.0 (the -+# "License"); you may not use this file except in compliance -+# with the License. You may obtain a copy of the License at -+# -+# http://www.apache.org/licenses/LICENSE-2.0 -+# -+# Unless required by applicable law or agreed to in writing, -+# software distributed under the License is distributed on an -+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -+# KIND, either express or implied. See the License for the -+# specific language governing permissions and limitations -+# under the License. -+ -+''' -+:maintainer: Alberto Planas -+:maturity: new -+:depends: None -+:platform: Linux -+''' -+from __future__ import absolute_import, print_function, unicode_literals -+import logging -+import os -+import sys -+import tempfile -+ -+from salt.defaults.exitcodes import EX_OK -+from salt.exceptions import CommandExecutionError -+from salt.utils.args import clean_kwargs -+ -+log = logging.getLogger(__name__) -+ -+ -+def __virtual__(): -+ ''' -+ Chroot command is required. -+ ''' -+ if __utils__['path.which']('chroot') is not None: -+ return True -+ else: -+ return (False, 'Module chroot requires the command chroot') -+ -+ -+def exist(name): -+ ''' -+ Return True if the chroot environment is present. -+ ''' -+ dev = os.path.join(name, 'dev') -+ proc = os.path.join(name, 'proc') -+ return all(os.path.isdir(i) for i in (name, dev, proc)) -+ -+ -+def create(name): -+ ''' -+ Create a basic chroot environment. -+ -+ Note that this environment is not functional. The caller needs to -+ install the minimal required binaries, including Python if -+ chroot.call is called. -+ -+ name -+ Path to the chroot environment -+ -+ CLI Example: -+ -+ .. code-block:: bash -+ -+ salt myminion chroot.create /chroot -+ -+ ''' -+ if not exist(name): -+ dev = os.path.join(name, 'dev') -+ proc = os.path.join(name, 'proc') -+ try: -+ os.makedirs(dev, mode=0o755) -+ os.makedirs(proc, mode=0o555) -+ except OSError as e: -+ log.error('Error when trying to create chroot directories: %s', e) -+ return False -+ return True -+ -+ -+def call(name, function, *args, **kwargs): -+ ''' -+ Executes a Salt function inside a chroot environment. -+ -+ The chroot does not need to have Salt installed, but Python is -+ required. -+ -+ name -+ Path to the chroot environment -+ -+ function -+ Salt execution module function -+ -+ CLI Example: -+ -+ .. code-block:: bash -+ -+ salt myminion chroot.call /chroot test.ping -+ -+ ''' -+ -+ if not function: -+ raise CommandExecutionError('Missing function parameter') -+ -+ if not exist(name): -+ raise CommandExecutionError('Chroot environment not found') -+ -+ # Create a temporary directory inside the chroot where we can -+ # untar salt-thin -+ thin_dest_path = tempfile.mkdtemp(dir=name) -+ thin_path = __utils__['thin.gen_thin']( -+ __opts__['cachedir'], -+ extra_mods=__salt__['config.option']('thin_extra_mods', ''), -+ so_mods=__salt__['config.option']('thin_so_mods', '') -+ ) -+ stdout = __salt__['archive.tar']('xzf', thin_path, dest=thin_dest_path) -+ if stdout: -+ __utils__['files.rm_rf'](thin_dest_path) -+ return {'result': False, 'comment': stdout} -+ -+ chroot_path = os.path.join(os.path.sep, -+ os.path.relpath(thin_dest_path, name)) -+ try: -+ safe_kwargs = clean_kwargs(**kwargs) -+ salt_argv = [ -+ 'python{}'.format(sys.version_info[0]), -+ os.path.join(chroot_path, 'salt-call'), -+ '--metadata', -+ '--local', -+ '--log-file', os.path.join(chroot_path, 'log'), -+ '--cachedir', os.path.join(chroot_path, 'cache'), -+ '--out', 'json', -+ '-l', 'quiet', -+ '--', -+ function -+ ] + list(args) + ['{}={}'.format(k, v) for (k, v) in safe_kwargs] -+ ret = __salt__['cmd.run_chroot'](name, [str(x) for x in salt_argv]) -+ if ret['retcode'] != EX_OK: -+ raise CommandExecutionError(ret['stderr']) -+ -+ # Process "real" result in stdout -+ try: -+ data = __utils__['json.find_json'](ret['stdout']) -+ local = data.get('local', data) -+ if isinstance(local, dict) and 'retcode' in local: -+ __context__['retcode'] = local['retcode'] -+ return local.get('return', data) -+ except ValueError: -+ return { -+ 'result': False, -+ 'comment': "Can't parse container command output" -+ } -+ finally: -+ __utils__['files.rm_rf'](thin_dest_path) -diff --git a/salt/modules/cmdmod.py b/salt/modules/cmdmod.py -index 723eddc67b..1801147f57 100644 ---- a/salt/modules/cmdmod.py -+++ b/salt/modules/cmdmod.py -@@ -2904,6 +2904,7 @@ def run_chroot(root, - group=None, - shell=DEFAULT_SHELL, - python_shell=True, -+ binds=None, - env=None, - clean_env=False, - template=None, -@@ -2929,19 +2930,17 @@ def run_chroot(root, - - :param str root: Path to the root of the jail to use. - -- stdin -- A string of standard input can be specified for the command to be run using -- the ``stdin`` parameter. This can be useful in cases where sensitive -- information must be read from standard input.: -+ :param str stdin: A string of standard input can be specified for -+ the command to be run using the ``stdin`` parameter. This can -+ be useful in cases where sensitive information must be read -+ from standard input.: - -- runas -- User to run script as. -+ :param str runas: User to run script as. - -- group -- Group to run script as. -+ :param str group: Group to run script as. - -- shell -- Shell to execute under. Defaults to the system default shell. -+ :param str shell: Shell to execute under. Defaults to the system -+ default shell. - - :param str cmd: The command to run. ex: ``ls -lart /home`` - -@@ -2965,6 +2964,9 @@ def run_chroot(root, - arguments. Set to True to use shell features, such as pipes or - redirection. - -+ :param list binds: List of directories that will be exported inside -+ the chroot with the bind option. -+ - :param dict env: Environment variables to be set prior to execution. - - .. note:: -@@ -2983,11 +2985,11 @@ def run_chroot(root, - engine will be used to render the downloaded file. Currently jinja, - mako, and wempy are supported. - -- :param bool rstrip: -- Strip all whitespace off the end of output before it is returned. -+ :param bool rstrip: Strip all whitespace off the end of output -+ before it is returned. - -- :param str umask: -- The umask (in octal) to use when running the command. -+ :param str umask: The umask (in octal) to use when running the -+ command. - - :param str output_encoding: Control the encoding used to decode the - command's output. -@@ -3061,6 +3063,15 @@ def run_chroot(root, - 'sysfs', - fstype='sysfs') - -+ binds = binds if binds else [] -+ for bind_exported in binds: -+ bind_exported_to = os.path.relpath(bind_exported, os.path.sep) -+ bind_exported_to = os.path.join(root, bind_exported_to) -+ __salt__['mount.mount']( -+ bind_exported_to, -+ bind_exported, -+ opts='default,bind') -+ - # Execute chroot routine - sh_ = '/bin/sh' - if os.path.isfile(os.path.join(root, 'bin/bash')): -@@ -3111,6 +3122,11 @@ def run_chroot(root, - log.error('Processes running in chroot could not be killed, ' - 'filesystem will remain mounted') - -+ for bind_exported in binds: -+ bind_exported_to = os.path.relpath(bind_exported, os.path.sep) -+ bind_exported_to = os.path.join(root, bind_exported_to) -+ __salt__['mount.umount'](bind_exported_to) -+ - __salt__['mount.umount'](os.path.join(root, 'sys')) - __salt__['mount.umount'](os.path.join(root, 'proc')) - __salt__['mount.umount'](os.path.join(root, 'dev')) -diff --git a/salt/modules/disk.py b/salt/modules/disk.py -index 0e0f6eef55..9b0c001e35 100644 ---- a/salt/modules/disk.py -+++ b/salt/modules/disk.py -@@ -268,24 +268,34 @@ def percent(args=None): - - - @salt.utils.decorators.path.which('blkid') --def blkid(device=None): -+def blkid(device=None, token=None): - ''' - Return block device attributes: UUID, LABEL, etc. This function only works - on systems where blkid is available. - -+ device -+ Device name from the system -+ -+ token -+ Any valid token used for the search -+ - CLI Example: - - .. code-block:: bash - - salt '*' disk.blkid - salt '*' disk.blkid /dev/sda -+ salt '*' disk.blkid token='UUID=6a38ee5-7235-44e7-8b22-816a403bad5d' -+ salt '*' disk.blkid token='TYPE=ext4' - ''' -- args = "" -+ cmd = ['blkid'] - if device: -- args = " " + device -+ cmd.append(device) -+ elif token: -+ cmd.extend(['-t', token]) - - ret = {} -- blkid_result = __salt__['cmd.run_all']('blkid' + args, python_shell=False) -+ blkid_result = __salt__['cmd.run_all'](cmd, python_shell=False) - - if blkid_result['retcode'] > 0: - return ret -@@ -422,6 +432,7 @@ def format_(device, - fs_type='ext4', - inode_size=None, - lazy_itable_init=None, -+ fat=None, - force=False): - ''' - Format a filesystem onto a device -@@ -449,6 +460,10 @@ def format_(device, - - This option is only enabled for ext filesystems - -+ fat -+ FAT size option. Can be 12, 16 or 32, and can only be used on -+ fat or vfat filesystems. -+ - force - Force mke2fs to create a filesystem, even if the specified device is - not a partition on a block special device. This option is only enabled -@@ -471,6 +486,9 @@ def format_(device, - if lazy_itable_init is not None: - if fs_type[:3] == 'ext': - cmd.extend(['-E', 'lazy_itable_init={0}'.format(lazy_itable_init)]) -+ if fat is not None and fat in (12, 16, 32): -+ if fs_type[-3:] == 'fat': -+ cmd.extend(['-F', fat]) - if force: - if fs_type[:3] == 'ext': - cmd.append('-F') diff --git a/salt/modules/dpkg_lowpkg.py b/salt/modules/dpkg_lowpkg.py -index 26ca5dcf5a..d5c89cb195 100644 +index b78e844830..a64e6d57da 100644 --- a/salt/modules/dpkg_lowpkg.py +++ b/salt/modules/dpkg_lowpkg.py @@ -135,7 +135,7 @@ def unpurge(*packages): @@ -1455,623 +511,6 @@ index 43f127ef35..0bae7a3bab 100644 ''' List the files that belong to a package, grouped by package. Not specifying any packages will return a list of _every_ file on the -diff --git a/salt/modules/freezer.py b/salt/modules/freezer.py -new file mode 100644 -index 0000000000..786dfe4515 ---- /dev/null -+++ b/salt/modules/freezer.py -@@ -0,0 +1,294 @@ -+# -*- coding: utf-8 -*- -+# -+# Author: Alberto Planas -+# -+# Copyright 2018 SUSE LINUX GmbH, Nuernberg, Germany. -+# -+# Licensed to the Apache Software Foundation (ASF) under one -+# or more contributor license agreements. See the NOTICE file -+# distributed with this work for additional information -+# regarding copyright ownership. The ASF licenses this file -+# to you under the Apache License, Version 2.0 (the -+# "License"); you may not use this file except in compliance -+# with the License. You may obtain a copy of the License at -+# -+# http://www.apache.org/licenses/LICENSE-2.0 -+# -+# Unless required by applicable law or agreed to in writing, -+# software distributed under the License is distributed on an -+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -+# KIND, either express or implied. See the License for the -+# specific language governing permissions and limitations -+# under the License. -+ -+''' -+:maintainer: Alberto Planas -+:maturity: new -+:depends: None -+:platform: Linux -+''' -+from __future__ import absolute_import, print_function, unicode_literals -+import logging -+import os -+ -+from salt.exceptions import CommandExecutionError -+from salt.utils.args import clean_kwargs -+from salt.utils.files import fopen -+import salt.utils.json as json -+from salt.ext.six.moves import zip -+ -+log = logging.getLogger(__name__) -+ -+__func_alias__ = { -+ 'list_': 'list', -+} -+ -+ -+def __virtual__(): -+ ''' -+ Freezer is based on top of the pkg module. -+ -+ Return True as pkg is going to be there, so we can avoid of -+ loading all modules. -+ -+ ''' -+ return True -+ -+ -+def _states_path(): -+ ''' -+ Return the path where we will store the states. -+ ''' -+ return os.path.join(__opts__['cachedir'], 'freezer') -+ -+ -+def _paths(name=None): -+ ''' -+ Return the full path for the packages and repository freezer -+ files. -+ -+ ''' -+ name = 'freezer' if not name else name -+ states_path = _states_path() -+ return ( -+ os.path.join(states_path, '{}-pkgs.yml'.format(name)), -+ os.path.join(states_path, '{}-reps.yml'.format(name)), -+ ) -+ -+ -+def status(name=None): -+ ''' -+ Return True if there is already a frozen state. -+ -+ A frozen state is merely a list of packages (including the -+ version) in a specific time. This information can be used to -+ compare with the current list of packages, and revert the -+ installation of some extra packages that are in the system. -+ -+ name -+ Name of the frozen state. Optional. -+ -+ CLI Example: -+ -+ .. code-block:: bash -+ -+ salt '*' freezer.status -+ salt '*' freezer.status pre_install -+ -+ ''' -+ name = 'freezer' if not name else name -+ return all(os.path.isfile(i) for i in _paths(name)) -+ -+ -+def list_(): -+ ''' -+ Return the list of frozen states. -+ -+ CLI Example: -+ -+ .. code-block:: bash -+ -+ salt '*' freezer.list -+ -+ ''' -+ ret = [] -+ states_path = _states_path() -+ if not os.path.isdir(states_path): -+ return ret -+ -+ for state in os.listdir(states_path): -+ if state.endswith(('-pkgs.yml', '-reps.yml')): -+ # Remove the suffix, as both share the same size -+ ret.append(state[:-9]) -+ return sorted(set(ret)) -+ -+ -+def freeze(name=None, force=False, **kwargs): -+ ''' -+ Save the list of package and repos in a freeze file. -+ -+ As this module is build on top of the pkg module, the user can -+ send extra attributes to the underlying pkg module via kwargs. -+ This function will call ``pkg.list_pkgs`` and ``pkg.list_repos``, -+ and any additional arguments will be passed through to those -+ functions. -+ -+ name -+ Name of the frozen state. Optional. -+ -+ force -+ If true, overwrite the state. Optional. -+ -+ CLI Example: -+ -+ .. code-block:: bash -+ -+ salt '*' freezer.freeze -+ salt '*' freezer.freeze pre_install -+ salt '*' freezer.freeze force=True root=/chroot -+ -+ ''' -+ states_path = _states_path() -+ -+ try: -+ os.makedirs(states_path) -+ except OSError as e: -+ msg = 'Error when trying to create the freezer storage %s: %s' -+ log.error(msg, states_path, e) -+ raise CommandExecutionError(msg % (states_path, e)) -+ -+ if status(name) and not force: -+ raise CommandExecutionError('The state is already present. Use ' -+ 'force parameter to overwrite.') -+ safe_kwargs = clean_kwargs(**kwargs) -+ pkgs = __salt__['pkg.list_pkgs'](**safe_kwargs) -+ repos = __salt__['pkg.list_repos'](**safe_kwargs) -+ for name, content in zip(_paths(name), (pkgs, repos)): -+ with fopen(name, 'w') as fp: -+ json.dump(content, fp) -+ return True -+ -+ -+def restore(name=None, **kwargs): -+ ''' -+ Make sure that the system contains the packages and repos from a -+ frozen state. -+ -+ Read the list of packages and repositories from the freeze file, -+ and compare it with the current list of packages and repos. If -+ there is any difference, all the missing packages are repos will -+ be installed, and all the extra packages and repos will be -+ removed. -+ -+ As this module is build on top of the pkg module, the user can -+ send extra attributes to the underlying pkg module via kwargs. -+ This function will call ``pkg.list_repos``, ``pkg.mod_repo``, -+ ``pkg.list_pkgs``, ``pkg.install``, ``pkg.remove`` and -+ ``pkg.del_repo``, and any additional arguments will be passed -+ through to those functions. -+ -+ name -+ Name of the frozen state. Optional. -+ -+ CLI Example: -+ -+ .. code-block:: bash -+ -+ salt '*' freezer.restore -+ salt '*' freezer.restore root=/chroot -+ -+ ''' -+ if not status(name): -+ raise CommandExecutionError('Frozen state not found.') -+ -+ frozen_pkgs = {} -+ frozen_repos = {} -+ for name, content in zip(_paths(name), (frozen_pkgs, frozen_repos)): -+ with fopen(name) as fp: -+ content.update(json.load(fp)) -+ -+ # The ordering of removing or adding packages and repos can be -+ # relevant, as maybe some missing package comes from a repo that -+ # is also missing, so it cannot be installed. But can also happend -+ # that a missing package comes from a repo that is present, but -+ # will be removed. -+ # -+ # So the proposed order is; -+ # - Add missing repos -+ # - Add missing packages -+ # - Remove extra packages -+ # - Remove extra repos -+ -+ safe_kwargs = clean_kwargs(**kwargs) -+ -+ # Note that we expect that the information stored in list_XXX -+ # match with the mod_XXX counterpart. If this is not the case the -+ # recovery will be partial. -+ -+ res = { -+ 'pkgs': {'add': [], 'remove': []}, -+ 'repos': {'add': [], 'remove': []}, -+ 'comment': [], -+ } -+ -+ # Add missing repositories -+ repos = __salt__['pkg.list_repos'](**safe_kwargs) -+ missing_repos = set(frozen_repos) - set(repos) -+ for repo in missing_repos: -+ try: -+ # In Python 2 we cannot do advance destructuring, so we -+ # need to create a temporary dictionary that will merge -+ # all the parameters -+ _tmp_kwargs = frozen_repos[repo].copy() -+ _tmp_kwargs.update(safe_kwargs) -+ __salt__['pkg.mod_repo'](repo, **_tmp_kwargs) -+ res['repos']['add'].append(repo) -+ log.info('Added missing repository %s', repo) -+ except Exception as e: -+ msg = 'Error adding %s repository: %s' -+ log.error(msg, repo, e) -+ res['comment'].append(msg % (repo, e)) -+ -+ # Add missing packages -+ # NOTE: we can remove the `for` using `pkgs`. This will improve -+ # performance, but I want to have a more detalied report of what -+ # packages are installed or failled. -+ pkgs = __salt__['pkg.list_pkgs'](**safe_kwargs) -+ missing_pkgs = set(frozen_pkgs) - set(pkgs) -+ for pkg in missing_pkgs: -+ try: -+ __salt__['pkg.install'](name=pkg, **safe_kwargs) -+ res['pkgs']['add'].append(pkg) -+ log.info('Added missing package %s', pkg) -+ except Exception as e: -+ msg = 'Error adding %s package: %s' -+ log.error(msg, pkg, e) -+ res['comment'].append(msg % (pkg, e)) -+ -+ # Remove extra packages -+ pkgs = __salt__['pkg.list_pkgs'](**safe_kwargs) -+ extra_pkgs = set(pkgs) - set(frozen_pkgs) -+ for pkg in extra_pkgs: -+ try: -+ __salt__['pkg.remove'](name=pkg, **safe_kwargs) -+ res['pkgs']['remove'].append(pkg) -+ log.info('Removed extra package %s', pkg) -+ except Exception as e: -+ msg = 'Error removing %s package: %s' -+ log.error(msg, pkg, e) -+ res['comment'].append(msg % (pkg, e)) -+ -+ # Remove extra repositories -+ repos = __salt__['pkg.list_repos'](**safe_kwargs) -+ extra_repos = set(repos) - set(frozen_repos) -+ for repo in extra_repos: -+ try: -+ __salt__['pkg.del_repo'](repo, **safe_kwargs) -+ res['repos']['remove'].append(repo) -+ log.info('Removed extra repository %s', repo) -+ except Exception as e: -+ msg = 'Error removing %s repository: %s' -+ log.error(msg, repo, e) -+ res['comment'].append(msg % (repo, e)) -+ -+ return res -diff --git a/salt/modules/groupadd.py b/salt/modules/groupadd.py -index e2e1560ab0..15dec6e898 100644 ---- a/salt/modules/groupadd.py -+++ b/salt/modules/groupadd.py -@@ -12,8 +12,12 @@ Manage groups on Linux, OpenBSD and NetBSD - # Import python libs - from __future__ import absolute_import, print_function, unicode_literals - import logging -+import functools -+import os - - from salt.ext import six -+import salt.utils.files -+import salt.utils.stringutils - try: - import grp - except ImportError: -@@ -40,6 +44,18 @@ def add(name, gid=None, system=False, root=None): - ''' - Add the specified group - -+ name -+ Name of the new group -+ -+ gid -+ Use GID for the new group -+ -+ system -+ Create a system account -+ -+ root -+ Directory to chroot into -+ - CLI Example: - - .. code-block:: bash -@@ -51,11 +67,12 @@ def add(name, gid=None, system=False, root=None): - cmd.append('-g {0}'.format(gid)) - if system and __grains__['kernel'] != 'OpenBSD': - cmd.append('-r') -- cmd.append(name) - - if root is not None: - cmd.extend(('-R', root)) - -+ cmd.append(name) -+ - ret = __salt__['cmd.run_all'](cmd, python_shell=False) - - return not ret['retcode'] -@@ -65,34 +82,53 @@ def delete(name, root=None): - ''' - Remove the named group - -+ name -+ Name group to delete -+ -+ root -+ Directory to chroot into -+ - CLI Example: - - .. code-block:: bash - - salt '*' group.delete foo - ''' -- cmd = ['groupdel', name] -+ cmd = ['groupdel'] - - if root is not None: - cmd.extend(('-R', root)) - -+ cmd.append(name) -+ - ret = __salt__['cmd.run_all'](cmd, python_shell=False) - - return not ret['retcode'] - - --def info(name): -+def info(name, root=None): - ''' - Return information about a group - -+ name -+ Name of the group -+ -+ root -+ Directory to chroot into -+ - CLI Example: - - .. code-block:: bash - - salt '*' group.info foo - ''' -+ if root is not None: -+ getgrnam = functools.partial(_getgrnam, root=root) -+ else: -+ getgrnam = functools.partial(grp.getgrnam) -+ - try: -- grinfo = grp.getgrnam(name) -+ grinfo = getgrnam(name) - except KeyError: - return {} - else: -@@ -109,10 +145,16 @@ def _format_info(data): - 'members': data.gr_mem} - - --def getent(refresh=False): -+def getent(refresh=False, root=None): - ''' - Return info on all groups - -+ refresh -+ Force a refresh of group information -+ -+ root -+ Directory to chroot into -+ - CLI Example: - - .. code-block:: bash -@@ -123,41 +165,74 @@ def getent(refresh=False): - return __context__['group.getent'] - - ret = [] -- for grinfo in grp.getgrall(): -+ if root is not None: -+ getgrall = functools.partial(_getgrall, root=root) -+ else: -+ getgrall = functools.partial(grp.getgrall) -+ -+ for grinfo in getgrall(): - ret.append(_format_info(grinfo)) - __context__['group.getent'] = ret - return ret - - -+def _chattrib(name, key, value, param, root=None): -+ ''' -+ Change an attribute for a named user -+ ''' -+ pre_info = info(name, root=root) -+ if not pre_info: -+ return False -+ -+ if value == pre_info[key]: -+ return True -+ -+ cmd = ['groupmod'] -+ -+ if root is not None: -+ cmd.extend(('-R', root)) -+ -+ cmd.extend((param, value, name)) -+ -+ __salt__['cmd.run'](cmd, python_shell=False) -+ return info(name, root=root).get(key) == value -+ -+ - def chgid(name, gid, root=None): - ''' - Change the gid for a named group - -+ name -+ Name of the group to modify -+ -+ gid -+ Change the group ID to GID -+ -+ root -+ Directory to chroot into -+ - CLI Example: - - .. code-block:: bash - - salt '*' group.chgid foo 4376 - ''' -- pre_gid = __salt__['file.group_to_gid'](name) -- if gid == pre_gid: -- return True -- cmd = ['groupmod', '-g', gid, name] -- -- if root is not None: -- cmd.extend(('-R', root)) -- -- __salt__['cmd.run'](cmd, python_shell=False) -- post_gid = __salt__['file.group_to_gid'](name) -- if post_gid != pre_gid: -- return post_gid == gid -- return False -+ return _chattrib(name, 'gid', gid, '-g', root=root) - - - def adduser(name, username, root=None): - ''' - Add a user in the group. - -+ name -+ Name of the group to modify -+ -+ username -+ Username to add to the group -+ -+ root -+ Directory to chroot into -+ - CLI Example: - - .. code-block:: bash -@@ -178,7 +253,7 @@ def adduser(name, username, root=None): - else: - cmd = ['gpasswd', '--add', username, name] - if root is not None: -- cmd.extend(('-Q', root)) -+ cmd.extend(('--root', root)) - else: - cmd = ['usermod', '-G', name, username] - if root is not None: -@@ -193,6 +268,15 @@ def deluser(name, username, root=None): - ''' - Remove a user from the group. - -+ name -+ Name of the group to modify -+ -+ username -+ Username to delete from the group -+ -+ root -+ Directory to chroot into -+ - CLI Example: - - .. code-block:: bash -@@ -216,7 +300,7 @@ def deluser(name, username, root=None): - else: - cmd = ['gpasswd', '--del', username, name] - if root is not None: -- cmd.extend(('-R', root)) -+ cmd.extend(('--root', root)) - retcode = __salt__['cmd.retcode'](cmd, python_shell=False) - elif __grains__['kernel'] == 'OpenBSD': - out = __salt__['cmd.run_stdout']('id -Gn {0}'.format(username), -@@ -239,6 +323,15 @@ def members(name, members_list, root=None): - ''' - Replaces members of the group with a provided list. - -+ name -+ Name of the group to modify -+ -+ members_list -+ Username list to set into the group -+ -+ root -+ Directory to chroot into -+ - CLI Example: - - salt '*' group.members foo 'user1,user2,user3,...' -@@ -259,7 +352,7 @@ def members(name, members_list, root=None): - else: - cmd = ['gpasswd', '--members', members_list, name] - if root is not None: -- cmd.extend(('-R', root)) -+ cmd.extend(('--root', root)) - retcode = __salt__['cmd.retcode'](cmd, python_shell=False) - elif __grains__['kernel'] == 'OpenBSD': - retcode = 1 -@@ -284,3 +377,43 @@ def members(name, members_list, root=None): - return False - - return not retcode -+ -+ -+def _getgrnam(name, root=None): -+ ''' -+ Alternative implementation for getgrnam, that use only /etc/group -+ ''' -+ root = root or '/' -+ passwd = os.path.join(root, 'etc/group') -+ with salt.utils.files.fopen(passwd) as fp_: -+ for line in fp_: -+ line = salt.utils.stringutils.to_unicode(line) -+ comps = line.strip().split(':') -+ if len(comps) < 4: -+ log.debug('Ignoring group line: %s', line) -+ continue -+ if comps[0] == name: -+ # Generate a getpwnam compatible output -+ comps[2] = int(comps[2]) -+ comps[3] = comps[3].split(',') if comps[3] else [] -+ return grp.struct_group(comps) -+ raise KeyError('getgrnam(): name not found: {}'.format(name)) -+ -+ -+def _getgrall(root=None): -+ ''' -+ Alternative implemetantion for getgrall, that use only /etc/group -+ ''' -+ root = root or '/' -+ passwd = os.path.join(root, 'etc/group') -+ with salt.utils.files.fopen(passwd) as fp_: -+ for line in fp_: -+ line = salt.utils.stringutils.to_unicode(line) -+ comps = line.strip().split(':') -+ if len(comps) < 4: -+ log.debug('Ignoring group line: %s', line) -+ continue -+ # Generate a getgrall compatible output -+ comps[2] = int(comps[2]) -+ comps[3] = comps[3].split(',') if comps[3] else [] -+ yield grp.struct_group(comps) diff --git a/salt/modules/kubeadm.py b/salt/modules/kubeadm.py new file mode 100644 index 0000000000..2b1e7906a1 @@ -3343,120 +1782,11 @@ index 0000000000..2b1e7906a1 +# * upgrade_diff +# * upgrade_node +# * upgrade_plan -diff --git a/salt/modules/linux_lvm.py b/salt/modules/linux_lvm.py -index 003d6c0b06..0a975324af 100644 ---- a/salt/modules/linux_lvm.py -+++ b/salt/modules/linux_lvm.py -@@ -64,17 +64,21 @@ def fullversion(): - return ret - - --def pvdisplay(pvname='', real=False): -+def pvdisplay(pvname='', real=False, quiet=False): - ''' - Return information about the physical volume(s) - - pvname - physical device name -+ - real - dereference any symlinks and report the real device - - .. versionadded:: 2015.8.7 - -+ quiet -+ if the physical volume is not present, do not show any error -+ - - CLI Examples: - -@@ -87,7 +91,8 @@ def pvdisplay(pvname='', real=False): - cmd = ['pvdisplay', '-c'] - if pvname: - cmd.append(pvname) -- cmd_ret = __salt__['cmd.run_all'](cmd, python_shell=False) -+ cmd_ret = __salt__['cmd.run_all'](cmd, python_shell=False, -+ ignore_retcode=quiet) - - if cmd_ret['retcode'] != 0: - return {} -@@ -118,10 +123,16 @@ def pvdisplay(pvname='', real=False): - return ret - - --def vgdisplay(vgname=''): -+def vgdisplay(vgname='', quiet=False): - ''' - Return information about the volume group(s) - -+ vgname -+ volume group name -+ -+ quiet -+ if the volume group is not present, do not show any error -+ - CLI Examples: - - .. code-block:: bash -@@ -133,7 +144,8 @@ def vgdisplay(vgname=''): - cmd = ['vgdisplay', '-c'] - if vgname: - cmd.append(vgname) -- cmd_ret = __salt__['cmd.run_all'](cmd, python_shell=False) -+ cmd_ret = __salt__['cmd.run_all'](cmd, python_shell=False, -+ ignore_retcode=quiet) - - if cmd_ret['retcode'] != 0: - return {} -@@ -167,6 +179,12 @@ def lvdisplay(lvname='', quiet=False): - ''' - Return information about the logical volume(s) - -+ lvname -+ logical device name -+ -+ quiet -+ if the logical volume is not present, do not show any error -+ - CLI Examples: - - .. code-block:: bash -@@ -178,10 +196,8 @@ def lvdisplay(lvname='', quiet=False): - cmd = ['lvdisplay', '-c'] - if lvname: - cmd.append(lvname) -- if quiet: -- cmd_ret = __salt__['cmd.run_all'](cmd, python_shell=False, output_loglevel='quiet') -- else: -- cmd_ret = __salt__['cmd.run_all'](cmd, python_shell=False) -+ cmd_ret = __salt__['cmd.run_all'](cmd, python_shell=False, -+ ignore_retcode=quiet) - - if cmd_ret['retcode'] != 0: - return {} -@@ -230,7 +246,7 @@ def pvcreate(devices, override=True, **kwargs): - for device in devices: - if not os.path.exists(device): - raise CommandExecutionError('{0} does not exist'.format(device)) -- if not pvdisplay(device): -+ if not pvdisplay(device, quiet=True): - cmd.append(device) - elif not override: - raise CommandExecutionError('Device "{0}" is already an LVM physical volume.'.format(device)) -@@ -295,7 +311,7 @@ def pvremove(devices, override=True): - - # Verify pvcremove was successful - for device in devices: -- if pvdisplay(device): -+ if pvdisplay(device, quiet=True): - raise CommandExecutionError('Device "{0}" was not affected.'.format(device)) - - return True diff --git a/salt/modules/mac_brew_pkg.py b/salt/modules/mac_brew_pkg.py -index c4507d8267..0152908fb6 100644 +index 5484955edc..ee13fc2102 100644 --- a/salt/modules/mac_brew_pkg.py +++ b/salt/modules/mac_brew_pkg.py -@@ -276,7 +276,7 @@ def remove(name=None, pkgs=None, **kwargs): +@@ -290,7 +290,7 @@ def remove(name=None, pkgs=None, **kwargs): return ret @@ -3465,7 +1795,7 @@ index c4507d8267..0152908fb6 100644 ''' Update the homebrew package repository. -@@ -459,7 +459,7 @@ def list_upgrades(refresh=True, **kwargs): # pylint: disable=W0613 +@@ -474,7 +474,7 @@ def list_upgrades(refresh=True, **kwargs): # pylint: disable=W0613 return ret @@ -3474,7 +1804,7 @@ index c4507d8267..0152908fb6 100644 ''' Check whether or not an upgrade is available for a given package -@@ -472,7 +472,7 @@ def upgrade_available(pkg): +@@ -487,7 +487,7 @@ def upgrade_available(pkg): return pkg in list_upgrades() @@ -3483,7 +1813,7 @@ index c4507d8267..0152908fb6 100644 ''' Upgrade outdated, unpinned brews. -@@ -517,7 +517,7 @@ def upgrade(refresh=True): +@@ -532,7 +532,7 @@ def upgrade(refresh=True): return ret @@ -3523,192 +1853,6 @@ index 78a38d54a9..d403d0e29b 100644 ''' Run a full upgrade using MacPorts 'port upgrade outdated' -diff --git a/salt/modules/mdadm_raid.py b/salt/modules/mdadm_raid.py -index 829f4cdd24..1581a558b6 100644 ---- a/salt/modules/mdadm_raid.py -+++ b/salt/modules/mdadm_raid.py -@@ -247,7 +247,7 @@ def create(name, - '-v', - '-l', six.text_type(level), - ] + opts + [ -- '-e', metadata, -+ '-e', six.text_type(metadata), - '-n', six.text_type(raid_devices), - ] + devices - -@@ -360,17 +360,25 @@ def assemble(name, - return __salt__['cmd.run'](cmd, python_shell=False) - - --def examine(device): -+def examine(device, quiet=False): - ''' - Show detail for a specified RAID component device - -+ device -+ Device to examine, that is part of the RAID -+ -+ quiet -+ If the device is not part of the RAID, do not show any error -+ - CLI Example: - - .. code-block:: bash - - salt '*' raid.examine '/dev/sda1' - ''' -- res = __salt__['cmd.run_stdout']('mdadm -Y -E {0}'.format(device), output_loglevel='trace', python_shell=False) -+ res = __salt__['cmd.run_stdout']('mdadm -Y -E {0}'.format(device), -+ python_shell=False, -+ ignore_retcode=quiet) - ret = {} - - for line in res.splitlines(): -diff --git a/salt/modules/mount.py b/salt/modules/mount.py -index 97263252c7..f2737b9a5c 100644 ---- a/salt/modules/mount.py -+++ b/salt/modules/mount.py -@@ -711,11 +711,15 @@ def set_fstab( - config='/etc/fstab', - test=False, - match_on='auto', -+ not_change=False, - **kwargs): - ''' - Verify that this mount is represented in the fstab, change the mount - to match the data passed, or add the mount if it is not present. - -+ If the entry is found via `match_on` and `not_change` is True, the -+ current line will be preserved. -+ - CLI Example: - - .. code-block:: bash -@@ -793,7 +797,7 @@ def set_fstab( - # Note: If ret isn't None here, - # we've matched multiple lines - ret = 'present' -- if entry.match(line): -+ if entry.match(line) or not_change: - lines.append(line) - else: - ret = 'change' -@@ -837,12 +841,16 @@ def set_vfstab( - config='/etc/vfstab', - test=False, - match_on='auto', -+ not_change=False, - **kwargs): - ''' - ..verionadded:: 2016.3.2 - Verify that this mount is represented in the fstab, change the mount - to match the data passed, or add the mount if it is not present. - -+ If the entry is found via `match_on` and `not_change` is True, the -+ current line will be preserved. -+ - CLI Example: - - .. code-block:: bash -@@ -922,7 +930,7 @@ def set_vfstab( - # Note: If ret isn't None here, - # we've matched multiple lines - ret = 'present' -- if entry.match(line): -+ if entry.match(line) or not_change: - lines.append(line) - else: - ret = 'change' -@@ -1023,6 +1031,7 @@ def set_automaster( - opts='', - config='/etc/auto_salt', - test=False, -+ not_change=False, - **kwargs): - ''' - Verify that this mount is represented in the auto_salt, change the mount -@@ -1071,9 +1080,11 @@ def set_automaster( - lines.append(line) - continue - if comps[0] == name or comps[2] == device_fmt: -+ present = True -+ if not_change: -+ continue - # check to see if there are changes - # and fix them if there are any -- present = True - if comps[0] != name: - change = True - comps[0] = name -@@ -1218,6 +1229,8 @@ def mount(name, device, mkmnt=False, fstype='', opts='defaults', user=None, util - # fstype in /etc/filesystems - if 'AIX' in __grains__['os']: - args += ' -v {0}'.format(fstype) -+ elif 'solaris' in __grains__['os'].lower(): -+ args += ' -F {0}'.format(fstype) - else: - args += ' -t {0}'.format(fstype) - -@@ -1248,7 +1261,7 @@ def remount(name, device, mkmnt=False, fstype='', opts='defaults', user=None): - - if 'AIX' in __grains__['os']: - if opts == 'defaults': -- opts = '' -+ opts = [] - - if isinstance(opts, six.string_types): - opts = opts.split(',') -@@ -1263,14 +1276,16 @@ def remount(name, device, mkmnt=False, fstype='', opts='defaults', user=None): - lopts = ','.join(opts) - args = '-o {0}'.format(lopts) - -- # use of fstype on AIX differs from typical Linux use of -t functionality -- # AIX uses -v vfsname, -t fstype mounts all with fstype in /etc/filesystems -- if 'AIX' in __grains__['os']: -- if fstype: -+ if fstype: -+ # use of fstype on AIX differs from typical Linux use of -+ # -t functionality AIX uses -v vfsname, -t fstype mounts -+ # all with fstype in /etc/filesystems -+ if 'AIX' in __grains__['os']: - args += ' -v {0}'.format(fstype) -- args += ' -o remount' -- else: -- args += ' -t {0}'.format(fstype) -+ elif 'solaris' in __grains__['os'].lower(): -+ args += ' -F {0}'.format(fstype) -+ else: -+ args += ' -t {0}'.format(fstype) - - if __grains__['os'] not in ['OpenBSD', 'MacOS', 'Darwin'] or force_mount: - cmd = 'mount {0} {1} {2} '.format(args, device, name) -@@ -1668,6 +1683,7 @@ def set_filesystems( - config='/etc/filesystems', - test=False, - match_on='auto', -+ not_change=False, - **kwargs): - ''' - .. versionadded:: 2018.3.3 -@@ -1675,6 +1691,9 @@ def set_filesystems( - Verify that this mount is represented in the filesystems, change the mount - to match the data passed, or add the mount if it is not present on AIX - -+ If the entry is found via `match_on` and `not_change` is True, the -+ current line will be preserved. -+ - Provide information if the path is mounted - - :param name: The name of the mount point where the device is mounted. -@@ -1774,7 +1793,7 @@ def set_filesystems( - for fsys_view in six.viewitems(fsys_filedict): - if criteria.match(fsys_view): - ret = 'present' -- if entry_ip.match(fsys_view): -+ if entry_ip.match(fsys_view) or not_change: - view_lines.append(fsys_view) - else: - ret = 'change' diff --git a/salt/modules/openbsdpkg.py b/salt/modules/openbsdpkg.py index b3b6bab912..819a24afb1 100644 --- a/salt/modules/openbsdpkg.py @@ -3771,136 +1915,6 @@ index e30296e8c8..35007e27f5 100644 ''' .. versionadded:: 2014.7.0 -diff --git a/salt/modules/parted_partition.py b/salt/modules/parted_partition.py -index 1757e7118f..c2e0ebb882 100644 ---- a/salt/modules/parted_partition.py -+++ b/salt/modules/parted_partition.py -@@ -44,6 +44,15 @@ __func_alias__ = { - VALID_UNITS = set(['s', 'B', 'kB', 'MB', 'MiB', 'GB', 'GiB', 'TB', 'TiB', '%', - 'cyl', 'chs', 'compact']) - -+VALID_DISK_FLAGS = set(['cylinder_alignment', 'pmbr_boot', -+ 'implicit_partition_table']) -+ -+VALID_PARTITION_FLAGS = set(['boot', 'root', 'swap', 'hidden', 'raid', -+ 'lvm', 'lba', 'hp-service', 'palo', -+ 'prep', 'msftres', 'bios_grub', 'atvrecv', -+ 'diag', 'legacy_boot', 'msftdata', 'irst', -+ 'esp', 'type']) -+ - - def __virtual__(): - ''' -@@ -641,8 +650,26 @@ def set_(device, minor, flag, state): - :ref:`YAML Idiosyncrasies `). Some or all of these - flags will be available, depending on what disk label you are using. - -- Valid flags are: bios_grub, legacy_boot, boot, lba, root, swap, hidden, raid, -- LVM, PALO, PREP, DIAG -+ Valid flags are: -+ * boot -+ * root -+ * swap -+ * hidden -+ * raid -+ * lvm -+ * lba -+ * hp-service -+ * palo -+ * prep -+ * msftres -+ * bios_grub -+ * atvrecv -+ * diag -+ * legacy_boot -+ * msftdata -+ * irst -+ * esp -+ * type - - CLI Example: - -@@ -659,8 +686,7 @@ def set_(device, minor, flag, state): - 'Invalid minor number passed to partition.set' - ) - -- if flag not in set(['bios_grub', 'legacy_boot', 'boot', 'lba', 'root', -- 'swap', 'hidden', 'raid', 'LVM', 'PALO', 'PREP', 'DIAG']): -+ if flag not in VALID_PARTITION_FLAGS: - raise CommandExecutionError('Invalid flag passed to partition.set') - - if state not in set(['on', 'off']): -@@ -691,8 +717,7 @@ def toggle(device, partition, flag): - 'Invalid partition number passed to partition.toggle' - ) - -- if flag not in set(['bios_grub', 'legacy_boot', 'boot', 'lba', 'root', -- 'swap', 'hidden', 'raid', 'LVM', 'PALO', 'PREP', 'DIAG']): -+ if flag not in VALID_PARTITION_FLAGS: - raise CommandExecutionError('Invalid flag passed to partition.toggle') - - cmd = 'parted -m -s {0} toggle {1} {2}'.format(device, partition, flag) -@@ -700,6 +725,60 @@ def toggle(device, partition, flag): - return out - - -+def disk_set(device, flag, state): -+ ''' -+ Changes a flag on selected device. -+ -+ A flag can be either "on" or "off" (make sure to use proper -+ quoting, see :ref:`YAML Idiosyncrasies -+ `). Some or all of these flags will be -+ available, depending on what disk label you are using. -+ -+ Valid flags are: -+ * cylinder_alignment -+ * pmbr_boot -+ * implicit_partition_table -+ -+ CLI Example: -+ -+ .. code-block:: bash -+ -+ salt '*' partition.disk_set /dev/sda pmbr_boot '"on"' -+ ''' -+ _validate_device(device) -+ -+ if flag not in VALID_DISK_FLAGS: -+ raise CommandExecutionError('Invalid flag passed to partition.disk_set') -+ -+ if state not in set(['on', 'off']): -+ raise CommandExecutionError('Invalid state passed to partition.disk_set') -+ -+ cmd = ['parted', '-m', '-s', device, 'disk_set', flag, state] -+ out = __salt__['cmd.run'](cmd).splitlines() -+ return out -+ -+ -+def disk_toggle(device, flag): -+ ''' -+ Toggle the state of on . Valid flags are the same -+ as the disk_set command. -+ -+ CLI Example: -+ -+ .. code-block:: bash -+ -+ salt '*' partition.disk_toggle /dev/sda pmbr_boot -+ ''' -+ _validate_device(device) -+ -+ if flag not in VALID_DISK_FLAGS: -+ raise CommandExecutionError('Invalid flag passed to partition.disk_toggle') -+ -+ cmd = ['parted', '-m', '-s', device, 'disk_toggle', flag] -+ out = __salt__['cmd.run'](cmd).splitlines() -+ return out -+ -+ - def exists(device=''): - ''' - Check to see if the partition exists diff --git a/salt/modules/pkgin.py b/salt/modules/pkgin.py index 240f79ca26..dd5257c80d 100644 --- a/salt/modules/pkgin.py @@ -3942,7 +1956,7 @@ index 240f79ca26..dd5257c80d 100644 .. versionchanged: 2016.3.0 diff --git a/salt/modules/pkgng.py b/salt/modules/pkgng.py -index dabd817fbf..ab20d05ef2 100644 +index 4a908084ea..7435628112 100644 --- a/salt/modules/pkgng.py +++ b/salt/modules/pkgng.py @@ -224,7 +224,7 @@ def version(*names, **kwargs): @@ -3964,7 +1978,7 @@ index dabd817fbf..ab20d05ef2 100644 Do a cmp-style comparison on two packages. Return -1 if pkg1 < pkg2, 0 if pkg1 == pkg2, and 1 if pkg1 > pkg2. Return None if there was a problem diff --git a/salt/modules/rpm_lowpkg.py b/salt/modules/rpm_lowpkg.py -index 893ae4f817..e577c4391a 100644 +index 439404ae90..c8a87276b2 100644 --- a/salt/modules/rpm_lowpkg.py +++ b/salt/modules/rpm_lowpkg.py @@ -76,7 +76,7 @@ def bin_pkg_info(path, saltenv='base'): @@ -4230,521 +2244,11 @@ index 893ae4f817..e577c4391a 100644 ignore_retcode=True, output_loglevel='trace', python_shell=False)) -diff --git a/salt/modules/shadow.py b/salt/modules/shadow.py -index 9659867f05..98c7369c5e 100644 ---- a/salt/modules/shadow.py -+++ b/salt/modules/shadow.py -@@ -13,6 +13,7 @@ from __future__ import absolute_import, unicode_literals, print_function - # Import python libs - import os - import datetime -+import functools - try: - import spwd - except ImportError: -@@ -24,6 +25,7 @@ import salt.utils.files - import salt.utils.stringutils - from salt.exceptions import CommandExecutionError - from salt.ext import six -+from salt.ext.six.moves import range - try: - import salt.utils.pycrypto - HAS_CRYPT = True -@@ -48,21 +50,32 @@ def default_hash(): - return '!' - - --def info(name): -+def info(name, root=None): - ''' - Return information for the specified user - -+ name -+ User to get the information for -+ -+ root -+ Directory to chroot into -+ - CLI Example: - - .. code-block:: bash - - salt '*' shadow.info root - ''' -+ if root is not None: -+ getspnam = functools.partial(_getspnam, root=root) -+ else: -+ getspnam = functools.partial(spwd.getspnam) -+ - try: -- data = spwd.getspnam(name) -+ data = getspnam(name) - ret = { -- 'name': data.sp_nam, -- 'passwd': data.sp_pwd, -+ 'name': data.sp_namp if hasattr(data, 'sp_namp') else data.sp_nam, -+ 'passwd': data.sp_pwdp if hasattr(data, 'sp_pwdp') else data.sp_pwd, - 'lstchg': data.sp_lstchg, - 'min': data.sp_min, - 'max': data.sp_max, -@@ -82,69 +95,99 @@ def info(name): - return ret - - --def set_inactdays(name, inactdays): -+def _set_attrib(name, key, value, param, root=None, validate=True): -+ ''' -+ Set a parameter in /etc/shadow -+ ''' -+ pre_info = info(name, root=root) -+ -+ # If the user is not present or the attribute is already present, -+ # we return early -+ if not pre_info['name']: -+ return False -+ -+ if value == pre_info[key]: -+ return True -+ -+ cmd = ['chage'] -+ -+ if root is not None: -+ cmd.extend(('-R', root)) -+ -+ cmd.extend((param, value, name)) -+ -+ ret = not __salt__['cmd.run'](cmd, python_shell=False) -+ if validate: -+ ret = info(name, root=root).get(key) == value -+ return ret -+ -+ -+def set_inactdays(name, inactdays, root=None): - ''' - Set the number of days of inactivity after a password has expired before - the account is locked. See man chage. - -+ name -+ User to modify -+ -+ inactdays -+ Set password inactive after this number of days -+ -+ root -+ Directory to chroot into -+ - CLI Example: - - .. code-block:: bash - - salt '*' shadow.set_inactdays username 7 - ''' -- pre_info = info(name) -- if inactdays == pre_info['inact']: -- return True -- cmd = 'chage -I {0} {1}'.format(inactdays, name) -- __salt__['cmd.run'](cmd, python_shell=False) -- post_info = info(name) -- if post_info['inact'] != pre_info['inact']: -- return post_info['inact'] == inactdays -- return False -+ return _set_attrib(name, 'inact', inactdays, '-I', root=root) - - --def set_maxdays(name, maxdays): -+def set_maxdays(name, maxdays, root=None): - ''' - Set the maximum number of days during which a password is valid. - See man chage. - -+ name -+ User to modify -+ -+ maxdays -+ Maximum number of days during which a password is valid -+ -+ root -+ Directory to chroot into -+ - CLI Example: - - .. code-block:: bash - - salt '*' shadow.set_maxdays username 90 - ''' -- pre_info = info(name) -- if maxdays == pre_info['max']: -- return True -- cmd = 'chage -M {0} {1}'.format(maxdays, name) -- __salt__['cmd.run'](cmd, python_shell=False) -- post_info = info(name) -- if post_info['max'] != pre_info['max']: -- return post_info['max'] == maxdays -- return False -+ return _set_attrib(name, 'max', maxdays, '-M', root=root) - - --def set_mindays(name, mindays): -+def set_mindays(name, mindays, root=None): - ''' - Set the minimum number of days between password changes. See man chage. - -+ name -+ User to modify -+ -+ mindays -+ Minimum number of days between password changes -+ -+ root -+ Directory to chroot into -+ - CLI Example: - - .. code-block:: bash - - salt '*' shadow.set_mindays username 7 - ''' -- pre_info = info(name) -- if mindays == pre_info['min']: -- return True -- cmd = 'chage -m {0} {1}'.format(mindays, name) -- __salt__['cmd.run'](cmd, python_shell=False) -- post_info = info(name) -- if post_info['min'] != pre_info['min']: -- return post_info['min'] == mindays -- return False -+ return _set_attrib(name, 'min', mindays, '-m', root=root) - - - def gen_password(password, crypt_salt=None, algorithm='sha512'): -@@ -189,77 +232,107 @@ def gen_password(password, crypt_salt=None, algorithm='sha512'): - return salt.utils.pycrypto.gen_hash(crypt_salt, password, algorithm) - - --def del_password(name): -+def del_password(name, root=None): - ''' - .. versionadded:: 2014.7.0 - - Delete the password from name user - -+ name -+ User to delete -+ -+ root -+ Directory to chroot into -+ - CLI Example: - - .. code-block:: bash - - salt '*' shadow.del_password username - ''' -- cmd = 'passwd -d {0}'.format(name) -+ cmd = ['passwd'] -+ if root is not None: -+ cmd.extend(('-R', root)) -+ cmd.extend(('-d', name)) -+ - __salt__['cmd.run'](cmd, python_shell=False, output_loglevel='quiet') -- uinfo = info(name) -+ uinfo = info(name, root=root) - return not uinfo['passwd'] and uinfo['name'] == name - - --def lock_password(name): -+def lock_password(name, root=None): - ''' - .. versionadded:: 2016.11.0 - - Lock the password from specified user - -+ name -+ User to lock -+ -+ root -+ Directory to chroot into -+ - CLI Example: - - .. code-block:: bash - - salt '*' shadow.lock_password username - ''' -- pre_info = info(name) -- if pre_info['name'] == '': -+ pre_info = info(name, root=root) -+ if not pre_info['name']: - return False -+ - if pre_info['passwd'].startswith('!'): - return True - -- cmd = 'passwd -l {0}'.format(name) -- __salt__['cmd.run'](cmd, python_shell=False) -+ cmd = ['passwd'] - -- post_info = info(name) -+ if root is not None: -+ cmd.extend(('-R', root)) - -- return post_info['passwd'].startswith('!') -+ cmd.extend(('-l', name)) - -+ __salt__['cmd.run'](cmd, python_shell=False) -+ return info(name, root=root)['passwd'].startswith('!') - --def unlock_password(name): -+ -+def unlock_password(name, root=None): - ''' - .. versionadded:: 2016.11.0 - - Unlock the password from name user - -+ name -+ User to unlock -+ -+ root -+ Directory to chroot into -+ - CLI Example: - - .. code-block:: bash - - salt '*' shadow.unlock_password username - ''' -- pre_info = info(name) -- if pre_info['name'] == '': -+ pre_info = info(name, root=root) -+ if not pre_info['name']: - return False -- if pre_info['passwd'][0] != '!': -+ -+ if not pre_info['passwd'].startswith('!'): - return True - -- cmd = 'passwd -u {0}'.format(name) -- __salt__['cmd.run'](cmd, python_shell=False) -+ cmd = ['passwd'] - -- post_info = info(name) -+ if root is not None: -+ cmd.extend(('-R', root)) - -- return post_info['passwd'][0] != '!' -+ cmd.extend(('-u', name)) -+ -+ __salt__['cmd.run'](cmd, python_shell=False) -+ return not info(name, root=root)['passwd'].startswith('!') - - --def set_password(name, password, use_usermod=False): -+def set_password(name, password, use_usermod=False, root=None): - ''' - Set the password for a named user. The password must be a properly defined - hash. The password hash can be generated with this command: -@@ -273,6 +346,18 @@ def set_password(name, password, use_usermod=False): - Keep in mind that the $6 represents a sha512 hash, if your OS is using a - different hashing algorithm this needs to be changed accordingly - -+ name -+ User to set the password -+ -+ password -+ Password already hashed -+ -+ use_usermod -+ Use usermod command to better compatibility -+ -+ root -+ Directory to chroot into -+ - CLI Example: - - .. code-block:: bash -@@ -287,6 +372,9 @@ def set_password(name, password, use_usermod=False): - s_file = '/etc/tcb/{0}/shadow'.format(name) - else: - s_file = '/etc/shadow' -+ if root: -+ s_file = os.path.join(root, os.path.relpath(s_file, os.path.sep)) -+ - ret = {} - if not os.path.isfile(s_file): - return ret -@@ -306,54 +394,67 @@ def set_password(name, password, use_usermod=False): - with salt.utils.files.fopen(s_file, 'w+') as fp_: - lines = [salt.utils.stringutils.to_str(_l) for _l in lines] - fp_.writelines(lines) -- uinfo = info(name) -+ uinfo = info(name, root=root) - return uinfo['passwd'] == password - else: - # Use usermod -p (less secure, but more feature-complete) -- cmd = 'usermod -p {0} {1}'.format(password, name) -+ cmd = ['usermod'] -+ if root is not None: -+ cmd.extend(('-R', root)) -+ cmd.extend(('-p', password, name)) -+ - __salt__['cmd.run'](cmd, python_shell=False, output_loglevel='quiet') -- uinfo = info(name) -+ uinfo = info(name, root=root) - return uinfo['passwd'] == password - - --def set_warndays(name, warndays): -+def set_warndays(name, warndays, root=None): - ''' - Set the number of days of warning before a password change is required. - See man chage. - -+ name -+ User to modify -+ -+ warndays -+ Number of days of warning before a password change is required -+ -+ root -+ Directory to chroot into -+ - CLI Example: - - .. code-block:: bash - - salt '*' shadow.set_warndays username 7 - ''' -- pre_info = info(name) -- if warndays == pre_info['warn']: -- return True -- cmd = 'chage -W {0} {1}'.format(warndays, name) -- __salt__['cmd.run'](cmd, python_shell=False) -- post_info = info(name) -- if post_info['warn'] != pre_info['warn']: -- return post_info['warn'] == warndays -- return False -+ return _set_attrib(name, 'warn', warndays, '-W', root=root) - - --def set_date(name, date): -+def set_date(name, date, root=None): - ''' - Sets the value for the date the password was last changed to days since the - epoch (January 1, 1970). See man chage. - -+ name -+ User to modify -+ -+ date -+ Date the password was last changed -+ -+ root -+ Directory to chroot into -+ - CLI Example: - - .. code-block:: bash - - salt '*' shadow.set_date username 0 - ''' -- cmd = ['chage', '-d', date, name] -- return __salt__['cmd.retcode'](cmd, python_shell=False) == 0 -+ return _set_attrib(name, 'lstchg', date, '-d', root=root, validate=False) - - --def set_expire(name, expire): -+def set_expire(name, expire, root=None): - ''' - .. versionchanged:: 2014.7.0 - -@@ -361,26 +462,77 @@ def set_expire(name, expire): - (January 1, 1970). Using a value of -1 will clear expiration. See man - chage. - -+ name -+ User to modify -+ -+ date -+ Date the account expires -+ -+ root -+ Directory to chroot into -+ - CLI Example: - - .. code-block:: bash - - salt '*' shadow.set_expire username -1 - ''' -- cmd = ['chage', '-E', expire, name] -- return __salt__['cmd.retcode'](cmd, python_shell=False) == 0 -+ return _set_attrib(name, 'expire', expire, '-E', root=root, validate=False) - - --def list_users(): -+def list_users(root=None): - ''' - .. versionadded:: 2018.3.0 - - Return a list of all shadow users - -+ root -+ Directory to chroot into -+ - CLI Example: - - .. code-block:: bash - - salt '*' shadow.list_users - ''' -- return sorted([user.sp_nam for user in spwd.getspall()]) -+ if root is not None: -+ getspall = functools.partial(_getspall, root=root) -+ else: -+ getspall = functools.partial(spwd.getspall) -+ -+ return sorted([user.sp_namp if hasattr(user, 'sp_namp') else user.sp_nam -+ for user in getspall()]) -+ -+ -+def _getspnam(name, root=None): -+ ''' -+ Alternative implementation for getspnam, that use only /etc/shadow -+ ''' -+ root = '/' if not root else root -+ passwd = os.path.join(root, 'etc/shadow') -+ with salt.utils.files.fopen(passwd) as fp_: -+ for line in fp_: -+ line = salt.utils.stringutils.to_unicode(line) -+ comps = line.strip().split(':') -+ if comps[0] == name: -+ # Generate a getspnam compatible output -+ for i in range(2, 9): -+ comps[i] = int(comps[i]) if comps[i] else -1 -+ return spwd.struct_spwd(comps) -+ raise KeyError -+ -+ -+def _getspall(root=None): -+ ''' -+ Alternative implementation for getspnam, that use only /etc/shadow -+ ''' -+ root = '/' if not root else root -+ passwd = os.path.join(root, 'etc/shadow') -+ with salt.utils.files.fopen(passwd) as fp_: -+ for line in fp_: -+ line = salt.utils.stringutils.to_unicode(line) -+ comps = line.strip().split(':') -+ # Generate a getspall compatible output -+ for i in range(2, 9): -+ comps[i] = int(comps[i]) if comps[i] else -1 -+ yield spwd.struct_spwd(comps) diff --git a/salt/modules/solarisipspkg.py b/salt/modules/solarisipspkg.py -index b249bd1b3d..cb6f754a59 100644 +index 3da1dbe5a2..43fd213726 100644 --- a/salt/modules/solarisipspkg.py +++ b/salt/modules/solarisipspkg.py -@@ -109,7 +109,7 @@ def _ips_get_pkgversion(line): +@@ -105,7 +105,7 @@ def _ips_get_pkgversion(line): return line.split()[0].split('@')[1].strip() @@ -4753,7 +2257,7 @@ index b249bd1b3d..cb6f754a59 100644 ''' Updates the remote repos database. -@@ -133,7 +133,7 @@ def refresh_db(full=False): +@@ -129,7 +129,7 @@ def refresh_db(full=False): return __salt__['cmd.retcode']('/bin/pkg refresh') == 0 @@ -4776,620 +2280,10 @@ index 2a828f6e9c..b28349a7d8 100644 Check whether or not an upgrade is available for a given package diff --git a/salt/modules/systemd_service.py b/salt/modules/systemd_service.py -index fb349d30e6..c530d7c3b7 100644 +index 743758bf9c..e39962f9ac 100644 --- a/salt/modules/systemd_service.py +++ b/salt/modules/systemd_service.py -@@ -56,7 +56,7 @@ def __virtual__(): - Only work on systems that have been booted with systemd - ''' - if __grains__['kernel'] == 'Linux' \ -- and salt.utils.systemd.booted(__context__): -+ and salt.utils.systemd.booted(__context__): - return __virtualname__ - return ( - False, -@@ -65,6 +65,16 @@ def __virtual__(): - ) - - -+def _root(path, root): -+ ''' -+ Relocate an absolute path to a new root directory. -+ ''' -+ if root: -+ return os.path.join(root, os.path.relpath(path, os.path.sep)) -+ else: -+ return path -+ -+ - def _canonical_unit_name(name): - ''' - Build a canonical unit name treating unit names without one -@@ -123,15 +133,15 @@ def _check_for_unit_changes(name): - __context__[contextkey] = True - - --def _check_unmask(name, unmask, unmask_runtime): -+def _check_unmask(name, unmask, unmask_runtime, root=None): - ''' - Common code for conditionally removing masks before making changes to a - service's state. - ''' - if unmask: -- unmask_(name, runtime=False) -+ unmask_(name, runtime=False, root=root) - if unmask_runtime: -- unmask_(name, runtime=True) -+ unmask_(name, runtime=True, root=root) - - - def _clear_context(): -@@ -193,15 +203,16 @@ def _default_runlevel(): - return runlevel - - --def _get_systemd_services(): -+def _get_systemd_services(root): - ''' - Use os.listdir() to get all the unit files - ''' - ret = set() - for path in SYSTEM_CONFIG_PATHS + (LOCAL_CONFIG_PATH,): -- # Make sure user has access to the path, and if the path is a link -- # it's likely that another entry in SYSTEM_CONFIG_PATHS or LOCAL_CONFIG_PATH -- # points to it, so we can ignore it. -+ # Make sure user has access to the path, and if the path is a -+ # link it's likely that another entry in SYSTEM_CONFIG_PATHS -+ # or LOCAL_CONFIG_PATH points to it, so we can ignore it. -+ path = _root(path, root) - if os.access(path, os.R_OK) and not os.path.islink(path): - for fullname in os.listdir(path): - try: -@@ -213,19 +224,20 @@ def _get_systemd_services(): - return ret - - --def _get_sysv_services(systemd_services=None): -+def _get_sysv_services(root, systemd_services=None): - ''' - Use os.listdir() and os.access() to get all the initscripts - ''' -+ initscript_path = _root(INITSCRIPT_PATH, root) - try: -- sysv_services = os.listdir(INITSCRIPT_PATH) -+ sysv_services = os.listdir(initscript_path) - except OSError as exc: - if exc.errno == errno.ENOENT: - pass - elif exc.errno == errno.EACCES: - log.error( - 'Unable to check sysvinit scripts, permission denied to %s', -- INITSCRIPT_PATH -+ initscript_path - ) - else: - log.error( -@@ -236,11 +248,11 @@ def _get_sysv_services(systemd_services=None): - return [] - - if systemd_services is None: -- systemd_services = _get_systemd_services() -+ systemd_services = _get_systemd_services(root) - - ret = [] - for sysv_service in sysv_services: -- if os.access(os.path.join(INITSCRIPT_PATH, sysv_service), os.X_OK): -+ if os.access(os.path.join(initscript_path, sysv_service), os.X_OK): - if sysv_service in systemd_services: - log.debug( - 'sysvinit script \'%s\' found, but systemd unit ' -@@ -303,7 +315,8 @@ def _strip_scope(msg): - return '\n'.join(ret).strip() - - --def _systemctl_cmd(action, name=None, systemd_scope=False, no_block=False): -+def _systemctl_cmd(action, name=None, systemd_scope=False, no_block=False, -+ root=None): - ''' - Build a systemctl command line. Treat unit names without one - of the valid suffixes as a service. -@@ -316,6 +329,8 @@ def _systemctl_cmd(action, name=None, systemd_scope=False, no_block=False): - ret.append('systemctl') - if no_block: - ret.append('--no-block') -+ if root: -+ ret.extend(['--root', root]) - if isinstance(action, six.string_types): - action = shlex.split(action) - ret.extend(action) -@@ -343,26 +358,27 @@ def _systemctl_status(name): - return __context__[contextkey] - - --def _sysv_enabled(name): -+def _sysv_enabled(name, root): - ''' - A System-V style service is assumed disabled if the "startup" symlink - (starts with "S") to its script is found in /etc/init.d in the current - runlevel. - ''' - # Find exact match (disambiguate matches like "S01anacron" for cron) -- for match in glob.glob('/etc/rc%s.d/S*%s' % (_runlevel(), name)): -+ rc = _root('/etc/rc{}.d/S*{}'.format(_runlevel(), name), root) -+ for match in glob.glob(rc): - if re.match(r'S\d{,2}%s' % name, os.path.basename(match)): - return True - return False - - --def _untracked_custom_unit_found(name): -+def _untracked_custom_unit_found(name, root=None): - ''' - If the passed service name is not available, but a unit file exist in - /etc/systemd/system, return True. Otherwise, return False. - ''' -- unit_path = os.path.join('/etc/systemd/system', -- _canonical_unit_name(name)) -+ system = _root('/etc/systemd/system', root) -+ unit_path = os.path.join(system, _canonical_unit_name(name)) - return os.access(unit_path, os.R_OK) and not _check_available(name) - - -@@ -371,7 +387,8 @@ def _unit_file_changed(name): - Returns True if systemctl reports that the unit file has changed, otherwise - returns False. - ''' -- return "'systemctl daemon-reload'" in _systemctl_status(name)['stdout'].lower() -+ status = _systemctl_status(name)['stdout'].lower() -+ return "'systemctl daemon-reload'" in status - - - def systemctl_reload(): -@@ -389,8 +406,7 @@ def systemctl_reload(): - out = __salt__['cmd.run_all']( - _systemctl_cmd('--system daemon-reload'), - python_shell=False, -- redirect_stderr=True -- ) -+ redirect_stderr=True) - if out['retcode'] != 0: - raise CommandExecutionError( - 'Problem performing systemctl daemon-reload: %s' % out['stdout'] -@@ -414,8 +430,7 @@ def get_running(): - out = __salt__['cmd.run']( - _systemctl_cmd('--full --no-legend --no-pager'), - python_shell=False, -- ignore_retcode=True, -- ) -+ ignore_retcode=True) - for line in salt.utils.itertools.split(out, '\n'): - try: - comps = line.strip().split() -@@ -438,10 +453,13 @@ def get_running(): - return sorted(ret) - - --def get_enabled(): -+def get_enabled(root=None): - ''' - Return a list of all enabled services - -+ root -+ Enable/disable/mask unit files in the specified root directory -+ - CLI Example: - - .. code-block:: bash -@@ -452,10 +470,10 @@ def get_enabled(): - # Get enabled systemd units. Can't use --state=enabled here because it's - # not present until systemd 216. - out = __salt__['cmd.run']( -- _systemctl_cmd('--full --no-legend --no-pager list-unit-files'), -+ _systemctl_cmd('--full --no-legend --no-pager list-unit-files', -+ root=root), - python_shell=False, -- ignore_retcode=True, -- ) -+ ignore_retcode=True) - for line in salt.utils.itertools.split(out, '\n'): - try: - fullname, unit_state = line.strip().split(None, 1) -@@ -473,15 +491,18 @@ def get_enabled(): - - # Add in any sysvinit services that are enabled - ret.update(set( -- [x for x in _get_sysv_services() if _sysv_enabled(x)] -+ [x for x in _get_sysv_services(root) if _sysv_enabled(x, root)] - )) - return sorted(ret) - - --def get_disabled(): -+def get_disabled(root=None): - ''' - Return a list of all disabled services - -+ root -+ Enable/disable/mask unit files in the specified root directory -+ - CLI Example: - - .. code-block:: bash -@@ -492,10 +513,10 @@ def get_disabled(): - # Get disabled systemd units. Can't use --state=disabled here because it's - # not present until systemd 216. - out = __salt__['cmd.run']( -- _systemctl_cmd('--full --no-legend --no-pager list-unit-files'), -+ _systemctl_cmd('--full --no-legend --no-pager list-unit-files', -+ root=root), - python_shell=False, -- ignore_retcode=True, -- ) -+ ignore_retcode=True) - for line in salt.utils.itertools.split(out, '\n'): - try: - fullname, unit_state = line.strip().split(None, 1) -@@ -513,17 +534,20 @@ def get_disabled(): - - # Add in any sysvinit services that are disabled - ret.update(set( -- [x for x in _get_sysv_services() if not _sysv_enabled(x)] -+ [x for x in _get_sysv_services(root) if not _sysv_enabled(x, root)] - )) - return sorted(ret) - - --def get_static(): -+def get_static(root=None): - ''' - .. versionadded:: 2015.8.5 - - Return a list of all static services - -+ root -+ Enable/disable/mask unit files in the specified root directory -+ - CLI Example: - - .. code-block:: bash -@@ -534,10 +558,10 @@ def get_static(): - # Get static systemd units. Can't use --state=static here because it's - # not present until systemd 216. - out = __salt__['cmd.run']( -- _systemctl_cmd('--full --no-legend --no-pager list-unit-files'), -+ _systemctl_cmd('--full --no-legend --no-pager list-unit-files', -+ root=root), - python_shell=False, -- ignore_retcode=True, -- ) -+ ignore_retcode=True) - for line in salt.utils.itertools.split(out, '\n'): - try: - fullname, unit_state = line.strip().split(None, 1) -@@ -557,18 +581,21 @@ def get_static(): - return sorted(ret) - - --def get_all(): -+def get_all(root=None): - ''' - Return a list of all available services - -+ root -+ Enable/disable/mask unit files in the specified root directory -+ - CLI Example: - - .. code-block:: bash - - salt '*' service.get_all - ''' -- ret = _get_systemd_services() -- ret.update(set(_get_sysv_services(systemd_services=ret))) -+ ret = _get_systemd_services(root) -+ ret.update(set(_get_sysv_services(root, systemd_services=ret))) - return sorted(ret) - - -@@ -606,7 +633,7 @@ def missing(name): - return not available(name) - - --def unmask_(name, runtime=False): -+def unmask_(name, runtime=False, root=None): - ''' - .. versionadded:: 2015.5.0 - .. versionchanged:: 2015.8.12,2016.3.3,2016.11.0 -@@ -633,6 +660,9 @@ def unmask_(name, runtime=False): - removes a runtime mask only when this argument is set to ``True``, - and otherwise removes an indefinite mask. - -+ root -+ Enable/disable/mask unit files in the specified root directory -+ - CLI Example: - - .. code-block:: bash -@@ -641,15 +671,16 @@ def unmask_(name, runtime=False): - salt '*' service.unmask foo runtime=True - ''' - _check_for_unit_changes(name) -- if not masked(name, runtime): -+ if not masked(name, runtime, root=root): - log.debug('Service \'%s\' is not %smasked', - name, 'runtime-' if runtime else '') - return True - - cmd = 'unmask --runtime' if runtime else 'unmask' -- out = __salt__['cmd.run_all'](_systemctl_cmd(cmd, name, systemd_scope=True), -- python_shell=False, -- redirect_stderr=True) -+ out = __salt__['cmd.run_all']( -+ _systemctl_cmd(cmd, name, systemd_scope=True, root=root), -+ python_shell=False, -+ redirect_stderr=True) - - if out['retcode'] != 0: - raise CommandExecutionError('Failed to unmask service \'%s\'' % name) -@@ -657,7 +688,7 @@ def unmask_(name, runtime=False): - return True - - --def mask(name, runtime=False): -+def mask(name, runtime=False, root=None): - ''' - .. versionadded:: 2015.5.0 - .. versionchanged:: 2015.8.12,2016.3.3,2016.11.0 -@@ -678,6 +709,9 @@ def mask(name, runtime=False): - - .. versionadded:: 2015.8.5 - -+ root -+ Enable/disable/mask unit files in the specified root directory -+ - CLI Example: - - .. code-block:: bash -@@ -688,9 +722,10 @@ def mask(name, runtime=False): - _check_for_unit_changes(name) - - cmd = 'mask --runtime' if runtime else 'mask' -- out = __salt__['cmd.run_all'](_systemctl_cmd(cmd, name, systemd_scope=True), -- python_shell=False, -- redirect_stderr=True) -+ out = __salt__['cmd.run_all']( -+ _systemctl_cmd(cmd, name, systemd_scope=True, root=root), -+ python_shell=False, -+ redirect_stderr=True) - - if out['retcode'] != 0: - raise CommandExecutionError( -@@ -701,7 +736,7 @@ def mask(name, runtime=False): - return True - - --def masked(name, runtime=False): -+def masked(name, runtime=False, root=None): - ''' - .. versionadded:: 2015.8.0 - .. versionchanged:: 2015.8.5 -@@ -731,6 +766,9 @@ def masked(name, runtime=False): - only checks for runtime masks if this argument is set to ``True``. - Otherwise, it will check for an indefinite mask. - -+ root -+ Enable/disable/mask unit files in the specified root directory -+ - CLI Examples: - - .. code-block:: bash -@@ -739,7 +777,7 @@ def masked(name, runtime=False): - salt '*' service.masked foo runtime=True - ''' - _check_for_unit_changes(name) -- root_dir = '/run' if runtime else '/etc' -+ root_dir = _root('/run' if runtime else '/etc', root) - link_path = os.path.join(root_dir, - 'systemd', - 'system', -@@ -1055,9 +1093,10 @@ def status(name, sig=None): # pylint: disable=unused-argument - results = {} - for service in services: - _check_for_unit_changes(service) -- results[service] = __salt__['cmd.retcode'](_systemctl_cmd('is-active', service), -- python_shell=False, -- ignore_retcode=True) == 0 -+ results[service] = __salt__['cmd.retcode']( -+ _systemctl_cmd('is-active', service), -+ python_shell=False, -+ ignore_retcode=True) == 0 - if contains_globbing: - return results - return results[name] -@@ -1065,7 +1104,8 @@ def status(name, sig=None): # pylint: disable=unused-argument - - # **kwargs is required to maintain consistency with the API established by - # Salt's service management states. --def enable(name, no_block=False, unmask=False, unmask_runtime=False, **kwargs): # pylint: disable=unused-argument -+def enable(name, no_block=False, unmask=False, unmask_runtime=False, -+ root=None, **kwargs): # pylint: disable=unused-argument - ''' - .. versionchanged:: 2015.8.12,2016.3.3,2016.11.0 - On minions running systemd>=205, `systemd-run(1)`_ is now used to -@@ -1101,6 +1141,9 @@ def enable(name, no_block=False, unmask=False, unmask_runtime=False, **kwargs): - In previous releases, Salt would simply unmask a service before - enabling. This behavior is no longer the default. - -+ root -+ Enable/disable/mask unit files in the specified root directory -+ - CLI Example: - - .. code-block:: bash -@@ -1108,8 +1151,8 @@ def enable(name, no_block=False, unmask=False, unmask_runtime=False, **kwargs): - salt '*' service.enable - ''' - _check_for_unit_changes(name) -- _check_unmask(name, unmask, unmask_runtime) -- if name in _get_sysv_services(): -+ _check_unmask(name, unmask, unmask_runtime, root) -+ if name in _get_sysv_services(root): - cmd = [] - if salt.utils.systemd.has_scope(__context__) \ - and __salt__['config.get']('systemd.scope', True): -@@ -1123,7 +1166,8 @@ def enable(name, no_block=False, unmask=False, unmask_runtime=False, **kwargs): - python_shell=False, - ignore_retcode=True) == 0 - ret = __salt__['cmd.run_all']( -- _systemctl_cmd('enable', name, systemd_scope=True, no_block=no_block), -+ _systemctl_cmd('enable', name, systemd_scope=True, no_block=no_block, -+ root=root), - python_shell=False, - ignore_retcode=True) - -@@ -1137,7 +1181,7 @@ def enable(name, no_block=False, unmask=False, unmask_runtime=False, **kwargs): - - # The unused kwargs argument is required to maintain consistency with the API - # established by Salt's service management states. --def disable(name, no_block=False, **kwargs): # pylint: disable=unused-argument -+def disable(name, no_block=False, root=None, **kwargs): # pylint: disable=unused-argument - ''' - .. versionchanged:: 2015.8.12,2016.3.3,2016.11.0 - On minions running systemd>=205, `systemd-run(1)`_ is now used to -@@ -1157,6 +1201,9 @@ def disable(name, no_block=False, **kwargs): # pylint: disable=unused-argument - - .. versionadded:: 2017.7.0 - -+ root -+ Enable/disable/mask unit files in the specified root directory -+ - CLI Example: - - .. code-block:: bash -@@ -1164,7 +1211,7 @@ def disable(name, no_block=False, **kwargs): # pylint: disable=unused-argument - salt '*' service.disable - ''' - _check_for_unit_changes(name) -- if name in _get_sysv_services(): -+ if name in _get_sysv_services(root): - cmd = [] - if salt.utils.systemd.has_scope(__context__) \ - and __salt__['config.get']('systemd.scope', True): -@@ -1179,17 +1226,21 @@ def disable(name, no_block=False, **kwargs): # pylint: disable=unused-argument - ignore_retcode=True) == 0 - # Using cmd.run_all instead of cmd.retcode here to make unit tests easier - return __salt__['cmd.run_all']( -- _systemctl_cmd('disable', name, systemd_scope=True, no_block=no_block), -+ _systemctl_cmd('disable', name, systemd_scope=True, no_block=no_block, -+ root=root), - python_shell=False, - ignore_retcode=True)['retcode'] == 0 - - - # The unused kwargs argument is required to maintain consistency with the API - # established by Salt's service management states. --def enabled(name, **kwargs): # pylint: disable=unused-argument -+def enabled(name, root=None, **kwargs): # pylint: disable=unused-argument - ''' - Return if the named service is enabled to start on boot - -+ root -+ Enable/disable/mask unit files in the specified root directory -+ - CLI Example: - - .. code-block:: bash -@@ -1199,7 +1250,7 @@ def enabled(name, **kwargs): # pylint: disable=unused-argument - # Try 'systemctl is-enabled' first, then look for a symlink created by - # systemctl (older systemd releases did not support using is-enabled to - # check templated services), and lastly check for a sysvinit service. -- if __salt__['cmd.retcode'](_systemctl_cmd('is-enabled', name), -+ if __salt__['cmd.retcode'](_systemctl_cmd('is-enabled', name, root=root), - python_shell=False, - ignore_retcode=True) == 0: - return True -@@ -1207,43 +1258,50 @@ def enabled(name, **kwargs): # pylint: disable=unused-argument - # On older systemd releases, templated services could not be checked - # with ``systemctl is-enabled``. As a fallback, look for the symlinks - # created by systemctl when enabling templated services. -- cmd = ['find', LOCAL_CONFIG_PATH, '-name', name, -+ local_config_path = _root(LOCAL_CONFIG_PATH, '/') -+ cmd = ['find', local_config_path, '-name', name, - '-type', 'l', '-print', '-quit'] - # If the find command returns any matches, there will be output and the - # string will be non-empty. - if bool(__salt__['cmd.run'](cmd, python_shell=False)): - return True -- elif name in _get_sysv_services(): -- return _sysv_enabled(name) -+ elif name in _get_sysv_services(root): -+ return _sysv_enabled(name, root) - - return False - - --def disabled(name): -+def disabled(name, root=None): - ''' - Return if the named service is disabled from starting on boot - -+ root -+ Enable/disable/mask unit files in the specified root directory -+ - CLI Example: - - .. code-block:: bash - - salt '*' service.disabled - ''' -- return not enabled(name) -+ return not enabled(name, root=root) - - --def show(name): -+def show(name, root=None): - ''' - .. versionadded:: 2014.7.0 - - Show properties of one or more units/jobs or the manager - -+ root -+ Enable/disable/mask unit files in the specified root directory -+ - CLI Example: - - salt '*' service.show - ''' - ret = {} -- out = __salt__['cmd.run'](_systemctl_cmd('show', name), -+ out = __salt__['cmd.run'](_systemctl_cmd('show', name, root=root), - python_shell=False) - for line in salt.utils.itertools.split(out, '\n'): - comps = line.split('=') -@@ -1263,20 +1321,78 @@ def show(name): - return ret - - --def execs(): -+def execs(root=None): - ''' - .. versionadded:: 2014.7.0 - - Return a list of all files specified as ``ExecStart`` for all services. - -+ root -+ Enable/disable/mask unit files in the specified root directory -+ - CLI Example: - - salt '*' service.execs - ''' - ret = {} -- for service in get_all(): -- data = show(service) -+ for service in get_all(root=root): -+ data = show(service, root=root) - if 'ExecStart' not in data: +@@ -1364,3 +1364,58 @@ def execs(root=None): continue ret[service] = data['ExecStart']['path'] return ret @@ -5448,677 +2342,6 @@ index fb349d30e6..c530d7c3b7 100644 + 'systemd-firstboot error: {}'.format(out['stderr'])) + + return True -diff --git a/salt/modules/useradd.py b/salt/modules/useradd.py -index e370dd4bb3..e38a094ed2 100644 ---- a/salt/modules/useradd.py -+++ b/salt/modules/useradd.py -@@ -17,6 +17,8 @@ except ImportError: - HAS_PWD = False - import logging - import copy -+import functools -+import os - - # Import salt libs - import salt.utils.data -@@ -55,12 +57,17 @@ def _quote_username(name): - return salt.utils.stringutils.to_str(name) - - --def _get_gecos(name): -+def _get_gecos(name, root=None): - ''' - Retrieve GECOS field info and return it in dictionary form - ''' -+ if root is not None and __grains__['kernel'] != 'AIX': -+ getpwnam = functools.partial(_getpwnam, root=root) -+ else: -+ getpwnam = functools.partial(pwd.getpwnam) - gecos_field = salt.utils.stringutils.to_unicode( -- pwd.getpwnam(_quote_username(name)).pw_gecos).split(',', 4) -+ getpwnam(_quote_username(name)).pw_gecos).split(',', 4) -+ - if not gecos_field: - return {} - else: -@@ -96,7 +103,7 @@ def _update_gecos(name, key, value, root=None): - value = six.text_type(value) - else: - value = salt.utils.stringutils.to_unicode(value) -- pre_info = _get_gecos(name) -+ pre_info = _get_gecos(name, root=root) - if not pre_info: - return False - if value == pre_info[key]: -@@ -104,14 +111,13 @@ def _update_gecos(name, key, value, root=None): - gecos_data = copy.deepcopy(pre_info) - gecos_data[key] = value - -- cmd = ['usermod', '-c', _build_gecos(gecos_data), name] -- -+ cmd = ['usermod'] - if root is not None and __grains__['kernel'] != 'AIX': - cmd.extend(('-R', root)) -+ cmd.extend(('-c', _build_gecos(gecos_data), name)) - - __salt__['cmd.run'](cmd, python_shell=False) -- post_info = info(name) -- return _get_gecos(name).get(key) == value -+ return _get_gecos(name, root=root).get(key) == value - - - def add(name, -@@ -129,11 +135,62 @@ def add(name, - other='', - createhome=True, - loginclass=None, -- root=None, -- nologinit=False): -+ nologinit=False, -+ root=None): - ''' - Add a user to the minion - -+ name -+ Username LOGIN to add -+ -+ uid -+ User ID of the new account -+ -+ gid -+ Name or ID of the primary group of the new accoun -+ -+ groups -+ List of supplementary groups of the new account -+ -+ home -+ Home directory of the new account -+ -+ shell -+ Login shell of the new account -+ -+ unique -+ Allow to create users with duplicate -+ -+ system -+ Create a system account -+ -+ fullname -+ GECOS field for the full name -+ -+ roomnumber -+ GECOS field for the room number -+ -+ workphone -+ GECOS field for the work phone -+ -+ homephone -+ GECOS field for the home phone -+ -+ other -+ GECOS field for other information -+ -+ createhome -+ Create the user's home directory -+ -+ loginclass -+ Login class for the new account (OpenBSD) -+ -+ nologinit -+ Do not add the user to the lastlog and faillog databases -+ -+ root -+ Directory to chroot into -+ - CLI Example: - - .. code-block:: bash -@@ -231,17 +288,17 @@ def add(name, - # user does exist, and B) running useradd again would result in a - # nonzero exit status and be interpreted as a False result. - if groups: -- chgroups(name, groups) -+ chgroups(name, groups, root=root) - if fullname: -- chfullname(name, fullname) -+ chfullname(name, fullname, root=root) - if roomnumber: -- chroomnumber(name, roomnumber) -+ chroomnumber(name, roomnumber, root=root) - if workphone: -- chworkphone(name, workphone) -+ chworkphone(name, workphone, root=root) - if homephone: -- chhomephone(name, homephone) -+ chhomephone(name, homephone, root=root) - if other: -- chother(name, other) -+ chother(name, other, root=root) - return True - - -@@ -249,6 +306,18 @@ def delete(name, remove=False, force=False, root=None): - ''' - Remove a user from the minion - -+ name -+ Username to delete -+ -+ remove -+ Remove home directory and mail spool -+ -+ force -+ Force some actions that would fail otherwise -+ -+ root -+ Directory to chroot into -+ - CLI Example: - - .. code-block:: bash -@@ -292,10 +361,16 @@ def delete(name, remove=False, force=False, root=None): - return False - - --def getent(refresh=False): -+def getent(refresh=False, root=None): - ''' - Return the list of all info for all users - -+ refresh -+ Force a refresh of user information -+ -+ root -+ Directory to chroot into -+ - CLI Example: - - .. code-block:: bash -@@ -306,72 +381,106 @@ def getent(refresh=False): - return __context__['user.getent'] - - ret = [] -- for data in pwd.getpwall(): -+ if root is not None and __grains__['kernel'] != 'AIX': -+ getpwall = functools.partial(_getpwall, root=root) -+ else: -+ getpwall = functools.partial(pwd.getpwall) -+ -+ for data in getpwall(): - ret.append(_format_info(data)) - __context__['user.getent'] = ret - return ret - - --def chuid(name, uid): -+def _chattrib(name, key, value, param, persist=False, root=None): -+ ''' -+ Change an attribute for a named user -+ ''' -+ pre_info = info(name, root=root) -+ if not pre_info: -+ raise CommandExecutionError('User \'{0}\' does not exist'.format(name)) -+ -+ if value == pre_info[key]: -+ return True -+ -+ cmd = ['usermod'] -+ -+ if root is not None and __grains__['kernel'] != 'AIX': -+ cmd.extend(('-R', root)) -+ -+ if persist and __grains__['kernel'] != 'OpenBSD': -+ cmd.append('-m') -+ -+ cmd.extend((param, value, name)) -+ -+ __salt__['cmd.run'](cmd, python_shell=False) -+ return info(name, root=root).get(key) == value -+ -+ -+def chuid(name, uid, root=None): - ''' - Change the uid for a named user - -+ name -+ User to modify -+ -+ uid -+ New UID for the user account -+ -+ root -+ Directory to chroot into -+ - CLI Example: - - .. code-block:: bash - - salt '*' user.chuid foo 4376 - ''' -- pre_info = info(name) -- if uid == pre_info['uid']: -- return True -- cmd = ['usermod', '-u', uid, name] -- __salt__['cmd.run'](cmd, python_shell=False) -- return info(name).get('uid') == uid -+ return _chattrib(name, 'uid', uid, '-u', root=root) - - - def chgid(name, gid, root=None): - ''' - Change the default group of the user - -+ name -+ User to modify -+ -+ gid -+ Force use GID as new primary group -+ -+ root -+ Directory to chroot into -+ - CLI Example: - - .. code-block:: bash - - salt '*' user.chgid foo 4376 - ''' -- pre_info = info(name) -- if gid == pre_info['gid']: -- return True -- cmd = ['usermod', '-g', gid, name] -- -- if root is not None and __grains__['kernel'] != 'AIX': -- cmd.extend(('-R', root)) -- -- __salt__['cmd.run'](cmd, python_shell=False) -- return info(name).get('gid') == gid -+ return _chattrib(name, 'gid', gid, '-g', root=root) - - - def chshell(name, shell, root=None): - ''' - Change the default shell of the user - -+ name -+ User to modify -+ -+ shell -+ New login shell for the user account -+ -+ root -+ Directory to chroot into -+ - CLI Example: - - .. code-block:: bash - - salt '*' user.chshell foo /bin/zsh - ''' -- pre_info = info(name) -- if shell == pre_info['shell']: -- return True -- cmd = ['usermod', '-s', shell, name] -- -- if root is not None and __grains__['kernel'] != 'AIX': -- cmd.extend(('-R', root)) -- -- __salt__['cmd.run'](cmd, python_shell=False) -- return info(name).get('shell') == shell -+ return _chattrib(name, 'shell', shell, '-s', root=root) - - - def chhome(name, home, persist=False, root=None): -@@ -379,25 +488,25 @@ def chhome(name, home, persist=False, root=None): - Change the home directory of the user, pass True for persist to move files - to the new home directory if the old home directory exist. - -+ name -+ User to modify -+ -+ home -+ New home directory for the user account -+ -+ presist -+ Move contents of the home directory to the new location -+ -+ root -+ Directory to chroot into -+ - CLI Example: - - .. code-block:: bash - - salt '*' user.chhome foo /home/users/foo True - ''' -- pre_info = info(name) -- if home == pre_info['home']: -- return True -- cmd = ['usermod', '-d', home] -- -- if root is not None and __grains__['kernel'] != 'AIX': -- cmd.extend(('-R', root)) -- -- if persist and __grains__['kernel'] != 'OpenBSD': -- cmd.append('-m') -- cmd.append(name) -- __salt__['cmd.run'](cmd, python_shell=False) -- return info(name).get('home') == home -+ return _chattrib(name, 'home', home, '-d', persist=persist, root=root) - - - def chgroups(name, groups, append=False, root=None): -@@ -414,6 +523,9 @@ def chgroups(name, groups, append=False, root=None): - If ``True``, append the specified group(s). Otherwise, this function - will replace the user's groups with the specified group(s). - -+ root -+ Directory to chroot into -+ - CLI Examples: - - .. code-block:: bash -@@ -460,20 +572,29 @@ def chgroups(name, groups, append=False, root=None): - return result['retcode'] == 0 - - --def chfullname(name, fullname): -+def chfullname(name, fullname, root=None): - ''' - Change the user's Full Name - -+ name -+ User to modify -+ -+ fullname -+ GECOS field for the full name -+ -+ root -+ Directory to chroot into -+ - CLI Example: - - .. code-block:: bash - - salt '*' user.chfullname foo "Foo Bar" - ''' -- return _update_gecos(name, 'fullname', fullname) -+ return _update_gecos(name, 'fullname', fullname, root=root) - - --def chroomnumber(name, roomnumber): -+def chroomnumber(name, roomnumber, root=None): - ''' - Change the user's Room Number - -@@ -483,52 +604,88 @@ def chroomnumber(name, roomnumber): - - salt '*' user.chroomnumber foo 123 - ''' -- return _update_gecos(name, 'roomnumber', roomnumber) -+ return _update_gecos(name, 'roomnumber', roomnumber, root=root) - - --def chworkphone(name, workphone): -+def chworkphone(name, workphone, root=None): - ''' - Change the user's Work Phone - -+ name -+ User to modify -+ -+ workphone -+ GECOS field for the work phone -+ -+ root -+ Directory to chroot into -+ - CLI Example: - - .. code-block:: bash - - salt '*' user.chworkphone foo 7735550123 - ''' -- return _update_gecos(name, 'workphone', workphone) -+ return _update_gecos(name, 'workphone', workphone, root=root) - - --def chhomephone(name, homephone): -+def chhomephone(name, homephone, root=None): - ''' - Change the user's Home Phone - -+ name -+ User to modify -+ -+ homephone -+ GECOS field for the home phone -+ -+ root -+ Directory to chroot into -+ - CLI Example: - - .. code-block:: bash - - salt '*' user.chhomephone foo 7735551234 - ''' -- return _update_gecos(name, 'homephone', homephone) -+ return _update_gecos(name, 'homephone', homephone, root=root) - - --def chother(name, other): -+def chother(name, other, root=None): - ''' - Change the user's other GECOS attribute - -+ name -+ User to modify -+ -+ other -+ GECOS field for other information -+ -+ root -+ Directory to chroot into -+ - CLI Example: - - .. code-block:: bash - - salt '*' user.chother foobar - ''' -- return _update_gecos(name, 'other', other) -+ return _update_gecos(name, 'other', other, root=root) - - - def chloginclass(name, loginclass, root=None): - ''' - Change the default login class of the user - -+ name -+ User to modify -+ -+ loginclass -+ Login class for the new account -+ -+ root -+ Directory to chroot into -+ - .. note:: - This function only applies to OpenBSD systems. - -@@ -546,25 +703,43 @@ def chloginclass(name, loginclass, root=None): - - cmd = ['usermod', '-L', loginclass, name] - -- if root is not None: -+ if root is not None and __grains__['kernel'] != 'AIX': - cmd.extend(('-R', root)) - - __salt__['cmd.run'](cmd, python_shell=False) - return get_loginclass(name) == loginclass - - --def info(name): -+def info(name, root=None): - ''' - Return user information - -+ name -+ User to get the information -+ -+ root -+ Directory to chroot into -+ - CLI Example: - - .. code-block:: bash - - salt '*' user.info root - ''' -+ # If root is provided, we use a less portable solution that -+ # depends on analyzing /etc/passwd manually. Of course we cannot -+ # find users from NIS nor LDAP, but in those cases do not makes -+ # sense to provide a root parameter. -+ # -+ # Please, note that if the non-root /etc/passwd file is long the -+ # iteration can be slow. -+ if root is not None and __grains__['kernel'] != 'AIX': -+ getpwnam = functools.partial(_getpwnam, root=root) -+ else: -+ getpwnam = functools.partial(pwd.getpwnam) -+ - try: -- data = pwd.getpwnam(_quote_username(name)) -+ data = getpwnam(_quote_username(name)) - except KeyError: - return {} - else: -@@ -575,6 +750,9 @@ def get_loginclass(name): - ''' - Get the login class of the user - -+ name -+ User to get the information -+ - .. note:: - This function only applies to OpenBSD systems. - -@@ -632,6 +810,9 @@ def primary_group(name): - - .. versionadded:: 2016.3.0 - -+ name -+ User to get the information -+ - CLI Example: - - .. code-block:: bash -@@ -645,6 +826,9 @@ def list_groups(name): - ''' - Return a list of groups the named user belongs to - -+ name -+ User to get the information -+ - CLI Example: - - .. code-block:: bash -@@ -654,43 +838,79 @@ def list_groups(name): - return salt.utils.user.get_group_list(name) - - --def list_users(): -+def list_users(root=None): - ''' - Return a list of all users - -+ root -+ Directory to chroot into -+ - CLI Example: - - .. code-block:: bash - - salt '*' user.list_users - ''' -- return sorted([user.pw_name for user in pwd.getpwall()]) -+ if root is not None and __grains__['kernel'] != 'AIX': -+ getpwall = functools.partial(_getpwall, root=root) -+ else: -+ getpwall = functools.partial(pwd.getpwall) -+ -+ return sorted([user.pw_name for user in getpwall()]) - - - def rename(name, new_name, root=None): - ''' - Change the username for a named user - -+ name -+ User to modify -+ -+ new_name -+ New value of the login name -+ -+ root -+ Directory to chroot into -+ - CLI Example: - - .. code-block:: bash - - salt '*' user.rename name new_name - ''' -- current_info = info(name) -- if not current_info: -- raise CommandExecutionError('User \'{0}\' does not exist'.format(name)) -+ if info(new_name, root=root): -+ raise CommandExecutionError('User \'{0}\' already exists'.format(new_name)) - -- new_info = info(new_name) -- if new_info: -- raise CommandExecutionError( -- 'User \'{0}\' already exists'.format(new_name) -- ) -+ return _chattrib(name, 'name', new_name, '-l', root=root) - -- cmd = ['usermod', '-l', new_name, name] - -- if root is not None and __grains__['kernel'] != 'AIX': -- cmd.extend(('-R', root)) -+def _getpwnam(name, root=None): -+ ''' -+ Alternative implementation for getpwnam, that use only /etc/passwd -+ ''' -+ root = '/' if not root else root -+ passwd = os.path.join(root, 'etc/passwd') -+ with salt.utils.files.fopen(passwd) as fp_: -+ for line in fp_: -+ line = salt.utils.stringutils.to_unicode(line) -+ comps = line.strip().split(':') -+ if comps[0] == name: -+ # Generate a getpwnam compatible output -+ comps[2], comps[3] = int(comps[2]), int(comps[3]) -+ return pwd.struct_passwd(comps) -+ raise KeyError - -- __salt__['cmd.run'](cmd, python_shell=False) -- return info(name).get('name') == new_name -+ -+def _getpwall(root=None): -+ ''' -+ Alternative implemetantion for getpwall, that use only /etc/passwd -+ ''' -+ root = '/' if not root else root -+ passwd = os.path.join(root, 'etc/passwd') -+ with salt.utils.files.fopen(passwd) as fp_: -+ for line in fp_: -+ line = salt.utils.stringutils.to_unicode(line) -+ comps = line.strip().split(':') -+ # Generate a getpwall compatible output -+ comps[2], comps[3] = int(comps[2]), int(comps[3]) -+ yield pwd.struct_passwd(comps) diff --git a/salt/modules/xbpspkg.py b/salt/modules/xbpspkg.py index e493f8c80f..b5d7d8a477 100644 --- a/salt/modules/xbpspkg.py @@ -6178,7 +2401,7 @@ index e493f8c80f..b5d7d8a477 100644 Remove an XBPS repository from the system. diff --git a/salt/modules/yumpkg.py b/salt/modules/yumpkg.py -index 3a4fe47a45..1c5327c700 100644 +index 3ddf989511..88d74020b3 100644 --- a/salt/modules/yumpkg.py +++ b/salt/modules/yumpkg.py @@ -619,7 +619,7 @@ def version(*names, **kwargs): @@ -6274,7 +2497,7 @@ index 3a4fe47a45..1c5327c700 100644 ''' Return a formatted diff between current files and original in a package. NOTE: this function includes all files (configuration and not), but does -@@ -3235,7 +3235,7 @@ def _get_patches(installed_only=False): +@@ -3239,7 +3239,7 @@ def _get_patches(installed_only=False): return patches @@ -6283,7 +2506,7 @@ index 3a4fe47a45..1c5327c700 100644 ''' .. versionadded:: 2017.7.0 -@@ -3258,7 +3258,7 @@ def list_patches(refresh=False): +@@ -3262,7 +3262,7 @@ def list_patches(refresh=False): return _get_patches() @@ -6293,7 +2516,7 @@ index 3a4fe47a45..1c5327c700 100644 .. versionadded:: 2017.7.0 diff --git a/salt/modules/zypperpkg.py b/salt/modules/zypperpkg.py -index 7ac0df26c6..9d0407e674 100644 +index 37428cf67c..582caffb59 100644 --- a/salt/modules/zypperpkg.py +++ b/salt/modules/zypperpkg.py @@ -99,6 +99,7 @@ class _Zypper(object): @@ -6386,16 +2609,7 @@ index 7ac0df26c6..9d0407e674 100644 ret = dict() cmd = ['list-updates'] -@@ -467,7 +481,7 @@ def list_upgrades(refresh=True, **kwargs): - if not isinstance(repo_name, six.string_types): - repo_name = six.text_type(repo_name) - cmd.extend(['--repo', repo_name]) -- for update_node in __zypper__.nolock.xml.call(*cmd).getElementsByTagName('update'): -+ for update_node in __zypper__(root=root).nolock.xml.call(*cmd).getElementsByTagName('update'): - if update_node.getAttribute('kind') == 'package': - ret[update_node.getAttribute('name')] = update_node.getAttribute('edition') - -@@ -504,6 +518,9 @@ def info_installed(*names, **kwargs): +@@ -506,6 +520,9 @@ def info_installed(*names, **kwargs): :param all_versions: Include information for all versions of the packages installed on the minion. @@ -6405,7 +2619,7 @@ index 7ac0df26c6..9d0407e674 100644 CLI example: .. code-block:: bash -@@ -544,6 +561,9 @@ def info_available(*names, **kwargs): +@@ -546,6 +563,9 @@ def info_available(*names, **kwargs): If set to False it depends on zypper if a refresh is executed or not. @@ -6415,7 +2629,7 @@ index 7ac0df26c6..9d0407e674 100644 CLI example: .. code-block:: bash -@@ -558,9 +578,11 @@ def info_available(*names, **kwargs): +@@ -560,9 +580,11 @@ def info_available(*names, **kwargs): else: names = sorted(list(set(names))) @@ -6428,7 +2642,7 @@ index 7ac0df26c6..9d0407e674 100644 pkg_info = [] batch = names[:] -@@ -569,7 +591,8 @@ def info_available(*names, **kwargs): +@@ -571,7 +593,8 @@ def info_available(*names, **kwargs): # Run in batches while batch: pkg_info.extend(re.split(r"Information for package*", @@ -6438,7 +2652,7 @@ index 7ac0df26c6..9d0407e674 100644 batch = batch[batch_size:] for pkg_data in pkg_info: -@@ -629,6 +652,9 @@ def latest_version(*names, **kwargs): +@@ -631,6 +654,9 @@ def latest_version(*names, **kwargs): If set to False it depends on zypper if a refresh is executed or not. @@ -6448,7 +2662,7 @@ index 7ac0df26c6..9d0407e674 100644 CLI example: .. code-block:: bash -@@ -671,6 +697,9 @@ def upgrade_available(name, **kwargs): +@@ -673,6 +699,9 @@ def upgrade_available(name, **kwargs): If set to False it depends on zypper if a refresh is executed or not. @@ -6458,7 +2672,7 @@ index 7ac0df26c6..9d0407e674 100644 CLI Example: .. code-block:: bash -@@ -687,6 +716,9 @@ def version(*names, **kwargs): +@@ -689,6 +718,9 @@ def version(*names, **kwargs): installed. If more than one package name is specified, a dict of name/version pairs is returned. @@ -6468,7 +2682,7 @@ index 7ac0df26c6..9d0407e674 100644 CLI Example: .. code-block:: bash -@@ -697,7 +729,7 @@ def version(*names, **kwargs): +@@ -699,7 +731,7 @@ def version(*names, **kwargs): return __salt__['pkg_resource.version'](*names, **kwargs) or {} @@ -6477,7 +2691,7 @@ index 7ac0df26c6..9d0407e674 100644 ''' .. versionadded:: 2015.5.4 -@@ -719,7 +751,7 @@ def version_cmp(ver1, ver2, ignore_epoch=False): +@@ -721,7 +753,7 @@ def version_cmp(ver1, ver2, ignore_epoch=False): return __salt__['lowpkg.version_cmp'](ver1, ver2, ignore_epoch=ignore_epoch) @@ -6486,7 +2700,7 @@ index 7ac0df26c6..9d0407e674 100644 ''' List the packages currently installed as a dict. By default, the dict contains versions as a comma separated string:: -@@ -731,6 +763,13 @@ def list_pkgs(versions_as_list=False, **kwargs): +@@ -733,6 +765,13 @@ def list_pkgs(versions_as_list=False, **kwargs): {'': ['', '']} @@ -6500,7 +2714,7 @@ index 7ac0df26c6..9d0407e674 100644 attr: If a list of package attributes is specified, returned value will contain them in addition to version, eg.:: -@@ -768,12 +807,18 @@ def list_pkgs(versions_as_list=False, **kwargs): +@@ -770,12 +809,18 @@ def list_pkgs(versions_as_list=False, **kwargs): if attr is not None: attr = salt.utils.args.split_input(attr) @@ -6521,7 +2735,7 @@ index 7ac0df26c6..9d0407e674 100644 output = __salt__['cmd.run'](cmd, python_shell=False, output_loglevel='trace') -@@ -808,6 +853,28 @@ def list_pkgs(versions_as_list=False, **kwargs): +@@ -810,6 +855,28 @@ def list_pkgs(versions_as_list=False, **kwargs): continue _ret[pkgname] = sorted(ret[pkgname], key=lambda d: d['version']) @@ -6550,7 +2764,7 @@ index 7ac0df26c6..9d0407e674 100644 __context__[contextkey] = _ret return __salt__['pkg_resource.format_pkg_list']( -@@ -859,6 +926,9 @@ def list_repo_pkgs(*args, **kwargs): +@@ -861,6 +928,9 @@ def list_repo_pkgs(*args, **kwargs): When ``True``, the return data for each package will be organized by repository. @@ -6560,7 +2774,7 @@ index 7ac0df26c6..9d0407e674 100644 CLI Examples: .. code-block:: bash -@@ -891,7 +961,8 @@ def list_repo_pkgs(*args, **kwargs): +@@ -893,7 +963,8 @@ def list_repo_pkgs(*args, **kwargs): return True return False @@ -6570,7 +2784,7 @@ index 7ac0df26c6..9d0407e674 100644 pkginfo = dict(node.attributes.items()) try: if pkginfo['kind'] != 'package': -@@ -933,23 +1004,27 @@ def list_repo_pkgs(*args, **kwargs): +@@ -935,23 +1006,27 @@ def list_repo_pkgs(*args, **kwargs): return byrepo_ret @@ -6602,7 +2816,7 @@ index 7ac0df26c6..9d0407e674 100644 meta['alias'] = alias for key, val in six.iteritems(meta): if val in ['0', '1']: -@@ -961,51 +1036,60 @@ def _get_repo_info(alias, repos_cfg=None): +@@ -963,51 +1038,60 @@ def _get_repo_info(alias, repos_cfg=None): return {} @@ -6671,7 +2885,7 @@ index 7ac0df26c6..9d0407e674 100644 msg = doc.getElementsByTagName('message') if doc.getElementsByTagName('progress') and msg: return { -@@ -1044,6 +1128,9 @@ def mod_repo(repo, **kwargs): +@@ -1046,6 +1130,9 @@ def mod_repo(repo, **kwargs): If set to True, automatically trust and import public GPG key for the repository. @@ -6681,7 +2895,7 @@ index 7ac0df26c6..9d0407e674 100644 Key/Value pairs may also be removed from a repo's configuration by setting a key to a blank value. Bear in mind that a name cannot be deleted, and a URL can only be deleted if a ``mirrorlist`` is specified (or vice versa). -@@ -1056,7 +1143,8 @@ def mod_repo(repo, **kwargs): +@@ -1058,7 +1145,8 @@ def mod_repo(repo, **kwargs): salt '*' pkg.mod_repo alias url= mirrorlist=http://host.com/ ''' @@ -6691,7 +2905,7 @@ index 7ac0df26c6..9d0407e674 100644 added = False # An attempt to add new one? -@@ -1076,7 +1164,7 @@ def mod_repo(repo, **kwargs): +@@ -1078,7 +1166,7 @@ def mod_repo(repo, **kwargs): # Is there already such repo under different alias? for alias in repos_cfg.sections(): @@ -6700,7 +2914,7 @@ index 7ac0df26c6..9d0407e674 100644 # Complete user URL, in case it is not new_url = _urlparse(url) -@@ -1098,17 +1186,17 @@ def mod_repo(repo, **kwargs): +@@ -1100,17 +1188,17 @@ def mod_repo(repo, **kwargs): ) # Add new repo @@ -6721,7 +2935,7 @@ index 7ac0df26c6..9d0407e674 100644 if ( not added and 'baseurl' in kwargs and not (kwargs['baseurl'] == repo_info['baseurl']) -@@ -1117,8 +1205,8 @@ def mod_repo(repo, **kwargs): +@@ -1119,8 +1207,8 @@ def mod_repo(repo, **kwargs): # we need to remove the repository and add it again with the new baseurl repo_info.update(kwargs) repo_info.setdefault('cache', False) @@ -6732,7 +2946,7 @@ index 7ac0df26c6..9d0407e674 100644 # Modify added or existing repo according to the options cmd_opt = [] -@@ -1151,7 +1239,7 @@ def mod_repo(repo, **kwargs): +@@ -1153,7 +1241,7 @@ def mod_repo(repo, **kwargs): if cmd_opt: cmd_opt = global_cmd_opt + ['mr'] + cmd_opt + [repo] @@ -6741,7 +2955,7 @@ index 7ac0df26c6..9d0407e674 100644 comment = None if call_refresh: -@@ -1159,23 +1247,26 @@ def mod_repo(repo, **kwargs): +@@ -1161,23 +1249,26 @@ def mod_repo(repo, **kwargs): # --gpg-auto-import-keys is not doing anything # so we need to specifically refresh here with --gpg-auto-import-keys refresh_opts = global_cmd_opt + ['refresh'] + [repo] @@ -6771,7 +2985,7 @@ index 7ac0df26c6..9d0407e674 100644 CLI Example: .. code-block:: bash -@@ -1185,7 +1276,7 @@ def refresh_db(): +@@ -1187,7 +1278,7 @@ def refresh_db(): # Remove rtag file to keep multiple refreshes from happening in pkg states salt.utils.pkg.clear_rtag(__opts__) ret = {} @@ -6780,7 +2994,7 @@ index 7ac0df26c6..9d0407e674 100644 for line in out.splitlines(): if not line: -@@ -1204,6 +1295,12 @@ def refresh_db(): +@@ -1206,6 +1297,12 @@ def refresh_db(): return ret @@ -6793,7 +3007,7 @@ index 7ac0df26c6..9d0407e674 100644 def install(name=None, refresh=False, fromrepo=None, -@@ -1213,6 +1310,8 @@ def install(name=None, +@@ -1215,6 +1312,8 @@ def install(name=None, skip_verify=False, version=None, ignore_repo_failure=False, @@ -6802,7 +3016,7 @@ index 7ac0df26c6..9d0407e674 100644 **kwargs): ''' .. versionchanged:: 2015.8.12,2016.3.3,2016.11.0 -@@ -1301,6 +1400,12 @@ def install(name=None, +@@ -1303,6 +1402,12 @@ def install(name=None, Zypper returns error code 106 if one of the repositories are not available for various reasons. In case to set strict check, this parameter needs to be set to True. Default: False. @@ -6815,7 +3029,7 @@ index 7ac0df26c6..9d0407e674 100644 diff_attr: If a list of package attributes is specified, returned value will contain them, eg.:: -@@ -1340,7 +1445,7 @@ def install(name=None, +@@ -1342,7 +1447,7 @@ def install(name=None, 'arch': ''}}} ''' if refresh: @@ -6824,7 +3038,7 @@ index 7ac0df26c6..9d0407e674 100644 try: pkg_params, pkg_type = __salt__['pkg_resource.parse_targets'](name, pkgs, sources, **kwargs) -@@ -1350,7 +1455,7 @@ def install(name=None, +@@ -1352,7 +1457,7 @@ def install(name=None, if pkg_params is None or len(pkg_params) == 0: return {} @@ -6833,7 +3047,7 @@ index 7ac0df26c6..9d0407e674 100644 if version_num: if pkgs is None and sources is None: -@@ -1375,17 +1480,20 @@ def install(name=None, +@@ -1377,17 +1482,20 @@ def install(name=None, targets.append(target) elif pkg_type == 'advisory': targets = [] @@ -6857,7 +3071,7 @@ index 7ac0df26c6..9d0407e674 100644 downgrades = [] if fromrepo: fromrepoopt = ['--force', '--force-resolution', '--from', fromrepo] -@@ -1404,10 +1512,10 @@ def install(name=None, +@@ -1406,10 +1514,10 @@ def install(name=None, cmd_install.append('--download-only') if fromrepo: cmd_install.extend(fromrepoopt) @@ -6870,7 +3084,7 @@ index 7ac0df26c6..9d0407e674 100644 # Split the targets into batches of 500 packages each, so that # the maximal length of the command line is not broken -@@ -1415,7 +1523,7 @@ def install(name=None, +@@ -1417,7 +1525,7 @@ def install(name=None, while targets: cmd = cmd_install + targets[:500] targets = targets[500:] @@ -6879,7 +3093,7 @@ index 7ac0df26c6..9d0407e674 100644 match = re.match(r"^The selected package '([^']+)'.+has lower version", line) if match: downgrades.append(match.group(1)) -@@ -1423,12 +1531,17 @@ def install(name=None, +@@ -1425,12 +1533,17 @@ def install(name=None, while downgrades: cmd = cmd_install + ['--force'] + downgrades[:500] downgrades = downgrades[500:] @@ -6899,7 +3113,7 @@ index 7ac0df26c6..9d0407e674 100644 if errors: raise CommandExecutionError( 'Problem encountered {0} package(s)'.format( -@@ -1446,6 +1559,8 @@ def upgrade(refresh=True, +@@ -1448,6 +1561,8 @@ def upgrade(refresh=True, fromrepo=None, novendorchange=False, skip_verify=False, @@ -6908,7 +3122,7 @@ index 7ac0df26c6..9d0407e674 100644 **kwargs): # pylint: disable=unused-argument ''' .. versionchanged:: 2015.8.12,2016.3.3,2016.11.0 -@@ -1485,6 +1600,12 @@ def upgrade(refresh=True, +@@ -1487,6 +1602,12 @@ def upgrade(refresh=True, skip_verify Skip the GPG verification check (e.g., ``--no-gpg-checks``) @@ -6921,7 +3135,7 @@ index 7ac0df26c6..9d0407e674 100644 Returns a dictionary containing the changes: .. code-block:: python -@@ -1507,7 +1628,7 @@ def upgrade(refresh=True, +@@ -1509,7 +1630,7 @@ def upgrade(refresh=True, cmd_update.insert(0, '--no-gpg-checks') if refresh: @@ -6930,7 +3144,7 @@ index 7ac0df26c6..9d0407e674 100644 if dryrun: cmd_update.append('--dry-run') -@@ -1526,16 +1647,20 @@ def upgrade(refresh=True, +@@ -1530,16 +1651,20 @@ def upgrade(refresh=True, else: log.warning('Disabling vendor changes is not supported on this Zypper version') @@ -6955,7 +3169,7 @@ index 7ac0df26c6..9d0407e674 100644 ret = salt.utils.data.compare_dicts(old, new) if __zypper__.exit_code not in __zypper__.SUCCESS_EXIT_CODES: -@@ -1556,7 +1681,7 @@ def upgrade(refresh=True, +@@ -1560,7 +1685,7 @@ def upgrade(refresh=True, return ret @@ -6964,7 +3178,7 @@ index 7ac0df26c6..9d0407e674 100644 ''' Remove and purge do identical things but with different Zypper commands, this function performs the common logic. -@@ -1566,7 +1691,8 @@ def _uninstall(name=None, pkgs=None): +@@ -1570,7 +1695,8 @@ def _uninstall(name=None, pkgs=None): except MinionError as exc: raise CommandExecutionError(exc) @@ -6974,7 +3188,7 @@ index 7ac0df26c6..9d0407e674 100644 targets = [] for target in pkg_params: # Check if package version set to be removed is actually installed: -@@ -1582,11 +1708,12 @@ def _uninstall(name=None, pkgs=None): +@@ -1586,11 +1712,12 @@ def _uninstall(name=None, pkgs=None): errors = [] while targets: @@ -6989,7 +3203,7 @@ index 7ac0df26c6..9d0407e674 100644 if errors: raise CommandExecutionError( -@@ -1623,7 +1750,7 @@ def normalize_name(name): +@@ -1627,7 +1754,7 @@ def normalize_name(name): return name @@ -6998,7 +3212,7 @@ index 7ac0df26c6..9d0407e674 100644 ''' .. versionchanged:: 2015.8.12,2016.3.3,2016.11.0 On minions running systemd>=205, `systemd-run(1)`_ is now used to -@@ -1651,6 +1778,9 @@ def remove(name=None, pkgs=None, **kwargs): # pylint: disable=unused-argument +@@ -1655,6 +1782,9 @@ def remove(name=None, pkgs=None, **kwargs): # pylint: disable=unused-argument A list of packages to delete. Must be passed as a python list. The ``name`` parameter will be ignored if this option is passed. @@ -7008,7 +3222,7 @@ index 7ac0df26c6..9d0407e674 100644 .. versionadded:: 0.16.0 -@@ -1664,10 +1794,10 @@ def remove(name=None, pkgs=None, **kwargs): # pylint: disable=unused-argument +@@ -1668,10 +1798,10 @@ def remove(name=None, pkgs=None, **kwargs): # pylint: disable=unused-argument salt '*' pkg.remove ,, salt '*' pkg.remove pkgs='["foo", "bar"]' ''' @@ -7021,7 +3235,7 @@ index 7ac0df26c6..9d0407e674 100644 ''' .. versionchanged:: 2015.8.12,2016.3.3,2016.11.0 On minions running systemd>=205, `systemd-run(1)`_ is now used to -@@ -1696,6 +1826,9 @@ def purge(name=None, pkgs=None, **kwargs): # pylint: disable=unused-argument +@@ -1700,6 +1830,9 @@ def purge(name=None, pkgs=None, **kwargs): # pylint: disable=unused-argument A list of packages to delete. Must be passed as a python list. The ``name`` parameter will be ignored if this option is passed. @@ -7031,7 +3245,7 @@ index 7ac0df26c6..9d0407e674 100644 .. versionadded:: 0.16.0 -@@ -1709,13 +1842,16 @@ def purge(name=None, pkgs=None, **kwargs): # pylint: disable=unused-argument +@@ -1713,13 +1846,16 @@ def purge(name=None, pkgs=None, **kwargs): # pylint: disable=unused-argument salt '*' pkg.purge ,, salt '*' pkg.purge pkgs='["foo", "bar"]' ''' @@ -7050,7 +3264,7 @@ index 7ac0df26c6..9d0407e674 100644 Return a dict containing the locked package with attributes:: {'': {'case_sensitive': '', -@@ -1729,8 +1865,9 @@ def list_locks(): +@@ -1733,8 +1869,9 @@ def list_locks(): salt '*' pkg.list_locks ''' locks = {} @@ -7062,7 +3276,7 @@ index 7ac0df26c6..9d0407e674 100644 items = salt.utils.stringutils.to_unicode(fhr.read()).split('\n\n') for meta in [item.split('\n') for item in items]: lock = {} -@@ -1739,15 +1876,22 @@ def list_locks(): +@@ -1743,15 +1880,22 @@ def list_locks(): lock.update(dict([tuple([i.strip() for i in element.split(':', 1)]), ])) if lock.get('solvable_name'): locks[lock.pop('solvable_name')] = lock @@ -7086,7 +3300,7 @@ index 7ac0df26c6..9d0407e674 100644 CLI Example: .. code-block:: bash -@@ -1756,10 +1900,11 @@ def clean_locks(): +@@ -1760,10 +1904,11 @@ def clean_locks(): ''' LCK = "removed" out = {LCK: 0} @@ -7100,7 +3314,7 @@ index 7ac0df26c6..9d0407e674 100644 text = node.childNodes[0].nodeValue.lower() if text.startswith(LCK): out[LCK] = text.split(" ")[1] -@@ -1772,6 +1917,9 @@ def unhold(name=None, pkgs=None, **kwargs): +@@ -1776,6 +1921,9 @@ def unhold(name=None, pkgs=None, **kwargs): ''' Remove specified package lock. @@ -7110,7 +3324,7 @@ index 7ac0df26c6..9d0407e674 100644 CLI Example: .. code-block:: bash -@@ -1781,12 +1929,13 @@ def unhold(name=None, pkgs=None, **kwargs): +@@ -1785,12 +1933,13 @@ def unhold(name=None, pkgs=None, **kwargs): salt '*' pkg.remove_lock pkgs='["foo", "bar"]' ''' ret = {} @@ -7125,7 +3339,7 @@ index 7ac0df26c6..9d0407e674 100644 try: pkgs = list(__salt__['pkg_resource.parse_targets'](pkgs)[0].keys()) except MinionError as exc: -@@ -1803,15 +1952,18 @@ def unhold(name=None, pkgs=None, **kwargs): +@@ -1807,15 +1956,18 @@ def unhold(name=None, pkgs=None, **kwargs): ret[pkg]['comment'] = 'Package {0} unable to be unheld.'.format(pkg) if removed: @@ -7146,7 +3360,7 @@ index 7ac0df26c6..9d0407e674 100644 CLI Example: .. code-block:: bash -@@ -1821,7 +1973,7 @@ def remove_lock(packages, **kwargs): # pylint: disable=unused-argument +@@ -1825,7 +1977,7 @@ def remove_lock(packages, **kwargs): # pylint: disable=unused-argument salt '*' pkg.remove_lock pkgs='["foo", "bar"]' ''' salt.utils.versions.warn_until('Sodium', 'This function is deprecated. Please use unhold() instead.') @@ -7155,7 +3369,7 @@ index 7ac0df26c6..9d0407e674 100644 try: packages = list(__salt__['pkg_resource.parse_targets'](packages)[0].keys()) except MinionError as exc: -@@ -1836,7 +1988,7 @@ def remove_lock(packages, **kwargs): # pylint: disable=unused-argument +@@ -1840,7 +1992,7 @@ def remove_lock(packages, **kwargs): # pylint: disable=unused-argument missing.append(pkg) if removed: @@ -7164,7 +3378,7 @@ index 7ac0df26c6..9d0407e674 100644 return {'removed': len(removed), 'not_found': missing} -@@ -1845,6 +1997,9 @@ def hold(name=None, pkgs=None, **kwargs): +@@ -1849,6 +2001,9 @@ def hold(name=None, pkgs=None, **kwargs): ''' Add a package lock. Specify packages to lock by exact name. @@ -7174,7 +3388,7 @@ index 7ac0df26c6..9d0407e674 100644 CLI Example: .. code-block:: bash -@@ -1859,12 +2014,13 @@ def hold(name=None, pkgs=None, **kwargs): +@@ -1863,12 +2018,13 @@ def hold(name=None, pkgs=None, **kwargs): :return: ''' ret = {} @@ -7189,7 +3403,7 @@ index 7ac0df26c6..9d0407e674 100644 added = [] try: pkgs = list(__salt__['pkg_resource.parse_targets'](pkgs)[0].keys()) -@@ -1880,15 +2036,18 @@ def hold(name=None, pkgs=None, **kwargs): +@@ -1884,15 +2040,18 @@ def hold(name=None, pkgs=None, **kwargs): ret[pkg]['comment'] = 'Package {0} is already set to be held.'.format(pkg) if added: @@ -7210,7 +3424,7 @@ index 7ac0df26c6..9d0407e674 100644 CLI Example: .. code-block:: bash -@@ -1898,7 +2057,7 @@ def add_lock(packages, **kwargs): # pylint: disable=unused-argument +@@ -1902,7 +2061,7 @@ def add_lock(packages, **kwargs): # pylint: disable=unused-argument salt '*' pkg.add_lock pkgs='["foo", "bar"]' ''' salt.utils.versions.warn_until('Sodium', 'This function is deprecated. Please use hold() instead.') @@ -7219,7 +3433,7 @@ index 7ac0df26c6..9d0407e674 100644 added = [] try: packages = list(__salt__['pkg_resource.parse_targets'](packages)[0].keys()) -@@ -1910,7 +2069,7 @@ def add_lock(packages, **kwargs): # pylint: disable=unused-argument +@@ -1914,7 +2073,7 @@ def add_lock(packages, **kwargs): # pylint: disable=unused-argument added.append(pkg) if added: @@ -7228,7 +3442,7 @@ index 7ac0df26c6..9d0407e674 100644 return {'added': len(added), 'packages': added} -@@ -1920,7 +2079,9 @@ def verify(*names, **kwargs): +@@ -1924,7 +2083,9 @@ def verify(*names, **kwargs): Runs an rpm -Va on a system, and returns the results in a dict Files with an attribute of config, doc, ghost, license or readme in the @@ -7239,7 +3453,7 @@ index 7ac0df26c6..9d0407e674 100644 CLI Example: -@@ -1934,12 +2095,14 @@ def verify(*names, **kwargs): +@@ -1938,12 +2099,14 @@ def verify(*names, **kwargs): return __salt__['lowpkg.verify'](*names, **kwargs) @@ -7255,7 +3469,7 @@ index 7ac0df26c6..9d0407e674 100644 CLI Examples: .. code-block:: bash -@@ -1948,15 +2111,17 @@ def file_list(*packages): +@@ -1952,15 +2115,17 @@ def file_list(*packages): salt '*' pkg.file_list httpd postfix salt '*' pkg.file_list ''' @@ -7275,7 +3489,7 @@ index 7ac0df26c6..9d0407e674 100644 CLI Examples: .. code-block:: bash -@@ -1965,7 +2130,7 @@ def file_dict(*packages): +@@ -1969,7 +2134,7 @@ def file_dict(*packages): salt '*' pkg.file_list httpd postfix salt '*' pkg.file_list ''' @@ -7284,7 +3498,7 @@ index 7ac0df26c6..9d0407e674 100644 def modified(*packages, **flags): -@@ -2004,6 +2169,9 @@ def modified(*packages, **flags): +@@ -2008,6 +2173,9 @@ def modified(*packages, **flags): capabilities Include only files where capabilities differ or not. Note: supported only on newer RPM versions. @@ -7294,7 +3508,7 @@ index 7ac0df26c6..9d0407e674 100644 CLI Examples: .. code-block:: bash -@@ -2017,7 +2185,7 @@ def modified(*packages, **flags): +@@ -2021,7 +2189,7 @@ def modified(*packages, **flags): return __salt__['lowpkg.modified'](*packages, **flags) @@ -7303,7 +3517,7 @@ index 7ac0df26c6..9d0407e674 100644 ''' Return the name of the package that owns the file. Multiple file paths can be passed. If a single path is passed, a string will be returned, -@@ -2027,6 +2195,8 @@ def owner(*paths): +@@ -2031,6 +2199,8 @@ def owner(*paths): If the file is not owned by a package, or is not present on the minion, then an empty string will be returned for that path. @@ -7312,7 +3526,7 @@ index 7ac0df26c6..9d0407e674 100644 CLI Examples: .. code-block:: bash -@@ -2034,26 +2204,69 @@ def owner(*paths): +@@ -2038,26 +2208,69 @@ def owner(*paths): salt '*' pkg.owner /usr/bin/apachectl salt '*' pkg.owner /usr/bin/apachectl /etc/httpd/conf/httpd.conf ''' @@ -7393,7 +3607,7 @@ index 7ac0df26c6..9d0407e674 100644 ''' List all known patterns from available repos. -@@ -2062,6 +2275,9 @@ def list_patterns(refresh=False): +@@ -2066,6 +2279,9 @@ def list_patterns(refresh=False): If set to False (default) it depends on zypper if a refresh is executed. @@ -7403,7 +3617,7 @@ index 7ac0df26c6..9d0407e674 100644 CLI Examples: .. code-block:: bash -@@ -2069,27 +2285,30 @@ def list_patterns(refresh=False): +@@ -2073,27 +2289,30 @@ def list_patterns(refresh=False): salt '*' pkg.list_patterns ''' if refresh: @@ -7439,7 +3653,7 @@ index 7ac0df26c6..9d0407e674 100644 refresh force a refresh if set to True. -@@ -2137,6 +2356,9 @@ def search(criteria, refresh=False, **kwargs): +@@ -2141,6 +2360,9 @@ def search(criteria, refresh=False, **kwargs): details (bool) Show version and repository @@ -7449,7 +3663,7 @@ index 7ac0df26c6..9d0407e674 100644 CLI Examples: .. code-block:: bash -@@ -2157,8 +2379,11 @@ def search(criteria, refresh=False, **kwargs): +@@ -2161,8 +2383,11 @@ def search(criteria, refresh=False, **kwargs): 'not_installed_only': '-u', 'details': '--details' } @@ -7462,7 +3676,7 @@ index 7ac0df26c6..9d0407e674 100644 cmd = ['search'] if kwargs.get('match') == 'exact': -@@ -2173,7 +2398,7 @@ def search(criteria, refresh=False, **kwargs): +@@ -2177,7 +2402,7 @@ def search(criteria, refresh=False, **kwargs): cmd.append(ALLOWED_SEARCH_OPTIONS.get(opt)) cmd.append(criteria) @@ -7471,7 +3685,7 @@ index 7ac0df26c6..9d0407e674 100644 if not solvables: raise CommandExecutionError( 'No packages found matching \'{0}\''.format(criteria) -@@ -2202,7 +2427,7 @@ def _get_first_aggregate_text(node_list): +@@ -2206,7 +2431,7 @@ def _get_first_aggregate_text(node_list): return '\n'.join(out) @@ -7480,7 +3694,7 @@ index 7ac0df26c6..9d0407e674 100644 ''' List all available or installed SUSE products. -@@ -2214,6 +2439,9 @@ def list_products(all=False, refresh=False): +@@ -2218,6 +2443,9 @@ def list_products(all=False, refresh=False): If set to False (default) it depends on zypper if a refresh is executed. @@ -7490,7 +3704,7 @@ index 7ac0df26c6..9d0407e674 100644 Includes handling for OEM products, which read the OEM productline file and overwrite the release value. -@@ -2225,10 +2453,12 @@ def list_products(all=False, refresh=False): +@@ -2229,10 +2457,12 @@ def list_products(all=False, refresh=False): salt '*' pkg.list_products all=True ''' if refresh: @@ -7505,7 +3719,7 @@ index 7ac0df26c6..9d0407e674 100644 cmd = list() if not all: cmd.append('--disable-repos') -@@ -2236,7 +2466,7 @@ def list_products(all=False, refresh=False): +@@ -2240,7 +2470,7 @@ def list_products(all=False, refresh=False): if not all: cmd.append('-i') @@ -7514,7 +3728,7 @@ index 7ac0df26c6..9d0407e674 100644 if not product_list: return ret # No products found -@@ -2278,6 +2508,9 @@ def download(*packages, **kwargs): +@@ -2282,6 +2512,9 @@ def download(*packages, **kwargs): If set to False (default) it depends on zypper if a refresh is executed. @@ -7524,7 +3738,7 @@ index 7ac0df26c6..9d0407e674 100644 CLI example: .. code-block:: bash -@@ -2288,12 +2521,14 @@ def download(*packages, **kwargs): +@@ -2292,12 +2525,14 @@ def download(*packages, **kwargs): if not packages: raise SaltInvocationError('No packages specified') @@ -7541,7 +3755,7 @@ index 7ac0df26c6..9d0407e674 100644 repo = dld_result.getElementsByTagName("repository")[0] path = dld_result.getElementsByTagName("localfile")[0].getAttribute("path") pkg_info = { -@@ -2304,7 +2539,7 @@ def download(*packages, **kwargs): +@@ -2308,7 +2543,7 @@ def download(*packages, **kwargs): key = _get_first_aggregate_text( dld_result.getElementsByTagName('name') ) @@ -7550,7 +3764,7 @@ index 7ac0df26c6..9d0407e674 100644 pkg_ret[key] = pkg_info if pkg_ret: -@@ -2318,12 +2553,15 @@ def download(*packages, **kwargs): +@@ -2322,12 +2557,15 @@ def download(*packages, **kwargs): ) @@ -7567,7 +3781,7 @@ index 7ac0df26c6..9d0407e674 100644 CLI example: .. code-block:: bash -@@ -2331,6 +2569,8 @@ def list_downloaded(): +@@ -2335,6 +2573,8 @@ def list_downloaded(): salt '*' pkg.list_downloaded ''' CACHE_DIR = '/var/cache/zypp/packages/' @@ -7576,7 +3790,7 @@ index 7ac0df26c6..9d0407e674 100644 ret = {} for root, dirnames, filenames in salt.utils.path.os_walk(CACHE_DIR): -@@ -2347,12 +2587,14 @@ def list_downloaded(): +@@ -2351,12 +2591,14 @@ def list_downloaded(): return ret @@ -7592,7 +3806,7 @@ index 7ac0df26c6..9d0407e674 100644 :param path: Full path to the installed file :return: Difference string or raises and exception if examined file is binary. -@@ -2366,7 +2608,7 @@ def diff(*paths): +@@ -2370,7 +2612,7 @@ def diff(*paths): pkg_to_paths = {} for pth in paths: @@ -7601,7 +3815,7 @@ index 7ac0df26c6..9d0407e674 100644 if not pth_pkg: ret[pth] = os.path.exists(pth) and 'Not managed' or 'N/A' else: -@@ -2375,7 +2617,7 @@ def diff(*paths): +@@ -2379,7 +2621,7 @@ def diff(*paths): pkg_to_paths[pth_pkg].append(pth) if pkg_to_paths: @@ -7610,7 +3824,7 @@ index 7ac0df26c6..9d0407e674 100644 for pkg, files in six.iteritems(pkg_to_paths): for path in files: ret[path] = __salt__['lowpkg.diff']( -@@ -2386,12 +2628,12 @@ def diff(*paths): +@@ -2390,12 +2632,12 @@ def diff(*paths): return ret @@ -7625,7 +3839,7 @@ index 7ac0df26c6..9d0407e674 100644 installed = element.getAttribute('status') == 'installed' if (installed_only and installed) or not installed_only: patches[element.getAttribute('name')] = { -@@ -2402,7 +2644,7 @@ def _get_patches(installed_only=False): +@@ -2406,7 +2648,7 @@ def _get_patches(installed_only=False): return patches @@ -7634,7 +3848,7 @@ index 7ac0df26c6..9d0407e674 100644 ''' .. versionadded:: 2017.7.0 -@@ -2413,6 +2655,9 @@ def list_patches(refresh=False): +@@ -2417,6 +2659,9 @@ def list_patches(refresh=False): If set to False (default) it depends on zypper if a refresh is executed. @@ -7644,7 +3858,7 @@ index 7ac0df26c6..9d0407e674 100644 CLI Examples: .. code-block:: bash -@@ -2420,33 +2665,39 @@ def list_patches(refresh=False): +@@ -2424,33 +2669,39 @@ def list_patches(refresh=False): salt '*' pkg.list_patches ''' if refresh: @@ -7689,7 +3903,7 @@ index 7ac0df26c6..9d0407e674 100644 CLI Examples: .. code-block:: bash -@@ -2455,7 +2706,10 @@ def list_provides(**kwargs): +@@ -2459,7 +2710,10 @@ def list_provides(**kwargs): ''' ret = __context__.get('pkg.list_provides') if not ret: @@ -7701,7 +3915,7 @@ index 7ac0df26c6..9d0407e674 100644 ret = dict() for line in __salt__['cmd.run'](cmd, output_loglevel='trace', python_shell=False).splitlines(): provide, realname = line.split('_|-') -@@ -2471,7 +2725,7 @@ def list_provides(**kwargs): +@@ -2475,7 +2729,7 @@ def list_provides(**kwargs): return ret @@ -7710,7 +3924,7 @@ index 7ac0df26c6..9d0407e674 100644 ''' .. versionadded:: 2018.3.0 -@@ -2485,6 +2739,9 @@ def resolve_capabilities(pkgs, refresh, **kwargs): +@@ -2489,6 +2743,9 @@ def resolve_capabilities(pkgs, refresh, **kwargs): If set to False (default) it depends on zypper if a refresh is executed. @@ -7720,7 +3934,7 @@ index 7ac0df26c6..9d0407e674 100644 resolve_capabilities If this option is set to True the input will be checked if a package with this name exists. If not, this function will -@@ -2500,7 +2757,7 @@ def resolve_capabilities(pkgs, refresh, **kwargs): +@@ -2504,7 +2761,7 @@ def resolve_capabilities(pkgs, refresh, **kwargs): salt '*' pkg.resolve_capabilities resolve_capabilities=True w3m_ssl ''' if refresh: @@ -7729,7 +3943,7 @@ index 7ac0df26c6..9d0407e674 100644 ret = list() for pkg in pkgs: -@@ -2513,12 +2770,12 @@ def resolve_capabilities(pkgs, refresh, **kwargs): +@@ -2517,12 +2774,12 @@ def resolve_capabilities(pkgs, refresh, **kwargs): if kwargs.get('resolve_capabilities', False): try: @@ -7744,18 +3958,6 @@ index 7ac0df26c6..9d0407e674 100644 if len(result) == 1: name = next(iter(result.keys())) elif len(result) > 1: -diff --git a/salt/states/blockdev.py b/salt/states/blockdev.py -index 38543ac8a0..2db5d805c3 100644 ---- a/salt/states/blockdev.py -+++ b/salt/states/blockdev.py -@@ -193,5 +193,6 @@ def _checkblk(name): - Check if the blk exists and return its fstype if ok - ''' - -- blk = __salt__['cmd.run']('blkid -o value -s TYPE {0}'.format(name)) -+ blk = __salt__['cmd.run']('blkid -o value -s TYPE {0}'.format(name), -+ ignore_retcode=True) - return '' if not blk else blk diff --git a/salt/states/btrfs.py b/salt/states/btrfs.py new file mode 100644 index 0000000000..af78c8ae00 @@ -8147,73 +4349,8 @@ index 0000000000..af78c8ae00 + + ret['result'] = True + return ret -diff --git a/salt/states/cmd.py b/salt/states/cmd.py -index 4d20b51381..86934f9ffc 100644 ---- a/salt/states/cmd.py -+++ b/salt/states/cmd.py -@@ -402,6 +402,7 @@ def wait(name, - unless=None, - creates=None, - cwd=None, -+ root=None, - runas=None, - shell=None, - env=(), -@@ -436,6 +437,10 @@ def wait(name, - The current working directory to execute the command in, defaults to - /root - -+ root -+ Path to the root of the jail to use. If this parameter is set, the command -+ will run inside a chroot -+ - runas - The user name to run the command as - -@@ -674,6 +679,7 @@ def run(name, - unless=None, - creates=None, - cwd=None, -+ root=None, - runas=None, - shell=None, - env=None, -@@ -707,6 +713,10 @@ def run(name, - The current working directory to execute the command in, defaults to - /root - -+ root -+ Path to the root of the jail to use. If this parameter is set, the command -+ will run inside a chroot -+ - runas - The user name to run the command as - -@@ -882,6 +892,7 @@ def run(name, - - cmd_kwargs = copy.deepcopy(kwargs) - cmd_kwargs.update({'cwd': cwd, -+ 'root': root, - 'runas': runas, - 'use_vt': use_vt, - 'shell': shell or __grains__['shell'], -@@ -912,10 +923,11 @@ def run(name, - - # Wow, we passed the test, run this sucker! - try: -- cmd_all = __salt__['cmd.run_all']( -- name, timeout=timeout, python_shell=True, **cmd_kwargs -+ run_cmd = 'cmd.run_all' if not root else 'cmd.run_chroot' -+ cmd_all = __salt__[run_cmd]( -+ cmd=name, timeout=timeout, python_shell=True, **cmd_kwargs - ) -- except CommandExecutionError as err: -+ except Exception as err: - ret['comment'] = six.text_type(err) - return ret - diff --git a/salt/states/file.py b/salt/states/file.py -index 4e451c58f8..c98081fa7f 100644 +index dd5bcec62a..0e925bb2ed 100644 --- a/salt/states/file.py +++ b/salt/states/file.py @@ -291,7 +291,11 @@ import shutil @@ -8230,427 +4367,25 @@ index 4e451c58f8..c98081fa7f 100644 # Import salt libs diff --git a/salt/states/loop.py b/salt/states/loop.py -index edaf8c3063..db4971ceb0 100644 +index 524fa56c1a..726c8c8016 100644 --- a/salt/states/loop.py +++ b/salt/states/loop.py -@@ -94,6 +94,10 @@ def until(name, - ret['comment'] = 'The execution module {0} will be run'.format(name) - ret['result'] = None +@@ -185,6 +185,10 @@ def until_no_eval( + ''.format(name, expected)) + if ret['comment']: return ret + if not m_args: + m_args = [] + if not m_kwargs: + m_kwargs = {} - def timed_out(): - if time.time() >= timeout: -diff --git a/salt/states/lvm.py b/salt/states/lvm.py -index bc937a33ab..5cb15d0ed6 100644 ---- a/salt/states/lvm.py -+++ b/salt/states/lvm.py -@@ -56,7 +56,7 @@ def pv_present(name, **kwargs): - 'name': name, - 'result': True} - -- if __salt__['lvm.pvdisplay'](name): -+ if __salt__['lvm.pvdisplay'](name, quiet=True): - ret['comment'] = 'Physical Volume {0} already present'.format(name) - elif __opts__['test']: - ret['comment'] = 'Physical Volume {0} is set to be created'.format(name) -@@ -86,7 +86,7 @@ def pv_absent(name): - 'name': name, - 'result': True} - -- if not __salt__['lvm.pvdisplay'](name): -+ if not __salt__['lvm.pvdisplay'](name, quiet=True): - ret['comment'] = 'Physical Volume {0} does not exist'.format(name) - elif __opts__['test']: - ret['comment'] = 'Physical Volume {0} is set to be removed'.format(name) -@@ -95,7 +95,7 @@ def pv_absent(name): - else: - changes = __salt__['lvm.pvremove'](name) - -- if __salt__['lvm.pvdisplay'](name): -+ if __salt__['lvm.pvdisplay'](name, quiet=True): - ret['comment'] = 'Failed to remove Physical Volume {0}'.format(name) - ret['result'] = False - else: -@@ -125,7 +125,7 @@ def vg_present(name, devices=None, **kwargs): - if isinstance(devices, six.string_types): - devices = devices.split(',') - -- if __salt__['lvm.vgdisplay'](name): -+ if __salt__['lvm.vgdisplay'](name, quiet=True): - ret['comment'] = 'Volume Group {0} already present'.format(name) - for device in devices: - realdev = os.path.realpath(device) -@@ -185,7 +185,7 @@ def vg_absent(name): - 'name': name, - 'result': True} - -- if not __salt__['lvm.vgdisplay'](name): -+ if not __salt__['lvm.vgdisplay'](name, quiet=True): - ret['comment'] = 'Volume Group {0} already absent'.format(name) - elif __opts__['test']: - ret['comment'] = 'Volume Group {0} is set to be removed'.format(name) -@@ -194,7 +194,7 @@ def vg_absent(name): - else: - changes = __salt__['lvm.vgremove'](name) - -- if not __salt__['lvm.vgdisplay'](name): -+ if not __salt__['lvm.vgdisplay'](name, quiet=True): - ret['comment'] = 'Removed Volume Group {0}'.format(name) - ret['changes']['removed'] = changes - else: -@@ -311,7 +311,7 @@ def lv_absent(name, vgname=None): - 'result': True} - - lvpath = '/dev/{0}/{1}'.format(vgname, name) -- if not __salt__['lvm.lvdisplay'](lvpath): -+ if not __salt__['lvm.lvdisplay'](lvpath, quiet=True): - ret['comment'] = 'Logical Volume {0} already absent'.format(name) - elif __opts__['test']: - ret['comment'] = 'Logical Volume {0} is set to be removed'.format(name) -@@ -320,7 +320,7 @@ def lv_absent(name, vgname=None): - else: - changes = __salt__['lvm.lvremove'](name, vgname) - -- if not __salt__['lvm.lvdisplay'](lvpath): -+ if not __salt__['lvm.lvdisplay'](lvpath, quiet=True): - ret['comment'] = 'Removed Logical Volume {0}'.format(name) - ret['changes']['removed'] = changes - else: -diff --git a/salt/states/mdadm_raid.py b/salt/states/mdadm_raid.py -index fd285b6ace..d634522c33 100644 ---- a/salt/states/mdadm_raid.py -+++ b/salt/states/mdadm_raid.py -@@ -98,7 +98,7 @@ def present(name, - if dev == 'missing' or not __salt__['file.access'](dev, 'f'): - missing.append(dev) - continue -- superblock = __salt__['raid.examine'](dev) -+ superblock = __salt__['raid.examine'](dev, quiet=True) - - if 'MD_UUID' in superblock: - uuid = superblock['MD_UUID'] -diff --git a/salt/states/mount.py b/salt/states/mount.py -index 162da1ca62..0802bf4388 100644 ---- a/salt/states/mount.py -+++ b/salt/states/mount.py -@@ -956,3 +956,308 @@ def mod_watch(name, user=None, **kwargs): - else: - ret['comment'] = 'Watch not supported in {0} at this time'.format(kwargs['sfun']) - return ret -+ -+ -+def _convert_to(maybe_device, convert_to): -+ ''' -+ Convert a device name, UUID or LABEL to a device name, UUID or -+ LABEL. -+ -+ Return the fs_spec required for fstab. -+ -+ ''' -+ -+ # Fast path. If we already have the information required, we can -+ # save one blkid call -+ if not convert_to or \ -+ (convert_to == 'device' and maybe_device.startswith('/')) or \ -+ maybe_device.startswith('{}='.format(convert_to.upper())): -+ return maybe_device -+ -+ # Get the device information -+ if maybe_device.startswith('/'): -+ blkid = __salt__['disk.blkid'](maybe_device) -+ else: -+ blkid = __salt__['disk.blkid'](token=maybe_device) -+ -+ result = None -+ if len(blkid) == 1: -+ if convert_to == 'device': -+ result = list(blkid.keys())[0] -+ else: -+ key = convert_to.upper() -+ result = '{}={}'.format(key, list(blkid.values())[0][key]) -+ -+ return result -+ -+ -+def fstab_present(name, fs_file, fs_vfstype, fs_mntops='defaults', -+ fs_freq=0, fs_passno=0, mount_by=None, -+ config='/etc/fstab', mount=True, match_on='auto', -+ not_change=False): -+ '''Makes sure that a fstab mount point is pressent. -+ -+ name -+ The name of block device. Can be any valid fs_spec value. -+ -+ fs_file -+ Mount point (target) for the filesystem. -+ -+ fs_vfstype -+ The type of the filesystem (e.g. ext4, xfs, btrfs, ...) -+ -+ fs_mntops -+ The mount options associated with the filesystem. Default is -+ ``defaults``. -+ -+ fs_freq -+ Field is used by dump to determine which fs need to be -+ dumped. Default is ``0`` -+ -+ fs_passno -+ Field is used by fsck to determine the order in which -+ filesystem checks are done at boot time. Default is ``0`` -+ -+ mount_by -+ Select the final value for fs_spec. Can be [``None``, -+ ``device``, ``label``, ``uuid``, ``partlabel``, -+ ``partuuid``]. If ``None``, the value for fs_spect will be the -+ parameter ``name``, in other case will search the correct -+ value based on the device name. For example, for ``uuid``, the -+ value for fs_spec will be of type 'UUID=xxx' instead of the -+ device name set in ``name``. -+ -+ config -+ Place where the fstab file lives. Default is ``/etc/fstab`` -+ -+ mount -+ Set if the mount should be mounted immediately. Default is -+ ``True`` -+ -+ match_on -+ A name or list of fstab properties on which this state should -+ be applied. Default is ``auto``, a special value indicating -+ to guess based on fstype. In general, ``auto`` matches on -+ name for recognized special devices and device otherwise. -+ -+ not_change -+ By default, if the entry is found in the fstab file but is -+ different from the expected content (like different options), -+ the entry will be replaced with the correct content. If this -+ parameter is set to ``True`` and the line is found, the -+ original content will be preserved. -+ -+ ''' -+ ret = { -+ 'name': name, -+ 'result': False, -+ 'changes': {}, -+ 'comment': [], -+ } -+ -+ # Adjust fs_mntops based on the OS -+ if fs_mntops == 'defaults': -+ if __grains__['os'] in ['MacOS', 'Darwin']: -+ fs_mntops = 'noowners' -+ elif __grains__['os'] == 'AIX': -+ fs_mntops = '' -+ -+ # Adjust the config file based on the OS -+ if config == '/etc/fstab': -+ if __grains__['os'] in ['MacOS', 'Darwin']: -+ config = '/etc/auto_salt' -+ elif __grains__['os'] == 'AIX': -+ config = '/etc/filesystems' -+ -+ if not fs_file == '/': -+ fs_file = fs_file.rstrip('/') -+ -+ fs_spec = _convert_to(name, mount_by) -+ -+ # Validate that the device is valid after the conversion -+ if not fs_spec: -+ msg = 'Device {} cannot be converted to {}' -+ ret['comment'].append(msg.format(name, mount_by)) -+ return ret -+ -+ if __opts__['test']: -+ if __grains__['os'] in ['MacOS', 'Darwin']: -+ out = __salt__['mount.set_automaster'](name=fs_file, -+ device=fs_spec, -+ fstype=fs_vfstype, -+ opts=fs_mntops, -+ config=config, -+ test=True, -+ not_change=not_change) -+ elif __grains__['os'] == 'AIX': -+ out = __salt__['mount.set_filesystems'](name=fs_file, -+ device=fs_spec, -+ fstype=fs_vfstype, -+ opts=fs_mntops, -+ mount=mount, -+ config=config, -+ test=True, -+ match_on=match_on, -+ not_change=not_change) -+ else: -+ out = __salt__['mount.set_fstab'](name=fs_file, -+ device=fs_spec, -+ fstype=fs_vfstype, -+ opts=fs_mntops, -+ dump=fs_freq, -+ pass_num=fs_passno, -+ config=config, -+ test=True, -+ match_on=match_on, -+ not_change=not_change) -+ ret['result'] = None -+ if out == 'present': -+ msg = '{} entry is already in {}.' -+ ret['comment'].append(msg.format(fs_file, config)) -+ elif out == 'new': -+ msg = '{} entry will be written in {}.' -+ ret['comment'].append(msg.format(fs_file, config)) -+ elif out == 'change': -+ msg = '{} entry will be updated in {}.' -+ ret['comment'].append(msg.format(fs_file, config)) -+ else: -+ ret['result'] = False -+ msg = '{} entry cannot be created in {}: {}.' -+ ret['comment'].append(msg.format(fs_file, config, out)) -+ return ret -+ -+ if __grains__['os'] in ['MacOS', 'Darwin']: -+ out = __salt__['mount.set_automaster'](name=fs_file, -+ device=fs_spec, -+ fstype=fs_vfstype, -+ opts=fs_mntops, -+ config=config, -+ not_change=not_change) -+ elif __grains__['os'] == 'AIX': -+ out = __salt__['mount.set_filesystems'](name=fs_file, -+ device=fs_spec, -+ fstype=fs_vfstype, -+ opts=fs_mntops, -+ mount=mount, -+ config=config, -+ match_on=match_on, -+ not_change=not_change) -+ else: -+ out = __salt__['mount.set_fstab'](name=fs_file, -+ device=fs_spec, -+ fstype=fs_vfstype, -+ opts=fs_mntops, -+ dump=fs_freq, -+ pass_num=fs_passno, -+ config=config, -+ match_on=match_on, -+ not_change=not_change) -+ -+ ret['result'] = True -+ if out == 'present': -+ msg = '{} entry was already in {}.' -+ ret['comment'].append(msg.format(fs_file, config)) -+ elif out == 'new': -+ ret['changes']['persist'] = out -+ msg = '{} entry added in {}.' -+ ret['comment'].append(msg.format(fs_file, config)) -+ elif out == 'change': -+ ret['changes']['persist'] = out -+ msg = '{} entry updated in {}.' -+ ret['comment'].append(msg.format(fs_file, config)) -+ else: -+ ret['result'] = False -+ msg = '{} entry cannot be changed in {}: {}.' -+ ret['comment'].append(msg.format(fs_file, config, out)) -+ -+ return ret -+ -+ -+def fstab_absent(name, fs_file, mount_by=None, config='/etc/fstab'): -+ ''' -+ Makes sure that a fstab mount point is absent. -+ -+ name -+ The name of block device. Can be any valid fs_spec value. -+ -+ fs_file -+ Mount point (target) for the filesystem. -+ -+ mount_by -+ Select the final value for fs_spec. Can be [``None``, -+ ``device``, ``label``, ``uuid``, ``partlabel``, -+ ``partuuid``]. If ``None``, the value for fs_spect will be the -+ parameter ``name``, in other case will search the correct -+ value based on the device name. For example, for ``uuid``, the -+ value for fs_spec will be of type 'UUID=xxx' instead of the -+ device name set in ``name``. -+ -+ config -+ Place where the fstab file lives -+ -+ ''' -+ ret = { -+ 'name': name, -+ 'result': False, -+ 'changes': {}, -+ 'comment': [], -+ } -+ -+ # Adjust the config file based on the OS -+ if config == '/etc/fstab': -+ if __grains__['os'] in ['MacOS', 'Darwin']: -+ config = '/etc/auto_salt' -+ elif __grains__['os'] == 'AIX': -+ config = '/etc/filesystems' -+ -+ if not fs_file == '/': -+ fs_file = fs_file.rstrip('/') -+ -+ fs_spec = _convert_to(name, mount_by) -+ -+ if __grains__['os'] in ['MacOS', 'Darwin']: -+ fstab_data = __salt__['mount.automaster'](config) -+ elif __grains__['os'] == 'AIX': -+ fstab_data = __salt__['mount.filesystems'](config) -+ else: -+ fstab_data = __salt__['mount.fstab'](config) -+ -+ if __opts__['test']: -+ ret['result'] = None -+ if fs_file not in fstab_data: -+ msg = '{} entry is already missing in {}.' -+ ret['comment'].append(msg.format(fs_file, config)) -+ else: -+ msg = '{} entry will be removed from {}.' -+ ret['comment'].append(msg.format(fs_file, config)) -+ return ret -+ -+ if fs_file in fstab_data: -+ if __grains__['os'] in ['MacOS', 'Darwin']: -+ out = __salt__['mount.rm_automaster'](name=fs_file, -+ device=fs_spec, -+ config=config) -+ elif __grains__['os'] == 'AIX': -+ out = __salt__['mount.rm_filesystems'](name=fs_file, -+ device=fs_spec, -+ config=config) -+ else: -+ out = __salt__['mount.rm_fstab'](name=fs_file, -+ device=fs_spec, -+ config=config) -+ -+ if out is not True: -+ ret['result'] = False -+ msg = '{} entry failed when removing from {}.' -+ ret['comment'].append(msg.format(fs_file, config)) -+ else: -+ ret['result'] = True -+ ret['changes']['persist'] = 'removed' -+ msg = '{} entry removed from {}.' -+ ret['comment'].append(msg.format(fs_file, config)) -+ else: -+ ret['result'] = True -+ msg = '{} entry is already missing in {}.' -+ ret['comment'].append(msg.format(fs_file, config)) -+ -+ return ret + if init_wait: + time.sleep(init_wait) diff --git a/salt/states/pkg.py b/salt/states/pkg.py -index 0aca1e0af8..22a97fe98c 100644 +index a13d418400..71ba29a27c 100644 --- a/salt/states/pkg.py +++ b/salt/states/pkg.py -@@ -241,7 +241,7 @@ def _fulfills_version_spec(versions, oper, desired_version, +@@ -236,7 +236,7 @@ def _fulfills_version_spec(versions, oper, desired_version, return False @@ -8659,7 +4394,7 @@ index 0aca1e0af8..22a97fe98c 100644 ''' Find packages which are marked to be purged but can't yet be removed because they are dependencies for other installed packages. These are the -@@ -250,7 +250,7 @@ def _find_unpurge_targets(desired): +@@ -245,7 +245,7 @@ def _find_unpurge_targets(desired): ''' return [ x for x in desired @@ -8668,16 +4403,16 @@ index 0aca1e0af8..22a97fe98c 100644 ] -@@ -265,7 +265,7 @@ def _find_download_targets(name=None, +@@ -260,7 +260,7 @@ def _find_download_targets(name=None, Inspect the arguments to pkg.downloaded and discover what packages need to be downloaded. Return a dict of packages to download. ''' - cur_pkgs = __salt__['pkg.list_downloaded']() + cur_pkgs = __salt__['pkg.list_downloaded'](**kwargs) if pkgs: - to_download = _repack_pkgs(pkgs, normalize=normalize) + to_download = _repack_pkgs(pkgs, normalize=normalize) # pylint: disable=not-callable -@@ -383,7 +383,7 @@ def _find_advisory_targets(name=None, +@@ -378,7 +378,7 @@ def _find_advisory_targets(name=None, Inspect the arguments to pkg.patch_installed and discover what advisory patches need to be installed. Return a dict of advisory patches to install. ''' @@ -8686,7 +4421,7 @@ index 0aca1e0af8..22a97fe98c 100644 if advisory_ids: to_download = advisory_ids else: -@@ -587,7 +587,7 @@ def _find_install_targets(name=None, +@@ -582,7 +582,7 @@ def _find_install_targets(name=None, 'minion log.'.format('pkgs' if pkgs else 'sources')} @@ -8694,8 +4429,8 @@ index 0aca1e0af8..22a97fe98c 100644 + to_unpurge = _find_unpurge_targets(desired, **kwargs) else: if salt.utils.platform.is_windows(): - pkginfo = _get_package_info(name, saltenv=kwargs['saltenv']) -@@ -607,7 +607,7 @@ def _find_install_targets(name=None, + pkginfo = _get_package_info(name, saltenv=kwargs['saltenv']) # pylint: disable=not-callable +@@ -602,7 +602,7 @@ def _find_install_targets(name=None, else: desired = {name: version} @@ -8704,7 +4439,7 @@ index 0aca1e0af8..22a97fe98c 100644 # FreeBSD pkg supports `openjdk` and `java/openjdk7` package names origin = bool(re.search('/', name)) -@@ -766,7 +766,8 @@ def _find_install_targets(name=None, +@@ -761,7 +761,8 @@ def _find_install_targets(name=None, verify_result = __salt__['pkg.verify']( package_name, ignore_types=ignore_types, @@ -8714,7 +4449,7 @@ index 0aca1e0af8..22a97fe98c 100644 ) except (CommandExecutionError, SaltInvocationError) as exc: failed_verify = exc.strerror -@@ -795,7 +796,9 @@ def _find_install_targets(name=None, +@@ -790,7 +791,9 @@ def _find_install_targets(name=None, verify_result = __salt__['pkg.verify']( package_name, ignore_types=ignore_types, @@ -8725,7 +4460,7 @@ index 0aca1e0af8..22a97fe98c 100644 except (CommandExecutionError, SaltInvocationError) as exc: failed_verify = exc.strerror continue -@@ -1910,7 +1913,8 @@ def installed( +@@ -1974,7 +1977,8 @@ def installed( # have caught invalid arguments earlier. verify_result = __salt__['pkg.verify'](reinstall_pkg, ignore_types=ignore_types, @@ -8735,16 +4470,7 @@ index 0aca1e0af8..22a97fe98c 100644 if verify_result: failed.append(reinstall_pkg) altered_files[reinstall_pkg] = verify_result -@@ -2098,7 +2102,7 @@ def downloaded(name, - 'package(s): {0}'.format(exc) - return ret - -- new_pkgs = __salt__['pkg.list_downloaded']() -+ new_pkgs = __salt__['pkg.list_downloaded'](**kwargs) - ok, failed = _verify_install(targets, new_pkgs, ignore_epoch=ignore_epoch) - - if failed: -@@ -2974,7 +2978,7 @@ def uptodate(name, refresh=False, pkgs=None, **kwargs): +@@ -3038,7 +3042,7 @@ def uptodate(name, refresh=False, pkgs=None, **kwargs): pkgs, refresh = _resolve_capabilities(pkgs, refresh=refresh, **kwargs) try: packages = __salt__['pkg.list_upgrades'](refresh=refresh, **kwargs) @@ -8753,7 +4479,7 @@ index 0aca1e0af8..22a97fe98c 100644 for pkgname, pkgver in six.iteritems(packages)} if isinstance(pkgs, list): packages = [pkg for pkg in packages if pkg in pkgs] -@@ -3156,7 +3160,7 @@ def group_installed(name, skip=None, include=None, **kwargs): +@@ -3220,7 +3224,7 @@ def group_installed(name, skip=None, include=None, **kwargs): .format(name, exc)) return ret @@ -8763,10 +4489,10 @@ index 0aca1e0af8..22a97fe98c 100644 ret['comment'] = ( 'Failed to install the following packages: {0}' diff --git a/salt/states/pkgrepo.py b/salt/states/pkgrepo.py -index 4d5e9eea92..6d8e94aa18 100644 +index f1ae3a0f6f..c39e857580 100644 --- a/salt/states/pkgrepo.py +++ b/salt/states/pkgrepo.py -@@ -393,10 +393,7 @@ def managed(name, ppa=None, **kwargs): +@@ -385,10 +385,7 @@ def managed(name, ppa=None, **kwargs): kwargs.pop(kwarg, None) try: @@ -8778,7 +4504,7 @@ index 4d5e9eea92..6d8e94aa18 100644 except CommandExecutionError as exc: ret['result'] = False ret['comment'] = \ -@@ -512,10 +509,7 @@ def managed(name, ppa=None, **kwargs): +@@ -504,10 +501,7 @@ def managed(name, ppa=None, **kwargs): return ret try: @@ -8790,7 +4516,7 @@ index 4d5e9eea92..6d8e94aa18 100644 if pre: for kwarg in sanitizedkwargs: if post.get(kwarg) != pre.get(kwarg): -@@ -608,9 +602,7 @@ def absent(name, **kwargs): +@@ -600,9 +594,7 @@ def absent(name, **kwargs): return ret try: @@ -8802,7 +4528,7 @@ index 4d5e9eea92..6d8e94aa18 100644 ret['result'] = False ret['comment'] = \ diff --git a/salt/utils/oset.py b/salt/utils/oset.py -index f5ab3c1e94..aae5965b86 100644 +index acfd59b53b..cd4e88be40 100644 --- a/salt/utils/oset.py +++ b/salt/utils/oset.py @@ -22,7 +22,10 @@ Rob Speer's changes are as follows: @@ -8826,1015 +4552,6 @@ index f5ab3c1e94..aae5965b86 100644 """ An OrderedSet is a custom MutableSet that remembers its order, so that every entry has an index that can be looked up. -diff --git a/salt/utils/path.py b/salt/utils/path.py -index b1d601e464..132190b271 100644 ---- a/salt/utils/path.py -+++ b/salt/utils/path.py -@@ -6,7 +6,10 @@ lack of support for reading NTFS links. - - # Import python libs - from __future__ import absolute_import, print_function, unicode_literals --import collections -+try: -+ from collections.abc import Iterable -+except ImportError: -+ from collections import Iterable - import errno - import logging - import os -@@ -262,7 +265,7 @@ def which_bin(exes): - ''' - Scan over some possible executables and return the first one that is found - ''' -- if not isinstance(exes, collections.Iterable): -+ if not isinstance(exes, Iterable): - return None - for exe in exes: - path = which(exe) -diff --git a/tests/conftest.py b/tests/conftest.py -index 906cca6dd5..1dbe2176b6 100644 ---- a/tests/conftest.py -+++ b/tests/conftest.py -@@ -244,24 +244,24 @@ def pytest_runtest_setup(item): - ''' - Fixtures injection based on markers or test skips based on CLI arguments - ''' -- destructive_tests_marker = item.get_marker('destructive_test') -+ destructive_tests_marker = item.get_closest_marker('destructive_test') - if destructive_tests_marker is not None: - if item.config.getoption('--run-destructive') is False: - pytest.skip('Destructive tests are disabled') - os.environ['DESTRUCTIVE_TESTS'] = six.text_type(item.config.getoption('--run-destructive')) - -- expensive_tests_marker = item.get_marker('expensive_test') -+ expensive_tests_marker = item.get_closest_marker('expensive_test') - if expensive_tests_marker is not None: - if item.config.getoption('--run-expensive') is False: - pytest.skip('Expensive tests are disabled') - os.environ['EXPENSIVE_TESTS'] = six.text_type(item.config.getoption('--run-expensive')) - -- skip_if_not_root_marker = item.get_marker('skip_if_not_root') -+ skip_if_not_root_marker = item.get_closest_marker('skip_if_not_root') - if skip_if_not_root_marker is not None: - if os.getuid() != 0: - pytest.skip('You must be logged in as root to run this test') - -- skip_if_binaries_missing_marker = item.get_marker('skip_if_binaries_missing') -+ skip_if_binaries_missing_marker = item.get_closest_marker('skip_if_binaries_missing') - if skip_if_binaries_missing_marker is not None: - binaries = skip_if_binaries_missing_marker.args - if len(binaries) == 1: -@@ -286,7 +286,7 @@ def pytest_runtest_setup(item): - ) - ) - -- requires_network_marker = item.get_marker('requires_network') -+ requires_network_marker = item.get_closest_marker('requires_network') - if requires_network_marker is not None: - only_local_network = requires_network_marker.kwargs.get('only_local_network', False) - has_local_network = False -diff --git a/tests/unit/grains/test_core.py b/tests/unit/grains/test_core.py -index e43be4939c..af9d27dd0e 100644 ---- a/tests/unit/grains/test_core.py -+++ b/tests/unit/grains/test_core.py -@@ -1262,3 +1262,42 @@ class CoreGrainsTestCase(TestCase, LoaderModuleMockMixin): - is_proxy.assert_called_once_with() - is_windows.assert_not_called() - self.assertEqual(ret['locale_info']['timezone'], 'unknown') -+ -+ @skipIf(not salt.utils.platform.is_linux(), 'System is not Linux') -+ @patch('os.path.exists') -+ @patch('salt.utils.platform.is_proxy') -+ def test__hw_data_linux_empty(self, is_proxy, exists): -+ is_proxy.return_value = False -+ exists.return_value = True -+ with patch('salt.utils.files.fopen', mock_open(read_data='')): -+ self.assertEqual(core._hw_data({'kernel': 'Linux'}), { -+ 'biosreleasedate': '', -+ 'biosversion': '', -+ 'manufacturer': '', -+ 'productname': '', -+ 'serialnumber': '', -+ 'uuid': '' -+ }) -+ -+ @skipIf(not salt.utils.platform.is_linux(), 'System is not Linux') -+ @skipIf(six.PY2, 'UnicodeDecodeError is throw in Python 3') -+ @patch('os.path.exists') -+ @patch('salt.utils.platform.is_proxy') -+ def test__hw_data_linux_unicode_error(self, is_proxy, exists): -+ def _fopen(*args): -+ class _File(object): -+ def __enter__(self): -+ return self -+ -+ def __exit__(self, *args): -+ pass -+ -+ def read(self): -+ raise UnicodeDecodeError('enconding', b'', 1, 2, 'reason') -+ -+ return _File() -+ -+ is_proxy.return_value = False -+ exists.return_value = True -+ with patch('salt.utils.files.fopen', _fopen): -+ self.assertEqual(core._hw_data({'kernel': 'Linux'}), {}) -diff --git a/tests/unit/modules/test_btrfs.py b/tests/unit/modules/test_btrfs.py -index ebd28a6451..b5f934034d 100644 ---- a/tests/unit/modules/test_btrfs.py -+++ b/tests/unit/modules/test_btrfs.py -@@ -5,6 +5,8 @@ - # Import python libs - from __future__ import absolute_import, print_function, unicode_literals - -+import pytest -+ - # Import Salt Testing Libs - from tests.support.mixins import LoaderModuleMockMixin - from tests.support.unit import TestCase, skipIf -@@ -29,7 +31,7 @@ class BtrfsTestCase(TestCase, LoaderModuleMockMixin): - Test cases for salt.modules.btrfs - ''' - def setup_loader_modules(self): -- return {btrfs: {}} -+ return {btrfs: {'__salt__': {}}} - - # 'version' function tests: 1 - def test_version(self): -@@ -362,3 +364,369 @@ class BtrfsTestCase(TestCase, LoaderModuleMockMixin): - ''' - self.assertRaises(CommandExecutionError, btrfs.properties, - '/dev/sda1', 'subvol', True) -+ -+ def test_subvolume_exists(self): -+ ''' -+ Test subvolume_exists -+ ''' -+ salt_mock = { -+ 'cmd.retcode': MagicMock(return_value=0), -+ } -+ with patch.dict(btrfs.__salt__, salt_mock): -+ assert btrfs.subvolume_exists('/mnt/one') -+ -+ def test_subvolume_not_exists(self): -+ ''' -+ Test subvolume_exists -+ ''' -+ salt_mock = { -+ 'cmd.retcode': MagicMock(return_value=1), -+ } -+ with patch.dict(btrfs.__salt__, salt_mock): -+ assert not btrfs.subvolume_exists('/mnt/nowhere') -+ -+ def test_subvolume_create_fails_parameters(self): -+ ''' -+ Test btrfs subvolume create -+ ''' -+ # Fails when qgroupids is not a list -+ with pytest.raises(CommandExecutionError): -+ btrfs.subvolume_create('var', qgroupids='1') -+ -+ @patch('salt.modules.btrfs.subvolume_exists') -+ def test_subvolume_create_already_exists(self, subvolume_exists): -+ ''' -+ Test btrfs subvolume create -+ ''' -+ subvolume_exists.return_value = True -+ assert not btrfs.subvolume_create('var', dest='/mnt') -+ -+ @patch('salt.modules.btrfs.subvolume_exists') -+ def test_subvolume_create(self, subvolume_exists): -+ ''' -+ Test btrfs subvolume create -+ ''' -+ subvolume_exists.return_value = False -+ salt_mock = { -+ 'cmd.run_all': MagicMock(return_value={'recode': 0}), -+ } -+ with patch.dict(btrfs.__salt__, salt_mock): -+ assert btrfs.subvolume_create('var', dest='/mnt') -+ subvolume_exists.assert_called_once() -+ salt_mock['cmd.run_all'].assert_called_once() -+ salt_mock['cmd.run_all'].assert_called_with( -+ ['btrfs', 'subvolume', 'create', '/mnt/var']) -+ -+ def test_subvolume_delete_fails_parameters(self): -+ ''' -+ Test btrfs subvolume delete -+ ''' -+ # We need to provide name or names -+ with pytest.raises(CommandExecutionError): -+ btrfs.subvolume_delete() -+ -+ with pytest.raises(CommandExecutionError): -+ btrfs.subvolume_delete(names='var') -+ -+ def test_subvolume_delete_fails_parameter_commit(self): -+ ''' -+ Test btrfs subvolume delete -+ ''' -+ # Parameter commit can be 'after' or 'each' -+ with pytest.raises(CommandExecutionError): -+ btrfs.subvolume_delete(name='var', commit='maybe') -+ -+ @patch('salt.modules.btrfs.subvolume_exists') -+ def test_subvolume_delete_already_missing(self, subvolume_exists): -+ ''' -+ Test btrfs subvolume delete -+ ''' -+ subvolume_exists.return_value = False -+ assert not btrfs.subvolume_delete(name='var', names=['tmp']) -+ -+ @patch('salt.modules.btrfs.subvolume_exists') -+ def test_subvolume_delete_already_missing_name(self, subvolume_exists): -+ ''' -+ Test btrfs subvolume delete -+ ''' -+ subvolume_exists.return_value = False -+ assert not btrfs.subvolume_delete(name='var') -+ -+ @patch('salt.modules.btrfs.subvolume_exists') -+ def test_subvolume_delete_already_missing_names(self, subvolume_exists): -+ ''' -+ Test btrfs subvolume delete -+ ''' -+ subvolume_exists.return_value = False -+ assert not btrfs.subvolume_delete(names=['tmp']) -+ -+ @patch('salt.modules.btrfs.subvolume_exists') -+ def test_subvolume_delete(self, subvolume_exists): -+ ''' -+ Test btrfs subvolume delete -+ ''' -+ subvolume_exists.return_value = True -+ salt_mock = { -+ 'cmd.run_all': MagicMock(return_value={'recode': 0}), -+ } -+ with patch.dict(btrfs.__salt__, salt_mock): -+ assert btrfs.subvolume_delete('var', names=['tmp']) -+ salt_mock['cmd.run_all'].assert_called_once() -+ salt_mock['cmd.run_all'].assert_called_with( -+ ['btrfs', 'subvolume', 'delete', 'var', 'tmp']) -+ -+ def test_subvolume_find_new_empty(self): -+ ''' -+ Test btrfs subvolume find-new -+ ''' -+ salt_mock = { -+ 'cmd.run_all': MagicMock(return_value={ -+ 'recode': 0, -+ 'stdout': 'transid marker was 1024' -+ }), -+ } -+ with patch.dict(btrfs.__salt__, salt_mock): -+ assert btrfs.subvolume_find_new('var', '2000') == { -+ 'files': [], -+ 'transid': '1024' -+ } -+ salt_mock['cmd.run_all'].assert_called_once() -+ salt_mock['cmd.run_all'].assert_called_with( -+ ['btrfs', 'subvolume', 'find-new', 'var', '2000']) -+ -+ def test_subvolume_find_new(self): -+ ''' -+ Test btrfs subvolume find-new -+ ''' -+ salt_mock = { -+ 'cmd.run_all': MagicMock(return_value={ -+ 'recode': 0, -+ 'stdout': '''inode 185148 ... gen 2108 flags NONE var/log/audit/audit.log -+inode 187390 ... INLINE etc/openvpn/openvpn-status.log -+transid marker was 1024''' -+ }), -+ } -+ with patch.dict(btrfs.__salt__, salt_mock): -+ assert btrfs.subvolume_find_new('var', '1023') == { -+ 'files': ['var/log/audit/audit.log', -+ 'etc/openvpn/openvpn-status.log'], -+ 'transid': '1024' -+ } -+ salt_mock['cmd.run_all'].assert_called_once() -+ salt_mock['cmd.run_all'].assert_called_with( -+ ['btrfs', 'subvolume', 'find-new', 'var', '1023']) -+ -+ def test_subvolume_get_default_free(self): -+ ''' -+ Test btrfs subvolume get-default -+ ''' -+ salt_mock = { -+ 'cmd.run_all': MagicMock(return_value={ -+ 'recode': 0, -+ 'stdout': 'ID 5 (FS_TREE)', -+ }), -+ } -+ with patch.dict(btrfs.__salt__, salt_mock): -+ assert btrfs.subvolume_get_default('/mnt') == { -+ 'id': '5', -+ 'name': '(FS_TREE)', -+ } -+ salt_mock['cmd.run_all'].assert_called_once() -+ salt_mock['cmd.run_all'].assert_called_with( -+ ['btrfs', 'subvolume', 'get-default', '/mnt']) -+ -+ def test_subvolume_get_default(self): -+ ''' -+ Test btrfs subvolume get-default -+ ''' -+ salt_mock = { -+ 'cmd.run_all': MagicMock(return_value={ -+ 'recode': 0, -+ 'stdout': 'ID 257 gen 8 top level 5 path var', -+ }), -+ } -+ with patch.dict(btrfs.__salt__, salt_mock): -+ assert btrfs.subvolume_get_default('/mnt') == { -+ 'id': '257', -+ 'name': 'var', -+ } -+ salt_mock['cmd.run_all'].assert_called_once() -+ salt_mock['cmd.run_all'].assert_called_with( -+ ['btrfs', 'subvolume', 'get-default', '/mnt']) -+ -+ def test_subvolume_list_fails_parameters(self): -+ ''' -+ Test btrfs subvolume list -+ ''' -+ # Fails when sort is not a list -+ with pytest.raises(CommandExecutionError): -+ btrfs.subvolume_list('/mnt', sort='-rootid') -+ -+ # Fails when sort is not recognized -+ with pytest.raises(CommandExecutionError): -+ btrfs.subvolume_list('/mnt', sort=['-root']) -+ -+ def test_subvolume_list_simple(self): -+ ''' -+ Test btrfs subvolume list -+ ''' -+ salt_mock = { -+ 'cmd.run_all': MagicMock(return_value={ -+ 'recode': 0, -+ 'stdout': '''ID 257 gen 8 top level 5 path one -+ID 258 gen 10 top level 5 path another one -+''', -+ }), -+ } -+ with patch.dict(btrfs.__salt__, salt_mock): -+ assert btrfs.subvolume_list('/mnt') == [ -+ { -+ 'id': '257', -+ 'gen': '8', -+ 'top level': '5', -+ 'path': 'one', -+ }, -+ { -+ 'id': '258', -+ 'gen': '10', -+ 'top level': '5', -+ 'path': 'another one', -+ }, -+ ] -+ salt_mock['cmd.run_all'].assert_called_once() -+ salt_mock['cmd.run_all'].assert_called_with( -+ ['btrfs', 'subvolume', 'list', '/mnt']) -+ -+ def test_subvolume_list(self): -+ ''' -+ Test btrfs subvolume list -+ ''' -+ salt_mock = { -+ 'cmd.run_all': MagicMock(return_value={ -+ 'recode': 0, -+ 'stdout': '''\ -+ID 257 gen 8 cgen 8 parent 5 top level 5 parent_uuid - received_uuid - \ -+ uuid 777...-..05 path one -+ID 258 gen 10 cgen 10 parent 5 top level 5 parent_uuid - received_uuid - \ -+ uuid a90...-..01 path another one -+''', -+ }), -+ } -+ with patch.dict(btrfs.__salt__, salt_mock): -+ assert btrfs.subvolume_list('/mnt', parent_id=True, -+ absolute=True, -+ ogeneration=True, -+ generation=True, -+ subvolumes=True, uuid=True, -+ parent_uuid=True, -+ sent_subvolume_uuid=True, -+ generation_cmp='-100', -+ ogeneration_cmp='+5', -+ sort=['-rootid', 'gen']) == [ -+ { -+ 'id': '257', -+ 'gen': '8', -+ 'cgen': '8', -+ 'parent': '5', -+ 'top level': '5', -+ 'parent_uuid': '-', -+ 'received_uuid': '-', -+ 'uuid': '777...-..05', -+ 'path': 'one', -+ }, -+ { -+ 'id': '258', -+ 'gen': '10', -+ 'cgen': '10', -+ 'parent': '5', -+ 'top level': '5', -+ 'parent_uuid': '-', -+ 'received_uuid': '-', -+ 'uuid': 'a90...-..01', -+ 'path': 'another one', -+ }, -+ ] -+ salt_mock['cmd.run_all'].assert_called_once() -+ salt_mock['cmd.run_all'].assert_called_with( -+ ['btrfs', 'subvolume', 'list', '-p', '-a', '-c', '-g', -+ '-o', '-u', '-q', '-R', '-G', '-100', '-C', '+5', -+ '--sort=-rootid,gen', '/mnt']) -+ -+ def test_subvolume_set_default(self): -+ ''' -+ Test btrfs subvolume set-default -+ ''' -+ salt_mock = { -+ 'cmd.run_all': MagicMock(return_value={'recode': 0}), -+ } -+ with patch.dict(btrfs.__salt__, salt_mock): -+ assert btrfs.subvolume_set_default('257', '/mnt') -+ salt_mock['cmd.run_all'].assert_called_once() -+ salt_mock['cmd.run_all'].assert_called_with( -+ ['btrfs', 'subvolume', 'set-default', '257', '/mnt']) -+ -+ def test_subvolume_show(self): -+ ''' -+ Test btrfs subvolume show -+ ''' -+ salt_mock = { -+ 'cmd.run_all': MagicMock(return_value={ -+ 'recode': 0, -+ 'stdout': '''@/var -+ Name: var -+ UUID: 7a14...-...04 -+ Parent UUID: - -+ Received UUID: - -+ Creation time: 2018-10-01 14:33:12 +0200 -+ Subvolume ID: 258 -+ Generation: 82479 -+ Gen at creation: 10 -+ Parent ID: 256 -+ Top level ID: 256 -+ Flags: - -+ Snapshot(s): -+''', -+ }), -+ } -+ with patch.dict(btrfs.__salt__, salt_mock): -+ assert btrfs.subvolume_show('/var') == { -+ '@/var': { -+ 'name': 'var', -+ 'uuid': '7a14...-...04', -+ 'parent uuid': '-', -+ 'received uuid': '-', -+ 'creation time': '2018-10-01 14:33:12 +0200', -+ 'subvolume id': '258', -+ 'generation': '82479', -+ 'gen at creation': '10', -+ 'parent id': '256', -+ 'top level id': '256', -+ 'flags': '-', -+ 'snapshot(s)': '', -+ }, -+ } -+ salt_mock['cmd.run_all'].assert_called_once() -+ salt_mock['cmd.run_all'].assert_called_with( -+ ['btrfs', 'subvolume', 'show', '/var']) -+ -+ def test_subvolume_sync_fail_parameters(self): -+ ''' -+ Test btrfs subvolume sync -+ ''' -+ # Fails when subvolids is not a list -+ with pytest.raises(CommandExecutionError): -+ btrfs.subvolume_sync('/mnt', subvolids='257') -+ -+ def test_subvolume_sync(self): -+ ''' -+ Test btrfs subvolume sync -+ ''' -+ salt_mock = { -+ 'cmd.run_all': MagicMock(return_value={'recode': 0}), -+ } -+ with patch.dict(btrfs.__salt__, salt_mock): -+ assert btrfs.subvolume_sync('/mnt', subvolids=['257'], -+ sleep='1') -+ salt_mock['cmd.run_all'].assert_called_once() -+ salt_mock['cmd.run_all'].assert_called_with( -+ ['btrfs', 'subvolume', 'sync', '-s', '1', '/mnt', '257']) -diff --git a/tests/unit/modules/test_chroot.py b/tests/unit/modules/test_chroot.py -new file mode 100644 -index 0000000000..7181dd7e50 ---- /dev/null -+++ b/tests/unit/modules/test_chroot.py -@@ -0,0 +1,184 @@ -+# -*- coding: utf-8 -*- -+# -+# Author: Alberto Planas -+# -+# Copyright 2018 SUSE LINUX GmbH, Nuernberg, Germany. -+# -+# Licensed to the Apache Software Foundation (ASF) under one -+# or more contributor license agreements. See the NOTICE file -+# distributed with this work for additional information -+# regarding copyright ownership. The ASF licenses this file -+# to you under the Apache License, Version 2.0 (the -+# "License"); you may not use this file except in compliance -+# with the License. You may obtain a copy of the License at -+# -+# http://www.apache.org/licenses/LICENSE-2.0 -+# -+# Unless required by applicable law or agreed to in writing, -+# software distributed under the License is distributed on an -+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -+# KIND, either express or implied. See the License for the -+# specific language governing permissions and limitations -+# under the License. -+ -+''' -+:maintainer: Alberto Planas -+:platform: Linux -+''' -+ -+# Import Python Libs -+from __future__ import absolute_import, print_function, unicode_literals -+ -+# Import Salt Testing Libs -+from tests.support.mixins import LoaderModuleMockMixin -+from tests.support.unit import skipIf, TestCase -+from tests.support.mock import ( -+ MagicMock, -+ NO_MOCK, -+ NO_MOCK_REASON, -+ patch, -+) -+ -+from salt.exceptions import CommandExecutionError -+import salt.modules.chroot as chroot -+ -+ -+@skipIf(NO_MOCK, NO_MOCK_REASON) -+class ChrootTestCase(TestCase, LoaderModuleMockMixin): -+ ''' -+ Test cases for salt.modules.chroot -+ ''' -+ -+ def setup_loader_modules(self): -+ return { -+ chroot: { -+ '__salt__': {}, -+ '__utils__': {}, -+ '__opts__': {'cachedir': ''}, -+ } -+ } -+ -+ @patch('os.path.isdir') -+ def test_exist(self, isdir): -+ ''' -+ Test if the chroot environment exist. -+ ''' -+ isdir.side_effect = (True, True, True) -+ self.assertTrue(chroot.exist('/chroot')) -+ -+ isdir.side_effect = (True, True, False) -+ self.assertFalse(chroot.exist('/chroot')) -+ -+ @patch('os.makedirs') -+ @patch('salt.modules.chroot.exist') -+ def test_create(self, exist, makedirs): -+ ''' -+ Test the creation of an empty chroot environment. -+ ''' -+ exist.return_value = True -+ self.assertTrue(chroot.create('/chroot')) -+ makedirs.assert_not_called() -+ -+ exist.return_value = False -+ self.assertTrue(chroot.create('/chroot')) -+ makedirs.assert_called() -+ -+ @patch('salt.modules.chroot.exist') -+ def test_call_fails_input_validation(self, exist): -+ ''' -+ Test execution of Salt functions in chroot. -+ ''' -+ # Basic input validation -+ exist.return_value = False -+ self.assertRaises(CommandExecutionError, chroot.call, '/chroot', '') -+ self.assertRaises(CommandExecutionError, chroot.call, '/chroot', 'test.ping') -+ -+ @patch('salt.modules.chroot.exist') -+ @patch('tempfile.mkdtemp') -+ def test_call_fails_untar(self, mkdtemp, exist): -+ ''' -+ Test execution of Salt functions in chroot. -+ ''' -+ # Fail the tar command -+ exist.return_value = True -+ mkdtemp.return_value = '/chroot/tmp01' -+ utils_mock = { -+ 'thin.gen_thin': MagicMock(return_value='/salt-thin.tgz'), -+ 'files.rm_rf': MagicMock(), -+ } -+ salt_mock = { -+ 'archive.tar': MagicMock(return_value='Error'), -+ 'config.option': MagicMock(), -+ } -+ with patch.dict(chroot.__utils__, utils_mock), \ -+ patch.dict(chroot.__salt__, salt_mock): -+ self.assertEqual(chroot.call('/chroot', 'test.ping'), { -+ 'result': False, -+ 'comment': 'Error' -+ }) -+ utils_mock['thin.gen_thin'].assert_called_once() -+ salt_mock['config.option'].assert_called() -+ salt_mock['archive.tar'].assert_called_once() -+ utils_mock['files.rm_rf'].assert_called_once() -+ -+ @patch('salt.modules.chroot.exist') -+ @patch('tempfile.mkdtemp') -+ def test_call_fails_salt_thin(self, mkdtemp, exist): -+ ''' -+ Test execution of Salt functions in chroot. -+ ''' -+ # Fail the inner command -+ exist.return_value = True -+ mkdtemp.return_value = '/chroot/tmp01' -+ utils_mock = { -+ 'thin.gen_thin': MagicMock(return_value='/salt-thin.tgz'), -+ 'files.rm_rf': MagicMock(), -+ } -+ salt_mock = { -+ 'archive.tar': MagicMock(return_value=''), -+ 'config.option': MagicMock(), -+ 'cmd.run_chroot': MagicMock(return_value={ -+ 'retcode': 1, -+ 'stderr': 'Error', -+ }), -+ } -+ with patch.dict(chroot.__utils__, utils_mock), \ -+ patch.dict(chroot.__salt__, salt_mock): -+ self.assertRaises(CommandExecutionError, chroot.call, '/chroot', -+ 'test.ping') -+ utils_mock['thin.gen_thin'].assert_called_once() -+ salt_mock['config.option'].assert_called() -+ salt_mock['archive.tar'].assert_called_once() -+ salt_mock['cmd.run_chroot'].assert_called_once() -+ utils_mock['files.rm_rf'].assert_called_once() -+ -+ @patch('salt.modules.chroot.exist') -+ @patch('tempfile.mkdtemp') -+ def test_call_success(self, mkdtemp, exist): -+ ''' -+ Test execution of Salt functions in chroot. -+ ''' -+ # Success test -+ exist.return_value = True -+ mkdtemp.return_value = '/chroot/tmp01' -+ utils_mock = { -+ 'thin.gen_thin': MagicMock(return_value='/salt-thin.tgz'), -+ 'files.rm_rf': MagicMock(), -+ 'json.find_json': MagicMock(return_value={'return': 'result'}) -+ } -+ salt_mock = { -+ 'archive.tar': MagicMock(return_value=''), -+ 'config.option': MagicMock(), -+ 'cmd.run_chroot': MagicMock(return_value={ -+ 'retcode': 0, -+ 'stdout': '', -+ }), -+ } -+ with patch.dict(chroot.__utils__, utils_mock), \ -+ patch.dict(chroot.__salt__, salt_mock): -+ self.assertEqual(chroot.call('/chroot', 'test.ping'), 'result') -+ utils_mock['thin.gen_thin'].assert_called_once() -+ salt_mock['config.option'].assert_called() -+ salt_mock['archive.tar'].assert_called_once() -+ salt_mock['cmd.run_chroot'].assert_called_once() -+ utils_mock['files.rm_rf'].assert_called_once() -diff --git a/tests/unit/modules/test_freezer.py b/tests/unit/modules/test_freezer.py -new file mode 100644 -index 0000000000..f6cf2f374f ---- /dev/null -+++ b/tests/unit/modules/test_freezer.py -@@ -0,0 +1,274 @@ -+# -*- coding: utf-8 -*- -+# -+# Author: Alberto Planas -+# -+# Copyright 2018 SUSE LINUX GmbH, Nuernberg, Germany. -+# -+# Licensed to the Apache Software Foundation (ASF) under one -+# or more contributor license agreements. See the NOTICE file -+# distributed with this work for additional information -+# regarding copyright ownership. The ASF licenses this file -+# to you under the Apache License, Version 2.0 (the -+# "License"); you may not use this file except in compliance -+# with the License. You may obtain a copy of the License at -+# -+# http://www.apache.org/licenses/LICENSE-2.0 -+# -+# Unless required by applicable law or agreed to in writing, -+# software distributed under the License is distributed on an -+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -+# KIND, either express or implied. See the License for the -+# specific language governing permissions and limitations -+# under the License. -+ -+''' -+:maintainer: Alberto Planas -+:platform: Linux -+''' -+ -+# Import Python Libs -+from __future__ import absolute_import, print_function, unicode_literals -+ -+# Import Salt Testing Libs -+from tests.support.mixins import LoaderModuleMockMixin -+from tests.support.unit import skipIf, TestCase -+from tests.support.mock import ( -+ MagicMock, -+ NO_MOCK, -+ NO_MOCK_REASON, -+ patch, -+) -+ -+from salt.exceptions import CommandExecutionError -+import salt.modules.freezer as freezer -+ -+ -+@skipIf(NO_MOCK, NO_MOCK_REASON) -+class FreezerTestCase(TestCase, LoaderModuleMockMixin): -+ ''' -+ Test cases for salt.modules.freezer -+ ''' -+ -+ def setup_loader_modules(self): -+ return { -+ freezer: { -+ '__salt__': {}, -+ '__opts__': {'cachedir': ''}, -+ } -+ } -+ -+ @patch('os.path.isfile') -+ def test_status(self, isfile): -+ ''' -+ Test if a frozen state exist. -+ ''' -+ isfile.side_effect = (True, True) -+ self.assertTrue(freezer.status()) -+ -+ isfile.side_effect = (True, False) -+ self.assertFalse(freezer.status()) -+ -+ @patch('os.listdir') -+ @patch('os.path.isdir') -+ def test_list(self, isdir, listdir): -+ ''' -+ Test the listing of all frozen states. -+ ''' -+ # There is no freezer directory -+ isdir.return_value = False -+ self.assertEqual(freezer.list_(), []) -+ -+ # There is freezer directory, but is empty -+ isdir.return_value = True -+ listdir.return_value = [] -+ self.assertEqual(freezer.list_(), []) -+ -+ # There is freezer directory with states -+ isdir.return_value = True -+ listdir.return_value = [ -+ 'freezer-pkgs.yml', 'freezer-reps.yml', -+ 'state-pkgs.yml', 'state-reps.yml', -+ 'random-file' -+ ] -+ self.assertEqual(freezer.list_(), ['freezer', 'state']) -+ -+ @patch('os.makedirs') -+ def test_freeze_fails_cache(self, makedirs): -+ ''' -+ Test to freeze a current installation -+ ''' -+ # Fails when creating the freeze cache directory -+ makedirs.side_effect = OSError() -+ self.assertRaises(CommandExecutionError, freezer.freeze) -+ -+ @patch('salt.modules.freezer.status') -+ @patch('os.makedirs') -+ def test_freeze_fails_already_frozen(self, makedirs, status): -+ ''' -+ Test to freeze a current installation -+ ''' -+ # Fails when there is already a frozen state -+ status.return_value = True -+ self.assertRaises(CommandExecutionError, freezer.freeze) -+ makedirs.assert_called_once() -+ -+ @patch('salt.utils.json.dump') -+ @patch('salt.modules.freezer.fopen') -+ @patch('salt.modules.freezer.status') -+ @patch('os.makedirs') -+ def test_freeze_success_new_state(self, makedirs, status, fopen, dump): -+ ''' -+ Test to freeze a current installation -+ ''' -+ # Freeze the current new state -+ status.return_value = False -+ salt_mock = { -+ 'pkg.list_pkgs': MagicMock(return_value={}), -+ 'pkg.list_repos': MagicMock(return_value={}), -+ } -+ with patch.dict(freezer.__salt__, salt_mock): -+ self.assertTrue(freezer.freeze()) -+ makedirs.assert_called_once() -+ salt_mock['pkg.list_pkgs'].assert_called_once() -+ salt_mock['pkg.list_repos'].assert_called_once() -+ fopen.assert_called() -+ dump.asster_called() -+ -+ @patch('salt.utils.json.dump') -+ @patch('salt.modules.freezer.fopen') -+ @patch('salt.modules.freezer.status') -+ @patch('os.makedirs') -+ def test_freeze_success_force(self, makedirs, status, fopen, dump): -+ ''' -+ Test to freeze a current installation -+ ''' -+ # Freeze the current old state -+ status.return_value = True -+ salt_mock = { -+ 'pkg.list_pkgs': MagicMock(return_value={}), -+ 'pkg.list_repos': MagicMock(return_value={}), -+ } -+ with patch.dict(freezer.__salt__, salt_mock): -+ self.assertTrue(freezer.freeze(force=True)) -+ makedirs.assert_called_once() -+ salt_mock['pkg.list_pkgs'].assert_called_once() -+ salt_mock['pkg.list_repos'].assert_called_once() -+ fopen.assert_called() -+ dump.asster_called() -+ -+ @patch('salt.modules.freezer.status') -+ def test_restore_fails_missing_state(self, status): -+ ''' -+ Test to restore an old state -+ ''' -+ # Fails if the state is not found -+ status.return_value = False -+ self.assertRaises(CommandExecutionError, freezer.restore) -+ -+ @patch('salt.utils.json.load') -+ @patch('salt.modules.freezer.fopen') -+ @patch('salt.modules.freezer.status') -+ def test_restore_add_missing_repo(self, status, fopen, load): -+ ''' -+ Test to restore an old state -+ ''' -+ # Only a missing repo is installed -+ status.return_value = True -+ load.side_effect = ({}, {'missing-repo': {}}) -+ salt_mock = { -+ 'pkg.list_pkgs': MagicMock(return_value={}), -+ 'pkg.list_repos': MagicMock(return_value={}), -+ 'pkg.mod_repo': MagicMock(), -+ } -+ with patch.dict(freezer.__salt__, salt_mock): -+ self.assertEqual(freezer.restore(), { -+ 'pkgs': {'add': [], 'remove': []}, -+ 'repos': {'add': ['missing-repo'], 'remove': []}, -+ 'comment': [], -+ }) -+ salt_mock['pkg.list_pkgs'].assert_called() -+ salt_mock['pkg.list_repos'].assert_called() -+ salt_mock['pkg.mod_repo'].assert_called_once() -+ fopen.assert_called() -+ load.asster_called() -+ -+ @patch('salt.utils.json.load') -+ @patch('salt.modules.freezer.fopen') -+ @patch('salt.modules.freezer.status') -+ def test_restore_add_missing_package(self, status, fopen, load): -+ ''' -+ Test to restore an old state -+ ''' -+ # Only a missing package is installed -+ status.return_value = True -+ load.side_effect = ({'missing-package': {}}, {}) -+ salt_mock = { -+ 'pkg.list_pkgs': MagicMock(return_value={}), -+ 'pkg.list_repos': MagicMock(return_value={}), -+ 'pkg.install': MagicMock(), -+ } -+ with patch.dict(freezer.__salt__, salt_mock): -+ self.assertEqual(freezer.restore(), { -+ 'pkgs': {'add': ['missing-package'], 'remove': []}, -+ 'repos': {'add': [], 'remove': []}, -+ 'comment': [], -+ }) -+ salt_mock['pkg.list_pkgs'].assert_called() -+ salt_mock['pkg.list_repos'].assert_called() -+ salt_mock['pkg.install'].assert_called_once() -+ fopen.assert_called() -+ load.asster_called() -+ -+ @patch('salt.utils.json.load') -+ @patch('salt.modules.freezer.fopen') -+ @patch('salt.modules.freezer.status') -+ def test_restore_remove_extra_package(self, status, fopen, load): -+ ''' -+ Test to restore an old state -+ ''' -+ # Only an extra package is removed -+ status.return_value = True -+ load.side_effect = ({}, {}) -+ salt_mock = { -+ 'pkg.list_pkgs': MagicMock(return_value={'extra-package': {}}), -+ 'pkg.list_repos': MagicMock(return_value={}), -+ 'pkg.remove': MagicMock(), -+ } -+ with patch.dict(freezer.__salt__, salt_mock): -+ self.assertEqual(freezer.restore(), { -+ 'pkgs': {'add': [], 'remove': ['extra-package']}, -+ 'repos': {'add': [], 'remove': []}, -+ 'comment': [], -+ }) -+ salt_mock['pkg.list_pkgs'].assert_called() -+ salt_mock['pkg.list_repos'].assert_called() -+ salt_mock['pkg.remove'].assert_called_once() -+ fopen.assert_called() -+ load.asster_called() -+ -+ @patch('salt.utils.json.load') -+ @patch('salt.modules.freezer.fopen') -+ @patch('salt.modules.freezer.status') -+ def test_restore_remove_extra_repo(self, status, fopen, load): -+ ''' -+ Test to restore an old state -+ ''' -+ # Only an extra repository is removed -+ status.return_value = True -+ load.side_effect = ({}, {}) -+ salt_mock = { -+ 'pkg.list_pkgs': MagicMock(return_value={}), -+ 'pkg.list_repos': MagicMock(return_value={'extra-repo': {}}), -+ 'pkg.del_repo': MagicMock(), -+ } -+ with patch.dict(freezer.__salt__, salt_mock): -+ self.assertEqual(freezer.restore(), { -+ 'pkgs': {'add': [], 'remove': []}, -+ 'repos': {'add': [], 'remove': ['extra-repo']}, -+ 'comment': [], -+ }) -+ salt_mock['pkg.list_pkgs'].assert_called() -+ salt_mock['pkg.list_repos'].assert_called() -+ salt_mock['pkg.del_repo'].assert_called_once() -+ fopen.assert_called() -+ load.asster_called() -diff --git a/tests/unit/modules/test_groupadd.py b/tests/unit/modules/test_groupadd.py -index 8e0e64749a..2ce7897a06 100644 ---- a/tests/unit/modules/test_groupadd.py -+++ b/tests/unit/modules/test_groupadd.py -@@ -84,21 +84,19 @@ class GroupAddTestCase(TestCase, LoaderModuleMockMixin): - ''' - Tests if the group id is the same as argument - ''' -- mock_pre_gid = MagicMock(return_value=10) -- with patch.dict(groupadd.__salt__, -- {'file.group_to_gid': mock_pre_gid}): -+ mock = MagicMock(return_value={'gid': 10}) -+ with patch.object(groupadd, 'info', mock): - self.assertTrue(groupadd.chgid('test', 10)) - - def test_chgid(self): - ''' - Tests the gid for a named group was changed - ''' -- mock_pre_gid = MagicMock(return_value=0) -- mock_cmdrun = MagicMock(return_value=0) -- with patch.dict(groupadd.__salt__, -- {'file.group_to_gid': mock_pre_gid}): -- with patch.dict(groupadd.__salt__, {'cmd.run': mock_cmdrun}): -- self.assertFalse(groupadd.chgid('test', 500)) -+ mock = MagicMock(return_value=None) -+ with patch.dict(groupadd.__salt__, {'cmd.run': mock}): -+ mock = MagicMock(side_effect=[{'gid': 10}, {'gid': 500}]) -+ with patch.object(groupadd, 'info', mock): -+ self.assertTrue(groupadd.chgid('test', 500)) - - # 'delete' function tests: 1 - diff --git a/tests/unit/modules/test_kubeadm.py b/tests/unit/modules/test_kubeadm.py new file mode 100644 index 0000000000..a58f54f118 @@ -10985,205 +5702,11 @@ index 0000000000..a58f54f118 + with patch.dict(kubeadm.__salt__, salt_mock): + with pytest.raises(CommandExecutionError): + assert kubeadm.reset() -diff --git a/tests/unit/modules/test_mount.py b/tests/unit/modules/test_mount.py -index 1a0d64f2f5..fe9b067665 100644 ---- a/tests/unit/modules/test_mount.py -+++ b/tests/unit/modules/test_mount.py -@@ -216,6 +216,21 @@ class MountTestCase(TestCase, LoaderModuleMockMixin): - mock_open(read_data=MOCK_SHELL_FILE)): - self.assertEqual(mount.set_fstab('A', 'B', 'C'), 'new') - -+ mock = MagicMock(return_value=True) -+ with patch.object(os.path, 'isfile', mock): -+ with patch('salt.utils.files.fopen', -+ mock_open(read_data=MOCK_SHELL_FILE)): -+ self.assertEqual(mount.set_fstab('B', 'A', 'C', 'D', 'F', 'G'), -+ 'present') -+ -+ mock = MagicMock(return_value=True) -+ with patch.object(os.path, 'isfile', mock): -+ with patch('salt.utils.files.fopen', -+ mock_open(read_data=MOCK_SHELL_FILE)): -+ self.assertEqual(mount.set_fstab('B', 'A', 'C', -+ not_change=True), -+ 'present') -+ - def test_rm_automaster(self): - ''' - Remove the mount point from the auto_master -@@ -239,6 +254,34 @@ class MountTestCase(TestCase, LoaderModuleMockMixin): - mount.set_automaster, - 'A', 'B', 'C') - -+ mock = MagicMock(return_value=True) -+ mock_read = MagicMock(side_effect=OSError) -+ with patch.object(os.path, 'isfile', mock): -+ with patch.object(salt.utils.files, 'fopen', mock_read): -+ self.assertRaises(CommandExecutionError, -+ mount.set_automaster, 'A', 'B', 'C') -+ -+ mock = MagicMock(return_value=True) -+ with patch.object(os.path, 'isfile', mock): -+ with patch('salt.utils.files.fopen', -+ mock_open(read_data=MOCK_SHELL_FILE)): -+ self.assertEqual(mount.set_automaster('A', 'B', 'C'), 'new') -+ -+ mock = MagicMock(return_value=True) -+ with patch.object(os.path, 'isfile', mock): -+ with patch('salt.utils.files.fopen', -+ mock_open(read_data='/..A -fstype=C,D C:B')): -+ self.assertEqual(mount.set_automaster('A', 'B', 'C', 'D'), -+ 'present') -+ -+ mock = MagicMock(return_value=True) -+ with patch.object(os.path, 'isfile', mock): -+ with patch('salt.utils.files.fopen', -+ mock_open(read_data='/..A -fstype=XX C:B')): -+ self.assertEqual(mount.set_automaster('A', 'B', 'C', 'D', -+ not_change=True), -+ 'present') -+ - def test_automaster(self): - ''' - Test the list the contents of the fstab -@@ -284,7 +327,7 @@ class MountTestCase(TestCase, LoaderModuleMockMixin): - with patch.dict(mount.__grains__, {'os': 'AIX', 'kernel': 'AIX'}): - with patch.object(os.path, 'isfile', mock): - self.assertRaises(CommandExecutionError, -- mount.set_filesystems, 'A', 'B', 'C') -+ mount.set_filesystems, 'A', 'B', 'C') - - mock_read = MagicMock(side_effect=OSError) - with patch.object(os.path, 'isfile', mock): -@@ -362,7 +405,7 @@ class MountTestCase(TestCase, LoaderModuleMockMixin): - with patch.dict(mount.__salt__, {'cmd.run_all': mock}): - self.assertTrue(mount.mount('name', 'device')) - -- def test_remount(self): -+ def test_remount_non_mounted(self): - ''' - Attempt to remount a device, if the device is not already mounted, mount - is called -@@ -381,6 +424,77 @@ class MountTestCase(TestCase, LoaderModuleMockMixin): - with patch.object(mount, 'mount', mock): - self.assertTrue(mount.remount('name', 'device')) - -+ with patch.dict(mount.__grains__, {'os': 'Linux'}): -+ mock = MagicMock(return_value=[]) -+ with patch.object(mount, 'active', mock): -+ mock = MagicMock(return_value=True) -+ with patch.object(mount, 'mount', mock): -+ self.assertTrue(mount.remount('name', 'device')) -+ -+ def test_remount_already_mounted_no_fstype(self): -+ ''' -+ Attempt to remount a device already mounted that do not provides -+ fstype -+ ''' -+ with patch.dict(mount.__grains__, {'os': 'MacOS'}): -+ mock = MagicMock(return_value=['name']) -+ with patch.object(mount, 'active', mock): -+ mock = MagicMock(return_value={'retcode': 0}) -+ with patch.dict(mount.__salt__, {'cmd.run_all': mock}): -+ self.assertTrue(mount.remount('name', 'device')) -+ mock.assert_called_with('mount -u -o noowners device name ', -+ python_shell=False, runas=None) -+ -+ with patch.dict(mount.__grains__, {'os': 'AIX'}): -+ mock = MagicMock(return_value=['name']) -+ with patch.object(mount, 'active', mock): -+ mock = MagicMock(return_value={'retcode': 0}) -+ with patch.dict(mount.__salt__, {'cmd.run_all': mock}): -+ self.assertTrue(mount.remount('name', 'device')) -+ mock.assert_called_with('mount -o remount device name ', -+ python_shell=False, runas=None) -+ -+ with patch.dict(mount.__grains__, {'os': 'Linux'}): -+ mock = MagicMock(return_value=['name']) -+ with patch.object(mount, 'active', mock): -+ mock = MagicMock(return_value={'retcode': 0}) -+ with patch.dict(mount.__salt__, {'cmd.run_all': mock}): -+ self.assertTrue(mount.remount('name', 'device')) -+ mock.assert_called_with('mount -o defaults,remount device name ', -+ python_shell=False, runas=None) -+ -+ def test_remount_already_mounted_with_fstype(self): -+ ''' -+ Attempt to remount a device already mounted that do not provides -+ fstype -+ ''' -+ with patch.dict(mount.__grains__, {'os': 'MacOS'}): -+ mock = MagicMock(return_value=['name']) -+ with patch.object(mount, 'active', mock): -+ mock = MagicMock(return_value={'retcode': 0}) -+ with patch.dict(mount.__salt__, {'cmd.run_all': mock}): -+ self.assertTrue(mount.remount('name', 'device', fstype='type')) -+ mock.assert_called_with('mount -u -o noowners -t type device name ', -+ python_shell=False, runas=None) -+ -+ with patch.dict(mount.__grains__, {'os': 'AIX'}): -+ mock = MagicMock(return_value=['name']) -+ with patch.object(mount, 'active', mock): -+ mock = MagicMock(return_value={'retcode': 0}) -+ with patch.dict(mount.__salt__, {'cmd.run_all': mock}): -+ self.assertTrue(mount.remount('name', 'device', fstype='type')) -+ mock.assert_called_with('mount -o remount -v type device name ', -+ python_shell=False, runas=None) -+ -+ with patch.dict(mount.__grains__, {'os': 'Linux'}): -+ mock = MagicMock(return_value=['name']) -+ with patch.object(mount, 'active', mock): -+ mock = MagicMock(return_value={'retcode': 0}) -+ with patch.dict(mount.__salt__, {'cmd.run_all': mock}): -+ self.assertTrue(mount.remount('name', 'device', fstype='type')) -+ mock.assert_called_with('mount -o defaults,remount -t type device name ', -+ python_shell=False, runas=None) -+ - def test_umount(self): - ''' - Attempt to unmount a device by specifying the directory it is -diff --git a/tests/unit/modules/test_parted_partition.py b/tests/unit/modules/test_parted_partition.py -index 8f381d55a6..1959e5978e 100644 ---- a/tests/unit/modules/test_parted_partition.py -+++ b/tests/unit/modules/test_parted_partition.py -@@ -376,3 +376,20 @@ class PartedTestCase(TestCase, LoaderModuleMockMixin): - } - } - self.assertEqual(output, expected) -+ -+ def test_disk_set(self): -+ with patch('salt.modules.parted_partition._validate_device', MagicMock()): -+ self.cmdrun.return_value = '' -+ output = parted.disk_set('/dev/sda', 'pmbr_boot', 'on') -+ self.cmdrun.assert_called_once_with( -+ ['parted', '-m', '-s', '/dev/sda', 'disk_set', -+ 'pmbr_boot', 'on']) -+ assert output == [] -+ -+ def test_disk_toggle(self): -+ with patch('salt.modules.parted_partition._validate_device', MagicMock()): -+ self.cmdrun.return_value = '' -+ output = parted.disk_toggle('/dev/sda', 'pmbr_boot') -+ self.cmdrun.assert_called_once_with( -+ ['parted', '-m', '-s', '/dev/sda', 'disk_toggle', 'pmbr_boot']) -+ assert output == [] diff --git a/tests/unit/modules/test_rpm_lowpkg.py b/tests/unit/modules/test_rpm_lowpkg.py -index 0a2359ccb2..dc9f52c572 100644 +index 527c8d3bf8..54b81f6972 100644 --- a/tests/unit/modules/test_rpm_lowpkg.py +++ b/tests/unit/modules/test_rpm_lowpkg.py -@@ -20,6 +20,11 @@ from tests.support.mock import ( - import salt.modules.rpm_lowpkg as rpm - - -+def _called_with_root(mock): -+ cmd = ' '.join(mock.call_args[0][0]) -+ return cmd.startswith('rpm --root /') -+ -+ - @skipIf(NO_MOCK, NO_MOCK_REASON) - class RpmTestCase(TestCase, LoaderModuleMockMixin): - ''' -@@ -28,7 +33,7 @@ class RpmTestCase(TestCase, LoaderModuleMockMixin): +@@ -25,7 +25,7 @@ class RpmTestCase(TestCase, LoaderModuleMockMixin): def setup_loader_modules(self): return {rpm: {'rpm': MagicMock(return_value=MagicMock)}} @@ -11192,12 +5715,13 @@ index 0a2359ccb2..dc9f52c572 100644 def test_list_pkgs(self): ''' -@@ -37,13 +42,24 @@ class RpmTestCase(TestCase, LoaderModuleMockMixin): +@@ -34,13 +34,24 @@ class RpmTestCase(TestCase, LoaderModuleMockMixin): mock = MagicMock(return_value='') with patch.dict(rpm.__salt__, {'cmd.run': mock}): self.assertDictEqual(rpm.list_pkgs(), {}) + self.assertFalse(_called_with_root(mock)) -+ + +- # 'verify' function tests: 1 + def test_list_pkgs_root(self): + ''' + Test if it list the packages currently installed in a dict, @@ -11207,8 +5731,7 @@ index 0a2359ccb2..dc9f52c572 100644 + with patch.dict(rpm.__salt__, {'cmd.run': mock}): + rpm.list_pkgs(root='/') + self.assertTrue(_called_with_root(mock)) - -- # 'verify' function tests: 1 ++ + # 'verify' function tests: 2 def test_verify(self): @@ -11220,12 +5743,13 @@ index 0a2359ccb2..dc9f52c572 100644 ''' mock = MagicMock(return_value={'stdout': '', 'stderr': '', -@@ -51,8 +67,22 @@ class RpmTestCase(TestCase, LoaderModuleMockMixin): +@@ -48,8 +59,22 @@ class RpmTestCase(TestCase, LoaderModuleMockMixin): 'pid': 12345}) with patch.dict(rpm.__salt__, {'cmd.run_all': mock}): self.assertDictEqual(rpm.verify('httpd'), {}) + self.assertFalse(_called_with_root(mock)) -+ + +- # 'file_list' function tests: 1 + def test_verify_root(self): + ''' + Test if it runs an rpm -Va on a system, and returns the @@ -11238,19 +5762,17 @@ index 0a2359ccb2..dc9f52c572 100644 + with patch.dict(rpm.__salt__, {'cmd.run_all': mock}): + rpm.verify('httpd', root='/') + self.assertTrue(_called_with_root(mock)) - -- # 'file_list' function tests: 1 ++ + # 'file_list' function tests: 2 def test_file_list(self): ''' -@@ -62,8 +92,20 @@ class RpmTestCase(TestCase, LoaderModuleMockMixin): +@@ -59,8 +84,20 @@ class RpmTestCase(TestCase, LoaderModuleMockMixin): with patch.dict(rpm.__salt__, {'cmd.run': mock}): self.assertDictEqual(rpm.file_list('httpd'), {'errors': [], 'files': []}) + self.assertFalse(_called_with_root(mock)) - -- # 'file_dict' function tests: 1 ++ + def test_file_list_root(self): + ''' + Test if it list the files that belong to a package, using the @@ -11261,12 +5783,13 @@ index 0a2359ccb2..dc9f52c572 100644 + with patch.dict(rpm.__salt__, {'cmd.run': mock}): + rpm.file_list('httpd', root='/') + self.assertTrue(_called_with_root(mock)) -+ + +- # 'file_dict' function tests: 1 + # 'file_dict' function tests: 2 def test_file_dict(self): ''' -@@ -73,6 +115,16 @@ class RpmTestCase(TestCase, LoaderModuleMockMixin): +@@ -70,6 +107,16 @@ class RpmTestCase(TestCase, LoaderModuleMockMixin): with patch.dict(rpm.__salt__, {'cmd.run': mock}): self.assertDictEqual(rpm.file_dict('httpd'), {'errors': [], 'packages': {}}) @@ -11283,7 +5806,7 @@ index 0a2359ccb2..dc9f52c572 100644 # 'owner' function tests: 1 -@@ -86,6 +138,7 @@ class RpmTestCase(TestCase, LoaderModuleMockMixin): +@@ -83,6 +130,7 @@ class RpmTestCase(TestCase, LoaderModuleMockMixin): mock = MagicMock(return_value=ret) with patch.dict(rpm.__salt__, {'cmd.run_stdout': mock}): self.assertEqual(rpm.owner('/usr/bin/salt-jenkins-build'), '') @@ -11291,13 +5814,12 @@ index 0a2359ccb2..dc9f52c572 100644 ret = {'/usr/bin/vim': 'vim-enhanced-7.4.160-1.e17.x86_64', '/usr/bin/python': 'python-2.7.5-16.e17.x86_64'} -@@ -94,8 +147,22 @@ class RpmTestCase(TestCase, LoaderModuleMockMixin): +@@ -91,8 +139,22 @@ class RpmTestCase(TestCase, LoaderModuleMockMixin): with patch.dict(rpm.__salt__, {'cmd.run_stdout': mock}): self.assertDictEqual(rpm.owner('/usr/bin/python', '/usr/bin/vim'), ret) + self.assertFalse(_called_with_root(mock)) - -- # 'checksum' function tests: 1 ++ + def test_owner_root(self): + ''' + Test if it return the name of the package that owns the file, @@ -11310,12 +5832,13 @@ index 0a2359ccb2..dc9f52c572 100644 + with patch.dict(rpm.__salt__, {'cmd.run_stdout': mock}): + rpm.owner('/usr/bin/salt-jenkins-build', root='/') + self.assertTrue(_called_with_root(mock)) -+ + +- # 'checksum' function tests: 1 + # 'checksum' function tests: 2 def test_checksum(self): ''' -@@ -110,6 +177,17 @@ class RpmTestCase(TestCase, LoaderModuleMockMixin): +@@ -107,6 +169,17 @@ class RpmTestCase(TestCase, LoaderModuleMockMixin): mock = MagicMock(side_effect=[True, 0, True, 1, False, 0]) with patch.dict(rpm.__salt__, {'file.file_exists': mock, 'cmd.retcode': mock}): self.assertDictEqual(rpm.checksum("file1.rpm", "file2.rpm", "file3.rpm"), ret) @@ -11334,7 +5857,7 @@ index 0a2359ccb2..dc9f52c572 100644 def test_version_cmp_rpm(self): ''' diff --git a/tests/unit/modules/test_systemd_service.py b/tests/unit/modules/test_systemd_service.py -index 1d3a760c13..ed44459f93 100644 +index 13ddc394be..752fb1d659 100644 --- a/tests/unit/modules/test_systemd_service.py +++ b/tests/unit/modules/test_systemd_service.py @@ -7,6 +7,8 @@ @@ -11345,26 +5868,8 @@ index 1d3a760c13..ed44459f93 100644 + # Import Salt Testing Libs from tests.support.mixins import LoaderModuleMockMixin - from tests.support.unit import TestCase, skipIf -@@ -110,7 +112,7 @@ class SystemdTestCase(TestCase, LoaderModuleMockMixin): - 'README' - ) - ) -- sysv_enabled_mock = MagicMock(side_effect=lambda x: x == 'baz') -+ sysv_enabled_mock = MagicMock(side_effect=lambda x, _: x == 'baz') - - with patch.dict(systemd.__salt__, {'cmd.run': cmd_mock}): - with patch.object(os, 'listdir', listdir_mock): -@@ -146,7 +148,7 @@ class SystemdTestCase(TestCase, LoaderModuleMockMixin): - 'README' - ) - ) -- sysv_enabled_mock = MagicMock(side_effect=lambda x: x == 'baz') -+ sysv_enabled_mock = MagicMock(side_effect=lambda x, _: x == 'baz') - - with patch.dict(systemd.__salt__, {'cmd.run': cmd_mock}): - with patch.object(os, 'listdir', listdir_mock): -@@ -571,3 +573,54 @@ class SystemdScopeTestCase(TestCase, LoaderModuleMockMixin): + from tests.support.unit import TestCase +@@ -643,3 +645,54 @@ class SystemdScopeTestCase(TestCase, LoaderModuleMockMixin): def test_unmask_runtime(self): self._mask_unmask('unmask_', True) @@ -11419,33 +5924,11 @@ index 1d3a760c13..ed44459f93 100644 + with patch.dict(systemd.__salt__, salt_mock): + with pytest.raises(CommandExecutionError): + assert systemd.firstboot() -diff --git a/tests/unit/modules/test_useradd.py b/tests/unit/modules/test_useradd.py -index 18da8d8ce8..74cafc6440 100644 ---- a/tests/unit/modules/test_useradd.py -+++ b/tests/unit/modules/test_useradd.py -@@ -415,14 +415,15 @@ class UserAddTestCase(TestCase, LoaderModuleMockMixin): - - mock = MagicMock(return_value=None) - with patch.dict(useradd.__salt__, {'cmd.run': mock}): -- mock = MagicMock(side_effect=[{'name': ''}, False, -+ mock = MagicMock(side_effect=[False, {'name': ''}, - {'name': 'salt'}]) - with patch.object(useradd, 'info', mock): - self.assertTrue(useradd.rename('name', 'salt')) - - mock = MagicMock(return_value=None) - with patch.dict(useradd.__salt__, {'cmd.run': mock}): -- mock = MagicMock(side_effect=[{'name': ''}, False, {'name': ''}]) -+ mock = MagicMock(side_effect=[False, {'name': ''}, -+ {'name': ''}]) - with patch.object(useradd, 'info', mock): - self.assertFalse(useradd.rename('salt', 'salt')) - diff --git a/tests/unit/modules/test_zypperpkg.py b/tests/unit/modules/test_zypperpkg.py -index a7063e47c6..d2ae06a98e 100644 +index 956902eab3..3a6466f061 100644 --- a/tests/unit/modules/test_zypperpkg.py +++ b/tests/unit/modules/test_zypperpkg.py -@@ -40,6 +40,9 @@ class ZyppCallMock(object): +@@ -38,6 +38,9 @@ class ZyppCallMock(object): return self def __call__(self, *args, **kwargs): @@ -11455,7 +5938,7 @@ index a7063e47c6..d2ae06a98e 100644 return MagicMock(return_value=self.__return_value)() -@@ -925,7 +928,7 @@ Repository 'DUMMY' not found by its alias, number, or URI. +@@ -926,7 +929,7 @@ Repository 'DUMMY' not found by its alias, number, or URI. 'pico': '0.1.1', } @@ -11464,7 +5947,7 @@ index a7063e47c6..d2ae06a98e 100644 pkgs = self._pkgs.copy() for target in self._packages: if self._pkgs.get(target): -@@ -991,10 +994,10 @@ Repository 'DUMMY' not found by its alias, number, or URI. +@@ -992,10 +995,10 @@ Repository 'DUMMY' not found by its alias, number, or URI. with zypper_patcher: zypper.mod_repo(name, **{'url': url}) self.assertEqual( @@ -11477,7 +5960,7 @@ index a7063e47c6..d2ae06a98e 100644 def test_repo_noadd_nomod_noref(self): ''' -@@ -1016,8 +1019,8 @@ Repository 'DUMMY' not found by its alias, number, or URI. +@@ -1017,8 +1020,8 @@ Repository 'DUMMY' not found by its alias, number, or URI. self.assertEqual( out['comment'], 'Specified arguments did not result in modification of repo') @@ -11488,7 +5971,7 @@ index a7063e47c6..d2ae06a98e 100644 def test_repo_noadd_modbaseurl_ref(self): ''' -@@ -1045,9 +1048,11 @@ Repository 'DUMMY' not found by its alias, number, or URI. +@@ -1046,9 +1049,11 @@ Repository 'DUMMY' not found by its alias, number, or URI. 'priority': 1, 'cache': False, 'keeppackages': False, @@ -11503,7 +5986,7 @@ index a7063e47c6..d2ae06a98e 100644 def test_repo_add_mod_noref(self): ''' -@@ -1063,10 +1068,10 @@ Repository 'DUMMY' not found by its alias, number, or URI. +@@ -1064,10 +1069,10 @@ Repository 'DUMMY' not found by its alias, number, or URI. with zypper_patcher: zypper.mod_repo(name, **{'url': url, 'refresh': True}) self.assertEqual( @@ -11516,7 +5999,7 @@ index a7063e47c6..d2ae06a98e 100644 'mr', '--refresh', name ) -@@ -1085,8 +1090,8 @@ Repository 'DUMMY' not found by its alias, number, or URI. +@@ -1086,8 +1091,8 @@ Repository 'DUMMY' not found by its alias, number, or URI. 'salt.modules.zypperpkg', **self.zypper_patcher_config) with zypper_patcher: zypper.mod_repo(name, **{'url': url, 'refresh': True}) @@ -11527,7 +6010,7 @@ index a7063e47c6..d2ae06a98e 100644 'mr', '--refresh', name ) -@@ -1105,13 +1110,13 @@ Repository 'DUMMY' not found by its alias, number, or URI. +@@ -1106,13 +1111,13 @@ Repository 'DUMMY' not found by its alias, number, or URI. with zypper_patcher: zypper.mod_repo(name, **{'url': url, 'gpgautoimport': True}) self.assertEqual( @@ -11543,7 +6026,7 @@ index a7063e47c6..d2ae06a98e 100644 def test_repo_noadd_nomod_ref(self): ''' -@@ -1132,10 +1137,10 @@ Repository 'DUMMY' not found by its alias, number, or URI. +@@ -1133,10 +1138,10 @@ Repository 'DUMMY' not found by its alias, number, or URI. with zypper_patcher: zypper.mod_repo(name, **{'url': url, 'gpgautoimport': True}) self.assertEqual( @@ -11556,7 +6039,7 @@ index a7063e47c6..d2ae06a98e 100644 def test_repo_add_mod_ref(self): ''' -@@ -1156,13 +1161,13 @@ Repository 'DUMMY' not found by its alias, number, or URI. +@@ -1157,13 +1162,13 @@ Repository 'DUMMY' not found by its alias, number, or URI. **{'url': url, 'refresh': True, 'gpgautoimport': True} ) self.assertEqual( @@ -11572,7 +6055,7 @@ index a7063e47c6..d2ae06a98e 100644 '--gpg-auto-import-keys', 'mr', '--refresh', name ) -@@ -1188,10 +1193,10 @@ Repository 'DUMMY' not found by its alias, number, or URI. +@@ -1189,10 +1194,10 @@ Repository 'DUMMY' not found by its alias, number, or URI. **{'url': url, 'refresh': True, 'gpgautoimport': True} ) self.assertEqual( @@ -11585,7 +6068,7 @@ index a7063e47c6..d2ae06a98e 100644 '--gpg-auto-import-keys', 'mr', '--refresh', name ) -@@ -1368,3 +1373,58 @@ Repository 'DUMMY' not found by its alias, number, or URI. +@@ -1369,3 +1374,58 @@ Repository 'DUMMY' not found by its alias, number, or URI. with self.assertRaises(CommandExecutionError): for op in ['>>', '==', '<<', '+']: zypper.Wildcard(_zpr)('libzypp', '{0}*.1'.format(op)) @@ -12432,624 +6915,11 @@ index 0000000000..3f45ed94f9 + set='ro=true') + mount.assert_called_once() + umount.assert_called_once() -diff --git a/tests/unit/states/test_mount.py b/tests/unit/states/test_mount.py -index 3e3a75d3cd..8f21db0cbb 100644 ---- a/tests/unit/states/test_mount.py -+++ b/tests/unit/states/test_mount.py -@@ -449,3 +449,608 @@ class MountTestCase(TestCase, LoaderModuleMockMixin): - 'changes': {}} - - self.assertDictEqual(mount.mod_watch(name, sfun='unmount'), ret) -+ -+ def test__convert_to_fast_none(self): -+ ''' -+ Test the device name conversor -+ ''' -+ assert mount._convert_to('/dev/sda1', None) == '/dev/sda1' -+ -+ def test__convert_to_fast_device(self): -+ ''' -+ Test the device name conversor -+ ''' -+ assert mount._convert_to('/dev/sda1', 'device') == '/dev/sda1' -+ -+ def test__convert_to_fast_token(self): -+ ''' -+ Test the device name conversor -+ ''' -+ assert mount._convert_to('LABEL=home', 'label') == 'LABEL=home' -+ -+ def test__convert_to_device_none(self): -+ ''' -+ Test the device name conversor -+ ''' -+ salt_mock = { -+ 'disk.blkid': MagicMock(return_value={}), -+ } -+ with patch.dict(mount.__salt__, salt_mock): -+ assert mount._convert_to('/dev/sda1', 'uuid') is None -+ salt_mock['disk.blkid'].assert_called_with('/dev/sda1') -+ -+ def test__convert_to_device_token(self): -+ ''' -+ Test the device name conversor -+ ''' -+ uuid = '988c663d-74a2-432b-ba52-3eea34015f22' -+ salt_mock = { -+ 'disk.blkid': MagicMock(return_value={ -+ '/dev/sda1': {'UUID': uuid} -+ }), -+ } -+ with patch.dict(mount.__salt__, salt_mock): -+ uuid = 'UUID={}'.format(uuid) -+ assert mount._convert_to('/dev/sda1', 'uuid') == uuid -+ salt_mock['disk.blkid'].assert_called_with('/dev/sda1') -+ -+ def test__convert_to_token_device(self): -+ ''' -+ Test the device name conversor -+ ''' -+ uuid = '988c663d-74a2-432b-ba52-3eea34015f22' -+ salt_mock = { -+ 'disk.blkid': MagicMock(return_value={ -+ '/dev/sda1': {'UUID': uuid} -+ }), -+ } -+ with patch.dict(mount.__salt__, salt_mock): -+ uuid = 'UUID={}'.format(uuid) -+ assert mount._convert_to(uuid, 'device') == '/dev/sda1' -+ salt_mock['disk.blkid'].assert_called_with(token=uuid) -+ -+ def test_fstab_present_macos_test_present(self): -+ ''' -+ Test fstab_present -+ ''' -+ ret = { -+ 'name': '/dev/sda1', -+ 'result': None, -+ 'changes': {}, -+ 'comment': ['/home entry is already in /etc/auto_salt.'], -+ } -+ -+ grains_mock = {'os': 'MacOS'} -+ opts_mock = {'test': True} -+ salt_mock = { -+ 'mount.set_automaster': MagicMock(return_value='present') -+ } -+ with patch.dict(mount.__grains__, grains_mock), \ -+ patch.dict(mount.__opts__, opts_mock), \ -+ patch.dict(mount.__salt__, salt_mock): -+ assert mount.fstab_present('/dev/sda1', '/home', 'ext2') == ret -+ salt_mock['mount.set_automaster'].assert_called_with(name='/home', -+ device='/dev/sda1', -+ fstype='ext2', -+ opts='noowners', -+ config='/etc/auto_salt', -+ test=True, -+ not_change=False) -+ -+ def test_fstab_present_aix_test_present(self): -+ ''' -+ Test fstab_present -+ ''' -+ ret = { -+ 'name': '/dev/sda1', -+ 'result': None, -+ 'changes': {}, -+ 'comment': ['/home entry is already in /etc/filesystems.'], -+ } -+ -+ grains_mock = {'os': 'AIX'} -+ opts_mock = {'test': True} -+ salt_mock = { -+ 'mount.set_filesystems': MagicMock(return_value='present') -+ } -+ with patch.dict(mount.__grains__, grains_mock), \ -+ patch.dict(mount.__opts__, opts_mock), \ -+ patch.dict(mount.__salt__, salt_mock): -+ assert mount.fstab_present('/dev/sda1', '/home', 'ext2') == ret -+ salt_mock['mount.set_filesystems'].assert_called_with(name='/home', -+ device='/dev/sda1', -+ fstype='ext2', -+ mount=True, -+ opts='', -+ config='/etc/filesystems', -+ test=True, -+ match_on='auto', -+ not_change=False) -+ -+ def test_fstab_present_test_present(self): -+ ''' -+ Test fstab_present -+ ''' -+ ret = { -+ 'name': '/dev/sda1', -+ 'result': None, -+ 'changes': {}, -+ 'comment': ['/home entry is already in /etc/fstab.'], -+ } -+ -+ grains_mock = {'os': 'Linux'} -+ opts_mock = {'test': True} -+ salt_mock = { -+ 'mount.set_fstab': MagicMock(return_value='present') -+ } -+ with patch.dict(mount.__grains__, grains_mock), \ -+ patch.dict(mount.__opts__, opts_mock), \ -+ patch.dict(mount.__salt__, salt_mock): -+ assert mount.fstab_present('/dev/sda1', '/home', 'ext2') == ret -+ salt_mock['mount.set_fstab'].assert_called_with(name='/home', -+ device='/dev/sda1', -+ fstype='ext2', -+ opts='defaults', -+ dump=0, -+ pass_num=0, -+ config='/etc/fstab', -+ test=True, -+ match_on='auto', -+ not_change=False) -+ -+ def test_fstab_present_test_new(self): -+ ''' -+ Test fstab_present -+ ''' -+ ret = { -+ 'name': '/dev/sda1', -+ 'result': None, -+ 'changes': {}, -+ 'comment': ['/home entry will be written in /etc/fstab.'], -+ } -+ -+ grains_mock = {'os': 'Linux'} -+ opts_mock = {'test': True} -+ salt_mock = { -+ 'mount.set_fstab': MagicMock(return_value='new') -+ } -+ with patch.dict(mount.__grains__, grains_mock), \ -+ patch.dict(mount.__opts__, opts_mock), \ -+ patch.dict(mount.__salt__, salt_mock): -+ assert mount.fstab_present('/dev/sda1', '/home', 'ext2') == ret -+ salt_mock['mount.set_fstab'].assert_called_with(name='/home', -+ device='/dev/sda1', -+ fstype='ext2', -+ opts='defaults', -+ dump=0, -+ pass_num=0, -+ config='/etc/fstab', -+ test=True, -+ match_on='auto', -+ not_change=False) -+ -+ def test_fstab_present_test_change(self): -+ ''' -+ Test fstab_present -+ ''' -+ ret = { -+ 'name': '/dev/sda1', -+ 'result': None, -+ 'changes': {}, -+ 'comment': ['/home entry will be updated in /etc/fstab.'], -+ } -+ -+ grains_mock = {'os': 'Linux'} -+ opts_mock = {'test': True} -+ salt_mock = { -+ 'mount.set_fstab': MagicMock(return_value='change') -+ } -+ with patch.dict(mount.__grains__, grains_mock), \ -+ patch.dict(mount.__opts__, opts_mock), \ -+ patch.dict(mount.__salt__, salt_mock): -+ assert mount.fstab_present('/dev/sda1', '/home', 'ext2') == ret -+ salt_mock['mount.set_fstab'].assert_called_with(name='/home', -+ device='/dev/sda1', -+ fstype='ext2', -+ opts='defaults', -+ dump=0, -+ pass_num=0, -+ config='/etc/fstab', -+ test=True, -+ match_on='auto', -+ not_change=False) -+ -+ def test_fstab_present_test_error(self): -+ ''' -+ Test fstab_present -+ ''' -+ ret = { -+ 'name': '/dev/sda1', -+ 'result': False, -+ 'changes': {}, -+ 'comment': ['/home entry cannot be created in /etc/fstab: error.'], -+ } -+ -+ grains_mock = {'os': 'Linux'} -+ opts_mock = {'test': True} -+ salt_mock = { -+ 'mount.set_fstab': MagicMock(return_value='error') -+ } -+ with patch.dict(mount.__grains__, grains_mock), \ -+ patch.dict(mount.__opts__, opts_mock), \ -+ patch.dict(mount.__salt__, salt_mock): -+ assert mount.fstab_present('/dev/sda1', '/home', 'ext2') == ret -+ salt_mock['mount.set_fstab'].assert_called_with(name='/home', -+ device='/dev/sda1', -+ fstype='ext2', -+ opts='defaults', -+ dump=0, -+ pass_num=0, -+ config='/etc/fstab', -+ test=True, -+ match_on='auto', -+ not_change=False) -+ -+ def test_fstab_present_macos_present(self): -+ ''' -+ Test fstab_present -+ ''' -+ ret = { -+ 'name': '/dev/sda1', -+ 'result': True, -+ 'changes': {}, -+ 'comment': ['/home entry was already in /etc/auto_salt.'], -+ } -+ -+ grains_mock = {'os': 'MacOS'} -+ opts_mock = {'test': False} -+ salt_mock = { -+ 'mount.set_automaster': MagicMock(return_value='present') -+ } -+ with patch.dict(mount.__grains__, grains_mock), \ -+ patch.dict(mount.__opts__, opts_mock), \ -+ patch.dict(mount.__salt__, salt_mock): -+ assert mount.fstab_present('/dev/sda1', '/home', 'ext2') == ret -+ salt_mock['mount.set_automaster'].assert_called_with(name='/home', -+ device='/dev/sda1', -+ fstype='ext2', -+ opts='noowners', -+ config='/etc/auto_salt', -+ not_change=False) -+ -+ def test_fstab_present_aix_present(self): -+ ''' -+ Test fstab_present -+ ''' -+ ret = { -+ 'name': '/dev/sda1', -+ 'result': True, -+ 'changes': {}, -+ 'comment': ['/home entry was already in /etc/filesystems.'], -+ } -+ -+ grains_mock = {'os': 'AIX'} -+ opts_mock = {'test': False} -+ salt_mock = { -+ 'mount.set_filesystems': MagicMock(return_value='present') -+ } -+ with patch.dict(mount.__grains__, grains_mock), \ -+ patch.dict(mount.__opts__, opts_mock), \ -+ patch.dict(mount.__salt__, salt_mock): -+ assert mount.fstab_present('/dev/sda1', '/home', 'ext2') == ret -+ salt_mock['mount.set_filesystems'].assert_called_with(name='/home', -+ device='/dev/sda1', -+ fstype='ext2', -+ mount=True, -+ opts='', -+ config='/etc/filesystems', -+ match_on='auto', -+ not_change=False) -+ -+ def test_fstab_present_present(self): -+ ''' -+ Test fstab_present -+ ''' -+ ret = { -+ 'name': '/dev/sda1', -+ 'result': True, -+ 'changes': {}, -+ 'comment': ['/home entry was already in /etc/fstab.'], -+ } -+ -+ grains_mock = {'os': 'Linux'} -+ opts_mock = {'test': False} -+ salt_mock = { -+ 'mount.set_fstab': MagicMock(return_value='present') -+ } -+ with patch.dict(mount.__grains__, grains_mock), \ -+ patch.dict(mount.__opts__, opts_mock), \ -+ patch.dict(mount.__salt__, salt_mock): -+ assert mount.fstab_present('/dev/sda1', '/home', 'ext2') == ret -+ salt_mock['mount.set_fstab'].assert_called_with(name='/home', -+ device='/dev/sda1', -+ fstype='ext2', -+ opts='defaults', -+ dump=0, -+ pass_num=0, -+ config='/etc/fstab', -+ match_on='auto', -+ not_change=False) -+ -+ def test_fstab_present_new(self): -+ ''' -+ Test fstab_present -+ ''' -+ ret = { -+ 'name': '/dev/sda1', -+ 'result': True, -+ 'changes': {'persist': 'new'}, -+ 'comment': ['/home entry added in /etc/fstab.'], -+ } -+ -+ grains_mock = {'os': 'Linux'} -+ opts_mock = {'test': False} -+ salt_mock = { -+ 'mount.set_fstab': MagicMock(return_value='new') -+ } -+ with patch.dict(mount.__grains__, grains_mock), \ -+ patch.dict(mount.__opts__, opts_mock), \ -+ patch.dict(mount.__salt__, salt_mock): -+ assert mount.fstab_present('/dev/sda1', '/home', 'ext2') == ret -+ salt_mock['mount.set_fstab'].assert_called_with(name='/home', -+ device='/dev/sda1', -+ fstype='ext2', -+ opts='defaults', -+ dump=0, -+ pass_num=0, -+ config='/etc/fstab', -+ match_on='auto', -+ not_change=False) -+ -+ def test_fstab_present_change(self): -+ ''' -+ Test fstab_present -+ ''' -+ ret = { -+ 'name': '/dev/sda1', -+ 'result': True, -+ 'changes': {'persist': 'change'}, -+ 'comment': ['/home entry updated in /etc/fstab.'], -+ } -+ -+ grains_mock = {'os': 'Linux'} -+ opts_mock = {'test': False} -+ salt_mock = { -+ 'mount.set_fstab': MagicMock(return_value='change') -+ } -+ with patch.dict(mount.__grains__, grains_mock), \ -+ patch.dict(mount.__opts__, opts_mock), \ -+ patch.dict(mount.__salt__, salt_mock): -+ assert mount.fstab_present('/dev/sda1', '/home', 'ext2') == ret -+ salt_mock['mount.set_fstab'].assert_called_with(name='/home', -+ device='/dev/sda1', -+ fstype='ext2', -+ opts='defaults', -+ dump=0, -+ pass_num=0, -+ config='/etc/fstab', -+ match_on='auto', -+ not_change=False) -+ -+ def test_fstab_present_fail(self): -+ ''' -+ Test fstab_present -+ ''' -+ ret = { -+ 'name': '/dev/sda1', -+ 'result': False, -+ 'changes': {}, -+ 'comment': ['/home entry cannot be changed in /etc/fstab: error.'], -+ } -+ -+ grains_mock = {'os': 'Linux'} -+ opts_mock = {'test': False} -+ salt_mock = { -+ 'mount.set_fstab': MagicMock(return_value='error') -+ } -+ with patch.dict(mount.__grains__, grains_mock), \ -+ patch.dict(mount.__opts__, opts_mock), \ -+ patch.dict(mount.__salt__, salt_mock): -+ assert mount.fstab_present('/dev/sda1', '/home', 'ext2') == ret -+ salt_mock['mount.set_fstab'].assert_called_with(name='/home', -+ device='/dev/sda1', -+ fstype='ext2', -+ opts='defaults', -+ dump=0, -+ pass_num=0, -+ config='/etc/fstab', -+ match_on='auto', -+ not_change=False) -+ -+ def test_fstab_absent_macos_test_absent(self): -+ ''' -+ Test fstab_absent -+ ''' -+ ret = { -+ 'name': '/dev/sda1', -+ 'result': None, -+ 'changes': {}, -+ 'comment': ['/home entry is already missing in /etc/auto_salt.'], -+ } -+ -+ grains_mock = {'os': 'MacOS'} -+ opts_mock = {'test': True} -+ salt_mock = { -+ 'mount.automaster': MagicMock(return_value={}) -+ } -+ with patch.dict(mount.__grains__, grains_mock), \ -+ patch.dict(mount.__opts__, opts_mock), \ -+ patch.dict(mount.__salt__, salt_mock): -+ assert mount.fstab_absent('/dev/sda1', '/home') == ret -+ salt_mock['mount.automaster'].assert_called_with('/etc/auto_salt') -+ -+ def test_fstab_absent_aix_test_absent(self): -+ ''' -+ Test fstab_absent -+ ''' -+ ret = { -+ 'name': '/dev/sda1', -+ 'result': None, -+ 'changes': {}, -+ 'comment': ['/home entry is already missing in /etc/filesystems.'], -+ } -+ -+ grains_mock = {'os': 'AIX'} -+ opts_mock = {'test': True} -+ salt_mock = { -+ 'mount.filesystems': MagicMock(return_value={}) -+ } -+ with patch.dict(mount.__grains__, grains_mock), \ -+ patch.dict(mount.__opts__, opts_mock), \ -+ patch.dict(mount.__salt__, salt_mock): -+ assert mount.fstab_absent('/dev/sda1', '/home') == ret -+ salt_mock['mount.filesystems'].assert_called_with('/etc/filesystems') -+ -+ def test_fstab_absent_test_absent(self): -+ ''' -+ Test fstab_absent -+ ''' -+ ret = { -+ 'name': '/dev/sda1', -+ 'result': None, -+ 'changes': {}, -+ 'comment': ['/home entry is already missing in /etc/fstab.'], -+ } -+ -+ grains_mock = {'os': 'Linux'} -+ opts_mock = {'test': True} -+ salt_mock = { -+ 'mount.fstab': MagicMock(return_value={}) -+ } -+ with patch.dict(mount.__grains__, grains_mock), \ -+ patch.dict(mount.__opts__, opts_mock), \ -+ patch.dict(mount.__salt__, salt_mock): -+ assert mount.fstab_absent('/dev/sda1', '/home') == ret -+ salt_mock['mount.fstab'].assert_called_with('/etc/fstab') -+ -+ def test_fstab_absent_test_present(self): -+ ''' -+ Test fstab_absent -+ ''' -+ ret = { -+ 'name': '/dev/sda1', -+ 'result': None, -+ 'changes': {}, -+ 'comment': ['/home entry will be removed from /etc/fstab.'], -+ } -+ -+ grains_mock = {'os': 'Linux'} -+ opts_mock = {'test': True} -+ salt_mock = { -+ 'mount.fstab': MagicMock(return_value={'/home': {}}) -+ } -+ with patch.dict(mount.__grains__, grains_mock), \ -+ patch.dict(mount.__opts__, opts_mock), \ -+ patch.dict(mount.__salt__, salt_mock): -+ assert mount.fstab_absent('/dev/sda1', '/home') == ret -+ salt_mock['mount.fstab'].assert_called_with('/etc/fstab') -+ -+ def test_fstab_absent_macos_present(self): -+ ''' -+ Test fstab_absent -+ ''' -+ ret = { -+ 'name': '/dev/sda1', -+ 'result': True, -+ 'changes': {'persist': 'removed'}, -+ 'comment': ['/home entry removed from /etc/auto_salt.'], -+ } -+ -+ grains_mock = {'os': 'MacOS'} -+ opts_mock = {'test': False} -+ salt_mock = { -+ 'mount.automaster': MagicMock(return_value={'/home': {}}), -+ 'mount.rm_automaster': MagicMock(return_value=True) -+ } -+ with patch.dict(mount.__grains__, grains_mock), \ -+ patch.dict(mount.__opts__, opts_mock), \ -+ patch.dict(mount.__salt__, salt_mock): -+ assert mount.fstab_absent('/dev/sda1', '/home') == ret -+ salt_mock['mount.automaster'].assert_called_with('/etc/auto_salt') -+ salt_mock['mount.rm_automaster'].assert_called_with(name='/home', -+ device='/dev/sda1', -+ config='/etc/auto_salt') -+ -+ def test_fstab_absent_aix_present(self): -+ ''' -+ Test fstab_absent -+ ''' -+ ret = { -+ 'name': '/dev/sda1', -+ 'result': True, -+ 'changes': {'persist': 'removed'}, -+ 'comment': ['/home entry removed from /etc/filesystems.'], -+ } -+ -+ grains_mock = {'os': 'AIX'} -+ opts_mock = {'test': False} -+ salt_mock = { -+ 'mount.filesystems': MagicMock(return_value={'/home': {}}), -+ 'mount.rm_filesystems': MagicMock(return_value=True) -+ } -+ with patch.dict(mount.__grains__, grains_mock), \ -+ patch.dict(mount.__opts__, opts_mock), \ -+ patch.dict(mount.__salt__, salt_mock): -+ assert mount.fstab_absent('/dev/sda1', '/home') == ret -+ salt_mock['mount.filesystems'].assert_called_with('/etc/filesystems') -+ salt_mock['mount.rm_filesystems'].assert_called_with(name='/home', -+ device='/dev/sda1', -+ config='/etc/filesystems') -+ -+ def test_fstab_absent_present(self): -+ ''' -+ Test fstab_absent -+ ''' -+ ret = { -+ 'name': '/dev/sda1', -+ 'result': True, -+ 'changes': {'persist': 'removed'}, -+ 'comment': ['/home entry removed from /etc/fstab.'], -+ } -+ -+ grains_mock = {'os': 'Linux'} -+ opts_mock = {'test': False} -+ salt_mock = { -+ 'mount.fstab': MagicMock(return_value={'/home': {}}), -+ 'mount.rm_fstab': MagicMock(return_value=True) -+ } -+ with patch.dict(mount.__grains__, grains_mock), \ -+ patch.dict(mount.__opts__, opts_mock), \ -+ patch.dict(mount.__salt__, salt_mock): -+ assert mount.fstab_absent('/dev/sda1', '/home') == ret -+ salt_mock['mount.fstab'].assert_called_with('/etc/fstab') -+ salt_mock['mount.rm_fstab'].assert_called_with(name='/home', -+ device='/dev/sda1', -+ config='/etc/fstab') -+ -+ def test_fstab_absent_absent(self): -+ ''' -+ Test fstab_absent -+ ''' -+ ret = { -+ 'name': '/dev/sda1', -+ 'result': True, -+ 'changes': {}, -+ 'comment': ['/home entry is already missing in /etc/fstab.'], -+ } -+ -+ grains_mock = {'os': 'Linux'} -+ opts_mock = {'test': False} -+ salt_mock = { -+ 'mount.fstab': MagicMock(return_value={}) -+ } -+ with patch.dict(mount.__grains__, grains_mock), \ -+ patch.dict(mount.__opts__, opts_mock), \ -+ patch.dict(mount.__salt__, salt_mock): -+ assert mount.fstab_absent('/dev/sda1', '/home') == ret -+ salt_mock['mount.fstab'].assert_called_with('/etc/fstab') diff --git a/tests/unit/states/test_pkg.py b/tests/unit/states/test_pkg.py -index 42fe6c6867..d30e064167 100644 +index 174ab65ab8..38f72353fa 100644 --- a/tests/unit/states/test_pkg.py +++ b/tests/unit/states/test_pkg.py -@@ -46,7 +46,7 @@ class PkgTestCase(TestCase, LoaderModuleMockMixin): +@@ -43,7 +43,7 @@ class PkgTestCase(TestCase, LoaderModuleMockMixin): pkgname: pkgver['new'] for pkgname, pkgver in six.iteritems(self.pkgs) }) upgrade = MagicMock(return_value=self.pkgs) @@ -13058,7 +6928,7 @@ index 42fe6c6867..d30e064167 100644 with patch.dict(pkg.__salt__, {'pkg.list_upgrades': list_upgrades, -@@ -55,7 +55,6 @@ class PkgTestCase(TestCase, LoaderModuleMockMixin): +@@ -52,7 +52,6 @@ class PkgTestCase(TestCase, LoaderModuleMockMixin): # Run state with test=false with patch.dict(pkg.__opts__, {'test': False}): @@ -13066,7 +6936,7 @@ index 42fe6c6867..d30e064167 100644 ret = pkg.uptodate('dummy', test=True) self.assertTrue(ret['result']) self.assertDictEqual(ret['changes'], self.pkgs) -@@ -81,7 +80,7 @@ class PkgTestCase(TestCase, LoaderModuleMockMixin): +@@ -78,7 +77,7 @@ class PkgTestCase(TestCase, LoaderModuleMockMixin): pkgname: pkgver['new'] for pkgname, pkgver in six.iteritems(self.pkgs) }) upgrade = MagicMock(return_value=self.pkgs) @@ -13075,7 +6945,7 @@ index 42fe6c6867..d30e064167 100644 with patch.dict(pkg.__salt__, {'pkg.list_upgrades': list_upgrades, -@@ -160,7 +159,7 @@ class PkgTestCase(TestCase, LoaderModuleMockMixin): +@@ -157,7 +156,7 @@ class PkgTestCase(TestCase, LoaderModuleMockMixin): pkgname: pkgver['new'] for pkgname, pkgver in six.iteritems(self.pkgs) }) upgrade = MagicMock(return_value={}) @@ -13085,10 +6955,10 @@ index 42fe6c6867..d30e064167 100644 with patch.dict(pkg.__salt__, {'pkg.list_upgrades': list_upgrades, diff --git a/tests/unit/test_loader.py b/tests/unit/test_loader.py -index dd0ce8e2e2..38dcb18109 100644 +index c0877ff811..fe11cd0681 100644 --- a/tests/unit/test_loader.py +++ b/tests/unit/test_loader.py -@@ -119,6 +119,97 @@ class LazyLoaderTest(TestCase): +@@ -128,6 +128,97 @@ class LazyLoaderTest(TestCase): self.assertTrue(self.module_name + '.not_loaded' not in self.loader) @@ -13186,7 +7056,7 @@ index dd0ce8e2e2..38dcb18109 100644 class LazyLoaderVirtualEnabledTest(TestCase): ''' Test the base loader of salt. -@@ -995,8 +1086,9 @@ class LoaderGlobalsTest(ModuleCase): +@@ -1078,8 +1169,9 @@ class LoaderGlobalsTest(ModuleCase): # Now, test each module! for item in global_vars: diff --git a/re-adding-function-to-test-for-root.patch b/re-adding-function-to-test-for-root.patch new file mode 100644 index 0000000..330b7b7 --- /dev/null +++ b/re-adding-function-to-test-for-root.patch @@ -0,0 +1,29 @@ +From a6792f951f8090d8326de049eb48bb4a11291e06 Mon Sep 17 00:00:00 2001 +From: Jochen Breuer +Date: Fri, 20 Mar 2020 13:58:54 +0100 +Subject: [PATCH] Re-adding function to test for root + +--- + tests/unit/modules/test_rpm_lowpkg.py | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/tests/unit/modules/test_rpm_lowpkg.py b/tests/unit/modules/test_rpm_lowpkg.py +index 54b81f6972..b6cbd9e5cb 100644 +--- a/tests/unit/modules/test_rpm_lowpkg.py ++++ b/tests/unit/modules/test_rpm_lowpkg.py +@@ -18,6 +18,11 @@ from tests.support.mock import ( + import salt.modules.rpm_lowpkg as rpm + + ++def _called_with_root(mock): ++ cmd = ' '.join(mock.call_args[0][0]) ++ return cmd.startswith('rpm --root /') ++ ++ + class RpmTestCase(TestCase, LoaderModuleMockMixin): + ''' + Test cases for salt.modules.rpm +-- +2.16.4 + + diff --git a/read-repo-info-without-using-interpolation-bsc-11356.patch b/read-repo-info-without-using-interpolation-bsc-11356.patch index 5410057..0e4bce2 100644 --- a/read-repo-info-without-using-interpolation-bsc-11356.patch +++ b/read-repo-info-without-using-interpolation-bsc-11356.patch @@ -1,4 +1,4 @@ -From 53f6eb05bb33117483246cdd199c73954c936e19 Mon Sep 17 00:00:00 2001 +From b502d73be38aeb509a6c5324cdc9bb94d7220c0a Mon Sep 17 00:00:00 2001 From: Mihai Dinca Date: Thu, 7 Nov 2019 15:11:49 +0100 Subject: [PATCH] Read repo info without using interpolation @@ -9,10 +9,10 @@ Subject: [PATCH] Read repo info without using interpolation 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/modules/zypperpkg.py b/salt/modules/zypperpkg.py -index a87041aa70..8c1e05c21c 100644 +index 5f3b6d6855..0c15214e5e 100644 --- a/salt/modules/zypperpkg.py +++ b/salt/modules/zypperpkg.py -@@ -1043,7 +1043,7 @@ def _get_repo_info(alias, repos_cfg=None, root=None): +@@ -1045,7 +1045,7 @@ def _get_repo_info(alias, repos_cfg=None, root=None): Get one repo meta-data. ''' try: diff --git a/reintroducing-reverted-changes.patch b/reintroducing-reverted-changes.patch new file mode 100644 index 0000000..2dea6c7 --- /dev/null +++ b/reintroducing-reverted-changes.patch @@ -0,0 +1,31 @@ +From da91692b5a6cc0b895fa2a1a3a6d0c21d9913ebf Mon Sep 17 00:00:00 2001 +From: Jochen Breuer +Date: Wed, 25 Mar 2020 15:18:51 +0100 +Subject: [PATCH] Reintroducing reverted changes + +Reintroducing changes from commit e20362f6f053eaa4144583604e6aac3d62838419 +that got partially reverted by this commit: +https://github.com/openSUSE/salt/commit/d0ef24d113bdaaa29f180031b5da384cffe08c64#diff-820e6ce667fe3afddbc1b9cf1682fdef +--- + tests/unit/modules/test_aptpkg.py | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/tests/unit/modules/test_aptpkg.py b/tests/unit/modules/test_aptpkg.py +index 2224aba9a1..ba1d874e69 100644 +--- a/tests/unit/modules/test_aptpkg.py ++++ b/tests/unit/modules/test_aptpkg.py +@@ -253,7 +253,9 @@ class AptPkgTestCase(TestCase, LoaderModuleMockMixin): + if installed['wget'].get(names[name], False): + installed['wget'][name] = installed['wget'].pop(names[name]) + +- assert aptpkg.info_installed('wget') == installed ++ del installed['wget']['status'] ++ self.assertEqual(aptpkg.info_installed('wget'), installed) ++ self.assertEqual(len(aptpkg.info_installed()), 1) + + @patch('salt.modules.aptpkg.__salt__', {'lowpkg.info': MagicMock(return_value=LOWPKG_INFO)}) + def test_info_installed_attr(self): +-- +2.16.4 + + diff --git a/remove-arch-from-name-when-pkg.list_pkgs-is-called-w.patch b/remove-arch-from-name-when-pkg.list_pkgs-is-called-w.patch index 09d62b2..c6b4310 100644 --- a/remove-arch-from-name-when-pkg.list_pkgs-is-called-w.patch +++ b/remove-arch-from-name-when-pkg.list_pkgs-is-called-w.patch @@ -1,4 +1,4 @@ -From 560910fbf8a500c501032846d6250a1a633137c4 Mon Sep 17 00:00:00 2001 +From dcaf5a98cfb4e4fd874dd0ec17630d8b7650f5f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?= Date: Mon, 19 Nov 2018 11:46:26 +0000 @@ -37,707 +37,228 @@ Remove unnecessary lambda Return None instead empty string for arch and release in pkg.list_pkgs --- - salt/modules/aptpkg.py | 38 +++++++++++ - salt/modules/pkg_resource.py | 20 ++++-- - salt/modules/yumpkg.py | 32 ++++++++- - salt/modules/zypperpkg.py | 29 +++++++- - tests/unit/modules/test_pkg_resource.py | 116 ++++++++++++++++++++++++++++++++ - tests/unit/modules/test_yumpkg.py | 85 ++++++++++++++++++++++- - tests/unit/modules/test_zypperpkg.py | 79 +++++++++++++++++++++- - 7 files changed, 383 insertions(+), 16 deletions(-) + salt/modules/aptpkg.py | 4 +-- + salt/modules/pkg_resource.py | 13 ++++----- + salt/modules/yumpkg.py | 4 +-- + salt/modules/zypperpkg.py | 4 +-- + tests/unit/modules/test_pkg_resource.py | 2 +- + tests/unit/modules/test_yumpkg.py | 51 ++------------------------------- + tests/unit/modules/test_zypperpkg.py | 4 +-- + 7 files changed, 18 insertions(+), 64 deletions(-) diff --git a/salt/modules/aptpkg.py b/salt/modules/aptpkg.py -index 4a331444c9..f51b6958e5 100644 +index 3b0d8423db..345b8422d9 100644 --- a/salt/modules/aptpkg.py +++ b/salt/modules/aptpkg.py -@@ -73,6 +73,7 @@ except ImportError: - # pylint: enable=import-error - - APT_LISTS_PATH = "/var/lib/apt/lists" -+PKG_ARCH_SEPARATOR = ':' - - # Source format for urllib fallback on PPA handling - LP_SRC_FORMAT = 'deb http://ppa.launchpad.net/{0}/{1}/ubuntu {2} main' -@@ -185,6 +186,43 @@ def _warn_software_properties(repo): - log.warning('Best guess at ppa format: %s', repo) +@@ -206,7 +206,7 @@ def normalize_name(name): + return name -+def normalize_name(name): -+ ''' -+ Strips the architecture from the specified package name, if necessary. -+ -+ CLI Example: -+ -+ .. code-block:: bash -+ -+ salt '*' pkg.normalize_name zsh:amd64 -+ ''' -+ try: -+ name, arch = name.rsplit(PKG_ARCH_SEPARATOR, 1) -+ except ValueError: -+ return name -+ return name -+ -+ +-def parse_arch(name): +def parse_arch_from_name(name): -+ ''' -+ Parse name and architecture from the specified package name. -+ -+ CLI Example: -+ -+ .. code-block:: bash -+ -+ salt '*' pkg.parse_arch_from_name zsh:amd64 -+ ''' -+ try: -+ _name, _arch = name.rsplit(PKG_ARCH_SEPARATOR, 1) -+ except ValueError: -+ _name, _arch = name, None -+ return { -+ 'name': _name, -+ 'arch': _arch -+ } -+ -+ - def latest_version(*names, **kwargs): ''' - Return the latest version of the named package available for upgrade or + Parse name and architecture from the specified package name. + +@@ -214,7 +214,7 @@ def parse_arch(name): + + .. code-block:: bash + +- salt '*' pkg.parse_arch zsh:amd64 ++ salt '*' pkg.parse_arch_from_name zsh:amd64 + ''' + try: + _name, _arch = name.rsplit(PKG_ARCH_SEPARATOR, 1) diff --git a/salt/modules/pkg_resource.py b/salt/modules/pkg_resource.py -index 8b83f1cda5..0c872f1805 100644 +index 8fa3a074fa..0c872f1805 100644 --- a/salt/modules/pkg_resource.py +++ b/salt/modules/pkg_resource.py -@@ -311,21 +311,31 @@ def format_pkg_list(packages, versions_as_list, attr): - ''' +@@ -312,18 +312,17 @@ def format_pkg_list(packages, versions_as_list, attr): ret = copy.deepcopy(packages) if attr: + ret_attr = {} - requested_attr = {'epoch', 'version', 'release', 'arch', 'install_date', 'install_date_time_t'} -+ ret_attr = {} + requested_attr = set(['epoch', 'version', 'release', 'arch', + 'install_date', 'install_date_time_t']) if attr != 'all': -- requested_attr &= set(attr + ['version']) -+ requested_attr &= set(attr + ['version'] + ['arch']) + requested_attr &= set(attr + ['version'] + ['arch']) for name in ret: +- if 'pkg.parse_arch' in __salt__: +- _parse_arch = __salt__['pkg.parse_arch'](name) +- else: +- _parse_arch = {'name': name, 'arch': None} +- _name = _parse_arch['name'] +- _arch = _parse_arch['arch'] + _parse_arch_from_name = __salt__.get('pkg.parse_arch_from_name', lambda pkgname: {'name': pkgname, 'arch': None}) + name_arch_d = _parse_arch_from_name(name) + _name = name_arch_d['name'] + _arch = name_arch_d['arch'] -+ - versions = [] -+ pkgname = None - for all_attr in ret[name]: - filtered_attr = {} - for key in requested_attr: -- if all_attr[key]: -+ if key in all_attr: - filtered_attr[key] = all_attr[key] - versions.append(filtered_attr) -- ret[name] = versions -- return ret -+ if _name and filtered_attr.get('arch', None) == _arch: -+ pkgname = _name -+ ret_attr.setdefault(pkgname or name, []).extend(versions) -+ return ret_attr - for name in ret: - ret[name] = [format_version(d['epoch'], d['version'], d['release']) + versions = [] + pkgname = None diff --git a/salt/modules/yumpkg.py b/salt/modules/yumpkg.py -index a56a2e8366..4f26a41670 100644 +index c89d321a1b..b1257d0de0 100644 --- a/salt/modules/yumpkg.py +++ b/salt/modules/yumpkg.py -@@ -66,6 +66,8 @@ log = logging.getLogger(__name__) - - __HOLD_PATTERN = r'[\w+]+(?:[.-][^-]+)*' - -+PKG_ARCH_SEPARATOR = '.' -+ - # Define the module's virtual name - __virtualname__ = 'pkg' - -@@ -429,7 +431,7 @@ def normalize_name(name): - salt '*' pkg.normalize_name zsh.x86_64 - ''' - try: -- arch = name.rsplit('.', 1)[-1] -+ arch = name.rsplit(PKG_ARCH_SEPARATOR, 1)[-1] - if arch not in salt.utils.pkg.rpm.ARCHES + ('noarch',): - return name - except ValueError: -@@ -440,6 +442,30 @@ def normalize_name(name): +@@ -442,7 +442,7 @@ def normalize_name(name): return name +-def parse_arch(name): +def parse_arch_from_name(name): -+ ''' -+ Parse name and architecture from the specified package name. -+ -+ CLI Example: -+ -+ .. code-block:: bash -+ -+ salt '*' pkg.parse_arch_from_name zsh.x86_64 -+ ''' -+ _name, _arch = None, None -+ try: -+ _name, _arch = name.rsplit(PKG_ARCH_SEPARATOR, 1) -+ except ValueError: -+ pass -+ if _arch not in salt.utils.pkg.rpm.ARCHES + ('noarch',): -+ _name = name -+ _arch = None -+ return { -+ 'name': _name, -+ 'arch': _arch -+ } -+ -+ - def latest_version(*names, **kwargs): ''' - Return the latest version of the named package available for upgrade or -@@ -676,8 +702,8 @@ def list_pkgs(versions_as_list=False, **kwargs): - if pkginfo is not None: - # see rpm version string rules available at https://goo.gl/UGKPNd - pkgver = pkginfo.version -- epoch = '' -- release = '' -+ epoch = None -+ release = None - if ':' in pkgver: - epoch, pkgver = pkgver.split(":", 1) - if '-' in pkgver: + Parse name and architecture from the specified package name. + +@@ -450,7 +450,7 @@ def parse_arch(name): + + .. code-block:: bash + +- salt '*' pkg.parse_arch zsh.x86_64 ++ salt '*' pkg.parse_arch_from_name zsh.x86_64 + ''' + _name, _arch = None, None + try: diff --git a/salt/modules/zypperpkg.py b/salt/modules/zypperpkg.py -index 0c26e2214c..92e7052020 100644 +index 08a9c2ed4d..04a6a6872d 100644 --- a/salt/modules/zypperpkg.py +++ b/salt/modules/zypperpkg.py -@@ -53,6 +53,7 @@ ZYPP_HOME = '/etc/zypp' - LOCKS = '{0}/locks'.format(ZYPP_HOME) - REPOS = '{0}/repos.d'.format(ZYPP_HOME) - DEFAULT_PRIORITY = 99 -+PKG_ARCH_SEPARATOR = '.' - - # Define the module's virtual name - __virtualname__ = 'pkg' -@@ -590,6 +591,30 @@ def info_available(*names, **kwargs): +@@ -593,7 +593,7 @@ def info_available(*names, **kwargs): return ret +-def parse_arch(name): +def parse_arch_from_name(name): -+ ''' -+ Parse name and architecture from the specified package name. -+ -+ CLI Example: -+ -+ .. code-block:: bash -+ -+ salt '*' pkg.parse_arch_from_name zsh.x86_64 -+ ''' -+ _name, _arch = None, None -+ try: -+ _name, _arch = name.rsplit(PKG_ARCH_SEPARATOR, 1) -+ except ValueError: -+ pass -+ if _arch not in salt.utils.pkg.rpm.ARCHES + ('noarch',): -+ _name = name -+ _arch = None -+ return { -+ 'name': _name, -+ 'arch': _arch -+ } -+ -+ - def latest_version(*names, **kwargs): ''' - Return the latest version of the named package available for upgrade or -@@ -760,8 +785,8 @@ def list_pkgs(versions_as_list=False, **kwargs): - if pkginfo: - # see rpm version string rules available at https://goo.gl/UGKPNd - pkgver = pkginfo.version -- epoch = '' -- release = '' -+ epoch = None -+ release = None - if ':' in pkgver: - epoch, pkgver = pkgver.split(":", 1) - if '-' in pkgver: + Parse name and architecture from the specified package name. + +@@ -601,7 +601,7 @@ def parse_arch(name): + + .. code-block:: bash + +- salt '*' pkg.parse_arch zsh.x86_64 ++ salt '*' pkg.parse_arch_from_name zsh.x86_64 + ''' + _name, _arch = None, None + try: diff --git a/tests/unit/modules/test_pkg_resource.py b/tests/unit/modules/test_pkg_resource.py -index b6d90cc92c..a9ffe43cdd 100644 +index 6bb647082c..d5ccb2a7a2 100644 --- a/tests/unit/modules/test_pkg_resource.py +++ b/tests/unit/modules/test_pkg_resource.py -@@ -129,6 +129,122 @@ class PkgresTestCase(TestCase, LoaderModuleMockMixin): - ''' - self.assertIsNone(pkg_resource.sort_pkglist({})) - -+ def test_format_pkg_list_no_attr(self): -+ ''' -+ Test to output format of the package list with no attr parameter. -+ ''' -+ packages = { -+ 'glibc': [{'version': '2.12', 'epoch': None, 'release': '1.212.el6', 'arch': 'x86_64'}], -+ 'glibc.i686': [{'version': '2.12', 'epoch': None, 'release': '1.212.el6', 'arch': 'i686'}], -+ 'foobar': [ -+ {'version': '1.2.0', 'epoch': '2', 'release': '7', 'arch': 'x86_64'}, -+ {'version': '1.2.3', 'epoch': '2', 'release': '27', 'arch': 'x86_64'}, -+ ], -+ 'foobar.something': [{'version': '1.1', 'epoch': '3', 'release': '23.1', 'arch': 'i686'}], -+ 'foobar.': [{'version': '1.1', 'epoch': '3', 'release': '23.1', 'arch': 'i686'}] -+ } -+ expected_pkg_list = { -+ 'glibc': '2.12-1.212.el6', -+ 'glibc.i686': '2.12-1.212.el6', -+ 'foobar': '2:1.2.0-7,2:1.2.3-27', -+ 'foobar.something': '3:1.1-23.1', -+ 'foobar.': '3:1.1-23.1', -+ } -+ if six.PY3: -+ self.assertCountEqual(pkg_resource.format_pkg_list(packages, False, None), expected_pkg_list) -+ else: -+ self.assertItemsEqual(pkg_resource.format_pkg_list(packages, False, None), expected_pkg_list) -+ -+ def test_format_pkg_list_with_attr(self): -+ ''' -+ Test to output format of the package list with attr parameter. -+ In this case, any redundant "arch" reference will be removed from the package name since it's -+ include as part of the requested attr. -+ ''' -+ NAME_ARCH_MAPPING = { -+ 'glibc': { -+ 'name': 'glibc', -+ 'arch': None -+ }, -+ 'glibc.i686': { -+ 'name': 'glibc', -+ 'arch': 'i686' -+ }, -+ 'foobar': { -+ 'name': 'foobar', -+ 'arch': None -+ }, -+ 'foobar.something': { -+ 'name': 'foobar.something', -+ 'arch': None -+ }, -+ 'foobar.': { -+ 'name': 'foobar.', -+ 'arch': None -+ } -+ } -+ packages = { -+ 'glibc': [{'version': '2.12', 'epoch': None, 'release': '1.212.el6', 'arch': 'x86_64'}], -+ 'glibc.i686': [{'version': '2.12', 'epoch': None, 'release': '1.212.el6', 'arch': 'i686'}], -+ 'foobar': [ -+ {'version': '1.2.0', 'epoch': '2', 'release': '7', 'arch': 'x86_64'}, -+ {'version': '1.2.3', 'epoch': '2', 'release': '27', 'arch': 'x86_64'}, -+ ], -+ 'foobar.something': [{'version': '1.1', 'epoch': '3', 'release': '23.1', 'arch': 'i686'}], -+ 'foobar.': [{'version': '1.1', 'epoch': '3', 'release': '23.1', 'arch': 'i686'}] -+ } -+ expected_pkg_list = { -+ 'glibc': [ -+ { -+ 'arch': 'x86_64', -+ 'release': '1.212.el6', -+ 'epoch': None, -+ 'version': '2.12' -+ }, -+ { -+ 'arch': 'i686', -+ 'release': '1.212.el6', -+ 'epoch': None, -+ 'version': '2.12' -+ } -+ ], -+ 'foobar': [ -+ { -+ 'arch': 'x86_64', -+ 'release': '7', -+ 'epoch': '2', -+ 'version': '1.2.0' -+ }, -+ { -+ 'arch': 'x86_64', -+ 'release': '27', -+ 'epoch': '2', -+ 'version': '1.2.3' -+ } -+ ], -+ 'foobar.': [ -+ { -+ 'arch': 'i686', -+ 'release': '23.1', -+ 'epoch': '3', -+ 'version': '1.1' -+ } -+ ], -+ 'foobar.something': [ -+ { -+ 'arch': 'i686', -+ 'release': '23.1', -+ 'epoch': '3', -+ 'version': '1.1' -+ } -+ ] -+ } +@@ -236,7 +236,7 @@ class PkgresTestCase(TestCase, LoaderModuleMockMixin): + } + ] + } +- with patch.dict(pkg_resource.__salt__, {'pkg.parse_arch': NAME_ARCH_MAPPING.get}): + with patch.dict(pkg_resource.__salt__, {'pkg.parse_arch_from_name': NAME_ARCH_MAPPING.get}): -+ if six.PY3: -+ self.assertCountEqual(pkg_resource.format_pkg_list(packages, False, attr=['epoch', 'release']), expected_pkg_list) -+ else: -+ self.assertItemsEqual(pkg_resource.format_pkg_list(packages, False, attr=['epoch', 'release']), expected_pkg_list) -+ - def test_stringify(self): - ''' - Test to takes a dict of package name/version information + if six.PY3: + self.assertCountEqual(pkg_resource.format_pkg_list(packages, False, attr=['epoch', 'release']), expected_pkg_list) + else: diff --git a/tests/unit/modules/test_yumpkg.py b/tests/unit/modules/test_yumpkg.py -index 6113d3a4b1..6019a8179e 100644 +index 5e652b7e53..9fbe3d051e 100644 --- a/tests/unit/modules/test_yumpkg.py +++ b/tests/unit/modules/test_yumpkg.py -@@ -18,6 +18,7 @@ from tests.support.mock import ( - # Import Salt libs - from salt.exceptions import CommandExecutionError - import salt.modules.rpm_lowpkg as rpm -+from salt.ext import six - import salt.modules.yumpkg as yumpkg - import salt.modules.pkg_resource as pkg_resource - -@@ -76,7 +77,8 @@ class YumTestCase(TestCase, LoaderModuleMockMixin): - 'os_family': 'RedHat', - 'osmajorrelease': 7, - }, -- } -+ }, -+ pkg_resource: {} - } - - def test_list_pkgs(self): -@@ -107,7 +109,8 @@ class YumTestCase(TestCase, LoaderModuleMockMixin): - patch.dict(yumpkg.__salt__, {'cmd.run': MagicMock(return_value=os.linesep.join(rpm_out))}), \ +@@ -107,7 +107,7 @@ class YumTestCase(TestCase, LoaderModuleMockMixin): patch.dict(yumpkg.__salt__, {'pkg_resource.add_pkg': _add_data}), \ patch.dict(yumpkg.__salt__, {'pkg_resource.format_pkg_list': pkg_resource.format_pkg_list}), \ -- patch.dict(yumpkg.__salt__, {'pkg_resource.stringify': MagicMock()}): -+ patch.dict(yumpkg.__salt__, {'pkg_resource.stringify': MagicMock()}), \ + patch.dict(yumpkg.__salt__, {'pkg_resource.stringify': MagicMock()}), \ +- patch.dict(pkg_resource.__salt__, {'pkg.parse_arch': yumpkg.parse_arch}): + patch.dict(pkg_resource.__salt__, {'pkg.parse_arch_from_name': yumpkg.parse_arch_from_name}): pkgs = yumpkg.list_pkgs(versions_as_list=True) for pkg_name, pkg_version in { 'python-urlgrabber': '3.10-8.el7', -@@ -154,7 +157,8 @@ class YumTestCase(TestCase, LoaderModuleMockMixin): - patch.dict(yumpkg.__salt__, {'cmd.run': MagicMock(return_value=os.linesep.join(rpm_out))}), \ +@@ -155,7 +155,7 @@ class YumTestCase(TestCase, LoaderModuleMockMixin): patch.dict(yumpkg.__salt__, {'pkg_resource.add_pkg': _add_data}), \ patch.dict(yumpkg.__salt__, {'pkg_resource.format_pkg_list': pkg_resource.format_pkg_list}), \ -- patch.dict(yumpkg.__salt__, {'pkg_resource.stringify': MagicMock()}): -+ patch.dict(yumpkg.__salt__, {'pkg_resource.stringify': MagicMock()}), \ + patch.dict(yumpkg.__salt__, {'pkg_resource.stringify': MagicMock()}), \ +- patch.dict(pkg_resource.__salt__, {'pkg.parse_arch': yumpkg.parse_arch}): + patch.dict(pkg_resource.__salt__, {'pkg.parse_arch_from_name': yumpkg.parse_arch_from_name}): pkgs = yumpkg.list_pkgs(attr=['epoch', 'release', 'arch', 'install_date_time_t']) for pkg_name, pkg_attr in { 'python-urlgrabber': { -@@ -162,54 +166,63 @@ class YumTestCase(TestCase, LoaderModuleMockMixin): - 'release': '8.el7', - 'arch': 'noarch', - 'install_date_time_t': 1487838471, -+ 'epoch': None - }, - 'alsa-lib': { - 'version': '1.1.1', - 'release': '1.el7', - 'arch': 'x86_64', - 'install_date_time_t': 1487838475, -+ 'epoch': None - }, - 'gnupg2': { - 'version': '2.0.22', - 'release': '4.el7', - 'arch': 'x86_64', - 'install_date_time_t': 1487838477, -+ 'epoch': None - }, - 'rpm-python': { - 'version': '4.11.3', - 'release': '21.el7', - 'arch': 'x86_64', - 'install_date_time_t': 1487838477, -+ 'epoch': None - }, - 'pygpgme': { - 'version': '0.3', - 'release': '9.el7', - 'arch': 'x86_64', - 'install_date_time_t': 1487838478, -+ 'epoch': None - }, - 'yum': { - 'version': '3.4.3', - 'release': '150.el7.centos', - 'arch': 'noarch', - 'install_date_time_t': 1487838479, -+ 'epoch': None - }, - 'lzo': { - 'version': '2.06', - 'release': '8.el7', - 'arch': 'x86_64', - 'install_date_time_t': 1487838479, -+ 'epoch': None - }, - 'qrencode-libs': { - 'version': '3.4.1', - 'release': '3.el7', - 'arch': 'x86_64', - 'install_date_time_t': 1487838480, -+ 'epoch': None - }, - 'ustr': { - 'version': '1.0.4', - 'release': '16.el7', - 'arch': 'x86_64', - 'install_date_time_t': 1487838480, -+ 'epoch': None - }, - 'shadow-utils': { - 'epoch': '2', -@@ -223,22 +236,88 @@ class YumTestCase(TestCase, LoaderModuleMockMixin): - 'release': '33.el7', - 'arch': 'x86_64', - 'install_date_time_t': 1487838484, -+ 'epoch': None - }, - 'openssh': { - 'version': '6.6.1p1', - 'release': '33.el7_3', - 'arch': 'x86_64', - 'install_date_time_t': 1487838485, -+ 'epoch': None - }, - 'virt-what': { - 'version': '1.13', - 'release': '8.el7', - 'install_date_time_t': 1487838486, - 'arch': 'x86_64', -+ 'epoch': None - }}.items(): -+ - self.assertTrue(pkgs.get(pkg_name)) - self.assertEqual(pkgs[pkg_name], [pkg_attr]) - -+ def test_list_pkgs_with_attr_multiple_versions(self): -+ ''' -+ Test packages listing with the attr parameter reporting multiple version installed -+ -+ :return: -+ ''' -+ def _add_data(data, key, value): -+ data.setdefault(key, []).append(value) -+ -+ rpm_out = [ -+ 'glibc_|-(none)_|-2.12_|-1.212.el6_|-i686_|-(none)_|-1542394210' -+ 'glibc_|-(none)_|-2.12_|-1.212.el6_|-x86_64_|-(none)_|-1542394204', -+ 'virt-what_|-(none)_|-1.13_|-8.el7_|-x86_64_|-(none)_|-1487838486', -+ 'virt-what_|-(none)_|-1.10_|-2.el7_|-x86_64_|-(none)_|-1387838486', -+ ] -+ with patch.dict(yumpkg.__grains__, {'osarch': 'x86_64'}), \ -+ patch.dict(yumpkg.__salt__, {'cmd.run': MagicMock(return_value=os.linesep.join(rpm_out))}), \ -+ patch.dict(yumpkg.__salt__, {'pkg_resource.add_pkg': _add_data}), \ -+ patch.dict(yumpkg.__salt__, {'pkg_resource.format_pkg_list': pkg_resource.format_pkg_list}), \ -+ patch.dict(yumpkg.__salt__, {'pkg_resource.stringify': MagicMock()}), \ +@@ -273,7 +273,7 @@ class YumTestCase(TestCase, LoaderModuleMockMixin): + patch.dict(yumpkg.__salt__, {'pkg_resource.add_pkg': _add_data}), \ + patch.dict(yumpkg.__salt__, {'pkg_resource.format_pkg_list': pkg_resource.format_pkg_list}), \ + patch.dict(yumpkg.__salt__, {'pkg_resource.stringify': MagicMock()}), \ +- patch.dict(pkg_resource.__salt__, {'pkg.parse_arch': yumpkg.parse_arch}): + patch.dict(pkg_resource.__salt__, {'pkg.parse_arch_from_name': yumpkg.parse_arch_from_name}): -+ pkgs = yumpkg.list_pkgs(attr=['epoch', 'release', 'arch', 'install_date_time_t']) -+ expected_pkg_list = { -+ 'glibc': [ -+ { -+ 'version': '2.12', -+ 'release': '1.212.el6', -+ 'install_date_time_t': 1542394210, -+ 'arch': 'i686', -+ 'epoch': None -+ }, -+ { -+ 'version': '2.12', -+ 'release': '1.212.el6', -+ 'install_date_time_t': 1542394204, -+ 'arch': 'x86_64', -+ 'epoch': None -+ } -+ ], -+ 'virt-what': [ -+ { -+ 'version': '1.10', -+ 'release': '2.el7', -+ 'install_date_time_t': 1387838486, -+ 'arch': 'x86_64', -+ 'epoch': None -+ }, -+ { -+ 'version': '1.13', -+ 'release': '8.el7', -+ 'install_date_time_t': 1487838486, -+ 'arch': 'x86_64', -+ 'epoch': None -+ } -+ ] -+ } -+ for pkgname, pkginfo in pkgs.items(): -+ if six.PY3: -+ self.assertCountEqual(pkginfo, expected_pkg_list[pkgname]) -+ else: -+ self.assertItemsEqual(pkginfo, expected_pkg_list[pkgname]) -+ + pkgs = yumpkg.list_pkgs(attr=['epoch', 'release', 'arch', 'install_date_time_t']) + expected_pkg_list = { + 'glibc': [ +@@ -315,51 +315,6 @@ class YumTestCase(TestCase, LoaderModuleMockMixin): + else: + self.assertItemsEqual(pkginfo, expected_pkg_list[pkgname]) + +- def test_list_patches(self): +- ''' +- Test patches listing. +- +- :return: +- ''' +- yum_out = [ +- 'i my-fake-patch-not-installed-1234 recommended spacewalk-usix-2.7.5.2-2.2.noarch', +- ' my-fake-patch-not-installed-1234 recommended spacewalksd-5.0.26.2-21.2.x86_64', +- 'i my-fake-patch-not-installed-1234 recommended suseRegisterInfo-3.1.1-18.2.x86_64', +- 'i my-fake-patch-installed-1234 recommended my-package-one-1.1-0.1.x86_64', +- 'i my-fake-patch-installed-1234 recommended my-package-two-1.1-0.1.x86_64', +- ] +- +- expected_patches = { +- 'my-fake-patch-not-installed-1234': { +- 'installed': False, +- 'summary': [ +- 'spacewalk-usix-2.7.5.2-2.2.noarch', +- 'spacewalksd-5.0.26.2-21.2.x86_64', +- 'suseRegisterInfo-3.1.1-18.2.x86_64', +- ] +- }, +- 'my-fake-patch-installed-1234': { +- 'installed': True, +- 'summary': [ +- 'my-package-one-1.1-0.1.x86_64', +- 'my-package-two-1.1-0.1.x86_64', +- ] +- } +- } +- +- with patch.dict(yumpkg.__grains__, {'osarch': 'x86_64'}), \ +- patch.dict(yumpkg.__salt__, {'cmd.run_stdout': MagicMock(return_value=os.linesep.join(yum_out))}): +- patches = yumpkg.list_patches() +- self.assertFalse(patches['my-fake-patch-not-installed-1234']['installed']) +- self.assertTrue(len(patches['my-fake-patch-not-installed-1234']['summary']) == 3) +- for _patch in expected_patches['my-fake-patch-not-installed-1234']['summary']: +- self.assertTrue(_patch in patches['my-fake-patch-not-installed-1234']['summary']) +- +- self.assertTrue(patches['my-fake-patch-installed-1234']['installed']) +- self.assertTrue(len(patches['my-fake-patch-installed-1234']['summary']) == 2) +- for _patch in expected_patches['my-fake-patch-installed-1234']['summary']: +- self.assertTrue(_patch in patches['my-fake-patch-installed-1234']['summary']) +- def test_latest_version_with_options(self): with patch.object(yumpkg, 'list_pkgs', MagicMock(return_value={})): diff --git a/tests/unit/modules/test_zypperpkg.py b/tests/unit/modules/test_zypperpkg.py -index 3259e1810d..f586c23fd0 100644 +index 78414ca4ac..b3162f10cd 100644 --- a/tests/unit/modules/test_zypperpkg.py +++ b/tests/unit/modules/test_zypperpkg.py -@@ -61,7 +61,7 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin): - ''' - - def setup_loader_modules(self): -- return {zypper: {'rpm': None}} -+ return {zypper: {'rpm': None}, pkg_resource: {}} - - def setUp(self): - self.new_repo_config = dict( -@@ -605,7 +605,8 @@ Repository 'DUMMY' not found by its alias, number, or URI. - patch.dict(zypper.__grains__, {'osarch': 'x86_64'}), \ +@@ -607,7 +607,7 @@ Repository 'DUMMY' not found by its alias, number, or URI. patch.dict(zypper.__salt__, {'pkg_resource.add_pkg': _add_data}), \ patch.dict(zypper.__salt__, {'pkg_resource.format_pkg_list': pkg_resource.format_pkg_list}), \ -- patch.dict(zypper.__salt__, {'pkg_resource.stringify': MagicMock()}): -+ patch.dict(zypper.__salt__, {'pkg_resource.stringify': MagicMock()}), \ + patch.dict(zypper.__salt__, {'pkg_resource.stringify': MagicMock()}), \ +- patch.dict(pkg_resource.__salt__, {'pkg.parse_arch': zypper.parse_arch}): + patch.dict(pkg_resource.__salt__, {'pkg.parse_arch_from_name': zypper.parse_arch_from_name}): pkgs = zypper.list_pkgs(attr=['epoch', 'release', 'arch', 'install_date_time_t']) self.assertFalse(pkgs.get('gpg-pubkey', False)) for pkg_name, pkg_attr in { -@@ -614,58 +615,130 @@ Repository 'DUMMY' not found by its alias, number, or URI. - 'release': '129.686', - 'arch': 'noarch', - 'install_date_time_t': 1498636511, -+ 'epoch': None, - }], - 'yast2-ftp-server': [{ - 'version': '3.1.8', - 'release': '8.1', - 'arch': 'x86_64', - 'install_date_time_t': 1499257798, -+ 'epoch': None, - }], - 'protobuf-java': [{ - 'version': '2.6.1', - 'release': '3.1.develHead', - 'install_date_time_t': 1499257756, - 'arch': 'noarch', -+ 'epoch': None, - }], - 'susemanager-build-keys-web': [{ - 'version': '12.0', - 'release': '5.1.develHead', - 'arch': 'noarch', - 'install_date_time_t': 1498636510, -+ 'epoch': None, - }], - 'apache-commons-cli': [{ - 'version': '1.2', - 'release': '1.233', - 'arch': 'noarch', - 'install_date_time_t': 1498636510, -+ 'epoch': None, - }], - 'kernel-default': [{ - 'version': '4.4.138', - 'release': '94.39.1', - 'arch': 'x86_64', -- 'install_date_time_t': 1529936067 -+ 'install_date_time_t': 1529936067, -+ 'epoch': None, - }, - { - 'version': '4.4.73', - 'release': '5.1', - 'arch': 'x86_64', - 'install_date_time_t': 1503572639, -+ 'epoch': None, - }], - 'perseus-dummy.i586': [{ - 'version': '1.1', - 'release': '1.1', - 'arch': 'i586', - 'install_date_time_t': 1529936062, -+ 'epoch': None, - }], - 'jose4j': [{ - 'arch': 'noarch', - 'version': '0.4.4', - 'release': '2.1.develHead', - 'install_date_time_t': 1499257756, -+ 'epoch': None, - }]}.items(): - self.assertTrue(pkgs.get(pkg_name)) - self.assertEqual(pkgs[pkg_name], pkg_attr) - -+ def test_list_pkgs_with_attr_multiple_versions(self): -+ ''' -+ Test packages listing with the attr parameter reporting multiple version installed -+ -+ :return: -+ ''' -+ def _add_data(data, key, value): -+ data.setdefault(key, []).append(value) -+ -+ rpm_out = [ -+ 'glibc_|-2.12_|-1.212.el6_|-i686_|-_|-1542394210', -+ 'glibc_|-2.12_|-1.212.el6_|-x86_64_|-_|-1542394204', -+ 'virt-what_|-1.13_|-8.el7_|-x86_64_|-_|-1487838486', -+ 'virt-what_|-1.10_|-2.el7_|-x86_64_|-_|-1387838486', -+ ] -+ -+ with patch.dict(zypper.__grains__, {'osarch': 'x86_64'}), \ -+ patch.dict(zypper.__salt__, {'cmd.run': MagicMock(return_value=os.linesep.join(rpm_out))}), \ -+ patch.dict(zypper.__salt__, {'pkg_resource.add_pkg': _add_data}), \ -+ patch.dict(zypper.__salt__, {'pkg_resource.format_pkg_list': pkg_resource.format_pkg_list}), \ -+ patch.dict(zypper.__salt__, {'pkg_resource.stringify': MagicMock()}), \ +@@ -698,7 +698,7 @@ Repository 'DUMMY' not found by its alias, number, or URI. + patch.dict(zypper.__salt__, {'pkg_resource.add_pkg': _add_data}), \ + patch.dict(zypper.__salt__, {'pkg_resource.format_pkg_list': pkg_resource.format_pkg_list}), \ + patch.dict(zypper.__salt__, {'pkg_resource.stringify': MagicMock()}), \ +- patch.dict(pkg_resource.__salt__, {'pkg.parse_arch': zypper.parse_arch}): + patch.dict(pkg_resource.__salt__, {'pkg.parse_arch_from_name': zypper.parse_arch_from_name}): -+ pkgs = zypper.list_pkgs(attr=['epoch', 'release', 'arch', 'install_date_time_t']) -+ expected_pkg_list = { -+ 'glibc': [ -+ { -+ 'version': '2.12', -+ 'release': '1.212.el6', -+ 'install_date_time_t': 1542394210, -+ 'arch': 'i686', -+ 'epoch': None -+ }, -+ { -+ 'version': '2.12', -+ 'release': '1.212.el6', -+ 'install_date_time_t': 1542394204, -+ 'arch': 'x86_64', -+ 'epoch': None -+ } -+ ], -+ 'virt-what': [ -+ { -+ 'version': '1.10', -+ 'release': '2.el7', -+ 'install_date_time_t': 1387838486, -+ 'arch': 'x86_64', -+ 'epoch': None -+ }, -+ { -+ 'version': '1.13', -+ 'release': '8.el7', -+ 'install_date_time_t': 1487838486, -+ 'arch': 'x86_64', -+ 'epoch': None -+ } -+ ] -+ } -+ for pkgname, pkginfo in pkgs.items(): -+ if six.PY3: -+ self.assertCountEqual(pkginfo, expected_pkg_list[pkgname]) -+ else: -+ self.assertItemsEqual(pkginfo, expected_pkg_list[pkgname]) -+ - def test_list_patches(self): - ''' - Test advisory patches listing. + pkgs = zypper.list_pkgs(attr=['epoch', 'release', 'arch', 'install_date_time_t']) + expected_pkg_list = { + 'glibc': [ -- 2.16.4 diff --git a/remove-deprecated-usage-of-no_mock-and-no_mock_reaso.patch b/remove-deprecated-usage-of-no_mock-and-no_mock_reaso.patch new file mode 100644 index 0000000..daf6bd0 --- /dev/null +++ b/remove-deprecated-usage-of-no_mock-and-no_mock_reaso.patch @@ -0,0 +1,221 @@ +From 25b4e3ea983b2606b2fb3d3c0e42f9840208bf84 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?= + +Date: Wed, 11 Mar 2020 16:14:16 +0000 +Subject: [PATCH] Remove deprecated usage of NO_MOCK and NO_MOCK_REASON + +--- + tests/integration/pillar/test_git_pillar.py | 1 - + tests/unit/cli/test_batch_async.py | 3 +-- + tests/unit/cli/test_support.py | 6 +----- + tests/unit/modules/test_cmdmod.py | 1 - + tests/unit/modules/test_kubeadm.py | 5 +---- + tests/unit/modules/test_saltsupport.py | 4 +--- + tests/unit/modules/test_xfs.py | 3 --- + tests/unit/states/test_btrfs.py | 3 --- + tests/unit/utils/test_pkg.py | 3 +-- + 9 files changed, 5 insertions(+), 24 deletions(-) + +diff --git a/tests/integration/pillar/test_git_pillar.py b/tests/integration/pillar/test_git_pillar.py +index d417a7ebc3..9218f28d15 100644 +--- a/tests/integration/pillar/test_git_pillar.py ++++ b/tests/integration/pillar/test_git_pillar.py +@@ -1383,7 +1383,6 @@ class TestPygit2SSH(GitPillarSSHTestBase): + ) + + +-@skipIf(NO_MOCK, NO_MOCK_REASON) + @skipIf(_windows_or_mac(), 'minion is windows or mac') + @skip_if_not_root + @skipIf(not HAS_PYGIT2, 'pygit2 >= {0} and libgit2 >= {1} required'.format(PYGIT2_MINVER, LIBGIT2_MINVER)) +diff --git a/tests/unit/cli/test_batch_async.py b/tests/unit/cli/test_batch_async.py +index 635dc689a8..0c66550d5b 100644 +--- a/tests/unit/cli/test_batch_async.py ++++ b/tests/unit/cli/test_batch_async.py +@@ -8,10 +8,9 @@ from salt.cli.batch_async import BatchAsync + import salt.ext.tornado + from salt.ext.tornado.testing import AsyncTestCase + from tests.support.unit import skipIf, TestCase +-from tests.support.mock import MagicMock, patch, NO_MOCK, NO_MOCK_REASON ++from tests.support.mock import MagicMock, patch + + +-@skipIf(NO_MOCK, NO_MOCK_REASON) + class AsyncBatchTestCase(AsyncTestCase, TestCase): + + def setUp(self): +diff --git a/tests/unit/cli/test_support.py b/tests/unit/cli/test_support.py +index 85ea957d79..8d8c1cb11f 100644 +--- a/tests/unit/cli/test_support.py ++++ b/tests/unit/cli/test_support.py +@@ -6,7 +6,7 @@ + from __future__ import absolute_import, print_function, unicode_literals + + from tests.support.unit import skipIf, TestCase +-from tests.support.mock import MagicMock, patch, NO_MOCK, NO_MOCK_REASON ++from tests.support.mock import MagicMock, patch + + from salt.cli.support.console import IndentOutput + from salt.cli.support.collector import SupportDataCollector, SaltSupport +@@ -26,7 +26,6 @@ except ImportError: + + + @skipIf(not bool(pytest), 'Pytest needs to be installed') +-@skipIf(NO_MOCK, NO_MOCK_REASON) + class SaltSupportIndentOutputTestCase(TestCase): + ''' + Unit Tests for the salt-support indent output. +@@ -90,7 +89,6 @@ class SaltSupportIndentOutputTestCase(TestCase): + + + @skipIf(not bool(pytest), 'Pytest needs to be installed') +-@skipIf(NO_MOCK, NO_MOCK_REASON) + class SaltSupportCollectorTestCase(TestCase): + ''' + Collector tests. +@@ -211,7 +209,6 @@ class SaltSupportCollectorTestCase(TestCase): + + + @skipIf(not bool(pytest), 'Pytest needs to be installed') +-@skipIf(NO_MOCK, NO_MOCK_REASON) + class SaltSupportRunnerTestCase(TestCase): + ''' + Test runner class. +@@ -404,7 +401,6 @@ class SaltSupportRunnerTestCase(TestCase): + + + @skipIf(not bool(pytest), 'Pytest needs to be installed') +-@skipIf(NO_MOCK, NO_MOCK_REASON) + class ProfileIntegrityTestCase(TestCase): + ''' + Default profile integrity +diff --git a/tests/unit/modules/test_cmdmod.py b/tests/unit/modules/test_cmdmod.py +index 8d763435f8..3d13fb9290 100644 +--- a/tests/unit/modules/test_cmdmod.py ++++ b/tests/unit/modules/test_cmdmod.py +@@ -37,7 +37,6 @@ MOCK_SHELL_FILE = '# List of acceptable shells\n' \ + '/bin/bash\n' + + +-@skipIf(NO_MOCK, NO_MOCK_REASON) + class CMDMODTestCase(TestCase, LoaderModuleMockMixin): + ''' + Unit tests for the salt.modules.cmdmod module +diff --git a/tests/unit/modules/test_kubeadm.py b/tests/unit/modules/test_kubeadm.py +index a58f54f118..f17ba4ad64 100644 +--- a/tests/unit/modules/test_kubeadm.py ++++ b/tests/unit/modules/test_kubeadm.py +@@ -29,16 +29,13 @@ from tests.support.mixins import LoaderModuleMockMixin + from tests.support.unit import TestCase, skipIf + from tests.support.mock import ( + MagicMock, +- patch, +- NO_MOCK, +- NO_MOCK_REASON ++ patch + ) + + import salt.modules.kubeadm as kubeadm + from salt.exceptions import CommandExecutionError + + +-@skipIf(NO_MOCK, NO_MOCK_REASON) + class KubeAdmTestCase(TestCase, LoaderModuleMockMixin): + ''' + Test cases for salt.modules.kubeadm +diff --git a/tests/unit/modules/test_saltsupport.py b/tests/unit/modules/test_saltsupport.py +index 7bd652a90e..75616ba949 100644 +--- a/tests/unit/modules/test_saltsupport.py ++++ b/tests/unit/modules/test_saltsupport.py +@@ -9,7 +9,7 @@ from __future__ import absolute_import, print_function, unicode_literals + # Import Salt Testing Libs + from tests.support.mixins import LoaderModuleMockMixin + from tests.support.unit import TestCase, skipIf +-from tests.support.mock import patch, MagicMock, NO_MOCK, NO_MOCK_REASON ++from tests.support.mock import patch, MagicMock + from salt.modules import saltsupport + import salt.exceptions + import datetime +@@ -21,7 +21,6 @@ except ImportError: + + + @skipIf(not bool(pytest), 'Pytest required') +-@skipIf(NO_MOCK, NO_MOCK_REASON) + class SaltSupportModuleTestCase(TestCase, LoaderModuleMockMixin): + ''' + Test cases for salt.modules.support::SaltSupportModule +@@ -289,7 +288,6 @@ professor: Farnsworth + + + @skipIf(not bool(pytest), 'Pytest required') +-@skipIf(NO_MOCK, NO_MOCK_REASON) + class LogCollectorTestCase(TestCase, LoaderModuleMockMixin): + ''' + Test cases for salt.modules.support::LogCollector +diff --git a/tests/unit/modules/test_xfs.py b/tests/unit/modules/test_xfs.py +index 4b423d69d1..d680c4e317 100644 +--- a/tests/unit/modules/test_xfs.py ++++ b/tests/unit/modules/test_xfs.py +@@ -8,8 +8,6 @@ import textwrap + from tests.support.mixins import LoaderModuleMockMixin + from tests.support.unit import skipIf, TestCase + from tests.support.mock import ( +- NO_MOCK, +- NO_MOCK_REASON, + MagicMock, + patch) + +@@ -17,7 +15,6 @@ from tests.support.mock import ( + import salt.modules.xfs as xfs + + +-@skipIf(NO_MOCK, NO_MOCK_REASON) + @patch('salt.modules.xfs._get_mounts', MagicMock(return_value={})) + class XFSTestCase(TestCase, LoaderModuleMockMixin): + ''' +diff --git a/tests/unit/states/test_btrfs.py b/tests/unit/states/test_btrfs.py +index 3f45ed94f9..c68f6279dc 100644 +--- a/tests/unit/states/test_btrfs.py ++++ b/tests/unit/states/test_btrfs.py +@@ -32,8 +32,6 @@ from tests.support.mixins import LoaderModuleMockMixin + from tests.support.unit import skipIf, TestCase + from tests.support.mock import ( + MagicMock, +- NO_MOCK, +- NO_MOCK_REASON, + patch, + ) + +@@ -43,7 +41,6 @@ import salt.states.btrfs as btrfs + import pytest + + +-@skipIf(NO_MOCK, NO_MOCK_REASON) + class BtrfsTestCase(TestCase, LoaderModuleMockMixin): + ''' + Test cases for salt.states.btrfs +diff --git a/tests/unit/utils/test_pkg.py b/tests/unit/utils/test_pkg.py +index 361e0bf92f..38c0cb8f84 100644 +--- a/tests/unit/utils/test_pkg.py ++++ b/tests/unit/utils/test_pkg.py +@@ -3,7 +3,7 @@ + from __future__ import absolute_import, unicode_literals, print_function + + from tests.support.unit import TestCase, skipIf +-from tests.support.mock import Mock, MagicMock, patch, NO_MOCK, NO_MOCK_REASON ++from tests.support.mock import Mock, MagicMock, patch + import salt.utils.pkg + from salt.utils.pkg import rpm + +@@ -13,7 +13,6 @@ except ImportError: + pytest = None + + +-@skipIf(NO_MOCK, NO_MOCK_REASON) + @skipIf(pytest is None, 'PyTest is missing') + class PkgRPMTestCase(TestCase): + ''' +-- +2.23.0 + + diff --git a/remove-unnecessary-yield-causing-badyielderror-bsc-1.patch b/remove-unnecessary-yield-causing-badyielderror-bsc-1.patch index 3b3b0d5..0524b6f 100644 --- a/remove-unnecessary-yield-causing-badyielderror-bsc-1.patch +++ b/remove-unnecessary-yield-causing-badyielderror-bsc-1.patch @@ -1,4 +1,4 @@ -From 23d21edaf5565d99bb6316087863ecbf6a699034 Mon Sep 17 00:00:00 2001 +From bec0a06a069404c5043b1c59e3fe7cce2df177d3 Mon Sep 17 00:00:00 2001 From: Mihai Dinca Date: Wed, 30 Oct 2019 10:19:12 +0100 Subject: [PATCH] Remove unnecessary yield causing BadYieldError diff --git a/remove-virt.pool_delete-fast-parameter-178.patch b/remove-virt.pool_delete-fast-parameter-178.patch deleted file mode 100644 index 1f00c85..0000000 --- a/remove-virt.pool_delete-fast-parameter-178.patch +++ /dev/null @@ -1,76 +0,0 @@ -From 8d150403ceedd9bf7939bfa9ec1d6790e8ed4609 Mon Sep 17 00:00:00 2001 -From: Cedric Bosdonnat -Date: Wed, 30 Oct 2019 12:18:51 +0100 -Subject: [PATCH] Remove virt.pool_delete fast parameter (#178) - -There are two reasons to remove this parameter without deprecating it: - * the meaning has been mistakenly inversed - * fast=True will raise an exception for every libvirt storage backend -since that flag has never been implemented in any of those. - -Fixes issue #54474 ---- - salt/modules/virt.py | 9 ++------- - tests/unit/modules/test_virt.py | 17 +++++++++++++++++ - 2 files changed, 19 insertions(+), 7 deletions(-) - -diff --git a/salt/modules/virt.py b/salt/modules/virt.py -index d01b6c3f1e..3abc140a00 100644 ---- a/salt/modules/virt.py -+++ b/salt/modules/virt.py -@@ -4885,13 +4885,11 @@ def pool_undefine(name, **kwargs): - conn.close() - - --def pool_delete(name, fast=True, **kwargs): -+def pool_delete(name, **kwargs): - ''' - Delete the resources of a defined libvirt storage pool. - - :param name: libvirt storage pool name -- :param fast: if set to False, zeroes out all the data. -- Default value is True. - :param connection: libvirt connection URI, overriding defaults - :param username: username to connect with, overriding defaults - :param password: password to connect with, overriding defaults -@@ -4907,10 +4905,7 @@ def pool_delete(name, fast=True, **kwargs): - conn = __get_conn(**kwargs) - try: - pool = conn.storagePoolLookupByName(name) -- flags = libvirt.VIR_STORAGE_POOL_DELETE_NORMAL -- if fast: -- flags = libvirt.VIR_STORAGE_POOL_DELETE_ZEROED -- return not bool(pool.delete(flags)) -+ return not bool(pool.delete(libvirt.VIR_STORAGE_POOL_DELETE_NORMAL)) - finally: - conn.close() - -diff --git a/tests/unit/modules/test_virt.py b/tests/unit/modules/test_virt.py -index 4d20e998d8..b95f51807f 100644 ---- a/tests/unit/modules/test_virt.py -+++ b/tests/unit/modules/test_virt.py -@@ -3006,3 +3006,20 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin): - self.assertEqual('vnc', graphics['type']) - self.assertEqual('5900', graphics['port']) - self.assertEqual('0.0.0.0', graphics['listen']) -+ -+ def test_pool_delete(self): -+ ''' -+ Test virt.pool_delete function -+ ''' -+ mock_pool = MagicMock() -+ mock_pool.delete = MagicMock(return_value=0) -+ self.mock_conn.storagePoolLookupByName = MagicMock(return_value=mock_pool) -+ -+ res = virt.pool_delete('test-pool') -+ self.assertTrue(res) -+ -+ self.mock_conn.storagePoolLookupByName.assert_called_once_with('test-pool') -+ -+ # Shouldn't be called with another parameter so far since those are not implemented -+ # and thus throwing exceptions. -+ mock_pool.delete.assert_called_once_with(self.mock_libvirt.VIR_STORAGE_POOL_DELETE_NORMAL) --- -2.16.4 - - diff --git a/removes-unresolved-merge-conflict-in-yumpkg-module.patch b/removes-unresolved-merge-conflict-in-yumpkg-module.patch new file mode 100644 index 0000000..74e0987 --- /dev/null +++ b/removes-unresolved-merge-conflict-in-yumpkg-module.patch @@ -0,0 +1,29 @@ +From 93c0630b84b9da89acaf549a5c79e5d834c70a65 Mon Sep 17 00:00:00 2001 +From: Jochen Breuer +Date: Thu, 5 Mar 2020 21:01:31 +0100 +Subject: [PATCH] Removes unresolved merge conflict in yumpkg module + +--- + salt/modules/yumpkg.py | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/salt/modules/yumpkg.py b/salt/modules/yumpkg.py +index 88d74020b3..04ab240cd4 100644 +--- a/salt/modules/yumpkg.py ++++ b/salt/modules/yumpkg.py +@@ -3220,11 +3220,7 @@ def _get_patches(installed_only=False): + for line in salt.utils.itertools.split(ret, os.linesep): + inst, advisory_id, sev, pkg = re.match(r'([i|\s]) ([^\s]+) +([^\s]+) +([^\s]+)', + line).groups() +-<<<<<<< HEAD + if advisory_id not in patches: +-======= +- if not advisory_id in patches: +->>>>>>> Do not report patches as installed when not all the related packages are installed (bsc#1128061) + patches[advisory_id] = { + 'installed': True if inst == 'i' else False, + 'summary': [pkg] +-- +2.16.4 + + diff --git a/restore-default-behaviour-of-pkg-list-return.patch b/restore-default-behaviour-of-pkg-list-return.patch index 66b296d..f4f2fa5 100644 --- a/restore-default-behaviour-of-pkg-list-return.patch +++ b/restore-default-behaviour-of-pkg-list-return.patch @@ -1,4 +1,4 @@ -From 1da400568977ffc45d4071189658855ee73b4013 Mon Sep 17 00:00:00 2001 +From 8f9478ffba672767e77b9b263f279e0379ab1ed1 Mon Sep 17 00:00:00 2001 From: Jochen Breuer Date: Fri, 30 Aug 2019 14:20:06 +0200 Subject: [PATCH] Restore default behaviour of pkg list return @@ -13,10 +13,10 @@ Co-authored-by: Mihai Dinca 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/salt/modules/zypperpkg.py b/salt/modules/zypperpkg.py -index f71d6aac9e..da1953b2a5 100644 +index 8179cd8c1d..f7158e0810 100644 --- a/salt/modules/zypperpkg.py +++ b/salt/modules/zypperpkg.py -@@ -1302,8 +1302,10 @@ def refresh_db(root=None): +@@ -1304,8 +1304,10 @@ def refresh_db(root=None): return ret @@ -28,7 +28,7 @@ index f71d6aac9e..da1953b2a5 100644 return sorted({pkg.split(':', 1)[0] for pkg in pkgs if len(pkg.split(':', 1)) == 2}) -@@ -1319,6 +1321,7 @@ def install(name=None, +@@ -1321,6 +1323,7 @@ def install(name=None, ignore_repo_failure=False, no_recommends=False, root=None, @@ -36,7 +36,7 @@ index f71d6aac9e..da1953b2a5 100644 **kwargs): ''' .. versionchanged:: 2015.8.12,2016.3.3,2016.11.0 -@@ -1433,6 +1436,9 @@ def install(name=None, +@@ -1435,6 +1438,9 @@ def install(name=None, .. versionadded:: 2018.3.0 @@ -46,7 +46,7 @@ index f71d6aac9e..da1953b2a5 100644 Returns a dict containing the new package names and versions:: -@@ -1498,7 +1504,8 @@ def install(name=None, +@@ -1500,7 +1506,8 @@ def install(name=None, diff_attr = kwargs.get("diff_attr") @@ -56,7 +56,7 @@ index f71d6aac9e..da1953b2a5 100644 old = list_pkgs(attr=diff_attr, root=root, includes=includes) if not downloadonly else list_downloaded(root) downgrades = [] -@@ -1688,7 +1695,7 @@ def upgrade(refresh=True, +@@ -1692,7 +1699,7 @@ def upgrade(refresh=True, return ret @@ -65,7 +65,7 @@ index f71d6aac9e..da1953b2a5 100644 ''' Remove and purge do identical things but with different Zypper commands, this function performs the common logic. -@@ -1698,7 +1705,7 @@ def _uninstall(name=None, pkgs=None, root=None): +@@ -1702,7 +1709,7 @@ def _uninstall(name=None, pkgs=None, root=None): except MinionError as exc: raise CommandExecutionError(exc) @@ -74,7 +74,7 @@ index f71d6aac9e..da1953b2a5 100644 old = list_pkgs(root=root, includes=includes) targets = [] for target in pkg_params: -@@ -1757,7 +1764,7 @@ def normalize_name(name): +@@ -1761,7 +1768,7 @@ def normalize_name(name): return name @@ -83,7 +83,7 @@ index f71d6aac9e..da1953b2a5 100644 ''' .. versionchanged:: 2015.8.12,2016.3.3,2016.11.0 On minions running systemd>=205, `systemd-run(1)`_ is now used to -@@ -1788,8 +1795,11 @@ def remove(name=None, pkgs=None, root=None, **kwargs): # pylint: disable=unused +@@ -1792,8 +1799,11 @@ def remove(name=None, pkgs=None, root=None, **kwargs): # pylint: disable=unused root Operate on a different root directory. @@ -96,7 +96,7 @@ index f71d6aac9e..da1953b2a5 100644 Returns a dict containing the changes. -@@ -1801,10 +1811,10 @@ def remove(name=None, pkgs=None, root=None, **kwargs): # pylint: disable=unused +@@ -1805,10 +1815,10 @@ def remove(name=None, pkgs=None, root=None, **kwargs): # pylint: disable=unused salt '*' pkg.remove ,, salt '*' pkg.remove pkgs='["foo", "bar"]' ''' @@ -109,7 +109,7 @@ index f71d6aac9e..da1953b2a5 100644 ''' .. versionchanged:: 2015.8.12,2016.3.3,2016.11.0 On minions running systemd>=205, `systemd-run(1)`_ is now used to -@@ -1836,6 +1846,10 @@ def purge(name=None, pkgs=None, root=None, **kwargs): # pylint: disable=unused- +@@ -1840,6 +1850,10 @@ def purge(name=None, pkgs=None, root=None, **kwargs): # pylint: disable=unused- root Operate on a different root directory. @@ -120,7 +120,7 @@ index f71d6aac9e..da1953b2a5 100644 .. versionadded:: 0.16.0 -@@ -1849,7 +1863,7 @@ def purge(name=None, pkgs=None, root=None, **kwargs): # pylint: disable=unused- +@@ -1853,7 +1867,7 @@ def purge(name=None, pkgs=None, root=None, **kwargs): # pylint: disable=unused- salt '*' pkg.purge ,, salt '*' pkg.purge pkgs='["foo", "bar"]' ''' diff --git a/restrict-the-start_event_grains-only-to-the-start-ev.patch b/restrict-the-start_event_grains-only-to-the-start-ev.patch deleted file mode 100644 index 23bc679..0000000 --- a/restrict-the-start_event_grains-only-to-the-start-ev.patch +++ /dev/null @@ -1,102 +0,0 @@ -From 127f0fa48ed2e5f05320c6c82f928f0d59a94bd9 Mon Sep 17 00:00:00 2001 -From: Abid Mehmood -Date: Thu, 16 Jan 2020 11:28:04 +0100 -Subject: [PATCH] Restrict the 'start_event_grains' only to the start - events - -add test for custom events ---- - salt/minion.py | 11 ++++++++--- - tests/unit/test_minion.py | 18 +++++++++++++++++- - 2 files changed, 25 insertions(+), 4 deletions(-) - -diff --git a/salt/minion.py b/salt/minion.py -index 2b53da4f18..a2fb203bfe 100644 ---- a/salt/minion.py -+++ b/salt/minion.py -@@ -1437,7 +1437,7 @@ class Minion(MinionBase): - finally: - channel.close() - -- def _fire_master(self, data=None, tag=None, events=None, pretag=None, timeout=60, sync=True, timeout_handler=None): -+ def _fire_master(self, data=None, tag=None, events=None, pretag=None, timeout=60, sync=True, timeout_handler=None, include_startup_grains=False): - ''' - Fire an event on the master, or drop message if unable to send. - ''' -@@ -1456,7 +1456,7 @@ class Minion(MinionBase): - else: - return - -- if self.opts['start_event_grains']: -+ if include_startup_grains: - grains_to_add = dict( - [(k, v) for k, v in six.iteritems(self.opts.get('grains', {})) if k in self.opts['start_event_grains']]) - load['grains'] = grains_to_add -@@ -2149,6 +2149,9 @@ class Minion(MinionBase): - }) - - def _fire_master_minion_start(self): -+ include_grains = False -+ if self.opts['start_event_grains']: -+ include_grains = True - # Send an event to the master that the minion is live - if self.opts['enable_legacy_startup_events']: - # Old style event. Defaults to False in Sodium release. -@@ -2157,7 +2160,8 @@ class Minion(MinionBase): - self.opts['id'], - time.asctime() - ), -- 'minion_start' -+ 'minion_start', -+ include_startup_grains=include_grains - ) - # send name spaced event - self._fire_master( -@@ -2166,6 +2170,7 @@ class Minion(MinionBase): - time.asctime() - ), - tagify([self.opts['id'], 'start'], 'minion'), -+ include_startup_grains=include_grains - ) - - def module_refresh(self, force_refresh=False, notify=False): -diff --git a/tests/unit/test_minion.py b/tests/unit/test_minion.py -index 83215151ee..41dfab0f45 100644 ---- a/tests/unit/test_minion.py -+++ b/tests/unit/test_minion.py -@@ -314,7 +314,7 @@ class MinionTestCase(TestCase, AdaptedConfigurationTestCaseMixin): - try: - minion.tok = MagicMock() - minion._send_req_sync = MagicMock() -- minion._fire_master('Minion has started', 'minion_start') -+ minion._fire_master('Minion has started', 'minion_start', include_startup_grains=True) - load = minion._send_req_sync.call_args[0][0] - - self.assertTrue('grains' in load) -@@ -337,6 +337,22 @@ class MinionTestCase(TestCase, AdaptedConfigurationTestCaseMixin): - finally: - minion.destroy() - -+ def test_when_other_events_fired_and_start_event_grains_are_set(self): -+ mock_opts = self.get_config('minion', from_scratch=True) -+ mock_opts['start_event_grains'] = ["os"] -+ io_loop = tornado.ioloop.IOLoop() -+ io_loop.make_current() -+ minion = salt.minion.Minion(mock_opts, io_loop=io_loop) -+ try: -+ minion.tok = MagicMock() -+ minion._send_req_sync = MagicMock() -+ minion._fire_master('Custm_event_fired', 'custom_event') -+ load = minion._send_req_sync.call_args[0][0] -+ -+ self.assertTrue('grains' not in load) -+ finally: -+ minion.destroy() -+ - def test_minion_retry_dns_count(self): - ''' - Tests that the resolve_dns will retry dns look ups for a maximum of --- -2.16.4 - - diff --git a/return-the-expected-powerpc-os-arch-bsc-1117995.patch b/return-the-expected-powerpc-os-arch-bsc-1117995.patch index c4337f0..ab26e1c 100644 --- a/return-the-expected-powerpc-os-arch-bsc-1117995.patch +++ b/return-the-expected-powerpc-os-arch-bsc-1117995.patch @@ -1,22 +1,24 @@ -From 2140fc26fb347388ac60f91c4badf76a73a8a728 Mon Sep 17 00:00:00 2001 +From 27e90d416b89ac2c7839e1d03ded37f86df7290f Mon Sep 17 00:00:00 2001 From: Mihai Dinca Date: Thu, 13 Dec 2018 12:17:35 +0100 Subject: [PATCH] Return the expected powerpc os arch (bsc#1117995) --- - salt/utils/pkg/rpm.py | 7 +++++-- - 1 file changed, 5 insertions(+), 2 deletions(-) + salt/utils/pkg/rpm.py | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/salt/utils/pkg/rpm.py b/salt/utils/pkg/rpm.py -index bb8c3fb589..828b0cecda 100644 +index bc5eb30eda..cb85eb99fe 100644 --- a/salt/utils/pkg/rpm.py +++ b/salt/utils/pkg/rpm.py -@@ -53,8 +53,11 @@ def get_osarch(): +@@ -52,9 +52,12 @@ def get_osarch(): + stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0] else: - ret = ''.join(list(filter(None, platform.uname()[-2:]))[-1:]) +- ret = ''.join([x for x in platform.uname()[-2:] if x][-1:]) - - return salt.utils.stringutils.to_str(ret).strip() or 'unknown' ++ ret = ''.join(list(filter(None, platform.uname()[-2:]))[-1:]) + ret = salt.utils.stringutils.to_str(ret).strip() or 'unknown' + ARCH_FIXES_MAPPING = { + "powerpc64le": "ppc64le" diff --git a/run-salt-api-as-user-salt-bsc-1064520.patch b/run-salt-api-as-user-salt-bsc-1064520.patch index d117c8f..4efbfab 100644 --- a/run-salt-api-as-user-salt-bsc-1064520.patch +++ b/run-salt-api-as-user-salt-bsc-1064520.patch @@ -1,4 +1,4 @@ -From 6bec79137c30375d62a2e3238081a9f4a5a8ae1b Mon Sep 17 00:00:00 2001 +From 4e9b3808b5a27fcdc857b26d73e0f6716243ca92 Mon Sep 17 00:00:00 2001 From: Christian Lanig Date: Mon, 27 Nov 2017 13:10:26 +0100 Subject: [PATCH] Run salt-api as user salt (bsc#1064520) diff --git a/run-salt-master-as-dedicated-salt-user.patch b/run-salt-master-as-dedicated-salt-user.patch index a03f972..aab3edd 100644 --- a/run-salt-master-as-dedicated-salt-user.patch +++ b/run-salt-master-as-dedicated-salt-user.patch @@ -1,4 +1,4 @@ -From ab1bc69e1454fc78ac9ba8725e61e034d882b5aa Mon Sep 17 00:00:00 2001 +From 497acb852b0d4519984d981dfefdc0848c3e4159 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klaus=20K=C3=A4mpf?= Date: Wed, 20 Jan 2016 11:01:06 +0100 Subject: [PATCH] Run salt master as dedicated salt user @@ -10,7 +10,7 @@ Subject: [PATCH] Run salt master as dedicated salt user 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/conf/master b/conf/master -index 546db5cb28..573e4213ba 100644 +index ce2e26872a..22a4a7bdb4 100644 --- a/conf/master +++ b/conf/master @@ -25,7 +25,8 @@ @@ -21,8 +21,8 @@ index 546db5cb28..573e4213ba 100644 +user: salt +syndic_user: salt - # The port used by the communication interface. The ret (return) port is the - # interface used for the file server, authentication, job returns, etc. + # Tell the master to also use salt-ssh when running commands against minions. + #enable_ssh_minions: False diff --git a/pkg/salt-common.logrotate b/pkg/salt-common.logrotate index 3cd002308e..0d99d1b801 100644 --- a/pkg/salt-common.logrotate diff --git a/salt.changes b/salt.changes index c8e1ff6..e253553 100644 --- a/salt.changes +++ b/salt.changes @@ -1,3 +1,162 @@ +------------------------------------------------------------------- +Tue Apr 7 10:38:57 UTC 2020 - Pablo Suárez Hernández + +- Update to Salt version 3000 + See release notes: https://docs.saltstack.com/en/latest/topics/releases/3000.html + +- Do not make file.recurse state to fail when msgpack 0.5.4 (bsc#1167437) +- Fixes status attribute issue in aptpkg test +- Make setup.py script not to require setuptools greater than 9.1 + loop: fix variable names for until_no_eval +- Drop conflictive module.run state patch (bsc#1167437) +- Update patches after rebase with upstream v3000 tag (bsc#1167437) +- Fix some requirements issues depending on Python3 versions +- Removes obsolete patch +- Fix for low rpm_lowpkg unit test +- Add python-singledispatch as dependency for python2-salt +- Fix for temp folder definition in loader unit test +- Make "salt.ext.tornado.gen" to use "salt.ext.backports_abc" on Python 2 +- Fix regression in service states with reload argument +- Fix integration test failure for test_mod_del_repo_multiline_values +- Fix for unless requisite when pip is not installed +- Fix errors from unit tests due NO_MOCK and NO_MOCK_REASON deprecation +- Fix tornado imports and missing _utils after rebasing patches +- Removes unresolved merge conflict in yumpkg module + +- Added: + * make-setup.py-script-to-not-require-setuptools-9.1.patch + * opensuse-3000-virt-defined-states-222.patch + * fix-for-unless-requisite-when-pip-is-not-installed.patch + * fix-typo-on-msgpack-version-when-sanitizing-msgpack-.patch + * fix-regression-in-service-states-with-reload-argumen.patch + * batch_async-avoid-using-fnmatch-to-match-event-217.patch + * make-salt.ext.tornado.gen-to-use-salt.ext.backports_.patch + * virt._get_domain-don-t-raise-an-exception-if-there-i.patch + * loop-fix-variable-names-for-until_no_eval.patch + * removes-unresolved-merge-conflict-in-yumpkg-module.patch + * add-missing-_utils-at-loader-grains_func.patch + * changed-imports-to-vendored-tornado.patch + * sanitize-grains-loaded-from-roster_grains.json.patch + * fix-for-temp-folder-definition-in-loader-unit-test.patch + * remove-deprecated-usage-of-no_mock-and-no_mock_reaso.patch + * reintroducing-reverted-changes.patch + * adds-explicit-type-cast-for-port.patch + * fix-wrong-test_mod_del_repo_multiline_values-test-af.patch + * re-adding-function-to-test-for-root.patch + +- Modified: + * move-server_id-deprecation-warning-to-reduce-log-spa.patch + * let-salt-ssh-use-platform-python-binary-in-rhel8-191.patch + * strip-trailing-from-repo.uri-when-comparing-repos-in.patch + * prevent-test_mod_del_repo_multiline_values-to-fail.patch + * prevent-ansiblegate-unit-tests-to-fail-on-ubuntu.patch + * remove-arch-from-name-when-pkg.list_pkgs-is-called-w.patch + * async-batch-implementation.patch + * add-hold-unhold-functions.patch + * add-all_versions-parameter-to-include-all-installed-.patch + * enable-passing-a-unix_socket-for-mysql-returners-bsc.patch + * fix-for-log-checking-in-x509-test.patch + * fix-zypper.list_pkgs-to-be-aligned-with-pkg-state.patch + * add-multi-file-support-and-globbing-to-the-filetree-.patch + * remove-unnecessary-yield-causing-badyielderror-bsc-1.patch + * fix-bsc-1065792.patch + * use-threadpool-from-multiprocessing.pool-to-avoid-le.patch + * return-the-expected-powerpc-os-arch-bsc-1117995.patch + * fixes-cve-2018-15750-cve-2018-15751.patch + * add-cpe_name-for-osversion-grain-parsing-u-49946.patch + * fix-failing-unit-tests-for-batch-async.patch + * decide-if-the-source-should-be-actually-skipped.patch + * allow-passing-kwargs-to-pkg.list_downloaded-bsc-1140.patch + * add-batch_presence_ping_timeout-and-batch_presence_p.patch + * run-salt-master-as-dedicated-salt-user.patch + * use-current-ioloop-for-the-localclient-instance-of-b.patch + * integration-of-msi-authentication-with-azurearm-clou.patch + * temporary-fix-extend-the-whitelist-of-allowed-comman.patch + * improve-batch_async-to-release-consumed-memory-bsc-1.patch + * fix-unit-test-for-grains-core.patch + * add-supportconfig-module-for-remote-calls-and-saltss.patch + * avoid-excessive-syslogging-by-watchdog-cronjob-58.patch + * debian-info_installed-compatibility-50453.patch + * include-aliases-in-the-fqdns-grains.patch + * implement-network.fqdns-module-function-bsc-1134860-.patch + * fix-async-batch-multiple-done-events.patch + * support-config-non-root-permission-issues-fixes-u-50.patch + * fix-zypper-pkg.list_pkgs-expectation-and-dpkg-mockin.patch + * activate-all-beacons-sources-config-pillar-grains.patch + * avoid-traceback-when-http.query-request-cannot-be-pe.patch + * fix-aptpkg-systemd-call-bsc-1143301.patch + * use-adler32-algorithm-to-compute-string-checksums.patch + * do-not-break-repo-files-with-multiple-line-values-on.patch + * fix-batch_async-obsolete-test.patch + * provide-the-missing-features-required-for-yomi-yet-o.patch + * fall-back-to-pymysql.patch + * xfs-do-not-fails-if-type-is-not-present.patch + * restore-default-behaviour-of-pkg-list-return.patch + * add-missing-fun-for-returns-from-wfunc-executions.patch + * virt-adding-kernel-boot-parameters-to-libvirt-xml-55.patch + * run-salt-api-as-user-salt-bsc-1064520.patch + * loosen-azure-sdk-dependencies-in-azurearm-cloud-driv.patch + * support-for-btrfs-and-xfs-in-parted-and-mkfs.patch + * fixing-streamclosed-issue.patch + * do-not-crash-when-there-are-ipv6-established-connect.patch + * calculate-fqdns-in-parallel-to-avoid-blockings-bsc-1.patch + * fix-async-batch-race-conditions.patch + * fix-issue-2068-test.patch + * fix-a-wrong-rebase-in-test_core.py-180.patch + * fix-for-suse-expanded-support-detection.patch + * add-environment-variable-to-know-if-yum-is-invoked-f.patch + * add-standalone-configuration-file-for-enabling-packa.patch + * switch-firewalld-state-to-use-change_interface.patch + * do-not-make-ansiblegate-to-crash-on-python3-minions.patch + * make-aptpkg.list_repos-compatible-on-enabled-disable.patch + * add-custom-suse-capabilities-as-grains.patch + * accumulated-changes-from-yomi-167.patch + * get-os_arch-also-without-rpm-package-installed.patch + * fix-git_pillar-merging-across-multiple-__env__-repos.patch + * do-not-load-pip-state-if-there-is-no-3rd-party-depen.patch + * add-saltssh-multi-version-support-across-python-inte.patch + * early-feature-support-config.patch + * add-virt.all_capabilities.patch + * accumulated-changes-required-for-yomi-165.patch + * fix-memory-leak-produced-by-batch-async-find_jobs-me.patch + * fix-ipv6-scope-bsc-1108557.patch + * prevent-systemd-run-description-issue-when-running-a.patch + * make-profiles-a-package.patch + * don-t-call-zypper-with-more-than-one-no-refresh.patch + * batch.py-avoid-exception-when-minion-does-not-respon.patch + * read-repo-info-without-using-interpolation-bsc-11356.patch + * x509-fixes-111.patch + * do-not-report-patches-as-installed-when-not-all-the-.patch + +- Removed: + * remove-virt.pool_delete-fast-parameter-178.patch + * adds-the-possibility-to-also-use-downloadonly-in-kwa.patch + * align-virt-full-info-fixes-with-upstream-192.patch + * take-checksums-arg-into-account-for-postgres.datadir.patch + * virt-1.volume_infos-fix-for-single-vm.patch + * virt.volume_infos-needs-to-ignore-inactive-pools-174.patch + * preserve-already-defined-destructive_tests-and-expen.patch + * list_downloaded-for-apt-module.patch + * fix-virt-states-to-not-fail-on-vms-already-stopped.-.patch + * virt.volume_infos-fix-for-single-vm.patch + * restrict-the-start_event_grains-only-to-the-start-ev.patch + * fix-virt.full_info-176.patch + * preserving-signature-in-module.run-state-u-50049.patch + * checking-for-jid-before-returning-data.patch + * virt.volume_infos-silence-libvirt-error-message-175.patch + * add-virt.volume_infos-and-virt.volume_delete.patch + * add-virt.network_get_xml-function.patch + * virt.network_define-allow-adding-ip-configuration.patch + * add-ppc64le-as-a-valid-rpm-package-architecture.patch + * bugfix-any-unicode-string-of-length-16-will-raise-ty.patch + * fix-for-older-mock-module.patch + * fix-virt.get_hypervisor-188.patch + * 2019.2.0-pr-54196-backport-173.patch + * enable-passing-grains-to-start-event-based-on-start_.patch + * fix-load-cached-grain-osrelease_info.patch + * open-suse-2019.2.3-virt-defined-states-219.patch + * backport-saltutil-state-module-to-2019.2-codebase.patch + ------------------------------------------------------------------- Thu Apr 2 13:47:34 UTC 2020 - Pablo Suárez Hernández diff --git a/salt.spec b/salt.spec index 794db97..2ca3646 100644 --- a/salt.spec +++ b/salt.spec @@ -63,7 +63,7 @@ %bcond_with builddocs Name: salt -Version: 2019.2.3 +Version: 3000 Release: 0 Summary: A parallel remote execution system License: Apache-2.0 @@ -111,218 +111,193 @@ Patch18: do-not-load-pip-state-if-there-is-no-3rd-party-depen.patch Patch19: fix-ipv6-scope-bsc-1108557.patch # PATCH-FIX_UPSTREAM https://github.com/saltstack/salt/pull/49480 Patch20: early-feature-support-config.patch -# PATCH-FIX_UPSTREAM https://github.com/saltstack/salt/pull/49908 -Patch21: bugfix-any-unicode-string-of-length-16-will-raise-ty.patch # PATCH-FIX_UPSTREAM https://github.com/saltstack/salt/pull/49936 -Patch22: make-profiles-a-package.patch +Patch21: make-profiles-a-package.patch # PATCH-FIX_UPSTREAM https://github.com/saltstack/salt/pull/49946 -Patch23: add-cpe_name-for-osversion-grain-parsing-u-49946.patch +Patch22: add-cpe_name-for-osversion-grain-parsing-u-49946.patch # PATCH-FIX_OPENSUSE: Fix unit test for grains core -Patch24: fix-unit-test-for-grains-core.patch -# PATCH-FIX_UPSTREAM https://github.com/saltstack/salt/pull/50049 -# PATCH-FIX_UPSTREAM https://github.com/saltstack/salt/pull/50072 -Patch25: preserving-signature-in-module.run-state-u-50049.patch +Patch23: fix-unit-test-for-grains-core.patch # PATCH-FIX_UPSTREAM https://github.com/saltstack/salt/pull/50095 -Patch26: support-config-non-root-permission-issues-fixes-u-50.patch +Patch24: support-config-non-root-permission-issues-fixes-u-50.patch # PATCH-FIX_UPSTREAM https://github.com/saltstack/salt/pull/50018 -Patch27: add-multi-file-support-and-globbing-to-the-filetree-.patch +Patch25: add-multi-file-support-and-globbing-to-the-filetree-.patch # PATCH-FIX_UPSTREAM https://github.com/saltstack/salt/pull/49761 # PATCH-FIX_UPSTREAM https://github.com/saltstack/salt/pull/50201 -Patch28: fixes-cve-2018-15750-cve-2018-15751.patch +Patch26: fixes-cve-2018-15750-cve-2018-15751.patch # PATCH-FIX_UPSTREAM https://github.com/saltstack/salt/pull/50417 -Patch29: fix-git_pillar-merging-across-multiple-__env__-repos.patch +Patch27: fix-git_pillar-merging-across-multiple-__env__-repos.patch # PATCH-FIX_UPSTREAM https://github.com/saltstack/salt/pull/50523 -Patch30: get-os_arch-also-without-rpm-package-installed.patch +Patch28: get-os_arch-also-without-rpm-package-installed.patch # PATCH-FIX_UPSTREAM https://github.com/saltstack/salt/pull/50392 -Patch31: make-aptpkg.list_repos-compatible-on-enabled-disable.patch +Patch29: make-aptpkg.list_repos-compatible-on-enabled-disable.patch # PATCH-FIX_UPSTREAM https://github.com/saltstack/salt/pull/50453 -Patch32: debian-info_installed-compatibility-50453.patch +Patch30: debian-info_installed-compatibility-50453.patch # PATCH-FIX_UPSTREAM https://github.com/saltstack/salt/pull/50742 -Patch33: decide-if-the-source-should-be-actually-skipped.patch +Patch31: decide-if-the-source-should-be-actually-skipped.patch # PATCH-FIX_UPSTREAM https://github.com/saltstack/salt/pull/50773 -Patch34: add-hold-unhold-functions.patch +Patch32: add-hold-unhold-functions.patch # PATCH-FIX_UPSTREAM https://github.com/saltstack/salt/pull/50401 # NOTE: This is a techpreview as well as in Fluorine! Release only in Neon. -Patch35: add-supportconfig-module-for-remote-calls-and-saltss.patch +Patch33: add-supportconfig-module-for-remote-calls-and-saltss.patch # PATCH_FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/116 -Patch36: return-the-expected-powerpc-os-arch-bsc-1117995.patch +Patch34: return-the-expected-powerpc-os-arch-bsc-1117995.patch # PATCH-FIX_UPSTREAM https://github.com/saltstack/salt/pull/51108 -Patch37: remove-arch-from-name-when-pkg.list_pkgs-is-called-w.patch +Patch35: remove-arch-from-name-when-pkg.list_pkgs-is-called-w.patch # PATCH-FIX_UPSTREAM https://github.com/saltstack/salt/pull/51119 -Patch38: fix-issue-2068-test.patch +Patch36: fix-issue-2068-test.patch # PATCH_FIX_OPENSUSE: Temporary fix allowing "id_" and "force" params while upstrem figures it out -Patch39: temporary-fix-extend-the-whitelist-of-allowed-comman.patch +Patch37: temporary-fix-extend-the-whitelist-of-allowed-comman.patch # PATCH-FIX_UPSTREAM https://github.com/saltstack/salt/pull/51382 -Patch40: don-t-call-zypper-with-more-than-one-no-refresh.patch +Patch38: don-t-call-zypper-with-more-than-one-no-refresh.patch # PATCH-FIX_UPSTREAM https://github.com/saltstack/salt/pull/50109 # PATCH_FIX_OPENSUSE https://github.com/openSUSE/salt/pull/121 -Patch41: add-virt.all_capabilities.patch -# PATCH-FIX_UPSTREAM https://github.com/saltstack/salt/pull/51691 -Patch42: add-virt.volume_infos-and-virt.volume_delete.patch +Patch39: add-virt.all_capabilities.patch # PATCH-FIX_UPSTREAM https://github.com/saltstack/salt/pull/51384 -Patch43: include-aliases-in-the-fqdns-grains.patch +Patch40: include-aliases-in-the-fqdns-grains.patch # PATCH-FIX_UPSTREAM https://github.com/saltstack/salt/pull/50546 # PATCH-FIX_UPSTREAM https://github.com/saltstack/salt/pull/51863 -Patch44: async-batch-implementation.patch +Patch41: async-batch-implementation.patch # PATCH-FIX_UPSTREAM https://github.com/saltstack/salt/pull/52527 -Patch45: calculate-fqdns-in-parallel-to-avoid-blockings-bsc-1.patch +Patch42: calculate-fqdns-in-parallel-to-avoid-blockings-bsc-1.patch #PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/139 -Patch46: fix-async-batch-race-conditions.patch +Patch43: fix-async-batch-race-conditions.patch #PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/141 -Patch47: add-batch_presence_ping_timeout-and-batch_presence_p.patch +Patch44: add-batch_presence_ping_timeout-and-batch_presence_p.patch #PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/52657 -Patch48: do-not-report-patches-as-installed-when-not-all-the-.patch +Patch45: do-not-report-patches-as-installed-when-not-all-the-.patch # PATCH-FIX_UPSTREAM https://github.com/saltstack/salt/pull/52527 -Patch49: use-threadpool-from-multiprocessing.pool-to-avoid-le.patch +Patch46: use-threadpool-from-multiprocessing.pool-to-avoid-le.patch # PATCH-FIX_UPSTREAM https://github.com/saltstack/salt/pull/52888 -Patch50: do-not-crash-when-there-are-ipv6-established-connect.patch +Patch47: do-not-crash-when-there-are-ipv6-established-connect.patch # PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/144 # PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/52855 -Patch51: fix-async-batch-multiple-done-events.patch +Patch48: fix-async-batch-multiple-done-events.patch # PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/52743 -Patch52: switch-firewalld-state-to-use-change_interface.patch +Patch49: switch-firewalld-state-to-use-change_interface.patch # PATCH-FIX_OPENSUSE -Patch53: add-standalone-configuration-file-for-enabling-packa.patch -# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/53237 -Patch54: add-ppc64le-as-a-valid-rpm-package-architecture.patch +Patch50: add-standalone-configuration-file-for-enabling-packa.patch # PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/53293 -Patch55: do-not-break-repo-files-with-multiple-line-values-on.patch -# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/53343 -Patch56: preserve-already-defined-destructive_tests-and-expen.patch +Patch51: do-not-break-repo-files-with-multiple-line-values-on.patch # PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/53159 -Patch57: batch.py-avoid-exception-when-minion-does-not-respon.patch +Patch52: batch.py-avoid-exception-when-minion-does-not-respon.patch # PATCH_FIX_UPSTREAM: https://github.com/saltstack/salt/pull/53471 -Patch58: fix-zypper-pkg.list_pkgs-expectation-and-dpkg-mockin.patch -# PATCH_FIX_UPSTREAM: https://github.com/saltstack/salt/pull/52414 -Patch59: virt.volume_infos-fix-for-single-vm.patch +Patch53: fix-zypper-pkg.list_pkgs-expectation-and-dpkg-mockin.patch # PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/161 -Patch60: provide-the-missing-features-required-for-yomi-yet-o.patch +Patch54: provide-the-missing-features-required-for-yomi-yet-o.patch # PATCH_FIX_UPSTREAM: https://github.com/saltstack/salt/pull/53661 -Patch61: do-not-make-ansiblegate-to-crash-on-python3-minions.patch +Patch55: do-not-make-ansiblegate-to-crash-on-python3-minions.patch # PATCH_FIX_UPSTREAM: https://github.com/saltstack/salt/pull/53693 -Patch62: allow-passing-kwargs-to-pkg.list_downloaded-bsc-1140.patch +Patch56: allow-passing-kwargs-to-pkg.list_downloaded-bsc-1140.patch # PATCH_FIX_UPSTREAM: https://github.com/saltstack/salt/pull/53661 -Patch63: prevent-ansiblegate-unit-tests-to-fail-on-ubuntu.patch -# PATCH_FIX_UPSTREAM: https://github.com/saltstack/salt/pull/53755 -Patch64: virt-1.volume_infos-fix-for-single-vm.patch -# PATCH_FIX_UPSTREAM: https://github.com/saltstack/salt/pull/52459 -Patch65: checking-for-jid-before-returning-data.patch +Patch57: prevent-ansiblegate-unit-tests-to-fail-on-ubuntu.patch # PATCH_FIX_UPSTREAM: https://github.com/saltstack/salt/pull/54048 -Patch66: avoid-traceback-when-http.query-request-cannot-be-pe.patch +Patch58: avoid-traceback-when-http.query-request-cannot-be-pe.patch # PATCH_FIX_UPSTREAM: https://github.com/saltstack/salt/pull/53992 # https://github.com/saltstack/salt/pull/53996 # https://github.com/saltstack/salt/pull/54022 # https://github.com/saltstack/salt/pull/54024 -Patch67: accumulated-changes-required-for-yomi-165.patch +Patch59: accumulated-changes-required-for-yomi-165.patch # PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/159 -Patch68: move-server_id-deprecation-warning-to-reduce-log-spa.patch +Patch60: move-server_id-deprecation-warning-to-reduce-log-spa.patch # PATCH_FIX_UPSTREAM: https://github.com/saltstack/salt/pull/54077 # PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/166 -Patch69: fix-aptpkg-systemd-call-bsc-1143301.patch +Patch61: fix-aptpkg-systemd-call-bsc-1143301.patch # PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/170 -Patch70: strip-trailing-from-repo.uri-when-comparing-repos-in.patch +Patch62: strip-trailing-from-repo.uri-when-comparing-repos-in.patch # PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/177 -Patch71: restore-default-behaviour-of-pkg-list-return.patch +Patch63: restore-default-behaviour-of-pkg-list-return.patch # PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/172 -Patch72: implement-network.fqdns-module-function-bsc-1134860-.patch -# PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/173 -Patch73: 2019.2.0-pr-54196-backport-173.patch -# PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/174 -Patch74: virt.volume_infos-needs-to-ignore-inactive-pools-174.patch -# PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/175 -Patch75: virt.volume_infos-silence-libvirt-error-message-175.patch -# PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/176 -Patch76: fix-virt.full_info-176.patch +Patch64: implement-network.fqdns-module-function-bsc-1134860-.patch # PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/commit/6af07030a502c427781991fc9a2b994fa04ef32e -Patch77: fix-memory-leak-produced-by-batch-async-find_jobs-me.patch +Patch65: fix-memory-leak-produced-by-batch-async-find_jobs-me.patch # PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/commit/002543df392f65d95dbc127dc058ac897f2035ed -Patch78: improve-batch_async-to-release-consumed-memory-bsc-1.patch -# PATCH_FIX_UPSTREAM: https://github.com/saltstack/salt/pull/54770 -Patch79: take-checksums-arg-into-account-for-postgres.datadir.patch +Patch66: improve-batch_async-to-release-consumed-memory-bsc-1.patch # PATCH_FIX_UPSTREAM: https://github.com/saltstack/salt/pull/54077 # PATCH_FIX_OPENSUSE: https://github.com/openSUSE/salt/commit/44a91c2ce6df78d93ce0ef659dedb0e41b1c2e04 -Patch80: prevent-systemd-run-description-issue-when-running-a.patch +Patch67: prevent-systemd-run-description-issue-when-running-a.patch # PATCH_FIX_OPENSUSE: https://github.com/openSUSE/salt/commit/55d8a777d6a9b19c959e14a4060e5579e92cd106 -Patch81: use-current-ioloop-for-the-localclient-instance-of-b.patch +Patch68: use-current-ioloop-for-the-localclient-instance-of-b.patch # PATCH_FIX_OPENSUSE: https://github.com/openSUSE/salt/commit/8378bb24a5a53973e8dba7658b8b3465d967329f -Patch82: fix-failing-unit-tests-for-batch-async.patch +Patch69: fix-failing-unit-tests-for-batch-async.patch # PATCH_FIX_UPSTREAM: https://github.com/saltstack/salt/pull/54935 -Patch83: add-missing-fun-for-returns-from-wfunc-executions.patch -# PATCH_FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/179 -Patch84: adds-the-possibility-to-also-use-downloadonly-in-kwa.patch +Patch70: add-missing-fun-for-returns-from-wfunc-executions.patch # PATCH_FIX_UPSTREAM: https://github.com/saltstack/salt/pull/53326 # PATCH_FIX_UPSTREAM: https://github.com/saltstack/salt/pull/54954 -Patch85: accumulated-changes-from-yomi-167.patch +Patch71: accumulated-changes-from-yomi-167.patch # PATCH_FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/180 -Patch86: fix-a-wrong-rebase-in-test_core.py-180.patch -# PATCH_FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/181 -Patch87: fix-for-older-mock-module.patch +Patch72: fix-a-wrong-rebase-in-test_core.py-180.patch # PATCH_FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/182 -Patch88: remove-unnecessary-yield-causing-badyielderror-bsc-1.patch -# PATCH_FIX_UPSTREAM: https://github.com/saltstack/salt/pull/54475 -Patch89: remove-virt.pool_delete-fast-parameter-178.patch +Patch73: remove-unnecessary-yield-causing-badyielderror-bsc-1.patch # PATCH_FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/186 -Patch90: read-repo-info-without-using-interpolation-bsc-11356.patch +Patch74: read-repo-info-without-using-interpolation-bsc-11356.patch # PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/53293 -Patch91: prevent-test_mod_del_repo_multiline_values-to-fail.patch -Patch92: fix-for-log-checking-in-x509-test.patch +Patch75: prevent-test_mod_del_repo_multiline_values-to-fail.patch +Patch76: fix-for-log-checking-in-x509-test.patch # PATCH_FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/190 -Patch93: fixing-streamclosed-issue.patch -Patch94: fix-batch_async-obsolete-test.patch +Patch77: fixing-streamclosed-issue.patch +Patch78: fix-batch_async-obsolete-test.patch # PATCH_FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/191 -Patch95: let-salt-ssh-use-platform-python-binary-in-rhel8-191.patch -# PATCH_FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/192 -Patch96: align-virt-full-info-fixes-with-upstream-192.patch -# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/55351 -Patch97: fix-virt.get_hypervisor-188.patch +Patch79: let-salt-ssh-use-platform-python-binary-in-rhel8-191.patch # PATCH_FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/193 -Patch98: xfs-do-not-fails-if-type-is-not-present.patch -# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/54196 -# PATCH_FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/195 -Patch99: fix-virt-states-to-not-fail-on-vms-already-stopped.-.patch +Patch80: xfs-do-not-fails-if-type-is-not-present.patch # PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/55245 -Patch100: virt-adding-kernel-boot-parameters-to-libvirt-xml-55.patch -# PATCH_FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/189 -# PATCH_FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/185 -# PATCH_FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/184 -# PATCH_FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/183 -Patch101: virt.network_define-allow-adding-ip-configuration.patch -# PATCH_FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/196 -Patch102: add-virt.network_get_xml-function.patch -# PATCH_FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/198 -Patch103: list_downloaded-for-apt-module.patch +Patch81: virt-adding-kernel-boot-parameters-to-libvirt-xml-55.patch # PATCH_FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/200 -Patch104: support-for-btrfs-and-xfs-in-parted-and-mkfs.patch -# PATCH_FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/204 -Patch105: enable-passing-grains-to-start-event-based-on-start_.patch -# PATCH_FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/205 -Patch106: restrict-the-start_event_grains-only-to-the-start-ev.patch +Patch82: support-for-btrfs-and-xfs-in-parted-and-mkfs.patch # PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/56125 -Patch107: add-astra-linux-common-edition-to-the-os-family-list.patch +Patch83: add-astra-linux-common-edition-to-the-os-family-list.patch # PATCH_FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/211 -Patch108: apply-patch-from-upstream-to-support-python-3.8.patch +Patch84: apply-patch-from-upstream-to-support-python-3.8.patch # PATCH_FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/217 -Patch109: batch_async-avoid-using-fnmatch-to-match-event-217.patch +Patch85: batch_async-avoid-using-fnmatch-to-match-event-217.patch # PATCH_FIX_OPENSUSE: https://github.com/openSUSE/salt/commit/8a23030d347b7487328c0395f5e30ef29daf1455 -Patch110: batch-async-catch-exceptions-and-safety-unregister-a.patch +Patch86: batch-async-catch-exceptions-and-safety-unregister-a.patch # PATCH_FIX_OPENSUSE: https://github.com/openSUSE/salt/commit/a38adfa2efe40c2b1508b685af0b5d28a6bbcfc8 -Patch111: fix-unit-tests-for-batch-async-after-refactor.patch +Patch87: fix-unit-tests-for-batch-async-after-refactor.patch # PATCH_FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/218 -Patch112: use-full-option-name-instead-of-undocumented-abbrevi.patch +Patch88: use-full-option-name-instead-of-undocumented-abbrevi.patch +# PATCH_FIX_OPENSUSE: https://github.com/openSUSE/salt/commit/93c0630b84b9da89acaf549a5c79e5d834c70a65 +Patch89: removes-unresolved-merge-conflict-in-yumpkg-module.patch +# PATCH_FIX_OPENSUSE: https://github.com/openSUSE/salt/commit/b4c401cfe6031b61e27f7795bfa1aca6e8341e52 +Patch90: changed-imports-to-vendored-tornado.patch +# PATCH_FIX_OPENSUSE: https://github.com/openSUSE/salt/commit/082fa07e5301414b5b834b731aaa96bd5d966de7 +Patch91: add-missing-_utils-at-loader-grains_func.patch +# PATCH_FIX_OPENSUSE: https://github.com/openSUSE/salt/commit/25b4e3ea983b2606b2fb3d3c0e42f9840208bf84 +Patch92: remove-deprecated-usage-of-no_mock-and-no_mock_reaso.patch +# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/56215 +Patch93: fix-for-unless-requisite-when-pip-is-not-installed.patch +# PATCH_FIX_OPENSUSE: https://github.com/openSUSE/salt/commit/a8f0a15e4067ec278c8a2d690e3bf815523286ca +Patch94: fix-wrong-test_mod_del_repo_multiline_values-test-af.patch +# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/56185 +Patch95: fix-regression-in-service-states-with-reload-argumen.patch +# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/56369 +Patch96: make-salt.ext.tornado.gen-to-use-salt.ext.backports_.patch # PATCH_FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/221 -Patch113: loader-invalidate-the-import-cachefor-extra-modules.patch +Patch97: loader-invalidate-the-import-cachefor-extra-modules.patch # PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/55814 -Patch114: open-suse-2019.2.3-virt-defined-states-219.patch +Patch98: opensuse-3000-virt-defined-states-222.patch +# PATCH_FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/223 +Patch99: fix-for-temp-folder-definition-in-loader-unit-test.patch # PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/56392 -Patch115: virt._get_domain-don-t-raise-an-exception-if-there-i.patch -# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/50197 -Patch116: backport-saltutil-state-module-to-2019.2-codebase.patch +Patch100: virt._get_domain-don-t-raise-an-exception-if-there-i.patch +# PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/226 +Patch101: re-adding-function-to-test-for-root.patch +# PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/227 +Patch102: loop-fix-variable-names-for-until_no_eval.patch +# PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/226 +Patch103: make-setup.py-script-to-not-require-setuptools-9.1.patch +# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/50453 +# https://github.com/saltstack/salt/commit/e20362f6f053eaa4144583604e6aac3d62838419 +# Can be dropped one pull/50453 is in released version. +Patch104: reintroducing-reverted-changes.patch # PATCH_FIX_OPENSUSE: https://github.com/openSUSE/salt/commit/b713d0b3031faadc17cd9cf09977ccc19e50bef7 -Patch117: add-new-custom-suse-capability-for-saltutil-state-mo.patch -# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/55796 +Patch105: add-new-custom-suse-capability-for-saltutil-state-mo.patch +# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/56463 +Patch106: fix-typo-on-msgpack-version-when-sanitizing-msgpack-.patch # PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/56491 -Patch118: fix-load-cached-grain-osrelease_info.patch - +Patch107: sanitize-grains-loaded-from-roster_grains.json.patch +# PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/228 +Patch108: adds-explicit-type-cast-for-port.patch BuildRoot: %{_tmppath}/%{name}-%{version}-build BuildRequires: logrotate @@ -404,6 +379,7 @@ Group: System/Management Requires: %{name} = %{version}-%{release} BuildRequires: python >= 2.7 BuildRequires: python-devel >= 2.7 +BuildRequires: python-setuptools # requirements/base.txt %if 0%{?rhel} || 0%{?fedora} BuildRequires: python-jinja2 @@ -419,15 +395,7 @@ BuildRequires: python-futures >= 2.0 BuildRequires: python-msgpack-python > 0.3 BuildRequires: python-psutil BuildRequires: python-requests >= 1.0.0 -%if 0%{?suse_version} >= 1500 || 0%{?rhel} >= 8 || 0%{?fedora} >= 30 -# We can't cope with tornado 5.x and newer (boo#1101780); this is only relevant for SLE >= 15 and TW -# where tornado exists in multiple versions -BuildRequires: (python-tornado >= 4.2.1 with python-tornado < 5) -%else -BuildRequires: python-tornado >= 4.2.1 -# We can't cope with tornado 5.x and newer (boo#1101780) -BuildConflicts: python3-tornado >= 5 -%endif +BuildRequires: python-singledispatch # requirements/zeromq.txt %if 0%{?suse_version} >= 1500 @@ -473,9 +441,7 @@ Requires: python-futures >= 2.0 Requires: python-msgpack-python > 0.3 Requires: python-psutil Requires: python-requests >= 1.0.0 -Requires: python-tornado >= 4.2.1 -# We can't cope with tornado 5.x and newer (boo#1101780) -Conflicts: python3-tornado >= 5 +Requires: python-singledispatch %if 0%{?suse_version} # required for zypper.py Requires: rpm-python @@ -518,6 +484,7 @@ BuildRequires: platform-python BuildRequires: python3 %endif BuildRequires: python3-devel +BuildRequires: python3-setuptools # requirements/base.txt %if 0%{?rhel} || 0%{?fedora} BuildRequires: python3-jinja2 @@ -540,15 +507,6 @@ BuildRequires: python3-pycrypto >= 2.6.1 BuildRequires: python3-PyYAML BuildRequires: python3-psutil BuildRequires: python3-requests >= 1.0.0 -%if 0%{?suse_version} >= 1500 || 0%{?rhel} >= 8 || 0%{?fedora} >= 30 -# We can't cope with tornado 5.x and newer (boo#1101780); this is only relevant for SLE >= 15 and TW, -# where tornado exists in multiple versions -BuildRequires: (python3-tornado >= 4.2.1 with python3-tornado < 5) -%else -BuildRequires: python3-tornado >= 4.2.1 -# We can't cope with tornado 5.x and newer (boo#1101780) -BuildConflicts: python3-tornado >= 5 -%endif # requirements/zeromq.txt %if %{with test} @@ -603,9 +561,6 @@ Requires: python3-pyzmq >= 2.2.0 Requires: python3-PyYAML Requires: python3-psutil Requires: python3-requests >= 1.0.0 -Requires: python3-tornado >= 4.2.1 -# We can't cope with tornado 5.x and newer (boo#1101780) -Conflicts: python3-tornado >= 5 %if 0%{?suse_version} # required for zypper.py Requires: python3-rpm @@ -847,7 +802,7 @@ This package adds the standalone configuration for the Salt master in order to m %prep # %setup -q -n salt-%{version} -%setup -q -n salt-2019.2.3-suse +%setup -q -n salt-3000-suse cp %{S:1} . cp %{S:5} ./.travis.yml %patch1 -p1 @@ -958,16 +913,6 @@ cp %{S:5} ./.travis.yml %patch106 -p1 %patch107 -p1 %patch108 -p1 -%patch109 -p1 -%patch110 -p1 -%patch111 -p1 -%patch112 -p1 -%patch113 -p1 -%patch114 -p1 -%patch115 -p1 -%patch116 -p1 -%patch117 -p1 -%patch118 -p1 %build %if 0%{?build_py2} diff --git a/sanitize-grains-loaded-from-roster_grains.json.patch b/sanitize-grains-loaded-from-roster_grains.json.patch new file mode 100644 index 0000000..fc7ff42 --- /dev/null +++ b/sanitize-grains-loaded-from-roster_grains.json.patch @@ -0,0 +1,53 @@ +From 83a2a79ed3834a1cfd90941d0075d1c38341dc1d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?= + +Date: Wed, 1 Apr 2020 12:27:30 +0100 +Subject: [PATCH] Sanitize grains loaded from roster_grains.json + +Ensure _format_cached_grains is called on state.pkg test +--- + salt/modules/state.py | 3 ++- + tests/unit/modules/test_state.py | 4 +++- + 2 files changed, 5 insertions(+), 2 deletions(-) + +diff --git a/salt/modules/state.py b/salt/modules/state.py +index ec1e1edb42e9d8d5bc1e991434eb187e3b65ab89..a4f3f8c37086a79a60f85b5ca4b71d2af1e1f90f 100644 +--- a/salt/modules/state.py ++++ b/salt/modules/state.py +@@ -43,6 +43,7 @@ import salt.defaults.exitcodes + from salt.exceptions import CommandExecutionError, SaltInvocationError + from salt.runners.state import orchestrate as _orchestrate + from salt.utils.odict import OrderedDict ++from salt.loader import _format_cached_grains + + # Import 3rd-party libs + from salt.ext import six +@@ -2188,7 +2189,7 @@ def pkg(pkg_path, + roster_grains_json = os.path.join(root, 'roster_grains.json') + if os.path.isfile(roster_grains_json): + with salt.utils.files.fopen(roster_grains_json, 'r') as fp_: +- roster_grains = salt.utils.json.load(fp_) ++ roster_grains = _format_cached_grains(salt.utils.json.load(fp_)) + + if os.path.isfile(roster_grains_json): + popts['grains'] = roster_grains +diff --git a/tests/unit/modules/test_state.py b/tests/unit/modules/test_state.py +index e3c3dc8fc62efa848603082c3d8f3a8f09d5c426..cda846595eeec9788d17b55fcad5cab7a49a62c2 100644 +--- a/tests/unit/modules/test_state.py ++++ b/tests/unit/modules/test_state.py +@@ -1129,8 +1129,10 @@ class StateTestCase(TestCase, LoaderModuleMockMixin): + + MockTarFile.path = "" + with patch('salt.utils.files.fopen', mock_open()), \ +- patch.object(salt.utils.json, 'loads', mock_json_loads_true): ++ patch.object(salt.utils.json, 'loads', mock_json_loads_true), \ ++ patch.object(state, '_format_cached_grains', MagicMock()): + self.assertEqual(state.pkg(tar_file, 0, "md5"), True) ++ state._format_cached_grains.assert_called_once() + + MockTarFile.path = "" + if six.PY2: +-- +2.23.0 + + diff --git a/strip-trailing-from-repo.uri-when-comparing-repos-in.patch b/strip-trailing-from-repo.uri-when-comparing-repos-in.patch index 0573e04..b8628f2 100644 --- a/strip-trailing-from-repo.uri-when-comparing-repos-in.patch +++ b/strip-trailing-from-repo.uri-when-comparing-repos-in.patch @@ -1,4 +1,4 @@ -From 1cdaeb8613132c020364b7078448834be7bbb705 Mon Sep 17 00:00:00 2001 +From f2b465f41575a8a28d4762f9647ea30df6a64637 Mon Sep 17 00:00:00 2001 From: Matei Albu Date: Fri, 15 Feb 2019 14:34:13 +0100 Subject: [PATCH] Strip trailing "/" from repo.uri when comparing repos @@ -10,10 +10,10 @@ Subject: [PATCH] Strip trailing "/" from repo.uri when comparing repos 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/modules/aptpkg.py b/salt/modules/aptpkg.py -index b7c1a342ef..d49a48310e 100644 +index a5b039fc79..bafad40efe 100644 --- a/salt/modules/aptpkg.py +++ b/salt/modules/aptpkg.py -@@ -2354,7 +2354,7 @@ def mod_repo(repo, saltenv='base', **kwargs): +@@ -2365,7 +2365,7 @@ def mod_repo(repo, saltenv='base', **kwargs): # and the resulting source line. The idea here is to ensure # we are not returning bogus data because the source line # has already been modified on a previous run. diff --git a/support-config-non-root-permission-issues-fixes-u-50.patch b/support-config-non-root-permission-issues-fixes-u-50.patch index 0896c8f..3e0d2d7 100644 --- a/support-config-non-root-permission-issues-fixes-u-50.patch +++ b/support-config-non-root-permission-issues-fixes-u-50.patch @@ -1,4 +1,4 @@ -From f5d743b6a2a0dd2066e33d0a0ea13bfccc9ae9b0 Mon Sep 17 00:00:00 2001 +From be2f4d3da3612ca02f215f987e4055d2bd177a7b Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Wed, 17 Oct 2018 14:10:47 +0200 Subject: [PATCH] Support-config non-root permission issues fixes @@ -88,10 +88,10 @@ index 478d07e13b..a4343297b6 100644 else: self.out.warning('File {} already exists.'.format(self.config['support_archive'])) diff --git a/salt/utils/parsers.py b/salt/utils/parsers.py -index aa13310d5a..901bbbea55 100644 +index 83dfe717f6..5f98c73291 100644 --- a/salt/utils/parsers.py +++ b/salt/utils/parsers.py -@@ -1961,7 +1961,7 @@ class SaltSupportOptionParser(six.with_metaclass(OptionParserMeta, OptionParser, +@@ -1972,7 +1972,7 @@ class SaltSupportOptionParser(six.with_metaclass(OptionParserMeta, OptionParser, ''' _opts, _args = optparse.OptionParser.parse_args(self) configs = self.find_existing_configs(_opts.support_unit) diff --git a/support-for-btrfs-and-xfs-in-parted-and-mkfs.patch b/support-for-btrfs-and-xfs-in-parted-and-mkfs.patch index 932ecf4..05638f5 100644 --- a/support-for-btrfs-and-xfs-in-parted-and-mkfs.patch +++ b/support-for-btrfs-and-xfs-in-parted-and-mkfs.patch @@ -1,4 +1,4 @@ -From 92df25d10789e5d0686a882a1cbadbfc0602b2f5 Mon Sep 17 00:00:00 2001 +From 570b45e5a1f1786fe0f449a038f8f8a19b6b9ce2 Mon Sep 17 00:00:00 2001 From: Jochen Breuer Date: Fri, 10 Jan 2020 17:18:14 +0100 Subject: [PATCH] Support for Btrfs and XFS in parted and mkfs @@ -9,7 +9,7 @@ Subject: [PATCH] Support for Btrfs and XFS in parted and mkfs 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/salt/modules/parted_partition.py b/salt/modules/parted_partition.py -index c2e0ebb882..e68124c245 100644 +index c991530aba..9441fec49f 100644 --- a/salt/modules/parted_partition.py +++ b/salt/modules/parted_partition.py @@ -390,8 +390,8 @@ def _is_fstype(fs_type): @@ -24,10 +24,10 @@ index c2e0ebb882..e68124c245 100644 def mkfs(device, fs_type): diff --git a/tests/unit/modules/test_parted_partition.py b/tests/unit/modules/test_parted_partition.py -index 1959e5978e..5d92bd6d14 100644 +index aad2829867..571e30292b 100644 --- a/tests/unit/modules/test_parted_partition.py +++ b/tests/unit/modules/test_parted_partition.py -@@ -377,6 +377,22 @@ class PartedTestCase(TestCase, LoaderModuleMockMixin): +@@ -376,6 +376,22 @@ class PartedTestCase(TestCase, LoaderModuleMockMixin): } self.assertEqual(output, expected) diff --git a/switch-firewalld-state-to-use-change_interface.patch b/switch-firewalld-state-to-use-change_interface.patch index 116a498..b12059b 100644 --- a/switch-firewalld-state-to-use-change_interface.patch +++ b/switch-firewalld-state-to-use-change_interface.patch @@ -1,4 +1,4 @@ -From d21552ca35f9f90acc12e907251ed5ded3c2a5f7 Mon Sep 17 00:00:00 2001 +From c48d54fe6243614aba481c887208e473f58a5057 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?= Date: Mon, 20 May 2019 11:59:39 +0100 @@ -19,10 +19,10 @@ and updates `firewalld.present` state to use this call. 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/salt/modules/firewalld.py b/salt/modules/firewalld.py -index 7eeb865fa7..232fe052a2 100644 +index a6d90d38b8..c8b646024b 100644 --- a/salt/modules/firewalld.py +++ b/salt/modules/firewalld.py -@@ -951,6 +951,29 @@ def remove_interface(zone, interface, permanent=True): +@@ -932,6 +932,29 @@ def remove_interface(zone, interface, permanent=True): return __firewall_cmd(cmd) @@ -53,10 +53,10 @@ index 7eeb865fa7..232fe052a2 100644 ''' List sources bound to a zone diff --git a/salt/states/firewalld.py b/salt/states/firewalld.py -index 4623798658..fc5b233f98 100644 +index 25cbad170a..e4338beaf2 100644 --- a/salt/states/firewalld.py +++ b/salt/states/firewalld.py -@@ -647,8 +647,8 @@ def _present(name, +@@ -633,8 +633,8 @@ def _present(name, for interface in new_interfaces: if not __opts__['test']: try: diff --git a/take-checksums-arg-into-account-for-postgres.datadir.patch b/take-checksums-arg-into-account-for-postgres.datadir.patch deleted file mode 100644 index 1e241a7..0000000 --- a/take-checksums-arg-into-account-for-postgres.datadir.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 34659b17ef083021c582ec0e7d225f94e409b500 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?= - -Date: Thu, 26 Sep 2019 15:57:58 +0100 -Subject: [PATCH] Take checksums arg into account for - postgres.datadir_init (bsc#1151650) - -Update unit test for postgres.datadir_init ---- - salt/modules/postgres.py | 1 + - tests/unit/modules/test_postgres.py | 1 + - 2 files changed, 2 insertions(+) - -diff --git a/salt/modules/postgres.py b/salt/modules/postgres.py -index b6f7cbe5d4..f0d1b034b9 100644 ---- a/salt/modules/postgres.py -+++ b/salt/modules/postgres.py -@@ -3151,6 +3151,7 @@ def datadir_init(name, - password=password, - encoding=encoding, - locale=locale, -+ checksums=checksums, - runas=runas) - return ret['retcode'] == 0 - -diff --git a/tests/unit/modules/test_postgres.py b/tests/unit/modules/test_postgres.py -index 03fb7fddfd..6f10fcf2e0 100644 ---- a/tests/unit/modules/test_postgres.py -+++ b/tests/unit/modules/test_postgres.py -@@ -1467,6 +1467,7 @@ class PostgresTestCase(TestCase, LoaderModuleMockMixin): - locale=None, - password='test', - runas='postgres', -+ checksums=False, - user='postgres', - ) - self.assertTrue(ret) --- -2.16.4 - - diff --git a/temporary-fix-extend-the-whitelist-of-allowed-comman.patch b/temporary-fix-extend-the-whitelist-of-allowed-comman.patch index afea0f4..78fb15b 100644 --- a/temporary-fix-extend-the-whitelist-of-allowed-comman.patch +++ b/temporary-fix-extend-the-whitelist-of-allowed-comman.patch @@ -1,4 +1,4 @@ -From 6a3a1b36ba7157a6318084bd67acda3ad9f9556e Mon Sep 17 00:00:00 2001 +From 89c188107bc60d4e84879c3f3c2fde7489a14153 Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Thu, 24 Jan 2019 18:12:35 +0100 Subject: [PATCH] temporary fix: extend the whitelist of allowed commands @@ -8,7 +8,7 @@ Subject: [PATCH] temporary fix: extend the whitelist of allowed commands 1 file changed, 2 insertions(+) diff --git a/salt/auth/__init__.py b/salt/auth/__init__.py -index cf5e2deb9c..d43c57338c 100644 +index 329e4a62c9..ecbd1c808c 100644 --- a/salt/auth/__init__.py +++ b/salt/auth/__init__.py @@ -47,6 +47,8 @@ AUTH_INTERNAL_KEYWORDS = frozenset([ diff --git a/use-adler32-algorithm-to-compute-string-checksums.patch b/use-adler32-algorithm-to-compute-string-checksums.patch index b35ebbd..8961ffb 100644 --- a/use-adler32-algorithm-to-compute-string-checksums.patch +++ b/use-adler32-algorithm-to-compute-string-checksums.patch @@ -1,4 +1,4 @@ -From c1e2410749479940275a217d598b22b24eef8758 Mon Sep 17 00:00:00 2001 +From a8e3defcb484296e18343c6447649fe508ab2644 Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Sat, 28 Jul 2018 22:59:04 +0200 Subject: [PATCH] Use Adler32 algorithm to compute string checksums @@ -20,10 +20,10 @@ Add warning for Sodium. 2 files changed, 41 insertions(+), 19 deletions(-) diff --git a/salt/config/__init__.py b/salt/config/__init__.py -index f4496f3a61..b272610fa4 100644 +index 70b34ec949..0ebe1181dd 100644 --- a/salt/config/__init__.py +++ b/salt/config/__init__.py -@@ -1221,6 +1221,10 @@ VALID_OPTS = { +@@ -1190,6 +1190,10 @@ VALID_OPTS = immutabletypes.freeze({ # Allow raw_shell option when using the ssh # client via the Salt API 'netapi_allow_raw_shell': bool, @@ -31,21 +31,21 @@ index f4496f3a61..b272610fa4 100644 + # Use Adler32 hashing algorithm for server_id (default False until Sodium, "adler32" after) + # Possible values are: False, adler32, crc32 + 'server_id_use_crc': (bool, six.string_types), - } + }) # default configurations -@@ -1529,7 +1533,8 @@ DEFAULT_MINION_OPTS = { - }, +@@ -1480,7 +1484,8 @@ DEFAULT_MINION_OPTS = immutabletypes.freeze({ + 'minion_sign_messages': False, 'discovery': False, 'schedule': {}, - 'ssh_merge_pillar': True + 'ssh_merge_pillar': True, + 'server_id_use_crc': False, - } + }) - DEFAULT_MASTER_OPTS = { + DEFAULT_MASTER_OPTS = immutabletypes.freeze({ diff --git a/salt/grains/core.py b/salt/grains/core.py -index 82cd3fb657..cd7ee39d2f 100644 +index 2851809472..9c1b5d930e 100644 --- a/salt/grains/core.py +++ b/salt/grains/core.py @@ -20,6 +20,7 @@ import platform @@ -64,7 +64,7 @@ index 82cd3fb657..cd7ee39d2f 100644 from salt.ext import six from salt.ext.six.moves import range -@@ -2785,40 +2787,55 @@ def _hw_data(osdata): +@@ -2792,40 +2794,55 @@ def _hw_data(osdata): return grains diff --git a/use-current-ioloop-for-the-localclient-instance-of-b.patch b/use-current-ioloop-for-the-localclient-instance-of-b.patch index 24aa47a..48d6eea 100644 --- a/use-current-ioloop-for-the-localclient-instance-of-b.patch +++ b/use-current-ioloop-for-the-localclient-instance-of-b.patch @@ -1,4 +1,4 @@ -From 1947ddfd6883de285c82ba4bb6423454216e37c4 Mon Sep 17 00:00:00 2001 +From 1ab46d5f9ed435021aa8eeb40ada984f42c8e93d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?= Date: Thu, 3 Oct 2019 15:19:02 +0100 diff --git a/use-full-option-name-instead-of-undocumented-abbrevi.patch b/use-full-option-name-instead-of-undocumented-abbrevi.patch index fed150d..b800758 100644 --- a/use-full-option-name-instead-of-undocumented-abbrevi.patch +++ b/use-full-option-name-instead-of-undocumented-abbrevi.patch @@ -1,4 +1,4 @@ -From b06d2882f4e89011b1f5eeb442620b4543694140 Mon Sep 17 00:00:00 2001 +From c4742f553fe60aee82577622def1eeca0e2abf93 Mon Sep 17 00:00:00 2001 From: Michael Calmer Date: Sun, 1 Mar 2020 16:22:54 +0100 Subject: [PATCH] use full option name instead of undocumented @@ -10,10 +10,10 @@ Subject: [PATCH] use full option name instead of undocumented 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/salt/modules/zypperpkg.py b/salt/modules/zypperpkg.py -index 8c1e05c21c..19d1fd96c7 100644 +index 0c15214e5e..e3f802a911 100644 --- a/salt/modules/zypperpkg.py +++ b/salt/modules/zypperpkg.py -@@ -2494,7 +2494,7 @@ def list_products(all=False, refresh=False, root=None): +@@ -2498,7 +2498,7 @@ def list_products(all=False, refresh=False, root=None): OEM_PATH = os.path.join(root, os.path.relpath(OEM_PATH, os.path.sep)) cmd = list() if not all: @@ -23,10 +23,10 @@ index 8c1e05c21c..19d1fd96c7 100644 if not all: cmd.append('-i') diff --git a/tests/unit/modules/test_zypperpkg.py b/tests/unit/modules/test_zypperpkg.py -index 7617113401..ae85152d30 100644 +index 76937cc358..2a8e753b9d 100644 --- a/tests/unit/modules/test_zypperpkg.py +++ b/tests/unit/modules/test_zypperpkg.py -@@ -241,7 +241,18 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin): +@@ -238,7 +238,18 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin): 'stdout': get_test_data(filename) } @@ -46,7 +46,7 @@ index 7617113401..ae85152d30 100644 products = zypper.list_products() self.assertEqual(len(products), 7) self.assertIn(test_data['vendor'], [product['vendor'] for product in products]) -@@ -250,6 +261,7 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin): +@@ -247,6 +258,7 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin): self.assertCountEqual(test_data[kwd], [prod.get(kwd) for prod in products]) else: self.assertEqual(test_data[kwd], sorted([prod.get(kwd) for prod in products])) diff --git a/use-threadpool-from-multiprocessing.pool-to-avoid-le.patch b/use-threadpool-from-multiprocessing.pool-to-avoid-le.patch index e8cefd3..566ca90 100644 --- a/use-threadpool-from-multiprocessing.pool-to-avoid-le.patch +++ b/use-threadpool-from-multiprocessing.pool-to-avoid-le.patch @@ -1,4 +1,4 @@ -From a4735644b2e6527e36796722516540f153ccabb9 Mon Sep 17 00:00:00 2001 +From 1f50b796dd551c25a8fc87fe825d1508f340858e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?= Date: Tue, 30 Apr 2019 10:51:42 +0100 @@ -10,7 +10,7 @@ Subject: [PATCH] Use ThreadPool from multiprocessing.pool to avoid 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/salt/grains/core.py b/salt/grains/core.py -index ac66a437fd..38b82b7f7c 100644 +index 4600f055dd..f1e3ebe9d2 100644 --- a/salt/grains/core.py +++ b/salt/grains/core.py @@ -27,7 +27,7 @@ import datetime @@ -22,7 +22,7 @@ index ac66a437fd..38b82b7f7c 100644 # pylint: disable=import-error try: -@@ -2280,10 +2280,14 @@ def fqdns(): +@@ -2300,10 +2300,14 @@ def fqdns(): # Create a ThreadPool to process the underlying calls to 'socket.gethostbyaddr' in parallel. # This avoid blocking the execution when the "fqdn" is not defined for certains IP addresses, which was causing # that "socket.timeout" was reached multiple times secuencially, blocking execution for several seconds. diff --git a/v2019.2.3.tar.gz b/v2019.2.3.tar.gz deleted file mode 100644 index 16281ec..0000000 --- a/v2019.2.3.tar.gz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:76745e1d409f01004e9bdc677ecc5ac48edba5b532996a341499ad1bacd8007c -size 14661032 diff --git a/v3000.tar.gz b/v3000.tar.gz new file mode 100644 index 0000000..451f604 --- /dev/null +++ b/v3000.tar.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:47118206f5c3480796cec0c15f2efdcb79200c3636576758437f65c35daf2667 +size 15191254 diff --git a/virt-1.volume_infos-fix-for-single-vm.patch b/virt-1.volume_infos-fix-for-single-vm.patch deleted file mode 100644 index 38dc525..0000000 --- a/virt-1.volume_infos-fix-for-single-vm.patch +++ /dev/null @@ -1,91 +0,0 @@ -From 4e32b8efa3ef393f2d19d5f06a16668a514044c1 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?C=C3=A9dric=20Bosdonnat?= -Date: Thu, 4 Apr 2019 16:18:58 +0200 -Subject: [PATCH] virt.volume_infos fix for single VM - -virt.volume_infos: don't raise an error if there is no VM ---- - salt/modules/virt.py | 8 +++++-- - tests/unit/modules/test_virt.py | 46 +++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 52 insertions(+), 2 deletions(-) - -diff --git a/salt/modules/virt.py b/salt/modules/virt.py -index d160f0905f..953064cc2c 100644 ---- a/salt/modules/virt.py -+++ b/salt/modules/virt.py -@@ -5050,8 +5050,12 @@ def volume_infos(pool=None, volume=None, **kwargs): - conn = __get_conn(**kwargs) - try: - backing_stores = _get_all_volumes_paths(conn) -- domains = _get_domain(conn) -- domains_list = domains if isinstance(domains, list) else [domains] -+ try: -+ domains = _get_domain(conn) -+ domains_list = domains if isinstance(domains, list) else [domains] -+ except CommandExecutionError: -+ # Having no VM is not an error here. -+ domains_list = [] - disks = {domain.name(): - {node.get('file') for node - in ElementTree.fromstring(domain.XMLDesc(0)).findall('.//disk/source/[@file]')} -diff --git a/tests/unit/modules/test_virt.py b/tests/unit/modules/test_virt.py -index cc62b67918..b343b9bc31 100644 ---- a/tests/unit/modules/test_virt.py -+++ b/tests/unit/modules/test_virt.py -@@ -2910,6 +2910,52 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin): - } - }) - -+ # No VM test -+ with patch('salt.modules.virt._get_domain', MagicMock(side_effect=CommandExecutionError('no VM'))): -+ actual = virt.volume_infos('pool0', 'vol0') -+ self.assertEqual(1, len(actual.keys())) -+ self.assertEqual(1, len(actual['pool0'].keys())) -+ self.assertEqual([], sorted(actual['pool0']['vol0']['used_by'])) -+ self.assertEqual('/path/to/vol0.qcow2', actual['pool0']['vol0']['path']) -+ self.assertEqual('file', actual['pool0']['vol0']['type']) -+ self.assertEqual('/key/of/vol0', actual['pool0']['vol0']['key']) -+ self.assertEqual(123456789, actual['pool0']['vol0']['capacity']) -+ self.assertEqual(123456, actual['pool0']['vol0']['allocation']) -+ -+ self.assertEqual(virt.volume_infos('pool1', None), { -+ 'pool1': { -+ 'vol1': { -+ 'type': 'file', -+ 'key': '/key/of/vol1', -+ 'path': '/path/to/vol1.qcow2', -+ 'capacity': 12345, -+ 'allocation': 1234, -+ 'used_by': [], -+ }, -+ 'vol2': { -+ 'type': 'file', -+ 'key': '/key/of/vol2', -+ 'path': '/path/to/vol2.qcow2', -+ 'capacity': 12345, -+ 'allocation': 1234, -+ 'used_by': [], -+ } -+ } -+ }) -+ -+ self.assertEqual(virt.volume_infos(None, 'vol2'), { -+ 'pool1': { -+ 'vol2': { -+ 'type': 'file', -+ 'key': '/key/of/vol2', -+ 'path': '/path/to/vol2.qcow2', -+ 'capacity': 12345, -+ 'allocation': 1234, -+ 'used_by': [], -+ } -+ } -+ }) -+ - def test_volume_delete(self): - ''' - Test virt.volume_delete --- -2.16.4 - - diff --git a/virt-adding-kernel-boot-parameters-to-libvirt-xml-55.patch b/virt-adding-kernel-boot-parameters-to-libvirt-xml-55.patch index 3899337..9c811c6 100644 --- a/virt-adding-kernel-boot-parameters-to-libvirt-xml-55.patch +++ b/virt-adding-kernel-boot-parameters-to-libvirt-xml-55.patch @@ -1,4 +1,4 @@ -From 26a227868bcf1f790348e197e000561903f7fc72 Mon Sep 17 00:00:00 2001 +From f8ccfae9908d6a1001d68a1b8e5e8cee495b5aef Mon Sep 17 00:00:00 2001 From: Larry Dewey Date: Tue, 7 Jan 2020 02:48:11 -0700 Subject: [PATCH] virt: adding kernel boot parameters to libvirt xml @@ -17,258 +17,16 @@ Signed-off-by: Larry Dewey Signed-off-by: Larry Dewey --- - salt/modules/virt.py | 129 ++++++++++++++++++++++- - salt/states/virt.py | 29 ++++- - salt/templates/virt/libvirt_domain.jinja | 12 ++- - salt/utils/virt.py | 45 +++++++- - tests/unit/modules/test_virt.py | 79 +++++++++++++- - tests/unit/states/test_virt.py | 19 +++- - 6 files changed, 302 insertions(+), 11 deletions(-) + salt/states/virt.py | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) -diff --git a/salt/modules/virt.py b/salt/modules/virt.py -index dedcf8cb6f..0f62856f5c 100644 ---- a/salt/modules/virt.py -+++ b/salt/modules/virt.py -@@ -106,6 +106,8 @@ import salt.utils.templates - import salt.utils.validate.net - import salt.utils.versions - import salt.utils.yaml -+ -+from salt.utils.virt import check_remote, download_remote - from salt.exceptions import CommandExecutionError, SaltInvocationError - from salt.ext import six - from salt.ext.six.moves import range # pylint: disable=import-error,redefined-builtin -@@ -119,6 +121,8 @@ JINJA = jinja2.Environment( - ) - ) - -+CACHE_DIR = '/var/lib/libvirt/saltinst' -+ - VIRT_STATE_NAME_MAP = {0: 'running', - 1: 'running', - 2: 'running', -@@ -532,6 +536,7 @@ def _gen_xml(name, - os_type, - arch, - graphics=None, -+ boot=None, - **kwargs): - ''' - Generate the XML string to define a libvirt VM -@@ -568,11 +573,15 @@ def _gen_xml(name, - else: - context['boot_dev'] = ['hd'] - -+ context['boot'] = boot if boot else {} -+ - if os_type == 'xen': - # Compute the Xen PV boot method - if __grains__['os_family'] == 'Suse': -- context['kernel'] = '/usr/lib/grub2/x86_64-xen/grub.xen' -- context['boot_dev'] = [] -+ if not boot or not boot.get('kernel', None): -+ context['boot']['kernel'] = \ -+ '/usr/lib/grub2/x86_64-xen/grub.xen' -+ context['boot_dev'] = [] - - if 'serial_type' in kwargs: - context['serial_type'] = kwargs['serial_type'] -@@ -1115,6 +1124,34 @@ def _get_merged_nics(hypervisor, profile, interfaces=None, dmac=None): - return nicp - - -+def _handle_remote_boot_params(orig_boot): -+ """ -+ Checks if the boot parameters contain a remote path. If so, it will copy -+ the parameters, download the files specified in the remote path, and return -+ a new dictionary with updated paths containing the canonical path to the -+ kernel and/or initrd -+ -+ :param orig_boot: The original boot parameters passed to the init or update -+ functions. -+ """ -+ saltinst_dir = None -+ new_boot = orig_boot.copy() -+ -+ try: -+ for key in ['kernel', 'initrd']: -+ if check_remote(orig_boot.get(key)): -+ if saltinst_dir is None: -+ os.makedirs(CACHE_DIR) -+ saltinst_dir = CACHE_DIR -+ -+ new_boot[key] = download_remote(orig_boot.get(key), -+ saltinst_dir) -+ -+ return new_boot -+ except Exception as err: -+ raise err -+ -+ - def init(name, - cpu, - mem, -@@ -1136,6 +1173,7 @@ def init(name, - graphics=None, - os_type=None, - arch=None, -+ boot=None, - **kwargs): - ''' - Initialize a new vm -@@ -1266,6 +1304,22 @@ def init(name, - :param password: password to connect with, overriding defaults - - .. versionadded:: 2019.2.0 -+ :param boot: -+ Specifies kernel for the virtual machine, as well as boot parameters -+ for the virtual machine. This is an optionl parameter, and all of the -+ keys are optional within the dictionary. If a remote path is provided -+ to kernel or initrd, salt will handle the downloading of the specified -+ remote fild, and will modify the XML accordingly. -+ -+ .. code-block:: python -+ -+ { -+ 'kernel': '/root/f8-i386-vmlinuz', -+ 'initrd': '/root/f8-i386-initrd', -+ 'cmdline': 'console=ttyS0 ks=http://example.com/f8-i386/os/' -+ } -+ -+ .. versionadded:: neon - - .. _init-nic-def: - -@@ -1513,7 +1567,11 @@ def init(name, - if arch is None: - arch = 'x86_64' if 'x86_64' in arches else arches[0] - -- vm_xml = _gen_xml(name, cpu, mem, diskp, nicp, hypervisor, os_type, arch, graphics, **kwargs) -+ if boot is not None: -+ boot = _handle_remote_boot_params(boot) -+ -+ vm_xml = _gen_xml(name, cpu, mem, diskp, nicp, hypervisor, os_type, arch, -+ graphics, boot, **kwargs) - conn = __get_conn(**kwargs) - try: - conn.defineXML(vm_xml) -@@ -1692,6 +1750,7 @@ def update(name, - interfaces=None, - graphics=None, - live=True, -+ boot=None, - **kwargs): - ''' - Update the definition of an existing domain. -@@ -1727,6 +1786,23 @@ def update(name, - :param username: username to connect with, overriding defaults - :param password: password to connect with, overriding defaults - -+ :param boot: -+ Specifies kernel for the virtual machine, as well as boot parameters -+ for the virtual machine. This is an optionl parameter, and all of the -+ keys are optional within the dictionary. If a remote path is provided -+ to kernel or initrd, salt will handle the downloading of the specified -+ remote fild, and will modify the XML accordingly. -+ -+ .. code-block:: python -+ -+ { -+ 'kernel': '/root/f8-i386-vmlinuz', -+ 'initrd': '/root/f8-i386-initrd', -+ 'cmdline': 'console=ttyS0 ks=http://example.com/f8-i386/os/' -+ } -+ -+ .. versionadded:: neon -+ - :return: - - Returns a dictionary indicating the status of what has been done. It is structured in -@@ -1767,6 +1843,10 @@ def update(name, - # Compute the XML to get the disks, interfaces and graphics - hypervisor = desc.get('type') - all_disks = _disk_profile(disk_profile, hypervisor, disks, name, **kwargs) -+ -+ if boot is not None: -+ boot = _handle_remote_boot_params(boot) -+ - new_desc = ElementTree.fromstring(_gen_xml(name, - cpu, - mem, -@@ -1776,6 +1856,7 @@ def update(name, - domain.OSType(), - desc.find('.//os/type').get('arch'), - graphics, -+ boot, - **kwargs)) - - # Update the cpu -@@ -1785,6 +1866,48 @@ def update(name, - cpu_node.set('current', six.text_type(cpu)) - need_update = True - -+ # Update the kernel boot parameters -+ boot_tags = ['kernel', 'initrd', 'cmdline'] -+ parent_tag = desc.find('os') -+ -+ # We need to search for each possible subelement, and update it. -+ for tag in boot_tags: -+ # The Existing Tag... -+ found_tag = desc.find(tag) -+ -+ # The new value -+ boot_tag_value = boot.get(tag, None) if boot else None -+ -+ # Existing tag is found and values don't match -+ if found_tag and found_tag.text != boot_tag_value: -+ -+ # If the existing tag is found, but the new value is None -+ # remove it. If the existing tag is found, and the new value -+ # doesn't match update it. In either case, mark for update. -+ if boot_tag_value is None \ -+ and boot is not None \ -+ and parent_tag is not None: -+ ElementTree.remove(parent_tag, tag) -+ else: -+ found_tag.text = boot_tag_value -+ -+ need_update = True -+ -+ # Existing tag is not found, but value is not None -+ elif found_tag is None and boot_tag_value is not None: -+ -+ # Need to check for parent tag, and add it if it does not exist. -+ # Add a subelement and set the value to the new value, and then -+ # mark for update. -+ if parent_tag is not None: -+ child_tag = ElementTree.SubElement(parent_tag, tag) -+ else: -+ new_parent_tag = ElementTree.Element('os') -+ child_tag = ElementTree.SubElement(new_parent_tag, tag) -+ -+ child_tag.text = boot_tag_value -+ need_update = True -+ - # Update the memory, note that libvirt outputs all memory sizes in KiB - for mem_node_name in ['memory', 'currentMemory']: - mem_node = desc.find(mem_node_name) diff --git a/salt/states/virt.py b/salt/states/virt.py -index 68e9ac6fb6..c700cae849 100644 +index 500509fcc0..55a9ad2616 100644 --- a/salt/states/virt.py +++ b/salt/states/virt.py -@@ -264,7 +264,8 @@ def running(name, - username=None, - password=None, - os_type=None, -- arch=None): -+ arch=None, -+ boot=None): - ''' - Starts an existing guest, or defines and starts a new VM with specified arguments. +@@ -367,6 +367,23 @@ def running(name, -@@ -349,6 +350,23 @@ def running(name, - - .. versionadded:: Neon + .. versionadded:: 3000 + :param boot: + Specifies kernel for the virtual machine, as well as boot parameters @@ -285,299 +43,12 @@ index 68e9ac6fb6..c700cae849 100644 + 'cmdline': 'console=ttyS0 ks=http://example.com/f8-i386/os/' + } + -+ .. versionadded:: neon ++ .. versionadded:: 3000 + .. rubric:: Example States Make sure an already-defined virtual machine called ``domain_name`` is running: -@@ -413,7 +431,8 @@ def running(name, - live=False, - connection=connection, - username=username, -- password=password) -+ password=password, -+ boot=boot) - if status['definition']: - action_msg = 'updated and started' - __salt__['virt.start'](name) -@@ -431,7 +450,8 @@ def running(name, - graphics=graphics, - connection=connection, - username=username, -- password=password) -+ password=password, -+ boot=boot) - ret['changes'][name] = status - if status.get('errors', None): - ret['comment'] = 'Domain {0} updated, but some live update(s) failed'.format(name) -@@ -466,7 +486,8 @@ def running(name, - priv_key=priv_key, - connection=connection, - username=username, -- password=password) -+ password=password, -+ boot=boot) - ret['changes'][name] = 'Domain defined and started' - ret['comment'] = 'Domain {0} defined and started'.format(name) - except libvirt.libvirtError as err: -diff --git a/salt/templates/virt/libvirt_domain.jinja b/salt/templates/virt/libvirt_domain.jinja -index 0b4c3fc2d6..fdaea168f2 100644 ---- a/salt/templates/virt/libvirt_domain.jinja -+++ b/salt/templates/virt/libvirt_domain.jinja -@@ -5,7 +5,17 @@ - {{ mem }} - - {{ os_type }} -- {% if kernel %}{{ kernel }}{% endif %} -+ {% if boot %} -+ {% if 'kernel' in boot %} -+ {{ boot.kernel }} -+ {% endif %} -+ {% if 'initrd' in boot %} -+ {{ boot.initrd }} -+ {% endif %} -+ {% if 'cmdline' in boot %} -+ {{ boot.cmdline }} -+ {% endif %} -+ {% endif %} - {% for dev in boot_dev %} - - {% endfor %} -diff --git a/salt/utils/virt.py b/salt/utils/virt.py -index 9dad849c0e..b36adba81c 100644 ---- a/salt/utils/virt.py -+++ b/salt/utils/virt.py -@@ -6,16 +6,59 @@ from __future__ import absolute_import, print_function, unicode_literals - - # Import python libs - import os -+import re - import time - import logging -+import hashlib -+ -+# pylint: disable=E0611 -+from salt.ext.six.moves.urllib.parse import urlparse -+from salt.ext.six.moves.urllib import request - - # Import salt libs - import salt.utils.files - -- - log = logging.getLogger(__name__) - - -+def download_remote(url, dir): -+ """ -+ Attempts to download a file specified by 'url' -+ -+ :param url: The full remote path of the file which should be downloaded. -+ :param dir: The path the file should be downloaded to. -+ """ -+ -+ try: -+ rand = hashlib.md5(os.urandom(32)).hexdigest() -+ remote_filename = urlparse(url).path.split('/')[-1] -+ full_directory = \ -+ os.path.join(dir, "{}-{}".format(rand, remote_filename)) -+ with salt.utils.files.fopen(full_directory, 'wb') as file,\ -+ request.urlopen(url) as response: -+ file.write(response.rease()) -+ -+ return full_directory -+ -+ except Exception as err: -+ raise err -+ -+ -+def check_remote(cmdline_path): -+ """ -+ Checks to see if the path provided contains ftp, http, or https. Returns -+ the full path if it is found. -+ -+ :param cmdline_path: The path to the initrd image or the kernel -+ """ -+ regex = re.compile('^(ht|f)tps?\\b') -+ -+ if regex.match(urlparse(cmdline_path).scheme): -+ return True -+ -+ return False -+ -+ - class VirtKey(object): - ''' - Used to manage key signing requests. -diff --git a/tests/unit/modules/test_virt.py b/tests/unit/modules/test_virt.py -index 6f594a8ff3..4bdb933a2d 100644 ---- a/tests/unit/modules/test_virt.py -+++ b/tests/unit/modules/test_virt.py -@@ -10,6 +10,7 @@ from __future__ import absolute_import, print_function, unicode_literals - import os - import re - import datetime -+import shutil - - # Import Salt Testing libs - from tests.support.mixins import LoaderModuleMockMixin -@@ -23,6 +24,7 @@ import salt.modules.config as config - from salt._compat import ElementTree as ET - import salt.config - import salt.syspaths -+import tempfile - from salt.exceptions import CommandExecutionError - - # Import third party libs -@@ -30,7 +32,6 @@ from salt.ext import six - # pylint: disable=import-error - from salt.ext.six.moves import range # pylint: disable=redefined-builtin - -- - # pylint: disable=invalid-name,protected-access,attribute-defined-outside-init,too-many-public-methods,unused-argument - - -@@ -610,6 +611,7 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin): - 'xen', - 'xen', - 'x86_64', -+ boot=None - ) - root = ET.fromstring(xml_data) - self.assertEqual(root.attrib['type'], 'xen') -@@ -1123,6 +1125,67 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin): - self.assertFalse(' Date: Tue, 17 Mar 2020 11:01:48 +0100 Subject: [PATCH] virt._get_domain: don't raise an exception if there @@ -12,7 +12,7 @@ looking for some VMs, but not when listing all VMs. 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/salt/modules/virt.py b/salt/modules/virt.py -index b44d1a65bf97a363c2fe7a871e090cb9ca957e03..46a349ef98aa78483291dcafb38b4541bf0ac247 100644 +index f0820e882524e1ebaae335e0a72940d6ff85c1b2..c8e046a47ae76b50651871fe1d149590d5d1e930 100644 --- a/salt/modules/virt.py +++ b/salt/modules/virt.py @@ -268,7 +268,7 @@ def _get_domain(conn, *vms, **kwargs): @@ -25,10 +25,10 @@ index b44d1a65bf97a363c2fe7a871e090cb9ca957e03..46a349ef98aa78483291dcafb38b4541 if vms: diff --git a/tests/unit/modules/test_virt.py b/tests/unit/modules/test_virt.py -index 2d3417ce91506a1819dbe03045a89887c9d19721..2696ed9d1bb892ee539b385e32393f8f98d23a30 100644 +index 8690154662f41c8d9699fba62fcda6d83208a7d7..3e9bd5ef49dfddc019f9b4da1b505d81018e7eed 100644 --- a/tests/unit/modules/test_virt.py +++ b/tests/unit/modules/test_virt.py -@@ -3634,3 +3634,44 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin): +@@ -3639,3 +3639,44 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin): } }, [backend for backend in backends if backend['name'] == 'netfs'][0]['options']) diff --git a/virt.network_define-allow-adding-ip-configuration.patch b/virt.network_define-allow-adding-ip-configuration.patch deleted file mode 100644 index de698e9..0000000 --- a/virt.network_define-allow-adding-ip-configuration.patch +++ /dev/null @@ -1,2074 +0,0 @@ -From 83fa82b713ac92371b1a6c1cf2b909fc440d30d0 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?C=C3=A9dric=20Bosdonnat?= -Date: Tue, 13 Aug 2019 12:26:59 +0200 -Subject: [PATCH] virt.network_define allow adding IP configuration - -If using virt.network_define with nat network type, then libvirt -complains about missing IP configuration. Allow setting it in both the -virt.network_define module and the virt.network_running state. - -Add virt.pool_deleted state - -The new virt.pool_deleted state takes care of removing a virtual storage -pool and optionally the contained volumes. - -Fix virt._gen_pool_xml when all source parameters are None - -When all the source_* parameters of _gen_pool_xml are None, no -element should be generated. Instead we had the following: - - - -Rather than filling a source structure with empty members, directly pass -a None for the source as expected by the jinja template. - -Add virt.pool_update function - -Add a function that allows changing a virtual storage pool. By using the -test=True parameter, this function can be used to check if a change -would be done. - -virt.pool_running state improvements - -With this commit the virt.pool_running state is capable to update an -existing pool before ensuring it is running. - -This also adds support for the test parameter. - -Fix virt.pool_define documentation - -virt.pool_define example are mentioning a uuid property while this one -should be named value. The code was right, but not the doc. - -Add source_initiator parameter in virt.pool_define - -In order to define iscsi-direct virtual storage pools, the use needs to -be able to provide the initiator IQN. Add a parameter for it in: - * virt.pool_define module function - * virt.pool_update module function - * virt.pool_running state - -virt pool secret have no type attribute - -According to libvirt schemas and doc only the volume secrets have a -type. - -virt: create and update pool secret's password for the user - -Libvirt stores RBD and iSCSI passwords in secrets. Add a password field -in the source_auth parameter of virt.pool_define and virt.pool_update to -set the password value rather than reuse an already defined libvirt -secret. - -virt.pool_define: remove potential leading / in CIFS source path - -libvirt needs the CIFS source path not to start with a /. Let's remove -them since this could be a common user mistake. - -Add virt.pool_capabilities function - -Not all storage backends are supported for a given libvirt hypervisor. For the user -to know what is supported and what is not expose the recently added -libvirt function providing pool capabilities. - -For older libvirt version, let's craft data that are reasonable by -adding a computed flag to warn these data may not be 100% accurate. ---- - salt/modules/virt.py | 497 +++++++++++++++++++++++++++++- - salt/states/virt.py | 279 +++++++++++++++-- - salt/templates/virt/libvirt_network.jinja | 13 +- - salt/templates/virt/libvirt_pool.jinja | 13 +- - salt/templates/virt/libvirt_secret.jinja | 12 + - tests/unit/modules/test_virt.py | 455 ++++++++++++++++++++++++++- - tests/unit/states/test_virt.py | 400 +++++++++++++++++++----- - 7 files changed, 1543 insertions(+), 126 deletions(-) - create mode 100644 salt/templates/virt/libvirt_secret.jinja - -diff --git a/salt/modules/virt.py b/salt/modules/virt.py -index 0f62856f5c..44c7e78ef0 100644 ---- a/salt/modules/virt.py -+++ b/salt/modules/virt.py -@@ -74,6 +74,7 @@ The calls not using the libvirt connection setup are: - - # Import python libs - from __future__ import absolute_import, print_function, unicode_literals -+import base64 - import copy - import os - import re -@@ -111,6 +112,7 @@ from salt.utils.virt import check_remote, download_remote - from salt.exceptions import CommandExecutionError, SaltInvocationError - from salt.ext import six - from salt.ext.six.moves import range # pylint: disable=import-error,redefined-builtin -+from salt._compat import ipaddress - - log = logging.getLogger(__name__) - -@@ -662,7 +664,8 @@ def _gen_net_xml(name, - bridge, - forward, - vport, -- tag=None): -+ tag=None, -+ ip_configs=None): - ''' - Generate the XML string to define a libvirt network - ''' -@@ -672,6 +675,10 @@ def _gen_net_xml(name, - 'forward': forward, - 'vport': vport, - 'tag': tag, -+ 'ip_configs': [{ -+ 'address': ipaddress.ip_network(config['cidr']), -+ 'dhcp_ranges': config.get('dhcp_ranges', []), -+ } for config in ip_configs or []], - } - fn_ = 'libvirt_network.jinja' - try: -@@ -692,24 +699,31 @@ def _gen_pool_xml(name, - source_hosts=None, - source_auth=None, - source_name=None, -- source_format=None): -+ source_format=None, -+ source_initiator=None): - ''' - Generate the XML string to define a libvirt storage pool - ''' - hosts = [host.split(':') for host in source_hosts or []] -- context = { -- 'name': name, -- 'ptype': ptype, -- 'target': {'path': target, 'permissions': permissions}, -- 'source': { -+ source = None -+ if any([source_devices, source_dir, source_adapter, hosts, source_auth, source_name, source_format, -+ source_initiator]): -+ source = { - 'devices': source_devices or [], -- 'dir': source_dir, -+ 'dir': source_dir if source_format != 'cifs' or not source_dir else source_dir.lstrip('/'), - 'adapter': source_adapter, - 'hosts': [{'name': host[0], 'port': host[1] if len(host) > 1 else None} for host in hosts], - 'auth': source_auth, - 'name': source_name, -- 'format': source_format -+ 'format': source_format, -+ 'initiator': source_initiator, - } -+ -+ context = { -+ 'name': name, -+ 'ptype': ptype, -+ 'target': {'path': target, 'permissions': permissions}, -+ 'source': source - } - fn_ = 'libvirt_pool.jinja' - try: -@@ -720,6 +734,24 @@ def _gen_pool_xml(name, - return template.render(**context) - - -+def _gen_secret_xml(auth_type, usage, description): -+ ''' -+ Generate a libvirt secret definition XML -+ ''' -+ context = { -+ 'type': auth_type, -+ 'usage': usage, -+ 'description': description, -+ } -+ fn_ = 'libvirt_secret.jinja' -+ try: -+ template = JINJA.get_template(fn_) -+ except jinja2.exceptions.TemplateNotFound: -+ log.error('Could not load template %s', fn_) -+ return '' -+ return template.render(**context) -+ -+ - def _get_images_dir(): - ''' - Extract the images dir from the configuration. First attempts to -@@ -4425,7 +4457,12 @@ def cpu_baseline(full=False, migratable=False, out='libvirt', **kwargs): - return cpu.toxml() - - --def network_define(name, bridge, forward, **kwargs): -+def network_define(name, -+ bridge, -+ forward, -+ ipv4_config=None, -+ ipv6_config=None, -+ **kwargs): - ''' - Create libvirt network. - -@@ -4436,10 +4473,38 @@ def network_define(name, bridge, forward, **kwargs): - :param tag: Vlan tag - :param autostart: Network autostart (default True) - :param start: Network start (default True) -+ :param ipv4_config: IP v4 configuration -+ Dictionary describing the IP v4 setup like IP range and -+ a possible DHCP configuration. The structure is documented -+ in net-define-ip_. -+ -+ ..versionadded:: Neon -+ :type ipv4_config: dict or None -+ -+ :param ipv6_config: IP v6 configuration -+ Dictionary describing the IP v6 setup like IP range and -+ a possible DHCP configuration. The structure is documented -+ in net-define-ip_. -+ -+ ..versionadded:: Neon -+ :type ipv6_config: dict or None -+ - :param connection: libvirt connection URI, overriding defaults - :param username: username to connect with, overriding defaults - :param password: password to connect with, overriding defaults - -+ .. _net-define-ip: -+ -+ ** IP configuration definition -+ -+ Both the IPv4 and IPv6 configuration dictionaries can contain the following properties: -+ -+ cidr -+ CIDR notation for the network. For example '192.168.124.0/24' -+ -+ dhcp_ranges -+ A list of dictionary with ``'start'`` and ``'end'`` properties. -+ - CLI Example: - - .. code-block:: bash -@@ -4453,12 +4518,14 @@ def network_define(name, bridge, forward, **kwargs): - tag = kwargs.get('tag', None) - autostart = kwargs.get('autostart', True) - starting = kwargs.get('start', True) -+ - net_xml = _gen_net_xml( - name, - bridge, - forward, - vport, -- tag, -+ tag=tag, -+ ip_configs=[config for config in [ipv4_config, ipv6_config] if config], - ) - try: - conn.networkDefineXML(net_xml) -@@ -4669,12 +4736,171 @@ def network_set_autostart(name, state='on', **kwargs): - conn.close() - - -+def _parse_pools_caps(doc): -+ ''' -+ Parse libvirt pool capabilities XML -+ ''' -+ def _parse_pool_caps(pool): -+ pool_caps = { -+ 'name': pool.get('type'), -+ 'supported': pool.get('supported', 'no') == 'yes' -+ } -+ for option_kind in ['pool', 'vol']: -+ options = {} -+ default_format_node = pool.find('{0}Options/defaultFormat'.format(option_kind)) -+ if default_format_node is not None: -+ options['default_format'] = default_format_node.get('type') -+ options_enums = {enum.get('name'): [value.text for value in enum.findall('value')] -+ for enum in pool.findall('{0}Options/enum'.format(option_kind))} -+ if options_enums: -+ options.update(options_enums) -+ if options: -+ if 'options' not in pool_caps: -+ pool_caps['options'] = {} -+ kind = option_kind if option_kind is not 'vol' else 'volume' -+ pool_caps['options'][kind] = options -+ return pool_caps -+ -+ return [_parse_pool_caps(pool) for pool in doc.findall('pool')] -+ -+ -+def pool_capabilities(**kwargs): -+ ''' -+ Return the hypervisor connection storage pool capabilities. -+ -+ The returned data are either directly extracted from libvirt or computed. -+ In the latter case some pool types could be listed as supported while they -+ are not. To distinguish between the two cases, check the value of the ``computed`` property. -+ -+ :param connection: libvirt connection URI, overriding defaults -+ :param username: username to connect with, overriding defaults -+ :param password: password to connect with, overriding defaults -+ -+ .. versionadded:: Neon -+ -+ CLI Example: -+ -+ .. code-block:: bash -+ -+ salt '*' virt.pool_capabilities -+ -+ ''' -+ try: -+ conn = __get_conn(**kwargs) -+ has_pool_capabilities = bool(getattr(conn, 'getStoragePoolCapabilities', None)) -+ if has_pool_capabilities: -+ caps = ElementTree.fromstring(conn.getStoragePoolCapabilities()) -+ pool_types = _parse_pools_caps(caps) -+ else: -+ # Compute reasonable values -+ all_hypervisors = ['xen', 'kvm', 'bhyve'] -+ images_formats = ['none', 'raw', 'dir', 'bochs', 'cloop', 'dmg', 'iso', 'vpc', 'vdi', -+ 'fat', 'vhd', 'ploop', 'cow', 'qcow', 'qcow2', 'qed', 'vmdk'] -+ common_drivers = [ -+ { -+ 'name': 'fs', -+ 'default_source_format': 'auto', -+ 'source_formats': ['auto', 'ext2', 'ext3', 'ext4', 'ufs', 'iso9660', 'udf', 'gfs', 'gfs2', -+ 'vfat', 'hfs+', 'xfs', 'ocfs2'], -+ 'default_target_format': 'raw', -+ 'target_formats': images_formats -+ }, -+ { -+ 'name': 'dir', -+ 'default_target_format': 'raw', -+ 'target_formats': images_formats -+ }, -+ {'name': 'iscsi'}, -+ {'name': 'scsi'}, -+ { -+ 'name': 'logical', -+ 'default_source_format': 'lvm2', -+ 'source_formats': ['unknown', 'lvm2'], -+ }, -+ { -+ 'name': 'netfs', -+ 'default_source_format': 'auto', -+ 'source_formats': ['auto', 'nfs', 'glusterfs', 'cifs'], -+ 'default_target_format': 'raw', -+ 'target_formats': images_formats -+ }, -+ { -+ 'name': 'disk', -+ 'default_source_format': 'unknown', -+ 'source_formats': ['unknown', 'dos', 'dvh', 'gpt', 'mac', 'bsd', 'pc98', 'sun', 'lvm2'], -+ 'default_target_format': 'none', -+ 'target_formats': ['none', 'linux', 'fat16', 'fat32', 'linux-swap', 'linux-lvm', -+ 'linux-raid', 'extended'] -+ }, -+ {'name': 'mpath'}, -+ { -+ 'name': 'rbd', -+ 'default_target_format': 'raw', -+ 'target_formats': [] -+ }, -+ { -+ 'name': 'sheepdog', -+ 'version': 10000, -+ 'hypervisors': ['kvm'], -+ 'default_target_format': 'raw', -+ 'target_formats': images_formats -+ }, -+ { -+ 'name': 'gluster', -+ 'version': 1002000, -+ 'hypervisors': ['kvm'], -+ 'default_target_format': 'raw', -+ 'target_formats': images_formats -+ }, -+ {'name': 'zfs', 'version': 1002008, 'hypervisors': ['bhyve']}, -+ {'name': 'iscsi-direct', 'version': 4007000, 'hypervisors': ['kvm', 'xen']} -+ ] -+ -+ libvirt_version = conn.getLibVersion() -+ hypervisor = get_hypervisor() -+ -+ def _get_backend_output(backend): -+ output = { -+ 'name': backend['name'], -+ 'supported': (not backend.get('version') or libvirt_version >= backend['version']) and -+ hypervisor in backend.get('hypervisors', all_hypervisors), -+ 'options': { -+ 'pool': { -+ 'default_format': backend.get('default_source_format'), -+ 'sourceFormatType': backend.get('source_formats') -+ }, -+ 'volume': { -+ 'default_format': backend.get('default_target_format'), -+ 'targetFormatType': backend.get('target_formats') -+ } -+ } -+ } -+ -+ # Cleanup the empty members to match the libvirt output -+ for option_kind in ['pool', 'volume']: -+ if not [value for value in output['options'][option_kind].values() if value is not None]: -+ del output['options'][option_kind] -+ if not output['options']: -+ del output['options'] -+ -+ return output -+ pool_types = [_get_backend_output(backend) for backend in common_drivers] -+ finally: -+ conn.close() -+ -+ return { -+ 'computed': not has_pool_capabilities, -+ 'pool_types': pool_types, -+ } -+ -+ - def pool_define(name, - ptype, - target=None, - permissions=None, - source_devices=None, - source_dir=None, -+ source_initiator=None, - source_adapter=None, - source_hosts=None, - source_auth=None, -@@ -4705,6 +4931,10 @@ def pool_define(name, - :param source_dir: - Path to the source directory for pools of type ``dir``, ``netfs`` or ``gluster``. - (Default: ``None``) -+ :param source_initiator: -+ Initiator IQN for libiscsi-direct pool types. (Default: ``None``) -+ -+ .. versionadded:: neon - :param source_adapter: - SCSI source definition. The value is a dictionary with ``type``, ``name``, ``parent``, - ``managed``, ``parent_wwnn``, ``parent_wwpn``, ``parent_fabric_wwn``, ``wwnn``, ``wwpn`` -@@ -4736,7 +4966,7 @@ def pool_define(name, - 'username': 'admin', - 'secret': { - 'type': 'uuid', -- 'uuid': '2ec115d7-3a88-3ceb-bc12-0ac909a6fd87' -+ 'value': '2ec115d7-3a88-3ceb-bc12-0ac909a6fd87' - } - } - -@@ -4747,10 +4977,14 @@ def pool_define(name, - 'username': 'myname', - 'secret': { - 'type': 'usage', -- 'uuid': 'mycluster_myname' -+ 'value': 'mycluster_myname' - } - } - -+ Since neon, instead the source authentication can only contain ``username`` -+ and ``password`` properties. In this case the libvirt secret will be defined and used. -+ For Ceph authentications a base64 encoded key is expected. -+ - :param source_name: - Identifier of name-based sources. - :param source_format: -@@ -4803,6 +5037,8 @@ def pool_define(name, - .. versionadded:: 2019.2.0 - ''' - conn = __get_conn(**kwargs) -+ auth = _pool_set_secret(conn, ptype, name, source_auth) -+ - pool_xml = _gen_pool_xml( - name, - ptype, -@@ -4812,9 +5048,10 @@ def pool_define(name, - source_dir=source_dir, - source_adapter=source_adapter, - source_hosts=source_hosts, -- source_auth=source_auth, -+ source_auth=auth, - source_name=source_name, -- source_format=source_format -+ source_format=source_format, -+ source_initiator=source_initiator - ) - try: - if transient: -@@ -4832,6 +5069,236 @@ def pool_define(name, - return True - - -+def _pool_set_secret(conn, pool_type, pool_name, source_auth, uuid=None, usage=None, test=False): -+ secret_types = { -+ 'rbd': 'ceph', -+ 'iscsi': 'chap', -+ 'iscsi-direct': 'chap' -+ } -+ secret_type = secret_types.get(pool_type) -+ auth = source_auth -+ if source_auth and 'username' in source_auth and 'password' in source_auth: -+ if secret_type: -+ # Get the previously defined secret if any -+ secret = None -+ if usage: -+ usage_type = libvirt.VIR_SECRET_USAGE_TYPE_CEPH if secret_type == 'ceph' \ -+ else libvirt.VIR_SECRET_USAGE_TYPE_ISCSI -+ secret = conn.secretLookupByUsage(usage_type, usage) -+ elif uuid: -+ secret = conn.secretLookupByUUIDString(uuid) -+ -+ # Create secret if needed -+ if not secret: -+ description = 'Passphrase for {} pool created by Salt'.format(pool_name) -+ if not usage: -+ usage = 'pool_{}'.format(pool_name) -+ secret_xml = _gen_secret_xml(secret_type, usage, description) -+ if not test: -+ secret = conn.secretDefineXML(secret_xml) -+ -+ # Assign the password to it -+ password = auth['password'] -+ if pool_type == 'rbd': -+ # RBD password are already base64-encoded, but libvirt will base64-encode them later -+ password = base64.b64decode(salt.utils.stringutils.to_bytes(password)) -+ if not test: -+ secret.setValue(password) -+ -+ # update auth with secret reference -+ auth['type'] = secret_type -+ auth['secret'] = { -+ 'type': 'uuid' if uuid else 'usage', -+ 'value': uuid if uuid else usage, -+ } -+ return auth -+ -+ -+def pool_update(name, -+ ptype, -+ target=None, -+ permissions=None, -+ source_devices=None, -+ source_dir=None, -+ source_initiator=None, -+ source_adapter=None, -+ source_hosts=None, -+ source_auth=None, -+ source_name=None, -+ source_format=None, -+ test=False, -+ **kwargs): -+ ''' -+ Update a libvirt storage pool if needed. -+ If called with test=True, this is also reporting whether an update would be performed. -+ -+ :param name: Pool name -+ :param ptype: -+ Pool type. See `libvirt documentation `_ for the -+ possible values. -+ :param target: Pool full path target -+ :param permissions: -+ Permissions to set on the target folder. This is mostly used for filesystem-based -+ pool types. See :ref:`pool-define-permissions` for more details on this structure. -+ :param source_devices: -+ List of source devices for pools backed by physical devices. (Default: ``None``) -+ -+ Each item in the list is a dictionary with ``path`` and optionally ``part_separator`` -+ keys. The path is the qualified name for iSCSI devices. -+ -+ Report to `this libvirt page `_ -+ for more informations on the use of ``part_separator`` -+ :param source_dir: -+ Path to the source directory for pools of type ``dir``, ``netfs`` or ``gluster``. -+ (Default: ``None``) -+ :param source_initiator: -+ Initiator IQN for libiscsi-direct pool types. (Default: ``None``) -+ -+ .. versionadded:: neon -+ :param source_adapter: -+ SCSI source definition. The value is a dictionary with ``type``, ``name``, ``parent``, -+ ``managed``, ``parent_wwnn``, ``parent_wwpn``, ``parent_fabric_wwn``, ``wwnn``, ``wwpn`` -+ and ``parent_address`` keys. -+ -+ The ``parent_address`` value is a dictionary with ``unique_id`` and ``address`` keys. -+ The address represents a PCI address and is itself a dictionary with ``domain``, ``bus``, -+ ``slot`` and ``function`` properties. -+ Report to `this libvirt page `_ -+ for the meaning and possible values of these properties. -+ :param source_hosts: -+ List of source for pools backed by storage from remote servers. Each item is the hostname -+ optionally followed by the port separated by a colon. (Default: ``None``) -+ :param source_auth: -+ Source authentication details. (Default: ``None``) -+ -+ The value is a dictionary with ``type``, ``username`` and ``secret`` keys. The type -+ can be one of ``ceph`` for Ceph RBD or ``chap`` for iSCSI sources. -+ -+ The ``secret`` value links to a libvirt secret object. It is a dictionary with -+ ``type`` and ``value`` keys. The type value can be either ``uuid`` or ``usage``. -+ -+ Examples: -+ -+ .. code-block:: python -+ -+ source_auth={ -+ 'type': 'ceph', -+ 'username': 'admin', -+ 'secret': { -+ 'type': 'uuid', -+ 'uuid': '2ec115d7-3a88-3ceb-bc12-0ac909a6fd87' -+ } -+ } -+ -+ .. code-block:: python -+ -+ source_auth={ -+ 'type': 'chap', -+ 'username': 'myname', -+ 'secret': { -+ 'type': 'usage', -+ 'uuid': 'mycluster_myname' -+ } -+ } -+ -+ Since neon, instead the source authentication can only contain ``username`` -+ and ``password`` properties. In this case the libvirt secret will be defined and used. -+ For Ceph authentications a base64 encoded key is expected. -+ -+ :param source_name: -+ Identifier of name-based sources. -+ :param source_format: -+ String representing the source format. The possible values are depending on the -+ source type. See `libvirt documentation `_ for -+ the possible values. -+ :param test: run in dry-run mode if set to True -+ :param connection: libvirt connection URI, overriding defaults -+ :param username: username to connect with, overriding defaults -+ :param password: password to connect with, overriding defaults -+ -+ .. rubric:: Example: -+ -+ Local folder pool: -+ -+ .. code-block:: bash -+ -+ salt '*' virt.pool_update somepool dir target=/srv/mypool \ -+ permissions="{'mode': '0744' 'ower': 107, 'group': 107 }" -+ -+ CIFS backed pool: -+ -+ .. code-block:: bash -+ -+ salt '*' virt.pool_update myshare netfs source_format=cifs \ -+ source_dir=samba_share source_hosts="['example.com']" target=/mnt/cifs -+ -+ .. versionadded:: neon -+ ''' -+ # Get the current definition to compare the two -+ conn = __get_conn(**kwargs) -+ needs_update = False -+ try: -+ pool = conn.storagePoolLookupByName(name) -+ old_xml = ElementTree.fromstring(pool.XMLDesc()) -+ -+ # If we have username and password in source_auth generate a new secret -+ # Or change the value of the existing one -+ secret_node = old_xml.find('source/auth/secret') -+ usage = secret_node.get('usage') if secret_node is not None else None -+ uuid = secret_node.get('uuid') if secret_node is not None else None -+ auth = _pool_set_secret(conn, ptype, name, source_auth, uuid=uuid, usage=usage, test=test) -+ -+ # Compute new definition -+ new_xml = ElementTree.fromstring(_gen_pool_xml( -+ name, -+ ptype, -+ target, -+ permissions=permissions, -+ source_devices=source_devices, -+ source_dir=source_dir, -+ source_initiator=source_initiator, -+ source_adapter=source_adapter, -+ source_hosts=source_hosts, -+ source_auth=auth, -+ source_name=source_name, -+ source_format=source_format -+ )) -+ -+ # Copy over the uuid, capacity, allocation, available elements -+ elements_to_copy = ['available', 'allocation', 'capacity', 'uuid'] -+ for to_copy in elements_to_copy: -+ element = old_xml.find(to_copy) -+ new_xml.insert(1, element) -+ -+ # Filter out spaces and empty elements like since those would mislead the comparison -+ def visit_xml(node, fn): -+ fn(node) -+ for child in node: -+ visit_xml(child, fn) -+ -+ def space_stripper(node): -+ if node.tail is not None: -+ node.tail = node.tail.strip(' \t\n') -+ if node.text is not None: -+ node.text = node.text.strip(' \t\n') -+ -+ visit_xml(old_xml, space_stripper) -+ visit_xml(new_xml, space_stripper) -+ -+ def empty_node_remover(node): -+ for child in node: -+ if not child.tail and not child.text and not child.items() and not child: -+ node.remove(child) -+ visit_xml(old_xml, empty_node_remover) -+ -+ needs_update = ElementTree.tostring(old_xml) != ElementTree.tostring(new_xml) -+ if needs_update and not test: -+ conn.storagePoolDefineXML(salt.utils.stringutils.to_str(ElementTree.tostring(new_xml))) -+ finally: -+ conn.close() -+ return needs_update -+ -+ - def list_pools(**kwargs): - ''' - List all storage pools. -diff --git a/salt/states/virt.py b/salt/states/virt.py -index c700cae849..d1c9191a29 100644 ---- a/salt/states/virt.py -+++ b/salt/states/virt.py -@@ -658,6 +658,8 @@ def network_running(name, - forward, - vport=None, - tag=None, -+ ipv4_config=None, -+ ipv6_config=None, - autostart=True, - connection=None, - username=None, -@@ -665,6 +667,25 @@ def network_running(name, - ''' - Defines and starts a new network with specified arguments. - -+ :param bridge: Bridge name -+ :param forward: Forward mode(bridge, router, nat) -+ :param vport: Virtualport type (Default: ``'None'``) -+ :param tag: Vlan tag (Default: ``'None'``) -+ :param ipv4_config: -+ IPv4 network configuration. See the :py:func`virt.network_define -+ ` function corresponding parameter documentation -+ for more details on this dictionary. -+ (Default: None). -+ -+ .. versionadded:: neon -+ :param ipv6_config: -+ IPv6 network configuration. See the :py:func`virt.network_define -+ ` function corresponding parameter documentation -+ for more details on this dictionary. -+ (Default: None). -+ -+ .. versionadded:: neon -+ :param autostart: Network autostart (default ``'True'``) - :param connection: libvirt connection URI, overriding defaults - - .. versionadded:: 2019.2.0 -@@ -690,6 +711,21 @@ def network_running(name, - - tag: 180 - - autostart: True - -+ .. code-block:: yaml -+ -+ network_name: -+ virt.network_define: -+ - bridge: natted -+ - forward: nat -+ - ipv4_config: -+ cidr: 192.168.42.0/24 -+ dhcp_ranges: -+ - start: 192.168.42.10 -+ end: 192.168.42.25 -+ - start: 192.168.42.100 -+ end: 192.168.42.150 -+ - autostart: True -+ - ''' - ret = {'name': name, - 'changes': {}, -@@ -712,6 +748,8 @@ def network_running(name, - forward, - vport=vport, - tag=tag, -+ ipv4_config=ipv4_config, -+ ipv6_config=ipv6_config, - autostart=autostart, - start=True, - connection=connection, -@@ -784,57 +822,230 @@ def pool_running(name, - ''' - ret = {'name': name, - 'changes': {}, -- 'result': True, -+ 'result': True if not __opts__['test'] else None, - 'comment': '' - } - - try: - info = __salt__['virt.pool_info'](name, connection=connection, username=username, password=password) -+ needs_autostart = False - if info: -- if info[name]['state'] == 'running': -- ret['comment'] = 'Pool {0} exists and is running'.format(name) -+ needs_autostart = info[name]['autostart'] and not autostart or not info[name]['autostart'] and autostart -+ -+ # Update can happen for both running and stopped pools -+ needs_update = __salt__['virt.pool_update'](name, -+ ptype=ptype, -+ target=target, -+ permissions=permissions, -+ source_devices=(source or {}).get('devices'), -+ source_dir=(source or {}).get('dir'), -+ source_initiator=(source or {}).get('initiator'), -+ source_adapter=(source or {}).get('adapter'), -+ source_hosts=(source or {}).get('hosts'), -+ source_auth=(source or {}).get('auth'), -+ source_name=(source or {}).get('name'), -+ source_format=(source or {}).get('format'), -+ test=True, -+ connection=connection, -+ username=username, -+ password=password) -+ if needs_update: -+ if not __opts__['test']: -+ __salt__['virt.pool_update'](name, -+ ptype=ptype, -+ target=target, -+ permissions=permissions, -+ source_devices=(source or {}).get('devices'), -+ source_dir=(source or {}).get('dir'), -+ source_initiator=(source or {}).get('initiator'), -+ source_adapter=(source or {}).get('adapter'), -+ source_hosts=(source or {}).get('hosts'), -+ source_auth=(source or {}).get('auth'), -+ source_name=(source or {}).get('name'), -+ source_format=(source or {}).get('format'), -+ connection=connection, -+ username=username, -+ password=password) -+ -+ action = "started" -+ if info[name]['state'] == 'running': -+ action = "restarted" -+ if not __opts__['test']: -+ __salt__['virt.pool_stop'](name, connection=connection, username=username, password=password) -+ -+ if not __opts__['test']: -+ __salt__['virt.pool_build'](name, connection=connection, username=username, password=password) -+ __salt__['virt.pool_start'](name, connection=connection, username=username, password=password) -+ -+ autostart_str = ', autostart flag changed' if needs_autostart else '' -+ ret['changes'][name] = 'Pool updated, built{0} and {1}'.format(autostart_str, action) -+ ret['comment'] = 'Pool {0} updated, built{1} and {2}'.format(name, autostart_str, action) -+ - else: -- __salt__['virt.pool_start'](name, connection=connection, username=username, password=password) -- ret['changes'][name] = 'Pool started' -- ret['comment'] = 'Pool {0} started'.format(name) -+ if info[name]['state'] == 'running': -+ ret['comment'] = 'Pool {0} unchanged and is running'.format(name) -+ ret['result'] = True -+ else: -+ ret['changes'][name] = 'Pool started' -+ ret['comment'] = 'Pool {0} started'.format(name) -+ if not __opts__['test']: -+ __salt__['virt.pool_start'](name, connection=connection, username=username, password=password) - else: -- __salt__['virt.pool_define'](name, -- ptype=ptype, -- target=target, -- permissions=permissions, -- source_devices=(source or {}).get('devices', None), -- source_dir=(source or {}).get('dir', None), -- source_adapter=(source or {}).get('adapter', None), -- source_hosts=(source or {}).get('hosts', None), -- source_auth=(source or {}).get('auth', None), -- source_name=(source or {}).get('name', None), -- source_format=(source or {}).get('format', None), -- transient=transient, -- start=False, -- connection=connection, -- username=username, -- password=password) -- if autostart: -+ needs_autostart = autostart -+ if not __opts__['test']: -+ __salt__['virt.pool_define'](name, -+ ptype=ptype, -+ target=target, -+ permissions=permissions, -+ source_devices=(source or {}).get('devices'), -+ source_dir=(source or {}).get('dir'), -+ source_initiator=(source or {}).get('initiator'), -+ source_adapter=(source or {}).get('adapter'), -+ source_hosts=(source or {}).get('hosts'), -+ source_auth=(source or {}).get('auth'), -+ source_name=(source or {}).get('name'), -+ source_format=(source or {}).get('format'), -+ transient=transient, -+ start=False, -+ connection=connection, -+ username=username, -+ password=password) -+ -+ __salt__['virt.pool_build'](name, -+ connection=connection, -+ username=username, -+ password=password) -+ -+ __salt__['virt.pool_start'](name, -+ connection=connection, -+ username=username, -+ password=password) -+ if needs_autostart: -+ ret['changes'][name] = 'Pool defined, started and marked for autostart' -+ ret['comment'] = 'Pool {0} defined, started and marked for autostart'.format(name) -+ else: -+ ret['changes'][name] = 'Pool defined and started' -+ ret['comment'] = 'Pool {0} defined and started'.format(name) -+ -+ if needs_autostart: -+ if not __opts__['test']: - __salt__['virt.pool_set_autostart'](name, - state='on' if autostart else 'off', - connection=connection, - username=username, - password=password) -+ except libvirt.libvirtError as err: -+ ret['comment'] = err.get_error_message() -+ ret['result'] = False -+ -+ return ret -+ - -- __salt__['virt.pool_build'](name, -- connection=connection, -- username=username, -- password=password) -+def pool_deleted(name, -+ purge=False, -+ connection=None, -+ username=None, -+ password=None): -+ ''' -+ Deletes a virtual storage pool. -+ -+ :param name: the name of the pool to delete. -+ :param purge: -+ if ``True``, the volumes contained in the pool will be deleted as well as the pool itself. -+ Note that these will be lost for ever. If ``False`` the pool will simply be undefined. -+ (Default: ``False``) -+ :param connection: libvirt connection URI, overriding defaults -+ :param username: username to connect with, overriding defaults -+ :param password: password to connect with, overriding defaults - -- __salt__['virt.pool_start'](name, -- connection=connection, -- username=username, -- password=password) -+ In order to be purged a storage pool needs to be running to get the list of volumes to delete. -+ -+ Some libvirt storage drivers may not implement deleting, those actions are implemented on a -+ best effort idea. In any case check the result's comment property to see if any of the action -+ was unsupported. -+ -+ .. code-block::yaml -+ -+ pool_name: -+ uyuni_virt.pool_deleted: -+ - purge: True -+ -+ .. versionadded:: Neon -+ ''' -+ ret = {'name': name, 'changes': {}, 'result': True, 'comment': ''} - -- ret['changes'][name] = 'Pool defined and started' -- ret['comment'] = 'Pool {0} defined and started'.format(name) -+ try: -+ info = __salt__['virt.pool_info'](name, connection=connection, username=username, password=password) -+ if info: -+ ret['changes']['stopped'] = False -+ ret['changes']['deleted'] = False -+ ret['changes']['undefined'] = False -+ ret['changes']['deleted_volumes'] = [] -+ unsupported = [] -+ -+ if info[name]['state'] == 'running': -+ if purge: -+ unsupported_volume_delete = ['iscsi', 'iscsi-direct', 'mpath', 'scsi'] -+ if info[name]['type'] not in unsupported_volume_delete: -+ __salt__['virt.pool_refresh'](name, -+ connection=connection, -+ username=username, -+ password=password) -+ volumes = __salt__['virt.pool_list_volumes'](name, -+ connection=connection, -+ username=username, -+ password=password) -+ for volume in volumes: -+ # Not supported for iSCSI and SCSI drivers -+ deleted = __opts__['test'] -+ if not __opts__['test']: -+ deleted = __salt__['virt.volume_delete'](name, -+ volume, -+ connection=connection, -+ username=username, -+ password=password) -+ if deleted: -+ ret['changes']['deleted_volumes'].append(volume) -+ else: -+ unsupported.append('deleting volume') -+ -+ if not __opts__['test']: -+ ret['changes']['stopped'] = __salt__['virt.pool_stop'](name, -+ connection=connection, -+ username=username, -+ password=password) -+ else: -+ ret['changes']['stopped'] = True -+ -+ if purge: -+ supported_pool_delete = ['dir', 'fs', 'netfs', 'logical', 'vstorage', 'zfs'] -+ if info[name]['type'] in supported_pool_delete: -+ if not __opts__['test']: -+ ret['changes']['deleted'] = __salt__['virt.pool_delete'](name, -+ connection=connection, -+ username=username, -+ password=password) -+ else: -+ ret['changes']['deleted'] = True -+ else: -+ unsupported.append('deleting pool') -+ -+ if not __opts__['test']: -+ ret['changes']['undefined'] = __salt__['virt.pool_undefine'](name, -+ connection=connection, -+ username=username, -+ password=password) -+ else: -+ ret['changes']['undefined'] = True -+ ret['result'] = None -+ -+ if unsupported: -+ ret['comment'] = 'Unsupported actions for pool of type "{0}": {1}'.format(info[name]['type'], -+ ', '.join(unsupported)) -+ else: -+ ret['comment'] = 'Storage pool could not be found: {0}'.format(name) - except libvirt.libvirtError as err: -- ret['comment'] = err.get_error_message() -+ ret['comment'] = 'Failed deleting pool: {0}'.format(err.get_error_message()) - ret['result'] = False - - return ret -diff --git a/salt/templates/virt/libvirt_network.jinja b/salt/templates/virt/libvirt_network.jinja -index d0db99cad8..2f11e64559 100644 ---- a/salt/templates/virt/libvirt_network.jinja -+++ b/salt/templates/virt/libvirt_network.jinja -@@ -6,4 +6,15 @@ - - - {% endif %} -- -\ No newline at end of file -+ {% for ip_config in ip_configs %} -+ -+ -+ {% for range in ip_config.dhcp_ranges %} -+ -+ {% endfor %} -+ -+ -+ {% endfor %} -+ -diff --git a/salt/templates/virt/libvirt_pool.jinja b/salt/templates/virt/libvirt_pool.jinja -index 58c82f7177..515702cf46 100644 ---- a/salt/templates/virt/libvirt_pool.jinja -+++ b/salt/templates/virt/libvirt_pool.jinja -@@ -18,7 +18,7 @@ - {% endif %} - {% if source %} - -- {% if ptype in ['fs', 'logical', 'disk', 'iscsi', 'zfs', 'vstorage'] %} -+ {% if ptype in ['fs', 'logical', 'disk', 'iscsi', 'zfs', 'vstorage', 'iscsi-direct'] %} - {% for device in source.devices %} - -@@ -43,14 +43,14 @@ - {% endif %} - - {% endif %} -- {% if ptype in ['netfs', 'iscsi', 'rbd', 'sheepdog', 'gluster'] and source.hosts %} -+ {% if ptype in ['netfs', 'iscsi', 'rbd', 'sheepdog', 'gluster', 'iscsi-direct'] and source.hosts %} - {% for host in source.hosts %} - - {% endfor %} - {% endif %} -- {% if ptype in ['iscsi', 'rbd'] and source.auth %} -+ {% if ptype in ['iscsi', 'rbd', 'iscsi-direct'] and source.auth %} - -- -+ - - {% endif %} - {% if ptype in ['logical', 'rbd', 'sheepdog', 'gluster'] and source.name %} -@@ -59,6 +59,11 @@ - {% if ptype in ['fs', 'netfs', 'logical', 'disk'] and source.format %} - - {% endif %} -+ {% if ptype == 'iscsi-direct' and source.initiator %} -+ -+ -+ -+ {% endif %} - - {% endif %} - -diff --git a/salt/templates/virt/libvirt_secret.jinja b/salt/templates/virt/libvirt_secret.jinja -new file mode 100644 -index 0000000000..41c6dd811a ---- /dev/null -+++ b/salt/templates/virt/libvirt_secret.jinja -@@ -0,0 +1,12 @@ -+ -+ {{ description }} -+ {% if type == 'chap' %} -+ -+ {{ usage }} -+ -+ {% elif type == 'ceph' %} -+ -+ {{ usage }} -+ -+ {% endif %} -+ -diff --git a/tests/unit/modules/test_virt.py b/tests/unit/modules/test_virt.py -index 4bdb933a2d..698e1922fc 100644 ---- a/tests/unit/modules/test_virt.py -+++ b/tests/unit/modules/test_virt.py -@@ -2016,6 +2016,32 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin): - self.assertEqual(root.find('forward').attrib['mode'], 'bridge') - self.assertEqual(root.find('virtualport').attrib['type'], 'openvswitch') - -+ def test_network_nat(self): -+ ''' -+ Test virt._get_net_xml() in a nat setup -+ ''' -+ xml_data = virt._gen_net_xml('network', 'main', 'nat', None, ip_configs=[ -+ { -+ 'cidr': '192.168.2.0/24', -+ 'dhcp_ranges': [ -+ {'start': '192.168.2.10', 'end': '192.168.2.25'}, -+ {'start': '192.168.2.110', 'end': '192.168.2.125'}, -+ ] -+ } -+ ]) -+ root = ET.fromstring(xml_data) -+ self.assertEqual(root.find('name').text, 'network') -+ self.assertEqual(root.find('bridge').attrib['name'], 'main') -+ self.assertEqual(root.find('forward').attrib['mode'], 'nat') -+ self.assertEqual(root.find("./ip[@address='192.168.2.0']").attrib['prefix'], '24') -+ self.assertEqual(root.find("./ip[@address='192.168.2.0']").attrib['family'], 'ipv4') -+ self.assertEqual( -+ root.find("./ip[@address='192.168.2.0']/dhcp/range[@start='192.168.2.10']").attrib['end'], -+ '192.168.2.25') -+ self.assertEqual( -+ root.find("./ip[@address='192.168.2.0']/dhcp/range[@start='192.168.2.110']").attrib['end'], -+ '192.168.2.125') -+ - def test_domain_capabilities(self): - ''' - Test the virt.domain_capabilities parsing -@@ -2468,7 +2494,6 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin): - self.assertEqual(root.findall('source/host')[1].attrib['port'], '69') - self.assertEqual(root.find('source/auth').attrib['type'], 'ceph') - self.assertEqual(root.find('source/auth').attrib['username'], 'admin') -- self.assertEqual(root.find('source/auth/secret').attrib['type'], 'uuid') - self.assertEqual(root.find('source/auth/secret').attrib['uuid'], 'someuuid') - - def test_pool_with_netfs(self): -@@ -2506,6 +2531,114 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin): - self.assertEqual(root.find('source/host').attrib['name'], 'nfs.host') - self.assertEqual(root.find('source/auth'), None) - -+ def test_pool_with_iscsi_direct(self): -+ ''' -+ Test virt._gen_pool_xml() with a iscsi-direct source -+ ''' -+ xml_data = virt._gen_pool_xml('pool', -+ 'iscsi-direct', -+ source_hosts=['iscsi.example.com'], -+ source_devices=[{'path': 'iqn.2013-06.com.example:iscsi-pool'}], -+ source_initiator='iqn.2013-06.com.example:iscsi-initiator') -+ root = ET.fromstring(xml_data) -+ self.assertEqual(root.find('name').text, 'pool') -+ self.assertEqual(root.attrib['type'], 'iscsi-direct') -+ self.assertEqual(root.find('target'), None) -+ self.assertEqual(root.find('source/device').attrib['path'], 'iqn.2013-06.com.example:iscsi-pool') -+ self.assertEqual(root.findall('source/host')[0].attrib['name'], 'iscsi.example.com') -+ self.assertEqual(root.find('source/initiator/iqn').attrib['name'], 'iqn.2013-06.com.example:iscsi-initiator') -+ -+ def test_pool_define(self): -+ ''' -+ Test virt.pool_define() -+ ''' -+ mock_pool = MagicMock() -+ mock_secret = MagicMock() -+ mock_secret_define = MagicMock(return_value=mock_secret) -+ self.mock_conn.secretDefineXML = mock_secret_define -+ self.mock_conn.storagePoolCreateXML = MagicMock(return_value=mock_pool) -+ self.mock_conn.storagePoolDefineXML = MagicMock(return_value=mock_pool) -+ -+ mocks = [mock_pool, mock_secret, mock_secret_define, self.mock_conn.storagePoolCreateXML, -+ self.mock_conn.secretDefineXML, self.mock_conn.storagePoolDefineXML] -+ -+ # Test case with already defined secret and permanent pool -+ self.assertTrue(virt.pool_define('default', -+ 'rbd', -+ source_hosts=['one.example.com', 'two.example.com'], -+ source_name='rbdvol', -+ source_auth={ -+ 'type': 'ceph', -+ 'username': 'admin', -+ 'secret': { -+ 'type': 'uuid', -+ 'value': 'someuuid' -+ } -+ })) -+ self.mock_conn.storagePoolDefineXML.assert_called_once() -+ self.mock_conn.storagePoolCreateXML.assert_not_called() -+ mock_pool.create.assert_called_once() -+ mock_secret_define.assert_not_called() -+ -+ # Test case with Ceph secret to be defined and transient pool -+ for mock in mocks: -+ mock.reset_mock() -+ self.assertTrue(virt.pool_define('default', -+ 'rbd', -+ transient=True, -+ source_hosts=['one.example.com', 'two.example.com'], -+ source_name='rbdvol', -+ source_auth={ -+ 'username': 'admin', -+ 'password': 'c2VjcmV0' -+ })) -+ self.mock_conn.storagePoolDefineXML.assert_not_called() -+ -+ pool_xml = self.mock_conn.storagePoolCreateXML.call_args[0][0] -+ root = ET.fromstring(pool_xml) -+ self.assertEqual(root.find('source/auth').attrib['type'], 'ceph') -+ self.assertEqual(root.find('source/auth').attrib['username'], 'admin') -+ self.assertEqual(root.find('source/auth/secret').attrib['usage'], 'pool_default') -+ mock_pool.create.assert_not_called() -+ mock_secret.setValue.assert_called_once_with(b'secret') -+ -+ secret_xml = mock_secret_define.call_args[0][0] -+ root = ET.fromstring(secret_xml) -+ self.assertEqual(root.find('usage/name').text, 'pool_default') -+ self.assertEqual(root.find('usage').attrib['type'], 'ceph') -+ self.assertEqual(root.attrib['private'], 'yes') -+ self.assertEqual(root.find('description').text, 'Passphrase for default pool created by Salt') -+ -+ # Test case with iscsi secret not starting -+ for mock in mocks: -+ mock.reset_mock() -+ self.assertTrue(virt.pool_define('default', -+ 'iscsi', -+ target='/dev/disk/by-path', -+ source_hosts=['iscsi.example.com'], -+ source_devices=[{'path': 'iqn.2013-06.com.example:iscsi-pool'}], -+ source_auth={ -+ 'username': 'admin', -+ 'password': 'secret' -+ }, -+ start=False)) -+ self.mock_conn.storagePoolCreateXML.assert_not_called() -+ -+ pool_xml = self.mock_conn.storagePoolDefineXML.call_args[0][0] -+ root = ET.fromstring(pool_xml) -+ self.assertEqual(root.find('source/auth').attrib['type'], 'chap') -+ self.assertEqual(root.find('source/auth').attrib['username'], 'admin') -+ self.assertEqual(root.find('source/auth/secret').attrib['usage'], 'pool_default') -+ mock_pool.create.assert_not_called() -+ mock_secret.setValue.assert_called_once_with('secret') -+ -+ secret_xml = mock_secret_define.call_args[0][0] -+ root = ET.fromstring(secret_xml) -+ self.assertEqual(root.find('usage/target').text, 'pool_default') -+ self.assertEqual(root.find('usage').attrib['type'], 'iscsi') -+ self.assertEqual(root.attrib['private'], 'yes') -+ self.assertEqual(root.find('description').text, 'Passphrase for default pool created by Salt') -+ - def test_list_pools(self): - ''' - Test virt.list_pools() -@@ -3135,3 +3268,323 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin): - - isxen_mock.return_value = True - self.assertEqual('xen', virt.get_hypervisor()) -+ -+ def test_pool_update(self): -+ ''' -+ Test the pool_update function -+ ''' -+ current_xml = ''' -+ default -+ 20fbe05c-ab40-418a-9afa-136d512f0ede -+ 1999421108224 -+ 713207042048 -+ 1286214066176 -+ -+ -+ -+ /path/to/pool -+ -+ 0775 -+ 0 -+ 100 -+ -+ -+ ''' -+ -+ expected_xml = '' \ -+ 'default' \ -+ '20fbe05c-ab40-418a-9afa-136d512f0ede' \ -+ '1999421108224' \ -+ '713207042048' \ -+ '1286214066176' \ -+ '' \ -+ '/mnt/cifs' \ -+ '' \ -+ '0774' \ -+ '1234' \ -+ '123' \ -+ '' \ -+ '' \ -+ '' \ -+ '' \ -+ '' \ -+ '' \ -+ '' \ -+ '' \ -+ '' -+ -+ mocked_pool = MagicMock() -+ mocked_pool.XMLDesc = MagicMock(return_value=current_xml) -+ self.mock_conn.storagePoolLookupByName = MagicMock(return_value=mocked_pool) -+ self.mock_conn.storagePoolDefineXML = MagicMock() -+ -+ self.assertTrue( -+ virt.pool_update('default', -+ 'netfs', -+ target='/mnt/cifs', -+ permissions={'mode': '0774', 'owner': '1234', 'group': '123'}, -+ source_format='cifs', -+ source_dir='samba_share', -+ source_hosts=['one.example.com', 'two.example.com'])) -+ self.mock_conn.storagePoolDefineXML.assert_called_once_with(expected_xml) -+ -+ def test_pool_update_nochange(self): -+ ''' -+ Test the pool_update function when no change is needed -+ ''' -+ -+ current_xml = ''' -+ default -+ 20fbe05c-ab40-418a-9afa-136d512f0ede -+ 1999421108224 -+ 713207042048 -+ 1286214066176 -+ -+ -+ -+ /path/to/pool -+ -+ 0775 -+ 0 -+ 100 -+ -+ -+ ''' -+ -+ mocked_pool = MagicMock() -+ mocked_pool.XMLDesc = MagicMock(return_value=current_xml) -+ self.mock_conn.storagePoolLookupByName = MagicMock(return_value=mocked_pool) -+ self.mock_conn.storagePoolDefineXML = MagicMock() -+ -+ self.assertFalse( -+ virt.pool_update('default', -+ 'dir', -+ target='/path/to/pool', -+ permissions={'mode': '0775', 'owner': '0', 'group': '100'}, -+ test=True)) -+ self.mock_conn.storagePoolDefineXML.assert_not_called() -+ -+ def test_pool_update_password(self): -+ ''' -+ Test the pool_update function, where the password only is changed -+ ''' -+ current_xml = ''' -+ default -+ 20fbe05c-ab40-418a-9afa-136d512f0ede -+ 1999421108224 -+ 713207042048 -+ 1286214066176 -+ -+ iscsi-images -+ -+ -+ -+ -+ -+ -+ ''' -+ -+ expected_xml = '' \ -+ 'default' \ -+ '20fbe05c-ab40-418a-9afa-136d512f0ede' \ -+ '1999421108224' \ -+ '713207042048' \ -+ '1286214066176' \ -+ '' \ -+ '' \ -+ '' \ -+ '' \ -+ '' \ -+ '' \ -+ 'iscsi-images' \ -+ '' \ -+ '' -+ -+ mock_secret = MagicMock() -+ self.mock_conn.secretLookupByUUIDString = MagicMock(return_value=mock_secret) -+ -+ mocked_pool = MagicMock() -+ mocked_pool.XMLDesc = MagicMock(return_value=current_xml) -+ self.mock_conn.storagePoolLookupByName = MagicMock(return_value=mocked_pool) -+ self.mock_conn.storagePoolDefineXML = MagicMock() -+ -+ self.assertTrue( -+ virt.pool_update('default', -+ 'rbd', -+ source_name='iscsi-images', -+ source_hosts=['ses4.tf.local', 'ses5.tf.local'], -+ source_auth={'username': 'libvirt', -+ 'password': 'c2VjcmV0'})) -+ self.mock_conn.storagePoolDefineXML.assert_called_once_with(expected_xml) -+ mock_secret.setValue.assert_called_once_with(b'secret') -+ -+ def test_pool_update_password_create(self): -+ ''' -+ Test the pool_update function, where the password only is changed -+ ''' -+ current_xml = ''' -+ default -+ 20fbe05c-ab40-418a-9afa-136d512f0ede -+ 1999421108224 -+ 713207042048 -+ 1286214066176 -+ -+ iscsi-images -+ -+ -+ -+ ''' -+ -+ expected_xml = '' \ -+ 'default' \ -+ '20fbe05c-ab40-418a-9afa-136d512f0ede' \ -+ '1999421108224' \ -+ '713207042048' \ -+ '1286214066176' \ -+ '' \ -+ '' \ -+ '' \ -+ '' \ -+ '' \ -+ '' \ -+ 'iscsi-images' \ -+ '' \ -+ '' -+ -+ mock_secret = MagicMock() -+ self.mock_conn.secretDefineXML = MagicMock(return_value=mock_secret) -+ -+ mocked_pool = MagicMock() -+ mocked_pool.XMLDesc = MagicMock(return_value=current_xml) -+ self.mock_conn.storagePoolLookupByName = MagicMock(return_value=mocked_pool) -+ self.mock_conn.storagePoolDefineXML = MagicMock() -+ -+ self.assertTrue( -+ virt.pool_update('default', -+ 'rbd', -+ source_name='iscsi-images', -+ source_hosts=['ses4.tf.local', 'ses5.tf.local'], -+ source_auth={'username': 'libvirt', -+ 'password': 'c2VjcmV0'})) -+ self.mock_conn.storagePoolDefineXML.assert_called_once_with(expected_xml) -+ mock_secret.setValue.assert_called_once_with(b'secret') -+ -+ def test_pool_capabilities(self): -+ ''' -+ Test virt.pool_capabilities where libvirt has the pool-capabilities feature -+ ''' -+ xml_caps = ''' -+ -+ -+ -+ -+ -+ unknown -+ dos -+ dvh -+ -+ -+ -+ -+ -+ none -+ linux -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ ''' -+ self.mock_conn.getStoragePoolCapabilities = MagicMock(return_value=xml_caps) -+ -+ actual = virt.pool_capabilities() -+ self.assertEqual({ -+ 'computed': False, -+ 'pool_types': [{ -+ 'name': 'disk', -+ 'supported': True, -+ 'options': { -+ 'pool': { -+ 'default_format': 'unknown', -+ 'sourceFormatType': ['unknown', 'dos', 'dvh'] -+ }, -+ 'volume': { -+ 'default_format': 'none', -+ 'targetFormatType': ['none', 'linux'] -+ } -+ } -+ }, -+ { -+ 'name': 'iscsi', -+ 'supported': True, -+ }, -+ { -+ 'name': 'rbd', -+ 'supported': True, -+ 'options': { -+ 'volume': { -+ 'default_format': 'raw', -+ 'targetFormatType': [] -+ } -+ } -+ }, -+ { -+ 'name': 'sheepdog', -+ 'supported': False, -+ }, -+ ]}, actual) -+ -+ @patch('salt.modules.virt.get_hypervisor', return_value='kvm') -+ def test_pool_capabilities_computed(self, mock_get_hypervisor): -+ ''' -+ Test virt.pool_capabilities where libvirt doesn't have the pool-capabilities feature -+ ''' -+ self.mock_conn.getLibVersion = MagicMock(return_value=4006000) -+ del self.mock_conn.getStoragePoolCapabilities -+ -+ actual = virt.pool_capabilities() -+ -+ self.assertTrue(actual['computed']) -+ backends = actual['pool_types'] -+ -+ # libvirt version matching check -+ self.assertFalse([backend for backend in backends if backend['name'] == 'iscsi-direct'][0]['supported']) -+ self.assertTrue([backend for backend in backends if backend['name'] == 'gluster'][0]['supported']) -+ self.assertFalse([backend for backend in backends if backend['name'] == 'zfs'][0]['supported']) -+ -+ # test case matching other hypervisors -+ mock_get_hypervisor.return_value = 'xen' -+ backends = virt.pool_capabilities()['pool_types'] -+ self.assertFalse([backend for backend in backends if backend['name'] == 'gluster'][0]['supported']) -+ -+ mock_get_hypervisor.return_value = 'bhyve' -+ backends = virt.pool_capabilities()['pool_types'] -+ self.assertFalse([backend for backend in backends if backend['name'] == 'gluster'][0]['supported']) -+ self.assertTrue([backend for backend in backends if backend['name'] == 'zfs'][0]['supported']) -+ -+ # Test options output -+ self.assertNotIn('options', [backend for backend in backends if backend['name'] == 'iscsi'][0]) -+ self.assertNotIn('pool', [backend for backend in backends if backend['name'] == 'dir'][0]['options']) -+ self.assertNotIn('volume', [backend for backend in backends if backend['name'] == 'logical'][0]['options']) -+ self.assertEqual({ -+ 'pool': { -+ 'default_format': 'auto', -+ 'sourceFormatType': ['auto', 'nfs', 'glusterfs', 'cifs'] -+ }, -+ 'volume': { -+ 'default_format': 'raw', -+ 'targetFormatType': ['none', 'raw', 'dir', 'bochs', 'cloop', 'dmg', 'iso', 'vpc', 'vdi', -+ 'fat', 'vhd', 'ploop', 'cow', 'qcow', 'qcow2', 'qed', 'vmdk'] -+ } -+ }, -+ [backend for backend in backends if backend['name'] == 'netfs'][0]['options']) -diff --git a/tests/unit/states/test_virt.py b/tests/unit/states/test_virt.py -index 109faf5fba..334c33b7d0 100644 ---- a/tests/unit/states/test_virt.py -+++ b/tests/unit/states/test_virt.py -@@ -619,6 +619,19 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin): - 'bridge', - vport='openvswitch', - tag=180, -+ ipv4_config={ -+ 'cidr': '192.168.2.0/24', -+ 'dhcp_ranges': [ -+ {'start': '192.168.2.10', 'end': '192.168.2.25'}, -+ {'start': '192.168.2.110', 'end': '192.168.2.125'}, -+ ] -+ }, -+ ipv6_config={ -+ 'cidr': '2001:db8:ca2:2::1/64', -+ 'dhcp_ranges': [ -+ {'start': '2001:db8:ca2:1::10', 'end': '2001:db8:ca2::1f'}, -+ ] -+ }, - autostart=False, - connection='myconnection', - username='user', -@@ -630,6 +643,19 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin): - tag=180, - autostart=False, - start=True, -+ ipv4_config={ -+ 'cidr': '192.168.2.0/24', -+ 'dhcp_ranges': [ -+ {'start': '192.168.2.10', 'end': '192.168.2.25'}, -+ {'start': '192.168.2.110', 'end': '192.168.2.125'}, -+ ] -+ }, -+ ipv6_config={ -+ 'cidr': '2001:db8:ca2:2::1/64', -+ 'dhcp_ranges': [ -+ {'start': '2001:db8:ca2:1::10', 'end': '2001:db8:ca2::1f'}, -+ ] -+ }, - connection='myconnection', - username='user', - password='secret') -@@ -668,92 +694,324 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin): - pool_running state test cases. - ''' - ret = {'name': 'mypool', 'changes': {}, 'result': True, 'comment': ''} -- mocks = {mock: MagicMock(return_value=True) for mock in ['define', 'autostart', 'build', 'start']} -- with patch.dict(virt.__salt__, { # pylint: disable=no-member -- 'virt.pool_info': MagicMock(return_value={}), -- 'virt.pool_define': mocks['define'], -- 'virt.pool_build': mocks['build'], -- 'virt.pool_start': mocks['start'], -- 'virt.pool_set_autostart': mocks['autostart'] -- }): -- ret.update({'changes': {'mypool': 'Pool defined and started'}, -- 'comment': 'Pool mypool defined and started'}) -- self.assertDictEqual(virt.pool_running('mypool', -+ mocks = {mock: MagicMock(return_value=True) for mock in ['define', 'autostart', 'build', 'start', 'stop']} -+ with patch.dict(virt.__opts__, {'test': False}): -+ with patch.dict(virt.__salt__, { # pylint: disable=no-member -+ 'virt.pool_info': MagicMock(return_value={}), -+ 'virt.pool_define': mocks['define'], -+ 'virt.pool_build': mocks['build'], -+ 'virt.pool_start': mocks['start'], -+ 'virt.pool_set_autostart': mocks['autostart'] -+ }): -+ ret.update({'changes': {'mypool': 'Pool defined, started and marked for autostart'}, -+ 'comment': 'Pool mypool defined, started and marked for autostart'}) -+ self.assertDictEqual(virt.pool_running('mypool', -+ ptype='logical', -+ target='/dev/base', -+ permissions={'mode': '0770', -+ 'owner': 1000, -+ 'group': 100, -+ 'label': 'seclabel'}, -+ source={'devices': [{'path': '/dev/sda'}]}, -+ transient=True, -+ autostart=True, -+ connection='myconnection', -+ username='user', -+ password='secret'), ret) -+ mocks['define'].assert_called_with('mypool', - ptype='logical', - target='/dev/base', - permissions={'mode': '0770', - 'owner': 1000, - 'group': 100, - 'label': 'seclabel'}, -- source={'devices': [{'path': '/dev/sda'}]}, -+ source_devices=[{'path': '/dev/sda'}], -+ source_dir=None, -+ source_adapter=None, -+ source_hosts=None, -+ source_auth=None, -+ source_name=None, -+ source_format=None, -+ source_initiator=None, - transient=True, -- autostart=True, -+ start=False, - connection='myconnection', - username='user', -- password='secret'), ret) -- mocks['define'].assert_called_with('mypool', -- ptype='logical', -- target='/dev/base', -- permissions={'mode': '0770', -- 'owner': 1000, -- 'group': 100, -- 'label': 'seclabel'}, -- source_devices=[{'path': '/dev/sda'}], -- source_dir=None, -- source_adapter=None, -- source_hosts=None, -- source_auth=None, -- source_name=None, -- source_format=None, -- transient=True, -- start=False, -- connection='myconnection', -- username='user', -- password='secret') -- mocks['autostart'].assert_called_with('mypool', -- state='on', -+ password='secret') -+ mocks['autostart'].assert_called_with('mypool', -+ state='on', -+ connection='myconnection', -+ username='user', -+ password='secret') -+ mocks['build'].assert_called_with('mypool', -+ connection='myconnection', -+ username='user', -+ password='secret') -+ mocks['start'].assert_called_with('mypool', - connection='myconnection', - username='user', - password='secret') -- mocks['build'].assert_called_with('mypool', -- connection='myconnection', -- username='user', -- password='secret') -- mocks['start'].assert_called_with('mypool', -- connection='myconnection', -- username='user', -- password='secret') - -- with patch.dict(virt.__salt__, { # pylint: disable=no-member -- 'virt.pool_info': MagicMock(return_value={'mypool': {'state': 'running'}}), -- }): -- ret.update({'changes': {}, 'comment': 'Pool mypool exists and is running'}) -- self.assertDictEqual(virt.pool_running('mypool', -+ mocks['update'] = MagicMock(return_value=False) -+ with patch.dict(virt.__salt__, { # pylint: disable=no-member -+ 'virt.pool_info': MagicMock(return_value={'mypool': {'state': 'running', 'autostart': True}}), -+ 'virt.pool_update': MagicMock(return_value=False), -+ }): -+ ret.update({'changes': {}, 'comment': 'Pool mypool unchanged and is running'}) -+ self.assertDictEqual(virt.pool_running('mypool', -+ ptype='logical', -+ target='/dev/base', -+ source={'devices': [{'path': '/dev/sda'}]}), ret) -+ -+ for mock in mocks: -+ mocks[mock].reset_mock() -+ with patch.dict(virt.__salt__, { # pylint: disable=no-member -+ 'virt.pool_info': MagicMock(return_value={'mypool': {'state': 'stopped', 'autostart': True}}), -+ 'virt.pool_update': mocks['update'], -+ 'virt.pool_build': mocks['build'], -+ 'virt.pool_start': mocks['start'] -+ }): -+ ret.update({'changes': {'mypool': 'Pool started'}, 'comment': 'Pool mypool started'}) -+ self.assertDictEqual(virt.pool_running('mypool', -+ ptype='logical', -+ target='/dev/base', -+ source={'devices': [{'path': '/dev/sda'}]}), ret) -+ mocks['start'].assert_called_with('mypool', connection=None, username=None, password=None) -+ mocks['build'].assert_not_called() -+ -+ with patch.dict(virt.__salt__, { # pylint: disable=no-member -+ 'virt.pool_info': MagicMock(return_value={}), -+ 'virt.pool_define': MagicMock(side_effect=self.mock_libvirt.libvirtError('Some error')) -+ }): -+ ret.update({'changes': {}, 'comment': 'Some error', 'result': False}) -+ self.assertDictEqual(virt.pool_running('mypool', -+ ptype='logical', -+ target='/dev/base', -+ source={'devices': [{'path': '/dev/sda'}]}), ret) -+ -+ # Test case with update and autostart change on stopped pool -+ for mock in mocks: -+ mocks[mock].reset_mock() -+ mocks['update'] = MagicMock(return_value=True) -+ with patch.dict(virt.__salt__, { # pylint: disable=no-member -+ 'virt.pool_info': MagicMock(return_value={'mypool': {'state': 'stopped', 'autostart': True}}), -+ 'virt.pool_update': mocks['update'], -+ 'virt.pool_set_autostart': mocks['autostart'], -+ 'virt.pool_build': mocks['build'], -+ 'virt.pool_start': mocks['start'] -+ }): -+ ret.update({'changes': {'mypool': 'Pool updated, built, autostart flag changed and started'}, -+ 'comment': 'Pool mypool updated, built, autostart flag changed and started', -+ 'result': True}) -+ self.assertDictEqual(virt.pool_running('mypool', -+ ptype='logical', -+ target='/dev/base', -+ autostart=False, -+ permissions={'mode': '0770', -+ 'owner': 1000, -+ 'group': 100, -+ 'label': 'seclabel'}, -+ source={'devices': [{'path': '/dev/sda'}]}), ret) -+ mocks['start'].assert_called_with('mypool', connection=None, username=None, password=None) -+ mocks['build'].assert_called_with('mypool', connection=None, username=None, password=None) -+ mocks['autostart'].assert_called_with('mypool', state='off', -+ connection=None, username=None, password=None) -+ mocks['update'].assert_called_with('mypool', - ptype='logical', - target='/dev/base', -- source={'devices': [{'path': '/dev/sda'}]}), ret) -- -- for mock in mocks: -- mocks[mock].reset_mock() -- with patch.dict(virt.__salt__, { # pylint: disable=no-member -- 'virt.pool_info': MagicMock(return_value={'mypool': {'state': 'stopped'}}), -- 'virt.pool_build': mocks['build'], -- 'virt.pool_start': mocks['start'] -- }): -- ret.update({'changes': {'mypool': 'Pool started'}, 'comment': 'Pool mypool started'}) -- self.assertDictEqual(virt.pool_running('mypool', -+ permissions={'mode': '0770', -+ 'owner': 1000, -+ 'group': 100, -+ 'label': 'seclabel'}, -+ source_devices=[{'path': '/dev/sda'}], -+ source_dir=None, -+ source_adapter=None, -+ source_hosts=None, -+ source_auth=None, -+ source_name=None, -+ source_format=None, -+ source_initiator=None, -+ connection=None, -+ username=None, -+ password=None) -+ -+ # test case with update and no autostart change on running pool -+ for mock in mocks: -+ mocks[mock].reset_mock() -+ with patch.dict(virt.__salt__, { # pylint: disable=no-member -+ 'virt.pool_info': MagicMock(return_value={'mypool': {'state': 'running', 'autostart': False}}), -+ 'virt.pool_update': mocks['update'], -+ 'virt.pool_build': mocks['build'], -+ 'virt.pool_start': mocks['start'], -+ 'virt.pool_stop': mocks['stop'] -+ }): -+ ret.update({'changes': {'mypool': 'Pool updated, built and restarted'}, -+ 'comment': 'Pool mypool updated, built and restarted', -+ 'result': True}) -+ self.assertDictEqual(virt.pool_running('mypool', -+ ptype='logical', -+ target='/dev/base', -+ autostart=False, -+ permissions={'mode': '0770', -+ 'owner': 1000, -+ 'group': 100, -+ 'label': 'seclabel'}, -+ source={'devices': [{'path': '/dev/sda'}]}), ret) -+ mocks['stop'].assert_called_with('mypool', connection=None, username=None, password=None) -+ mocks['start'].assert_called_with('mypool', connection=None, username=None, password=None) -+ mocks['build'].assert_called_with('mypool', connection=None, username=None, password=None) -+ mocks['update'].assert_called_with('mypool', - ptype='logical', - target='/dev/base', -- source={'devices': [{'path': '/dev/sda'}]}), ret) -- mocks['start'].assert_called_with('mypool', connection=None, username=None, password=None) -- mocks['build'].assert_not_called() -- -- with patch.dict(virt.__salt__, { # pylint: disable=no-member -- 'virt.pool_info': MagicMock(return_value={}), -- 'virt.pool_define': MagicMock(side_effect=self.mock_libvirt.libvirtError('Some error')) -+ permissions={'mode': '0770', -+ 'owner': 1000, -+ 'group': 100, -+ 'label': 'seclabel'}, -+ source_devices=[{'path': '/dev/sda'}], -+ source_dir=None, -+ source_adapter=None, -+ source_hosts=None, -+ source_auth=None, -+ source_name=None, -+ source_format=None, -+ source_initiator=None, -+ connection=None, -+ username=None, -+ password=None) -+ -+ with patch.dict(virt.__opts__, {'test': True}): -+ # test case with test=True and no change -+ with patch.dict(virt.__salt__, { # pylint: disable=no-member -+ 'virt.pool_info': MagicMock(return_value={'mypool': {'state': 'running', 'autostart': True}}), -+ 'virt.pool_update': MagicMock(return_value=False), -+ }): -+ ret.update({'changes': {}, 'comment': 'Pool mypool unchanged and is running', -+ 'result': True}) -+ self.assertDictEqual(virt.pool_running('mypool', -+ ptype='logical', -+ target='/dev/base', -+ source={'devices': [{'path': '/dev/sda'}]}), ret) -+ -+ # test case with test=True and started -+ for mock in mocks: -+ mocks[mock].reset_mock() -+ mocks['update'] = MagicMock(return_value=False) -+ with patch.dict(virt.__salt__, { # pylint: disable=no-member -+ 'virt.pool_info': MagicMock(return_value={'mypool': {'state': 'stopped', 'autostart': True}}), -+ 'virt.pool_update': mocks['update'] -+ }): -+ ret.update({'changes': {'mypool': 'Pool started'}, -+ 'comment': 'Pool mypool started', -+ 'result': None}) -+ self.assertDictEqual(virt.pool_running('mypool', -+ ptype='logical', -+ target='/dev/base', -+ source={'devices': [{'path': '/dev/sda'}]}), ret) -+ -+ def test_pool_deleted(self): -+ ''' -+ Test the pool_deleted state -+ ''' -+ # purge=False test case, stopped pool -+ with patch.dict(virt.__salt__, { -+ 'virt.pool_info': MagicMock(return_value={'test01': {'state': 'stopped', 'type': 'dir'}}), -+ 'virt.pool_undefine': MagicMock(return_value=True) - }): -- ret.update({'changes': {}, 'comment': 'Some error', 'result': False}) -- self.assertDictEqual(virt.pool_running('mypool', -- ptype='logical', -- target='/dev/base', -- source={'devices': [{'path': '/dev/sda'}]}), ret) -+ expected = { -+ 'name': 'test01', -+ 'changes': { -+ 'stopped': False, -+ 'deleted_volumes': [], -+ 'deleted': False, -+ 'undefined': True, -+ }, -+ 'result': True, -+ 'comment': '', -+ } -+ -+ with patch.dict(virt.__opts__, {'test': False}): -+ self.assertDictEqual(expected, virt.pool_deleted('test01')) -+ -+ with patch.dict(virt.__opts__, {'test': True}): -+ expected['result'] = None -+ self.assertDictEqual(expected, virt.pool_deleted('test01')) -+ -+ # purge=False test case -+ with patch.dict(virt.__salt__, { -+ 'virt.pool_info': MagicMock(return_value={'test01': {'state': 'running', 'type': 'dir'}}), -+ 'virt.pool_undefine': MagicMock(return_value=True), -+ 'virt.pool_stop': MagicMock(return_value=True) -+ }): -+ expected = { -+ 'name': 'test01', -+ 'changes': { -+ 'stopped': True, -+ 'deleted_volumes': [], -+ 'deleted': False, -+ 'undefined': True, -+ }, -+ 'result': True, -+ 'comment': '', -+ } -+ -+ with patch.dict(virt.__opts__, {'test': False}): -+ self.assertDictEqual(expected, virt.pool_deleted('test01')) -+ -+ with patch.dict(virt.__opts__, {'test': True}): -+ expected['result'] = None -+ self.assertDictEqual(expected, virt.pool_deleted('test01')) -+ -+ # purge=True test case -+ -+ with patch.dict(virt.__salt__, { -+ 'virt.pool_info': MagicMock(return_value={'test01': {'state': 'running', 'type': 'dir'}}), -+ 'virt.pool_list_volumes': MagicMock(return_value=['vm01.qcow2', 'vm02.qcow2']), -+ 'virt.pool_refresh': MagicMock(return_value=True), -+ 'virt.volume_delete': MagicMock(return_value=True), -+ 'virt.pool_stop': MagicMock(return_value=True), -+ 'virt.pool_delete': MagicMock(return_value=True), -+ 'virt.pool_undefine': MagicMock(return_value=True) -+ }): -+ expected = { -+ 'name': 'test01', -+ 'changes': { -+ 'stopped': True, -+ 'deleted_volumes': ['vm01.qcow2', 'vm02.qcow2'], -+ 'deleted': True, -+ 'undefined': True, -+ }, -+ 'result': True, -+ 'comment': '', -+ } -+ -+ with patch.dict(virt.__opts__, {'test': False}): -+ self.assertDictEqual(expected, virt.pool_deleted('test01', purge=True)) -+ -+ with patch.dict(virt.__opts__, {'test': True}): -+ expected['result'] = None -+ self.assertDictEqual(expected, virt.pool_deleted('test01', purge=True)) -+ -+ # Case of backend not unsupporting delete operations -+ with patch.dict(virt.__salt__, { -+ 'virt.pool_info': MagicMock(return_value={'test01': {'state': 'running', 'type': 'iscsi'}}), -+ 'virt.pool_stop': MagicMock(return_value=True), -+ 'virt.pool_undefine': MagicMock(return_value=True) -+ }): -+ expected = { -+ 'name': 'test01', -+ 'changes': { -+ 'stopped': True, -+ 'deleted_volumes': [], -+ 'deleted': False, -+ 'undefined': True, -+ }, -+ 'result': True, -+ 'comment': 'Unsupported actions for pool of type "iscsi": deleting volume, deleting pool', -+ } -+ -+ with patch.dict(virt.__opts__, {'test': False}): -+ self.assertDictEqual(expected, virt.pool_deleted('test01', purge=True)) -+ -+ with patch.dict(virt.__opts__, {'test': True}): -+ expected['result'] = None -+ self.assertDictEqual(expected, virt.pool_deleted('test01', purge=True)) --- -2.16.4 - - diff --git a/virt.volume_infos-fix-for-single-vm.patch b/virt.volume_infos-fix-for-single-vm.patch deleted file mode 100644 index 1bf83de..0000000 --- a/virt.volume_infos-fix-for-single-vm.patch +++ /dev/null @@ -1,92 +0,0 @@ -From 2635b6c87a74e6c274d41a1f526166f6d347ae0a Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?C=C3=A9dric=20Bosdonnat?= -Date: Thu, 4 Apr 2019 16:18:58 +0200 -Subject: [PATCH] virt.volume_infos fix for single VM - -_get_domain returns a domain object when only one VM has been found. -virt.volume_infos needs to take care of it or it will fail to list the -volumes informations if the host in such a case. ---- - salt/modules/virt.py | 4 +++- - tests/unit/modules/test_virt.py | 46 +++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 49 insertions(+), 1 deletion(-) - -diff --git a/salt/modules/virt.py b/salt/modules/virt.py -index 9bb3636bd1..d160f0905f 100644 ---- a/salt/modules/virt.py -+++ b/salt/modules/virt.py -@@ -5050,10 +5050,12 @@ def volume_infos(pool=None, volume=None, **kwargs): - conn = __get_conn(**kwargs) - try: - backing_stores = _get_all_volumes_paths(conn) -+ domains = _get_domain(conn) -+ domains_list = domains if isinstance(domains, list) else [domains] - disks = {domain.name(): - {node.get('file') for node - in ElementTree.fromstring(domain.XMLDesc(0)).findall('.//disk/source/[@file]')} -- for domain in _get_domain(conn)} -+ for domain in domains_list} - - def _volume_extract_infos(vol): - ''' -diff --git a/tests/unit/modules/test_virt.py b/tests/unit/modules/test_virt.py -index 6f9eea241a..cc62b67918 100644 ---- a/tests/unit/modules/test_virt.py -+++ b/tests/unit/modules/test_virt.py -@@ -2864,6 +2864,52 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin): - } - }) - -+ # Single VM test -+ with patch('salt.modules.virt._get_domain', MagicMock(return_value=mock_vms[0])): -+ actual = virt.volume_infos('pool0', 'vol0') -+ self.assertEqual(1, len(actual.keys())) -+ self.assertEqual(1, len(actual['pool0'].keys())) -+ self.assertEqual(['vm0'], sorted(actual['pool0']['vol0']['used_by'])) -+ self.assertEqual('/path/to/vol0.qcow2', actual['pool0']['vol0']['path']) -+ self.assertEqual('file', actual['pool0']['vol0']['type']) -+ self.assertEqual('/key/of/vol0', actual['pool0']['vol0']['key']) -+ self.assertEqual(123456789, actual['pool0']['vol0']['capacity']) -+ self.assertEqual(123456, actual['pool0']['vol0']['allocation']) -+ -+ self.assertEqual(virt.volume_infos('pool1', None), { -+ 'pool1': { -+ 'vol1': { -+ 'type': 'file', -+ 'key': '/key/of/vol1', -+ 'path': '/path/to/vol1.qcow2', -+ 'capacity': 12345, -+ 'allocation': 1234, -+ 'used_by': [], -+ }, -+ 'vol2': { -+ 'type': 'file', -+ 'key': '/key/of/vol2', -+ 'path': '/path/to/vol2.qcow2', -+ 'capacity': 12345, -+ 'allocation': 1234, -+ 'used_by': [], -+ } -+ } -+ }) -+ -+ self.assertEqual(virt.volume_infos(None, 'vol2'), { -+ 'pool1': { -+ 'vol2': { -+ 'type': 'file', -+ 'key': '/key/of/vol2', -+ 'path': '/path/to/vol2.qcow2', -+ 'capacity': 12345, -+ 'allocation': 1234, -+ 'used_by': [], -+ } -+ } -+ }) -+ - def test_volume_delete(self): - ''' - Test virt.volume_delete --- -2.16.4 - - diff --git a/virt.volume_infos-needs-to-ignore-inactive-pools-174.patch b/virt.volume_infos-needs-to-ignore-inactive-pools-174.patch deleted file mode 100644 index eb2a89b..0000000 --- a/virt.volume_infos-needs-to-ignore-inactive-pools-174.patch +++ /dev/null @@ -1,83 +0,0 @@ -From 0cf303fb475fc35c84aba0c4b2d4708aca3c211d Mon Sep 17 00:00:00 2001 -From: Cedric Bosdonnat -Date: Tue, 3 Sep 2019 15:17:38 +0200 -Subject: [PATCH] virt.volume_infos needs to ignore inactive pools (#174) - -libvirt raises an error when getting the list of volumes of a pool that -is not active. Rule out those pools from virt.volume_infos since we -still need to give infos on the other pools' volumes. ---- - salt/modules/virt.py | 7 +++++-- - tests/unit/modules/test_virt.py | 9 +++++++++ - 2 files changed, 14 insertions(+), 2 deletions(-) - -diff --git a/salt/modules/virt.py b/salt/modules/virt.py -index 953064cc2c..0353e6a1f5 100644 ---- a/salt/modules/virt.py -+++ b/salt/modules/virt.py -@@ -5021,7 +5021,9 @@ def _get_all_volumes_paths(conn): - - :param conn: libvirt connection to use - ''' -- volumes = [vol for l in [obj.listAllVolumes() for obj in conn.listAllStoragePools()] for vol in l] -+ volumes = [vol for l in -+ [obj.listAllVolumes() for obj in conn.listAllStoragePools() -+ if obj.info()[0] == libvirt.VIR_STORAGE_POOL_RUNNING] for vol in l] - return {vol.path(): [path.text for path in ElementTree.fromstring(vol.XMLDesc()).findall('.//backingStore/path')] - for vol in volumes if _is_valid_volume(vol)} - -@@ -5086,7 +5088,8 @@ def volume_infos(pool=None, volume=None, **kwargs): - 'used_by': used_by, - } - -- pools = [obj for obj in conn.listAllStoragePools() if pool is None or obj.name() == pool] -+ pools = [obj for obj in conn.listAllStoragePools() -+ if (pool is None or obj.name() == pool) and obj.info()[0] == libvirt.VIR_STORAGE_POOL_RUNNING] - vols = {pool_obj.name(): {vol.name(): _volume_extract_infos(vol) - for vol in pool_obj.listAllVolumes() - if (volume is None or vol.name() == volume) and _is_valid_volume(vol)} -diff --git a/tests/unit/modules/test_virt.py b/tests/unit/modules/test_virt.py -index b343b9bc31..e644e62452 100644 ---- a/tests/unit/modules/test_virt.py -+++ b/tests/unit/modules/test_virt.py -@@ -2743,6 +2743,7 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin): - mock_pool_data = [ - { - 'name': 'pool0', -+ 'state': self.mock_libvirt.VIR_STORAGE_POOL_RUNNING, - 'volumes': [ - { - 'key': '/key/of/vol0', -@@ -2755,6 +2756,7 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin): - }, - { - 'name': 'pool1', -+ 'state': self.mock_libvirt.VIR_STORAGE_POOL_RUNNING, - 'volumes': [ - { - 'key': '/key/of/vol0bad', -@@ -2784,6 +2786,7 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin): - for pool_data in mock_pool_data: - mock_pool = MagicMock() - mock_pool.name.return_value = pool_data['name'] # pylint: disable=no-member -+ mock_pool.info.return_value = [pool_data['state']] - mock_volumes = [] - for vol_data in pool_data['volumes']: - mock_volume = MagicMock() -@@ -2817,6 +2820,12 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin): - mock_pool.listAllVolumes.return_value = mock_volumes # pylint: disable=no-member - mock_pools.append(mock_pool) - -+ inactive_pool = MagicMock() -+ inactive_pool.name.return_value = 'pool2' -+ inactive_pool.info.return_value = [self.mock_libvirt.VIR_STORAGE_POOL_INACTIVE] -+ inactive_pool.listAllVolumes.side_effect = self.mock_libvirt.libvirtError('pool is inactive') -+ mock_pools.append(inactive_pool) -+ - self.mock_conn.listAllStoragePools.return_value = mock_pools # pylint: disable=no-member - - with patch('salt.modules.virt._get_domain', MagicMock(return_value=mock_vms)): --- -2.16.4 - - diff --git a/virt.volume_infos-silence-libvirt-error-message-175.patch b/virt.volume_infos-silence-libvirt-error-message-175.patch deleted file mode 100644 index d181409..0000000 --- a/virt.volume_infos-silence-libvirt-error-message-175.patch +++ /dev/null @@ -1,37 +0,0 @@ -From fa7ae6740e32adfc437923511b92aa2009b995f2 Mon Sep 17 00:00:00 2001 -From: Cedric Bosdonnat -Date: Tue, 3 Sep 2019 15:17:46 +0200 -Subject: [PATCH] virt.volume_infos: silence libvirt error message (#175) - -Even though the volume_infos handles the libvirt exception when a volume -is missing, libvirt was still outputting the error message in the log. -Since this can add noise to the log only record the libvirt error -message in debug level. ---- - salt/modules/virt.py | 8 +++++++- - 1 file changed, 7 insertions(+), 1 deletion(-) - -diff --git a/salt/modules/virt.py b/salt/modules/virt.py -index 0353e6a1f5..96c17bd60b 100644 ---- a/salt/modules/virt.py -+++ b/salt/modules/virt.py -@@ -5008,8 +5008,14 @@ def _is_valid_volume(vol): - the last pool refresh. - ''' - try: -- # Getting info on an invalid volume raises error -+ # Getting info on an invalid volume raises error and libvirt logs an error -+ def discarder(ctxt, error): # pylint: disable=unused-argument -+ log.debug("Ignore libvirt error: %s", error[2]) -+ # Disable the libvirt error logging -+ libvirt.registerErrorHandler(discarder, None) - vol.info() -+ # Reenable the libvirt error logging -+ libvirt.registerErrorHandler(None, None) - return True - except libvirt.libvirtError as err: - return False --- -2.16.4 - - diff --git a/x509-fixes-111.patch b/x509-fixes-111.patch index e6fe55e..a5671f4 100644 --- a/x509-fixes-111.patch +++ b/x509-fixes-111.patch @@ -1,4 +1,4 @@ -From 5e2b8d7ad2c98b0ab95e96a7f2df40715af11f3d Mon Sep 17 00:00:00 2001 +From ebd4bada22dca8f384078e977202c0052a80f1fc Mon Sep 17 00:00:00 2001 From: Florian Bergmann Date: Fri, 14 Sep 2018 10:30:39 +0200 Subject: [PATCH] X509 fixes (#111) @@ -34,12 +34,12 @@ PEP8: line too long * Fix unit tests --- salt/modules/publish.py | 8 +-- - salt/modules/x509.py | 132 +++++++++++++++++++----------------------------- - salt/states/x509.py | 22 +++++--- - 3 files changed, 69 insertions(+), 93 deletions(-) + salt/modules/x509.py | 129 +++++++++++++++++++----------------------------- + salt/states/x509.py | 19 ++++--- + 3 files changed, 66 insertions(+), 90 deletions(-) diff --git a/salt/modules/publish.py b/salt/modules/publish.py -index 62e3e98f2f..fda848d1ec 100644 +index 1550aa39a8..f12f1cc947 100644 --- a/salt/modules/publish.py +++ b/salt/modules/publish.py @@ -82,10 +82,8 @@ def _publish( @@ -55,9 +55,9 @@ index 62e3e98f2f..fda848d1ec 100644 if not matching_master_uris: raise SaltInvocationError('Could not find match for {0} in \ -@@ -178,6 +176,8 @@ def _publish( - finally: - channel.close() +@@ -175,6 +173,8 @@ def _publish( + else: + return ret + return {} + @@ -65,7 +65,7 @@ index 62e3e98f2f..fda848d1ec 100644 def publish(tgt, fun, diff --git a/salt/modules/x509.py b/salt/modules/x509.py -index 92e39a6b88..52c8024b2f 100644 +index 1cdd912bfb..72ab3bb03e 100644 --- a/salt/modules/x509.py +++ b/salt/modules/x509.py @@ -39,14 +39,13 @@ from salt.state import STATE_INTERNAL_KEYWORDS as _STATE_INTERNAL_KEYWORDS @@ -274,17 +274,7 @@ index 92e39a6b88..52c8024b2f 100644 raise salt.exceptions.SaltInvocationError( 'Either path or text must be specified.') if path and text: -@@ -1388,8 +1378,7 @@ def create_certificate( - # Including listen_in and preqreuired because they are not included - # in STATE_INTERNAL_KEYWORDS - # for salt 2014.7.2 -- for ignore in list(_STATE_INTERNAL_KEYWORDS) + \ -- ['listen_in', 'preqrequired', '__prerequired__']: -+ for ignore in list(_STATE_INTERNAL_KEYWORDS) + ['listen_in', 'preqrequired', '__prerequired__']: - kwargs.pop(ignore, None) - # TODO: Make timeout configurable in Neon - certs = __salt__['publish.publish']( -@@ -1504,8 +1493,7 @@ def create_certificate( +@@ -1504,8 +1494,7 @@ def create_certificate( continue # Use explicitly set values first, fall back to CSR values. @@ -294,7 +284,7 @@ index 92e39a6b88..52c8024b2f 100644 critical = False if extval.startswith('critical '): -@@ -1627,8 +1615,8 @@ def create_csr(path=None, text=False, **kwargs): +@@ -1627,8 +1616,8 @@ def create_csr(path=None, text=False, **kwargs): if 'private_key' not in kwargs and 'public_key' in kwargs: kwargs['private_key'] = kwargs['public_key'] @@ -305,7 +295,7 @@ index 92e39a6b88..52c8024b2f 100644 if 'private_key' not in kwargs: raise salt.exceptions.SaltInvocationError('private_key is required') -@@ -1640,11 +1628,9 @@ def create_csr(path=None, text=False, **kwargs): +@@ -1640,11 +1629,9 @@ def create_csr(path=None, text=False, **kwargs): kwargs['private_key_passphrase'] = None if 'public_key_passphrase' not in kwargs: kwargs['public_key_passphrase'] = None @@ -319,7 +309,7 @@ index 92e39a6b88..52c8024b2f 100644 kwargs['public_key_passphrase'] = kwargs['private_key_passphrase'] csr.set_pubkey(get_public_key(kwargs['public_key'], -@@ -1688,18 +1674,10 @@ def create_csr(path=None, text=False, **kwargs): +@@ -1688,18 +1675,10 @@ def create_csr(path=None, text=False, **kwargs): extstack.push(ext) csr.add_extensions(extstack) @@ -339,7 +329,7 @@ index 92e39a6b88..52c8024b2f 100644 def verify_private_key(private_key, public_key, passphrase=None): -@@ -1724,8 +1702,7 @@ def verify_private_key(private_key, public_key, passphrase=None): +@@ -1724,8 +1703,7 @@ def verify_private_key(private_key, public_key, passphrase=None): salt '*' x509.verify_private_key private_key=/etc/pki/myca.key \\ public_key=/etc/pki/myca.crt ''' @@ -349,7 +339,7 @@ index 92e39a6b88..52c8024b2f 100644 def verify_signature(certificate, signing_pub_key=None, -@@ -1779,9 +1756,8 @@ def verify_crl(crl, cert): +@@ -1779,9 +1757,8 @@ def verify_crl(crl, cert): salt '*' x509.verify_crl crl=/etc/pki/myca.crl cert=/etc/pki/myca.crt ''' if not salt.utils.path.which('openssl'): @@ -361,7 +351,7 @@ index 92e39a6b88..52c8024b2f 100644 crltext = _text_or_file(crl) crltext = get_pem_entry(crltext, pem_type='X509 CRL') crltempfile = tempfile.NamedTemporaryFile() -@@ -1802,10 +1778,7 @@ def verify_crl(crl, cert): +@@ -1802,10 +1779,7 @@ def verify_crl(crl, cert): crltempfile.close() certtempfile.close() @@ -373,7 +363,7 @@ index 92e39a6b88..52c8024b2f 100644 def expired(certificate): -@@ -1842,8 +1815,9 @@ def expired(certificate): +@@ -1842,8 +1816,9 @@ def expired(certificate): ret['expired'] = True else: ret['expired'] = False @@ -385,7 +375,7 @@ index 92e39a6b88..52c8024b2f 100644 return ret -@@ -1866,6 +1840,7 @@ def will_expire(certificate, days): +@@ -1866,6 +1841,7 @@ def will_expire(certificate, days): salt '*' x509.will_expire "/etc/pki/mycert.crt" days=30 ''' @@ -393,7 +383,7 @@ index 92e39a6b88..52c8024b2f 100644 ret = {} if os.path.isfile(certificate): -@@ -1875,18 +1850,13 @@ def will_expire(certificate, days): +@@ -1875,18 +1851,13 @@ def will_expire(certificate, days): cert = _get_certificate_obj(certificate) @@ -418,7 +408,7 @@ index 92e39a6b88..52c8024b2f 100644 return ret diff --git a/salt/states/x509.py b/salt/states/x509.py -index d44f85db17..c83d0d6047 100644 +index 3774f7d5eb..e4cc288dc9 100644 --- a/salt/states/x509.py +++ b/salt/states/x509.py @@ -163,6 +163,7 @@ import copy @@ -447,17 +437,7 @@ index d44f85db17..c83d0d6047 100644 def _revoked_to_list(revs): -@@ -267,7 +268,8 @@ def private_key_managed(name, - - new: - Always create a new key. Defaults to False. -- Combining new with :mod:`prereq `, or when used as part of a `managed_private_key` can allow key rotation whenever a new certificiate is generated. -+ Combining new with :mod:`prereq `, or when used as part of a -+ `managed_private_key` can allow key rotation whenever a new certificiate is generated. - - overwrite: - Overwrite an existing private key if the provided passphrase cannot decrypt it. -@@ -459,8 +461,10 @@ def certificate_managed(name, +@@ -459,8 +460,10 @@ def certificate_managed(name, private_key_args['name'], pem_type='RSA PRIVATE KEY') else: new_private_key = True @@ -470,7 +450,7 @@ index d44f85db17..c83d0d6047 100644 kwargs['public_key'] = private_key -@@ -671,8 +675,10 @@ def crl_managed(name, +@@ -671,8 +674,10 @@ def crl_managed(name, else: current = '{0} does not exist.'.format(name) @@ -483,7 +463,7 @@ index d44f85db17..c83d0d6047 100644 new = __salt__['x509.read_crl'](crl=new_crl) new_comp = new.copy() -@@ -714,6 +720,6 @@ def pem_managed(name, +@@ -714,6 +719,6 @@ def pem_managed(name, Any arguments supported by :py:func:`file.managed ` are supported. ''' file_args, kwargs = _get_file_args(name, **kwargs) diff --git a/xfs-do-not-fails-if-type-is-not-present.patch b/xfs-do-not-fails-if-type-is-not-present.patch index c4e3224..f1bd207 100644 --- a/xfs-do-not-fails-if-type-is-not-present.patch +++ b/xfs-do-not-fails-if-type-is-not-present.patch @@ -1,4 +1,4 @@ -From 4a922d62a899cacf15a80882b2d1aff7ab66097c Mon Sep 17 00:00:00 2001 +From 9d1e598bf8c7aff612a58405ad864ba701f022c3 Mon Sep 17 00:00:00 2001 From: Alberto Planas Date: Tue, 11 Jun 2019 17:21:05 +0200 Subject: [PATCH] xfs: do not fails if type is not present @@ -13,12 +13,12 @@ output. (cherry picked from commit 88df6963470007aa4fe2adb09f000311f48226a8) --- salt/modules/xfs.py | 2 +- - tests/unit/modules/test_xfs.py | 50 ++++++++++++++++++++++++++++++++++ + tests/unit/modules/test_xfs.py | 50 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 tests/unit/modules/test_xfs.py diff --git a/salt/modules/xfs.py b/salt/modules/xfs.py -index 6546603ed6..e133ec83e1 100644 +index ce7bd187fe..0116d7600e 100644 --- a/salt/modules/xfs.py +++ b/salt/modules/xfs.py @@ -329,7 +329,7 @@ def _blkid_output(out): @@ -87,6 +87,6 @@ index 0000000000..4b423d69d1 + } + }) -- -2.23.0 +2.16.4