mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
Merge 3006.x into master
This commit is contained in:
commit
c07f66261e
59 changed files with 1274 additions and 236 deletions
1
.github/workflows/build-macos-packages.yml
vendored
1
.github/workflows/build-macos-packages.yml
vendored
|
@ -110,6 +110,7 @@ jobs:
|
|||
DEV_APP_CERT: "${{ secrets.MAC_SIGN_DEV_APP_CERT }}"
|
||||
DEV_INSTALL_CERT: "${{ secrets.MAC_SIGN_DEV_INSTALL_CERT }}"
|
||||
APPLE_ACCT: "${{ secrets.MAC_SIGN_APPLE_ACCT }}"
|
||||
APPLE_TEAM_ID: "${{ secrets.MAC_SIGN_APPLE_TEAM_ID }}"
|
||||
APP_SPEC_PWD: "${{ secrets.MAC_SIGN_APP_SPEC_PWD }}"
|
||||
run: |
|
||||
tools pkg build macos --relenv-version=${{ inputs.relenv-version }} --python-version=${{ inputs.python-version }} ${{
|
||||
|
|
|
@ -578,6 +578,9 @@ commit message, it's usually a good idea to add other information, such as
|
|||
This will also help you out, because when you go to create the PR it
|
||||
will automatically insert the body of your commit messages.
|
||||
|
||||
See the `changelog <https://docs.saltproject.io/en/latest/topics/development/changelog.html>`__
|
||||
docs for more information.
|
||||
|
||||
|
||||
Pull request time!
|
||||
------------------
|
||||
|
|
|
@ -121,7 +121,7 @@ Security advisories
|
|||
Keep an eye on the Salt Project
|
||||
`Security Announcements <https://saltproject.io/security-announcements/>`_
|
||||
landing page. Salt Project recommends subscribing to the
|
||||
`Salt Project Security RSS feed <https://saltproject.io/feed/?post_type=security>`_
|
||||
`Salt Project Security RSS feed <https://saltproject.io/security-announcements/index.xml>`_
|
||||
to receive notification when new information is available regarding security
|
||||
announcements.
|
||||
|
||||
|
|
1
changelog/65093.fixed.md
Normal file
1
changelog/65093.fixed.md
Normal file
|
@ -0,0 +1 @@
|
|||
Only attempt to create a keys directory when `--gen-keys` is passed to the `salt-key` CLI
|
1
changelog/65179.fixed.md
Normal file
1
changelog/65179.fixed.md
Normal file
|
@ -0,0 +1 @@
|
|||
Ensure __kwarg__ is preserved when checking for kwargs. This change affects proxy minions when used with Deltaproxy, which had kwargs popped when targeting multiple minions id.
|
1
changelog/65210.fixed.md
Normal file
1
changelog/65210.fixed.md
Normal file
|
@ -0,0 +1 @@
|
|||
Fixes traceback when state id is an int in a reactor SLS file.
|
|
@ -197,3 +197,12 @@ How to access python binary
|
|||
|
||||
The python library is available in the install directory of the onedir package. For example
|
||||
on linux the default location would be ``/opt/saltstack/salt/bin/python3``.
|
||||
|
||||
Testing the packages
|
||||
====================
|
||||
|
||||
If you want to test your built packages, or any other collection of salt packages post 3006.0, follow :ref:`this guide <pkging-testing>`
|
||||
|
||||
.. toctree::
|
||||
|
||||
testing
|
||||
|
|
157
doc/topics/packaging/testing.rst
Normal file
157
doc/topics/packaging/testing.rst
Normal file
|
@ -0,0 +1,157 @@
|
|||
.. _pkging-testing:
|
||||
|
||||
================
|
||||
Testing packages
|
||||
================
|
||||
|
||||
The package test suite
|
||||
======================
|
||||
|
||||
The salt repo provides a test suite for testing basic functionality of our
|
||||
packages at ``<repo-root>/pkg/tests/``. You can run the install, upgrade, and
|
||||
downgrade tests. These tests run automatically on most PRs that are submitted
|
||||
against Salt.
|
||||
|
||||
|
||||
.. warning::
|
||||
|
||||
These tests make destructive changes to your system because they install the
|
||||
built packages onto the system. They may also install older versions in the
|
||||
case of upgrades or downgrades. To prevent destructive changes, run the
|
||||
tests in an isolated system, preferably a virtual machine.
|
||||
|
||||
Setup
|
||||
=====
|
||||
In order to run the package tests, the `relenv
|
||||
<https://github.com/saltstack/relative-environment-for-python>`_ onedir and
|
||||
built packages need to be placed in the correct locations.
|
||||
|
||||
* Place all salt packages for the applicable testing version in
|
||||
``<repo-root>/pkg/artifacts/``.
|
||||
* The onedir must be located under ``<repo-root>/artifacts/``.
|
||||
* Additionally, to ensure complete parity with Salt's CI/CD suite, place the
|
||||
``nox`` virtual environment in ``<repo-root>/.nox/test-pkgs-onedir``.
|
||||
|
||||
The following are a few ways this can be accomplished easily.
|
||||
|
||||
You can ensure parity by installing the package test suite through a few
|
||||
possible methods:
|
||||
|
||||
* Using ``tools``
|
||||
* Downloading individually
|
||||
|
||||
Using ``tools``
|
||||
---------------
|
||||
Salt has preliminary support for setting up the package test suite in the
|
||||
``tools`` command suite that is located under ``<repo-root>/tools/testsuite/``.
|
||||
This method requires the Github CLI tool ``gh`` (https://cli.github.com/) to be properly configured for
|
||||
interaction with the salt repo.
|
||||
|
||||
#. Install the dependencies using this command:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pip install -r requirements/static/ci/py{python_version}/tools.txt
|
||||
|
||||
#. Download and extract the artifacts with this ``tools`` command:
|
||||
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
tools ts setup --platform {linux|darwin|windows} --slug
|
||||
<operating-system-slug> --pr <pr-number> --pkg
|
||||
|
||||
The most common use case is to test the packages built on a CI/CD run for a
|
||||
given PR. To see the possible options for each argument, and other ways to
|
||||
utilize this command, use the following:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
tools ts setup -h
|
||||
|
||||
.. warning::
|
||||
|
||||
You can only download artifacts from finished workflow runs. This is something
|
||||
imposed by the GitHub API.
|
||||
To download artifacts from a running workflow run, you either have to wait for
|
||||
the finish or cancel it.
|
||||
|
||||
Downloading individually
|
||||
------------------------
|
||||
If the ``tools ts setup`` command doesn't work, you can download, unzip, and
|
||||
place the artifacts in the correct locations manually. Typically, you want to
|
||||
test packages built on a CI/CD run for a given PR. This guide explains how to
|
||||
set up for running the package tests using those artifacts. An analogous process
|
||||
can be performed for artifacts from nightly builds.
|
||||
|
||||
#. Find and download the artifacts:
|
||||
|
||||
Under the summary page for the most recent actions run for that PR, there is
|
||||
a list of available artifacts from that run that can be downloaded. Download
|
||||
the package artifacts by finding
|
||||
``salt-<major>.<minor>+<number>.<sha>-<arch>-<pkg-type>``. For example, the
|
||||
amd64 deb packages might look like:
|
||||
``salt-3006.2+123.01234567890-x86_64-deb``.
|
||||
|
||||
The onedir artifact will look like
|
||||
``salt-<major>.<minor>+<number>.<sha>-onedir-<platform>-<arch>.tar.xz``. For
|
||||
instance, the macos x86_64 onedir may have the name
|
||||
``salt-3006.2+123.01234567890-onedir-darwin-x86_64.tar.xz``.
|
||||
|
||||
.. note::
|
||||
|
||||
Windows onedir artifacts have ``.zip`` extensions instead of ``tar.xz``
|
||||
|
||||
While it is optional, it is recommended to download the ``nox`` session
|
||||
artifact as well. This will have the form of
|
||||
``nox-<os-name>-test-pkgs-onedir-<arch>``. The amd64 Ubuntu 20.04 nox
|
||||
artifact may look like ``nox-ubuntu-20.04-test-pkgs-onedir-x86_64``.
|
||||
|
||||
#. Place the artifacts in the correct location:
|
||||
|
||||
Unzip the packages and place them in ``<repo-root>/pkg/artifacts/``.
|
||||
|
||||
You must unzip and untar the onedir packages and place them in
|
||||
``<repo-root>/artifacts/``. Windows onedir requires an additional unzip
|
||||
action. If you set it up correctly, the ``<repo-root>/artifacts/salt``
|
||||
directory then contains the uncompressed onedir files.
|
||||
|
||||
Additionally, decompress the ``nox`` artifact and place it under
|
||||
``<repo-root>/.nox/``.
|
||||
|
||||
Running the tests
|
||||
=================
|
||||
You can run the test suite run if all the artifacts are in the correct location.
|
||||
|
||||
.. note::
|
||||
|
||||
You need root access to run the test artifacts. Run all nox commands at the
|
||||
root of the salt repo and as the root user.
|
||||
|
||||
#. Install ``nox``:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pip install nox
|
||||
|
||||
#. Run the install tests:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
nox -e test-pkgs-onedir -- install
|
||||
|
||||
#. Run the upgrade or downgrade tests:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
nox -e test-pkgs-onedir -- upgrade --prev-version <previous-version>
|
||||
|
||||
You can run the downgrade tests in the same way, replacing ``upgrade`` with
|
||||
``downgrade``.
|
||||
|
||||
.. note::
|
||||
|
||||
If you are testing upgrades or downgrades and classic packages are
|
||||
available for your system, replace ``upgrade`` or
|
||||
``downgrade`` with ``upgrade-classic`` or ``downgrade-classic``
|
||||
respectively to test against those versions.
|
|
@ -53,10 +53,7 @@ def test_salt_downgrade(salt_call_cli, install_salt):
|
|||
ret.stdout.strip().split()[1]
|
||||
) < packaging.version.parse(install_salt.artifact_version)
|
||||
|
||||
# Windows does not keep the extras directory around in the same state
|
||||
# TODO: Fix this problem in windows installers
|
||||
# TODO: Fix this problem in macos installers
|
||||
if is_downgrade_to_relenv and not (platform.is_windows() or platform.is_darwin()):
|
||||
if is_downgrade_to_relenv:
|
||||
new_py_version = install_salt.package_python_version()
|
||||
if new_py_version == original_py_version:
|
||||
# test pip install after a downgrade
|
||||
|
|
|
@ -272,7 +272,7 @@ netaddr==0.8.0
|
|||
# pyeapi
|
||||
netmiko==4.2.0
|
||||
# via napalm
|
||||
netutils==1.4.1
|
||||
netutils==1.6.0
|
||||
# via napalm
|
||||
ntc-templates==3.4.0
|
||||
# via netmiko
|
||||
|
@ -485,7 +485,7 @@ sqlparse==0.4.4
|
|||
# via -r requirements/static/ci/common.in
|
||||
strict-rfc3339==0.7
|
||||
# via -r requirements/static/ci/common.in
|
||||
tempora==5.2.2
|
||||
tempora==5.3.0
|
||||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.10/darwin.txt
|
||||
# portend
|
||||
|
@ -510,13 +510,13 @@ transitions==0.9.0
|
|||
# via junos-eznc
|
||||
ttp-templates==0.3.5
|
||||
# via napalm
|
||||
ttp==0.9.4
|
||||
ttp==0.9.5
|
||||
# via
|
||||
# napalm
|
||||
# ttp-templates
|
||||
types-pyyaml==6.0.1
|
||||
# via responses
|
||||
typing-extensions==4.6.2
|
||||
typing-extensions==4.6.3
|
||||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.10/darwin.txt
|
||||
# napalm
|
||||
|
|
|
@ -142,11 +142,11 @@ sphinxcontrib-serializinghtml==1.1.5
|
|||
# via sphinx
|
||||
sphinxcontrib-spelling==8.0.0
|
||||
# via -r requirements/static/ci/docs.in
|
||||
tempora==5.2.2
|
||||
tempora==5.3.0
|
||||
# via
|
||||
# -c requirements/static/ci/py3.10/linux.txt
|
||||
# portend
|
||||
typing-extensions==4.6.2
|
||||
typing-extensions==4.6.3
|
||||
# via
|
||||
# -c requirements/static/ci/py3.10/linux.txt
|
||||
# pydantic
|
||||
|
|
|
@ -267,7 +267,7 @@ netaddr==0.8.0
|
|||
# pyeapi
|
||||
netmiko==4.2.0
|
||||
# via napalm
|
||||
netutils==1.4.1
|
||||
netutils==1.6.0
|
||||
# via napalm
|
||||
ntc-templates==3.4.0
|
||||
# via netmiko
|
||||
|
@ -477,7 +477,7 @@ sqlparse==0.4.4
|
|||
# via -r requirements/static/ci/common.in
|
||||
strict-rfc3339==0.7
|
||||
# via -r requirements/static/ci/common.in
|
||||
tempora==5.2.2
|
||||
tempora==5.3.0
|
||||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.10/freebsd.txt
|
||||
# portend
|
||||
|
@ -502,13 +502,13 @@ transitions==0.9.0
|
|||
# via junos-eznc
|
||||
ttp-templates==0.3.5
|
||||
# via napalm
|
||||
ttp==0.9.4
|
||||
ttp==0.9.5
|
||||
# via
|
||||
# napalm
|
||||
# ttp-templates
|
||||
types-pyyaml==6.0.1
|
||||
# via responses
|
||||
typing-extensions==4.6.2
|
||||
typing-extensions==4.6.3
|
||||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.10/freebsd.txt
|
||||
# napalm
|
||||
|
|
|
@ -292,7 +292,7 @@ netaddr==0.8.0
|
|||
# pyeapi
|
||||
netmiko==4.2.0
|
||||
# via napalm
|
||||
netutils==1.4.1
|
||||
netutils==1.6.0
|
||||
# via napalm
|
||||
ntc-templates==3.4.0
|
||||
# via netmiko
|
||||
|
@ -539,7 +539,7 @@ sqlparse==0.4.4
|
|||
# via -r requirements/static/ci/common.in
|
||||
strict-rfc3339==0.7
|
||||
# via -r requirements/static/ci/common.in
|
||||
tempora==5.2.2
|
||||
tempora==5.3.0
|
||||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.10/linux.txt
|
||||
# portend
|
||||
|
@ -548,7 +548,7 @@ textfsm==1.1.3
|
|||
# napalm
|
||||
# netmiko
|
||||
# ntc-templates
|
||||
timelib==0.2.5
|
||||
timelib==0.3.0
|
||||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.10/linux.txt
|
||||
# -r requirements/static/pkg/linux.in
|
||||
|
@ -564,7 +564,7 @@ transitions==0.9.0
|
|||
# via junos-eznc
|
||||
ttp-templates==0.3.5
|
||||
# via napalm
|
||||
ttp==0.9.4
|
||||
ttp==0.9.5
|
||||
# via
|
||||
# napalm
|
||||
# ttp-templates
|
||||
|
@ -572,7 +572,7 @@ twilio==8.2.2
|
|||
# via -r requirements/static/ci/linux.in
|
||||
types-pyyaml==6.0.1
|
||||
# via responses
|
||||
typing-extensions==4.6.2
|
||||
typing-extensions==4.6.3
|
||||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.10/linux.txt
|
||||
# napalm
|
||||
|
|
|
@ -109,7 +109,7 @@ pytest-helpers-namespace==2021.12.29
|
|||
# pytest-shell-utilities
|
||||
pytest-salt-factories==1.0.0rc17
|
||||
# via -r requirements/static/ci/pkgtests-windows.in
|
||||
pytest-shell-utilities==1.7.0
|
||||
pytest-shell-utilities==1.8.0
|
||||
# via pytest-salt-factories
|
||||
pytest-skip-markers==1.4.1
|
||||
# via
|
||||
|
|
|
@ -106,7 +106,7 @@ pytest-helpers-namespace==2021.12.29
|
|||
# pytest-shell-utilities
|
||||
pytest-salt-factories==1.0.0rc17
|
||||
# via -r requirements/static/ci/pkgtests.in
|
||||
pytest-shell-utilities==1.7.0
|
||||
pytest-shell-utilities==1.8.0
|
||||
# via pytest-salt-factories
|
||||
pytest-skip-markers==1.4.1
|
||||
# via
|
||||
|
|
|
@ -441,7 +441,7 @@ sqlparse==0.4.4
|
|||
# via -r requirements/static/ci/common.in
|
||||
strict-rfc3339==0.7
|
||||
# via -r requirements/static/ci/common.in
|
||||
tempora==5.2.2
|
||||
tempora==5.3.0
|
||||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.10/windows.txt
|
||||
# portend
|
||||
|
@ -459,7 +459,7 @@ tornado==6.3.2
|
|||
# -r requirements/base.txt
|
||||
types-pyyaml==6.0.1
|
||||
# via responses
|
||||
typing-extensions==4.6.2
|
||||
typing-extensions==4.6.3
|
||||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.10/windows.txt
|
||||
# pydantic
|
||||
|
|
|
@ -270,7 +270,7 @@ netaddr==0.8.0
|
|||
# pyeapi
|
||||
netmiko==4.2.0
|
||||
# via napalm
|
||||
netutils==1.4.1
|
||||
netutils==1.6.0
|
||||
# via napalm
|
||||
ntc-templates==3.4.0
|
||||
# via netmiko
|
||||
|
@ -483,7 +483,7 @@ sqlparse==0.4.4
|
|||
# via -r requirements/static/ci/common.in
|
||||
strict-rfc3339==0.7
|
||||
# via -r requirements/static/ci/common.in
|
||||
tempora==5.2.2
|
||||
tempora==5.3.0
|
||||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.11/darwin.txt
|
||||
# portend
|
||||
|
@ -506,13 +506,13 @@ transitions==0.9.0
|
|||
# via junos-eznc
|
||||
ttp-templates==0.3.5
|
||||
# via napalm
|
||||
ttp==0.9.4
|
||||
ttp==0.9.5
|
||||
# via
|
||||
# napalm
|
||||
# ttp-templates
|
||||
types-pyyaml==6.0.1
|
||||
# via responses
|
||||
typing-extensions==4.6.2
|
||||
typing-extensions==4.6.3
|
||||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.11/darwin.txt
|
||||
# napalm
|
||||
|
|
|
@ -142,11 +142,11 @@ sphinxcontrib-serializinghtml==1.1.5
|
|||
# via sphinx
|
||||
sphinxcontrib-spelling==8.0.0
|
||||
# via -r requirements/static/ci/docs.in
|
||||
tempora==5.2.2
|
||||
tempora==5.3.0
|
||||
# via
|
||||
# -c requirements/static/ci/py3.11/linux.txt
|
||||
# portend
|
||||
typing-extensions==4.6.2
|
||||
typing-extensions==4.6.3
|
||||
# via
|
||||
# -c requirements/static/ci/py3.11/linux.txt
|
||||
# pydantic
|
||||
|
|
|
@ -265,7 +265,7 @@ netaddr==0.8.0
|
|||
# pyeapi
|
||||
netmiko==4.2.0
|
||||
# via napalm
|
||||
netutils==1.4.1
|
||||
netutils==1.6.0
|
||||
# via napalm
|
||||
ntc-templates==3.4.0
|
||||
# via netmiko
|
||||
|
@ -475,7 +475,7 @@ sqlparse==0.4.4
|
|||
# via -r requirements/static/ci/common.in
|
||||
strict-rfc3339==0.7
|
||||
# via -r requirements/static/ci/common.in
|
||||
tempora==5.2.2
|
||||
tempora==5.3.0
|
||||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.11/freebsd.txt
|
||||
# portend
|
||||
|
@ -498,13 +498,13 @@ transitions==0.9.0
|
|||
# via junos-eznc
|
||||
ttp-templates==0.3.5
|
||||
# via napalm
|
||||
ttp==0.9.4
|
||||
ttp==0.9.5
|
||||
# via
|
||||
# napalm
|
||||
# ttp-templates
|
||||
types-pyyaml==6.0.1
|
||||
# via responses
|
||||
typing-extensions==4.6.2
|
||||
typing-extensions==4.6.3
|
||||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.11/freebsd.txt
|
||||
# napalm
|
||||
|
|
|
@ -288,7 +288,7 @@ netaddr==0.8.0
|
|||
# pyeapi
|
||||
netmiko==4.2.0
|
||||
# via napalm
|
||||
netutils==1.4.1
|
||||
netutils==1.6.0
|
||||
# via napalm
|
||||
ntc-templates==3.4.0
|
||||
# via netmiko
|
||||
|
@ -535,7 +535,7 @@ sqlparse==0.4.4
|
|||
# via -r requirements/static/ci/common.in
|
||||
strict-rfc3339==0.7
|
||||
# via -r requirements/static/ci/common.in
|
||||
tempora==5.2.2
|
||||
tempora==5.3.0
|
||||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.11/linux.txt
|
||||
# portend
|
||||
|
@ -558,7 +558,7 @@ transitions==0.9.0
|
|||
# via junos-eznc
|
||||
ttp-templates==0.3.5
|
||||
# via napalm
|
||||
ttp==0.9.4
|
||||
ttp==0.9.5
|
||||
# via
|
||||
# napalm
|
||||
# ttp-templates
|
||||
|
@ -566,7 +566,7 @@ twilio==8.2.2
|
|||
# via -r requirements/static/ci/linux.in
|
||||
types-pyyaml==6.0.1
|
||||
# via responses
|
||||
typing-extensions==4.6.2
|
||||
typing-extensions==4.6.3
|
||||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.11/linux.txt
|
||||
# napalm
|
||||
|
|
|
@ -142,11 +142,11 @@ pyzmq==25.1.0
|
|||
# pytest-salt-factories
|
||||
requests==2.31.0
|
||||
# via -r requirements/base.txt
|
||||
tempora==5.2.2
|
||||
tempora==5.3.0
|
||||
# via portend
|
||||
tornado==6.3.2
|
||||
# via -r requirements/base.txt
|
||||
typing-extensions==4.6.2
|
||||
typing-extensions==4.6.3
|
||||
# via
|
||||
# pydantic
|
||||
# pytest-shell-utilities
|
||||
|
|
|
@ -135,11 +135,11 @@ requests==2.31.0
|
|||
# via
|
||||
# -r requirements/base.txt
|
||||
# docker
|
||||
tempora==5.2.2
|
||||
tempora==5.3.0
|
||||
# via portend
|
||||
tornado==6.3.2
|
||||
# via -r requirements/base.txt
|
||||
typing-extensions==4.6.2
|
||||
typing-extensions==4.6.3
|
||||
# via
|
||||
# pydantic
|
||||
# pytest-shell-utilities
|
||||
|
|
|
@ -439,7 +439,7 @@ sqlparse==0.4.4
|
|||
# via -r requirements/static/ci/common.in
|
||||
strict-rfc3339==0.7
|
||||
# via -r requirements/static/ci/common.in
|
||||
tempora==5.2.2
|
||||
tempora==5.3.0
|
||||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.11/windows.txt
|
||||
# portend
|
||||
|
@ -455,7 +455,7 @@ tornado==6.3.2
|
|||
# -r requirements/base.txt
|
||||
types-pyyaml==6.0.1
|
||||
# via responses
|
||||
typing-extensions==4.6.2
|
||||
typing-extensions==4.6.3
|
||||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.11/windows.txt
|
||||
# pydantic
|
||||
|
|
|
@ -151,11 +151,11 @@ sphinxcontrib-serializinghtml==1.1.5
|
|||
# via sphinx
|
||||
sphinxcontrib-spelling==8.0.0
|
||||
# via -r requirements/static/ci/docs.in
|
||||
tempora==5.2.2
|
||||
tempora==5.3.0
|
||||
# via
|
||||
# -c requirements/static/ci/py3.8/linux.txt
|
||||
# portend
|
||||
typing-extensions==4.6.2
|
||||
typing-extensions==4.6.3
|
||||
# via
|
||||
# -c requirements/static/ci/py3.8/linux.txt
|
||||
# pydantic
|
||||
|
|
|
@ -481,7 +481,7 @@ sqlparse==0.4.4
|
|||
# via -r requirements/static/ci/common.in
|
||||
strict-rfc3339==0.7
|
||||
# via -r requirements/static/ci/common.in
|
||||
tempora==5.2.2
|
||||
tempora==5.3.0
|
||||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.8/freebsd.txt
|
||||
# portend
|
||||
|
@ -512,7 +512,7 @@ ttp==0.9.5
|
|||
# ttp-templates
|
||||
types-pyyaml==6.0.1
|
||||
# via responses
|
||||
typing-extensions==4.6.2
|
||||
typing-extensions==4.6.3
|
||||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.8/freebsd.txt
|
||||
# napalm
|
||||
|
|
|
@ -543,7 +543,7 @@ sqlparse==0.4.4
|
|||
# via -r requirements/static/ci/common.in
|
||||
strict-rfc3339==0.7
|
||||
# via -r requirements/static/ci/common.in
|
||||
tempora==5.2.2
|
||||
tempora==5.3.0
|
||||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.8/linux.txt
|
||||
# portend
|
||||
|
@ -576,7 +576,7 @@ twilio==8.2.2
|
|||
# via -r requirements/static/ci/linux.in
|
||||
types-pyyaml==6.0.1
|
||||
# via responses
|
||||
typing-extensions==4.6.2
|
||||
typing-extensions==4.6.3
|
||||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.8/linux.txt
|
||||
# napalm
|
||||
|
|
|
@ -446,7 +446,7 @@ sqlparse==0.4.4
|
|||
# via -r requirements/static/ci/common.in
|
||||
strict-rfc3339==0.7
|
||||
# via -r requirements/static/ci/common.in
|
||||
tempora==5.2.2
|
||||
tempora==5.3.0
|
||||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.8/windows.txt
|
||||
# portend
|
||||
|
@ -464,7 +464,7 @@ tornado==6.3.2
|
|||
# -r requirements/base.txt
|
||||
types-pyyaml==6.0.1
|
||||
# via responses
|
||||
typing-extensions==4.6.2
|
||||
typing-extensions==4.6.3
|
||||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.8/windows.txt
|
||||
# pydantic
|
||||
|
|
|
@ -485,7 +485,7 @@ sqlparse==0.4.4
|
|||
# via -r requirements/static/ci/common.in
|
||||
strict-rfc3339==0.7
|
||||
# via -r requirements/static/ci/common.in
|
||||
tempora==5.2.2
|
||||
tempora==5.3.0
|
||||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.9/darwin.txt
|
||||
# portend
|
||||
|
@ -516,7 +516,7 @@ ttp==0.9.5
|
|||
# ttp-templates
|
||||
types-pyyaml==6.0.1
|
||||
# via responses
|
||||
typing-extensions==4.6.2
|
||||
typing-extensions==4.6.3
|
||||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.9/darwin.txt
|
||||
# napalm
|
||||
|
|
|
@ -146,11 +146,11 @@ sphinxcontrib-serializinghtml==1.1.5
|
|||
# via sphinx
|
||||
sphinxcontrib-spelling==8.0.0
|
||||
# via -r requirements/static/ci/docs.in
|
||||
tempora==5.2.2
|
||||
tempora==5.3.0
|
||||
# via
|
||||
# -c requirements/static/ci/py3.9/linux.txt
|
||||
# portend
|
||||
typing-extensions==4.6.2
|
||||
typing-extensions==4.6.3
|
||||
# via
|
||||
# -c requirements/static/ci/py3.9/linux.txt
|
||||
# pydantic
|
||||
|
|
|
@ -477,7 +477,7 @@ sqlparse==0.4.4
|
|||
# via -r requirements/static/ci/common.in
|
||||
strict-rfc3339==0.7
|
||||
# via -r requirements/static/ci/common.in
|
||||
tempora==5.2.2
|
||||
tempora==5.3.0
|
||||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.9/freebsd.txt
|
||||
# portend
|
||||
|
@ -508,7 +508,7 @@ ttp==0.9.5
|
|||
# ttp-templates
|
||||
types-pyyaml==6.0.1
|
||||
# via responses
|
||||
typing-extensions==4.6.2
|
||||
typing-extensions==4.6.3
|
||||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.9/freebsd.txt
|
||||
# napalm
|
||||
|
|
|
@ -541,7 +541,7 @@ sqlparse==0.4.4
|
|||
# via -r requirements/static/ci/common.in
|
||||
strict-rfc3339==0.7
|
||||
# via -r requirements/static/ci/common.in
|
||||
tempora==5.2.2
|
||||
tempora==5.3.0
|
||||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.9/linux.txt
|
||||
# portend
|
||||
|
@ -574,7 +574,7 @@ twilio==8.2.2
|
|||
# via -r requirements/static/ci/linux.in
|
||||
types-pyyaml==6.0.1
|
||||
# via responses
|
||||
typing-extensions==4.6.2
|
||||
typing-extensions==4.6.3
|
||||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.9/linux.txt
|
||||
# napalm
|
||||
|
|
|
@ -442,7 +442,7 @@ sqlparse==0.4.4
|
|||
# via -r requirements/static/ci/common.in
|
||||
strict-rfc3339==0.7
|
||||
# via -r requirements/static/ci/common.in
|
||||
tempora==5.2.2
|
||||
tempora==5.3.0
|
||||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.9/windows.txt
|
||||
# portend
|
||||
|
@ -460,7 +460,7 @@ tornado==6.3.2
|
|||
# -r requirements/base.txt
|
||||
types-pyyaml==6.0.1
|
||||
# via responses
|
||||
typing-extensions==4.6.2
|
||||
typing-extensions==4.6.3
|
||||
# via
|
||||
# -c requirements/static/ci/../pkg/py3.9/windows.txt
|
||||
# pydantic
|
||||
|
|
|
@ -107,13 +107,13 @@ six==1.16.0
|
|||
# via python-dateutil
|
||||
smmap==3.0.2
|
||||
# via gitdb
|
||||
tempora==5.2.2
|
||||
tempora==5.3.0
|
||||
# via portend
|
||||
timelib==0.3.0
|
||||
# via -r requirements/darwin.txt
|
||||
tornado==6.3.2
|
||||
# via -r requirements/base.txt
|
||||
typing-extensions==4.6.2
|
||||
typing-extensions==4.6.3
|
||||
# via pydantic
|
||||
urllib3==1.26.6
|
||||
# via requests
|
||||
|
|
|
@ -94,13 +94,13 @@ setproctitle==1.3.2
|
|||
# via -r requirements/static/pkg/freebsd.in
|
||||
six==1.16.0
|
||||
# via python-dateutil
|
||||
tempora==5.2.2
|
||||
tempora==5.3.0
|
||||
# via portend
|
||||
timelib==0.3.0
|
||||
# via -r requirements/static/pkg/freebsd.in
|
||||
tornado==6.3.2
|
||||
# via -r requirements/base.txt
|
||||
typing-extensions==4.6.2
|
||||
typing-extensions==4.6.3
|
||||
# via pydantic
|
||||
urllib3==1.26.6
|
||||
# via requests
|
||||
|
|
|
@ -94,13 +94,13 @@ setproctitle==1.3.2
|
|||
# via -r requirements/static/pkg/linux.in
|
||||
six==1.16.0
|
||||
# via python-dateutil
|
||||
tempora==5.2.2
|
||||
tempora==5.3.0
|
||||
# via portend
|
||||
timelib==0.2.5
|
||||
timelib==0.3.0
|
||||
# via -r requirements/static/pkg/linux.in
|
||||
tornado==6.3.2
|
||||
# via -r requirements/base.txt
|
||||
typing-extensions==4.6.2
|
||||
typing-extensions==4.6.3
|
||||
# via pydantic
|
||||
urllib3==1.26.6
|
||||
# via requests
|
||||
|
|
|
@ -121,13 +121,13 @@ six==1.15.0
|
|||
# via python-dateutil
|
||||
smmap==4.0.0
|
||||
# via gitdb
|
||||
tempora==5.2.2
|
||||
tempora==5.3.0
|
||||
# via portend
|
||||
timelib==0.3.0
|
||||
# via -r requirements/windows.txt
|
||||
tornado==6.3.2
|
||||
# via -r requirements/base.txt
|
||||
typing-extensions==4.6.2
|
||||
typing-extensions==4.6.3
|
||||
# via pydantic
|
||||
urllib3==1.26.6
|
||||
# via
|
||||
|
|
|
@ -107,13 +107,13 @@ six==1.16.0
|
|||
# via python-dateutil
|
||||
smmap==3.0.2
|
||||
# via gitdb
|
||||
tempora==5.2.2
|
||||
tempora==5.3.0
|
||||
# via portend
|
||||
timelib==0.3.0
|
||||
# via -r requirements/darwin.txt
|
||||
tornado==6.3.2
|
||||
# via -r requirements/base.txt
|
||||
typing-extensions==4.6.2
|
||||
typing-extensions==4.6.3
|
||||
# via pydantic
|
||||
urllib3==1.26.6
|
||||
# via requests
|
||||
|
|
|
@ -94,13 +94,13 @@ setproctitle==1.3.2
|
|||
# via -r requirements/static/pkg/freebsd.in
|
||||
six==1.16.0
|
||||
# via python-dateutil
|
||||
tempora==5.2.2
|
||||
tempora==5.3.0
|
||||
# via portend
|
||||
timelib==0.3.0
|
||||
# via -r requirements/static/pkg/freebsd.in
|
||||
tornado==6.3.2
|
||||
# via -r requirements/base.txt
|
||||
typing-extensions==4.6.2
|
||||
typing-extensions==4.6.3
|
||||
# via pydantic
|
||||
urllib3==1.26.6
|
||||
# via requests
|
||||
|
|
|
@ -94,13 +94,13 @@ setproctitle==1.3.2
|
|||
# via -r requirements/static/pkg/linux.in
|
||||
six==1.16.0
|
||||
# via python-dateutil
|
||||
tempora==5.2.2
|
||||
tempora==5.3.0
|
||||
# via portend
|
||||
timelib==0.3.0
|
||||
# via -r requirements/static/pkg/linux.in
|
||||
tornado==6.3.2
|
||||
# via -r requirements/base.txt
|
||||
typing-extensions==4.6.2
|
||||
typing-extensions==4.6.3
|
||||
# via pydantic
|
||||
urllib3==1.26.6
|
||||
# via requests
|
||||
|
|
|
@ -121,13 +121,13 @@ six==1.15.0
|
|||
# via python-dateutil
|
||||
smmap==4.0.0
|
||||
# via gitdb
|
||||
tempora==5.2.2
|
||||
tempora==5.3.0
|
||||
# via portend
|
||||
timelib==0.3.0
|
||||
# via -r requirements/windows.txt
|
||||
tornado==6.3.2
|
||||
# via -r requirements/base.txt
|
||||
typing-extensions==4.6.2
|
||||
typing-extensions==4.6.3
|
||||
# via pydantic
|
||||
urllib3==1.26.6
|
||||
# via
|
||||
|
|
|
@ -96,13 +96,13 @@ setproctitle==1.3.2
|
|||
# via -r requirements/static/pkg/freebsd.in
|
||||
six==1.16.0
|
||||
# via python-dateutil
|
||||
tempora==5.2.2
|
||||
tempora==5.3.0
|
||||
# via portend
|
||||
timelib==0.3.0
|
||||
# via -r requirements/static/pkg/freebsd.in
|
||||
tornado==6.3.2
|
||||
# via -r requirements/base.txt
|
||||
typing-extensions==4.6.2
|
||||
typing-extensions==4.6.3
|
||||
# via pydantic
|
||||
urllib3==1.26.6
|
||||
# via requests
|
||||
|
|
|
@ -96,13 +96,13 @@ setproctitle==1.3.2
|
|||
# via -r requirements/static/pkg/linux.in
|
||||
six==1.16.0
|
||||
# via python-dateutil
|
||||
tempora==5.2.2
|
||||
tempora==5.3.0
|
||||
# via portend
|
||||
timelib==0.3.0
|
||||
# via -r requirements/static/pkg/linux.in
|
||||
tornado==6.3.2
|
||||
# via -r requirements/base.txt
|
||||
typing-extensions==4.6.2
|
||||
typing-extensions==4.6.3
|
||||
# via pydantic
|
||||
urllib3==1.26.6
|
||||
# via requests
|
||||
|
|
|
@ -124,13 +124,13 @@ six==1.15.0
|
|||
# via python-dateutil
|
||||
smmap==4.0.0
|
||||
# via gitdb
|
||||
tempora==5.2.2
|
||||
tempora==5.3.0
|
||||
# via portend
|
||||
timelib==0.3.0
|
||||
# via -r requirements/windows.txt
|
||||
tornado==6.3.2
|
||||
# via -r requirements/base.txt
|
||||
typing-extensions==4.6.2
|
||||
typing-extensions==4.6.3
|
||||
# via pydantic
|
||||
urllib3==1.26.6
|
||||
# via
|
||||
|
|
|
@ -107,13 +107,13 @@ six==1.16.0
|
|||
# via python-dateutil
|
||||
smmap==3.0.2
|
||||
# via gitdb
|
||||
tempora==5.2.2
|
||||
tempora==5.3.0
|
||||
# via portend
|
||||
timelib==0.3.0
|
||||
# via -r requirements/darwin.txt
|
||||
tornado==6.3.2
|
||||
# via -r requirements/base.txt
|
||||
typing-extensions==4.6.2
|
||||
typing-extensions==4.6.3
|
||||
# via pydantic
|
||||
urllib3==1.26.6
|
||||
# via requests
|
||||
|
|
|
@ -94,13 +94,13 @@ setproctitle==1.3.2
|
|||
# via -r requirements/static/pkg/freebsd.in
|
||||
six==1.16.0
|
||||
# via python-dateutil
|
||||
tempora==5.2.2
|
||||
tempora==5.3.0
|
||||
# via portend
|
||||
timelib==0.3.0
|
||||
# via -r requirements/static/pkg/freebsd.in
|
||||
tornado==6.3.2
|
||||
# via -r requirements/base.txt
|
||||
typing-extensions==4.6.2
|
||||
typing-extensions==4.6.3
|
||||
# via pydantic
|
||||
urllib3==1.26.6
|
||||
# via requests
|
||||
|
|
|
@ -94,13 +94,13 @@ setproctitle==1.3.2
|
|||
# via -r requirements/static/pkg/linux.in
|
||||
six==1.16.0
|
||||
# via python-dateutil
|
||||
tempora==5.2.2
|
||||
tempora==5.3.0
|
||||
# via portend
|
||||
timelib==0.3.0
|
||||
# via -r requirements/static/pkg/linux.in
|
||||
tornado==6.3.2
|
||||
# via -r requirements/base.txt
|
||||
typing-extensions==4.6.2
|
||||
typing-extensions==4.6.3
|
||||
# via pydantic
|
||||
urllib3==1.26.6
|
||||
# via requests
|
||||
|
|
|
@ -122,13 +122,13 @@ six==1.15.0
|
|||
# via python-dateutil
|
||||
smmap==4.0.0
|
||||
# via gitdb
|
||||
tempora==5.2.2
|
||||
tempora==5.3.0
|
||||
# via portend
|
||||
timelib==0.3.0
|
||||
# via -r requirements/windows.txt
|
||||
tornado==6.3.2
|
||||
# via -r requirements/base.txt
|
||||
typing-extensions==4.6.2
|
||||
typing-extensions==4.6.3
|
||||
# via pydantic
|
||||
urllib3==1.26.6
|
||||
# via
|
||||
|
|
|
@ -328,9 +328,12 @@ def load_args_and_kwargs(func, args, data=None, ignore_invalid=False):
|
|||
invalid_kwargs = []
|
||||
|
||||
for arg in args:
|
||||
if isinstance(arg, dict) and arg.pop("__kwarg__", False) is True:
|
||||
if isinstance(arg, dict) and arg.get("__kwarg__", False) is True:
|
||||
# if the arg is a dict with __kwarg__ == True, then its a kwarg
|
||||
for key, val in arg.items():
|
||||
# Skip __kwarg__ when checking kwargs
|
||||
if key == "__kwarg__":
|
||||
continue
|
||||
if argspec.keywords or key in argspec.args:
|
||||
# Function supports **kwargs or is a positional argument to
|
||||
# the function.
|
||||
|
|
278
salt/state.py
278
salt/state.py
|
@ -449,145 +449,157 @@ class Compiler:
|
|||
if not isinstance(high, dict):
|
||||
errors.append("High data is not a dictionary and is invalid")
|
||||
reqs = OrderedDict()
|
||||
for name, body in high.items():
|
||||
if name.startswith("__"):
|
||||
continue
|
||||
if not isinstance(name, str):
|
||||
errors.append(
|
||||
"ID '{}' in SLS '{}' is not formed as a string, but is a {}".format(
|
||||
name, body["__sls__"], type(name).__name__
|
||||
)
|
||||
)
|
||||
if not isinstance(body, dict):
|
||||
err = "The type {} in {} is not formatted as a dictionary".format(
|
||||
name, body
|
||||
)
|
||||
errors.append(err)
|
||||
continue
|
||||
for state in body:
|
||||
if state.startswith("__"):
|
||||
continue
|
||||
if not isinstance(body[state], list):
|
||||
if not errors:
|
||||
for name, body in high.items():
|
||||
try:
|
||||
if name.startswith("__"):
|
||||
continue
|
||||
except (AttributeError, TypeError):
|
||||
# Do not traceback on non string state ID
|
||||
# handle the error properly
|
||||
pass
|
||||
|
||||
if not isinstance(name, str):
|
||||
errors.append(
|
||||
"State '{}' in SLS '{}' is not formed as a list".format(
|
||||
name, body["__sls__"]
|
||||
"ID '{}' in SLS '{}' is not formed as a string, but is a {}. It may need to be quoted".format(
|
||||
name, body["__sls__"], type(name).__name__
|
||||
)
|
||||
)
|
||||
else:
|
||||
fun = 0
|
||||
if "." in state:
|
||||
fun += 1
|
||||
for arg in body[state]:
|
||||
if isinstance(arg, str):
|
||||
fun += 1
|
||||
if " " in arg.strip():
|
||||
errors.append(
|
||||
'The function "{}" in state '
|
||||
'"{}" in SLS "{}" has '
|
||||
"whitespace, a function with whitespace is "
|
||||
"not supported, perhaps this is an argument "
|
||||
'that is missing a ":"'.format(
|
||||
arg, name, body["__sls__"]
|
||||
)
|
||||
)
|
||||
elif isinstance(arg, dict):
|
||||
# The arg is a dict, if the arg is require or
|
||||
# watch, it must be a list.
|
||||
#
|
||||
# Add the requires to the reqs dict and check them
|
||||
# all for recursive requisites.
|
||||
argfirst = next(iter(arg))
|
||||
if argfirst in ("require", "watch", "prereq", "onchanges"):
|
||||
if not isinstance(arg[argfirst], list):
|
||||
errors.append(
|
||||
"The {} statement in state '{}' in SLS '{}' "
|
||||
"needs to be formed as a list".format(
|
||||
argfirst, name, body["__sls__"]
|
||||
)
|
||||
)
|
||||
# It is a list, verify that the members of the
|
||||
# list are all single key dicts.
|
||||
else:
|
||||
reqs[name] = {"state": state}
|
||||
for req in arg[argfirst]:
|
||||
if isinstance(req, str):
|
||||
req = {"id": req}
|
||||
if not isinstance(req, dict):
|
||||
errors.append(
|
||||
"Requisite declaration {} in SLS {} "
|
||||
"is not formed as a single key "
|
||||
"dictionary".format(
|
||||
req, body["__sls__"]
|
||||
)
|
||||
)
|
||||
continue
|
||||
req_key = next(iter(req))
|
||||
req_val = req[req_key]
|
||||
if "." in req_key:
|
||||
errors.append(
|
||||
"Invalid requisite type '{}' "
|
||||
"in state '{}', in SLS "
|
||||
"'{}'. Requisite types must "
|
||||
"not contain dots, did you "
|
||||
"mean '{}'?".format(
|
||||
req_key,
|
||||
name,
|
||||
body["__sls__"],
|
||||
req_key[: req_key.find(".")],
|
||||
)
|
||||
)
|
||||
if not ishashable(req_val):
|
||||
errors.append(
|
||||
'Illegal requisite "{}", is SLS {}\n'.format(
|
||||
str(req_val),
|
||||
body["__sls__"],
|
||||
)
|
||||
)
|
||||
continue
|
||||
|
||||
# Check for global recursive requisites
|
||||
reqs[name][req_val] = req_key
|
||||
# I am going beyond 80 chars on
|
||||
# purpose, this is just too much
|
||||
# of a pain to deal with otherwise
|
||||
if req_val in reqs:
|
||||
if name in reqs[req_val]:
|
||||
if reqs[req_val][name] == state:
|
||||
if (
|
||||
reqs[req_val]["state"]
|
||||
== reqs[name][req_val]
|
||||
):
|
||||
errors.append(
|
||||
"A recursive requisite was"
|
||||
' found, SLS "{}" ID "{}"'
|
||||
' ID "{}"'.format(
|
||||
body["__sls__"],
|
||||
name,
|
||||
req_val,
|
||||
)
|
||||
)
|
||||
# Make sure that there is only one key in the
|
||||
# dict
|
||||
if len(list(arg)) != 1:
|
||||
errors.append(
|
||||
"Multiple dictionaries defined in argument "
|
||||
"of state '{}' in SLS '{}'".format(
|
||||
name, body["__sls__"]
|
||||
)
|
||||
)
|
||||
if not fun:
|
||||
if state == "require" or state == "watch":
|
||||
continue
|
||||
if not isinstance(body, dict):
|
||||
err = "The type {} in {} is not formatted as a dictionary".format(
|
||||
name, body
|
||||
)
|
||||
errors.append(err)
|
||||
continue
|
||||
for state in body:
|
||||
if state.startswith("__"):
|
||||
continue
|
||||
if not isinstance(body[state], list):
|
||||
errors.append(
|
||||
"No function declared in state '{}' in SLS '{}'".format(
|
||||
state, body["__sls__"]
|
||||
"State '{}' in SLS '{}' is not formed as a list".format(
|
||||
name, body["__sls__"]
|
||||
)
|
||||
)
|
||||
elif fun > 1:
|
||||
errors.append(
|
||||
"Too many functions declared in state '{}' in "
|
||||
"SLS '{}'".format(state, body["__sls__"])
|
||||
)
|
||||
else:
|
||||
fun = 0
|
||||
if "." in state:
|
||||
fun += 1
|
||||
for arg in body[state]:
|
||||
if isinstance(arg, str):
|
||||
fun += 1
|
||||
if " " in arg.strip():
|
||||
errors.append(
|
||||
'The function "{}" in state '
|
||||
'"{}" in SLS "{}" has '
|
||||
"whitespace, a function with whitespace is "
|
||||
"not supported, perhaps this is an argument "
|
||||
'that is missing a ":"'.format(
|
||||
arg, name, body["__sls__"]
|
||||
)
|
||||
)
|
||||
elif isinstance(arg, dict):
|
||||
# The arg is a dict, if the arg is require or
|
||||
# watch, it must be a list.
|
||||
#
|
||||
# Add the requires to the reqs dict and check them
|
||||
# all for recursive requisites.
|
||||
argfirst = next(iter(arg))
|
||||
if argfirst in (
|
||||
"require",
|
||||
"watch",
|
||||
"prereq",
|
||||
"onchanges",
|
||||
):
|
||||
if not isinstance(arg[argfirst], list):
|
||||
errors.append(
|
||||
"The {} statement in state '{}' in SLS '{}' "
|
||||
"needs to be formed as a list".format(
|
||||
argfirst, name, body["__sls__"]
|
||||
)
|
||||
)
|
||||
# It is a list, verify that the members of the
|
||||
# list are all single key dicts.
|
||||
else:
|
||||
reqs[name] = {"state": state}
|
||||
for req in arg[argfirst]:
|
||||
if isinstance(req, str):
|
||||
req = {"id": req}
|
||||
if not isinstance(req, dict):
|
||||
errors.append(
|
||||
"Requisite declaration {} in SLS {} "
|
||||
"is not formed as a single key "
|
||||
"dictionary".format(
|
||||
req, body["__sls__"]
|
||||
)
|
||||
)
|
||||
continue
|
||||
req_key = next(iter(req))
|
||||
req_val = req[req_key]
|
||||
if "." in req_key:
|
||||
errors.append(
|
||||
"Invalid requisite type '{}' "
|
||||
"in state '{}', in SLS "
|
||||
"'{}'. Requisite types must "
|
||||
"not contain dots, did you "
|
||||
"mean '{}'?".format(
|
||||
req_key,
|
||||
name,
|
||||
body["__sls__"],
|
||||
req_key[: req_key.find(".")],
|
||||
)
|
||||
)
|
||||
if not ishashable(req_val):
|
||||
errors.append(
|
||||
'Illegal requisite "{}", is SLS {}\n'.format(
|
||||
str(req_val),
|
||||
body["__sls__"],
|
||||
)
|
||||
)
|
||||
continue
|
||||
|
||||
# Check for global recursive requisites
|
||||
reqs[name][req_val] = req_key
|
||||
# I am going beyond 80 chars on
|
||||
# purpose, this is just too much
|
||||
# of a pain to deal with otherwise
|
||||
if req_val in reqs:
|
||||
if name in reqs[req_val]:
|
||||
if reqs[req_val][name] == state:
|
||||
if (
|
||||
reqs[req_val]["state"]
|
||||
== reqs[name][req_val]
|
||||
):
|
||||
errors.append(
|
||||
"A recursive requisite was"
|
||||
' found, SLS "{}" ID "{}"'
|
||||
' ID "{}"'.format(
|
||||
body["__sls__"],
|
||||
name,
|
||||
req_val,
|
||||
)
|
||||
)
|
||||
# Make sure that there is only one key in the
|
||||
# dict
|
||||
if len(list(arg)) != 1:
|
||||
errors.append(
|
||||
"Multiple dictionaries defined in argument "
|
||||
"of state '{}' in SLS '{}'".format(
|
||||
name, body["__sls__"]
|
||||
)
|
||||
)
|
||||
if not fun:
|
||||
if state == "require" or state == "watch":
|
||||
continue
|
||||
errors.append(
|
||||
"No function declared in state '{}' in SLS '{}'".format(
|
||||
state, body["__sls__"]
|
||||
)
|
||||
)
|
||||
elif fun > 1:
|
||||
errors.append(
|
||||
"Too many functions declared in state '{}' in "
|
||||
"SLS '{}'".format(state, body["__sls__"])
|
||||
)
|
||||
return errors
|
||||
|
||||
def order_chunks(self, chunks):
|
||||
|
|
|
@ -101,6 +101,9 @@ def present(
|
|||
docker_image.present:
|
||||
- tag: mytag
|
||||
|
||||
name
|
||||
The name of the docker image.
|
||||
|
||||
tag
|
||||
Tag name for the image. Required when using ``build``, ``load``, or
|
||||
``sls`` to create the image, but optional if pulling from a repository.
|
||||
|
@ -146,10 +149,14 @@ def present(
|
|||
.. versionchanged:: 2018.3.0
|
||||
The ``tag`` must be manually specified using the ``tag`` argument.
|
||||
|
||||
force : False
|
||||
force
|
||||
Set this parameter to ``True`` to force Salt to pull/build/load the
|
||||
image even if it is already present.
|
||||
|
||||
insecure_registry
|
||||
If ``True``, the Docker client will permit the use of insecure
|
||||
(non-HTTPS) registries.
|
||||
|
||||
client_timeout
|
||||
Timeout in seconds for the Docker client. This is not a timeout for
|
||||
the state, but for receiving a response from the API.
|
||||
|
@ -212,6 +219,10 @@ def present(
|
|||
``pillar_roots`` or an external Pillar source.
|
||||
|
||||
.. versionadded:: 2018.3.0
|
||||
|
||||
kwargs
|
||||
Additional keyword arguments to pass to
|
||||
:py:func:`docker.build <salt.modules.dockermod.build>`
|
||||
"""
|
||||
ret = {"name": name, "changes": {}, "result": False, "comment": ""}
|
||||
|
||||
|
@ -375,6 +386,9 @@ def absent(name=None, images=None, force=False):
|
|||
specified either using ``repo:tag`` notation, or just the repo name (in
|
||||
which case a tag of ``latest`` is assumed).
|
||||
|
||||
name
|
||||
The name of the docker image.
|
||||
|
||||
images
|
||||
Run this state on more than one image at a time. The following two
|
||||
examples accomplish the same thing:
|
||||
|
@ -401,7 +415,7 @@ def absent(name=None, images=None, force=False):
|
|||
all the deletions in a single run, rather than executing the state
|
||||
separately on each image (as it would in the first example).
|
||||
|
||||
force : False
|
||||
force
|
||||
Salt will fail to remove any images currently in use by a container.
|
||||
Set this option to true to remove the image even if it is already
|
||||
present.
|
||||
|
|
|
@ -2649,7 +2649,7 @@ class SaltKeyOptionParser(
|
|||
default=".",
|
||||
help=(
|
||||
"Set the directory to save the generated keypair, only "
|
||||
"works with \"gen_keys_dir\" option. Default: '%default'."
|
||||
"works with \"--gen-keys\" option. Default: '%default'."
|
||||
),
|
||||
)
|
||||
|
||||
|
@ -2767,10 +2767,11 @@ class SaltKeyOptionParser(
|
|||
|
||||
def process_gen_keys_dir(self):
|
||||
# Schedule __create_keys_dir() to run if there's a value for
|
||||
# --create-keys-dir
|
||||
self._mixin_after_parsed_funcs.append(
|
||||
self.__create_keys_dir
|
||||
) # pylint: disable=no-member
|
||||
# --gen-keys-dir
|
||||
if self.options.gen_keys:
|
||||
self._mixin_after_parsed_funcs.append(
|
||||
self.__create_keys_dir
|
||||
) # pylint: disable=no-member
|
||||
|
||||
def __create_keys_dir(self):
|
||||
if not os.path.isdir(self.config["gen_keys_dir"]):
|
||||
|
|
|
@ -44,7 +44,7 @@ class PublishModuleTest(ModuleCase, SaltReturnAssertsMixin):
|
|||
self.assertTrue(name in ret)
|
||||
|
||||
self.assertEqual(ret["cheese"], "spam")
|
||||
self.assertEqual(ret["__pub_arg"], [{"cheese": "spam"}])
|
||||
self.assertEqual(ret["__pub_arg"], [{"__kwarg__": True, "cheese": "spam"}])
|
||||
self.assertEqual(ret["__pub_id"], "minion")
|
||||
self.assertEqual(ret["__pub_fun"], "test.kwarg")
|
||||
|
||||
|
@ -125,7 +125,7 @@ class PublishModuleTest(ModuleCase, SaltReturnAssertsMixin):
|
|||
self.assertTrue(name in ret)
|
||||
|
||||
self.assertEqual(ret["cheese"], "spam")
|
||||
self.assertEqual(ret["__pub_arg"], [{"cheese": "spam"}])
|
||||
self.assertEqual(ret["__pub_arg"], [{"__kwarg__": True, "cheese": "spam"}])
|
||||
self.assertEqual(ret["__pub_id"], "minion")
|
||||
self.assertEqual(ret["__pub_fun"], "test.kwarg")
|
||||
|
||||
|
|
|
@ -353,3 +353,38 @@ def test_onlyif_req(state, subtests):
|
|||
assert ret.result is False
|
||||
assert ret.changes
|
||||
assert ret.comment == "Failure!"
|
||||
|
||||
|
||||
def test_listen_requisite_not_exist(state, state_tree):
|
||||
"""
|
||||
Tests a simple state using the listen requisite
|
||||
when the state id does not exist
|
||||
"""
|
||||
sls_contents = """
|
||||
successful_changing_state:
|
||||
cmd.run:
|
||||
- name: echo "Successful Change"
|
||||
|
||||
non_changing_state:
|
||||
test.succeed_without_changes
|
||||
|
||||
test_listening_change_state:
|
||||
cmd.run:
|
||||
- name: echo "Listening State"
|
||||
- listen:
|
||||
- cmd: successful_changing_state
|
||||
|
||||
test_listening_non_changing_state:
|
||||
cmd.run:
|
||||
- name: echo "Only run once"
|
||||
- listen:
|
||||
- test: non_changing_state_not_exist
|
||||
"""
|
||||
with pytest.helpers.temp_file("requisite.sls", sls_contents, state_tree):
|
||||
ret = state.sls("requisite")
|
||||
assert (
|
||||
ret.raw[
|
||||
"Listen_Error_|-listen_non_changing_state_not_exist_|-listen_test_|-Listen_Error"
|
||||
]["comment"]
|
||||
== "Referenced state test: non_changing_state_not_exist does not exist"
|
||||
)
|
||||
|
|
|
@ -7,6 +7,37 @@ pytestmark = [
|
|||
pytest.mark.core_test,
|
||||
]
|
||||
|
||||
import salt.modules.cmdmod as cmd
|
||||
import salt.modules.config as config
|
||||
import salt.modules.grains as grains
|
||||
import salt.modules.saltutil as saltutil
|
||||
import salt.modules.state as state_mod
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def configure_loader_modules(minion_opts):
|
||||
return {
|
||||
state_mod: {
|
||||
"__opts__": minion_opts,
|
||||
"__salt__": {
|
||||
"config.option": config.option,
|
||||
"config.get": config.get,
|
||||
"saltutil.is_running": saltutil.is_running,
|
||||
"grains.get": grains.get,
|
||||
"cmd.run": cmd.run,
|
||||
},
|
||||
},
|
||||
config: {
|
||||
"__opts__": minion_opts,
|
||||
},
|
||||
saltutil: {
|
||||
"__opts__": minion_opts,
|
||||
},
|
||||
grains: {
|
||||
"__opts__": minion_opts,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def test_requisites_mixed_require_prereq_use_1(state, state_tree):
|
||||
"""
|
||||
|
@ -401,3 +432,23 @@ def test_issue_30161_unless_and_onlyif_together(state, state_tree, tmp_path):
|
|||
}
|
||||
for slsid in _expected:
|
||||
assert ret[slsid].comment == _expected[slsid]["comment"]
|
||||
|
||||
|
||||
def test_requisites_mixed_illegal_req(state_tree):
|
||||
"""
|
||||
Call sls file containing several requisites.
|
||||
When one of the requisites is illegal.
|
||||
"""
|
||||
sls_contents = """
|
||||
A:
|
||||
cmd.run:
|
||||
- name: echo A
|
||||
B:
|
||||
cmd.run:
|
||||
- name: echo B
|
||||
- require:
|
||||
- cmd: ["A"]
|
||||
"""
|
||||
with pytest.helpers.temp_file("requisite.sls", sls_contents, state_tree):
|
||||
ret = state_mod.sls("requisite")
|
||||
assert ret == ["Illegal requisite \"['A']\", please check your syntax.\n"]
|
||||
|
|
|
@ -7,10 +7,16 @@ import time
|
|||
import pytest
|
||||
|
||||
import salt.loader
|
||||
import salt.modules.cmdmod as cmd
|
||||
import salt.modules.config as config
|
||||
import salt.modules.grains as grains
|
||||
import salt.modules.saltutil as saltutil
|
||||
import salt.modules.state as state_mod
|
||||
import salt.utils.atomicfile
|
||||
import salt.utils.files
|
||||
import salt.utils.path
|
||||
import salt.utils.platform
|
||||
import salt.utils.state as state_util
|
||||
import salt.utils.stringutils
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
@ -22,6 +28,32 @@ pytestmark = [
|
|||
]
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def configure_loader_modules(minion_opts):
|
||||
return {
|
||||
state_mod: {
|
||||
"__opts__": minion_opts,
|
||||
"__salt__": {
|
||||
"config.option": config.option,
|
||||
"config.get": config.get,
|
||||
"saltutil.is_running": saltutil.is_running,
|
||||
"grains.get": grains.get,
|
||||
"cmd.run": cmd.run,
|
||||
},
|
||||
"__utils__": {"state.check_result": state_util.check_result},
|
||||
},
|
||||
config: {
|
||||
"__opts__": minion_opts,
|
||||
},
|
||||
saltutil: {
|
||||
"__opts__": minion_opts,
|
||||
},
|
||||
grains: {
|
||||
"__opts__": minion_opts,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def _check_skip(grains):
|
||||
if grains["os"] == "SUSE":
|
||||
return True
|
||||
|
@ -1032,3 +1064,20 @@ def test_state_sls_defaults(state, state_tree):
|
|||
for state_return in ret:
|
||||
assert state_return.result is True
|
||||
assert "echo 1" in state_return.comment
|
||||
|
||||
|
||||
def test_state_sls_mock_ret(state_tree):
|
||||
"""
|
||||
test state.sls when mock=True is passed
|
||||
"""
|
||||
sls_contents = """
|
||||
echo1:
|
||||
cmd.run:
|
||||
- name: "echo 'This is a test!'"
|
||||
"""
|
||||
with pytest.helpers.temp_file("mock.sls", sls_contents, state_tree):
|
||||
ret = state_mod.sls("mock", mock=True)
|
||||
assert (
|
||||
ret["cmd_|-echo1_|-echo 'This is a test!'_|-run"]["comment"]
|
||||
== "Not called, mocked"
|
||||
)
|
||||
|
|
|
@ -337,6 +337,13 @@ def test_keys_generation(salt_key_cli, tmp_path):
|
|||
filename.chmod(0o700)
|
||||
|
||||
|
||||
def test_gen_keys_dir_without_gen_keys(salt_key_cli, tmp_path):
|
||||
gen_keys_path = tmp_path / "temp-gen-keys-path"
|
||||
ret = salt_key_cli.run("--gen-keys-dir", str(gen_keys_path))
|
||||
assert ret.returncode == 0
|
||||
assert not gen_keys_path.exists()
|
||||
|
||||
|
||||
def test_keys_generation_keysize_min(salt_key_cli, tmp_path):
|
||||
ret = salt_key_cli.run(
|
||||
"--gen-keys", "minibar", "--gen-keys-dir", str(tmp_path), "--keysize", "1024"
|
||||
|
|
669
tests/pytests/unit/state/test_reactor_compiler.py
Normal file
669
tests/pytests/unit/state/test_reactor_compiler.py
Normal file
|
@ -0,0 +1,669 @@
|
|||
import logging
|
||||
|
||||
import pytest
|
||||
|
||||
import salt.minion
|
||||
import salt.state
|
||||
from salt.utils.odict import OrderedDict
|
||||
from tests.support.mock import MagicMock, patch
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
pytestmark = [
|
||||
pytest.mark.core_test,
|
||||
]
|
||||
|
||||
|
||||
def test_compiler_render_template(minion_opts, tmp_path):
|
||||
"""
|
||||
Test Compiler.render_template
|
||||
"""
|
||||
minion = "poc-minion"
|
||||
kwargs = {
|
||||
"tag": f"salt/minion/{minion}/start",
|
||||
"data": {
|
||||
"id": minion,
|
||||
"cmd": "_minion_event",
|
||||
"pretag": None,
|
||||
"data": f"Minion {minion} started at Thu Sep 14 07:31:04 2023",
|
||||
"tag": f"salt/minion/{minion}/start",
|
||||
"_stamp": "2023-09-14T13:31:05.000316",
|
||||
},
|
||||
}
|
||||
|
||||
reactor_file = tmp_path / "reactor.sls"
|
||||
content = f"""
|
||||
highstate_run:
|
||||
local.state.apply:
|
||||
- tgt: {minion}
|
||||
- args:
|
||||
- mods: test
|
||||
"""
|
||||
with salt.utils.files.fopen(reactor_file, "w") as fp:
|
||||
fp.write(content)
|
||||
|
||||
mminion = salt.minion.MasterMinion(minion_opts)
|
||||
comp = salt.state.Compiler(minion_opts, mminion.rend)
|
||||
ret = comp.render_template(template=str(reactor_file), kwargs=kwargs)
|
||||
assert ret["highstate_run"]["local"][0]["tgt"] == minion
|
||||
assert ret["highstate_run"]["local"][1]["args"][0]["mods"] == "test"
|
||||
|
||||
|
||||
def test_compiler_render_template_doesnotexist(minion_opts, tmp_path):
|
||||
"""
|
||||
Test Compiler.render_template when
|
||||
the reactor file does not exist
|
||||
"""
|
||||
minion = "poc-minion"
|
||||
kwargs = {
|
||||
"tag": f"salt/minion/{minion}/start",
|
||||
"data": {
|
||||
"id": minion,
|
||||
"cmd": "_minion_event",
|
||||
"pretag": None,
|
||||
"data": f"Minion {minion} started at Thu Sep 14 07:31:04 2023",
|
||||
"tag": f"salt/minion/{minion}/start",
|
||||
"_stamp": "2023-09-14T13:31:05.000316",
|
||||
},
|
||||
}
|
||||
|
||||
reactor_file = tmp_path / "reactor.sls"
|
||||
mminion = salt.minion.MasterMinion(minion_opts)
|
||||
comp = salt.state.Compiler(minion_opts, mminion.rend)
|
||||
mock_pad = MagicMock(return_value=None)
|
||||
patch_pad = patch.object(comp, "pad_funcs", mock_pad)
|
||||
with patch_pad:
|
||||
ret = comp.render_template(template=str(reactor_file), kwargs=kwargs)
|
||||
assert ret == {}
|
||||
mock_pad.assert_not_called()
|
||||
|
||||
|
||||
def test_compiler_pad_funcs(minion_opts, tmp_path):
|
||||
"""
|
||||
Test Compiler.pad_funcs
|
||||
"""
|
||||
high = OrderedDict(
|
||||
[
|
||||
(
|
||||
"highstate_run",
|
||||
OrderedDict(
|
||||
[
|
||||
(
|
||||
"local.state.apply",
|
||||
[
|
||||
OrderedDict([("tgt", "poc-minion")]),
|
||||
OrderedDict(
|
||||
[("args", [OrderedDict([("mods", "test")])])]
|
||||
),
|
||||
],
|
||||
)
|
||||
]
|
||||
),
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
exp = OrderedDict(
|
||||
[
|
||||
(
|
||||
"highstate_run",
|
||||
OrderedDict(
|
||||
[
|
||||
(
|
||||
"local",
|
||||
[
|
||||
OrderedDict([("tgt", "poc-minion")]),
|
||||
OrderedDict(
|
||||
[("args", [OrderedDict([("mods", "test")])])]
|
||||
),
|
||||
"state.apply",
|
||||
],
|
||||
)
|
||||
]
|
||||
),
|
||||
)
|
||||
]
|
||||
)
|
||||
mminion = salt.minion.MasterMinion(minion_opts)
|
||||
comp = salt.state.Compiler(minion_opts, mminion.rend)
|
||||
ret = comp.pad_funcs(high)
|
||||
assert ret == exp
|
||||
|
||||
|
||||
def test_compiler_pad_funcs_short_sls(minion_opts, tmp_path):
|
||||
"""
|
||||
Test Compiler.pad_funcs when using a shorter
|
||||
sls with no extra arguments
|
||||
"""
|
||||
high = OrderedDict([("master_pub", "wheel.key.master_key_str")])
|
||||
exp = OrderedDict([("master_pub", {"wheel": ["key.master_key_str"]})])
|
||||
|
||||
mminion = salt.minion.MasterMinion(minion_opts)
|
||||
comp = salt.state.Compiler(minion_opts, mminion.rend)
|
||||
ret = comp.pad_funcs(high)
|
||||
assert ret == exp
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"high,exp",
|
||||
[
|
||||
(
|
||||
{
|
||||
"master_pub": {
|
||||
"wheel": ["key.master_key_str"],
|
||||
"__sls__": "/srv/reactor/start.sls",
|
||||
}
|
||||
},
|
||||
[],
|
||||
),
|
||||
(set(), ["High data is not a dictionary and is invalid"]),
|
||||
(
|
||||
{
|
||||
1234: {
|
||||
"wheel": ["key.master_key_str"],
|
||||
"__sls__": "/srv/reactor/start.sls",
|
||||
}
|
||||
},
|
||||
[
|
||||
"ID '1234' in SLS '/srv/reactor/start.sls' is not formed as a string, but is a int. It may need to be quoted"
|
||||
],
|
||||
),
|
||||
(
|
||||
{
|
||||
b"test": {
|
||||
"wheel": ["key.master_key_str"],
|
||||
"__sls__": "/srv/reactor/start.sls",
|
||||
}
|
||||
},
|
||||
[
|
||||
"ID 'b'test'' in SLS '/srv/reactor/start.sls' is not formed as a string, but is a bytes. It may need to be quoted"
|
||||
],
|
||||
),
|
||||
(
|
||||
{
|
||||
True: {
|
||||
"wheel": ["key.master_key_str"],
|
||||
"__sls__": "/srv/reactor/start.sls",
|
||||
}
|
||||
},
|
||||
[
|
||||
"ID 'True' in SLS '/srv/reactor/start.sls' is not formed as a string, but is a bool. It may need to be quoted"
|
||||
],
|
||||
),
|
||||
(
|
||||
{"master_pub": ["wheel", "key.master_key_str"]},
|
||||
[
|
||||
"The type master_pub in ['wheel', 'key.master_key_str'] is not formatted as a dictionary"
|
||||
],
|
||||
),
|
||||
(
|
||||
{
|
||||
"master_pub": {
|
||||
"wheel": {"key.master_key_str"},
|
||||
"__sls__": "/srv/reactor/start.sls",
|
||||
}
|
||||
},
|
||||
[
|
||||
"State 'master_pub' in SLS '/srv/reactor/start.sls' is not formed as a list"
|
||||
],
|
||||
),
|
||||
(
|
||||
{
|
||||
"master_pub": {
|
||||
"wheel": ["key. master_key_str"],
|
||||
"__sls__": "/srv/reactor/start.sls",
|
||||
}
|
||||
},
|
||||
[
|
||||
'The function "key. master_key_str" in state "master_pub" in SLS "/srv/reactor/start.sls" has whitespace, a function with whitespace is not supported, perhaps this is an argument that is missing a ":"'
|
||||
],
|
||||
),
|
||||
(
|
||||
{
|
||||
"master_pub": {
|
||||
"wheel": ["key.master_key_str "],
|
||||
"__sls__": "/srv/reactor/start.sls",
|
||||
}
|
||||
},
|
||||
[],
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_compiler_verify_high_short_sls(minion_opts, tmp_path, high, exp):
|
||||
"""
|
||||
Test Compiler.verify_high when using
|
||||
a shorter sls with know extra arguments
|
||||
"""
|
||||
mminion = salt.minion.MasterMinion(minion_opts)
|
||||
comp = salt.state.Compiler(minion_opts, mminion.rend)
|
||||
ret = comp.verify_high(high)
|
||||
# empty is successful. Means we have no errors
|
||||
assert ret == exp
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"high,exp",
|
||||
[
|
||||
(
|
||||
{
|
||||
"add_test_1": OrderedDict(
|
||||
[
|
||||
(
|
||||
"local",
|
||||
[
|
||||
OrderedDict([("tgt", "poc-minion")]),
|
||||
OrderedDict(
|
||||
[
|
||||
(
|
||||
"args",
|
||||
[
|
||||
OrderedDict(
|
||||
[("cmd", "touch /tmp/test1")]
|
||||
)
|
||||
],
|
||||
)
|
||||
]
|
||||
),
|
||||
"cmd.run",
|
||||
],
|
||||
),
|
||||
("__sls__", "/srv/reactor/start.sls"),
|
||||
]
|
||||
),
|
||||
"add_test_2": OrderedDict(
|
||||
[
|
||||
(
|
||||
"local",
|
||||
[
|
||||
OrderedDict([("tgt", "poc-minion")]),
|
||||
OrderedDict(
|
||||
[
|
||||
(
|
||||
"args",
|
||||
[
|
||||
OrderedDict(
|
||||
[("cmd", "touch /tmp/test2")]
|
||||
)
|
||||
],
|
||||
)
|
||||
]
|
||||
),
|
||||
OrderedDict(
|
||||
[
|
||||
(
|
||||
"require",
|
||||
[OrderedDict([("local", "add_test_1")])],
|
||||
)
|
||||
]
|
||||
),
|
||||
"cmd.run",
|
||||
],
|
||||
),
|
||||
("__sls__", "/srv/reactor/start.sls"),
|
||||
]
|
||||
),
|
||||
},
|
||||
[],
|
||||
),
|
||||
(
|
||||
{
|
||||
"add_test_1": OrderedDict(
|
||||
[
|
||||
(
|
||||
"local",
|
||||
[
|
||||
OrderedDict([("tgt", "poc-minion")]),
|
||||
OrderedDict(
|
||||
[
|
||||
(
|
||||
"args",
|
||||
[
|
||||
OrderedDict(
|
||||
[("cmd", "touch /tmp/test1")]
|
||||
)
|
||||
],
|
||||
)
|
||||
]
|
||||
),
|
||||
"cmd.run",
|
||||
],
|
||||
),
|
||||
("__sls__", "/srv/reactor/start.sls"),
|
||||
]
|
||||
),
|
||||
"add_test_2": OrderedDict(
|
||||
[
|
||||
(
|
||||
"local",
|
||||
[
|
||||
OrderedDict([("tgt", "poc-minion")]),
|
||||
OrderedDict(
|
||||
[
|
||||
(
|
||||
"args",
|
||||
[
|
||||
OrderedDict(
|
||||
[("cmd", "touch /tmp/test2")]
|
||||
)
|
||||
],
|
||||
)
|
||||
]
|
||||
),
|
||||
OrderedDict([("require", {"local": "add_test_1"})]),
|
||||
"cmd.run",
|
||||
],
|
||||
),
|
||||
("__sls__", "/srv/reactor/start.sls"),
|
||||
]
|
||||
),
|
||||
},
|
||||
[
|
||||
"The require statement in state 'add_test_2' in SLS '/srv/reactor/start.sls' needs to be formed as a list"
|
||||
],
|
||||
),
|
||||
(
|
||||
{
|
||||
"add_test_1": OrderedDict(
|
||||
[
|
||||
(
|
||||
"local",
|
||||
[
|
||||
OrderedDict([("tgt", "poc-minion")]),
|
||||
OrderedDict(
|
||||
[
|
||||
(
|
||||
"args",
|
||||
[
|
||||
OrderedDict(
|
||||
[("cmd", "touch /tmp/test1")]
|
||||
)
|
||||
],
|
||||
)
|
||||
]
|
||||
),
|
||||
"cmd.run",
|
||||
],
|
||||
),
|
||||
("__sls__", "/srv/reactor/start.sls"),
|
||||
]
|
||||
),
|
||||
"add_test_2": OrderedDict(
|
||||
[
|
||||
(
|
||||
"local.cmd.run",
|
||||
[
|
||||
OrderedDict([("tgt", "poc-minion")]),
|
||||
OrderedDict(
|
||||
[
|
||||
(
|
||||
"args",
|
||||
[
|
||||
OrderedDict(
|
||||
[("cmd", "touch /tmp/test2")]
|
||||
)
|
||||
],
|
||||
)
|
||||
]
|
||||
),
|
||||
OrderedDict([("require", {"local": "add_test_1"})]),
|
||||
"cmd.run",
|
||||
],
|
||||
),
|
||||
("__sls__", "/srv/reactor/start.sls"),
|
||||
]
|
||||
),
|
||||
},
|
||||
[
|
||||
"The require statement in state 'add_test_2' in SLS '/srv/reactor/start.sls' needs to be formed as a list",
|
||||
"Too many functions declared in state 'local.cmd.run' in SLS '/srv/reactor/start.sls'",
|
||||
],
|
||||
),
|
||||
(
|
||||
{
|
||||
"add_test_1": OrderedDict(
|
||||
[
|
||||
(
|
||||
"local",
|
||||
[
|
||||
OrderedDict([("tgt", "poc-minion")]),
|
||||
OrderedDict(
|
||||
[("args", ([("cmd", "touch /tmp/test1")]))]
|
||||
),
|
||||
"cmd.run",
|
||||
],
|
||||
),
|
||||
("__sls__", "/srv/reactor/start.sls"),
|
||||
]
|
||||
),
|
||||
"add_test_2": OrderedDict(
|
||||
[
|
||||
(
|
||||
"local",
|
||||
[
|
||||
OrderedDict([("tgt", "poc-minion")]),
|
||||
OrderedDict(
|
||||
[
|
||||
(
|
||||
"args",
|
||||
[
|
||||
OrderedDict(
|
||||
[("cmd", "touch /tmp/test2")]
|
||||
)
|
||||
],
|
||||
)
|
||||
]
|
||||
),
|
||||
OrderedDict([("require", ([("local", "add_test_1")]))]),
|
||||
"cmd.run",
|
||||
],
|
||||
),
|
||||
("__sls__", "/srv/reactor/start.sls"),
|
||||
]
|
||||
),
|
||||
},
|
||||
[
|
||||
"Requisite declaration ('local', 'add_test_1') in SLS /srv/reactor/start.sls is not formed as a single key dictionary"
|
||||
],
|
||||
),
|
||||
(
|
||||
{
|
||||
"add_test_1": OrderedDict(
|
||||
[
|
||||
(
|
||||
"local",
|
||||
[
|
||||
OrderedDict([("tgt", "poc-minion")]),
|
||||
OrderedDict(
|
||||
[
|
||||
(
|
||||
"args",
|
||||
[
|
||||
OrderedDict(
|
||||
[("cmd", "touch /tmp/test1")]
|
||||
)
|
||||
],
|
||||
)
|
||||
]
|
||||
),
|
||||
"cmd.run",
|
||||
],
|
||||
),
|
||||
("__sls__", "/srv/reactor/start.sls"),
|
||||
]
|
||||
),
|
||||
"add_test_2": OrderedDict(
|
||||
[
|
||||
(
|
||||
"local",
|
||||
[
|
||||
OrderedDict([("tgt", "poc-minion")]),
|
||||
OrderedDict(
|
||||
[
|
||||
(
|
||||
"args",
|
||||
[
|
||||
OrderedDict(
|
||||
[("cmd", "touch /tmp/test2")]
|
||||
)
|
||||
],
|
||||
)
|
||||
]
|
||||
),
|
||||
OrderedDict(
|
||||
[
|
||||
(
|
||||
"require",
|
||||
[
|
||||
OrderedDict(
|
||||
[("local", (["add_test_1"]))]
|
||||
)
|
||||
],
|
||||
)
|
||||
]
|
||||
),
|
||||
"cmd.run",
|
||||
],
|
||||
),
|
||||
("__sls__", "/srv/reactor/start.sls"),
|
||||
]
|
||||
),
|
||||
},
|
||||
["Illegal requisite \"['add_test_1']\", is SLS /srv/reactor/start.sls\n"],
|
||||
),
|
||||
(
|
||||
{
|
||||
"add_test_1": OrderedDict(
|
||||
[
|
||||
(
|
||||
"local",
|
||||
[
|
||||
OrderedDict([("tgt", "poc-minion")]),
|
||||
OrderedDict(
|
||||
[
|
||||
(
|
||||
"args",
|
||||
[
|
||||
OrderedDict(
|
||||
[("cmd", "touch /tmp/test1")]
|
||||
)
|
||||
],
|
||||
)
|
||||
]
|
||||
),
|
||||
"cmd.run",
|
||||
],
|
||||
),
|
||||
("__sls__", "/srv/reactor/start.sls"),
|
||||
]
|
||||
),
|
||||
"add_test_2": OrderedDict(
|
||||
[
|
||||
(
|
||||
"local",
|
||||
[
|
||||
OrderedDict([("tgt", "poc-minion")]),
|
||||
OrderedDict(
|
||||
[
|
||||
(
|
||||
"args",
|
||||
[
|
||||
OrderedDict(
|
||||
[("cmd", "touch /tmp/test2")]
|
||||
)
|
||||
],
|
||||
)
|
||||
]
|
||||
),
|
||||
OrderedDict(
|
||||
[
|
||||
(
|
||||
"require",
|
||||
[OrderedDict([("local", "add_test_2")])],
|
||||
)
|
||||
]
|
||||
),
|
||||
"cmd.run",
|
||||
],
|
||||
),
|
||||
("__sls__", "/srv/reactor/start.sls"),
|
||||
]
|
||||
),
|
||||
},
|
||||
[
|
||||
'A recursive requisite was found, SLS "/srv/reactor/start.sls" ID "add_test_2" ID "add_test_2"'
|
||||
],
|
||||
),
|
||||
(
|
||||
{
|
||||
"add_test_1": OrderedDict(
|
||||
[
|
||||
(
|
||||
"local",
|
||||
[
|
||||
OrderedDict([("tgt", "poc-minion")]),
|
||||
OrderedDict(
|
||||
[
|
||||
(
|
||||
"args",
|
||||
[
|
||||
OrderedDict(
|
||||
[("cmd", "touch /tmp/test1")]
|
||||
)
|
||||
],
|
||||
)
|
||||
]
|
||||
),
|
||||
"cmd.run",
|
||||
],
|
||||
),
|
||||
("__sls__", "/srv/reactor/start.sls"),
|
||||
]
|
||||
),
|
||||
"add_test_2": OrderedDict(
|
||||
[
|
||||
(
|
||||
"local",
|
||||
[
|
||||
OrderedDict([("tgt", "poc-minion")]),
|
||||
OrderedDict(
|
||||
[
|
||||
(
|
||||
"args",
|
||||
[
|
||||
OrderedDict(
|
||||
[("cmd", "touch /tmp/test2")]
|
||||
)
|
||||
],
|
||||
)
|
||||
]
|
||||
),
|
||||
OrderedDict(
|
||||
[
|
||||
(
|
||||
"require",
|
||||
[OrderedDict([("local", "add_test_1")])],
|
||||
)
|
||||
]
|
||||
),
|
||||
"cmd.run",
|
||||
],
|
||||
),
|
||||
("__sls__", "/srv/reactor/start.sls"),
|
||||
]
|
||||
),
|
||||
},
|
||||
[],
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_compiler_verify_high_sls_requisites(minion_opts, tmp_path, high, exp):
|
||||
"""
|
||||
Test Compiler.verify_high when using
|
||||
a sls with requisites
|
||||
"""
|
||||
mminion = salt.minion.MasterMinion(minion_opts)
|
||||
comp = salt.state.Compiler(minion_opts, mminion.rend)
|
||||
ret = comp.verify_high(high)
|
||||
# empty is successful. Means we have no errors
|
||||
assert ret == exp
|
|
@ -38,6 +38,16 @@ def test_format_log_non_ascii_character():
|
|||
salt.state.format_log(ret)
|
||||
|
||||
|
||||
def test_format_log_list(caplog):
|
||||
"""
|
||||
Test running format_log when ret is not a dictionary
|
||||
"""
|
||||
ret = ["test1", "test2"]
|
||||
salt.state.format_log(ret)
|
||||
assert "INFO" in caplog.text
|
||||
assert f"{ret}" in caplog.text
|
||||
|
||||
|
||||
def test_render_error_on_invalid_requisite(minion_opts):
|
||||
"""
|
||||
Test that the state compiler correctly deliver a rendering
|
||||
|
|
|
@ -8,6 +8,7 @@ import tornado.gen
|
|||
import tornado.testing
|
||||
|
||||
import salt.minion
|
||||
import salt.modules.test as test_mod
|
||||
import salt.syspaths
|
||||
import salt.utils.crypt
|
||||
import salt.utils.event as event
|
||||
|
@ -1109,3 +1110,19 @@ async def test_syndic_async_req_channel(syndic_opts):
|
|||
syndic.pub_channel = MagicMock()
|
||||
syndic.tune_in_no_block()
|
||||
assert isinstance(syndic.async_req_channel, salt.channel.client.AsyncReqChannel)
|
||||
|
||||
|
||||
@pytest.mark.slow_test
|
||||
def test_load_args_and_kwargs(minion_opts):
|
||||
"""
|
||||
Ensure load_args_and_kwargs performs correctly
|
||||
"""
|
||||
_args = [{"max": 40, "__kwarg__": True}]
|
||||
ret = salt.minion.load_args_and_kwargs(test_mod.rand_sleep, _args)
|
||||
assert ret == ([], {"max": 40})
|
||||
assert all([True if "__kwarg__" in item else False for item in _args])
|
||||
|
||||
# Test invalid arguments
|
||||
_args = [{"max_sleep": 40, "__kwarg__": True}]
|
||||
with pytest.raises(salt.exceptions.SaltInvocationError):
|
||||
ret = salt.minion.load_args_and_kwargs(test_mod.rand_sleep, _args)
|
||||
|
|
Loading…
Add table
Reference in a new issue