mirror of
https://github.com/saltstack/salt.git
synced 2025-04-15 09:10:20 +00:00
Merge branch '3006.x' into merge/3007.x/3006.x
This commit is contained in:
commit
1a834761bf
67 changed files with 666 additions and 300 deletions
4
changelog/58969.fixed.md
Normal file
4
changelog/58969.fixed.md
Normal file
|
@ -0,0 +1,4 @@
|
|||
Issue 58969: Fixes an issue with `saltclass.expand_classes_in_order`
|
||||
function where it was losing nested classes states during class
|
||||
expansion. The logic now use `salt.utils.odict.OrderedDict` to keep
|
||||
the inclusion ordering.
|
4
changelog/63933.fixed.md
Normal file
4
changelog/63933.fixed.md
Normal file
|
@ -0,0 +1,4 @@
|
|||
Issue 63933: Fixes an issue with `saltclass.expanded_dict_from_minion`
|
||||
function where it was passing a reference to minion `dict` which was
|
||||
overridden by nested classes during class expansion. Copy the node
|
||||
definition with `copy.deepcopy` instead of passing a reference.
|
1
changelog/66252.fixed.md
Normal file
1
changelog/66252.fixed.md
Normal file
|
@ -0,0 +1 @@
|
|||
Applying `selinux.fcontext_policy_present` to a shorter path than an existing entry now works
|
1
changelog/66883.fixed.md
Normal file
1
changelog/66883.fixed.md
Normal file
|
@ -0,0 +1 @@
|
|||
Added cryptogrpahy back to base.txt requirements as a dependency
|
1
changelog/66891.fixed.md
Normal file
1
changelog/66891.fixed.md
Normal file
|
@ -0,0 +1 @@
|
|||
Remove "perms" from `linux_acl.list_absent()` documentation
|
2
changelog/66959.fixed.md
Normal file
2
changelog/66959.fixed.md
Normal file
|
@ -0,0 +1,2 @@
|
|||
Removed the usage of wmic to get the disk and iscsi grains for Windows. The wmic
|
||||
binary is being deprecated.
|
1
changelog/66996.fixed.md
Normal file
1
changelog/66996.fixed.md
Normal file
|
@ -0,0 +1 @@
|
|||
Ensured global dunders like __env__ are defined in state module that are run in parallel on spawning platforms
|
1
changelog/66999.fixed.md
Normal file
1
changelog/66999.fixed.md
Normal file
|
@ -0,0 +1 @@
|
|||
Filtered unpicklable objects from the context dict when invoking states in parallel on spawning platforms to avoid a crash
|
|
@ -10,7 +10,8 @@ requests>=2.32.3 ; python_version >= '3.10'
|
|||
certifi==2023.07.22; python_version < '3.10'
|
||||
certifi>=2024.7.4; python_version >= '3.10'
|
||||
distro>=1.0.1
|
||||
psutil>=5.0.0
|
||||
psutil<6.0.0; python_version <= '3.9'
|
||||
psutil>=5.0.0; python_version >= '3.10'
|
||||
packaging>=21.3
|
||||
looseversion
|
||||
tornado>=6.3.3
|
||||
|
|
|
@ -15,3 +15,5 @@ pyfakefs
|
|||
trustme
|
||||
pytest-skip-markers >= 1.5.2 ; python_version >= '3.8'
|
||||
pytest-skip-markers <= 1.5.1 ; python_version < '3.8'
|
||||
pytest-shell-utilities <= 1.9.0; python_version <= '3.9'
|
||||
pytest-shell-utilities >= 1.9.7; python_version >= '3.10'
|
||||
|
|
|
@ -310,7 +310,7 @@ portend==3.1.0
|
|||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.10/darwin.txt
|
||||
# cherrypy
|
||||
psutil==5.9.6
|
||||
psutil==5.9.6 ; python_version >= "3.10"
|
||||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.10/darwin.txt
|
||||
# -r requirements/base.txt
|
||||
|
@ -373,8 +373,10 @@ pytest-httpserver==1.0.8
|
|||
# via -r requirements/pytest.txt
|
||||
pytest-salt-factories==1.0.1
|
||||
# via -r requirements/pytest.txt
|
||||
pytest-shell-utilities==1.8.0
|
||||
# via pytest-salt-factories
|
||||
pytest-shell-utilities==1.9.7 ; python_version >= "3.10"
|
||||
# via
|
||||
# -r requirements/pytest.txt
|
||||
# pytest-salt-factories
|
||||
pytest-skip-markers==1.5.2 ; python_version >= "3.8"
|
||||
# via
|
||||
# -r requirements/pytest.txt
|
||||
|
@ -534,7 +536,6 @@ typing-extensions==4.8.0
|
|||
# napalm
|
||||
# pydantic
|
||||
# pydantic-core
|
||||
# pytest-shell-utilities
|
||||
# pytest-system-statistics
|
||||
urllib3==1.26.18
|
||||
# via
|
||||
|
|
|
@ -314,7 +314,7 @@ portend==3.1.0
|
|||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.10/freebsd.txt
|
||||
# cherrypy
|
||||
psutil==5.9.6
|
||||
psutil==5.9.6 ; python_version >= "3.10"
|
||||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.10/freebsd.txt
|
||||
# -r requirements/base.txt
|
||||
|
@ -377,8 +377,10 @@ pytest-httpserver==1.0.8
|
|||
# via -r requirements/pytest.txt
|
||||
pytest-salt-factories==1.0.1
|
||||
# via -r requirements/pytest.txt
|
||||
pytest-shell-utilities==1.8.0
|
||||
# via pytest-salt-factories
|
||||
pytest-shell-utilities==1.9.7 ; python_version >= "3.10"
|
||||
# via
|
||||
# -r requirements/pytest.txt
|
||||
# pytest-salt-factories
|
||||
pytest-skip-markers==1.5.2 ; python_version >= "3.8"
|
||||
# via
|
||||
# -r requirements/pytest.txt
|
||||
|
@ -539,7 +541,6 @@ typing-extensions==4.8.0
|
|||
# napalm
|
||||
# pydantic
|
||||
# pydantic-core
|
||||
# pytest-shell-utilities
|
||||
# pytest-system-statistics
|
||||
urllib3==1.26.18
|
||||
# via
|
||||
|
|
|
@ -340,7 +340,7 @@ portend==3.1.0
|
|||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.10/linux.txt
|
||||
# cherrypy
|
||||
psutil==5.9.6
|
||||
psutil==5.9.6 ; python_version >= "3.10"
|
||||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.10/linux.txt
|
||||
# -r requirements/base.txt
|
||||
|
@ -411,8 +411,10 @@ pytest-httpserver==1.0.8
|
|||
# via -r requirements/pytest.txt
|
||||
pytest-salt-factories==1.0.1
|
||||
# via -r requirements/pytest.txt
|
||||
pytest-shell-utilities==1.8.0
|
||||
# via pytest-salt-factories
|
||||
pytest-shell-utilities==1.9.7 ; python_version >= "3.10"
|
||||
# via
|
||||
# -r requirements/pytest.txt
|
||||
# pytest-salt-factories
|
||||
pytest-skip-markers==1.5.2 ; python_version >= "3.8"
|
||||
# via
|
||||
# -r requirements/pytest.txt
|
||||
|
@ -603,7 +605,6 @@ typing-extensions==4.8.0
|
|||
# napalm
|
||||
# pydantic
|
||||
# pydantic-core
|
||||
# pytest-shell-utilities
|
||||
# pytest-system-statistics
|
||||
urllib3==1.26.18
|
||||
# via
|
||||
|
|
|
@ -272,7 +272,7 @@ portend==3.1.0
|
|||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.10/windows.txt
|
||||
# cherrypy
|
||||
psutil==5.9.6
|
||||
psutil==5.9.6 ; python_version >= "3.10"
|
||||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.10/windows.txt
|
||||
# -r requirements/base.txt
|
||||
|
@ -335,8 +335,10 @@ pytest-httpserver==1.0.8
|
|||
# via -r requirements/pytest.txt
|
||||
pytest-salt-factories==1.0.1
|
||||
# via -r requirements/pytest.txt
|
||||
pytest-shell-utilities==1.8.0
|
||||
# via pytest-salt-factories
|
||||
pytest-shell-utilities==1.9.7 ; python_version >= "3.10"
|
||||
# via
|
||||
# -r requirements/pytest.txt
|
||||
# pytest-salt-factories
|
||||
pytest-skip-markers==1.5.2 ; python_version >= "3.8"
|
||||
# via
|
||||
# -r requirements/pytest.txt
|
||||
|
@ -486,7 +488,6 @@ typing-extensions==4.8.0
|
|||
# inflect
|
||||
# pydantic
|
||||
# pydantic-core
|
||||
# pytest-shell-utilities
|
||||
# pytest-system-statistics
|
||||
urllib3==1.26.18
|
||||
# via
|
||||
|
|
|
@ -303,7 +303,7 @@ portend==3.1.0
|
|||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.11/darwin.txt
|
||||
# cherrypy
|
||||
psutil==5.9.6
|
||||
psutil==5.9.6 ; python_version >= "3.10"
|
||||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.11/darwin.txt
|
||||
# -r requirements/base.txt
|
||||
|
@ -366,8 +366,10 @@ pytest-httpserver==1.0.8
|
|||
# via -r requirements/pytest.txt
|
||||
pytest-salt-factories==1.0.1
|
||||
# via -r requirements/pytest.txt
|
||||
pytest-shell-utilities==1.8.0
|
||||
# via pytest-salt-factories
|
||||
pytest-shell-utilities==1.9.7 ; python_version >= "3.10"
|
||||
# via
|
||||
# -r requirements/pytest.txt
|
||||
# pytest-salt-factories
|
||||
pytest-skip-markers==1.5.2 ; python_version >= "3.8"
|
||||
# via
|
||||
# -r requirements/pytest.txt
|
||||
|
@ -525,7 +527,6 @@ typing-extensions==4.8.0
|
|||
# napalm
|
||||
# pydantic
|
||||
# pydantic-core
|
||||
# pytest-shell-utilities
|
||||
# pytest-system-statistics
|
||||
urllib3==1.26.18
|
||||
# via
|
||||
|
|
|
@ -307,7 +307,7 @@ portend==3.1.0
|
|||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.11/freebsd.txt
|
||||
# cherrypy
|
||||
psutil==5.9.6
|
||||
psutil==5.9.6 ; python_version >= "3.10"
|
||||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.11/freebsd.txt
|
||||
# -r requirements/base.txt
|
||||
|
@ -370,8 +370,10 @@ pytest-httpserver==1.0.8
|
|||
# via -r requirements/pytest.txt
|
||||
pytest-salt-factories==1.0.1
|
||||
# via -r requirements/pytest.txt
|
||||
pytest-shell-utilities==1.8.0
|
||||
# via pytest-salt-factories
|
||||
pytest-shell-utilities==1.9.7 ; python_version >= "3.10"
|
||||
# via
|
||||
# -r requirements/pytest.txt
|
||||
# pytest-salt-factories
|
||||
pytest-skip-markers==1.5.2 ; python_version >= "3.8"
|
||||
# via
|
||||
# -r requirements/pytest.txt
|
||||
|
@ -531,7 +533,6 @@ typing-extensions==4.8.0
|
|||
# napalm
|
||||
# pydantic
|
||||
# pydantic-core
|
||||
# pytest-shell-utilities
|
||||
# pytest-system-statistics
|
||||
urllib3==1.26.18
|
||||
# via
|
||||
|
|
|
@ -331,7 +331,7 @@ portend==3.1.0
|
|||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.11/linux.txt
|
||||
# cherrypy
|
||||
psutil==5.9.6
|
||||
psutil==5.9.6 ; python_version >= "3.10"
|
||||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.11/linux.txt
|
||||
# -r requirements/base.txt
|
||||
|
@ -402,8 +402,10 @@ pytest-httpserver==1.0.8
|
|||
# via -r requirements/pytest.txt
|
||||
pytest-salt-factories==1.0.1
|
||||
# via -r requirements/pytest.txt
|
||||
pytest-shell-utilities==1.8.0
|
||||
# via pytest-salt-factories
|
||||
pytest-shell-utilities==1.9.7 ; python_version >= "3.10"
|
||||
# via
|
||||
# -r requirements/pytest.txt
|
||||
# pytest-salt-factories
|
||||
pytest-skip-markers==1.5.2 ; python_version >= "3.8"
|
||||
# via
|
||||
# -r requirements/pytest.txt
|
||||
|
@ -593,7 +595,6 @@ typing-extensions==4.8.0
|
|||
# napalm
|
||||
# pydantic
|
||||
# pydantic-core
|
||||
# pytest-shell-utilities
|
||||
# pytest-system-statistics
|
||||
urllib3==1.26.18
|
||||
# via
|
||||
|
|
|
@ -265,7 +265,7 @@ portend==3.1.0
|
|||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.11/windows.txt
|
||||
# cherrypy
|
||||
psutil==5.9.6
|
||||
psutil==5.9.6 ; python_version >= "3.10"
|
||||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.11/windows.txt
|
||||
# -r requirements/base.txt
|
||||
|
@ -328,8 +328,10 @@ pytest-httpserver==1.0.8
|
|||
# via -r requirements/pytest.txt
|
||||
pytest-salt-factories==1.0.1
|
||||
# via -r requirements/pytest.txt
|
||||
pytest-shell-utilities==1.8.0
|
||||
# via pytest-salt-factories
|
||||
pytest-shell-utilities==1.9.7 ; python_version >= "3.10"
|
||||
# via
|
||||
# -r requirements/pytest.txt
|
||||
# pytest-salt-factories
|
||||
pytest-skip-markers==1.5.2 ; python_version >= "3.8"
|
||||
# via
|
||||
# -r requirements/pytest.txt
|
||||
|
@ -477,7 +479,6 @@ typing-extensions==4.8.0
|
|||
# inflect
|
||||
# pydantic
|
||||
# pydantic-core
|
||||
# pytest-shell-utilities
|
||||
# pytest-system-statistics
|
||||
urllib3==1.26.18
|
||||
# via
|
||||
|
|
|
@ -427,7 +427,7 @@ portend==3.1.0
|
|||
# cherrypy
|
||||
profitbricks==4.1.3
|
||||
# via -r requirements/static/ci/cloud.in
|
||||
psutil==5.9.6
|
||||
psutil==5.9.6 ; python_version >= "3.10"
|
||||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.12/linux.txt
|
||||
# -c requirements/static/ci/py3.12/linux.txt
|
||||
|
@ -525,9 +525,10 @@ pytest-salt-factories==1.0.1
|
|||
# via
|
||||
# -c requirements/static/ci/py3.12/linux.txt
|
||||
# -r requirements/pytest.txt
|
||||
pytest-shell-utilities==1.8.0
|
||||
pytest-shell-utilities==1.9.7 ; python_version >= "3.10"
|
||||
# via
|
||||
# -c requirements/static/ci/py3.12/linux.txt
|
||||
# -r requirements/pytest.txt
|
||||
# pytest-salt-factories
|
||||
pytest-skip-markers==1.5.2 ; python_version >= "3.8"
|
||||
# via
|
||||
|
@ -758,7 +759,6 @@ typing-extensions==4.8.0
|
|||
# napalm
|
||||
# pydantic
|
||||
# pydantic-core
|
||||
# pytest-shell-utilities
|
||||
# pytest-system-statistics
|
||||
urllib3==1.26.18
|
||||
# via
|
||||
|
|
|
@ -303,7 +303,7 @@ portend==3.1.0
|
|||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.12/darwin.txt
|
||||
# cherrypy
|
||||
psutil==5.9.6
|
||||
psutil==5.9.6 ; python_version >= "3.10"
|
||||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.12/darwin.txt
|
||||
# -r requirements/base.txt
|
||||
|
@ -366,8 +366,10 @@ pytest-httpserver==1.0.8
|
|||
# via -r requirements/pytest.txt
|
||||
pytest-salt-factories==1.0.1
|
||||
# via -r requirements/pytest.txt
|
||||
pytest-shell-utilities==1.8.0
|
||||
# via pytest-salt-factories
|
||||
pytest-shell-utilities==1.9.7 ; python_version >= "3.10"
|
||||
# via
|
||||
# -r requirements/pytest.txt
|
||||
# pytest-salt-factories
|
||||
pytest-skip-markers==1.5.2 ; python_version >= "3.8"
|
||||
# via
|
||||
# -r requirements/pytest.txt
|
||||
|
@ -525,7 +527,6 @@ typing-extensions==4.8.0
|
|||
# napalm
|
||||
# pydantic
|
||||
# pydantic-core
|
||||
# pytest-shell-utilities
|
||||
# pytest-system-statistics
|
||||
urllib3==1.26.18
|
||||
# via
|
||||
|
|
|
@ -168,7 +168,7 @@ portend==3.1.0
|
|||
# via
|
||||
# -c requirements/static/ci/py3.12/linux.txt
|
||||
# cherrypy
|
||||
psutil==5.9.6
|
||||
psutil==5.9.6 ; python_version >= "3.10"
|
||||
# via
|
||||
# -c requirements/static/ci/py3.12/linux.txt
|
||||
# -r requirements/base.txt
|
||||
|
|
|
@ -307,7 +307,7 @@ portend==3.1.0
|
|||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.12/freebsd.txt
|
||||
# cherrypy
|
||||
psutil==5.9.6
|
||||
psutil==5.9.6 ; python_version >= "3.10"
|
||||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.12/freebsd.txt
|
||||
# -r requirements/base.txt
|
||||
|
@ -370,8 +370,10 @@ pytest-httpserver==1.0.8
|
|||
# via -r requirements/pytest.txt
|
||||
pytest-salt-factories==1.0.1
|
||||
# via -r requirements/pytest.txt
|
||||
pytest-shell-utilities==1.8.0
|
||||
# via pytest-salt-factories
|
||||
pytest-shell-utilities==1.9.7 ; python_version >= "3.10"
|
||||
# via
|
||||
# -r requirements/pytest.txt
|
||||
# pytest-salt-factories
|
||||
pytest-skip-markers==1.5.2 ; python_version >= "3.8"
|
||||
# via
|
||||
# -r requirements/pytest.txt
|
||||
|
@ -531,7 +533,6 @@ typing-extensions==4.8.0
|
|||
# napalm
|
||||
# pydantic
|
||||
# pydantic-core
|
||||
# pytest-shell-utilities
|
||||
# pytest-system-statistics
|
||||
urllib3==1.26.18
|
||||
# via
|
||||
|
|
|
@ -453,7 +453,7 @@ portend==3.1.0
|
|||
# -c requirements/static/ci/../pkg/py3.12/linux.txt
|
||||
# -c requirements/static/ci/py3.12/linux.txt
|
||||
# cherrypy
|
||||
psutil==5.9.6
|
||||
psutil==5.9.6 ; python_version >= "3.10"
|
||||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.12/linux.txt
|
||||
# -c requirements/static/ci/py3.12/linux.txt
|
||||
|
|
|
@ -331,7 +331,7 @@ portend==3.1.0
|
|||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.12/linux.txt
|
||||
# cherrypy
|
||||
psutil==5.9.6
|
||||
psutil==5.9.6 ; python_version >= "3.10"
|
||||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.12/linux.txt
|
||||
# -r requirements/base.txt
|
||||
|
@ -402,8 +402,10 @@ pytest-httpserver==1.0.8
|
|||
# via -r requirements/pytest.txt
|
||||
pytest-salt-factories==1.0.1
|
||||
# via -r requirements/pytest.txt
|
||||
pytest-shell-utilities==1.8.0
|
||||
# via pytest-salt-factories
|
||||
pytest-shell-utilities==1.9.7 ; python_version >= "3.10"
|
||||
# via
|
||||
# -r requirements/pytest.txt
|
||||
# pytest-salt-factories
|
||||
pytest-skip-markers==1.5.2 ; python_version >= "3.8"
|
||||
# via
|
||||
# -r requirements/pytest.txt
|
||||
|
@ -593,7 +595,6 @@ typing-extensions==4.8.0
|
|||
# napalm
|
||||
# pydantic
|
||||
# pydantic-core
|
||||
# pytest-shell-utilities
|
||||
# pytest-system-statistics
|
||||
urllib3==1.26.18
|
||||
# via
|
||||
|
|
|
@ -265,7 +265,7 @@ portend==3.1.0
|
|||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.12/windows.txt
|
||||
# cherrypy
|
||||
psutil==5.9.6
|
||||
psutil==5.9.6 ; python_version >= "3.10"
|
||||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.12/windows.txt
|
||||
# -r requirements/base.txt
|
||||
|
@ -328,8 +328,10 @@ pytest-httpserver==1.0.8
|
|||
# via -r requirements/pytest.txt
|
||||
pytest-salt-factories==1.0.1
|
||||
# via -r requirements/pytest.txt
|
||||
pytest-shell-utilities==1.8.0
|
||||
# via pytest-salt-factories
|
||||
pytest-shell-utilities==1.9.7 ; python_version >= "3.10"
|
||||
# via
|
||||
# -r requirements/pytest.txt
|
||||
# pytest-salt-factories
|
||||
pytest-skip-markers==1.5.2 ; python_version >= "3.8"
|
||||
# via
|
||||
# -r requirements/pytest.txt
|
||||
|
@ -477,7 +479,6 @@ typing-extensions==4.8.0
|
|||
# inflect
|
||||
# pydantic
|
||||
# pydantic-core
|
||||
# pytest-shell-utilities
|
||||
# pytest-system-statistics
|
||||
urllib3==1.26.18
|
||||
# via
|
||||
|
|
|
@ -318,7 +318,7 @@ portend==3.1.0
|
|||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.8/freebsd.txt
|
||||
# cherrypy
|
||||
psutil==5.9.6
|
||||
psutil==5.9.6 ; python_version <= "3.9"
|
||||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.8/freebsd.txt
|
||||
# -r requirements/base.txt
|
||||
|
@ -381,8 +381,10 @@ pytest-httpserver==1.0.8
|
|||
# via -r requirements/pytest.txt
|
||||
pytest-salt-factories==1.0.1
|
||||
# via -r requirements/pytest.txt
|
||||
pytest-shell-utilities==1.8.0
|
||||
# via pytest-salt-factories
|
||||
pytest-shell-utilities==1.8.0 ; python_version <= "3.9"
|
||||
# via
|
||||
# -r requirements/pytest.txt
|
||||
# pytest-salt-factories
|
||||
pytest-skip-markers==1.5.2 ; python_version >= "3.8"
|
||||
# via
|
||||
# -r requirements/pytest.txt
|
||||
|
|
|
@ -337,7 +337,7 @@ portend==3.1.0
|
|||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.8/linux.txt
|
||||
# cherrypy
|
||||
psutil==5.9.6
|
||||
psutil==5.9.6 ; python_version <= "3.9"
|
||||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.8/linux.txt
|
||||
# -r requirements/base.txt
|
||||
|
@ -408,8 +408,10 @@ pytest-httpserver==1.0.8
|
|||
# via -r requirements/pytest.txt
|
||||
pytest-salt-factories==1.0.1
|
||||
# via -r requirements/pytest.txt
|
||||
pytest-shell-utilities==1.8.0
|
||||
# via pytest-salt-factories
|
||||
pytest-shell-utilities==1.8.0 ; python_version <= "3.9"
|
||||
# via
|
||||
# -r requirements/pytest.txt
|
||||
# pytest-salt-factories
|
||||
pytest-skip-markers==1.5.2 ; python_version >= "3.8"
|
||||
# via
|
||||
# -r requirements/pytest.txt
|
||||
|
|
|
@ -276,7 +276,7 @@ portend==3.1.0
|
|||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.8/windows.txt
|
||||
# cherrypy
|
||||
psutil==5.9.6
|
||||
psutil==5.9.6 ; python_version <= "3.9"
|
||||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.8/windows.txt
|
||||
# -r requirements/base.txt
|
||||
|
@ -339,8 +339,10 @@ pytest-httpserver==1.0.8
|
|||
# via -r requirements/pytest.txt
|
||||
pytest-salt-factories==1.0.1
|
||||
# via -r requirements/pytest.txt
|
||||
pytest-shell-utilities==1.8.0
|
||||
# via pytest-salt-factories
|
||||
pytest-shell-utilities==1.8.0 ; python_version <= "3.9"
|
||||
# via
|
||||
# -r requirements/pytest.txt
|
||||
# pytest-salt-factories
|
||||
pytest-skip-markers==1.5.2 ; python_version >= "3.8"
|
||||
# via
|
||||
# -r requirements/pytest.txt
|
||||
|
|
|
@ -310,7 +310,7 @@ portend==3.1.0
|
|||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.9/darwin.txt
|
||||
# cherrypy
|
||||
psutil==5.9.6
|
||||
psutil==5.9.6 ; python_version <= "3.9"
|
||||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.9/darwin.txt
|
||||
# -r requirements/base.txt
|
||||
|
@ -373,8 +373,10 @@ pytest-httpserver==1.0.8
|
|||
# via -r requirements/pytest.txt
|
||||
pytest-salt-factories==1.0.1
|
||||
# via -r requirements/pytest.txt
|
||||
pytest-shell-utilities==1.8.0
|
||||
# via pytest-salt-factories
|
||||
pytest-shell-utilities==1.8.0 ; python_version <= "3.9"
|
||||
# via
|
||||
# -r requirements/pytest.txt
|
||||
# pytest-salt-factories
|
||||
pytest-skip-markers==1.5.2 ; python_version >= "3.8"
|
||||
# via
|
||||
# -r requirements/pytest.txt
|
||||
|
|
|
@ -314,7 +314,7 @@ portend==3.1.0
|
|||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.9/freebsd.txt
|
||||
# cherrypy
|
||||
psutil==5.9.6
|
||||
psutil==5.9.6 ; python_version <= "3.9"
|
||||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.9/freebsd.txt
|
||||
# -r requirements/base.txt
|
||||
|
@ -377,8 +377,10 @@ pytest-httpserver==1.0.8
|
|||
# via -r requirements/pytest.txt
|
||||
pytest-salt-factories==1.0.1
|
||||
# via -r requirements/pytest.txt
|
||||
pytest-shell-utilities==1.8.0
|
||||
# via pytest-salt-factories
|
||||
pytest-shell-utilities==1.8.0 ; python_version <= "3.9"
|
||||
# via
|
||||
# -r requirements/pytest.txt
|
||||
# pytest-salt-factories
|
||||
pytest-skip-markers==1.5.2 ; python_version >= "3.8"
|
||||
# via
|
||||
# -r requirements/pytest.txt
|
||||
|
|
|
@ -333,7 +333,7 @@ portend==3.1.0
|
|||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.9/linux.txt
|
||||
# cherrypy
|
||||
psutil==5.9.6
|
||||
psutil==5.9.6 ; python_version <= "3.9"
|
||||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.9/linux.txt
|
||||
# -r requirements/base.txt
|
||||
|
@ -404,8 +404,10 @@ pytest-httpserver==1.0.8
|
|||
# via -r requirements/pytest.txt
|
||||
pytest-salt-factories==1.0.1
|
||||
# via -r requirements/pytest.txt
|
||||
pytest-shell-utilities==1.8.0
|
||||
# via pytest-salt-factories
|
||||
pytest-shell-utilities==1.8.0 ; python_version <= "3.9"
|
||||
# via
|
||||
# -r requirements/pytest.txt
|
||||
# pytest-salt-factories
|
||||
pytest-skip-markers==1.5.2 ; python_version >= "3.8"
|
||||
# via
|
||||
# -r requirements/pytest.txt
|
||||
|
|
|
@ -272,7 +272,7 @@ portend==3.1.0
|
|||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.9/windows.txt
|
||||
# cherrypy
|
||||
psutil==5.9.6
|
||||
psutil==5.9.6 ; python_version <= "3.9"
|
||||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.9/windows.txt
|
||||
# -r requirements/base.txt
|
||||
|
@ -335,8 +335,10 @@ pytest-httpserver==1.0.8
|
|||
# via -r requirements/pytest.txt
|
||||
pytest-salt-factories==1.0.1
|
||||
# via -r requirements/pytest.txt
|
||||
pytest-shell-utilities==1.8.0
|
||||
# via pytest-salt-factories
|
||||
pytest-shell-utilities==1.8.0 ; python_version <= "3.9"
|
||||
# via
|
||||
# -r requirements/pytest.txt
|
||||
# pytest-salt-factories
|
||||
pytest-skip-markers==1.5.2 ; python_version >= "3.8"
|
||||
# via
|
||||
# -r requirements/pytest.txt
|
||||
|
|
|
@ -89,7 +89,7 @@ packaging==23.1
|
|||
# via -r requirements/base.txt
|
||||
portend==3.1.0
|
||||
# via cherrypy
|
||||
psutil==5.9.6
|
||||
psutil==5.9.6 ; python_version >= "3.10"
|
||||
# via -r requirements/base.txt
|
||||
pycparser==2.21
|
||||
# via cffi
|
||||
|
|
|
@ -89,7 +89,7 @@ packaging==23.1
|
|||
# via -r requirements/base.txt
|
||||
portend==3.1.0
|
||||
# via cherrypy
|
||||
psutil==5.9.6
|
||||
psutil==5.9.6 ; python_version >= "3.10"
|
||||
# via -r requirements/base.txt
|
||||
pycparser==2.21
|
||||
# via cffi
|
||||
|
|
|
@ -89,7 +89,7 @@ packaging==23.1
|
|||
# via -r requirements/base.txt
|
||||
portend==3.1.0
|
||||
# via cherrypy
|
||||
psutil==5.9.6
|
||||
psutil==5.9.6 ; python_version >= "3.10"
|
||||
# via -r requirements/base.txt
|
||||
pycparser==2.21
|
||||
# via cffi
|
||||
|
|
|
@ -97,7 +97,7 @@ packaging==23.1
|
|||
# via -r requirements/base.txt
|
||||
portend==3.1.0
|
||||
# via cherrypy
|
||||
psutil==5.9.6
|
||||
psutil==5.9.6 ; python_version >= "3.10"
|
||||
# via -r requirements/base.txt
|
||||
pycparser==2.21
|
||||
# via cffi
|
||||
|
|
|
@ -87,7 +87,7 @@ packaging==23.1
|
|||
# via -r requirements/base.txt
|
||||
portend==3.1.0
|
||||
# via cherrypy
|
||||
psutil==5.9.6
|
||||
psutil==5.9.6 ; python_version >= "3.10"
|
||||
# via -r requirements/base.txt
|
||||
pycparser==2.21
|
||||
# via cffi
|
||||
|
|
|
@ -87,7 +87,7 @@ packaging==23.1
|
|||
# via -r requirements/base.txt
|
||||
portend==3.1.0
|
||||
# via cherrypy
|
||||
psutil==5.9.6
|
||||
psutil==5.9.6 ; python_version >= "3.10"
|
||||
# via -r requirements/base.txt
|
||||
pycparser==2.21
|
||||
# via cffi
|
||||
|
|
|
@ -87,7 +87,7 @@ packaging==23.1
|
|||
# via -r requirements/base.txt
|
||||
portend==3.1.0
|
||||
# via cherrypy
|
||||
psutil==5.9.6
|
||||
psutil==5.9.6 ; python_version >= "3.10"
|
||||
# via -r requirements/base.txt
|
||||
pycparser==2.21
|
||||
# via cffi
|
||||
|
|
|
@ -95,7 +95,7 @@ packaging==23.1
|
|||
# via -r requirements/base.txt
|
||||
portend==3.1.0
|
||||
# via cherrypy
|
||||
psutil==5.9.6
|
||||
psutil==5.9.6 ; python_version >= "3.10"
|
||||
# via -r requirements/base.txt
|
||||
pycparser==2.21
|
||||
# via cffi
|
||||
|
|
|
@ -87,7 +87,7 @@ packaging==23.1
|
|||
# via -r requirements/base.txt
|
||||
portend==3.1.0
|
||||
# via cherrypy
|
||||
psutil==5.9.6
|
||||
psutil==5.9.6 ; python_version >= "3.10"
|
||||
# via -r requirements/base.txt
|
||||
pycparser==2.21
|
||||
# via cffi
|
||||
|
|
|
@ -87,7 +87,7 @@ packaging==23.1
|
|||
# via -r requirements/base.txt
|
||||
portend==3.1.0
|
||||
# via cherrypy
|
||||
psutil==5.9.6
|
||||
psutil==5.9.6 ; python_version >= "3.10"
|
||||
# via -r requirements/base.txt
|
||||
pycparser==2.21
|
||||
# via cffi
|
||||
|
|
|
@ -87,7 +87,7 @@ packaging==23.1
|
|||
# via -r requirements/base.txt
|
||||
portend==3.1.0
|
||||
# via cherrypy
|
||||
psutil==5.9.6
|
||||
psutil==5.9.6 ; python_version >= "3.10"
|
||||
# via -r requirements/base.txt
|
||||
pycparser==2.21
|
||||
# via cffi
|
||||
|
|
|
@ -95,7 +95,7 @@ packaging==23.1
|
|||
# via -r requirements/base.txt
|
||||
portend==3.1.0
|
||||
# via cherrypy
|
||||
psutil==5.9.6
|
||||
psutil==5.9.6 ; python_version >= "3.10"
|
||||
# via -r requirements/base.txt
|
||||
pycparser==2.21
|
||||
# via cffi
|
||||
|
|
|
@ -91,7 +91,7 @@ packaging==23.1
|
|||
# via -r requirements/base.txt
|
||||
portend==3.1.0
|
||||
# via cherrypy
|
||||
psutil==5.9.6
|
||||
psutil==5.9.6 ; python_version <= "3.9"
|
||||
# via -r requirements/base.txt
|
||||
pycparser==2.21
|
||||
# via cffi
|
||||
|
|
|
@ -91,7 +91,7 @@ packaging==23.1
|
|||
# via -r requirements/base.txt
|
||||
portend==3.1.0
|
||||
# via cherrypy
|
||||
psutil==5.9.6
|
||||
psutil==5.9.6 ; python_version <= "3.9"
|
||||
# via -r requirements/base.txt
|
||||
pycparser==2.21
|
||||
# via cffi
|
||||
|
|
|
@ -99,7 +99,7 @@ packaging==23.1
|
|||
# via -r requirements/base.txt
|
||||
portend==3.1.0
|
||||
# via cherrypy
|
||||
psutil==5.9.6
|
||||
psutil==5.9.6 ; python_version <= "3.9"
|
||||
# via -r requirements/base.txt
|
||||
pycparser==2.21
|
||||
# via cffi
|
||||
|
|
|
@ -89,7 +89,7 @@ packaging==23.1
|
|||
# via -r requirements/base.txt
|
||||
portend==3.1.0
|
||||
# via cherrypy
|
||||
psutil==5.9.6
|
||||
psutil==5.9.6 ; python_version <= "3.9"
|
||||
# via -r requirements/base.txt
|
||||
pycparser==2.21
|
||||
# via cffi
|
||||
|
|
|
@ -89,7 +89,7 @@ packaging==23.1
|
|||
# via -r requirements/base.txt
|
||||
portend==3.1.0
|
||||
# via cherrypy
|
||||
psutil==5.9.6
|
||||
psutil==5.9.6 ; python_version <= "3.9"
|
||||
# via -r requirements/base.txt
|
||||
pycparser==2.21
|
||||
# via cffi
|
||||
|
|
|
@ -89,7 +89,7 @@ packaging==23.1
|
|||
# via -r requirements/base.txt
|
||||
portend==3.1.0
|
||||
# via cherrypy
|
||||
psutil==5.9.6
|
||||
psutil==5.9.6 ; python_version <= "3.9"
|
||||
# via -r requirements/base.txt
|
||||
pycparser==2.21
|
||||
# via cffi
|
||||
|
|
|
@ -97,7 +97,7 @@ packaging==23.1
|
|||
# via -r requirements/base.txt
|
||||
portend==3.1.0
|
||||
# via cherrypy
|
||||
psutil==5.9.6
|
||||
psutil==5.9.6 ; python_version <= "3.9"
|
||||
# via -r requirements/base.txt
|
||||
pycparser==2.21
|
||||
# via cffi
|
||||
|
|
|
@ -16,6 +16,7 @@ import salt.utils.platform
|
|||
__salt__ = {
|
||||
"cmd.run": salt.modules.cmdmod._run_quiet,
|
||||
"cmd.run_all": salt.modules.cmdmod._run_all_quiet,
|
||||
"cmd.powershell": salt.modules.cmdmod.powershell,
|
||||
}
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
@ -153,41 +154,28 @@ def _linux_disks():
|
|||
|
||||
|
||||
def _windows_disks():
|
||||
wmic = salt.utils.path.which("wmic")
|
||||
|
||||
namespace = r"\\root\microsoft\windows\storage"
|
||||
path = "MSFT_PhysicalDisk"
|
||||
get = "DeviceID,MediaType"
|
||||
|
||||
cmd = "Get-PhysicalDisk | Select DeviceID, MediaType"
|
||||
ret = {"disks": [], "ssds": []}
|
||||
|
||||
cmdret = __salt__["cmd.run_all"](
|
||||
"{} /namespace:{} path {} get {} /format:table".format(
|
||||
wmic, namespace, path, get
|
||||
)
|
||||
)
|
||||
drive_info = __salt__["cmd.powershell"](cmd)
|
||||
|
||||
if cmdret["retcode"] != 0:
|
||||
log.trace("Disk grain does not support this version of Windows")
|
||||
else:
|
||||
for line in cmdret["stdout"].splitlines():
|
||||
info = line.split()
|
||||
if len(info) != 2 or not info[0].isdigit() or not info[1].isdigit():
|
||||
continue
|
||||
device = rf"\\.\PhysicalDrive{info[0]}"
|
||||
mediatype = info[1]
|
||||
if mediatype == "3":
|
||||
log.trace("Device %s reports itself as an HDD", device)
|
||||
ret["disks"].append(device)
|
||||
elif mediatype == "4":
|
||||
log.trace("Device %s reports itself as an SSD", device)
|
||||
ret["ssds"].append(device)
|
||||
ret["disks"].append(device)
|
||||
elif mediatype == "5":
|
||||
log.trace("Device %s reports itself as an SCM", device)
|
||||
ret["disks"].append(device)
|
||||
else:
|
||||
log.trace("Device %s reports itself as Unspecified", device)
|
||||
ret["disks"].append(device)
|
||||
if not drive_info:
|
||||
log.trace("No physical discs found")
|
||||
return ret
|
||||
|
||||
# We need a list of dict
|
||||
if isinstance(drive_info, dict):
|
||||
drive_info = [drive_info]
|
||||
|
||||
for drive in drive_info:
|
||||
# Make sure we have a valid drive type
|
||||
if drive["MediaType"].lower() not in ["hdd", "ssd", "scm", "unspecified"]:
|
||||
log.trace(f'Unknown media type: {drive["MediaType"]}')
|
||||
continue
|
||||
device = rf'\\.\PhysicalDrive{drive["DeviceID"]}'
|
||||
ret["disks"].append(device)
|
||||
if drive["MediaType"].lower() == "ssd":
|
||||
ret["ssds"].append(device)
|
||||
|
||||
return ret
|
||||
|
|
|
@ -85,28 +85,25 @@ def _aix_iqn():
|
|||
|
||||
def _windows_iqn():
|
||||
"""
|
||||
Return iSCSI IQN from a Windows host.
|
||||
Return iSCSI nodes from a Windows host.
|
||||
"""
|
||||
cmd = "Get-InitiatorPort | Select NodeAddress"
|
||||
ret = []
|
||||
|
||||
wmic = salt.utils.path.which("wmic")
|
||||
nodes = salt.modules.cmdmod.powershell(cmd)
|
||||
|
||||
if not wmic:
|
||||
if not nodes:
|
||||
log.trace("No iSCSI nodes found")
|
||||
return ret
|
||||
|
||||
namespace = r"\\root\WMI"
|
||||
path = "MSiSCSIInitiator_MethodClass"
|
||||
get = "iSCSINodeName"
|
||||
# A single node will return a dictionary with a single entry
|
||||
# {"NodeAddress": "iqn.1991-05.com.microsoft:johnj99-pc2.contoso.com"}
|
||||
# Multiple nodes will return a list of single entry dicts
|
||||
# We need a list of dict
|
||||
if isinstance(nodes, dict):
|
||||
nodes = [nodes]
|
||||
|
||||
cmd_ret = salt.modules.cmdmod.run_all(
|
||||
"{} /namespace:{} path {} get {} /format:table".format(
|
||||
wmic, namespace, path, get
|
||||
)
|
||||
)
|
||||
|
||||
for line in cmd_ret["stdout"].splitlines():
|
||||
if line.startswith("iqn."):
|
||||
line = line.rstrip()
|
||||
ret.append(line.rstrip())
|
||||
for node in nodes:
|
||||
ret.append(node["NodeAddress"])
|
||||
|
||||
return ret
|
||||
|
|
|
@ -266,7 +266,7 @@ def _prep_powershell_cmd(win_shell, cmd, encoded_cmd):
|
|||
win_shell = salt.utils.path.which(win_shell)
|
||||
|
||||
if not win_shell:
|
||||
raise CommandExecutionError("PowerShell binary not found")
|
||||
raise CommandExecutionError(f"PowerShell binary not found: {win_shell}")
|
||||
|
||||
new_cmd = [win_shell, "-NonInteractive", "-NoProfile", "-ExecutionPolicy", "Bypass"]
|
||||
|
||||
|
|
|
@ -490,7 +490,7 @@ def fcontext_get_policy(
|
|||
"[[:alpha:] ]+" if filetype is None else filetype_id_to_string(filetype)
|
||||
)
|
||||
cmd = (
|
||||
"semanage fcontext -l | egrep "
|
||||
"semanage fcontext -l | grep -E "
|
||||
+ "'^{filespec}{spacer}{filetype}{spacer}{sel_user}:{sel_role}:{sel_type}:{sel_level}{ospacer}$'".format(
|
||||
**cmd_kwargs
|
||||
)
|
||||
|
@ -616,7 +616,7 @@ def _fcontext_add_or_delete_policy(
|
|||
if "add" == action:
|
||||
# need to use --modify if context for name file exists, otherwise ValueError
|
||||
filespec = re.escape(name)
|
||||
cmd = f"semanage fcontext -l | egrep '{filespec}'"
|
||||
cmd = f"semanage fcontext -l | grep -E '{filespec} '"
|
||||
current_entry_text = __salt__["cmd.shell"](cmd, ignore_retcode=True)
|
||||
if current_entry_text != "":
|
||||
action = "modify"
|
||||
|
@ -762,7 +762,7 @@ def port_get_policy(name, sel_type=None, protocol=None, port=None):
|
|||
"port": port,
|
||||
}
|
||||
cmd = (
|
||||
"semanage port -l | egrep "
|
||||
"semanage port -l | grep -E "
|
||||
+ "'^{sel_type}{spacer}{protocol}{spacer}((.*)*)[ ]{port}($|,)'".format(
|
||||
**cmd_kwargs
|
||||
)
|
||||
|
|
|
@ -318,7 +318,8 @@ def _get_options(**kwargs):
|
|||
ret.append(f"--branch={branch}")
|
||||
|
||||
for item in setopt:
|
||||
ret.extend(["--setopt", str(item)])
|
||||
log.info("Adding configuration option '%s'", item)
|
||||
ret.extend([f"--setopt={item}"])
|
||||
|
||||
if get_extra_options:
|
||||
# sorting here to make order uniform, makes unit testing more reliable
|
||||
|
|
|
@ -18,6 +18,7 @@ import importlib
|
|||
import inspect
|
||||
import logging
|
||||
import os
|
||||
import pickle
|
||||
import random
|
||||
import re
|
||||
import site
|
||||
|
@ -757,21 +758,21 @@ class State:
|
|||
loader="states",
|
||||
initial_pillar=None,
|
||||
file_client=None,
|
||||
__invocation_id=None,
|
||||
_invocation_id=None,
|
||||
):
|
||||
"""
|
||||
When instantiating an object of this class, do not pass
|
||||
``__invocation_id``. It is an internal field for tracking
|
||||
``_invocation_id``. It is an internal field for tracking
|
||||
parallel executions where no jid is available (Salt-SSH) and
|
||||
only exposed as an init argument to work on spawning platforms.
|
||||
"""
|
||||
if jid is not None:
|
||||
__invocation_id = jid
|
||||
if __invocation_id is None:
|
||||
_invocation_id = jid
|
||||
if _invocation_id is None:
|
||||
# For salt-ssh parallel states, we need a unique identifier
|
||||
# for a single execution. self.jid should not be set there
|
||||
# since it's used for other purposes as well.
|
||||
__invocation_id = salt.utils.jid.gen_jid(opts)
|
||||
_invocation_id = salt.utils.jid.gen_jid(opts)
|
||||
self._init_kwargs = {
|
||||
"opts": opts,
|
||||
"pillar_override": pillar_override,
|
||||
|
@ -782,7 +783,7 @@ class State:
|
|||
"mocked": mocked,
|
||||
"loader": loader,
|
||||
"initial_pillar": initial_pillar,
|
||||
"__invocation_id": __invocation_id,
|
||||
"_invocation_id": _invocation_id,
|
||||
}
|
||||
self.states_loader = loader
|
||||
if "grains" not in opts:
|
||||
|
@ -829,7 +830,7 @@ class State:
|
|||
self.pre = {}
|
||||
self.__run_num = 0
|
||||
self.jid = jid
|
||||
self.invocation_id = __invocation_id
|
||||
self.invocation_id = _invocation_id
|
||||
self.instance_id = str(id(self))
|
||||
self.inject_globals = {}
|
||||
self.mocked = mocked
|
||||
|
@ -2157,12 +2158,15 @@ class State:
|
|||
return req_in_high, errors
|
||||
|
||||
@classmethod
|
||||
def _call_parallel_target(cls, instance, init_kwargs, name, cdata, low):
|
||||
def _call_parallel_target(
|
||||
cls, instance, init_kwargs, name, cdata, low, inject_globals
|
||||
):
|
||||
"""
|
||||
The target function to call that will create the parallel thread/process
|
||||
"""
|
||||
if instance is None:
|
||||
instance = cls(**init_kwargs)
|
||||
instance.states.inject_globals = inject_globals
|
||||
# we need to re-record start/end duration here because it is impossible to
|
||||
# correctly calculate further down the chain
|
||||
utc_start_time = datetime.datetime.utcnow()
|
||||
|
@ -2267,7 +2271,7 @@ class State:
|
|||
with salt.utils.files.fopen(tfile, "wb+") as fp_:
|
||||
fp_.write(msgpack_serialize(ret))
|
||||
|
||||
def call_parallel(self, cdata, low):
|
||||
def call_parallel(self, cdata, low, inject_globals):
|
||||
"""
|
||||
Call the state defined in the given cdata in parallel
|
||||
"""
|
||||
|
@ -2284,13 +2288,37 @@ class State:
|
|||
instance = None
|
||||
else:
|
||||
instance = self
|
||||
inject_globals = None
|
||||
|
||||
proc = salt.utils.process.Process(
|
||||
target=self._call_parallel_target,
|
||||
args=(instance, self._init_kwargs, name, cdata, low),
|
||||
args=(instance, self._init_kwargs, name, cdata, low, inject_globals),
|
||||
name=f"ParallelState({name})",
|
||||
)
|
||||
proc.start()
|
||||
try:
|
||||
proc.start()
|
||||
except TypeError as err:
|
||||
# Some modules use the context to cache unpicklable objects like
|
||||
# database connections or loader instances.
|
||||
# Ensure we don't crash because of that on spawning platforms.
|
||||
if "cannot pickle" not in str(err):
|
||||
raise
|
||||
clean_context = {}
|
||||
for var, val in self._init_kwargs["context"].items():
|
||||
try:
|
||||
pickle.dumps(val)
|
||||
except TypeError:
|
||||
pass
|
||||
else:
|
||||
clean_context[var] = val
|
||||
init_kwargs = self._init_kwargs.copy()
|
||||
init_kwargs["context"] = clean_context
|
||||
proc = salt.utils.process.Process(
|
||||
target=self._call_parallel_target,
|
||||
args=(instance, init_kwargs, name, cdata, low, inject_globals),
|
||||
name=f"ParallelState({name})",
|
||||
)
|
||||
proc.start()
|
||||
ret = {
|
||||
"name": name,
|
||||
"result": None,
|
||||
|
@ -2434,7 +2462,7 @@ class State:
|
|||
)
|
||||
elif not low.get("__prereq__") and low.get("parallel"):
|
||||
# run the state call in parallel, but only if not in a prereq
|
||||
ret = self.call_parallel(cdata, low)
|
||||
ret = self.call_parallel(cdata, low, inject_globals)
|
||||
else:
|
||||
self.format_slots(cdata)
|
||||
with salt.utils.files.set_umask(low.get("__umask__")):
|
||||
|
|
|
@ -708,9 +708,6 @@ def list_absent(name, acl_type, acl_names=None, recurse=False):
|
|||
acl_names
|
||||
The list of users or groups
|
||||
|
||||
perms
|
||||
Remove the permissions eg.: rwx
|
||||
|
||||
recurse
|
||||
Set the permissions recursive in the path
|
||||
|
||||
|
|
|
@ -203,7 +203,7 @@ def which(exe=None):
|
|||
|
||||
# now to search through our system_path
|
||||
for path in system_path:
|
||||
p = join(path, exe)
|
||||
p = join(os.path.expandvars(path), exe)
|
||||
|
||||
# iterate through all extensions to see which one is executable
|
||||
for ext in pathext:
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import copy
|
||||
import glob
|
||||
import logging
|
||||
import os
|
||||
|
@ -5,6 +6,7 @@ import re
|
|||
|
||||
from jinja2 import Environment, FileSystemLoader
|
||||
|
||||
import salt.utils.odict
|
||||
import salt.utils.path
|
||||
import salt.utils.yaml
|
||||
|
||||
|
@ -277,9 +279,27 @@ def expand_classes_glob(classes, salt_data):
|
|||
return expanded_classes
|
||||
|
||||
|
||||
def expand_classes_in_order(
|
||||
minion_dict, salt_data, seen_classes, expanded_classes, classes_to_expand
|
||||
):
|
||||
def expand_classes_in_order(minion_dict, salt_data, seen_classes, classes_to_expand):
|
||||
"""
|
||||
Expand the list of `classes_to_expand` and return them in the order found
|
||||
|
||||
The return order is `[C, B, A, M, B, L, MINION_ID]` when:
|
||||
|
||||
- minion node include classes `A` and `L`
|
||||
- `A` include class `B`
|
||||
- `B` include class `C`
|
||||
- `L` include class `M` and `B`
|
||||
|
||||
:param dict minion_dict: definition of minion node
|
||||
:param dict salt_data: configuration data
|
||||
:param iterable(str) seen_classes: classes already processed
|
||||
:param iterable(str) classes_to_expand: classes to recursivly expand
|
||||
:return: Expanded classes in proper order
|
||||
:rtype: salt.utils.odict.OrderedDict
|
||||
"""
|
||||
|
||||
expanded_classes = salt.utils.odict.OrderedDict()
|
||||
|
||||
# Get classes to expand from minion dictionary
|
||||
if not classes_to_expand and "classes" in minion_dict:
|
||||
classes_to_expand = minion_dict["classes"]
|
||||
|
@ -290,71 +310,37 @@ def expand_classes_in_order(
|
|||
for klass in classes_to_expand:
|
||||
if klass not in seen_classes:
|
||||
seen_classes.append(klass)
|
||||
expanded_classes[klass] = get_class(klass, salt_data)
|
||||
klass_dict = salt.utils.odict.OrderedDict(
|
||||
{klass: get_class(klass, salt_data)}
|
||||
)
|
||||
# Fix corner case where class is loaded but doesn't contain anything
|
||||
if expanded_classes[klass] is None:
|
||||
expanded_classes[klass] = {}
|
||||
if klass_dict[klass] is None:
|
||||
klass_dict[klass] = {}
|
||||
|
||||
# Merge newly found pillars into existing ones
|
||||
new_pillars = expanded_classes[klass].get("pillars", {})
|
||||
new_pillars = klass_dict[klass].get("pillars", {})
|
||||
if new_pillars:
|
||||
dict_merge(salt_data["__pillar__"], new_pillars)
|
||||
|
||||
# Now replace class element in classes_to_expand by expansion
|
||||
if expanded_classes[klass].get("classes"):
|
||||
l_id = classes_to_expand.index(klass)
|
||||
classes_to_expand[l_id:l_id] = expanded_classes[klass]["classes"]
|
||||
expand_classes_in_order(
|
||||
minion_dict,
|
||||
if "classes" in klass_dict[klass]:
|
||||
nested_classes = expand_classes_in_order(
|
||||
{},
|
||||
salt_data,
|
||||
seen_classes,
|
||||
expanded_classes,
|
||||
classes_to_expand,
|
||||
)
|
||||
else:
|
||||
expand_classes_in_order(
|
||||
minion_dict,
|
||||
salt_data,
|
||||
seen_classes,
|
||||
expanded_classes,
|
||||
classes_to_expand,
|
||||
klass_dict[klass].get("classes", {}),
|
||||
)
|
||||
|
||||
# We may have duplicates here and we want to remove them
|
||||
tmp = []
|
||||
for t_element in classes_to_expand:
|
||||
if t_element not in tmp:
|
||||
tmp.append(t_element)
|
||||
# Put current class after nested classes
|
||||
klass_dict.update(nested_classes)
|
||||
klass_dict.move_to_end(klass)
|
||||
|
||||
classes_to_expand = tmp
|
||||
expanded_classes.update(klass_dict)
|
||||
|
||||
# Now that we've retrieved every class in order,
|
||||
# let's return an ordered list of dicts
|
||||
ord_expanded_classes = []
|
||||
ord_expanded_states = []
|
||||
for ord_klass in classes_to_expand:
|
||||
ord_expanded_classes.append(expanded_classes[ord_klass])
|
||||
# And be smart and sort out states list
|
||||
# Address the corner case where states is empty in a class definition
|
||||
if (
|
||||
"states" in expanded_classes[ord_klass]
|
||||
and expanded_classes[ord_klass]["states"] is None
|
||||
):
|
||||
expanded_classes[ord_klass]["states"] = {}
|
||||
# Minion dict must be at the end
|
||||
if minion_dict:
|
||||
expanded_classes.update({salt_data["minion_id"]: minion_dict})
|
||||
|
||||
if "states" in expanded_classes[ord_klass]:
|
||||
ord_expanded_states.extend(expanded_classes[ord_klass]["states"])
|
||||
|
||||
# Add our minion dict as final element but check if we have states to process
|
||||
if "states" in minion_dict and minion_dict["states"] is None:
|
||||
minion_dict["states"] = []
|
||||
|
||||
if "states" in minion_dict:
|
||||
ord_expanded_states.extend(minion_dict["states"])
|
||||
|
||||
ord_expanded_classes.append(minion_dict)
|
||||
|
||||
return ord_expanded_classes, classes_to_expand, ord_expanded_states
|
||||
return expanded_classes
|
||||
|
||||
|
||||
def expanded_dict_from_minion(minion_id, salt_data):
|
||||
|
@ -377,22 +363,35 @@ def expanded_dict_from_minion(minion_id, salt_data):
|
|||
node_dict[minion_id] = {}
|
||||
|
||||
# Merge newly found pillars into existing ones
|
||||
dict_merge(salt_data["__pillar__"], node_dict[minion_id].get("pillars", {}))
|
||||
dict_merge(
|
||||
salt_data["__pillar__"], copy.deepcopy(node_dict[minion_id]).get("pillars", {})
|
||||
)
|
||||
|
||||
# Get 2 ordered lists:
|
||||
# expanded_classes: A list of all the dicts
|
||||
# classes_list: List of all the classes
|
||||
expanded_classes, classes_list, states_list = expand_classes_in_order(
|
||||
node_dict[minion_id], salt_data, [], {}, []
|
||||
)
|
||||
expanded_classes = expand_classes_in_order(node_dict[minion_id], salt_data, [], [])
|
||||
|
||||
# Here merge the pillars together
|
||||
pillars_dict = {}
|
||||
for exp_dict in expanded_classes:
|
||||
states_list = []
|
||||
classes_list = list(expanded_classes.keys())[:-1]
|
||||
classes_values = list(expanded_classes.values())
|
||||
for exp_dict in classes_values:
|
||||
if "pillars" in exp_dict:
|
||||
dict_merge(pillars_dict, exp_dict)
|
||||
if "states" in exp_dict:
|
||||
states_list.extend(exp_dict["states"])
|
||||
|
||||
return expanded_classes, pillars_dict, classes_list, states_list
|
||||
# Avoid duplicates, keep first
|
||||
state_seen = set()
|
||||
states_list = [
|
||||
state
|
||||
for state in states_list
|
||||
if not (state in state_seen or state_seen.add(state))
|
||||
]
|
||||
|
||||
return classes_values, pillars_dict, classes_list, states_list
|
||||
|
||||
|
||||
def get_pillars(minion_id, salt_data):
|
||||
|
|
|
@ -3,6 +3,7 @@ import os
|
|||
import textwrap
|
||||
import threading
|
||||
import time
|
||||
from textwrap import dedent
|
||||
|
||||
import pytest
|
||||
|
||||
|
@ -1081,3 +1082,97 @@ def test_state_sls_mock_ret(state_tree):
|
|||
ret["cmd_|-echo1_|-echo 'This is a test!'_|-run"]["comment"]
|
||||
== "Not called, mocked"
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def _state_requires_env(loaders, state_tree):
|
||||
mod_contents = dedent(
|
||||
r"""
|
||||
def test_it(name):
|
||||
return {
|
||||
"name": name,
|
||||
"result": __env__ == "base",
|
||||
"comment": "",
|
||||
"changes": {},
|
||||
}
|
||||
"""
|
||||
)
|
||||
sls = "test_spawning"
|
||||
sls_contents = dedent(
|
||||
"""
|
||||
This should not fail on spawning platforms:
|
||||
requires_env.test_it:
|
||||
- name: foo
|
||||
- parallel: true
|
||||
"""
|
||||
)
|
||||
with pytest.helpers.temp_file(
|
||||
f"{sls}.sls", sls_contents, state_tree
|
||||
), pytest.helpers.temp_file("_states/requires_env.py", mod_contents, state_tree):
|
||||
res = loaders.modules.saltutil.sync_states()
|
||||
assert "states.requires_env" in res
|
||||
yield sls
|
||||
|
||||
|
||||
def test_state_apply_parallel_spawning_with_global_dunders(state, _state_requires_env):
|
||||
"""
|
||||
Ensure state modules called via `parallel: true` have access to injected
|
||||
global dunders like `__env__`.
|
||||
"""
|
||||
ret = state.apply(_state_requires_env)
|
||||
assert (
|
||||
ret[
|
||||
"requires_env_|-This should not fail on spawning platforms_|-foo_|-test_it"
|
||||
]["result"]
|
||||
is True
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def _state_unpicklable_ctx(loaders, state_tree):
|
||||
mod_contents = dedent(
|
||||
r"""
|
||||
import threading
|
||||
|
||||
class Unpicklable:
|
||||
def __init__(self):
|
||||
self._lock = threading.RLock()
|
||||
|
||||
def test_it():
|
||||
__context__["booh"] = Unpicklable()
|
||||
"""
|
||||
)
|
||||
sls = "test_spawning_unpicklable"
|
||||
sls_contents = dedent(
|
||||
r"""
|
||||
{%- do salt["unpicklable.test_it"]() %}
|
||||
|
||||
This should not fail on spawning platforms:
|
||||
test.nop:
|
||||
- name: foo
|
||||
- parallel: true
|
||||
"""
|
||||
)
|
||||
with pytest.helpers.temp_file(
|
||||
f"{sls}.sls", sls_contents, state_tree
|
||||
), pytest.helpers.temp_file("_modules/unpicklable.py", mod_contents, state_tree):
|
||||
res = loaders.modules.saltutil.sync_modules()
|
||||
assert "modules.unpicklable" in res
|
||||
yield sls
|
||||
|
||||
|
||||
@pytest.mark.skip_unless_on_spawning_platform(
|
||||
reason="Pickling is only relevant on spawning platforms"
|
||||
)
|
||||
def test_state_apply_parallel_spawning_with_unpicklable_context(
|
||||
state, _state_unpicklable_ctx
|
||||
):
|
||||
"""
|
||||
Ensure that if the __context__ dictionary contains unpicklable objects,
|
||||
they are filtered out instead of causing a crash.
|
||||
"""
|
||||
ret = state.apply(_state_unpicklable_ctx)
|
||||
assert (
|
||||
ret["test_|-This should not fail on spawning platforms_|-foo_|-nop"]["result"]
|
||||
is True
|
||||
)
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
:codeauthor: :email:`Shane Lee <slee@saltstack.com>`
|
||||
"""
|
||||
|
||||
import textwrap
|
||||
|
||||
import pytest
|
||||
|
||||
import salt.grains.disks as disks
|
||||
|
@ -17,63 +15,58 @@ def configure_loader_modules():
|
|||
}
|
||||
|
||||
|
||||
def test__windows_disks():
|
||||
def test__windows_disks_dict():
|
||||
"""
|
||||
Test grains._windows_disks, normal return
|
||||
Should return a populated dictionary
|
||||
Test grains._windows_disks with a single disk returned as a dict
|
||||
Should return 1 disk and no ssds
|
||||
"""
|
||||
mock_which = MagicMock(return_value="C:\\Windows\\System32\\wbem\\WMIC.exe")
|
||||
wmic_result = textwrap.dedent(
|
||||
"""
|
||||
DeviceId MediaType
|
||||
0 4
|
||||
1 0
|
||||
2 3
|
||||
3 5
|
||||
"""
|
||||
)
|
||||
mock_run_all = MagicMock(return_value={"stdout": wmic_result, "retcode": 0})
|
||||
devices = {"DeviceID": 0, "MediaType": "HDD"}
|
||||
mock_powershell = MagicMock(return_value=devices)
|
||||
|
||||
with patch("salt.utils.path.which", mock_which), patch.dict(
|
||||
disks.__salt__, {"cmd.run_all": mock_run_all}
|
||||
):
|
||||
with patch.dict(disks.__salt__, {"cmd.powershell": mock_powershell}):
|
||||
result = disks._windows_disks()
|
||||
expected = {"disks": ["\\\\.\\PhysicalDrive0"], "ssds": []}
|
||||
assert result == expected
|
||||
|
||||
|
||||
def test__windows_disks_list():
|
||||
"""
|
||||
test grains._windows_disks with multiple disks and types as a list of dicts
|
||||
Should return 4 disks and 1 ssd
|
||||
"""
|
||||
devices = [
|
||||
{"DeviceID": 0, "MediaType": "SSD"},
|
||||
{"DeviceID": 1, "MediaType": "HDD"},
|
||||
{"DeviceID": 2, "MediaType": "HDD"},
|
||||
{"DeviceID": 3, "MediaType": "HDD"},
|
||||
]
|
||||
mock_powershell = MagicMock(return_value=devices)
|
||||
|
||||
with patch.dict(disks.__salt__, {"cmd.powershell": mock_powershell}):
|
||||
result = disks._windows_disks()
|
||||
expected = {
|
||||
"ssds": ["\\\\.\\PhysicalDrive0"],
|
||||
"disks": [
|
||||
"\\\\.\\PhysicalDrive0",
|
||||
"\\\\.\\PhysicalDrive1",
|
||||
"\\\\.\\PhysicalDrive2",
|
||||
"\\\\.\\PhysicalDrive3",
|
||||
],
|
||||
"ssds": ["\\\\.\\PhysicalDrive0"],
|
||||
}
|
||||
assert result == expected
|
||||
cmd = " ".join(
|
||||
[
|
||||
"C:\\Windows\\System32\\wbem\\WMIC.exe",
|
||||
"/namespace:\\\\root\\microsoft\\windows\\storage",
|
||||
"path",
|
||||
"MSFT_PhysicalDisk",
|
||||
"get",
|
||||
"DeviceID,MediaType",
|
||||
"/format:table",
|
||||
]
|
||||
)
|
||||
mock_run_all.assert_called_once_with(cmd)
|
||||
|
||||
|
||||
def test__windows_disks_retcode():
|
||||
def test__windows_disks_empty():
|
||||
"""
|
||||
Test grains._windows_disks, retcode 1
|
||||
Test grains._windows_disks when nothing is returned
|
||||
Should return empty lists
|
||||
"""
|
||||
mock_which = MagicMock(return_value="C:\\Windows\\System32\\wbem\\WMIC.exe")
|
||||
mock_run_all = MagicMock(return_value={"stdout": "", "retcode": 1})
|
||||
with patch("salt.utils.path.which", mock_which), patch.dict(
|
||||
disks.__salt__, {"cmd.run_all": mock_run_all}
|
||||
):
|
||||
devices = {}
|
||||
mock_powershell = MagicMock(return_value=devices)
|
||||
|
||||
with patch.dict(disks.__salt__, {"cmd.powershell": mock_powershell}):
|
||||
expected = {"disks": [], "ssds": []}
|
||||
result = disks._windows_disks()
|
||||
expected = {"ssds": [], "disks": []}
|
||||
assert result == expected
|
||||
|
||||
|
||||
|
|
|
@ -9,16 +9,39 @@ import salt.grains.iscsi as iscsi
|
|||
from tests.support.mock import MagicMock, mock_open, patch
|
||||
|
||||
|
||||
def test_windows_iscsi_iqn_grains():
|
||||
cmd_run_mock = MagicMock(
|
||||
return_value={"stdout": "iSCSINodeName\niqn.1991-05.com.microsoft:simon-x1\n"}
|
||||
)
|
||||
_grains = {}
|
||||
with patch("salt.utils.path.which", MagicMock(return_value=True)):
|
||||
with patch("salt.modules.cmdmod.run_all", cmd_run_mock):
|
||||
_grains["iscsi_iqn"] = iscsi._windows_iqn()
|
||||
def test_windows_iscsi_iqn_grains_empty():
|
||||
nodes_dict = {}
|
||||
cmd_powershell_mock = MagicMock(return_value=nodes_dict)
|
||||
with patch("salt.modules.cmdmod.powershell", cmd_powershell_mock):
|
||||
result = iscsi._windows_iqn()
|
||||
expected = []
|
||||
assert result == expected
|
||||
|
||||
assert _grains.get("iscsi_iqn") == ["iqn.1991-05.com.microsoft:simon-x1"]
|
||||
|
||||
def test_windows_iscsi_iqn_grains_single():
|
||||
nodes_dict = {"NodeAddress": "iqn.1991-05.com.microsoft:simon-x1"}
|
||||
cmd_powershell_mock = MagicMock(return_value=nodes_dict)
|
||||
with patch("salt.modules.cmdmod.powershell", cmd_powershell_mock):
|
||||
result = iscsi._windows_iqn()
|
||||
expected = ["iqn.1991-05.com.microsoft:simon-x1"]
|
||||
assert result == expected
|
||||
|
||||
|
||||
def test_windows_iscsi_iqn_grains_multiple():
|
||||
nodes_list = [
|
||||
{"NodeAddress": "iqn.1991-05.com.microsoft:simon-x1"},
|
||||
{"NodeAddress": "iqn.1991-05.com.microsoft:simon-x2"},
|
||||
{"NodeAddress": "iqn.1991-05.com.microsoft:simon-x3"},
|
||||
]
|
||||
cmd_powershell_mock = MagicMock(return_value=nodes_list)
|
||||
with patch("salt.modules.cmdmod.powershell", cmd_powershell_mock):
|
||||
result = iscsi._windows_iqn()
|
||||
expected = [
|
||||
"iqn.1991-05.com.microsoft:simon-x1",
|
||||
"iqn.1991-05.com.microsoft:simon-x2",
|
||||
"iqn.1991-05.com.microsoft:simon-x3",
|
||||
]
|
||||
assert result == expected
|
||||
|
||||
|
||||
def test_aix_iscsi_iqn_grains():
|
||||
|
|
|
@ -6,6 +6,8 @@ import salt.modules.selinux as selinux
|
|||
from salt.exceptions import SaltInvocationError
|
||||
from tests.support.mock import MagicMock, mock_open, patch
|
||||
|
||||
pytestmark = [pytest.mark.skip_unless_on_linux]
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def configure_loader_modules():
|
||||
|
@ -399,7 +401,39 @@ def test_selinux_add_policy_regex(name, sel_type):
|
|||
):
|
||||
selinux.fcontext_add_policy(name, sel_type=sel_type)
|
||||
filespec = re.escape(name)
|
||||
expected_cmd_shell = f"semanage fcontext -l | egrep '{filespec}'"
|
||||
expected_cmd_shell = f"semanage fcontext -l | grep -E '{filespec} '"
|
||||
mock_cmd_shell.assert_called_once_with(
|
||||
expected_cmd_shell,
|
||||
ignore_retcode=True,
|
||||
)
|
||||
expected_cmd_run_all = (
|
||||
f"semanage fcontext --modify --type {sel_type} {filespec}"
|
||||
)
|
||||
mock_cmd_run_all.assert_called_once_with(
|
||||
expected_cmd_run_all,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"name,sel_type",
|
||||
(
|
||||
("/usr/share/munin/plugins/mysql_queries", "services_munin_plugin_exec_t"),
|
||||
("/usr/share/munin/plugins/mysql_", "unconfined_munin_plugin_exec_t"),
|
||||
),
|
||||
)
|
||||
def test_selinux_add_policy_shorter_path(name, sel_type):
|
||||
"""
|
||||
Test adding policy with a shorter path than an existing entry
|
||||
"""
|
||||
mock_cmd_shell = MagicMock(return_value={"retcode": 0})
|
||||
mock_cmd_run_all = MagicMock(return_value={"retcode": 0})
|
||||
|
||||
with patch.dict(selinux.__salt__, {"cmd.shell": mock_cmd_shell}), patch.dict(
|
||||
selinux.__salt__, {"cmd.run_all": mock_cmd_run_all}
|
||||
):
|
||||
selinux.fcontext_add_policy(name, sel_type=sel_type)
|
||||
filespec = re.escape(name)
|
||||
expected_cmd_shell = f"semanage fcontext -l | grep -E '{filespec} '"
|
||||
mock_cmd_shell.assert_called_once_with(
|
||||
expected_cmd_shell,
|
||||
ignore_retcode=True,
|
||||
|
|
|
@ -1428,10 +1428,8 @@ def test_install_with_options():
|
|||
"--disablerepo=*",
|
||||
"--enablerepo=good",
|
||||
"--branch=foo",
|
||||
"--setopt",
|
||||
"obsoletes=0",
|
||||
"--setopt",
|
||||
"plugins=0",
|
||||
"--setopt=obsoletes=0",
|
||||
"--setopt=plugins=0",
|
||||
"install",
|
||||
"foo",
|
||||
],
|
||||
|
@ -1459,10 +1457,8 @@ def test_install_with_options():
|
|||
"--disablerepo=bad",
|
||||
"--enablerepo=good",
|
||||
"--branch=foo",
|
||||
"--setopt",
|
||||
"obsoletes=0",
|
||||
"--setopt",
|
||||
"plugins=0",
|
||||
"--setopt=obsoletes=0",
|
||||
"--setopt=plugins=0",
|
||||
"install",
|
||||
"foo",
|
||||
],
|
||||
|
@ -1857,10 +1853,8 @@ def test_upgrade_with_options():
|
|||
"--disablerepo=*",
|
||||
"--enablerepo=good",
|
||||
"--branch=foo",
|
||||
"--setopt",
|
||||
"obsoletes=0",
|
||||
"--setopt",
|
||||
"plugins=0",
|
||||
"--setopt=obsoletes=0",
|
||||
"--setopt=plugins=0",
|
||||
"--exclude=kernel*",
|
||||
"--nogpgcheck",
|
||||
"upgrade",
|
||||
|
@ -1902,10 +1896,8 @@ def test_upgrade_with_options():
|
|||
"--disablerepo=bad",
|
||||
"--enablerepo=good",
|
||||
"--branch=foo",
|
||||
"--setopt",
|
||||
"obsoletes=0",
|
||||
"--setopt",
|
||||
"plugins=0",
|
||||
"--setopt=obsoletes=0",
|
||||
"--setopt=plugins=0",
|
||||
"--exclude=kernel*",
|
||||
"upgrade",
|
||||
],
|
||||
|
@ -3051,10 +3043,8 @@ def test_pkg_update_dnf():
|
|||
"dnf",
|
||||
"--quiet",
|
||||
"-y",
|
||||
"--setopt",
|
||||
"plugins=0",
|
||||
"--setopt",
|
||||
"obsoletes=False",
|
||||
"--setopt=plugins=0",
|
||||
"--setopt=obsoletes=False",
|
||||
"upgrade",
|
||||
"foo",
|
||||
],
|
||||
|
|
|
@ -23,6 +23,8 @@ def temp_saltclass_tree(tmp_path, minion_id):
|
|||
nodes_dir.mkdir(parents=True, exist_ok=True)
|
||||
default_dir = classes_dir / "default"
|
||||
default_dir.mkdir(parents=True, exist_ok=True)
|
||||
users_dir = default_dir / "users"
|
||||
users_dir.mkdir(parents=True, exist_ok=True)
|
||||
roles_dir = classes_dir / "roles"
|
||||
roles_dir.mkdir(parents=True, exist_ok=True)
|
||||
nginx_subdir = roles_dir / "nginx"
|
||||
|
@ -35,6 +37,9 @@ def temp_saltclass_tree(tmp_path, minion_id):
|
|||
- default.motd
|
||||
- default.empty
|
||||
|
||||
states:
|
||||
- default
|
||||
|
||||
pillars:
|
||||
default:
|
||||
network:
|
||||
|
@ -50,6 +55,13 @@ def temp_saltclass_tree(tmp_path, minion_id):
|
|||
test_list:
|
||||
- a: ${default:network:ntp:srv1}
|
||||
- ${default:network:ntp:srv2}
|
||||
|
||||
global_scalar: from default
|
||||
test_dict:
|
||||
a_scalar: from default
|
||||
a_list:
|
||||
- element1
|
||||
- element2
|
||||
"""
|
||||
default_init.write_text(test_list)
|
||||
|
||||
|
@ -57,24 +69,91 @@ def temp_saltclass_tree(tmp_path, minion_id):
|
|||
nodes_text = """
|
||||
environment: base
|
||||
|
||||
states:
|
||||
- minion_node
|
||||
|
||||
classes:
|
||||
{% for class in ['default', 'roles.*', 'empty.*'] %}
|
||||
- {{ class }}
|
||||
{% endfor %}
|
||||
|
||||
pillars:
|
||||
global_scalar: from minion_node
|
||||
test_dict:
|
||||
a_scalar: from minion_node
|
||||
"""
|
||||
minion_node_file.write_text(nodes_text)
|
||||
|
||||
(default_dir / "users.yml").write_text("test: this is a test")
|
||||
(users_dir / "init.yml").write_text(
|
||||
"""
|
||||
classes:
|
||||
- default.users.foo
|
||||
|
||||
states:
|
||||
- users
|
||||
|
||||
pillars:
|
||||
default:
|
||||
ntp:
|
||||
srv1: 192.168.20.10
|
||||
|
||||
global_scalar: from users
|
||||
test_dict:
|
||||
a_scalar: from users
|
||||
"""
|
||||
)
|
||||
(users_dir / "foo.yml").write_text(
|
||||
"""
|
||||
states:
|
||||
- users.foo
|
||||
|
||||
global_scalar: from users.foo
|
||||
users_foo_scalar: from users.foo
|
||||
test_dict:
|
||||
a_scalar: from users.foo
|
||||
"""
|
||||
)
|
||||
(default_dir / "empty.yml").write_text("test: this is a test")
|
||||
(default_dir / "motd.yml").write_text("test: this is a test")
|
||||
(roles_dir / "app.yml").write_text("test: this is a test")
|
||||
(nginx_subdir / "init.yml").write_text("test: this is a test")
|
||||
(default_dir / "motd.yml").write_text(
|
||||
"""
|
||||
states:
|
||||
- motd
|
||||
|
||||
pillars:
|
||||
global_scalar: from motd
|
||||
"""
|
||||
)
|
||||
(roles_dir / "app.yml").write_text(
|
||||
"""
|
||||
states:
|
||||
- app
|
||||
|
||||
pillars:
|
||||
global_scalar: from app
|
||||
"""
|
||||
)
|
||||
(nginx_subdir / "init.yml").write_text(
|
||||
"""
|
||||
states:
|
||||
- nginx
|
||||
|
||||
pillars:
|
||||
global_scalar: from nginx
|
||||
nginx_scalar: from nginx
|
||||
"""
|
||||
)
|
||||
|
||||
return dirname
|
||||
|
||||
|
||||
def test_succeeds(temp_saltclass_tree):
|
||||
def test_classes_order(temp_saltclass_tree):
|
||||
"""
|
||||
Classes must be correctly ordered.
|
||||
|
||||
See: https://github.com/saltstack/salt/issues/58969
|
||||
"""
|
||||
expected_ret = [
|
||||
"default.users.foo",
|
||||
"default.users",
|
||||
"default.motd",
|
||||
"default.empty",
|
||||
|
@ -110,3 +189,102 @@ def test_list_expansion_succeeds(temp_saltclass_tree):
|
|||
pytest.fail(err)
|
||||
# Else give the parsed content result
|
||||
assert expected_ret == parsed_ret
|
||||
|
||||
|
||||
def test_node_override_classes_scalars(temp_saltclass_tree):
|
||||
"""
|
||||
Scalars pillars defined in a node definition must override the
|
||||
definition from classes.
|
||||
"""
|
||||
expected_ret = "from minion_node"
|
||||
fake_args = {"path": str(temp_saltclass_tree)}
|
||||
fake_pillar = {}
|
||||
fake_minion_id = "fake_id"
|
||||
try:
|
||||
full_ret = saltclass.ext_pillar(fake_minion_id, fake_pillar, fake_args)
|
||||
parsed_ret = full_ret["global_scalar"]
|
||||
# Fail the test if we hit our NoneType error
|
||||
except TypeError as err:
|
||||
pytest.fail(err)
|
||||
# Else give the parsed content result
|
||||
assert expected_ret == parsed_ret
|
||||
|
||||
|
||||
def test_node_override_classes_scalar_in_dict(temp_saltclass_tree):
|
||||
"""
|
||||
Scalars defined in `dict` pillars defined in a node definition must override the
|
||||
same dict definition from classes.
|
||||
|
||||
See: https://github.com/saltstack/salt/issues/63933
|
||||
"""
|
||||
expected_ret = "from minion_node"
|
||||
fake_args = {"path": str(temp_saltclass_tree)}
|
||||
fake_pillar = {}
|
||||
fake_minion_id = "fake_id"
|
||||
try:
|
||||
full_ret = saltclass.ext_pillar(fake_minion_id, fake_pillar, fake_args)
|
||||
parsed_ret = full_ret["test_dict"]["a_scalar"]
|
||||
# Fail the test if we hit our NoneType error
|
||||
except TypeError as err:
|
||||
pytest.fail(err)
|
||||
# Else give the parsed content result
|
||||
assert expected_ret == parsed_ret
|
||||
|
||||
|
||||
def test_node_override_classes_list_in_dict(temp_saltclass_tree):
|
||||
"""
|
||||
`list` under a `dict` defined in a node definition must override the
|
||||
same definition from classes.
|
||||
|
||||
See: https://github.com/saltstack/salt/issues/63933
|
||||
"""
|
||||
expected_ret = {"srv1": "192.168.10.10", "srv2": "192.168.10.20"}
|
||||
fake_args = {"path": str(temp_saltclass_tree)}
|
||||
fake_pillar = {}
|
||||
fake_minion_id = "fake_id"
|
||||
try:
|
||||
full_ret = saltclass.ext_pillar(fake_minion_id, fake_pillar, fake_args)
|
||||
parsed_ret = full_ret["default"]["network"]["ntp"]
|
||||
# Fail the test if we hit our NoneType error
|
||||
except TypeError as err:
|
||||
pytest.fail(err)
|
||||
# Else give the parsed content result
|
||||
assert expected_ret == parsed_ret
|
||||
|
||||
|
||||
def test_list_in_dict_no_duplication(temp_saltclass_tree):
|
||||
"""
|
||||
`list` under a `dict` in pillar must not be duplicated.
|
||||
|
||||
See:
|
||||
"""
|
||||
expected_ret = ["element1", "element2"]
|
||||
fake_args = {"path": str(temp_saltclass_tree)}
|
||||
fake_pillar = {}
|
||||
fake_minion_id = "fake_id"
|
||||
try:
|
||||
full_ret = saltclass.ext_pillar(fake_minion_id, fake_pillar, fake_args)
|
||||
parsed_ret = full_ret["test_dict"]["a_list"]
|
||||
# Fail the test if we hit our NoneType error
|
||||
except TypeError as err:
|
||||
pytest.fail(err)
|
||||
# Else give the parsed content result
|
||||
assert expected_ret == parsed_ret
|
||||
|
||||
|
||||
def test_nested_classes_has_pillars(temp_saltclass_tree):
|
||||
"""
|
||||
pillars defined in nested classes are present
|
||||
"""
|
||||
expected_ret = "from nginx"
|
||||
fake_args = {"path": str(temp_saltclass_tree)}
|
||||
fake_pillar = {}
|
||||
fake_minion_id = "fake_id"
|
||||
try:
|
||||
full_ret = saltclass.ext_pillar(fake_minion_id, fake_pillar, fake_args)
|
||||
parsed_ret = full_ret["nginx_scalar"]
|
||||
# Fail the test if we hit our NoneType error
|
||||
except TypeError as err:
|
||||
pytest.fail(err)
|
||||
# Else give the parsed content result
|
||||
assert expected_ret == parsed_ret
|
||||
|
|
|
@ -345,7 +345,6 @@ MISSING_DOCSTRINGS = {
|
|||
"get_pillars",
|
||||
"expand_variables",
|
||||
"render_jinja",
|
||||
"expand_classes_in_order",
|
||||
"dict_search_and_replace",
|
||||
"expanded_dict_from_minion",
|
||||
"find_value_to_expand",
|
||||
|
|
Loading…
Add table
Reference in a new issue