Accepting request 887060 from systemsmanagement:saltstack
- Improvements on "ansiblegate" module: * New methods: ansible.targets / ansible.discover_playbooks * General bugfixes - Added: * improvements-on-ansiblegate-module-354.patch - Regression fix of salt-ssh on processing some targets - Added: * regression-fix-of-salt-ssh-on-processing-targets-353.patch - Add support for Alibaba Cloud Linux 2 (Aliyun Linux) - Added: * add-alibaba-cloud-linux-2-by-backporting-upstream-s-.patch - Update target fix for salt-ssh to process targets list (bsc#1179831) - Added: * update-target-fix-for-salt-ssh-to-process-targets-li.patch - Add notify beacon for Debian/Ubuntu systems - Add core grains support for AlmaLinux and Alibaba Could Linux - Added: * add-almalinux-and-alibaba-cloud-linux-to-the-os-fami.patch * notify-beacon-for-debian-ubuntu-systems-347.patch - Allow vendor change option with zypper - Added: * allow-vendor-change-option-with-zypper-313.patch OBS-URL: https://build.opensuse.org/request/show/887060 OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/salt?expand=0&rev=117
This commit is contained in:
commit
4a1d19e432
@ -1 +1 @@
|
||||
68bd2c45e40cf64ac426a7e5833daa076ab10cfe
|
||||
a94708ad2eba9aa15413d989ab3361b2c980589e
|
76
add-alibaba-cloud-linux-2-by-backporting-upstream-s-.patch
Normal file
76
add-alibaba-cloud-linux-2-by-backporting-upstream-s-.patch
Normal file
@ -0,0 +1,76 @@
|
||||
From ec0d11ed66e8541a9ccaebc85aab4724013fb71f Mon Sep 17 00:00:00 2001
|
||||
From: Pau Garcia Quiles <pau.garcia@suse.com>
|
||||
Date: Tue, 13 Apr 2021 10:31:09 +0200
|
||||
Subject: [PATCH] Add Alibaba Cloud Linux 2 by backporting upstream's
|
||||
grain and discarding my own (#352)
|
||||
|
||||
---
|
||||
salt/grains/core.py | 4 ++--
|
||||
tests/unit/grains/test_core.py | 26 +++++++++++++++++---------
|
||||
2 files changed, 19 insertions(+), 11 deletions(-)
|
||||
|
||||
diff --git a/salt/grains/core.py b/salt/grains/core.py
|
||||
index 09f9d29788..2b965a2a8a 100644
|
||||
--- a/salt/grains/core.py
|
||||
+++ b/salt/grains/core.py
|
||||
@@ -1547,7 +1547,7 @@ _OS_NAME_MAP = {
|
||||
"slesexpand": "RES",
|
||||
"linuxmint": "Mint",
|
||||
"neon": "KDE neon",
|
||||
- "alibaba": "Alibaba Cloud (Aliyun)",
|
||||
+ "alibabaclo": "Alinux",
|
||||
}
|
||||
|
||||
# Map the 'os' grain to the 'os_family' grain
|
||||
@@ -1622,7 +1622,7 @@ _OS_FAMILY_MAP = {
|
||||
"AIX": "AIX",
|
||||
"TurnKey": "Debian",
|
||||
"AstraLinuxCE": "Debian",
|
||||
- "Alibaba Cloud (Aliyun)": "RedHat",
|
||||
+ "Alinux": "RedHat",
|
||||
}
|
||||
|
||||
# Matches any possible format:
|
||||
diff --git a/tests/unit/grains/test_core.py b/tests/unit/grains/test_core.py
|
||||
index 6aa05abe40..8280d6de47 100644
|
||||
--- a/tests/unit/grains/test_core.py
|
||||
+++ b/tests/unit/grains/test_core.py
|
||||
@@ -782,17 +782,25 @@ class CoreGrainsTestCase(TestCase, LoaderModuleMockMixin):
|
||||
Test if OS grains are parsed correctly in Alibaba Cloud Linux (Aliyun Linux) 2.1903 LTS
|
||||
'''
|
||||
_os_release_map = {
|
||||
- '_linux_distribution': ('Alibaba Cloud Linux (Aliyun Linux)', '2.1903', 'Alibaba Cloud Linux (Aliyun Linux) 2.1903 LTS (Hunting Beagle)'),
|
||||
+ "os_release_file": {
|
||||
+ "NAME": "Alibaba Cloud Linux (Aliyun Linux)",
|
||||
+ "VERSION": "2.1903 LTS (Hunting Beagle)",
|
||||
+ "VERSION_ID": "2.1903",
|
||||
+ "PRETTY_NAME": "Alibaba Cloud Linux (Aliyun Linux) 2.1903 LTS (Hunting Beagle)",
|
||||
+ "ID": "alinux",
|
||||
+ "ANSI_COLOR": "0;31",
|
||||
+ },
|
||||
+ "_linux_distribution": ("alinux", "2.1903", "LTS"),
|
||||
}
|
||||
expectation = {
|
||||
- 'os': 'Alibaba Cloud (Aliyun)',
|
||||
- 'os_family': 'RedHat',
|
||||
- 'oscodename': 'Alibaba Cloud Linux (Aliyun Linux) 2.1903 LTS (Hunting Beagle)',
|
||||
- 'osfullname': 'Alibaba Cloud Linux (Aliyun Linux)',
|
||||
- 'osrelease': '2.1903',
|
||||
- 'osrelease_info': (2, 1903),
|
||||
- 'osmajorrelease': 2,
|
||||
- 'osfinger': 'Alibaba Cloud Linux (Aliyun Linux)-2',
|
||||
+ "os": "Alinux",
|
||||
+ "os_family": "RedHat",
|
||||
+ "oscodename": "Alibaba Cloud Linux (Aliyun Linux) 2.1903 LTS (Hunting Beagle)",
|
||||
+ "osfullname": "Alibaba Cloud Linux (Aliyun Linux)",
|
||||
+ "osrelease": "2.1903",
|
||||
+ "osrelease_info": (2, 1903),
|
||||
+ "osmajorrelease": 2,
|
||||
+ "osfinger": "Alibaba Cloud Linux (Aliyun Linux)-2",
|
||||
}
|
||||
self._run_os_grains_tests(None, _os_release_map, expectation)
|
||||
|
||||
--
|
||||
2.30.2
|
||||
|
||||
|
131
add-almalinux-and-alibaba-cloud-linux-to-the-os-fami.patch
Normal file
131
add-almalinux-and-alibaba-cloud-linux-to-the-os-fami.patch
Normal file
@ -0,0 +1,131 @@
|
||||
From beec6f3945bda722bfe9c0aa606065f04c89bc62 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Julio=20Gonz=C3=A1lez=20Gil?=
|
||||
<juliogonzalez@users.noreply.github.com>
|
||||
Date: Wed, 24 Mar 2021 14:12:34 +0100
|
||||
Subject: [PATCH] Add AlmaLinux and Alibaba Cloud Linux to the OS
|
||||
Family list (#341)
|
||||
|
||||
* Add AlmaLinux and Alibaba Cloud Linux to the OS Family list
|
||||
|
||||
* Fix some grains tests
|
||||
---
|
||||
salt/grains/core.py | 4 +++
|
||||
tests/unit/grains/test_core.py | 51 +++++++++++++++++++++++++++++++++-
|
||||
2 files changed, 54 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/salt/grains/core.py b/salt/grains/core.py
|
||||
index 5634327623..09f9d29788 100644
|
||||
--- a/salt/grains/core.py
|
||||
+++ b/salt/grains/core.py
|
||||
@@ -1532,6 +1532,7 @@ _OS_NAME_MAP = {
|
||||
"oracleserv": "OEL",
|
||||
"cloudserve": "CloudLinux",
|
||||
"cloudlinux": "CloudLinux",
|
||||
+ "almalinux": "AlmaLinux",
|
||||
"pidora": "Fedora",
|
||||
"scientific": "ScientificLinux",
|
||||
"synology": "Synology",
|
||||
@@ -1546,6 +1547,7 @@ _OS_NAME_MAP = {
|
||||
"slesexpand": "RES",
|
||||
"linuxmint": "Mint",
|
||||
"neon": "KDE neon",
|
||||
+ "alibaba": "Alibaba Cloud (Aliyun)",
|
||||
}
|
||||
|
||||
# Map the 'os' grain to the 'os_family' grain
|
||||
@@ -1563,6 +1565,7 @@ _OS_FAMILY_MAP = {
|
||||
"Scientific": "RedHat",
|
||||
"Amazon": "RedHat",
|
||||
"CloudLinux": "RedHat",
|
||||
+ "AlmaLinux": "RedHat",
|
||||
"OVS": "RedHat",
|
||||
"OEL": "RedHat",
|
||||
"XCP": "RedHat",
|
||||
@@ -1619,6 +1622,7 @@ _OS_FAMILY_MAP = {
|
||||
"AIX": "AIX",
|
||||
"TurnKey": "Debian",
|
||||
"AstraLinuxCE": "Debian",
|
||||
+ "Alibaba Cloud (Aliyun)": "RedHat",
|
||||
}
|
||||
|
||||
# Matches any possible format:
|
||||
diff --git a/tests/unit/grains/test_core.py b/tests/unit/grains/test_core.py
|
||||
index 15de4e363e..6aa05abe40 100644
|
||||
--- a/tests/unit/grains/test_core.py
|
||||
+++ b/tests/unit/grains/test_core.py
|
||||
@@ -678,6 +678,35 @@ class CoreGrainsTestCase(TestCase, LoaderModuleMockMixin):
|
||||
}
|
||||
self._run_os_grains_tests(None, _os_release_map, expectation)
|
||||
|
||||
+ @skipIf(not salt.utils.platform.is_linux(), "System is not Linux")
|
||||
+ def test_almalinux_8_os_grains(self):
|
||||
+ """
|
||||
+ Test if OS grains are parsed correctly in AlmaLinux 8
|
||||
+ """
|
||||
+ _os_release_map = {
|
||||
+ "os_release_file": {
|
||||
+ "NAME": "AlmaLinux",
|
||||
+ "VERSION_ID": "8.3",
|
||||
+ "PRETTY_NAME": "AlmaLinux 8",
|
||||
+ "ID": "almalinux",
|
||||
+ "ANSI_COLOR": "0;31",
|
||||
+ "CPE_NAME": "cpe:/o:almalinux:almalinux:8.3",
|
||||
+ },
|
||||
+ "_linux_distribution": ("almaLinux", "8.3", ""),
|
||||
+ }
|
||||
+
|
||||
+ expectation = {
|
||||
+ "os": "AlmaLinux",
|
||||
+ "os_family": "RedHat",
|
||||
+ "oscodename": "AlmaLinux 8",
|
||||
+ "osfullname": "AlmaLinux",
|
||||
+ "osrelease": "8.3",
|
||||
+ "osrelease_info": (8, 3,),
|
||||
+ "osmajorrelease": 8,
|
||||
+ "osfinger": "AlmaLinux-8",
|
||||
+ }
|
||||
+ self._run_os_grains_tests(None, _os_release_map, expectation)
|
||||
+
|
||||
def test_unicode_error(self):
|
||||
raise_unicode_mock = MagicMock(
|
||||
name="raise_unicode_error", side_effect=UnicodeError
|
||||
@@ -733,7 +762,7 @@ class CoreGrainsTestCase(TestCase, LoaderModuleMockMixin):
|
||||
Test if OS grains are parsed correctly in Astra Linux CE 2.12.22 "orel"
|
||||
"""
|
||||
_os_release_map = {
|
||||
- "linux_distribution": ("AstraLinuxCE", "2.12.22", "orel"),
|
||||
+ "_linux_distribution": ("AstraLinuxCE", "2.12.22", "orel"),
|
||||
}
|
||||
expectation = {
|
||||
"os": "AstraLinuxCE",
|
||||
@@ -747,6 +776,26 @@ class CoreGrainsTestCase(TestCase, LoaderModuleMockMixin):
|
||||
}
|
||||
self._run_os_grains_tests("astralinuxce-2.12.22", _os_release_map, expectation)
|
||||
|
||||
+ @skipIf(not salt.utils.platform.is_linux(), 'System is not Linux')
|
||||
+ def test_aliyunlinux2_os_grains(self):
|
||||
+ '''
|
||||
+ Test if OS grains are parsed correctly in Alibaba Cloud Linux (Aliyun Linux) 2.1903 LTS
|
||||
+ '''
|
||||
+ _os_release_map = {
|
||||
+ '_linux_distribution': ('Alibaba Cloud Linux (Aliyun Linux)', '2.1903', 'Alibaba Cloud Linux (Aliyun Linux) 2.1903 LTS (Hunting Beagle)'),
|
||||
+ }
|
||||
+ expectation = {
|
||||
+ 'os': 'Alibaba Cloud (Aliyun)',
|
||||
+ 'os_family': 'RedHat',
|
||||
+ 'oscodename': 'Alibaba Cloud Linux (Aliyun Linux) 2.1903 LTS (Hunting Beagle)',
|
||||
+ 'osfullname': 'Alibaba Cloud Linux (Aliyun Linux)',
|
||||
+ 'osrelease': '2.1903',
|
||||
+ 'osrelease_info': (2, 1903),
|
||||
+ 'osmajorrelease': 2,
|
||||
+ 'osfinger': 'Alibaba Cloud Linux (Aliyun Linux)-2',
|
||||
+ }
|
||||
+ self._run_os_grains_tests(None, _os_release_map, expectation)
|
||||
+
|
||||
@skipIf(not salt.utils.platform.is_windows(), "System is not Windows")
|
||||
def test_windows_platform_data(self):
|
||||
"""
|
||||
--
|
||||
2.30.2
|
||||
|
||||
|
292
allow-vendor-change-option-with-zypper-313.patch
Normal file
292
allow-vendor-change-option-with-zypper-313.patch
Normal file
@ -0,0 +1,292 @@
|
||||
From 33ad6876a04e800afc08748133dc568a5e362903 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Seidl <mseidl@suse.de>
|
||||
Date: Wed, 17 Mar 2021 14:05:42 +0100
|
||||
Subject: [PATCH] Allow vendor change option with zypper (#313)
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
* add patch support for allow vendor change option with zypper
|
||||
|
||||
* adjust unit tests vendor change refactor, dropping cli arg
|
||||
|
||||
* Fix pr issues
|
||||
|
||||
Co-authored-by: Pablo Suárez Hernández <psuarezhernandez@suse.com>
|
||||
|
||||
* Fix unit test for allow vendor change on upgrade
|
||||
|
||||
* Add unit test with unsupported zypper version
|
||||
|
||||
Co-authored-by: Pablo Suárez Hernández <psuarezhernandez@suse.com>
|
||||
---
|
||||
salt/modules/zypperpkg.py | 58 +++++++++++++---
|
||||
tests/unit/modules/test_zypperpkg.py | 99 ++++++++++++++++++----------
|
||||
2 files changed, 112 insertions(+), 45 deletions(-)
|
||||
|
||||
diff --git a/salt/modules/zypperpkg.py b/salt/modules/zypperpkg.py
|
||||
index 6f22994bf0..b35792237c 100644
|
||||
--- a/salt/modules/zypperpkg.py
|
||||
+++ b/salt/modules/zypperpkg.py
|
||||
@@ -105,6 +105,10 @@ class _Zypper:
|
||||
ZYPPER_LOCK = "/var/run/zypp.pid"
|
||||
TAG_RELEASED = "zypper/released"
|
||||
TAG_BLOCKED = "zypper/blocked"
|
||||
+ # Dist upgrade vendor change support (SLE12+)
|
||||
+ dup_avc = False
|
||||
+ # Install/Patch/Upgrade vendor change support (SLE15+)
|
||||
+ inst_avc = False
|
||||
|
||||
def __init__(self):
|
||||
"""
|
||||
@@ -218,6 +222,21 @@ class _Zypper:
|
||||
def pid(self):
|
||||
return self.__call_result.get("pid", "")
|
||||
|
||||
+ def refresh_zypper_flags(self):
|
||||
+ try:
|
||||
+ zypp_version = version('zypper')
|
||||
+ # zypper version 1.11.34 in SLE12 update supports vendor change for only dist upgrade
|
||||
+ if version_cmp(zypp_version, '1.11.34') >= 0:
|
||||
+ # zypper version supports vendor change for dist upgrade
|
||||
+ self.dup_avc = True
|
||||
+ # zypper version 1.14.8 in SLE15 update supports vendor change in install/patch/upgrading
|
||||
+ if version_cmp(zypp_version, '1.14.8') >= 0:
|
||||
+ self.inst_avc = True
|
||||
+ else:
|
||||
+ log.error("Failed to compare Zypper version")
|
||||
+ except Exception as ex:
|
||||
+ log.error("Unable to get Zypper version: {}".format(ex))
|
||||
+
|
||||
def _is_error(self):
|
||||
"""
|
||||
Is this is an error code?
|
||||
@@ -1431,6 +1450,7 @@ def install(
|
||||
no_recommends=False,
|
||||
root=None,
|
||||
inclusion_detection=False,
|
||||
+ novendorchange=True,
|
||||
**kwargs
|
||||
):
|
||||
"""
|
||||
@@ -1478,6 +1498,9 @@ def install(
|
||||
skip_verify
|
||||
Skip the GPG verification check (e.g., ``--no-gpg-checks``)
|
||||
|
||||
+ novendorchange
|
||||
+ Disallow vendor change
|
||||
+
|
||||
version
|
||||
Can be either a version number, or the combination of a comparison
|
||||
operator (<, >, <=, >=, =) and a version number (ex. '>1.2.3-4').
|
||||
@@ -1638,6 +1661,15 @@ def install(
|
||||
cmd_install.append(
|
||||
kwargs.get("resolve_capabilities") and "--capability" or "--name"
|
||||
)
|
||||
+ # Install / patching / upgrade with vendor change support is only in SLE 15+ opensuse Leap 15+
|
||||
+ if not novendorchange:
|
||||
+ __zypper__(root=root).refresh_zypper_flags()
|
||||
+ if __zypper__(root=root).inst_avc:
|
||||
+ cmd_install.append("--allow-vendor-change")
|
||||
+ log.info("Enabling vendor changes")
|
||||
+ else:
|
||||
+ log.warning("Enabling/Disabling vendor changes is not supported on this Zypper version")
|
||||
+
|
||||
|
||||
if not refresh:
|
||||
cmd_install.insert(0, "--no-refresh")
|
||||
@@ -1793,19 +1825,25 @@ def upgrade(
|
||||
cmd_update.extend(["--from" if dist_upgrade else "--repo", repo])
|
||||
log.info("Targeting repos: %s", fromrepo)
|
||||
|
||||
- if dist_upgrade:
|
||||
- # TODO: Grains validation should be moved to Zypper class
|
||||
- if __grains__["osrelease_info"][0] > 11:
|
||||
- if novendorchange:
|
||||
- cmd_update.append("--no-allow-vendor-change")
|
||||
- log.info("Disabling vendor changes")
|
||||
- else:
|
||||
+ if not novendorchange:
|
||||
+ __zypper__(root=root).refresh_zypper_flags()
|
||||
+ if dist_upgrade:
|
||||
+ if __zypper__(root=root).dup_avc:
|
||||
cmd_update.append("--allow-vendor-change")
|
||||
log.info("Enabling vendor changes")
|
||||
+ else:
|
||||
+ log.warning(
|
||||
+ "Enabling/Disabling vendor changes is not supported on this Zypper version"
|
||||
+ )
|
||||
else:
|
||||
- log.warning(
|
||||
- "Enabling/Disabling vendor changes is not supported on this Zypper version"
|
||||
- )
|
||||
+ # Install / patching / upgrade with vendor change support is only in SLE 15+ opensuse Leap 15+
|
||||
+ if __zypper__(root=root).inst_avc:
|
||||
+ cmd_update.append("--allow-vendor-change")
|
||||
+ log.info("Enabling vendor changes")
|
||||
+ else:
|
||||
+ log.warning(
|
||||
+ "Enabling/Disabling vendor changes is not supported on this Zypper version"
|
||||
+ )
|
||||
|
||||
if no_recommends:
|
||||
cmd_update.append("--no-recommends")
|
||||
diff --git a/tests/unit/modules/test_zypperpkg.py b/tests/unit/modules/test_zypperpkg.py
|
||||
index 9c4a224c55..f32c382d7f 100644
|
||||
--- a/tests/unit/modules/test_zypperpkg.py
|
||||
+++ b/tests/unit/modules/test_zypperpkg.py
|
||||
@@ -644,7 +644,6 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
|
||||
zypper_mock.assert_any_call(
|
||||
"dist-upgrade",
|
||||
"--auto-agree-with-licenses",
|
||||
- "--no-allow-vendor-change",
|
||||
)
|
||||
|
||||
with patch(
|
||||
@@ -691,46 +690,80 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
|
||||
"dist-upgrade",
|
||||
"--auto-agree-with-licenses",
|
||||
"--dry-run",
|
||||
- "--no-allow-vendor-change",
|
||||
)
|
||||
zypper_mock.assert_any_call(
|
||||
"dist-upgrade",
|
||||
"--auto-agree-with-licenses",
|
||||
"--dry-run",
|
||||
- "--no-allow-vendor-change",
|
||||
)
|
||||
|
||||
with patch(
|
||||
"salt.modules.zypperpkg.list_pkgs",
|
||||
- MagicMock(side_effect=[{"vim": "1.1"}, {"vim": "1.1"}]),
|
||||
+ MagicMock(side_effect=[{"vim": "1.1"}, {"vim": "1.1"}])
|
||||
):
|
||||
- ret = zypper.upgrade(
|
||||
- dist_upgrade=True,
|
||||
- dryrun=True,
|
||||
- fromrepo=["Dummy", "Dummy2"],
|
||||
- novendorchange=False,
|
||||
- )
|
||||
- zypper_mock.assert_any_call(
|
||||
- "dist-upgrade",
|
||||
- "--auto-agree-with-licenses",
|
||||
- "--dry-run",
|
||||
- "--from",
|
||||
- "Dummy",
|
||||
- "--from",
|
||||
- "Dummy2",
|
||||
- "--allow-vendor-change",
|
||||
- )
|
||||
- zypper_mock.assert_any_call(
|
||||
- "dist-upgrade",
|
||||
- "--auto-agree-with-licenses",
|
||||
- "--dry-run",
|
||||
- "--from",
|
||||
- "Dummy",
|
||||
- "--from",
|
||||
- "Dummy2",
|
||||
- "--allow-vendor-change",
|
||||
- "--debug-solver",
|
||||
- )
|
||||
+ with patch.dict(zypper.__salt__,
|
||||
+ {'pkg_resource.version': MagicMock(return_value='1.15'),
|
||||
+ 'lowpkg.version_cmp': MagicMock(return_value=1)}):
|
||||
+ ret = zypper.upgrade(
|
||||
+ dist_upgrade=True,
|
||||
+ dryrun=True,
|
||||
+ fromrepo=["Dummy", "Dummy2"],
|
||||
+ novendorchange=False,
|
||||
+ )
|
||||
+ zypper_mock.assert_any_call(
|
||||
+ "dist-upgrade",
|
||||
+ "--auto-agree-with-licenses",
|
||||
+ "--dry-run",
|
||||
+ "--from",
|
||||
+ "Dummy",
|
||||
+ "--from",
|
||||
+ "Dummy2",
|
||||
+ "--allow-vendor-change",
|
||||
+ )
|
||||
+ zypper_mock.assert_any_call(
|
||||
+ "dist-upgrade",
|
||||
+ "--auto-agree-with-licenses",
|
||||
+ "--dry-run",
|
||||
+ "--from",
|
||||
+ "Dummy",
|
||||
+ "--from",
|
||||
+ "Dummy2",
|
||||
+ "--allow-vendor-change",
|
||||
+ "--debug-solver",
|
||||
+ )
|
||||
+
|
||||
+ with patch(
|
||||
+ "salt.modules.zypperpkg.list_pkgs",
|
||||
+ MagicMock(side_effect=[{"vim": "1.1"}, {"vim": "1.1"}])
|
||||
+ ):
|
||||
+ with patch.dict(zypper.__salt__,
|
||||
+ {'pkg_resource.version': MagicMock(return_value='1.11'),
|
||||
+ 'lowpkg.version_cmp': MagicMock(return_value=1)}):
|
||||
+ ret = zypper.upgrade(
|
||||
+ dist_upgrade=True,
|
||||
+ dryrun=True,
|
||||
+ fromrepo=["Dummy", "Dummy2"],
|
||||
+ novendorchange=False,
|
||||
+ )
|
||||
+ zypper_mock.assert_any_call(
|
||||
+ "dist-upgrade",
|
||||
+ "--auto-agree-with-licenses",
|
||||
+ "--dry-run",
|
||||
+ "--from",
|
||||
+ "Dummy",
|
||||
+ "--from",
|
||||
+ "Dummy2",
|
||||
+ )
|
||||
+ zypper_mock.assert_any_call(
|
||||
+ "dist-upgrade",
|
||||
+ "--auto-agree-with-licenses",
|
||||
+ "--dry-run",
|
||||
+ "--from",
|
||||
+ "Dummy",
|
||||
+ "--from",
|
||||
+ "Dummy2",
|
||||
+ "--debug-solver",
|
||||
+ )
|
||||
|
||||
with patch(
|
||||
"salt.modules.zypperpkg.list_pkgs",
|
||||
@@ -750,7 +783,6 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
|
||||
"Dummy",
|
||||
"--from",
|
||||
"Dummy2",
|
||||
- "--no-allow-vendor-change",
|
||||
)
|
||||
zypper_mock.assert_any_call(
|
||||
"dist-upgrade",
|
||||
@@ -760,7 +792,6 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
|
||||
"Dummy",
|
||||
"--from",
|
||||
"Dummy2",
|
||||
- "--no-allow-vendor-change",
|
||||
"--debug-solver",
|
||||
)
|
||||
|
||||
@@ -797,7 +828,6 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
|
||||
"Dummy",
|
||||
"--from",
|
||||
"Dummy2",
|
||||
- "--no-allow-vendor-change",
|
||||
)
|
||||
|
||||
with patch(
|
||||
@@ -911,7 +941,6 @@ Repository 'DUMMY' not found by its alias, number, or URI.
|
||||
"--auto-agree-with-licenses",
|
||||
"--from",
|
||||
"DUMMY",
|
||||
- "--no-allow-vendor-change",
|
||||
)
|
||||
|
||||
def test_upgrade_available(self):
|
||||
--
|
||||
2.30.1
|
||||
|
||||
|
521
improvements-on-ansiblegate-module-354.patch
Normal file
521
improvements-on-ansiblegate-module-354.patch
Normal file
@ -0,0 +1,521 @@
|
||||
From aa0f845e2bbc37332db04c583f475cfe25304db6 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?=
|
||||
<psuarezhernandez@suse.com>
|
||||
Date: Tue, 20 Apr 2021 11:01:26 +0100
|
||||
Subject: [PATCH] Improvements on "ansiblegate" module (#354)
|
||||
|
||||
* Allow collecting Ansible Inventory from a minion
|
||||
|
||||
* Prevent crashing if ansible-playbook doesn't return JSON
|
||||
|
||||
* Add new 'ansible.discover_playbooks' method
|
||||
|
||||
* Include custom inventory when discovering Ansible playbooks
|
||||
|
||||
* Enhance 'ansible.discover_playbooks' to accept a list of locations
|
||||
|
||||
* Remove unused constants from Ansible utils
|
||||
|
||||
* Avoid string concatenation to calculate extra cmd args
|
||||
|
||||
* Add unit test for ansible.targets
|
||||
|
||||
* Improve Ansible roster targetting
|
||||
|
||||
* Add tests for new ansiblegate module functions
|
||||
|
||||
* Fix issue dealing with ungrouped targets on inventory
|
||||
|
||||
* Enable ansible utils for ansible roster tests
|
||||
|
||||
* Remove unnecessary code from Ansible utils
|
||||
|
||||
* Fix pylint issue
|
||||
|
||||
* Fix issue in documentation
|
||||
---
|
||||
salt/modules/ansiblegate.py | 166 +++++++++++++++++-
|
||||
salt/roster/ansible.py | 18 +-
|
||||
salt/utils/ansible.py | 44 +++++
|
||||
.../pytests/unit/modules/test_ansiblegate.py | 94 +++++++++-
|
||||
.../example_playbooks/example-playbook2/hosts | 7 +
|
||||
.../example-playbook2/site.yml | 28 +++
|
||||
.../playbooks/example_playbooks/playbook1.yml | 5 +
|
||||
tests/unit/roster/test_ansible.py | 2 +-
|
||||
8 files changed, 354 insertions(+), 10 deletions(-)
|
||||
create mode 100644 salt/utils/ansible.py
|
||||
create mode 100644 tests/unit/files/playbooks/example_playbooks/example-playbook2/hosts
|
||||
create mode 100644 tests/unit/files/playbooks/example_playbooks/example-playbook2/site.yml
|
||||
create mode 100644 tests/unit/files/playbooks/example_playbooks/playbook1.yml
|
||||
|
||||
diff --git a/salt/modules/ansiblegate.py b/salt/modules/ansiblegate.py
|
||||
index 5d4b986ec2..4f96607a07 100644
|
||||
--- a/salt/modules/ansiblegate.py
|
||||
+++ b/salt/modules/ansiblegate.py
|
||||
@@ -426,7 +426,171 @@ def playbooks(
|
||||
}
|
||||
ret = __salt__["cmd.run_all"](**cmd_kwargs)
|
||||
log.debug("Ansible Playbook Return: %s", ret)
|
||||
- retdata = json.loads(ret["stdout"])
|
||||
+ try:
|
||||
+ retdata = json.loads(ret["stdout"])
|
||||
+ except ValueError:
|
||||
+ retdata = ret
|
||||
if "retcode" in ret:
|
||||
__context__["retcode"] = retdata["retcode"] = ret["retcode"]
|
||||
return retdata
|
||||
+
|
||||
+
|
||||
+def targets(**kwargs):
|
||||
+ """
|
||||
+ Return the inventory from an Ansible inventory_file
|
||||
+
|
||||
+ :param inventory:
|
||||
+ The inventory file to read the inventory from. Default: "/etc/ansible/hosts"
|
||||
+
|
||||
+ :param yaml:
|
||||
+ Return the inventory as yaml output. Default: False
|
||||
+
|
||||
+ :param export:
|
||||
+ Return inventory as export format. Default: False
|
||||
+
|
||||
+ CLI Example:
|
||||
+
|
||||
+ .. code-block:: bash
|
||||
+
|
||||
+ salt 'ansiblehost' ansible.targets
|
||||
+ salt 'ansiblehost' ansible.targets inventory=my_custom_inventory
|
||||
+
|
||||
+ """
|
||||
+ return __utils__["ansible.targets"](**kwargs)
|
||||
+
|
||||
+
|
||||
+def discover_playbooks(path=None,
|
||||
+ locations=None,
|
||||
+ playbook_extension=None,
|
||||
+ hosts_filename=None,
|
||||
+ syntax_check=False):
|
||||
+ """
|
||||
+ Discover Ansible playbooks stored under the given path or from multiple paths (locations)
|
||||
+
|
||||
+ This will search for files matching with the playbook file extension under the given
|
||||
+ root path and will also look for files inside the first level of directories in this path.
|
||||
+
|
||||
+ The return of this function would be a dict like this:
|
||||
+
|
||||
+ .. code-block:: python
|
||||
+
|
||||
+ {
|
||||
+ "/home/foobar/": {
|
||||
+ "my_ansible_playbook.yml": {
|
||||
+ "fullpath": "/home/foobar/playbooks/my_ansible_playbook.yml",
|
||||
+ "custom_inventory": "/home/foobar/playbooks/hosts"
|
||||
+ },
|
||||
+ "another_playbook.yml": {
|
||||
+ "fullpath": "/home/foobar/playbooks/another_playbook.yml",
|
||||
+ "custom_inventory": "/home/foobar/playbooks/hosts"
|
||||
+ },
|
||||
+ "lamp_simple/site.yml": {
|
||||
+ "fullpath": "/home/foobar/playbooks/lamp_simple/site.yml",
|
||||
+ "custom_inventory": "/home/foobar/playbooks/lamp_simple/hosts"
|
||||
+ },
|
||||
+ "lamp_proxy/site.yml": {
|
||||
+ "fullpath": "/home/foobar/playbooks/lamp_proxy/site.yml",
|
||||
+ "custom_inventory": "/home/foobar/playbooks/lamp_proxy/hosts"
|
||||
+ }
|
||||
+ },
|
||||
+ "/srv/playbooks/": {
|
||||
+ "example_playbook/example.yml": {
|
||||
+ "fullpath": "/srv/playbooks/example_playbook/example.yml",
|
||||
+ "custom_inventory": "/srv/playbooks/example_playbook/hosts"
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ :param path:
|
||||
+ Path to discover playbooks from.
|
||||
+
|
||||
+ :param locations:
|
||||
+ List of paths to discover playbooks from.
|
||||
+
|
||||
+ :param playbook_extension:
|
||||
+ File extension of playbooks file to search for. Default: "yml"
|
||||
+
|
||||
+ :param hosts_filename:
|
||||
+ Filename of custom playbook inventory to search for. Default: "hosts"
|
||||
+
|
||||
+ :param syntax_check:
|
||||
+ Skip playbooks that do not pass "ansible-playbook --syntax-check" validation. Default: False
|
||||
+
|
||||
+ :return:
|
||||
+ The discovered playbooks under the given paths
|
||||
+
|
||||
+ CLI Example:
|
||||
+
|
||||
+ .. code-block:: bash
|
||||
+
|
||||
+ salt 'ansiblehost' ansible.discover_playbooks path=/srv/playbooks/
|
||||
+ salt 'ansiblehost' ansible.discover_playbooks locations='["/srv/playbooks/", "/srv/foobar"]'
|
||||
+
|
||||
+ """
|
||||
+
|
||||
+ if not path and not locations:
|
||||
+ raise CommandExecutionError("You have to specify either 'path' or 'locations' arguments")
|
||||
+
|
||||
+ if path and locations:
|
||||
+ raise CommandExecutionError("You cannot specify 'path' and 'locations' at the same time")
|
||||
+
|
||||
+ if not playbook_extension:
|
||||
+ playbook_extension = "yml"
|
||||
+ if not hosts_filename:
|
||||
+ hosts_filename = "hosts"
|
||||
+
|
||||
+ if path:
|
||||
+ if not os.path.isabs(path):
|
||||
+ raise CommandExecutionError("The given path is not an absolute path: {}".format(path))
|
||||
+ if not os.path.isdir(path):
|
||||
+ raise CommandExecutionError("The given path is not a directory: {}".format(path))
|
||||
+ return {path: _explore_path(path, playbook_extension, hosts_filename, syntax_check)}
|
||||
+
|
||||
+ if locations:
|
||||
+ all_ret = {}
|
||||
+ for location in locations:
|
||||
+ all_ret[location] = _explore_path(location, playbook_extension, hosts_filename, syntax_check)
|
||||
+ return all_ret
|
||||
+
|
||||
+
|
||||
+def _explore_path(path, playbook_extension, hosts_filename, syntax_check):
|
||||
+ ret = {}
|
||||
+
|
||||
+ if not os.path.isabs(path):
|
||||
+ log.error("The given path is not an absolute path: {}".format(path))
|
||||
+ return ret
|
||||
+ if not os.path.isdir(path):
|
||||
+ log.error("The given path is not a directory: {}".format(path))
|
||||
+ return ret
|
||||
+
|
||||
+ try:
|
||||
+ # Check files in the given path
|
||||
+ for _f in os.listdir(path):
|
||||
+ _path = os.path.join(path, _f)
|
||||
+ if os.path.isfile(_path) and _path.endswith("." + playbook_extension):
|
||||
+ ret[_f] = {"fullpath": _path}
|
||||
+ # Check for custom inventory file
|
||||
+ if os.path.isfile(os.path.join(path, hosts_filename)):
|
||||
+ ret[_f].update({"custom_inventory": os.path.join(path, hosts_filename)})
|
||||
+ elif os.path.isdir(_path):
|
||||
+ # Check files in the 1st level of subdirectories
|
||||
+ for _f2 in os.listdir(_path):
|
||||
+ _path2 = os.path.join(_path, _f2)
|
||||
+ if os.path.isfile(_path2) and _path2.endswith("." + playbook_extension):
|
||||
+ ret[os.path.join(_f, _f2)] = {"fullpath": _path2}
|
||||
+ # Check for custom inventory file
|
||||
+ if os.path.isfile(os.path.join(_path, hosts_filename)):
|
||||
+ ret[os.path.join(_f, _f2)].update({"custom_inventory": os.path.join(_path, hosts_filename)})
|
||||
+ except Exception as exc:
|
||||
+ raise CommandExecutionError("There was an exception while discovering playbooks: {}".format(exc))
|
||||
+
|
||||
+ # Run syntax check validation
|
||||
+ if syntax_check:
|
||||
+ check_command = ["ansible-playbook", "--syntax-check"]
|
||||
+ try:
|
||||
+ for pb in list(ret):
|
||||
+ if __salt__["cmd.retcode"](check_command + [ret[pb]]):
|
||||
+ del ret[pb]
|
||||
+ except Exception as exc:
|
||||
+ raise CommandExecutionError("There was an exception while checking syntax of playbooks: {}".format(exc))
|
||||
+ return ret
|
||||
diff --git a/salt/roster/ansible.py b/salt/roster/ansible.py
|
||||
index f17316bdd7..cc61f6fb7d 100644
|
||||
--- a/salt/roster/ansible.py
|
||||
+++ b/salt/roster/ansible.py
|
||||
@@ -89,7 +89,6 @@ Any of the [groups] or direct hostnames will return. The 'all' is special, and
|
||||
"""
|
||||
# Import Python libs
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
-
|
||||
import copy
|
||||
import fnmatch
|
||||
|
||||
@@ -121,27 +120,32 @@ def targets(tgt, tgt_type="glob", **kwargs):
|
||||
Return the targets from the ansible inventory_file
|
||||
Default: /etc/salt/roster
|
||||
"""
|
||||
- inventory = __runner__["salt.cmd"](
|
||||
- "cmd.run", "ansible-inventory -i {0} --list".format(get_roster_file(__opts__))
|
||||
- )
|
||||
- __context__["inventory"] = __utils__["json.loads"](
|
||||
- __utils__["stringutils.to_str"](inventory)
|
||||
+ __context__["inventory"] = __utils__["ansible.targets"](
|
||||
+ inventory=get_roster_file(__opts__), **kwargs
|
||||
)
|
||||
|
||||
if tgt_type == "glob":
|
||||
hosts = [
|
||||
host for host in _get_hosts_from_group("all") if fnmatch.fnmatch(host, tgt)
|
||||
]
|
||||
+ elif tgt_type == "list":
|
||||
+ hosts = [host for host in _get_hosts_from_group("all") if host in tgt]
|
||||
elif tgt_type == "nodegroup":
|
||||
hosts = _get_hosts_from_group(tgt)
|
||||
+ else:
|
||||
+ hosts = []
|
||||
+
|
||||
return {host: _get_hostvars(host) for host in hosts}
|
||||
|
||||
|
||||
def _get_hosts_from_group(group):
|
||||
inventory = __context__["inventory"]
|
||||
+ if group not in inventory:
|
||||
+ return []
|
||||
hosts = [host for host in inventory[group].get("hosts", [])]
|
||||
for child in inventory[group].get("children", []):
|
||||
- if child != "ungrouped":
|
||||
+ child_info = _get_hosts_from_group(child)
|
||||
+ if child_info not in hosts:
|
||||
hosts.extend(_get_hosts_from_group(child))
|
||||
return hosts
|
||||
|
||||
diff --git a/salt/utils/ansible.py b/salt/utils/ansible.py
|
||||
new file mode 100644
|
||||
index 0000000000..ee85cb656c
|
||||
--- /dev/null
|
||||
+++ b/salt/utils/ansible.py
|
||||
@@ -0,0 +1,44 @@
|
||||
+# -*- coding: utf-8 -*-
|
||||
+# Import Python libs
|
||||
+from __future__ import absolute_import, print_function, unicode_literals
|
||||
+import logging
|
||||
+import os
|
||||
+
|
||||
+# Import Salt libs
|
||||
+import salt.utils.json
|
||||
+import salt.utils.path
|
||||
+import salt.utils.stringutils
|
||||
+import salt.modules.cmdmod
|
||||
+from salt.exceptions import CommandExecutionError
|
||||
+
|
||||
+__virtualname__ = "ansible"
|
||||
+
|
||||
+log = logging.getLogger(__name__)
|
||||
+
|
||||
+
|
||||
+def __virtual__(): # pylint: disable=expected-2-blank-lines-found-0
|
||||
+ if salt.utils.path.which("ansible-inventory"):
|
||||
+ return __virtualname__
|
||||
+ return (False, "Install `ansible` to use inventory")
|
||||
+
|
||||
+
|
||||
+def targets(inventory="/etc/ansible/hosts", **kwargs):
|
||||
+ """
|
||||
+ Return the targets from the ansible inventory_file
|
||||
+ Default: /etc/salt/roster
|
||||
+ """
|
||||
+ if not os.path.isfile(inventory):
|
||||
+ raise CommandExecutionError("Inventory file not found: {}".format(inventory))
|
||||
+
|
||||
+ extra_cmd = []
|
||||
+ if "export" in kwargs:
|
||||
+ extra_cmd.append("--export")
|
||||
+ if "yaml" in kwargs:
|
||||
+ extra_cmd.append("--yaml")
|
||||
+ inv = salt.modules.cmdmod.run(
|
||||
+ "ansible-inventory -i {} --list {}".format(inventory, " ".join(extra_cmd))
|
||||
+ )
|
||||
+ if kwargs.get("yaml", False):
|
||||
+ return salt.utils.stringutils.to_str(inv)
|
||||
+ else:
|
||||
+ return salt.utils.json.loads(salt.utils.stringutils.to_str(inv))
|
||||
diff --git a/tests/pytests/unit/modules/test_ansiblegate.py b/tests/pytests/unit/modules/test_ansiblegate.py
|
||||
index 42c0968a6e..24c7e5e6b3 100644
|
||||
--- a/tests/pytests/unit/modules/test_ansiblegate.py
|
||||
+++ b/tests/pytests/unit/modules/test_ansiblegate.py
|
||||
@@ -8,8 +8,11 @@ import pytest
|
||||
import salt.modules.ansiblegate as ansible
|
||||
import salt.utils.path
|
||||
import salt.utils.platform
|
||||
+import salt.config
|
||||
+import salt.loader
|
||||
from salt.exceptions import LoaderError
|
||||
from tests.support.mock import MagicMock, MockTimedProc, patch
|
||||
+from tests.support.runtests import RUNTIME_VARS
|
||||
|
||||
pytestmark = pytest.mark.skipif(
|
||||
salt.utils.platform.is_windows(), reason="Not supported on Windows"
|
||||
@@ -18,7 +21,7 @@ pytestmark = pytest.mark.skipif(
|
||||
|
||||
@pytest.fixture
|
||||
def configure_loader_modules():
|
||||
- return {ansible: {}}
|
||||
+ return {ansible: {"__utils__": {}}}
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@@ -201,3 +204,92 @@ def test_ansible_playbooks_return_retcode(resolver):
|
||||
):
|
||||
ret = ansible.playbooks("fake-playbook.yml")
|
||||
assert "retcode" in ret
|
||||
+
|
||||
+
|
||||
+def test_ansible_targets():
|
||||
+ """
|
||||
+ Test ansible.targets execution module function.
|
||||
+ :return:
|
||||
+ """
|
||||
+ ansible_inventory_ret = """
|
||||
+{
|
||||
+ "_meta": {
|
||||
+ "hostvars": {
|
||||
+ "uyuni-stable-ansible-centos7-1.tf.local": {
|
||||
+ "ansible_ssh_private_key_file": "/etc/ansible/my_ansible_private_key"
|
||||
+ },
|
||||
+ "uyuni-stable-ansible-centos7-2.tf.local": {
|
||||
+ "ansible_ssh_private_key_file": "/etc/ansible/my_ansible_private_key"
|
||||
+ }
|
||||
+ }
|
||||
+ },
|
||||
+ "all": {
|
||||
+ "children": [
|
||||
+ "ungrouped"
|
||||
+ ]
|
||||
+ },
|
||||
+ "ungrouped": {
|
||||
+ "hosts": [
|
||||
+ "uyuni-stable-ansible-centos7-1.tf.local",
|
||||
+ "uyuni-stable-ansible-centos7-2.tf.local"
|
||||
+ ]
|
||||
+ }
|
||||
+}
|
||||
+ """
|
||||
+ ansible_inventory_mock = MagicMock(return_value=ansible_inventory_ret)
|
||||
+ with patch("salt.utils.path.which", MagicMock(return_value=True)):
|
||||
+ opts = salt.config.DEFAULT_MINION_OPTS.copy()
|
||||
+ utils = salt.loader.utils(opts, whitelist=["ansible"])
|
||||
+ with patch("salt.modules.cmdmod.run", ansible_inventory_mock), patch.dict(
|
||||
+ ansible.__utils__, utils), patch(
|
||||
+ "os.path.isfile", MagicMock(return_value=True)
|
||||
+ ):
|
||||
+ ret = ansible.targets()
|
||||
+ assert ansible_inventory_mock.call_args
|
||||
+ assert "_meta" in ret
|
||||
+ assert "uyuni-stable-ansible-centos7-1.tf.local" in ret["_meta"]["hostvars"]
|
||||
+ assert "ansible_ssh_private_key_file" in ret["_meta"]["hostvars"]["uyuni-stable-ansible-centos7-1.tf.local"]
|
||||
+ assert "all" in ret
|
||||
+ assert len(ret["ungrouped"]["hosts"]) == 2
|
||||
+
|
||||
+
|
||||
+def test_ansible_discover_playbooks_single_path():
|
||||
+ playbooks_dir = os.path.join(
|
||||
+ RUNTIME_VARS.TESTS_DIR, "unit/files/playbooks/example_playbooks/"
|
||||
+ )
|
||||
+ ret = ansible.discover_playbooks(playbooks_dir)
|
||||
+ assert playbooks_dir in ret
|
||||
+ assert ret[playbooks_dir]["playbook1.yml"] == {
|
||||
+ "fullpath": os.path.join(playbooks_dir, "playbook1.yml")
|
||||
+ }
|
||||
+ assert ret[playbooks_dir]["example-playbook2/site.yml"] == {
|
||||
+ "fullpath": os.path.join(playbooks_dir, "example-playbook2/site.yml"),
|
||||
+ "custom_inventory": os.path.join(playbooks_dir, "example-playbook2/hosts"),
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+def test_ansible_discover_playbooks_single_path_using_parameters():
|
||||
+ playbooks_dir = os.path.join(
|
||||
+ RUNTIME_VARS.TESTS_DIR, "unit/files/playbooks/example_playbooks/"
|
||||
+ )
|
||||
+ ret = ansible.discover_playbooks(
|
||||
+ playbooks_dir, playbook_extension="foobar", hosts_filename="deadbeaf"
|
||||
+ )
|
||||
+ assert playbooks_dir in ret
|
||||
+ assert ret[playbooks_dir] == {}
|
||||
+
|
||||
+
|
||||
+def test_ansible_discover_playbooks_multiple_locations():
|
||||
+ playbooks_dir = os.path.join(
|
||||
+ RUNTIME_VARS.TESTS_DIR, "unit/files/playbooks/example_playbooks/"
|
||||
+ )
|
||||
+ ret = ansible.discover_playbooks(locations=[playbooks_dir, "/tmp/foobar"])
|
||||
+ assert playbooks_dir in ret
|
||||
+ assert "/tmp/foobar" in ret
|
||||
+ assert ret[playbooks_dir]["playbook1.yml"] == {
|
||||
+ "fullpath": os.path.join(playbooks_dir, "playbook1.yml")
|
||||
+ }
|
||||
+ assert ret[playbooks_dir]["example-playbook2/site.yml"] == {
|
||||
+ "fullpath": os.path.join(playbooks_dir, "example-playbook2/site.yml"),
|
||||
+ "custom_inventory": os.path.join(playbooks_dir, "example-playbook2/hosts"),
|
||||
+ }
|
||||
diff --git a/tests/unit/files/playbooks/example_playbooks/example-playbook2/hosts b/tests/unit/files/playbooks/example_playbooks/example-playbook2/hosts
|
||||
new file mode 100644
|
||||
index 0000000000..75783285f6
|
||||
--- /dev/null
|
||||
+++ b/tests/unit/files/playbooks/example_playbooks/example-playbook2/hosts
|
||||
@@ -0,0 +1,7 @@
|
||||
+[databases]
|
||||
+host1
|
||||
+host2
|
||||
+
|
||||
+[webservers]
|
||||
+host3
|
||||
+host4
|
||||
diff --git a/tests/unit/files/playbooks/example_playbooks/example-playbook2/site.yml b/tests/unit/files/playbooks/example_playbooks/example-playbook2/site.yml
|
||||
new file mode 100644
|
||||
index 0000000000..a64ebd5e18
|
||||
--- /dev/null
|
||||
+++ b/tests/unit/files/playbooks/example_playbooks/example-playbook2/site.yml
|
||||
@@ -0,0 +1,28 @@
|
||||
+---
|
||||
+- name: update web servers
|
||||
+ hosts: webservers
|
||||
+ remote_user: root
|
||||
+
|
||||
+ tasks:
|
||||
+ - name: ensure apache is at the latest version
|
||||
+ yum:
|
||||
+ name: httpd
|
||||
+ state: latest
|
||||
+ - name: write the apache config file
|
||||
+ template:
|
||||
+ src: /srv/httpd.j2
|
||||
+ dest: /etc/httpd.conf
|
||||
+
|
||||
+- name: update db servers
|
||||
+ hosts: databases
|
||||
+ remote_user: root
|
||||
+
|
||||
+ tasks:
|
||||
+ - name: ensure postgresql is at the latest version
|
||||
+ yum:
|
||||
+ name: postgresql
|
||||
+ state: latest
|
||||
+ - name: ensure that postgresql is started
|
||||
+ service:
|
||||
+ name: postgresql
|
||||
+ state: started
|
||||
diff --git a/tests/unit/files/playbooks/example_playbooks/playbook1.yml b/tests/unit/files/playbooks/example_playbooks/playbook1.yml
|
||||
new file mode 100644
|
||||
index 0000000000..e258a101e1
|
||||
--- /dev/null
|
||||
+++ b/tests/unit/files/playbooks/example_playbooks/playbook1.yml
|
||||
@@ -0,0 +1,5 @@
|
||||
+---
|
||||
+- hosts: all
|
||||
+ gather_facts: false
|
||||
+ tasks:
|
||||
+ - ping:
|
||||
diff --git a/tests/unit/roster/test_ansible.py b/tests/unit/roster/test_ansible.py
|
||||
index a5cdcbbdbc..8bc9c1c6f7 100644
|
||||
--- a/tests/unit/roster/test_ansible.py
|
||||
+++ b/tests/unit/roster/test_ansible.py
|
||||
@@ -71,7 +71,7 @@ class AnsibleRosterTestCase(TestCase, mixins.LoaderModuleMockMixin):
|
||||
opts = salt.config.master_config(
|
||||
os.path.join(RUNTIME_VARS.TMP_CONF_DIR, "master")
|
||||
)
|
||||
- utils = salt.loader.utils(opts, whitelist=["json", "stringutils"])
|
||||
+ utils = salt.loader.utils(opts, whitelist=["json", "stringutils", "ansible"])
|
||||
runner = salt.loader.runner(opts, utils=utils, whitelist=["salt"])
|
||||
return {ansible: {"__utils__": utils, "__opts__": {}, "__runner__": runner}}
|
||||
|
||||
--
|
||||
2.31.1
|
||||
|
||||
|
92
notify-beacon-for-debian-ubuntu-systems-347.patch
Normal file
92
notify-beacon-for-debian-ubuntu-systems-347.patch
Normal file
@ -0,0 +1,92 @@
|
||||
From e0f8087409bdff4c3036e38ed4f22f5f031306e8 Mon Sep 17 00:00:00 2001
|
||||
From: Ricardo Mateus <rjmateus@gmail.com>
|
||||
Date: Fri, 9 Apr 2021 10:57:27 +0100
|
||||
Subject: [PATCH] Notify beacon for Debian/Ubuntu systems (#347)
|
||||
|
||||
Signed-off-by: Ricardo Mateus <rmateus@suse.com>
|
||||
(cherry picked from commit 33d6baebba94cc7a66d5555de984ca98684157a0)
|
||||
---
|
||||
scripts/suse/dpkg/99dpkgnotify | 1 +
|
||||
scripts/suse/dpkg/README.md | 9 +++++++
|
||||
scripts/suse/dpkg/dpkgnotify | 44 ++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 54 insertions(+)
|
||||
create mode 100644 scripts/suse/dpkg/99dpkgnotify
|
||||
create mode 100644 scripts/suse/dpkg/README.md
|
||||
create mode 100644 scripts/suse/dpkg/dpkgnotify
|
||||
|
||||
diff --git a/scripts/suse/dpkg/99dpkgnotify b/scripts/suse/dpkg/99dpkgnotify
|
||||
new file mode 100644
|
||||
index 0000000000..8013387a57
|
||||
--- /dev/null
|
||||
+++ b/scripts/suse/dpkg/99dpkgnotify
|
||||
@@ -0,0 +1 @@
|
||||
+DPkg::Post-Invoke {"/usr/bin/dpkgnotify";};
|
||||
diff --git a/scripts/suse/dpkg/README.md b/scripts/suse/dpkg/README.md
|
||||
new file mode 100644
|
||||
index 0000000000..b7a75c4786
|
||||
--- /dev/null
|
||||
+++ b/scripts/suse/dpkg/README.md
|
||||
@@ -0,0 +1,9 @@
|
||||
+## What it is
|
||||
+
|
||||
+Debian base package to notify installation of new packages outside the control of salt.
|
||||
+
|
||||
+## Installation
|
||||
+This script depends on python package, so python3 should be installed on the machine
|
||||
+
|
||||
+- The 99dpkgnotify file must be installed in /etc/apt/apt.conf.d/99dpkgnotify
|
||||
+- The dpkgnotify file must be installed in /usr/bin/dpkgnotify
|
||||
diff --git a/scripts/suse/dpkg/dpkgnotify b/scripts/suse/dpkg/dpkgnotify
|
||||
new file mode 100644
|
||||
index 0000000000..d3ad3d2ba9
|
||||
--- /dev/null
|
||||
+++ b/scripts/suse/dpkg/dpkgnotify
|
||||
@@ -0,0 +1,44 @@
|
||||
+#!/usr/bin/python3
|
||||
+
|
||||
+import os
|
||||
+import hashlib
|
||||
+
|
||||
+CK_PATH = "/var/cache/salt/minion/dpkg.cookie"
|
||||
+DPKG_PATH = "/var/lib/dpkg/status"
|
||||
+
|
||||
+def _get_mtime():
|
||||
+ """
|
||||
+ Get the modified time of the Package Database.
|
||||
+ Returns:
|
||||
+ Unix ticks
|
||||
+ """
|
||||
+ return os.path.exists(DPKG_PATH) and int(os.path.getmtime(DPKG_PATH)) or 0
|
||||
+
|
||||
+
|
||||
+def _get_checksum():
|
||||
+ """
|
||||
+ Get the checksum of the Package Database.
|
||||
+ Returns:
|
||||
+ hexdigest
|
||||
+ """
|
||||
+ digest = hashlib.sha256()
|
||||
+ with open(DPKG_PATH, "rb") as pkg_db_fh:
|
||||
+ while True:
|
||||
+ buff = pkg_db_fh.read(0x1000)
|
||||
+ if not buff:
|
||||
+ break
|
||||
+ digest.update(buff)
|
||||
+ return digest.hexdigest()
|
||||
+
|
||||
+
|
||||
+def dpkg_post_invoke():
|
||||
+ """
|
||||
+ Hook after the package installation transaction.
|
||||
+ """
|
||||
+ if 'SALT_RUNNING' not in os.environ:
|
||||
+ with open(CK_PATH, 'w') as ck_fh:
|
||||
+ ck_fh.write('{chksum} {mtime}\n'.format(chksum=_get_checksum(), mtime=_get_mtime()))
|
||||
+
|
||||
+
|
||||
+if __name__ == "__main__":
|
||||
+ dpkg_post_invoke()
|
||||
--
|
||||
2.30.2
|
||||
|
||||
|
27
regression-fix-of-salt-ssh-on-processing-targets-353.patch
Normal file
27
regression-fix-of-salt-ssh-on-processing-targets-353.patch
Normal file
@ -0,0 +1,27 @@
|
||||
From 543969c927df2f73662ac6ac19467d66d33e0577 Mon Sep 17 00:00:00 2001
|
||||
From: Victor Zhestkov <35733135+vzhestkov@users.noreply.github.com>
|
||||
Date: Tue, 13 Apr 2021 18:00:42 +0300
|
||||
Subject: [PATCH] Regression fix of salt-ssh on processing targets
|
||||
(#353)
|
||||
|
||||
---
|
||||
salt/client/ssh/__init__.py | 2 --
|
||||
1 file changed, 2 deletions(-)
|
||||
|
||||
diff --git a/salt/client/ssh/__init__.py b/salt/client/ssh/__init__.py
|
||||
index 1edb7b3b23..0a76627fe3 100644
|
||||
--- a/salt/client/ssh/__init__.py
|
||||
+++ b/salt/client/ssh/__init__.py
|
||||
@@ -435,8 +435,6 @@ class SSH:
|
||||
self.opts["tgt"] = _hosts
|
||||
elif _hosts:
|
||||
self.opts["tgt"] = _hosts[0]
|
||||
- else:
|
||||
- self.opts["tgt"] = ""
|
||||
|
||||
def get_pubkey(self):
|
||||
"""
|
||||
--
|
||||
2.30.2
|
||||
|
||||
|
52
salt.changes
52
salt.changes
@ -1,3 +1,55 @@
|
||||
-------------------------------------------------------------------
|
||||
Tue Apr 20 12:18:06 UTC 2021 - Pablo Suárez Hernández <pablo.suarezhernandez@suse.com>
|
||||
|
||||
- Improvements on "ansiblegate" module:
|
||||
* New methods: ansible.targets / ansible.discover_playbooks
|
||||
* General bugfixes
|
||||
|
||||
- Added:
|
||||
* improvements-on-ansiblegate-module-354.patch
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Tue Apr 13 15:03:48 UTC 2021 - Pablo Suárez Hernández <pablo.suarezhernandez@suse.com>
|
||||
|
||||
- Regression fix of salt-ssh on processing some targets
|
||||
|
||||
- Added:
|
||||
* regression-fix-of-salt-ssh-on-processing-targets-353.patch
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Tue Apr 13 08:40:32 UTC 2021 - Pablo Suárez Hernández <pablo.suarezhernandez@suse.com>
|
||||
|
||||
- Add support for Alibaba Cloud Linux 2 (Aliyun Linux)
|
||||
|
||||
- Added:
|
||||
* add-alibaba-cloud-linux-2-by-backporting-upstream-s-.patch
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Fri Apr 9 14:39:50 UTC 2021 - Victor Zhestkov <victor.zhestkov@suse.com>
|
||||
|
||||
- Update target fix for salt-ssh to process targets list (bsc#1179831)
|
||||
|
||||
- Added:
|
||||
* update-target-fix-for-salt-ssh-to-process-targets-li.patch
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Fri Apr 9 10:33:54 UTC 2021 - Alexander Graul <alexander.graul@suse.com>
|
||||
|
||||
- Add notify beacon for Debian/Ubuntu systems
|
||||
- Add core grains support for AlmaLinux and Alibaba Could Linux
|
||||
|
||||
- Added:
|
||||
* add-almalinux-and-alibaba-cloud-linux-to-the-os-fami.patch
|
||||
* notify-beacon-for-debian-ubuntu-systems-347.patch
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Wed Mar 17 14:17:05 UTC 2021 - Jochen Breuer <jbreuer@suse.de>
|
||||
|
||||
- Allow vendor change option with zypper
|
||||
|
||||
- Added:
|
||||
* allow-vendor-change-option-with-zypper-313.patch
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Wed Mar 10 08:42:54 UTC 2021 - Pablo Suárez Hernández <pablo.suarezhernandez@suse.com>
|
||||
|
||||
|
22
salt.spec
22
salt.spec
@ -381,6 +381,21 @@ Patch159: do-not-monkey-patch-yaml-bsc-1177474.patch
|
||||
Patch160: 3002-set-distro-requirement-to-oldest-supported-vers.patch
|
||||
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/59693
|
||||
Patch161: virt.network_update-handle-missing-ipv4-netmask-attr.patch
|
||||
# PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/313
|
||||
Patch162: allow-vendor-change-option-with-zypper-313.patch
|
||||
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/59404
|
||||
# PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/341
|
||||
Patch163: add-almalinux-and-alibaba-cloud-linux-to-the-os-fami.patch
|
||||
# PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/347
|
||||
Patch164: notify-beacon-for-debian-ubuntu-systems-347.patch
|
||||
# PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/336
|
||||
Patch165: update-target-fix-for-salt-ssh-to-process-targets-li.patch
|
||||
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/59687
|
||||
Patch166: add-alibaba-cloud-linux-2-by-backporting-upstream-s-.patch
|
||||
# PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/353
|
||||
Patch167: regression-fix-of-salt-ssh-on-processing-targets-353.patch
|
||||
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/60056
|
||||
Patch168: improvements-on-ansiblegate-module-354.patch
|
||||
|
||||
BuildRoot: %{_tmppath}/%{name}-%{version}-build
|
||||
BuildRequires: logrotate
|
||||
@ -937,6 +952,13 @@ cp %{S:5} ./.travis.yml
|
||||
%patch159 -p1
|
||||
%patch160 -p1
|
||||
%patch161 -p1
|
||||
%patch162 -p1
|
||||
%patch163 -p1
|
||||
%patch164 -p1
|
||||
%patch165 -p1
|
||||
%patch166 -p1
|
||||
%patch167 -p1
|
||||
%patch168 -p1
|
||||
|
||||
%build
|
||||
# Putting /usr/bin at the front of $PATH is needed for RHEL/RES 7. Without this
|
||||
|
98
update-target-fix-for-salt-ssh-to-process-targets-li.patch
Normal file
98
update-target-fix-for-salt-ssh-to-process-targets-li.patch
Normal file
@ -0,0 +1,98 @@
|
||||
From a603d31c4d3ace3590952ef848f4244c41abe7c8 Mon Sep 17 00:00:00 2001
|
||||
From: Victor Zhestkov <35733135+vzhestkov@users.noreply.github.com>
|
||||
Date: Fri, 9 Apr 2021 16:01:32 +0300
|
||||
Subject: [PATCH] Update target fix for salt-ssh to process targets
|
||||
list (bsc#1179831) (#336)
|
||||
|
||||
* Update target fix for salt-ssh to process targets list (bsc#1179831)
|
||||
|
||||
* Improvement for fixing (bsc#1179831)
|
||||
---
|
||||
salt/client/ssh/__init__.py | 48 ++++++++++++++++++++++++-------------
|
||||
1 file changed, 31 insertions(+), 17 deletions(-)
|
||||
|
||||
diff --git a/salt/client/ssh/__init__.py b/salt/client/ssh/__init__.py
|
||||
index 6570fba5b1..1edb7b3b23 100644
|
||||
--- a/salt/client/ssh/__init__.py
|
||||
+++ b/salt/client/ssh/__init__.py
|
||||
@@ -325,7 +325,7 @@ class SSH:
|
||||
if not self.opts.get("ssh_cli_tgt"):
|
||||
self.opts["ssh_cli_tgt"] = self.opts.get("tgt", "")
|
||||
hostname = self.opts.get("ssh_cli_tgt", "")
|
||||
- if "@" in hostname:
|
||||
+ if isinstance(hostname, str) and "@" in hostname:
|
||||
user, hostname = hostname.split("@", 1)
|
||||
else:
|
||||
user = self.opts.get("ssh_user")
|
||||
@@ -376,7 +376,7 @@ class SSH:
|
||||
self.__parsed_rosters[self.ROSTER_UPDATE_FLAG] = False
|
||||
return
|
||||
|
||||
- def _update_roster(self):
|
||||
+ def _update_roster(self, hostname=None, user=None):
|
||||
"""
|
||||
Update default flat roster with the passed in information.
|
||||
:return:
|
||||
@@ -391,8 +391,8 @@ class SSH:
|
||||
"\n passwd: {passwd}\n".format(
|
||||
s_user=getpass.getuser(),
|
||||
s_time=datetime.datetime.utcnow().isoformat(),
|
||||
- hostname=self.opts.get("tgt", ""),
|
||||
- user=self.opts.get("ssh_user", ""),
|
||||
+ hostname=hostname if hostname else self.opts.get("tgt", ""),
|
||||
+ user=user if user else self.opts.get("ssh_user", ""),
|
||||
passwd=self.opts.get("ssh_passwd", ""),
|
||||
)
|
||||
)
|
||||
@@ -409,20 +409,34 @@ class SSH:
|
||||
Uptade targets in case hostname was directly passed without the roster.
|
||||
:return:
|
||||
"""
|
||||
- hostname = self.parse_tgt["hostname"]
|
||||
+ hosts = self.parse_tgt["hostname"]
|
||||
user = self.parse_tgt["user"]
|
||||
- if hostname == "*":
|
||||
- hostname = ""
|
||||
-
|
||||
- if salt.utils.network.is_reachable_host(hostname):
|
||||
- self.opts["tgt"] = hostname
|
||||
- self.targets[hostname] = {
|
||||
- "passwd": self.opts.get("ssh_passwd", ""),
|
||||
- "host": hostname,
|
||||
- "user": user,
|
||||
- }
|
||||
- if self.opts.get("ssh_update_roster"):
|
||||
- self._update_roster()
|
||||
+
|
||||
+ if not isinstance(hosts, (list, tuple)):
|
||||
+ hosts = list([hosts])
|
||||
+ _hosts = list()
|
||||
+ for hostname in hosts:
|
||||
+ _user = user
|
||||
+ if "@" in hostname:
|
||||
+ _user, hostname = hostname.split("@", 1)
|
||||
+ if hostname == "*":
|
||||
+ continue
|
||||
+ if salt.utils.network.is_reachable_host(hostname):
|
||||
+ _hosts.append(hostname)
|
||||
+ self.targets[hostname] = {
|
||||
+ "passwd": self.opts.get("ssh_passwd", ""),
|
||||
+ "host": hostname,
|
||||
+ "user": _user,
|
||||
+ }
|
||||
+ if self.opts.get("ssh_update_roster"):
|
||||
+ self._update_roster(hostname=hostname, user=_user)
|
||||
+
|
||||
+ if self.tgt_type == "list":
|
||||
+ self.opts["tgt"] = _hosts
|
||||
+ elif _hosts:
|
||||
+ self.opts["tgt"] = _hosts[0]
|
||||
+ else:
|
||||
+ self.opts["tgt"] = ""
|
||||
|
||||
def get_pubkey(self):
|
||||
"""
|
||||
--
|
||||
2.31.1
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user