Hello community,

here is the log from the commit of package salt for openSUSE:Factory checked in 
at 2019-06-18 14:55:12
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/salt (Old)
 and      /work/SRC/openSUSE:Factory/.salt.new.4811 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "salt"

Tue Jun 18 14:55:12 2019 rev:87 rq:709997 version:2019.2.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/salt/salt.changes        2019-06-12 
12:58:20.985340065 +0200
+++ /work/SRC/openSUSE:Factory/.salt.new.4811/salt.changes      2019-06-18 
14:55:13.677446197 +0200
@@ -1,0 +2,51 @@
+Fri Jun 14 14:09:29 UTC 2019 - Pablo Suárez Hernández 
<pablo.suarezhernan...@suse.com>
+
+- Fix zypper pkg.list_pkgs test expectation and dpkg mocking
+
+- Added:
+  * fix-zypper-pkg.list_pkgs-expectation-and-dpkg-mockin.patch 
+
+-------------------------------------------------------------------
+Fri Jun 14 12:15:43 UTC 2019 - Pablo Suárez Hernández 
<pablo.suarezhernan...@suse.com>
+
+- Set 'salt' group for files and directories created by
+  salt-standalone-formulas-configuration package
+- Various fixes for virt module
+- Fix virt.volume_infos raising an exception when there is only virtual 
machine on the minion.
+- Fix virt.purge() on all non-KVM hypervisors. For instance on Xen, virt.purge 
would simply throw an exception about unsupported flag
+- Building a libvirt pool starts it. When defining a new pool, we need to
+let build start it or we will get libvirt errors.
+- Fix handling of Virtual Machines with white space in their name.
+
+- Added:
+  * virt.pool_running-fix-pool-start.patch
+  * virt-handle-whitespaces-in-vm-names.patch
+  * virt.volume_infos-fix-for-single-vm.patch
+  * try-except-undefineflags-as-this-operation-is-not-su.patch
+
+-------------------------------------------------------------------
+Wed Jun  5 14:26:29 UTC 2019 - Pablo Suárez Hernández 
<pablo.suarezhernan...@suse.com>
+
+- avoid batch.py exception when minion does not respond (bsc#1135507)
+
+- Added:
+  * batch.py-avoid-exception-when-minion-does-not-respon.patch
+
+-------------------------------------------------------------------
+Mon Jun  3 11:01:57 UTC 2019 - psuarezhernan...@suse.com
+
+- Preserve already defined DESTRUCTIVE_TESTS and EXPENSIVE_TESTS
+  env variables
+
+- Added:
+  * preserve-already-defined-destructive_tests-and-expen.patch
+
+-------------------------------------------------------------------
+Wed May 29 10:54:42 UTC 2019 - psuarezhernan...@suse.com
+
+- Do not break repo files with multiple line values on yumpkg (bsc#1135360)
+
+- Added:
+  * do-not-break-repo-files-with-multiple-line-values-on.patch
+
+-------------------------------------------------------------------

New:
----
  batch.py-avoid-exception-when-minion-does-not-respon.patch
  do-not-break-repo-files-with-multiple-line-values-on.patch
  fix-zypper-pkg.list_pkgs-expectation-and-dpkg-mockin.patch
  preserve-already-defined-destructive_tests-and-expen.patch
  try-except-undefineflags-as-this-operation-is-not-su.patch
  virt-handle-whitespaces-in-vm-names.patch
  virt.pool_running-fix-pool-start.patch
  virt.volume_infos-fix-for-single-vm.patch

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ salt.spec ++++++
--- /var/tmp/diff_new_pack.QvbGtG/_old  2019-06-18 14:55:15.229445189 +0200
+++ /var/tmp/diff_new_pack.QvbGtG/_new  2019-06-18 14:55:15.233445185 +0200
@@ -180,6 +180,22 @@
 Patch56:       add-standalone-configuration-file-for-enabling-packa.patch
 # PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/53237
 Patch57:       add-ppc64le-as-a-valid-rpm-package-architecture.patch
+# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/53293
+Patch58:       do-not-break-repo-files-with-multiple-line-values-on.patch
+# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/53343
+Patch59:       preserve-already-defined-destructive_tests-and-expen.patch
+# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/53159
+Patch60:       batch.py-avoid-exception-when-minion-does-not-respon.patch
+# PATCH_FIX_UPSTREAM: https://github.com/saltstack/salt/pull/53471
+Patch61:       fix-zypper-pkg.list_pkgs-expectation-and-dpkg-mockin.patch
+# PATCH_FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/142
+Patch62:       try-except-undefineflags-as-this-operation-is-not-su.patch
+# PATCH_FIX_UPSTREAM: https://github.com/saltstack/salt/pull/52160
+Patch63:       virt-handle-whitespaces-in-vm-names.patch
+# PATCH_FIX_UPSTREAM: https://github.com/saltstack/salt/pull/52341
+Patch64:       virt.pool_running-fix-pool-start.patch
+# PATCH_FIX_UPSTREAM: https://github.com/saltstack/salt/pull/52414
+Patch65:       virt.volume_infos-fix-for-single-vm.patch
 
 # BuildRoot:      %{_tmppath}/%{name}-%{version}-build
 BuildRoot:      %{_tmppath}/%{name}-%{version}-build
@@ -707,6 +723,14 @@
 %patch55 -p1
 %patch56 -p1
 %patch57 -p1
+%patch58 -p1
+%patch59 -p1
+%patch60 -p1
+%patch61 -p1
+%patch62 -p1
+%patch63 -p1
+%patch64 -p1
+%patch65 -p1
 
 %build
 %if 0%{?build_py2}
@@ -1426,9 +1450,9 @@
 
 %files standalone-formulas-configuration
 %defattr(-,root,root)
-%config(noreplace) %attr(0640, root, root) 
%{_sysconfdir}/salt/master.d/standalone-formulas-configuration.conf
-%dir               %attr(0750, root, root) %{_prefix}/share/salt-formulas/
-%dir               %attr(0750, root, root) 
%{_prefix}/share/salt-formulas/states/
-%dir               %attr(0750, root, root) 
%{_prefix}/share/salt-formulas/metadata/
+%config(noreplace) %attr(0640, root, salt) 
%{_sysconfdir}/salt/master.d/standalone-formulas-configuration.conf
+%dir               %attr(0750, root, salt) %{_prefix}/share/salt-formulas/
+%dir               %attr(0750, root, salt) 
%{_prefix}/share/salt-formulas/states/
+%dir               %attr(0750, root, salt) 
%{_prefix}/share/salt-formulas/metadata/
 
 %changelog

++++++ _lastrevision ++++++
--- /var/tmp/diff_new_pack.QvbGtG/_old  2019-06-18 14:55:15.313445133 +0200
+++ /var/tmp/diff_new_pack.QvbGtG/_new  2019-06-18 14:55:15.313445133 +0200
@@ -1 +1 @@
-6ea034113af0bc6f97110175d633bdf951af0fcd
\ No newline at end of file
+1d301081a6e8a705499eb861b24c46ab17120691
\ No newline at end of file

++++++ batch.py-avoid-exception-when-minion-does-not-respon.patch ++++++
>From 50377852ca989ffa141fcf32d5ca57d120b455b8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jos=C3=A9=20Guilherme=20Vanz?= <jv...@jvanz.com>
Date: Tue, 21 May 2019 16:13:18 -0300
Subject: [PATCH] batch.py: avoid exception when minion does not respond
 (bsc#1135507)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

We have several issues reporting that salt is throwing exception when
the minion does not respond. This change avoid the exception adding a
default data to the minion when it fails to respond. This patch based
on the patch suggested by @roskens.

Issues #46876 #48509 #50238
bsc#1135507

Signed-off-by: José Guilherme Vanz <jguilhermev...@suse.com>
---
 salt/cli/batch.py | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/salt/cli/batch.py b/salt/cli/batch.py
index ce239215cb..1623fc5be8 100644
--- a/salt/cli/batch.py
+++ b/salt/cli/batch.py
@@ -315,6 +315,11 @@ class Batch(object):
                     if self.opts.get('failhard') and data['ret']['retcode'] > 
0:
                         failhard = True
 
+                # avoid an exception if the minion does not respond.
+                if data.get("failed") is True:
+                    log.debug('Minion %s failed to respond: data=%s', minion, 
data)
+                    data = {'ret': 'Minion did not return. [Failed]', 
'retcode': salt.defaults.exitcodes.EX_GENERIC}
+
                 if self.opts.get('raw'):
                     ret[minion] = data
                     yield data
-- 
2.21.0


++++++ do-not-break-repo-files-with-multiple-line-values-on.patch ++++++
>From b99e55aab52d086315d54cf44af68f40dcf79dc9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?=
 <psuarezhernan...@suse.com>
Date: Wed, 29 May 2019 11:03:16 +0100
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(-)

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 0271cea81f..a82c9662c7 100644
--- a/tests/integration/modules/test_pkg.py
+++ b/tests/integration/modules/test_pkg.py
@@ -123,6 +123,54 @@ 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 = 
'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.21.0


++++++ fix-zypper-pkg.list_pkgs-expectation-and-dpkg-mockin.patch ++++++
>From 8c4066c668147b1180c56f39722d2ade78ffd41c Mon Sep 17 00:00:00 2001
From: Mihai Dinca <mdi...@suse.de>
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(-)

diff --git a/tests/unit/modules/test_dpkg_lowpkg.py 
b/tests/unit/modules/test_dpkg_lowpkg.py
index d16ce3cc1a..98557a1d10 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):
         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'))
+    @patch('salt.modules.dpkg_lowpkg._get_pkg_ds_avail', 
MagicMock(return_value=dselect_pkg))
+    @patch('salt.modules.dpkg_lowpkg._get_pkg_info', 
MagicMock(return_value=pkgs_info))
+    @patch('salt.modules.dpkg_lowpkg._get_pkg_license', 
MagicMock(return_value='BSD v3'))
     def test_info(self):
         '''
         Test info
@@ -154,9 +154,9 @@ class DpkgTestCase(TestCase, LoaderModuleMockMixin):
         assert pkg_data['maintainer'] == 'Simpsons Developers 
<simpsons-devel-disc...@lists.springfield.org>'
         assert pkg_data['license'] == 'BSD v3'
 
-    @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'))
+    @patch('salt.modules.dpkg_lowpkg._get_pkg_ds_avail', 
MagicMock(return_value=dselect_pkg))
+    @patch('salt.modules.dpkg_lowpkg._get_pkg_info', 
MagicMock(return_value=pkgs_info))
+    @patch('salt.modules.dpkg_lowpkg._get_pkg_license', 
MagicMock(return_value='BSD v3'))
     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.21.0


++++++ preserve-already-defined-destructive_tests-and-expen.patch ++++++
>From 5a1e0b7b8eab900e03fa800cc7a0a2b59bf2ff55 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?=
 <psuarezhernan...@suse.com>
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 ed262d46c0..f269457670 100644
--- a/tests/support/parser/__init__.py
+++ b/tests/support/parser/__init__.py
@@ -574,12 +574,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.17.1


++++++ try-except-undefineflags-as-this-operation-is-not-su.patch ++++++
>From e0bded83fa691c3b972fa4c22b14c5ac0a7a3f13 Mon Sep 17 00:00:00 2001
From: Jeroen Schutrup <jeroenschut...@hotmail.nl>
Date: Sun, 12 Aug 2018 19:43:22 +0200
Subject: [PATCH] Try/except undefineFlags() as this operation is not
 supported on bhyve

(cherry picked from commit 29a44aceb1a73347ac07dd241b4a64a4a38cef6e)
---
 salt/modules/virt.py | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/salt/modules/virt.py b/salt/modules/virt.py
index a3f625909d..423016cd90 100644
--- a/salt/modules/virt.py
+++ b/salt/modules/virt.py
@@ -3189,7 +3189,10 @@ def purge(vm_, dirs=False, removables=None, **kwargs):
             shutil.rmtree(dir_)
     if getattr(libvirt, 'VIR_DOMAIN_UNDEFINE_NVRAM', False):
         # This one is only in 1.2.8+
-        dom.undefineFlags(libvirt.VIR_DOMAIN_UNDEFINE_NVRAM)
+        try:
+            dom.undefineFlags(libvirt.VIR_DOMAIN_UNDEFINE_NVRAM)
+        except Exception:
+            dom.undefine()
     else:
         dom.undefine()
     conn.close()
-- 
2.21.0


++++++ virt-handle-whitespaces-in-vm-names.patch ++++++
>From fbad82a38b4460260726cb3b9456cad7986eb4cd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?C=C3=A9dric=20Bosdonnat?= <cbosdon...@suse.com>
Date: Wed, 13 Mar 2019 09:43:51 +0100
Subject: [PATCH] virt: handle whitespaces in VM names

The disk creation code is now ready to handle whitespaces in virtual
machine name.
---
 salt/modules/virt.py            |  8 +++---
 tests/unit/modules/test_virt.py | 46 ++++++++++++++++-----------------
 2 files changed, 27 insertions(+), 27 deletions(-)

diff --git a/salt/modules/virt.py b/salt/modules/virt.py
index 423016cd90..d160f0905f 100644
--- a/salt/modules/virt.py
+++ b/salt/modules/virt.py
@@ -760,14 +760,14 @@ def _qemu_image_create(disk, create_overlay=False, 
saltenv='base'):
 
         qcow2 = False
         if salt.utils.path.which('qemu-img'):
-            res = __salt__['cmd.run']('qemu-img info {}'.format(sfn))
+            res = __salt__['cmd.run']('qemu-img info "{}"'.format(sfn))
             imageinfo = salt.utils.yaml.safe_load(res)
             qcow2 = imageinfo['file format'] == 'qcow2'
         try:
             if create_overlay and qcow2:
                 log.info('Cloning qcow2 image %s using copy on write', sfn)
                 __salt__['cmd.run'](
-                    'qemu-img create -f qcow2 -o backing_file={0} {1}'
+                    'qemu-img create -f qcow2 -o backing_file="{0}" "{1}"'
                     .format(sfn, img_dest).split())
             else:
                 log.debug('Copying %s to %s', sfn, img_dest)
@@ -778,7 +778,7 @@ def _qemu_image_create(disk, create_overlay=False, 
saltenv='base'):
             if disk_size and qcow2:
                 log.debug('Resize qcow2 image to %sM', disk_size)
                 __salt__['cmd.run'](
-                    'qemu-img resize {0} {1}M'
+                    'qemu-img resize "{0}" {1}M'
                     .format(img_dest, disk_size)
                 )
 
@@ -800,7 +800,7 @@ def _qemu_image_create(disk, create_overlay=False, 
saltenv='base'):
             if disk_size:
                 log.debug('Create empty image with size %sM', disk_size)
                 __salt__['cmd.run'](
-                    'qemu-img create -f {0} {1} {2}M'
+                    'qemu-img create -f {0} "{1}" {2}M'
                     .format(disk.get('format', 'qcow2'), img_dest, disk_size)
                 )
             else:
diff --git a/tests/unit/modules/test_virt.py b/tests/unit/modules/test_virt.py
index bbe8d813d7..cc62b67918 100644
--- a/tests/unit/modules/test_virt.py
+++ b/tests/unit/modules/test_virt.py
@@ -1106,7 +1106,7 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
             with patch.dict(virt.__salt__, {'cmd.run': mock_run}):  # pylint: 
disable=no-member
 
                 # Ensure the init() function allows creating VM without NIC 
and disk
-                virt.init('testvm',
+                virt.init('test vm',
                           2,
                           1234,
                           nic=None,
@@ -1120,7 +1120,7 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
                 # Test case creating disks
                 defineMock.reset_mock()
                 mock_run.reset_mock()
-                virt.init('testvm',
+                virt.init('test vm',
                           2,
                           1234,
                           nic=None,
@@ -1134,10 +1134,10 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
                 definition = ET.fromstring(defineMock.call_args_list[0][0][0])
                 disk_sources = [disk.find('source').get('file') if 
disk.find('source') is not None else None
                                 for disk in 
definition.findall('./devices/disk')]
-                expected_disk_path = os.path.join(root_dir, 
'testvm_system.qcow2')
+                expected_disk_path = os.path.join(root_dir, 'test 
vm_system.qcow2')
                 self.assertEqual(disk_sources, [expected_disk_path, None])
                 self.assertEqual(mock_run.call_args[0][0],
-                                 'qemu-img create -f qcow2 {0} 
10240M'.format(expected_disk_path))
+                                 'qemu-img create -f qcow2 "{0}" 
10240M'.format(expected_disk_path))
                 self.assertEqual(mock_chmod.call_args[0][0], 
expected_disk_path)
 
     def test_update(self):
@@ -1147,7 +1147,7 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
         root_dir = os.path.join(salt.syspaths.ROOT_DIR, 'srv', 'salt-images')
         xml = '''
             <domain type='kvm' id='7'>
-              <name>myvm</name>
+              <name>my vm</name>
               <memory unit='KiB'>1048576</memory>
               <currentMemory unit='KiB'>1048576</currentMemory>
               <vcpu placement='auto'>1</vcpu>
@@ -1157,7 +1157,7 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
               <devices>
                 <disk type='file' device='disk'>
                   <driver name='qemu' type='qcow2'/>
-                  <source file='{0}{1}myvm_system.qcow2'/>
+                  <source file='{0}{1}my vm_system.qcow2'/>
                   <backingStore/>
                   <target dev='vda' bus='virtio'/>
                   <alias name='virtio-disk0'/>
@@ -1165,7 +1165,7 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
                 </disk>
                 <disk type='file' device='disk'>
                   <driver name='qemu' type='qcow2'/>
-                  <source file='{0}{1}myvm_data.qcow2'/>
+                  <source file='{0}{1}my vm_data.qcow2'/>
                   <backingStore/>
                   <target dev='vdb' bus='virtio'/>
                   <alias name='virtio-disk1'/>
@@ -1198,7 +1198,7 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
               </devices>
             </domain>
         '''.format(root_dir, os.sep)
-        domain_mock = self.set_mock_vm('myvm', xml)
+        domain_mock = self.set_mock_vm('my vm', xml)
         domain_mock.OSType = MagicMock(return_value='hvm')
         define_mock = MagicMock(return_value=True)
         self.mock_conn.defineXML = define_mock
@@ -1211,7 +1211,7 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
                 'cpu': True,
                 'disk': {'attached': [], 'detached': []},
                 'interface': {'attached': [], 'detached': []}
-            }, virt.update('myvm', cpu=2))
+            }, virt.update('my vm', cpu=2))
         setxml = ET.fromstring(define_mock.call_args[0][0])
         self.assertEqual(setxml.find('vcpu').text, '2')
         self.assertEqual(setvcpus_mock.call_args[0][0], 2)
@@ -1225,7 +1225,7 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
                 'mem': True,
                 'disk': {'attached': [], 'detached': []},
                 'interface': {'attached': [], 'detached': []}
-            }, virt.update('myvm', mem=2048))
+            }, virt.update('my vm', mem=2048))
         setxml = ET.fromstring(define_mock.call_args[0][0])
         self.assertEqual(setxml.find('memory').text, '2048')
         self.assertEqual(setxml.find('memory').get('unit'), 'MiB')
@@ -1240,21 +1240,21 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
         mock_run = MagicMock()
         with patch.dict(os.__dict__, {'chmod': mock_chmod, 'makedirs': 
MagicMock()}):  # pylint: disable=no-member
             with patch.dict(virt.__salt__, {'cmd.run': mock_run}):  # pylint: 
disable=no-member
-                ret = virt.update('myvm', disk_profile='default', disks=[
+                ret = virt.update('my vm', disk_profile='default', disks=[
                     {'name': 'cddrive', 'device': 'cdrom', 'source_file': 
None, 'model': 'ide'},
                     {'name': 'added', 'size': 2048}])
                 added_disk_path = os.path.join(
-                        virt.__salt__['config.get']('virt:images'), 
'myvm_added.qcow2')  # pylint: disable=no-member
+                        virt.__salt__['config.get']('virt:images'), 'my 
vm_added.qcow2')  # pylint: disable=no-member
                 self.assertEqual(mock_run.call_args[0][0],
-                                 'qemu-img create -f qcow2 {0} 
2048M'.format(added_disk_path))
+                                 'qemu-img create -f qcow2 "{0}" 
2048M'.format(added_disk_path))
                 self.assertEqual(mock_chmod.call_args[0][0], added_disk_path)
                 self.assertListEqual(
-                    [None, os.path.join(root_dir, 'myvm_added.qcow2')],
+                    [None, os.path.join(root_dir, 'my vm_added.qcow2')],
                     [ET.fromstring(disk).find('source').get('file') if 
str(disk).find('<source') > -1 else None
                      for disk in ret['disk']['attached']])
 
                 self.assertListEqual(
-                    [os.path.join(root_dir, 'myvm_data.qcow2')],
+                    [os.path.join(root_dir, 'my vm_data.qcow2')],
                     [ET.fromstring(disk).find('source').get('file') for disk 
in ret['disk']['detached']])
                 self.assertEqual(devattach_mock.call_count, 2)
                 devdetach_mock.assert_called_once()
@@ -1271,7 +1271,7 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
         devattach_mock.reset_mock()
         devdetach_mock.reset_mock()
         with patch.dict(salt.modules.config.__opts__, mock_config):  # pylint: 
disable=no-member
-            ret = virt.update('myvm', nic_profile='myprofile',
+            ret = virt.update('my vm', nic_profile='myprofile',
                               interfaces=[{'name': 'eth0', 'type': 'network', 
'source': 'default',
                                            'mac': '52:54:00:39:02:b1'},
                                           {'name': 'eth1', 'type': 'network', 
'source': 'newnet'}])
@@ -1285,7 +1285,7 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
         # Remove nics case
         devattach_mock.reset_mock()
         devdetach_mock.reset_mock()
-        ret = virt.update('myvm', nic_profile=None, interfaces=[])
+        ret = virt.update('my vm', nic_profile=None, interfaces=[])
         self.assertEqual([], ret['interface']['attached'])
         self.assertEqual(2, len(ret['interface']['detached']))
         devattach_mock.assert_not_called()
@@ -1294,7 +1294,7 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
         # Remove disks case (yeah, it surely is silly)
         devattach_mock.reset_mock()
         devdetach_mock.reset_mock()
-        ret = virt.update('myvm', disk_profile=None, disks=[])
+        ret = virt.update('my vm', disk_profile=None, disks=[])
         self.assertEqual([], ret['disk']['attached'])
         self.assertEqual(2, len(ret['disk']['detached']))
         devattach_mock.assert_not_called()
@@ -1305,7 +1305,7 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
                 'definition': True,
                 'disk': {'attached': [], 'detached': []},
                 'interface': {'attached': [], 'detached': []}
-            }, virt.update('myvm', graphics={'type': 'vnc'}))
+            }, virt.update('my vm', graphics={'type': 'vnc'}))
         setxml = ET.fromstring(define_mock.call_args[0][0])
         self.assertEqual('vnc', setxml.find('devices/graphics').get('type'))
 
@@ -1314,7 +1314,7 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
                 'definition': False,
                 'disk': {'attached': [], 'detached': []},
                 'interface': {'attached': [], 'detached': []}
-            }, virt.update('myvm', cpu=1, mem=1024,
+            }, virt.update('my vm', cpu=1, mem=1024,
                            disk_profile='default', disks=[{'name': 'data', 
'size': 2048}],
                            nic_profile='myprofile',
                            interfaces=[{'name': 'eth0', 'type': 'network', 
'source': 'default',
@@ -1328,7 +1328,7 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
         self.mock_conn.defineXML.side_effect = 
self.mock_libvirt.libvirtError("Test error")
         setmem_mock.reset_mock()
         with self.assertRaises(self.mock_libvirt.libvirtError):
-            virt.update('myvm', mem=2048)
+            virt.update('my vm', mem=2048)
 
         # Failed single update failure case
         self.mock_conn.defineXML = MagicMock(return_value=True)
@@ -1338,7 +1338,7 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
                 'errors': ['Failed to live change memory'],
                 'disk': {'attached': [], 'detached': []},
                 'interface': {'attached': [], 'detached': []}
-            }, virt.update('myvm', mem=2048))
+            }, virt.update('my vm', mem=2048))
 
         # Failed multiple updates failure case
         self.assertEqual({
@@ -1347,7 +1347,7 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
                 'cpu': True,
                 'disk': {'attached': [], 'detached': []},
                 'interface': {'attached': [], 'detached': []}
-            }, virt.update('myvm', cpu=4, mem=2048))
+            }, virt.update('my vm', cpu=4, mem=2048))
 
     def test_mixed_dict_and_list_as_profile_objects(self):
         '''
-- 
2.21.0


++++++ virt.pool_running-fix-pool-start.patch ++++++
>From 946dd98e911e62c7bc3bcdd8adc8a170645c981c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?C=C3=A9dric=20Bosdonnat?= <cbosdon...@suse.com>
Date: Wed, 6 Jun 2018 09:49:36 +0200
Subject: [PATCH] virt.pool_running: fix pool start

Building a libvirt pool starts it. When defining a new pool, we need to
let build start it or we will get libvirt errors.

Also backport virt states test to add test for the bug:

cherry picked from commits:
 - 451e7da55bd232546c4d30ec36d432de2d5a14ec
 - 495db345a570cb14cd9b0ae96e1bb0f3fad6aef0
 - cb00a5f9b4c9a2a863da3c1107ca6458a4092c3d
 - fc75872fb63e254eecc782168ff8b37157d9e514
 - 2a5f6ae5d69be71daeab6c9cbe4dd642255ff3c6
 - 2463ebe5a82b1a017004e8e0e390535485dc703e
 - c7c5d6ee88fbc74d0ee0aeab41beb421d8625f05
---
 salt/states/virt.py            |   7 +-
 tests/unit/states/test_virt.py | 508 ++++++++++++++++++++++++++++++++-
 2 files changed, 508 insertions(+), 7 deletions(-)

diff --git a/salt/states/virt.py b/salt/states/virt.py
index 90693880df..d411f864cd 100644
--- a/salt/states/virt.py
+++ b/salt/states/virt.py
@@ -780,7 +780,7 @@ def pool_running(name,
                                          source_name=(source or 
{}).get('name', None),
                                          source_format=(source or 
{}).get('format', None),
                                          transient=transient,
-                                         start=True,
+                                         start=False,
                                          connection=connection,
                                          username=username,
                                          password=password)
@@ -795,11 +795,6 @@ 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 2e421319ad..8022989937 100644
--- a/tests/unit/states/test_virt.py
+++ b/tests/unit/states/test_virt.py
@@ -21,6 +21,25 @@ from tests.support.mock import (
 # Import Salt Libs
 import salt.states.virt as virt
 import salt.utils.files
+from salt.exceptions import CommandExecutionError
+
+# Import 3rd-party libs
+from salt.ext import six
+
+
+class LibvirtMock(MagicMock):  # pylint: disable=too-many-ancestors
+    '''
+    libvirt library mockup
+    '''
+    class libvirtError(Exception):  # pylint: disable=invalid-name
+        '''
+        libvirt error mockup
+        '''
+        def get_error_message(self):
+            '''
+            Fake function return error message
+            '''
+            return six.text_type(self)
 
 
 @skipIf(NO_MOCK, NO_MOCK_REASON)
@@ -29,7 +48,12 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin):
     Test cases for salt.states.libvirt
     '''
     def setup_loader_modules(self):
-        return {virt: {}}
+        self.mock_libvirt = LibvirtMock()  # pylint: 
disable=attribute-defined-outside-init
+        self.addCleanup(delattr, self, 'mock_libvirt')
+        loader_globals = {
+            'libvirt': self.mock_libvirt
+        }
+        return {virt: loader_globals}
 
     @classmethod
     def setUpClass(cls):
@@ -195,3 +219,485 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin):
                                                        locality='Los_Angeles',
                                                        
organization='SaltStack',
                                                        expiration_days=700), 
ret)
+
+    def test_running(self):
+        '''
+        running state test cases.
+        '''
+        ret = {'name': 'myvm',
+               'changes': {},
+               'result': True,
+               'comment': 'myvm is running'}
+        with patch.dict(virt.__salt__, {  # pylint: disable=no-member
+                    'virt.vm_state': MagicMock(return_value='stopped'),
+                    'virt.start': MagicMock(return_value=0),
+                }):
+            ret.update({'changes': {'myvm': 'Domain started'},
+                        'comment': 'Domain myvm started'})
+            self.assertDictEqual(virt.running('myvm'), ret)
+
+        init_mock = MagicMock(return_value=True)
+        with patch.dict(virt.__salt__, {  # pylint: disable=no-member
+                    'virt.vm_state': 
MagicMock(side_effect=CommandExecutionError('not found')),
+                    'virt.init': init_mock,
+                    'virt.start': MagicMock(return_value=0)
+                }):
+            ret.update({'changes': {'myvm': 'Domain defined and started'},
+                        'comment': 'Domain myvm defined and started'})
+            self.assertDictEqual(virt.running('myvm',
+                                              cpu=2,
+                                              mem=2048,
+                                              image='/path/to/img.qcow2'), ret)
+            init_mock.assert_called_with('myvm', cpu=2, mem=2048, 
image='/path/to/img.qcow2',
+                                         os_type=None, arch=None,
+                                         disk=None, disks=None, nic=None, 
interfaces=None,
+                                         graphics=None, hypervisor=None,
+                                         seed=True, install=True, 
pub_key=None, priv_key=None,
+                                         connection=None, username=None, 
password=None)
+
+        with patch.dict(virt.__salt__, {  # pylint: disable=no-member
+                    'virt.vm_state': 
MagicMock(side_effect=CommandExecutionError('not found')),
+                    'virt.init': init_mock,
+                    'virt.start': MagicMock(return_value=0)
+                }):
+            ret.update({'changes': {'myvm': 'Domain defined and started'},
+                        'comment': 'Domain myvm defined and started'})
+            disks = [{
+                        'name': 'system',
+                        'size': 8192,
+                        'overlay_image': True,
+                        'pool': 'default',
+                        'image': '/path/to/image.qcow2'
+                     },
+                     {
+                        'name': 'data',
+                        'size': 16834
+                     }]
+            ifaces = [{
+                         'name': 'eth0',
+                         'mac': '01:23:45:67:89:AB'
+                      },
+                      {
+                         'name': 'eth1',
+                         'type': 'network',
+                         'source': 'admin'
+                      }]
+            graphics = {'type': 'spice', 'listen': {'type': 'address', 
'address': '192.168.0.1'}}
+            self.assertDictEqual(virt.running('myvm',
+                                              cpu=2,
+                                              mem=2048,
+                                              os_type='linux',
+                                              arch='i686',
+                                              vm_type='qemu',
+                                              disk_profile='prod',
+                                              disks=disks,
+                                              nic_profile='prod',
+                                              interfaces=ifaces,
+                                              graphics=graphics,
+                                              seed=False,
+                                              install=False,
+                                              pub_key='/path/to/key.pub',
+                                              priv_key='/path/to/key',
+                                              connection='someconnection',
+                                              username='libvirtuser',
+                                              password='supersecret'), ret)
+            init_mock.assert_called_with('myvm',
+                                         cpu=2,
+                                         mem=2048,
+                                         os_type='linux',
+                                         arch='i686',
+                                         image=None,
+                                         disk='prod',
+                                         disks=disks,
+                                         nic='prod',
+                                         interfaces=ifaces,
+                                         graphics=graphics,
+                                         hypervisor='qemu',
+                                         seed=False,
+                                         install=False,
+                                         pub_key='/path/to/key.pub',
+                                         priv_key='/path/to/key',
+                                         connection='someconnection',
+                                         username='libvirtuser',
+                                         password='supersecret')
+
+        with patch.dict(virt.__salt__, {  # pylint: disable=no-member
+                    'virt.vm_state': MagicMock(return_value='stopped'),
+                    'virt.start': 
MagicMock(side_effect=[self.mock_libvirt.libvirtError('libvirt error msg')])
+                }):
+            ret.update({'changes': {}, 'result': False, 'comment': 'libvirt 
error msg'})
+            self.assertDictEqual(virt.running('myvm'), ret)
+
+        # Working update case when running
+        with patch.dict(virt.__salt__, {  # pylint: disable=no-member
+                    'virt.vm_state': MagicMock(return_value='running'),
+                    'virt.update': MagicMock(return_value={'definition': True, 
'cpu': True})
+                }):
+            ret.update({'changes': {'myvm': {'definition': True, 'cpu': True}},
+                        'result': True,
+                        'comment': 'Domain myvm updated, restart to fully 
apply the changes'})
+            self.assertDictEqual(virt.running('myvm', update=True, cpu=2), ret)
+
+        # Working update case when stopped
+        with patch.dict(virt.__salt__, {  # pylint: disable=no-member
+                    'virt.vm_state': MagicMock(return_value='stopped'),
+                    'virt.start': MagicMock(return_value=0),
+                    'virt.update': MagicMock(return_value={'definition': True})
+                }):
+            ret.update({'changes': {'myvm': 'Domain updated and started'},
+                        'result': True,
+                        'comment': 'Domain myvm updated and started'})
+            self.assertDictEqual(virt.running('myvm', update=True, cpu=2), ret)
+
+        # Failed live update case
+        with patch.dict(virt.__salt__, {  # pylint: disable=no-member
+                    'virt.vm_state': MagicMock(return_value='running'),
+                    'virt.update': MagicMock(return_value={'definition': True, 
'cpu': False, 'errors': ['some error']})
+                }):
+            ret.update({'changes': {'myvm': {'definition': True, 'cpu': False, 
'errors': ['some error']}},
+                        'result': True,
+                        'comment': 'Domain myvm updated, but some live 
update(s) failed'})
+            self.assertDictEqual(virt.running('myvm', update=True, cpu=2), ret)
+
+        # Failed definition update case
+        with patch.dict(virt.__salt__, {  # pylint: disable=no-member
+                    'virt.vm_state': MagicMock(return_value='running'),
+                    'virt.update': 
MagicMock(side_effect=[self.mock_libvirt.libvirtError('error message')])
+                }):
+            ret.update({'changes': {},
+                        'result': False,
+                        'comment': 'error message'})
+            self.assertDictEqual(virt.running('myvm', update=True, cpu=2), ret)
+
+    def test_stopped(self):
+        '''
+        stopped state test cases.
+        '''
+        ret = {'name': 'myvm',
+               'changes': {},
+               'result': True}
+
+        shutdown_mock = MagicMock(return_value=True)
+        with patch.dict(virt.__salt__, {  # pylint: disable=no-member
+                    'virt.list_domains': MagicMock(return_value=['myvm', 
'vm1']),
+                    'virt.shutdown': shutdown_mock
+                }):
+            ret.update({'changes': {
+                            'stopped': [{'domain': 'myvm', 'shutdown': True}]
+                        },
+                        'comment': 'Machine has been shut down'})
+            self.assertDictEqual(virt.stopped('myvm'), ret)
+            shutdown_mock.assert_called_with('myvm', connection=None, 
username=None, password=None)
+
+        with patch.dict(virt.__salt__, {  # pylint: disable=no-member
+                    'virt.list_domains': MagicMock(return_value=['myvm', 
'vm1']),
+                    'virt.shutdown': shutdown_mock,
+                }):
+            self.assertDictEqual(virt.stopped('myvm',
+                                              connection='myconnection',
+                                              username='user',
+                                              password='secret'), ret)
+            shutdown_mock.assert_called_with('myvm', 
connection='myconnection', username='user', password='secret')
+
+        with patch.dict(virt.__salt__, {  # pylint: disable=no-member
+                    'virt.list_domains': MagicMock(return_value=['myvm', 
'vm1']),
+                    'virt.shutdown': 
MagicMock(side_effect=self.mock_libvirt.libvirtError('Some error'))
+                }):
+            ret.update({'changes': {'ignored': [{'domain': 'myvm', 'issue': 
'Some error'}]},
+                        'result': False,
+                        'comment': 'No changes had happened'})
+            self.assertDictEqual(virt.stopped('myvm'), ret)
+
+        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)
+
+    def test_powered_off(self):
+        '''
+        powered_off state test cases.
+        '''
+        ret = {'name': 'myvm',
+               'changes': {},
+               'result': True}
+
+        stop_mock = MagicMock(return_value=True)
+        with patch.dict(virt.__salt__, {  # pylint: disable=no-member
+                    'virt.list_domains': MagicMock(return_value=['myvm', 
'vm1']),
+                    'virt.stop': stop_mock
+                }):
+            ret.update({'changes': {
+                            'unpowered': [{'domain': 'myvm', 'stop': True}]
+                        },
+                        'comment': 'Machine has been powered off'})
+            self.assertDictEqual(virt.powered_off('myvm'), ret)
+            stop_mock.assert_called_with('myvm', connection=None, 
username=None, password=None)
+
+        with patch.dict(virt.__salt__, {  # pylint: disable=no-member
+                    'virt.list_domains': MagicMock(return_value=['myvm', 
'vm1']),
+                    'virt.stop': stop_mock,
+                }):
+            self.assertDictEqual(virt.powered_off('myvm',
+                                                  connection='myconnection',
+                                                  username='user',
+                                                  password='secret'), ret)
+            stop_mock.assert_called_with('myvm', connection='myconnection', 
username='user', password='secret')
+
+        with patch.dict(virt.__salt__, {  # pylint: disable=no-member
+                    'virt.list_domains': MagicMock(return_value=['myvm', 
'vm1']),
+                    'virt.stop': 
MagicMock(side_effect=self.mock_libvirt.libvirtError('Some error'))
+                }):
+            ret.update({'changes': {'ignored': [{'domain': 'myvm', 'issue': 
'Some error'}]},
+                        'result': False,
+                        'comment': 'No changes had happened'})
+            self.assertDictEqual(virt.powered_off('myvm'), ret)
+
+        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)
+
+    def test_snapshot(self):
+        '''
+        snapshot state test cases.
+        '''
+        ret = {'name': 'myvm',
+               'changes': {},
+               'result': True}
+
+        snapshot_mock = MagicMock(return_value=True)
+        with patch.dict(virt.__salt__, {  # pylint: disable=no-member
+                    'virt.list_domains': MagicMock(return_value=['myvm', 
'vm1']),
+                    'virt.snapshot': snapshot_mock
+                }):
+            ret.update({'changes': {
+                            'saved': [{'domain': 'myvm', 'snapshot': True}]
+                        },
+                        'comment': 'Snapshot has been taken'})
+            self.assertDictEqual(virt.snapshot('myvm'), ret)
+            snapshot_mock.assert_called_with('myvm', suffix=None, 
connection=None, username=None, password=None)
+
+        with patch.dict(virt.__salt__, {  # pylint: disable=no-member
+                    'virt.list_domains': MagicMock(return_value=['myvm', 
'vm1']),
+                    'virt.snapshot': snapshot_mock,
+                }):
+            self.assertDictEqual(virt.snapshot('myvm',
+                                               suffix='snap',
+                                               connection='myconnection',
+                                               username='user',
+                                               password='secret'), ret)
+            snapshot_mock.assert_called_with('myvm',
+                                             suffix='snap',
+                                             connection='myconnection',
+                                             username='user',
+                                             password='secret')
+
+        with patch.dict(virt.__salt__, {  # pylint: disable=no-member
+                    'virt.list_domains': MagicMock(return_value=['myvm', 
'vm1']),
+                    'virt.snapshot': 
MagicMock(side_effect=self.mock_libvirt.libvirtError('Some error'))
+                }):
+            ret.update({'changes': {'ignored': [{'domain': 'myvm', 'issue': 
'Some error'}]},
+                        'result': False,
+                        'comment': 'No changes had happened'})
+            self.assertDictEqual(virt.snapshot('myvm'), ret)
+
+        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.snapshot('myvm'), ret)
+
+    def test_rebooted(self):
+        '''
+        rebooted state test cases.
+        '''
+        ret = {'name': 'myvm',
+               'changes': {},
+               'result': True}
+
+        reboot_mock = MagicMock(return_value=True)
+        with patch.dict(virt.__salt__, {  # pylint: disable=no-member
+                    'virt.list_domains': MagicMock(return_value=['myvm', 
'vm1']),
+                    'virt.reboot': reboot_mock
+                }):
+            ret.update({'changes': {
+                            'rebooted': [{'domain': 'myvm', 'reboot': True}]
+                        },
+                        'comment': 'Machine has been rebooted'})
+            self.assertDictEqual(virt.rebooted('myvm'), ret)
+            reboot_mock.assert_called_with('myvm', connection=None, 
username=None, password=None)
+
+        with patch.dict(virt.__salt__, {  # pylint: disable=no-member
+                    'virt.list_domains': MagicMock(return_value=['myvm', 
'vm1']),
+                    'virt.reboot': reboot_mock,
+                }):
+            self.assertDictEqual(virt.rebooted('myvm',
+                                               connection='myconnection',
+                                               username='user',
+                                               password='secret'), ret)
+            reboot_mock.assert_called_with('myvm',
+                                           connection='myconnection',
+                                           username='user',
+                                           password='secret')
+
+        with patch.dict(virt.__salt__, {  # pylint: disable=no-member
+                    'virt.list_domains': MagicMock(return_value=['myvm', 
'vm1']),
+                    'virt.reboot': 
MagicMock(side_effect=self.mock_libvirt.libvirtError('Some error'))
+                }):
+            ret.update({'changes': {'ignored': [{'domain': 'myvm', 'issue': 
'Some error'}]},
+                        'result': False,
+                        'comment': 'No changes had happened'})
+            self.assertDictEqual(virt.rebooted('myvm'), ret)
+
+        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.rebooted('myvm'), ret)
+
+    def test_network_running(self):
+        '''
+        network_running state test cases.
+        '''
+        ret = {'name': 'mynet', 'changes': {}, 'result': True, 'comment': ''}
+        define_mock = MagicMock(return_value=True)
+        with patch.dict(virt.__salt__, {  # pylint: disable=no-member
+                    'virt.network_info': MagicMock(return_value={}),
+                    'virt.network_define': define_mock
+                }):
+            ret.update({'changes': {'mynet': 'Network defined and started'},
+                        'comment': 'Network mynet defined and started'})
+            self.assertDictEqual(virt.network_running('mynet',
+                                                      'br2',
+                                                      'bridge',
+                                                      vport='openvswitch',
+                                                      tag=180,
+                                                      autostart=False,
+                                                      
connection='myconnection',
+                                                      username='user',
+                                                      password='secret'), ret)
+            define_mock.assert_called_with('mynet',
+                                           'br2',
+                                           'bridge',
+                                           'openvswitch',
+                                           tag=180,
+                                           autostart=False,
+                                           start=True,
+                                           connection='myconnection',
+                                           username='user',
+                                           password='secret')
+
+        with patch.dict(virt.__salt__, {  # pylint: disable=no-member
+                    'virt.network_info': MagicMock(return_value={'active': 
True}),
+                    'virt.network_define': define_mock,
+                }):
+            ret.update({'changes': {}, 'comment': 'Network mynet exists and is 
running'})
+            self.assertDictEqual(virt.network_running('mynet', 'br2', 
'bridge'), ret)
+
+        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_start': start_mock,
+                    'virt.network_define': define_mock,
+                }):
+            ret.update({'changes': {'mynet': 'Network started'}, 'comment': 
'Network mynet started'})
+            self.assertDictEqual(virt.network_running('mynet',
+                                                      'br2',
+                                                      'bridge',
+                                                      
connection='myconnection',
+                                                      username='user',
+                                                      password='secret'), ret)
+            start_mock.assert_called_with('mynet', connection='myconnection', 
username='user', password='secret')
+
+        with patch.dict(virt.__salt__, {  # pylint: disable=no-member
+                    'virt.network_info': MagicMock(return_value={}),
+                    'virt.network_define': 
MagicMock(side_effect=self.mock_libvirt.libvirtError('Some error'))
+                }):
+            ret.update({'changes': {}, 'comment': 'Some error', 'result': 
False})
+            self.assertDictEqual(virt.network_running('mynet', 'br2', 
'bridge'), ret)
+
+    def test_pool_running(self):
+        '''
+        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',
+                                                   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_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',
+                                                  connection='myconnection',
+                                                  username='user',
+                                                  password='secret')
+            mocks['build'].assert_called_with('mypool',
+                                              connection='myconnection',
+                                              username='user',
+                                              password='secret')
+            mocks['start'].assert_not_called()
+
+        with patch.dict(virt.__salt__, {  # pylint: disable=no-member
+                    'virt.pool_info': MagicMock(return_value={'state': 
'running'}),
+                }):
+            ret.update({'changes': {}, 'comment': 'Pool mypool exists 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={'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',
+                                                   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)
-- 
2.21.0


++++++ virt.volume_infos-fix-for-single-vm.patch ++++++
>From b0b5a78a463f7587be4f81074b182d1f4b4461be Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?C=C3=A9dric=20Bosdonnat?= <cbosdon...@suse.com>
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 17039444c4..a3f625909d 100644
--- a/salt/modules/virt.py
+++ b/salt/modules/virt.py
@@ -5047,10 +5047,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 14e51e1e2a..bbe8d813d7 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.21.0



Reply via email to