osc copypac from project:systemsmanagement:saltstack:testing package:salt revision:318
OBS-URL: https://build.opensuse.org/package/show/systemsmanagement:saltstack/salt?expand=0&rev=159
This commit is contained in:
parent
4ead0d0098
commit
ddaff062ff
@ -1 +1 @@
|
||||
119d230d13c22207b56ca0276f65a25692e8f4bf
|
||||
d3f65020201314619013243463c3fe8098529e3e
|
123
add-virt.network_get_xml-function.patch
Normal file
123
add-virt.network_get_xml-function.patch
Normal file
@ -0,0 +1,123 @@
|
||||
From a5072a8e834127c9633c1af78631dcef6db0e6cb Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?C=C3=A9dric=20Bosdonnat?= <cbosdonnat@suse.com>
|
||||
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 = '<net>Raw XML</net>'
|
||||
+ self.mock_conn.networkLookupByName.return_value = network_mock
|
||||
+
|
||||
+ self.assertEqual('<net>Raw XML</net>', 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 = '<pool>Raw XML</pool>'
|
||||
+ self.mock_conn.storagePoolLookupByName.return_value = pool_mock
|
||||
+
|
||||
+ self.assertEqual('<pool>Raw XML</pool>', virt.pool_get_xml('default'))
|
||||
+
|
||||
def test_pool_list_volumes(self):
|
||||
'''
|
||||
Test virt.pool_list_volumes
|
||||
--
|
||||
2.16.4
|
||||
|
||||
|
217
fix-virt-states-to-not-fail-on-vms-already-stopped.-.patch
Normal file
217
fix-virt-states-to-not-fail-on-vms-already-stopped.-.patch
Normal file
@ -0,0 +1,217 @@
|
||||
From 46aeb732ed61051d436ac748bd95a50c6379682a Mon Sep 17 00:00:00 2001
|
||||
From: Cedric Bosdonnat <cbosdonnat@suse.com>
|
||||
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
|
||||
|
||||
|
162
list_downloaded-for-apt-module.patch
Normal file
162
list_downloaded-for-apt-module.patch
Normal file
@ -0,0 +1,162 @@
|
||||
From a1e0904a640d01d4bab0871db1ab8ea653335443 Mon Sep 17 00:00:00 2001
|
||||
From: Jochen Breuer <jbreuer@suse.de>
|
||||
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 <salt.modules.yumpkg>` and :mod:`zypper <salt.modules.zypper>`
|
||||
+ :mod:`yumpkg <salt.modules.yumpkg>`, :mod:`zypper <salt.modules.zypper>` and :mod:`zypper <salt.modules.aptpkg>`
|
||||
|
||||
: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
|
||||
|
||||
|
40
salt.changes
40
salt.changes
@ -1,3 +1,43 @@
|
||||
-------------------------------------------------------------------
|
||||
Mon Jan 13 16:09:36 UTC 2020 - Jochen Breuer <jbreuer@suse.de>
|
||||
|
||||
- Support for Btrfs and XFS in parted and mkfs added
|
||||
|
||||
- Added:
|
||||
* support-for-btrfs-and-xfs-in-parted-and-mkfs.patch
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Thu Jan 9 19:20:34 UTC 2020 - Jochen Breuer <jbreuer@suse.de>
|
||||
|
||||
- Adds list_downloaded for apt Module to enable pre-downloading support
|
||||
- Adds virt.(pool|network)_get_xml functions
|
||||
- Various libvirt updates
|
||||
* Add virt.pool_capabilities function
|
||||
* virt.pool_running improvements
|
||||
* Add virt.pool_deleted state
|
||||
* virt.network_define allow adding IP configuration
|
||||
|
||||
- Added:
|
||||
* virt.network_define-allow-adding-ip-configuration.patch
|
||||
* list_downloaded-for-apt-module.patch
|
||||
* add-virt.network_get_xml-function.patch
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Tue Jan 7 10:28:04 UTC 2020 - Pablo Suárez Hernández <pablo.suarezhernandez@suse.com>
|
||||
|
||||
- virt: adding kernel boot parameters to libvirt xml
|
||||
|
||||
- Added:
|
||||
* virt-adding-kernel-boot-parameters-to-libvirt-xml-55.patch
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Mon Dec 16 10:36:42 UTC 2019 - Pablo Suárez Hernández <pablo.suarezhernandez@suse.com>
|
||||
|
||||
- Fix virt states to not fail on VMs already stopped
|
||||
|
||||
- Added:
|
||||
* fix-virt-states-to-not-fail-on-vms-already-stopped.-.patch
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Thu Dec 12 10:21:15 UTC 2019 - Pablo Suárez Hernández <pablo.suarezhernandez@suse.com>
|
||||
|
||||
|
22
salt.spec
22
salt.spec
@ -272,6 +272,22 @@ Patch96: align-virt-full-info-fixes-with-upstream-192.patch
|
||||
Patch97: fix-virt.get_hypervisor-188.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
|
||||
# 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
|
||||
# PATCH_FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/200
|
||||
Patch104: support-for-btrfs-and-xfs-in-parted-and-mkfs.patch
|
||||
|
||||
BuildRoot: %{_tmppath}/%{name}-%{version}-build
|
||||
BuildRequires: logrotate
|
||||
@ -886,6 +902,12 @@ cp %{S:5} ./.travis.yml
|
||||
%patch96 -p1
|
||||
%patch97 -p1
|
||||
%patch98 -p1
|
||||
%patch99 -p1
|
||||
%patch100 -p1
|
||||
%patch101 -p1
|
||||
%patch102 -p1
|
||||
%patch103 -p1
|
||||
%patch104 -p1
|
||||
|
||||
%build
|
||||
%if 0%{?build_py2}
|
||||
|
56
support-for-btrfs-and-xfs-in-parted-and-mkfs.patch
Normal file
56
support-for-btrfs-and-xfs-in-parted-and-mkfs.patch
Normal file
@ -0,0 +1,56 @@
|
||||
From 92df25d10789e5d0686a882a1cbadbfc0602b2f5 Mon Sep 17 00:00:00 2001
|
||||
From: Jochen Breuer <jbreuer@suse.de>
|
||||
Date: Fri, 10 Jan 2020 17:18:14 +0100
|
||||
Subject: [PATCH] Support for Btrfs and XFS in parted and mkfs
|
||||
|
||||
---
|
||||
salt/modules/parted_partition.py | 4 ++--
|
||||
tests/unit/modules/test_parted_partition.py | 16 ++++++++++++++++
|
||||
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
|
||||
--- a/salt/modules/parted_partition.py
|
||||
+++ b/salt/modules/parted_partition.py
|
||||
@@ -390,8 +390,8 @@ def _is_fstype(fs_type):
|
||||
:param fs_type: file system type
|
||||
:return: True if fs_type is supported in this module, False otherwise
|
||||
'''
|
||||
- return fs_type in set(['ext2', 'ext3', 'ext4', 'fat32', 'fat16', 'linux-swap', 'reiserfs',
|
||||
- 'hfs', 'hfs+', 'hfsx', 'NTFS', 'ntfs', 'ufs'])
|
||||
+ return fs_type in set(['btrfs', 'ext2', 'ext3', 'ext4', 'fat32', 'fat16', 'linux-swap', 'reiserfs',
|
||||
+ 'hfs', 'hfs+', 'hfsx', 'NTFS', 'ntfs', 'ufs', 'xfs'])
|
||||
|
||||
|
||||
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
|
||||
--- a/tests/unit/modules/test_parted_partition.py
|
||||
+++ b/tests/unit/modules/test_parted_partition.py
|
||||
@@ -377,6 +377,22 @@ class PartedTestCase(TestCase, LoaderModuleMockMixin):
|
||||
}
|
||||
self.assertEqual(output, expected)
|
||||
|
||||
+ def test_btrfs_fstypes(self):
|
||||
+ '''Tests if we see btrfs as valid fs type'''
|
||||
+ with patch('salt.modules.parted_partition._validate_device', MagicMock()):
|
||||
+ try:
|
||||
+ parted.mkfs('/dev/foo', 'btrfs')
|
||||
+ except CommandExecutionError:
|
||||
+ self.fail("Btrfs is not in the supported fstypes")
|
||||
+
|
||||
+ def test_xfs_fstypes(self):
|
||||
+ '''Tests if we see xfs as valid fs type'''
|
||||
+ with patch('salt.modules.parted_partition._validate_device', MagicMock()):
|
||||
+ try:
|
||||
+ parted.mkfs('/dev/foo', 'xfs')
|
||||
+ except CommandExecutionError:
|
||||
+ self.fail("XFS is not in the supported fstypes")
|
||||
+
|
||||
def test_disk_set(self):
|
||||
with patch('salt.modules.parted_partition._validate_device', MagicMock()):
|
||||
self.cmdrun.return_value = ''
|
||||
--
|
||||
2.16.4
|
||||
|
||||
|
583
virt-adding-kernel-boot-parameters-to-libvirt-xml-55.patch
Normal file
583
virt-adding-kernel-boot-parameters-to-libvirt-xml-55.patch
Normal file
@ -0,0 +1,583 @@
|
||||
From 26a227868bcf1f790348e197e000561903f7fc72 Mon Sep 17 00:00:00 2001
|
||||
From: Larry Dewey <ldewey@suse.com>
|
||||
Date: Tue, 7 Jan 2020 02:48:11 -0700
|
||||
Subject: [PATCH] virt: adding kernel boot parameters to libvirt xml
|
||||
#55245 (#197)
|
||||
|
||||
* virt: adding kernel boot parameters to libvirt xml
|
||||
|
||||
SUSE's autoyast and Red Hat's kickstart take advantage of kernel paths,
|
||||
initrd paths, and kernel boot command line parameters. These changes
|
||||
provide the option of using these, and will allow salt and
|
||||
autoyast/kickstart to work together.
|
||||
|
||||
Signed-off-by: Larry Dewey <ldewey@suse.com>
|
||||
|
||||
* virt: Download linux and initrd
|
||||
|
||||
Signed-off-by: Larry Dewey <ldewey@suse.com>
|
||||
---
|
||||
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(-)
|
||||
|
||||
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
|
||||
--- 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.
|
||||
|
||||
@@ -349,6 +350,23 @@ def running(name,
|
||||
|
||||
.. versionadded:: Neon
|
||||
|
||||
+ :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
|
||||
+
|
||||
.. 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 @@
|
||||
<currentMemory unit='KiB'>{{ mem }}</currentMemory>
|
||||
<os>
|
||||
<type arch='{{ arch }}'>{{ os_type }}</type>
|
||||
- {% if kernel %}<kernel>{{ kernel }}</kernel>{% endif %}
|
||||
+ {% if boot %}
|
||||
+ {% if 'kernel' in boot %}
|
||||
+ <kernel>{{ boot.kernel }}</kernel>
|
||||
+ {% endif %}
|
||||
+ {% if 'initrd' in boot %}
|
||||
+ <initrd>{{ boot.initrd }}</initrd>
|
||||
+ {% endif %}
|
||||
+ {% if 'cmdline' in boot %}
|
||||
+ <cmdline>{{ boot.cmdline }}</cmdline>
|
||||
+ {% endif %}
|
||||
+ {% endif %}
|
||||
{% for dev in boot_dev %}
|
||||
<boot dev='{{ 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('<interface' in definition)
|
||||
self.assertFalse('<disk' in definition)
|
||||
|
||||
+ # Ensure the init() function allows creating VM without NIC and
|
||||
+ # disk but with boot parameters.
|
||||
+
|
||||
+ defineMock.reset_mock()
|
||||
+ mock_run.reset_mock()
|
||||
+ boot = {
|
||||
+ 'kernel': '/root/f8-i386-vmlinuz',
|
||||
+ 'initrd': '/root/f8-i386-initrd',
|
||||
+ 'cmdline':
|
||||
+ 'console=ttyS0 ks=http://example.com/f8-i386/os/'
|
||||
+ }
|
||||
+ retval = virt.init('test vm boot params',
|
||||
+ 2,
|
||||
+ 1234,
|
||||
+ nic=None,
|
||||
+ disk=None,
|
||||
+ seed=False,
|
||||
+ start=False,
|
||||
+ boot=boot)
|
||||
+ definition = defineMock.call_args_list[0][0][0]
|
||||
+ self.assertEqual('<kernel' in definition, True)
|
||||
+ self.assertEqual('<initrd' in definition, True)
|
||||
+ self.assertEqual('<cmdline' in definition, True)
|
||||
+ self.assertEqual(retval, True)
|
||||
+
|
||||
+ # Verify that remote paths are downloaded and the xml has been
|
||||
+ # modified
|
||||
+ mock_response = MagicMock()
|
||||
+ mock_response.read = MagicMock(return_value='filecontent')
|
||||
+ cache_dir = tempfile.mkdtemp()
|
||||
+
|
||||
+ with patch.dict(virt.__dict__, {'CACHE_DIR': cache_dir}):
|
||||
+ with patch('salt.ext.six.moves.urllib.request.urlopen',
|
||||
+ MagicMock(return_value=mock_response)):
|
||||
+ with patch('salt.utils.files.fopen',
|
||||
+ return_value=mock_response):
|
||||
+
|
||||
+ defineMock.reset_mock()
|
||||
+ mock_run.reset_mock()
|
||||
+ boot = {
|
||||
+ 'kernel':
|
||||
+ 'https://www.example.com/download/vmlinuz',
|
||||
+ 'initrd': '',
|
||||
+ 'cmdline':
|
||||
+ 'console=ttyS0 '
|
||||
+ 'ks=http://example.com/f8-i386/os/'
|
||||
+ }
|
||||
+
|
||||
+ retval = virt.init('test remote vm boot params',
|
||||
+ 2,
|
||||
+ 1234,
|
||||
+ nic=None,
|
||||
+ disk=None,
|
||||
+ seed=False,
|
||||
+ start=False,
|
||||
+ boot=boot)
|
||||
+ definition = defineMock.call_args_list[0][0][0]
|
||||
+ self.assertEqual(cache_dir in definition, True)
|
||||
+
|
||||
+ shutil.rmtree(cache_dir)
|
||||
+
|
||||
# Test case creating disks
|
||||
defineMock.reset_mock()
|
||||
mock_run.reset_mock()
|
||||
@@ -1222,6 +1285,20 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
|
||||
self.assertEqual(setxml.find('vcpu').text, '2')
|
||||
self.assertEqual(setvcpus_mock.call_args[0][0], 2)
|
||||
|
||||
+ boot = {
|
||||
+ 'kernel': '/root/f8-i386-vmlinuz',
|
||||
+ 'initrd': '/root/f8-i386-initrd',
|
||||
+ 'cmdline':
|
||||
+ 'console=ttyS0 ks=http://example.com/f8-i386/os/'
|
||||
+ }
|
||||
+
|
||||
+ # Update with boot parameter case
|
||||
+ self.assertEqual({
|
||||
+ 'definition': True,
|
||||
+ 'disk': {'attached': [], 'detached': []},
|
||||
+ 'interface': {'attached': [], 'detached': []}
|
||||
+ }, virt.update('my vm', boot=boot))
|
||||
+
|
||||
# Update memory case
|
||||
setmem_mock = MagicMock(return_value=0)
|
||||
domain_mock.setMemoryFlags = setmem_mock
|
||||
diff --git a/tests/unit/states/test_virt.py b/tests/unit/states/test_virt.py
|
||||
index 2af5caca1b..109faf5fba 100644
|
||||
--- a/tests/unit/states/test_virt.py
|
||||
+++ b/tests/unit/states/test_virt.py
|
||||
@@ -249,7 +249,7 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin):
|
||||
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,
|
||||
+ os_type=None, arch=None, boot=None,
|
||||
disk=None, disks=None, nic=None, interfaces=None,
|
||||
graphics=None, hypervisor=None,
|
||||
seed=True, install=True, pub_key=None, priv_key=None,
|
||||
@@ -314,6 +314,7 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin):
|
||||
graphics=graphics,
|
||||
hypervisor='qemu',
|
||||
seed=False,
|
||||
+ boot=None,
|
||||
install=False,
|
||||
pub_key='/path/to/key.pub',
|
||||
priv_key='/path/to/key',
|
||||
@@ -338,6 +339,22 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin):
|
||||
'comment': 'Domain myvm updated, restart to fully apply the changes'})
|
||||
self.assertDictEqual(virt.running('myvm', update=True, cpu=2), ret)
|
||||
|
||||
+ # Working update case when running with boot params
|
||||
+ boot = {
|
||||
+ 'kernel': '/root/f8-i386-vmlinuz',
|
||||
+ 'initrd': '/root/f8-i386-initrd',
|
||||
+ 'cmdline': 'console=ttyS0 ks=http://example.com/f8-i386/os/'
|
||||
+ }
|
||||
+
|
||||
+ with patch.dict(virt.__salt__, { # pylint: disable=no-member
|
||||
+ '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}},
|
||||
+ 'result': True,
|
||||
+ 'comment': 'Domain myvm updated, restart to fully apply the changes'})
|
||||
+ self.assertDictEqual(virt.running('myvm', update=True, boot=boot), ret)
|
||||
+
|
||||
# Working update case when stopped
|
||||
with patch.dict(virt.__salt__, { # pylint: disable=no-member
|
||||
'virt.vm_state': MagicMock(return_value={'myvm': 'stopped'}),
|
||||
--
|
||||
2.23.0
|
||||
|
||||
|
2074
virt.network_define-allow-adding-ip-configuration.patch
Normal file
2074
virt.network_define-allow-adding-ip-configuration.patch
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user