Merge pull request #64931 from s0undt3ch/hotfix/merge-forward

[master] Merge 3006.x into master
This commit is contained in:
Megan Wilhite 2023-08-07 19:34:39 +00:00 committed by GitHub
commit c2d2522f1f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
88 changed files with 1591 additions and 998 deletions

1
changelog/63824.fixed.md Normal file
View file

@ -0,0 +1 @@
Allow long running pillar and file client requests to finish using request_channel_timeout and request_channel_tries minion config.

View file

@ -0,0 +1 @@
Replace libnacl with PyNaCl

View file

@ -1,3 +1,10 @@
Upgrade to `cryptography==41.0.1`(and therefor `pyopenssl==23.2.0` due to https://github.com/advisories/GHSA-5cpq-8wj7-hf2v
Upgrade to `cryptography==41.0.3`(and therefor `pyopenssl==23.2.0` due to https://github.com/advisories/GHSA-jm77-qphf-c4w8)
This only really impacts pip installs of Salt and the windows onedir since the linux and macos onedir build every package dependency from source, not from pre-existing wheels.
Also resolves the following cryptography advisories:
Due to:
* https://github.com/advisories/GHSA-5cpq-8wj7-hf2v
* https://github.com/advisories/GHSA-x4qr-2fvf-3mr5
* https://github.com/advisories/GHSA-w7pp-m8wf-vj6r

View file

@ -1 +1 @@
Added support for Chocolatey 2.0.0+
Added support for Chocolatey 2.0.0+ while maintaining support for older versions

1
changelog/64651.fixed.md Normal file
View file

@ -0,0 +1 @@
Show user friendly message when pillars timeout

1
changelog/64653.fixed.md Normal file
View file

@ -0,0 +1 @@
File client timeouts durring jobs show user friendly errors instead of tracbacks

1
changelog/64729.fixed.md Normal file
View file

@ -0,0 +1 @@
SaltClientError does not log a traceback on minions, we expect these to happen so a user friendly log is shown.

View file

@ -1305,6 +1305,36 @@ restart.
auth_safemode: False
.. conf_minion:: request_channel_timeout
``request_channel_timeout``
---------------------------
.. versionadded:: 3006.2
Default: ``30``
The default timeout timeout for request channel requests. This setting can be used to tune minions to better handle long running pillar and file client requests.
.. code-block:: yaml
request_channel_timeout: 30
``request_channel_tries``
-------------------------
.. versionadded:: 3006.2
Default: ``3``
The default number of times the minion will try request channel requests. This
setting can be used to tune minions to better handle long running pillar and
file client requests by retrying them after a timeout happens.
.. code-block:: yaml
request_channel_tries: 3
.. conf_minion:: ping_interval
``ping_interval``

View file

@ -1,2 +1,2 @@
pycryptodomex>=3.9.8
cryptography>=40.0.2
cryptography>=40.0.3

View file

@ -6,7 +6,7 @@ apache-libcloud>=2.4.0
backports.ssl_match_hostname>=3.7.0.1; python_version < '3.7'
cherrypy>=17.4.1
gitpython>=3.1.30
cryptography>=41.0.2
cryptography>=41.0.3
idna>=2.8
linode-python>=1.1.1
pyasn1>=0.4.8

View file

@ -9,7 +9,7 @@ boto3>=1.21.46
boto>=2.46.0
cassandra-driver>=2.0
certifi>=2022.12.07
cffi>=1.12.2
cffi>=1.14.6
cherrypy>=17.4.1
clustershell
croniter>=0.3.0,!=0.3.22"; sys_platform != 'win32'
@ -32,6 +32,7 @@ paramiko>=2.10.1; sys_platform != 'win32' and sys_platform != 'darwin'
# since that will break using the compiled static requirements files as contraints file
bcrypt
passlib>=1.7.4
pynacl>=1.5.0
pyinotify>=0.9.6; sys_platform != 'win32' and sys_platform != 'darwin' and platform_system != "openbsd"
python-etcd>0.4.2
pyvmomi

View file

@ -2,5 +2,5 @@
--constraint=./py{py_version}/{platform}.txt
pylint==2.4.4
SaltPyLint>=v2020.9.28
SaltPyLint>=2023.3.8
toml

View file

@ -16,11 +16,11 @@ cffi==1.15.1
# via
# -c requirements/static/ci/py3.10/linux.txt
# cryptography
charset-normalizer==2.1.1
charset-normalizer==3.1.0
# via
# -c requirements/static/ci/py3.10/linux.txt
# requests
cryptography==41.0.2
cryptography==41.0.3
# via
# -c requirements/static/ci/py3.10/linux.txt
# pyspnego

View file

@ -67,7 +67,7 @@ cffi==1.15.1
# napalm
# pygit2
# pynacl
charset-normalizer==2.1.1
charset-normalizer==3.1.0
# via
# -c requirements/static/ci/../pkg/py3.10/darwin.txt
# aiohttp
@ -93,7 +93,7 @@ contextvars==2.4
# -r requirements/base.txt
croniter==1.3.15 ; sys_platform != "win32"
# via -r requirements/static/ci/common.in
cryptography==41.0.2
cryptography==41.0.3
# via
# -c requirements/static/ci/../pkg/py3.10/darwin.txt
# -r requirements/crypto.txt
@ -335,7 +335,9 @@ pyeapi==1.0.0
pygit2==1.12.1
# via -r requirements/static/ci/darwin.in
pynacl==1.5.0
# via paramiko
# via
# -r requirements/static/ci/common.in
# paramiko
pyopenssl==23.2.0
# via
# -c requirements/static/ci/../pkg/py3.10/darwin.txt

View file

@ -16,7 +16,7 @@ certifi==2023.07.22
# via
# -c requirements/static/ci/py3.10/linux.txt
# requests
charset-normalizer==2.1.1
charset-normalizer==3.1.0
# via
# -c requirements/static/ci/py3.10/linux.txt
# requests

View file

@ -63,7 +63,7 @@ cffi==1.15.1
# cryptography
# napalm
# pynacl
charset-normalizer==2.1.1
charset-normalizer==3.1.0
# via
# -c requirements/static/ci/../pkg/py3.10/freebsd.txt
# aiohttp
@ -89,10 +89,11 @@ contextvars==2.4
# -r requirements/base.txt
croniter==1.3.15 ; sys_platform != "win32"
# via -r requirements/static/ci/common.in
cryptography==41.0.2
cryptography==41.0.3
# via
# -c requirements/static/ci/../pkg/py3.10/freebsd.txt
# -r requirements/crypto.txt
# -r requirements/static/pkg/freebsd.in
# etcd3-py
# moto
# paramiko
@ -329,7 +330,9 @@ pyeapi==1.0.0
pyinotify==0.9.6 ; sys_platform != "win32" and sys_platform != "darwin" and platform_system != "openbsd"
# via -r requirements/static/ci/common.in
pynacl==1.5.0
# via paramiko
# via
# -r requirements/static/ci/common.in
# paramiko
pyopenssl==23.2.0
# via
# -c requirements/static/ci/../pkg/py3.10/freebsd.txt

View file

@ -20,7 +20,7 @@ pylint==2.4.4
# via
# -r requirements/static/ci/lint.in
# saltpylint
saltpylint==2020.9.28
saltpylint==2023.8.3
# via -r requirements/static/ci/lint.in
six==1.16.0
# via

View file

@ -77,7 +77,7 @@ cffi==1.15.1
# napalm
# pygit2
# pynacl
charset-normalizer==2.1.1
charset-normalizer==3.1.0
# via
# -c requirements/static/ci/../pkg/py3.10/linux.txt
# aiohttp
@ -103,7 +103,7 @@ contextvars==2.4
# -r requirements/base.txt
croniter==1.3.15 ; sys_platform != "win32"
# via -r requirements/static/ci/common.in
cryptography==41.0.2
cryptography==41.0.3
# via
# -c requirements/static/ci/../pkg/py3.10/linux.txt
# -r requirements/crypto.txt
@ -363,7 +363,9 @@ pyjwt==2.7.0
pymysql==1.0.3
# via -r requirements/static/ci/linux.in
pynacl==1.5.0
# via paramiko
# via
# -r requirements/static/ci/common.in
# paramiko
pyopenssl==23.2.0
# via
# -c requirements/static/ci/../pkg/py3.10/linux.txt

View file

@ -30,7 +30,7 @@ colorama==0.4.6
# via pytest
contextvars==2.4
# via -r requirements/base.txt
cryptography==41.0.1
cryptography==41.0.3
# via -r requirements/crypto.txt
distlib==0.3.6
# via virtualenv

View file

@ -24,7 +24,7 @@ cherrypy==18.8.0
# via -r requirements/static/ci/pkgtests.in
contextvars==2.4
# via -r requirements/base.txt
cryptography==41.0.1
cryptography==41.0.3
# via -r requirements/crypto.txt
distlib==0.3.6
# via virtualenv

View file

@ -55,7 +55,8 @@ cffi==1.14.6
# clr-loader
# cryptography
# pygit2
charset-normalizer==2.1.1
# pynacl
charset-normalizer==3.1.0
# via
# -c requirements/static/ci/../pkg/py3.10/windows.txt
# aiohttp
@ -87,7 +88,7 @@ contextvars==2.4
# via
# -c requirements/static/ci/../pkg/py3.10/windows.txt
# -r requirements/base.txt
cryptography==41.0.2
cryptography==41.0.3
# via
# -c requirements/static/ci/../pkg/py3.10/windows.txt
# -r requirements/crypto.txt
@ -294,6 +295,8 @@ pymysql==1.0.2
# via
# -c requirements/static/ci/../pkg/py3.10/windows.txt
# -r requirements/windows.txt
pynacl==1.5.0
# via -r requirements/static/ci/common.in
pyopenssl==23.2.0
# via
# -c requirements/static/ci/../pkg/py3.10/windows.txt

View file

@ -16,11 +16,11 @@ cffi==1.15.1
# via
# -c requirements/static/ci/py3.11/linux.txt
# cryptography
charset-normalizer==2.1.1
charset-normalizer==3.1.0
# via
# -c requirements/static/ci/py3.11/linux.txt
# requests
cryptography==41.0.2
cryptography==41.0.3
# via
# -c requirements/static/ci/py3.11/linux.txt
# pyspnego

View file

@ -67,7 +67,7 @@ cffi==1.15.1
# napalm
# pygit2
# pynacl
charset-normalizer==2.1.1
charset-normalizer==3.1.0
# via
# -c requirements/static/ci/../pkg/py3.11/darwin.txt
# aiohttp
@ -93,7 +93,7 @@ contextvars==2.4
# -r requirements/base.txt
croniter==1.3.15 ; sys_platform != "win32"
# via -r requirements/static/ci/common.in
cryptography==41.0.2
cryptography==41.0.3
# via
# -c requirements/static/ci/../pkg/py3.11/darwin.txt
# -r requirements/crypto.txt
@ -333,7 +333,9 @@ pyeapi==1.0.0
pygit2==1.12.1
# via -r requirements/static/ci/darwin.in
pynacl==1.5.0
# via paramiko
# via
# -r requirements/static/ci/common.in
# paramiko
pyopenssl==23.2.0
# via
# -c requirements/static/ci/../pkg/py3.11/darwin.txt

View file

@ -16,7 +16,7 @@ certifi==2023.07.22
# via
# -c requirements/static/ci/py3.11/linux.txt
# requests
charset-normalizer==2.1.1
charset-normalizer==3.1.0
# via
# -c requirements/static/ci/py3.11/linux.txt
# requests

View file

@ -63,7 +63,7 @@ cffi==1.15.1
# cryptography
# napalm
# pynacl
charset-normalizer==2.1.1
charset-normalizer==3.1.0
# via
# -c requirements/static/ci/../pkg/py3.11/freebsd.txt
# aiohttp
@ -89,10 +89,11 @@ contextvars==2.4
# -r requirements/base.txt
croniter==1.3.15 ; sys_platform != "win32"
# via -r requirements/static/ci/common.in
cryptography==41.0.2
cryptography==41.0.3
# via
# -c requirements/static/ci/../pkg/py3.11/freebsd.txt
# -r requirements/crypto.txt
# -r requirements/static/pkg/freebsd.in
# etcd3-py
# moto
# paramiko
@ -327,7 +328,9 @@ pyeapi==1.0.0
pyinotify==0.9.6 ; sys_platform != "win32" and sys_platform != "darwin" and platform_system != "openbsd"
# via -r requirements/static/ci/common.in
pynacl==1.5.0
# via paramiko
# via
# -r requirements/static/ci/common.in
# paramiko
pyopenssl==23.2.0
# via
# -c requirements/static/ci/../pkg/py3.11/freebsd.txt

View file

@ -20,7 +20,7 @@ pylint==2.4.4
# via
# -r requirements/static/ci/lint.in
# saltpylint
saltpylint==2020.9.28
saltpylint==2023.8.3
# via -r requirements/static/ci/lint.in
six==1.16.0
# via

View file

@ -77,7 +77,7 @@ cffi==1.15.1
# napalm
# pygit2
# pynacl
charset-normalizer==2.1.1
charset-normalizer==3.1.0
# via
# -c requirements/static/ci/../pkg/py3.11/linux.txt
# aiohttp
@ -103,7 +103,7 @@ contextvars==2.4
# -r requirements/base.txt
croniter==1.3.15 ; sys_platform != "win32"
# via -r requirements/static/ci/common.in
cryptography==41.0.2
cryptography==41.0.3
# via
# -c requirements/static/ci/../pkg/py3.11/linux.txt
# -r requirements/crypto.txt
@ -359,7 +359,9 @@ pyjwt==2.7.0
pymysql==1.0.3
# via -r requirements/static/ci/linux.in
pynacl==1.5.0
# via paramiko
# via
# -r requirements/static/ci/common.in
# paramiko
pyopenssl==23.2.0
# via
# -c requirements/static/ci/../pkg/py3.11/linux.txt

View file

@ -18,7 +18,7 @@ cffi==1.15.1
# via
# clr-loader
# cryptography
charset-normalizer==2.1.1
charset-normalizer==3.1.0
# via requests
cheroot==10.0.0
# via cherrypy
@ -30,7 +30,7 @@ colorama==0.4.6
# via pytest
contextvars==2.4
# via -r requirements/base.txt
cryptography==40.0.2
cryptography==41.0.3
# via -r requirements/crypto.txt
distlib==0.3.6
# via virtualenv

View file

@ -16,7 +16,7 @@ certifi==2023.07.22
# via requests
cffi==1.15.1
# via cryptography
charset-normalizer==2.1.1
charset-normalizer==3.1.0
# via requests
cheroot==10.0.0
# via cherrypy
@ -24,7 +24,7 @@ cherrypy==18.8.0
# via -r requirements/static/ci/pkgtests.in
contextvars==2.4
# via -r requirements/base.txt
cryptography==40.0.2
cryptography==41.0.3
# via -r requirements/crypto.txt
distlib==0.3.6
# via virtualenv

View file

@ -55,7 +55,8 @@ cffi==1.14.6
# clr-loader
# cryptography
# pygit2
charset-normalizer==2.1.1
# pynacl
charset-normalizer==3.1.0
# via
# -c requirements/static/ci/../pkg/py3.11/windows.txt
# aiohttp
@ -87,7 +88,7 @@ contextvars==2.4
# via
# -c requirements/static/ci/../pkg/py3.11/windows.txt
# -r requirements/base.txt
cryptography==41.0.2
cryptography==41.0.3
# via
# -c requirements/static/ci/../pkg/py3.11/windows.txt
# -r requirements/crypto.txt
@ -292,6 +293,8 @@ pymysql==1.0.2
# via
# -c requirements/static/ci/../pkg/py3.11/windows.txt
# -r requirements/windows.txt
pynacl==1.5.0
# via -r requirements/static/ci/common.in
pyopenssl==23.2.0
# via
# -c requirements/static/ci/../pkg/py3.11/windows.txt

View file

@ -16,11 +16,11 @@ cffi==1.15.1
# via
# -c requirements/static/ci/py3.8/linux.txt
# cryptography
charset-normalizer==2.1.1
charset-normalizer==3.1.0
# via
# -c requirements/static/ci/py3.8/linux.txt
# requests
cryptography==41.0.2
cryptography==41.0.3
# via
# -c requirements/static/ci/py3.8/linux.txt
# pyspnego

View file

@ -16,7 +16,7 @@ certifi==2023.07.22
# via
# -c requirements/static/ci/py3.8/linux.txt
# requests
charset-normalizer==2.1.1
charset-normalizer==3.1.0
# via
# -c requirements/static/ci/py3.8/linux.txt
# requests

View file

@ -63,7 +63,7 @@ cffi==1.15.1
# cryptography
# napalm
# pynacl
charset-normalizer==2.1.1
charset-normalizer==3.1.0
# via
# -c requirements/static/ci/../pkg/py3.8/freebsd.txt
# aiohttp
@ -89,10 +89,11 @@ contextvars==2.4
# -r requirements/base.txt
croniter==1.3.15 ; sys_platform != "win32"
# via -r requirements/static/ci/common.in
cryptography==41.0.2
cryptography==41.0.3
# via
# -c requirements/static/ci/../pkg/py3.8/freebsd.txt
# -r requirements/crypto.txt
# -r requirements/static/pkg/freebsd.in
# etcd3-py
# moto
# paramiko
@ -332,7 +333,9 @@ pyeapi==1.0.0
pyinotify==0.9.6 ; sys_platform != "win32" and sys_platform != "darwin" and platform_system != "openbsd"
# via -r requirements/static/ci/common.in
pynacl==1.5.0
# via paramiko
# via
# -r requirements/static/ci/common.in
# paramiko
pyopenssl==23.2.0
# via
# -c requirements/static/ci/../pkg/py3.8/freebsd.txt

View file

@ -20,7 +20,7 @@ pylint==2.4.4
# via
# -r requirements/static/ci/lint.in
# saltpylint
saltpylint==2020.9.28
saltpylint==2023.8.3
# via -r requirements/static/ci/lint.in
six==1.16.0
# via

View file

@ -77,7 +77,7 @@ cffi==1.15.1
# napalm
# pygit2
# pynacl
charset-normalizer==2.1.1
charset-normalizer==3.1.0
# via
# -c requirements/static/ci/../pkg/py3.8/linux.txt
# aiohttp
@ -103,7 +103,7 @@ contextvars==2.4
# -r requirements/base.txt
croniter==1.3.15 ; sys_platform != "win32"
# via -r requirements/static/ci/common.in
cryptography==41.0.2
cryptography==41.0.3
# via
# -c requirements/static/ci/../pkg/py3.8/linux.txt
# -r requirements/crypto.txt
@ -367,7 +367,9 @@ pyjwt==2.7.0
pymysql==1.0.3
# via -r requirements/static/ci/linux.in
pynacl==1.5.0
# via paramiko
# via
# -r requirements/static/ci/common.in
# paramiko
pyopenssl==23.2.0
# via
# -c requirements/static/ci/../pkg/py3.8/linux.txt

View file

@ -55,7 +55,8 @@ cffi==1.14.6
# clr-loader
# cryptography
# pygit2
charset-normalizer==2.1.1
# pynacl
charset-normalizer==3.1.0
# via
# -c requirements/static/ci/../pkg/py3.8/windows.txt
# aiohttp
@ -87,7 +88,7 @@ contextvars==2.4
# via
# -c requirements/static/ci/../pkg/py3.8/windows.txt
# -r requirements/base.txt
cryptography==41.0.2
cryptography==41.0.3
# via
# -c requirements/static/ci/../pkg/py3.8/windows.txt
# -r requirements/crypto.txt
@ -298,6 +299,8 @@ pymysql==1.0.2
# via
# -c requirements/static/ci/../pkg/py3.8/windows.txt
# -r requirements/windows.txt
pynacl==1.5.0
# via -r requirements/static/ci/common.in
pyopenssl==23.2.0
# via
# -c requirements/static/ci/../pkg/py3.8/windows.txt

View file

@ -16,11 +16,11 @@ cffi==1.15.1
# via
# -c requirements/static/ci/py3.9/linux.txt
# cryptography
charset-normalizer==2.1.1
charset-normalizer==3.1.0
# via
# -c requirements/static/ci/py3.9/linux.txt
# requests
cryptography==41.0.2
cryptography==41.0.3
# via
# -c requirements/static/ci/py3.9/linux.txt
# pyspnego

View file

@ -67,7 +67,7 @@ cffi==1.15.1
# napalm
# pygit2
# pynacl
charset-normalizer==2.1.1
charset-normalizer==3.1.0
# via
# -c requirements/static/ci/../pkg/py3.9/darwin.txt
# aiohttp
@ -93,7 +93,7 @@ contextvars==2.4
# -r requirements/base.txt
croniter==1.3.15 ; sys_platform != "win32"
# via -r requirements/static/ci/common.in
cryptography==41.0.2
cryptography==41.0.3
# via
# -c requirements/static/ci/../pkg/py3.9/darwin.txt
# -r requirements/crypto.txt
@ -335,7 +335,9 @@ pyeapi==1.0.0
pygit2==1.12.1
# via -r requirements/static/ci/darwin.in
pynacl==1.5.0
# via paramiko
# via
# -r requirements/static/ci/common.in
# paramiko
pyopenssl==23.2.0
# via
# -c requirements/static/ci/../pkg/py3.9/darwin.txt

View file

@ -16,7 +16,7 @@ certifi==2023.07.22
# via
# -c requirements/static/ci/py3.9/linux.txt
# requests
charset-normalizer==2.1.1
charset-normalizer==3.1.0
# via
# -c requirements/static/ci/py3.9/linux.txt
# requests

View file

@ -63,7 +63,7 @@ cffi==1.15.1
# cryptography
# napalm
# pynacl
charset-normalizer==2.1.1
charset-normalizer==3.1.0
# via
# -c requirements/static/ci/../pkg/py3.9/freebsd.txt
# aiohttp
@ -89,10 +89,11 @@ contextvars==2.4
# -r requirements/base.txt
croniter==1.3.15 ; sys_platform != "win32"
# via -r requirements/static/ci/common.in
cryptography==41.0.2
cryptography==41.0.3
# via
# -c requirements/static/ci/../pkg/py3.9/freebsd.txt
# -r requirements/crypto.txt
# -r requirements/static/pkg/freebsd.in
# etcd3-py
# moto
# paramiko
@ -329,7 +330,9 @@ pyeapi==1.0.0
pyinotify==0.9.6 ; sys_platform != "win32" and sys_platform != "darwin" and platform_system != "openbsd"
# via -r requirements/static/ci/common.in
pynacl==1.5.0
# via paramiko
# via
# -r requirements/static/ci/common.in
# paramiko
pyopenssl==23.2.0
# via
# -c requirements/static/ci/../pkg/py3.9/freebsd.txt

View file

@ -20,7 +20,7 @@ pylint==2.4.4
# via
# -r requirements/static/ci/lint.in
# saltpylint
saltpylint==2020.9.28
saltpylint==2023.8.3
# via -r requirements/static/ci/lint.in
six==1.16.0
# via

View file

@ -77,7 +77,7 @@ cffi==1.15.1
# napalm
# pygit2
# pynacl
charset-normalizer==2.1.1
charset-normalizer==3.1.0
# via
# -c requirements/static/ci/../pkg/py3.9/linux.txt
# aiohttp
@ -103,7 +103,7 @@ contextvars==2.4
# -r requirements/base.txt
croniter==1.3.15 ; sys_platform != "win32"
# via -r requirements/static/ci/common.in
cryptography==41.0.2
cryptography==41.0.3
# via
# -c requirements/static/ci/../pkg/py3.9/linux.txt
# -r requirements/crypto.txt
@ -365,7 +365,9 @@ pyjwt==2.7.0
pymysql==1.0.3
# via -r requirements/static/ci/linux.in
pynacl==1.5.0
# via paramiko
# via
# -r requirements/static/ci/common.in
# paramiko
pyopenssl==23.2.0
# via
# -c requirements/static/ci/../pkg/py3.9/linux.txt

View file

@ -55,7 +55,8 @@ cffi==1.14.6
# clr-loader
# cryptography
# pygit2
charset-normalizer==2.1.1
# pynacl
charset-normalizer==3.1.0
# via
# -c requirements/static/ci/../pkg/py3.9/windows.txt
# aiohttp
@ -87,7 +88,7 @@ contextvars==2.4
# via
# -c requirements/static/ci/../pkg/py3.9/windows.txt
# -r requirements/base.txt
cryptography==41.0.2
cryptography==41.0.3
# via
# -c requirements/static/ci/../pkg/py3.9/windows.txt
# -r requirements/crypto.txt
@ -294,6 +295,8 @@ pymysql==1.0.2
# via
# -c requirements/static/ci/../pkg/py3.9/windows.txt
# -r requirements/windows.txt
pynacl==1.5.0
# via -r requirements/static/ci/common.in
pyopenssl==23.2.0
# via
# -c requirements/static/ci/../pkg/py3.9/windows.txt

View file

@ -1,9 +1,10 @@
# This file only exists to trigger the right static compiled requirements destination
# Any non hard dependencies of Salt for FreeBSD can go here
cherrypy
cryptography>=41.0.3
backports.ssl_match_hostname>=3.7.0.1; python_version < '3.7'
pycparser>=2.21; python_version >= '3.9'
pyopenssl>=19.0.0
pyopenssl>=23.2.0
python-dateutil>=2.8.0
python-gnupg>=0.4.4
setproctitle>=1.2.3

View file

@ -9,4 +9,4 @@ rpm-vercmp
setproctitle>=1.2.3
timelib>=0.2.5
importlib-metadata>=3.3.0
cryptography>=41.0.2
cryptography>=41.0.3

View file

@ -12,7 +12,7 @@ certifi==2023.07.22
# via requests
cffi==1.15.1
# via cryptography
charset-normalizer==2.1.1
charset-normalizer==3.1.0
# via requests
cheroot==10.0.0
# via cherrypy
@ -20,7 +20,7 @@ cherrypy==18.8.0
# via -r requirements/darwin.txt
contextvars==2.4
# via -r requirements/base.txt
cryptography==41.0.2
cryptography==41.0.3
# via
# -r requirements/crypto.txt
# -r requirements/darwin.txt

View file

@ -10,7 +10,7 @@ certifi==2023.07.22
# via requests
cffi==1.15.1
# via cryptography
charset-normalizer==2.1.1
charset-normalizer==3.1.0
# via requests
cheroot==10.0.0
# via cherrypy
@ -18,9 +18,10 @@ cherrypy==18.8.0
# via -r requirements/static/pkg/freebsd.in
contextvars==2.4
# via -r requirements/base.txt
cryptography==41.0.2
cryptography==41.0.3
# via
# -r requirements/crypto.txt
# -r requirements/static/pkg/freebsd.in
# pyopenssl
distro==1.8.0
# via

View file

@ -10,7 +10,7 @@ certifi==2023.07.22
# via requests
cffi==1.15.1
# via cryptography
charset-normalizer==2.1.1
charset-normalizer==3.1.0
# via requests
cheroot==10.0.0
# via cherrypy
@ -18,7 +18,7 @@ cherrypy==18.8.0
# via -r requirements/static/pkg/linux.in
contextvars==2.4
# via -r requirements/base.txt
cryptography==41.0.2
cryptography==41.0.3
# via
# -r requirements/crypto.txt
# -r requirements/static/pkg/linux.in

View file

@ -15,7 +15,7 @@ cffi==1.14.6
# -r requirements/windows.txt
# clr-loader
# cryptography
charset-normalizer==2.1.1
charset-normalizer==3.1.0
# via requests
cheroot==10.0.0
# via cherrypy
@ -25,7 +25,7 @@ clr-loader==0.2.4
# via pythonnet
contextvars==2.4
# via -r requirements/base.txt
cryptography==41.0.2
cryptography==41.0.3
# via
# -r requirements/crypto.txt
# -r requirements/windows.txt

View file

@ -12,7 +12,7 @@ certifi==2023.07.22
# via requests
cffi==1.15.1
# via cryptography
charset-normalizer==2.1.1
charset-normalizer==3.1.0
# via requests
cheroot==10.0.0
# via cherrypy
@ -20,7 +20,7 @@ cherrypy==18.8.0
# via -r requirements/darwin.txt
contextvars==2.4
# via -r requirements/base.txt
cryptography==41.0.2
cryptography==41.0.3
# via
# -r requirements/crypto.txt
# -r requirements/darwin.txt

View file

@ -10,7 +10,7 @@ certifi==2023.07.22
# via requests
cffi==1.15.1
# via cryptography
charset-normalizer==2.1.1
charset-normalizer==3.1.0
# via requests
cheroot==10.0.0
# via cherrypy
@ -18,9 +18,10 @@ cherrypy==18.8.0
# via -r requirements/static/pkg/freebsd.in
contextvars==2.4
# via -r requirements/base.txt
cryptography==41.0.2
cryptography==41.0.3
# via
# -r requirements/crypto.txt
# -r requirements/static/pkg/freebsd.in
# pyopenssl
distro==1.8.0
# via

View file

@ -10,7 +10,7 @@ certifi==2023.07.22
# via requests
cffi==1.15.1
# via cryptography
charset-normalizer==2.1.1
charset-normalizer==3.1.0
# via requests
cheroot==10.0.0
# via cherrypy
@ -18,7 +18,7 @@ cherrypy==18.8.0
# via -r requirements/static/pkg/linux.in
contextvars==2.4
# via -r requirements/base.txt
cryptography==41.0.2
cryptography==41.0.3
# via
# -r requirements/crypto.txt
# -r requirements/static/pkg/linux.in

View file

@ -15,7 +15,7 @@ cffi==1.14.6
# -r requirements/windows.txt
# clr-loader
# cryptography
charset-normalizer==2.1.1
charset-normalizer==3.1.0
# via requests
cheroot==10.0.0
# via cherrypy
@ -25,7 +25,7 @@ clr-loader==0.2.4
# via pythonnet
contextvars==2.4
# via -r requirements/base.txt
cryptography==41.0.2
cryptography==41.0.3
# via
# -r requirements/crypto.txt
# -r requirements/windows.txt

View file

@ -10,7 +10,7 @@ certifi==2023.07.22
# via requests
cffi==1.15.1
# via cryptography
charset-normalizer==2.1.1
charset-normalizer==3.1.0
# via requests
cheroot==10.0.0
# via cherrypy
@ -18,9 +18,10 @@ cherrypy==18.8.0
# via -r requirements/static/pkg/freebsd.in
contextvars==2.4
# via -r requirements/base.txt
cryptography==41.0.2
cryptography==41.0.3
# via
# -r requirements/crypto.txt
# -r requirements/static/pkg/freebsd.in
# pyopenssl
distro==1.8.0
# via

View file

@ -10,7 +10,7 @@ certifi==2023.07.22
# via requests
cffi==1.15.1
# via cryptography
charset-normalizer==2.1.1
charset-normalizer==3.1.0
# via requests
cheroot==10.0.0
# via cherrypy
@ -18,7 +18,7 @@ cherrypy==18.8.0
# via -r requirements/static/pkg/linux.in
contextvars==2.4
# via -r requirements/base.txt
cryptography==41.0.2
cryptography==41.0.3
# via
# -r requirements/crypto.txt
# -r requirements/static/pkg/linux.in

View file

@ -15,7 +15,7 @@ cffi==1.14.6
# -r requirements/windows.txt
# clr-loader
# cryptography
charset-normalizer==2.1.1
charset-normalizer==3.1.0
# via requests
cheroot==10.0.0
# via cherrypy
@ -25,7 +25,7 @@ clr-loader==0.2.4
# via pythonnet
contextvars==2.4
# via -r requirements/base.txt
cryptography==41.0.2
cryptography==41.0.3
# via
# -r requirements/crypto.txt
# -r requirements/windows.txt

View file

@ -12,7 +12,7 @@ certifi==2023.07.22
# via requests
cffi==1.15.1
# via cryptography
charset-normalizer==2.1.1
charset-normalizer==3.1.0
# via requests
cheroot==10.0.0
# via cherrypy
@ -20,7 +20,7 @@ cherrypy==18.8.0
# via -r requirements/darwin.txt
contextvars==2.4
# via -r requirements/base.txt
cryptography==41.0.2
cryptography==41.0.3
# via
# -r requirements/crypto.txt
# -r requirements/darwin.txt

View file

@ -10,7 +10,7 @@ certifi==2023.07.22
# via requests
cffi==1.15.1
# via cryptography
charset-normalizer==2.1.1
charset-normalizer==3.1.0
# via requests
cheroot==10.0.0
# via cherrypy
@ -18,9 +18,10 @@ cherrypy==18.8.0
# via -r requirements/static/pkg/freebsd.in
contextvars==2.4
# via -r requirements/base.txt
cryptography==41.0.2
cryptography==41.0.3
# via
# -r requirements/crypto.txt
# -r requirements/static/pkg/freebsd.in
# pyopenssl
distro==1.8.0
# via

View file

@ -10,7 +10,7 @@ certifi==2023.07.22
# via requests
cffi==1.15.1
# via cryptography
charset-normalizer==2.1.1
charset-normalizer==3.1.0
# via requests
cheroot==10.0.0
# via cherrypy
@ -18,7 +18,7 @@ cherrypy==18.8.0
# via -r requirements/static/pkg/linux.in
contextvars==2.4
# via -r requirements/base.txt
cryptography==41.0.2
cryptography==41.0.3
# via
# -r requirements/crypto.txt
# -r requirements/static/pkg/linux.in

View file

@ -15,7 +15,7 @@ cffi==1.14.6
# -r requirements/windows.txt
# clr-loader
# cryptography
charset-normalizer==2.1.1
charset-normalizer==3.1.0
# via requests
cheroot==10.0.0
# via cherrypy
@ -25,7 +25,7 @@ clr-loader==0.2.4
# via pythonnet
contextvars==2.4
# via -r requirements/base.txt
cryptography==41.0.2
cryptography==41.0.3
# via
# -r requirements/crypto.txt
# -r requirements/windows.txt

View file

@ -11,7 +11,7 @@ certifi>=2022.12.07
cffi>=1.14.5
cherrypy>=18.6.1
gitpython>=3.1.30
cryptography>=41.0.2
cryptography>=41.0.3
lxml>=4.6.3
pyasn1>=0.4.8
pymssql>=2.2.1

View file

@ -3,6 +3,7 @@ Salt package
"""
import importlib
import os
import sys
import warnings
@ -12,6 +13,53 @@ if sys.version_info < (3,):
)
sys.stderr.flush()
class NaclImporter:
"""
Import hook to force PyNaCl to perform dlopen on libsodium with the
RTLD_DEEPBIND flag. This is to work around an issue where pyzmq does a dlopen
with RTLD_GLOBAL which then causes calls to libsodium to resolve to
tweetnacl when it's been bundled with pyzmq.
See: https://github.com/zeromq/pyzmq/issues/1878
"""
loading = False
def find_module(self, module_name, package_path=None):
if not NaclImporter.loading and module_name.startswith("nacl"):
NaclImporter.loading = True
return self
return None
def create_module(self, spec):
dlopen = hasattr(sys, "getdlopenflags")
if dlopen:
dlflags = sys.getdlopenflags()
# Use RTDL_DEEPBIND in case pyzmq was compiled with ZMQ_USE_TWEETNACL. This is
# needed because pyzmq imports libzmq with RTLD_GLOBAL.
if hasattr(os, "RTLD_DEEPBIND"):
flags = os.RTLD_DEEPBIND | dlflags
else:
flags = dlflags
sys.setdlopenflags(flags)
try:
mod = importlib.import_module(spec.name)
finally:
if dlopen:
sys.setdlopenflags(dlflags)
NaclImporter.loading = False
sys.modules[spec.name] = mod
return mod
def exec_module(self, module):
return None
# Try our importer first
sys.meta_path = [NaclImporter()] + sys.meta_path
# All salt related deprecation warnings should be shown once each!
warnings.filterwarnings(
"once", # Show once

View file

@ -41,6 +41,9 @@ except ImportError:
log = logging.getLogger(__name__)
REQUEST_CHANNEL_TIMEOUT = 60
REQUEST_CHANNEL_TRIES = 3
class ReqChannel:
"""
@ -122,6 +125,9 @@ class AsyncReqChannel:
if io_loop is None:
io_loop = tornado.ioloop.IOLoop.current()
timeout = opts.get("request_channel_timeout", REQUEST_CHANNEL_TIMEOUT)
tries = opts.get("request_channel_tries", REQUEST_CHANNEL_TRIES)
crypt = kwargs.get("crypt", "aes")
if crypt != "clear":
# we don't need to worry about auth as a kwarg, since its a singleton
@ -130,9 +136,17 @@ class AsyncReqChannel:
auth = None
transport = salt.transport.request_client(opts, io_loop=io_loop)
return cls(opts, transport, auth)
return cls(opts, transport, auth, tries=tries, timeout=timeout)
def __init__(self, opts, transport, auth, **kwargs):
def __init__(
self,
opts,
transport,
auth,
timeout=REQUEST_CHANNEL_TIMEOUT,
tries=REQUEST_CHANNEL_TRIES,
**kwargs,
):
self.opts = dict(opts)
self.transport = transport
self.auth = auth
@ -140,6 +154,8 @@ class AsyncReqChannel:
if self.auth:
self.master_pubkey_path = os.path.join(self.opts["pki_dir"], self.auth.mpub)
self._closing = False
self.timeout = timeout
self.tries = tries
@property
def crypt(self):
@ -158,28 +174,54 @@ class AsyncReqChannel:
"version": 2,
}
@tornado.gen.coroutine
def _send_with_retry(self, load, tries, timeout):
_try = 1
while True:
try:
ret = yield self.transport.send(
load,
timeout=timeout,
)
break
except Exception as exc: # pylint: disable=broad-except
log.trace("Failed to send msg %r", exc)
if _try >= tries:
raise
else:
_try += 1
continue
raise tornado.gen.Return(ret)
@tornado.gen.coroutine
def crypted_transfer_decode_dictentry(
self,
load,
dictkey=None,
timeout=60,
timeout=None,
tries=None,
):
if timeout is None:
timeout = self.timeout
if tries is None:
tries = self.tries
nonce = uuid.uuid4().hex
load["nonce"] = nonce
if not self.auth.authenticated:
yield self.auth.authenticate()
ret = yield self.transport.send(
ret = yield self._send_with_retry(
self._package_load(self.auth.crypticle.dumps(load)),
timeout=timeout,
tries,
timeout,
)
key = self.auth.get_keys()
if "key" not in ret:
# Reauth in the case our key is deleted on the master side.
yield self.auth.authenticate()
ret = yield self.transport.send(
ret = yield self._send_with_retry(
self._package_load(self.auth.crypticle.dumps(load)),
timeout=timeout,
tries,
timeout,
)
if HAS_M2:
aes = key.private_decrypt(ret["key"], RSA.pkcs1_oaep_padding)
@ -211,7 +253,7 @@ class AsyncReqChannel:
return salt.crypt.verify_signature(self.master_pubkey_path, data, sig)
@tornado.gen.coroutine
def _crypted_transfer(self, load, timeout=60, raw=False):
def _crypted_transfer(self, load, timeout, raw=False):
"""
Send a load across the wire, with encryption
@ -258,7 +300,7 @@ class AsyncReqChannel:
raise tornado.gen.Return(ret)
@tornado.gen.coroutine
def _uncrypted_transfer(self, load, timeout=60):
def _uncrypted_transfer(self, load, timeout):
"""
Send a load across the wire in cleartext
@ -277,7 +319,7 @@ class AsyncReqChannel:
yield self.transport.connect()
@tornado.gen.coroutine
def send(self, load, tries=3, timeout=60, raw=False):
def send(self, load, tries=None, timeout=None, raw=False):
"""
Send a request, return a future which will complete when we send the message
@ -285,6 +327,10 @@ class AsyncReqChannel:
:param int tries: The number of times to make before failure
:param int timeout: The number of seconds on a response before failing
"""
if timeout is None:
timeout = self.timeout
if tries is None:
tries = self.tries
_try = 1
while True:
try:
@ -402,7 +448,7 @@ class AsyncPubChannel:
except Exception as exc: # pylint: disable=broad-except
if "-|RETRY|-" not in str(exc):
raise salt.exceptions.SaltClientError(
"Unable to sign_in to master: {}".format(exc)
f"Unable to sign_in to master: {exc}"
) # TODO: better error message
def close(self):

View file

@ -990,6 +990,8 @@ VALID_OPTS = immutabletypes.freeze(
"maintenance_interval": int,
# Fileserver process restart interval
"fileserver_interval": int,
"request_channel_timeout": int,
"request_channel_tries": int,
}
)
@ -1051,6 +1053,8 @@ DEFAULT_MINION_OPTS = immutabletypes.freeze(
"pillar_cache": False,
"pillar_cache_ttl": 3600,
"pillar_cache_backend": "disk",
"request_channel_timeout": 30,
"request_channel_tries": 3,
"gpg_cache": False,
"gpg_cache_ttl": 86400,
"gpg_cache_backend": "disk",

View file

@ -9,6 +9,7 @@ import logging
import os
import shutil
import string
import time
import urllib.error
import urllib.parse
@ -33,7 +34,7 @@ import salt.utils.templates
import salt.utils.url
import salt.utils.verify
import salt.utils.versions
from salt.exceptions import CommandExecutionError, MinionError
from salt.exceptions import CommandExecutionError, MinionError, SaltClientError
from salt.utils.openstack.swift import SaltSwift
log = logging.getLogger(__name__)
@ -100,7 +101,7 @@ class Client:
Make sure that this path is intended for the salt master and trim it
"""
if not path.startswith("salt://"):
raise MinionError("Unsupported path: {}".format(path))
raise MinionError(f"Unsupported path: {path}")
file_path, saltenv = salt.utils.url.parse(path)
return file_path
@ -266,7 +267,7 @@ class Client:
for fn_ in self.file_list_emptydirs(saltenv):
fn_ = salt.utils.data.decode(fn_)
if fn_.startswith(path):
minion_dir = "{}/{}".format(dest, fn_)
minion_dir = f"{dest}/{fn_}"
if not os.path.isdir(minion_dir):
os.makedirs(minion_dir)
ret.append(minion_dir)
@ -431,7 +432,7 @@ class Client:
ret.append(
self.get_file(
salt.utils.url.create(fn_),
"{}/{}".format(dest, minion_relpath),
f"{dest}/{minion_relpath}",
True,
saltenv,
gzip,
@ -450,7 +451,7 @@ class Client:
# Remove the leading directories from path to derive
# the relative path on the minion.
minion_relpath = fn_[len(prefix) :].lstrip("/")
minion_mkdir = "{}/{}".format(dest, minion_relpath)
minion_mkdir = f"{dest}/{minion_relpath}"
if not os.path.isdir(minion_mkdir):
os.makedirs(minion_mkdir)
ret.append(minion_mkdir)
@ -501,9 +502,7 @@ class Client:
if url_scheme in ("file", ""):
# Local filesystem
if not os.path.isabs(url_path):
raise CommandExecutionError(
"Path '{}' is not absolute".format(url_path)
)
raise CommandExecutionError(f"Path '{url_path}' is not absolute")
if dest is None:
with salt.utils.files.fopen(url_path, "rb") as fp_:
data = fp_.read()
@ -577,9 +576,7 @@ class Client:
)
return dest
except Exception as exc: # pylint: disable=broad-except
raise MinionError(
"Could not fetch from {}. Exception: {}".format(url, exc)
)
raise MinionError(f"Could not fetch from {url}. Exception: {exc}")
if url_data.scheme == "ftp":
try:
ftp = ftplib.FTP() # nosec
@ -590,7 +587,7 @@ class Client:
ftp.login(url_data.username, url_data.password)
remote_file_path = url_data.path.lstrip("/")
with salt.utils.files.fopen(dest, "wb") as fp_:
ftp.retrbinary("RETR {}".format(remote_file_path), fp_.write)
ftp.retrbinary(f"RETR {remote_file_path}", fp_.write)
ftp.quit()
return dest
except Exception as exc: # pylint: disable=broad-except
@ -624,7 +621,7 @@ class Client:
swift_conn.get_object(url_data.netloc, url_data.path[1:], dest)
return dest
except Exception: # pylint: disable=broad-except
raise MinionError("Could not fetch from {}".format(url))
raise MinionError(f"Could not fetch from {url}")
get_kwargs = {}
if url_data.username is not None and url_data.scheme in ("http", "https"):
@ -647,7 +644,7 @@ class Client:
fixed_url = url
destfp = None
dest_etag = "{}.etag".format(dest)
dest_etag = f"{dest}.etag"
try:
# Tornado calls streaming_callback on redirect response bodies.
# But we need streaming to support fetching large files (> RAM
@ -761,7 +758,7 @@ class Client:
result.append(chunk)
else:
dest_tmp = "{}.part".format(dest)
dest_tmp = f"{dest}.part"
# We need an open filehandle to use in the on_chunk callback,
# that's why we're not using a with clause here.
# pylint: disable=resource-leakage
@ -790,7 +787,7 @@ class Client:
opts=self.opts,
verify_ssl=verify_ssl,
header_dict=header_dict,
**get_kwargs
**get_kwargs,
)
# 304 Not Modified is returned when If-None-Match header
@ -819,11 +816,11 @@ class Client:
"HTTP error {0} reading {1}: {3}".format(
exc.code,
url,
*http.server.BaseHTTPRequestHandler.responses[exc.code]
*http.server.BaseHTTPRequestHandler.responses[exc.code],
)
)
except urllib.error.URLError as exc:
raise MinionError("Error reading {}: {}".format(url, exc.reason))
raise MinionError(f"Error reading {url}: {exc.reason}")
finally:
if destfp is not None:
destfp.close()
@ -836,7 +833,7 @@ class Client:
makedirs=False,
saltenv="base",
cachedir=None,
**kwargs
**kwargs,
):
"""
Cache a file then process it as a template
@ -1133,6 +1130,18 @@ class RemoteClient(Client):
self.channel = salt.channel.client.ReqChannel.factory(self.opts)
return self.channel
def _channel_send(self, load, raw=False):
start = time.monotonic()
try:
return self.channel.send(
load,
raw=raw,
)
except salt.exceptions.SaltReqTimeoutError:
raise SaltClientError(
f"File client timed out after {int(time.time() - start)}"
)
def destroy(self):
if self._closing:
return
@ -1247,7 +1256,10 @@ class RemoteClient(Client):
load["loc"] = 0
else:
load["loc"] = fn_.tell()
data = self.channel.send(load, raw=True)
data = self._channel_send(
load,
raw=True,
)
# Sometimes the source is local (eg when using
# 'salt.fileserver.FSChan'), in which case the keys are
# already strings. Sometimes the source is remote, in which
@ -1340,28 +1352,36 @@ class RemoteClient(Client):
List the files on the master
"""
load = {"saltenv": saltenv, "prefix": prefix, "cmd": "_file_list"}
return self.channel.send(load)
return self._channel_send(
load,
)
def file_list_emptydirs(self, saltenv="base", prefix=""):
"""
List the empty dirs on the master
"""
load = {"saltenv": saltenv, "prefix": prefix, "cmd": "_file_list_emptydirs"}
return self.channel.send(load)
return self._channel_send(
load,
)
def dir_list(self, saltenv="base", prefix=""):
"""
List the dirs on the master
"""
load = {"saltenv": saltenv, "prefix": prefix, "cmd": "_dir_list"}
return self.channel.send(load)
return self._channel_send(
load,
)
def symlink_list(self, saltenv="base", prefix=""):
"""
List symlinked files and dirs on the master
"""
load = {"saltenv": saltenv, "prefix": prefix, "cmd": "_symlink_list"}
return self.channel.send(load)
return self._channel_send(
load,
)
def __hash_and_stat_file(self, path, saltenv="base"):
"""
@ -1382,7 +1402,9 @@ class RemoteClient(Client):
ret["hash_type"] = hash_type
return ret
load = {"path": path, "saltenv": saltenv, "cmd": "_file_hash"}
return self.channel.send(load)
return self._channel_send(
load,
)
def hash_file(self, path, saltenv="base"):
"""
@ -1409,7 +1431,9 @@ class RemoteClient(Client):
except Exception: # pylint: disable=broad-except
return hash_result, None
load = {"path": path, "saltenv": saltenv, "cmd": "_file_find"}
fnd = self.channel.send(load)
fnd = self._channel_send(
load,
)
try:
stat_result = fnd.get("stat")
except AttributeError:
@ -1421,21 +1445,27 @@ class RemoteClient(Client):
Return a list of the files in the file server's specified environment
"""
load = {"saltenv": saltenv, "cmd": "_file_list"}
return self.channel.send(load)
return self._channel_send(
load,
)
def envs(self):
"""
Return a list of available environments
"""
load = {"cmd": "_file_envs"}
return self.channel.send(load)
return self._channel_send(
load,
)
def master_opts(self):
"""
Return the master opts data
"""
load = {"cmd": "_master_opts"}
return self.channel.send(load)
return self._channel_send(
load,
)
def master_tops(self):
"""
@ -1444,7 +1474,9 @@ class RemoteClient(Client):
load = {"cmd": "_master_tops", "id": self.opts["id"], "opts": self.opts}
if self.auth:
load["tok"] = self.auth.gen_token(b"salt")
return self.channel.send(load)
return self._channel_send(
load,
)
def __enter__(self):
return self

View file

@ -9,6 +9,8 @@
are made to assure backwards compatibility.
"""
# pylint: disable = no-name-in-module
# Import several classes/functions from salt.log.setup for backwards compatibility
from salt._logging import LOG_LEVELS, SORTED_LEVEL_NAMES
from salt.log.setup import (

View file

@ -339,7 +339,7 @@ def load_args_and_kwargs(func, args, data=None, ignore_invalid=False):
# **kwargs not in argspec and parsed argument name not in
# list of positional arguments. This keyword argument is
# invalid.
invalid_kwargs.append("{}={}".format(key, val))
invalid_kwargs.append(f"{key}={val}")
continue
else:
@ -356,7 +356,7 @@ def load_args_and_kwargs(func, args, data=None, ignore_invalid=False):
# list of positional arguments. This keyword argument is
# invalid.
for key, val in string_kwarg.items():
invalid_kwargs.append("{}={}".format(key, val))
invalid_kwargs.append(f"{key}={val}")
else:
_args.append(arg)
@ -366,7 +366,7 @@ def load_args_and_kwargs(func, args, data=None, ignore_invalid=False):
if argspec.keywords and isinstance(data, dict):
# this function accepts **kwargs, pack in the publish data
for key, val in data.items():
_kwargs["__pub_{}".format(key)] = val
_kwargs[f"__pub_{key}"] = val
return _args, _kwargs
@ -411,7 +411,7 @@ def master_event(type, master=None):
}
if type == "alive" and master is not None:
return "{}_{}".format(event_map.get(type), master)
return f"{event_map.get(type)}_{master}"
return event_map.get(type, None)
@ -1886,9 +1886,9 @@ class Minion(MinionBase):
log.trace("Executors list %s", executors) # pylint: disable=no-member
for name in executors:
fname = "{}.execute".format(name)
fname = f"{name}.execute"
if fname not in self.executors:
raise SaltInvocationError("Executor '{}' is not available".format(name))
raise SaltInvocationError(f"Executor '{name}' is not available")
return_data = self.executors[fname](opts, data, func, args, kwargs)
if return_data is not None:
return return_data
@ -1907,7 +1907,7 @@ class Minion(MinionBase):
minion_instance.gen_modules()
fn_ = os.path.join(minion_instance.proc_dir, data["jid"])
salt.utils.process.appendproctitle("{}._thread_return".format(cls.__name__))
salt.utils.process.appendproctitle(f"{cls.__name__}._thread_return")
sdata = {"pid": os.getpid()}
sdata.update(data)
@ -1924,11 +1924,11 @@ class Minion(MinionBase):
)
allow_missing_funcs = any(
[
minion_instance.executors["{}.allow_missing_func".format(executor)](
minion_instance.executors[f"{executor}.allow_missing_func"](
function_name
)
for executor in executors
if "{}.allow_missing_func".format(executor) in minion_instance.executors
if f"{executor}.allow_missing_func" in minion_instance.executors
]
)
if function_name in minion_instance.functions or allow_missing_funcs is True:
@ -1974,9 +1974,9 @@ class Minion(MinionBase):
ret["retcode"] = retcode
ret["success"] = retcode == salt.defaults.exitcodes.EX_OK
except CommandNotFoundError as exc:
msg = "Command required for '{}' not found".format(function_name)
msg = f"Command required for '{function_name}' not found"
log.debug(msg, exc_info=True)
ret["return"] = "{}: {}".format(msg, exc)
ret["return"] = f"{msg}: {exc}"
ret["out"] = "nested"
ret["retcode"] = salt.defaults.exitcodes.EX_GENERIC
except CommandExecutionError as exc:
@ -1986,7 +1986,7 @@ class Minion(MinionBase):
exc,
exc_info_on_loglevel=logging.DEBUG,
)
ret["return"] = "ERROR: {}".format(exc)
ret["return"] = f"ERROR: {exc}"
ret["out"] = "nested"
ret["retcode"] = salt.defaults.exitcodes.EX_GENERIC
except SaltInvocationError as exc:
@ -1996,10 +1996,23 @@ class Minion(MinionBase):
exc,
exc_info_on_loglevel=logging.DEBUG,
)
ret["return"] = "ERROR executing '{}': {}".format(function_name, exc)
ret["return"] = f"ERROR executing '{function_name}': {exc}"
ret["out"] = "nested"
ret["retcode"] = salt.defaults.exitcodes.EX_GENERIC
except SaltClientError as exc:
log.error(
"Problem executing '%s': %s",
function_name,
exc,
)
ret["return"] = f"ERROR executing '{function_name}': {exc}"
ret["out"] = "nested"
ret["retcode"] = salt.defaults.exitcodes.EX_GENERIC
except TypeError as exc:
# XXX: This can ba extreemly missleading when something outside of a
# execution module call raises a TypeError. Make this it's own
# type of exception when we start validating state and
# execution argument module inputs.
msg = "Passed invalid arguments to {}: {}\n{}".format(
function_name,
exc,
@ -2015,11 +2028,11 @@ class Minion(MinionBase):
salt.utils.error.fire_exception(
salt.exceptions.MinionError(msg), opts, job=data
)
ret["return"] = "{}: {}".format(msg, traceback.format_exc())
ret["return"] = f"{msg}: {traceback.format_exc()}"
ret["out"] = "nested"
ret["retcode"] = salt.defaults.exitcodes.EX_GENERIC
else:
docs = minion_instance.functions["sys.doc"]("{}*".format(function_name))
docs = minion_instance.functions["sys.doc"](f"{function_name}*")
if docs:
docs[function_name] = minion_instance.functions.missing_fun_string(
function_name
@ -2069,7 +2082,7 @@ class Minion(MinionBase):
ret["id"] = opts["id"]
for returner in set(data["ret"].split(",")):
try:
returner_str = "{}.returner".format(returner)
returner_str = f"{returner}.returner"
if returner_str in minion_instance.returners:
minion_instance.returners[returner_str](ret)
else:
@ -2096,9 +2109,7 @@ class Minion(MinionBase):
minion_instance.gen_modules()
fn_ = os.path.join(minion_instance.proc_dir, data["jid"])
salt.utils.process.appendproctitle(
"{}._thread_multi_return".format(cls.__name__)
)
salt.utils.process.appendproctitle(f"{cls.__name__}._thread_multi_return")
sdata = {"pid": os.getpid()}
sdata.update(data)
@ -2175,7 +2186,7 @@ class Minion(MinionBase):
for returner in set(data["ret"].split(",")):
ret["id"] = opts["id"]
try:
minion_instance.returners["{}.returner".format(returner)](ret)
minion_instance.returners[f"{returner}.returner"](ret)
except Exception as exc: # pylint: disable=broad-except
log.error("The return failed for job %s: %s", data["jid"], exc)
@ -2700,11 +2711,14 @@ class Minion(MinionBase):
notify=data.get("notify", False),
)
elif tag.startswith("__master_req_channel_payload"):
yield _minion.req_channel.send(
data,
timeout=_minion._return_retry_timer(),
tries=_minion.opts["return_retry_tries"],
)
try:
yield _minion.req_channel.send(
data,
timeout=_minion._return_retry_timer(),
tries=_minion.opts["return_retry_tries"],
)
except salt.exceptions.SaltReqTimeoutError:
log.error("Timeout encountered while sending %r request", data)
elif tag.startswith("pillar_refresh"):
yield _minion.pillar_refresh(
force_refresh=data.get("force_refresh", False),
@ -3307,7 +3321,7 @@ class Syndic(Minion):
data["to"],
io_loop=self.io_loop,
callback=lambda _: None,
**kwargs
**kwargs,
)
def _send_req_sync(self, load, timeout):
@ -3964,8 +3978,8 @@ class SProxyMinion(SMinion):
self.proxy.reload_modules()
if (
"{}.init".format(fq_proxyname) not in self.proxy
or "{}.shutdown".format(fq_proxyname) not in self.proxy
f"{fq_proxyname}.init" not in self.proxy
or f"{fq_proxyname}.shutdown" not in self.proxy
):
errmsg = (
"Proxymodule {} is missing an init() or a shutdown() or both. ".format(
@ -3978,7 +3992,7 @@ class SProxyMinion(SMinion):
raise SaltSystemExit(code=salt.defaults.exitcodes.EX_GENERIC, msg=errmsg)
self.module_executors = self.proxy.get(
"{}.module_executors".format(fq_proxyname), lambda: []
f"{fq_proxyname}.module_executors", lambda: []
)()
proxy_init_fn = self.proxy[fq_proxyname + ".init"]
proxy_init_fn(self.opts)

View file

@ -1,5 +1,5 @@
"""
A dead simple module wrapping calls to the Chocolatey package manager
A module that wraps calls to the Chocolatey package manager
(http://chocolatey.org)
.. versionadded:: 2014.1.0
@ -40,13 +40,10 @@ def __virtual__():
salt-minion running as SYSTEM.
"""
if not salt.utils.platform.is_windows():
return (False, "Cannot load module chocolatey: Chocolatey requires Windows")
return False, "Chocolatey: Requires Windows"
if __grains__["osrelease"] in ("XP", "2003Server"):
return (
False,
"Cannot load module chocolatey: Chocolatey requires Windows Vista or later",
)
return False, "Chocolatey: Requires Windows Vista or later"
return __virtualname__
@ -355,12 +352,12 @@ def unbootstrap():
"""
Uninstall chocolatey from the system by doing the following:
.. versionadded:: 3001
- Delete the Chocolatey Directory
- Remove Chocolatey from the path
- Remove Chocolatey environment variables
.. versionadded:: 3001
Returns:
list: A list of items that were removed, otherwise an empty list
@ -441,10 +438,10 @@ def list_(
None is passed. Default is None.
local_only (bool):
Display packages only installed locally. Default is False.
Only display packages that are installed locally. Default is False.
exact (bool):
Display only packages that match ``narrow`` exactly. Default is
Only display packages that match ``narrow`` exactly. Default is
False.
.. versionadded:: 2017.7.0
@ -463,8 +460,14 @@ def list_(
# https://docs.chocolatey.org/en-us/guides/upgrading-to-chocolatey-v2-v6
if Version(chocolatey_version()) < Version("2.0.0"):
cmd = [choc_path, "list"]
if local_only:
cmd.append("--local-only")
else:
cmd = [choc_path, "search"]
if local_only:
# Starting with 2.0.0, list only returns local packages
cmd = [choc_path, "list"]
else:
cmd = [choc_path, "search"]
if narrow:
cmd.append(narrow)
if salt.utils.data.is_true(all_versions):
@ -473,8 +476,6 @@ def list_(
cmd.append("--prerelease")
if source:
cmd.extend(["--source", source])
if local_only:
cmd.append("--local-only")
if exact:
cmd.append("--exact")
@ -589,12 +590,12 @@ def install(
version (str):
Install a specific version of the package. Defaults to latest
version. Default is None.
version. Default is ``None``.
source (str):
Chocolatey repository (directory, share or remote URL feed) the
package comes from. Defaults to the official Chocolatey feed.
Default is None.
Default is ``None``.
Alternate Sources:
@ -606,36 +607,38 @@ def install(
force (bool):
Reinstall the current version of an existing package. Do not use
with ``allow_multiple``. Default is False.
with ``allow_multiple``. Default is ``False``.
pre_versions (bool):
Include pre-release packages. Default is False.
Include pre-release packages. Default is ``False``.
install_args (str):
A list of install arguments you want to pass to the installation
process i.e product key or feature list. Default is None.
process, i.e. product key or feature list. Default is ``None``.
override_args (bool):
Set to true if you want to override the original install arguments
(for the native installer) in the package and use your own. When
this is set to False install_args will be appended to the end of the
default arguments. Default is None.
this is set to ``False`` install_args will be appended to the end of
the default arguments. Default is ``None``.
force_x86 (bool):
Force x86 (32bit) installation on 64 bit systems. Default is False.
Force x86 (32bit) installation on 64bit systems. Default is
``False``.
package_args (str):
Arguments you want to pass to the package. Default is None.
Arguments you want to pass to the package. Default is ``None``.
allow_multiple (bool):
Allow multiple versions of the package to be installed. Do not use
with ``force``. Does not work with all packages. Default is False.
with ``force``. Does not work with all packages. Default is
``False``.
.. versionadded:: 2017.7.0
execution_timeout (str):
Chocolatey execution timeout value you want to pass to the
installation process. Default is None.
installation process. Default is ``None``.
.. versionadded:: 2018.3.0
@ -700,18 +703,21 @@ def install_cygwin(name, install_args=None, override_args=False):
"""
Instructs Chocolatey to install a package via Cygwin.
name
The name of the package to be installed. Only accepts a single argument.
Args:
install_args
A list of install arguments you want to pass to the installation process
i.e product key or feature list
name (str):
The name of the package to be installed. Only accepts a single
argument.
override_args
Set to true if you want to override the original install arguments (for
the native installer) in the package and use your own. When this is set
to False install_args will be appended to the end of the default
arguments
install_args (str):
A list of install arguments you want to pass to the installation
process, i.e. product key or feature list
override_args (bool):
Set to ``True`` if you want to override the original install
arguments (for the native installer) in the package and use your
own. When this is set to ``False`` install_args will be appended to
the end of the default arguments
CLI Example:
@ -729,22 +735,25 @@ def install_gem(name, version=None, install_args=None, override_args=False):
"""
Instructs Chocolatey to install a package via Ruby's Gems.
name
The name of the package to be installed. Only accepts a single argument.
Args:
version
Install a specific version of the package. Defaults to latest version
available.
name (str):
The name of the package to be installed. Only accepts a single
argument.
install_args
A list of install arguments you want to pass to the installation process
i.e product key or feature list
version (str):
Install a specific version of the package. Defaults to the latest
version available.
override_args
Set to true if you want to override the original install arguments (for
the native installer) in the package and use your own. When this is set
to False install_args will be appended to the end of the default
arguments
install_args (str):
A list of install arguments you want to pass to the installation
process, i.e. product key or feature list
override_args (bool):
Set to ``True`` if you want to override the original install
arguments (for the native installer) in the package and use your
own. When this is set to ``False`` install_args will be appended to
the end of the default arguments
CLI Example:
@ -773,16 +782,19 @@ def install_missing(name, version=None, source=None):
``installmissing`` is deprecated as of that version and will be removed
in Chocolatey 1.0.
name
The name of the package to be installed. Only accepts a single argument.
Args:
version
Install a specific version of the package. Defaults to latest version
available.
name (str):
The name of the package to be installed. Only accepts a single
argument.
source
Chocolatey repository (directory, share or remote URL feed) the package
comes from. Defaults to the official Chocolatey feed.
version (str):
Install a specific version of the package. Defaults to the latest
version available.
source (str):
Chocolatey repository (directory, share or remote URL feed) the
package comes from. Defaults to the official Chocolatey feed.
CLI Example:
@ -816,22 +828,25 @@ def install_python(name, version=None, install_args=None, override_args=False):
"""
Instructs Chocolatey to install a package via Python's easy_install.
name
The name of the package to be installed. Only accepts a single argument.
Args:
version
Install a specific version of the package. Defaults to latest version
available.
name (str):
The name of the package to be installed. Only accepts a single
argument.
install_args
A list of install arguments you want to pass to the installation process
i.e product key or feature list
version (str):
Install a specific version of the package. Defaults to the latest
version available.
override_args
Set to true if you want to override the original install arguments (for
the native installer) in the package and use your own. When this is set
to False install_args will be appended to the end of the default
arguments
install_args (str):
A list of install arguments you want to pass to the installation
process, i.e. product key or feature list.
override_args (bool):
Set to ``True`` if you want to override the original install
arguments (for the native installer) in the package and use your
own. When this is set to ``False`` install_args will be appended to
the end of the default arguments.
CLI Example:
@ -855,8 +870,11 @@ def install_windowsfeatures(name):
Instructs Chocolatey to install a Windows Feature via the Deployment Image
Servicing and Management tool.
name
The name of the feature to be installed. Only accepts a single argument.
Args:
name (str):
The name of the feature to be installed. Only accepts a single
argument.
CLI Example:
@ -871,18 +889,21 @@ def install_webpi(name, install_args=None, override_args=False):
"""
Instructs Chocolatey to install a package via the Microsoft Web PI service.
name
The name of the package to be installed. Only accepts a single argument.
Args:
install_args
A list of install arguments you want to pass to the installation process
i.e product key or feature list
name (str):
The name of the package to be installed. Only accepts a single
argument.
override_args
Set to true if you want to override the original install arguments (for
the native installer) in the package and use your own. When this is set
to False install_args will be appended to the end of the default
arguments
install_args (str):
A list of install arguments you want to pass to the installation
process, i.e. product key or feature list.
override_args (bool):
Set to ``True`` if you want to override the original install
arguments (for the native installer) in the package and use your
own. When this is set to ``False`` install_args will be appended to
the end of the default arguments.
CLI Example:
@ -896,27 +917,35 @@ def install_webpi(name, install_args=None, override_args=False):
)
def uninstall(name, version=None, uninstall_args=None, override_args=False):
def uninstall(
name,
version=None,
uninstall_args=None,
override_args=False,
force=False,
):
"""
Instructs Chocolatey to uninstall a package.
name
The name of the package to be uninstalled. Only accepts a single
argument.
Args:
version
Uninstalls a specific version of the package. Defaults to latest version
installed.
name (str):
The name of the package to be uninstalled. Only accepts a single
argument.
uninstall_args
A list of uninstall arguments you want to pass to the uninstallation
process i.e product key or feature list
version (str):
Uninstalls a specific version of the package. Defaults to the latest
version installed.
override_args
Set to true if you want to override the original uninstall arguments
(for the native uninstaller) in the package and use your own. When this
is set to False uninstall_args will be appended to the end of the
default arguments
uninstall_args (str):
A list of uninstall arguments you want to pass to the uninstallation
process, i.e. product key or feature list.
override_args
Set to ``True`` if you want to override the original uninstall
arguments (for the native uninstaller) in the package and use your
own. When this is set to ``False`` uninstall_args will be appended
to the end of the default arguments.
CLI Example:
@ -933,11 +962,13 @@ def uninstall(name, version=None, uninstall_args=None, override_args=False):
if uninstall_args:
cmd.extend(["--uninstallarguments", uninstall_args])
if override_args:
cmd.extend(["--overridearguments"])
cmd.append("--overridearguments")
if force:
cmd.append("--force")
cmd.extend(_yes())
result = __salt__["cmd.run_all"](cmd, python_shell=False)
if result["retcode"] not in [0, 1605, 1614, 1641]:
if result["retcode"] not in [0, 1, 1605, 1614, 1641]:
err = "Running chocolatey failed: {}".format(result["stdout"])
raise CommandExecutionError(err)
@ -976,26 +1007,27 @@ def upgrade(
package comes from. Defaults to the official Chocolatey feed.
force (bool):
Reinstall the **same** version already installed
Reinstall the **same** version already installed.
pre_versions (bool):
Include pre-release packages in comparison. Defaults to False.
Include pre-release packages in comparison. Defaults to ``False``.
install_args (str):
A list of install arguments you want to pass to the installation
process i.e product key or feature list
process, i.e. product key or feature list.
override_args (str):
Set to true if you want to override the original install arguments
(for the native installer) in the package and use your own. When
this is set to False install_args will be appended to the end of the
default arguments
override_args (bool):
Set to ``True`` if you want to override the original install
arguments (for the native installer) in the package and use your
own. When this is set to ``False`` install_args will be appended to
the end of the default arguments.
force_x86
Force x86 (32bit) installation on 64 bit systems. Defaults to false.
force_x86 (bool):
Force x86 (32bit) installation on 64bit systems. Defaults to
``False``.
package_args
A list of arguments you want to pass to the package
package_args (str):
A list of arguments you want to pass to the package.
Returns:
str: Results of the ``chocolatey`` command
@ -1043,16 +1075,18 @@ def update(name, source=None, pre_versions=False):
"""
Instructs Chocolatey to update packages on the system.
name
The name of the package to update, or "all" to update everything
installed on the system.
Args:
source
Chocolatey repository (directory, share or remote URL feed) the package
comes from. Defaults to the official Chocolatey feed.
name (str):
The name of the package to update, or "all" to update everything
installed on the system.
pre_versions
Include pre-release packages in comparison. Defaults to False.
source (str):
Chocolatey repository (directory, share or remote URL feed) the
package comes from. Defaults to the official Chocolatey feed.
pre_versions (bool):
Include pre-release packages in comparison. Defaults to ``False``.
CLI Example:
@ -1096,15 +1130,15 @@ def version(name, check_remote=False, source=None, pre_versions=False):
check_remote (bool):
Get the version number of the latest package from the remote feed.
Default is False.
Default is ``False``.
source (str):
Chocolatey repository (directory, share or remote URL feed) the
package comes from. Defaults to the official Chocolatey feed.
Default is None.
Default is ``None``.
pre_versions (bool):
Include pre-release packages in comparison. Default is False.
Include pre-release packages in comparison. Default is ``False``.
Returns:
dict: A dictionary of currently installed software and versions
@ -1120,21 +1154,23 @@ def version(name, check_remote=False, source=None, pre_versions=False):
packages = {}
lower_name = name.lower()
for pkg in installed:
if lower_name in pkg.lower():
packages[pkg] = installed[pkg]
if installed:
for pkg in installed:
if lower_name == pkg.lower():
packages.setdefault(pkg, {})
packages[pkg]["installed"] = installed[pkg]
if check_remote:
available = list_(narrow=name, pre_versions=pre_versions, source=source)
for pkg in packages:
# Grab the current version from the package that was installed
packages[pkg] = {"installed": installed[pkg]}
# If there's a remote package available, then also include that
# in the dictionary that we return.
if pkg in available:
packages[pkg]["available"] = available[pkg]
# If there's a remote package available, then also include that
# in the dictionary that we return.
available = list_(
narrow=name, local_only=False, pre_versions=pre_versions, source=source
)
if available:
for pkg in available:
if lower_name == pkg.lower():
packages.setdefault(pkg, {})
packages[pkg]["available"] = available[pkg]
return packages
@ -1143,25 +1179,27 @@ def add_source(name, source_location, username=None, password=None, priority=Non
"""
Instructs Chocolatey to add a source.
name
The name of the source to be added as a chocolatey repository.
Args:
source
Location of the source you want to work with.
name (str):
The name of the source to be added as a chocolatey repository.
username
Provide username for chocolatey sources that need authentication
credentials.
source (str):
Location of the source you want to work with.
password
Provide password for chocolatey sources that need authentication
credentials.
username (str):
Provide username for chocolatey sources that need authentication
credentials.
priority
The priority order of this source as compared to other sources,
lower is better. Defaults to 0 (no priority). All priorities
above 0 will be evaluated first, then zero-based values will be
evaluated in config file order.
password (str):
Provide password for chocolatey sources that need authentication
credentials.
priority (int):
The priority order of this source as compared to other sources,
lower is better. Defaults to 0 (no priority). All priorities
above 0 will be evaluated first, then zero-based values will be
evaluated in config file order.
CLI Example:
@ -1200,12 +1238,13 @@ def _change_source_state(name, state):
"""
Instructs Chocolatey to change the state of a source.
name
Name of the repository to affect.
Args:
state
State in which you want the chocolatey repository.
name (str):
Name of the repository to affect.
state (str):
State in which you want the chocolatey repository.
"""
cmd = [_find_chocolatey(), "source", state, "--name", name]
result = __salt__["cmd.run_all"](cmd, python_shell=False)
@ -1221,8 +1260,10 @@ def enable_source(name):
"""
Instructs Chocolatey to enable a source.
name
Name of the source repository to enable.
Args:
name (str):
Name of the source repository to enable.
CLI Example:
@ -1238,8 +1279,10 @@ def disable_source(name):
"""
Instructs Chocolatey to disable a source.
name
Name of the source repository to disable.
Args:
name (str):
Name of the source repository to disable.
CLI Example:

View file

@ -1,7 +1,7 @@
"""
This module helps include encrypted passwords in pillars, grains and salt state files.
:depends: libnacl, https://github.com/saltstack/libnacl
:depends: PyNaCl, https://github.com/pyca/pynacl
This is often useful if you wish to store your pillars in source control or
share your pillar data with others that you trust. I don't advise making your pillars public
@ -137,9 +137,9 @@ Optional small program to encrypt data without needing salt modules.
.. code-block:: python
#!/bin/python3
import sys, base64, libnacl.sealed
import sys, base64, nacl.public
pk = base64.b64decode('YOURPUBKEY')
b = libnacl.sealed.SealedBox(pk)
b = nacl.public.SealedBox(pk)
data = sys.stdin.buffer.read()
print(base64.b64encode(b.encrypt(data)).decode())
@ -163,7 +163,7 @@ def __virtual__():
def keygen(sk_file=None, pk_file=None, **kwargs):
"""
Use libnacl to generate a keypair.
Use PyNaCl to generate a keypair.
If no `sk_file` is defined return a keypair.

View file

@ -8,6 +8,7 @@ import fnmatch
import logging
import os
import sys
import time
import traceback
import tornado.gen
@ -260,6 +261,7 @@ class AsyncRemotePillar(RemotePillarMixin):
if self.ext:
load["ext"] = self.ext
try:
start = time.monotonic()
ret_pillar = yield self.channel.crypted_transfer_decode_dictentry(
load,
dictkey="pillar",
@ -267,6 +269,10 @@ class AsyncRemotePillar(RemotePillarMixin):
except salt.crypt.AuthenticationError as exc:
log.error(exc.message)
raise SaltClientError("Exception getting pillar.")
except salt.exceptions.SaltReqTimeoutError:
raise SaltClientError(
f"Pillar timed out after {int(time.monotonic() - start)} seconds"
)
except Exception: # pylint: disable=broad-except
log.exception("Exception getting pillar:")
raise SaltClientError("Exception getting pillar.")
@ -351,10 +357,23 @@ class RemotePillar(RemotePillarMixin):
}
if self.ext:
load["ext"] = self.ext
ret_pillar = self.channel.crypted_transfer_decode_dictentry(
load,
dictkey="pillar",
)
try:
start = time.monotonic()
ret_pillar = self.channel.crypted_transfer_decode_dictentry(
load,
dictkey="pillar",
)
except salt.crypt.AuthenticationError as exc:
log.error(exc.message)
raise SaltClientError("Exception getting pillar.")
except salt.exceptions.SaltReqTimeoutError:
raise SaltClientError(
f"Pillar timed out after {int(time.monotonic() - start)} seconds"
)
except Exception: # pylint: disable=broad-except
log.exception("Exception getting pillar:")
raise SaltClientError("Exception getting pillar.")
if not isinstance(ret_pillar, dict):
log.error(
@ -722,9 +741,7 @@ class Pillar:
)
)
except Exception as exc: # pylint: disable=broad-except
errors.append(
"Rendering Primary Top file failed, render error:\n{}".format(exc)
)
errors.append(f"Rendering Primary Top file failed, render error:\n{exc}")
log.exception("Pillar rendering failed for minion %s", self.minion_id)
# Search initial top files for includes
@ -926,10 +943,10 @@ class Pillar:
saltenv,
sls,
_pillar_rend=True,
**defaults
**defaults,
)
except Exception as exc: # pylint: disable=broad-except
msg = "Rendering SLS '{}' failed, render error:\n{}".format(sls, exc)
msg = f"Rendering SLS '{sls}' failed, render error:\n{exc}"
log.critical(msg, exc_info=True)
if self.opts.get("pillar_safe_render_error", True):
errors.append(
@ -942,7 +959,7 @@ class Pillar:
nstate = None
if state:
if not isinstance(state, dict):
msg = "SLS '{}' does not render to a dictionary".format(sls)
msg = f"SLS '{sls}' does not render to a dictionary"
log.error(msg)
errors.append(msg)
else:
@ -1079,7 +1096,7 @@ class Pillar:
"a sign of a malformed pillar sls file. Returned "
"errors: %s",
sls,
", ".join(["'{}'".format(e) for e in errors]),
", ".join([f"'{e}'" for e in errors]),
)
continue
pillar = merge(
@ -1105,7 +1122,7 @@ class Pillar:
self.minion_id,
pillar,
extra_minion_data=self.extra_minion_data,
**val
**val,
)
else:
ext = self.ext_pillars[key](self.minion_id, pillar, **val)
@ -1115,7 +1132,7 @@ class Pillar:
self.minion_id,
pillar,
*val,
extra_minion_data=self.extra_minion_data
extra_minion_data=self.extra_minion_data,
)
else:
ext = self.ext_pillars[key](self.minion_id, pillar, *val)
@ -1329,7 +1346,7 @@ class Pillar:
if ptr is not None:
ptr[child] = ret
except Exception as exc: # pylint: disable=broad-except
msg = "Failed to decrypt pillar key '{}': {}".format(key, exc)
msg = f"Failed to decrypt pillar key '{key}': {exc}"
errors.append(msg)
log.error(msg, exc_info=True)
return errors

View file

@ -10,8 +10,7 @@ The typical use-case would be to use ciphers in your pillar data, and keep a
secret key on your master. You can put the public key in source control so that
developers can add new secrets quickly and easily.
This renderer requires the libsodium library binary and libnacl >= 1.5.1
python package (support for sealed boxes came in 1.5.1 version).
This renderer requires the libsodium library binary and PyNacl >= 1.0
Setup

View file

@ -1,7 +1,7 @@
"""
This module helps include encrypted passwords in pillars, grains and salt state files.
:depends: libnacl, https://github.com/saltstack/libnacl
:depends: PyNaCl, https://github.com/pyca/pynacl
This is often useful if you wish to store your pillars in source control or
share your pillar data with others that you trust. I don't advise making your pillars public
@ -125,7 +125,7 @@ def __virtual__():
def keygen(sk_file=None, pk_file=None, **kwargs):
"""
Use libnacl to generate a keypair.
Use PyNaCL to generate a keypair.
If no `sk_file` is defined return a keypair.

View file

@ -1,5 +1,5 @@
"""
Manage Chocolatey package installs
Manage Windows Packages using Chocolatey
.. versionadded:: 2016.3.0
.. note::
@ -20,7 +20,7 @@ def __virtual__():
"""
if "chocolatey.install" in __salt__:
return "chocolatey"
return (False, "chocolatey module could not be loaded")
return False, "chocolatey module could not be loaded"
def installed(
@ -45,50 +45,55 @@ def installed(
The name of the package to be installed. Required.
version (str):
Install a specific version of the package. Defaults to latest
version. If the version is different to the one installed then the
specified version will be installed. Default is None.
Install a specific version of the package. Defaults to the latest
version. If the version is different to the one installed, then the
specified version will be installed. Default is ``None``.
source (str):
Chocolatey repository (directory, share or remote URL, feed).
Defaults to the official Chocolatey feed. Default is None.
``None`` defaults to the official Chocolatey feed. Default is
``None``.
force (bool):
Reinstall the current version of an existing package. Do not use
with ``allow_multiple``. Default is False.
with ``allow_multiple``. Default is ``False``.
pre_versions (bool):
Include pre-release packages. Default is False.
Include pre-release packages. Default is ``False``.
install_args (str):
Install arguments you want to pass to the installation process, i.e
product key or feature list. Default is None.
Install arguments you want to pass to the installation process, i.e.
product key or feature list. Default is ``None``.
override_args (bool):
Set to True if you want to override the original install arguments
(for the native installer) in the package and use your own. When
this is set to False install_args will be appended to the end of the
default arguments. Default is False.
Set to ``True`` to override the original install arguments (for the
native installer) in the package and use your own. When this is set
to ``False``, install_args will be appended to the end of the
default arguments. Default is ``False``.
force_x86 (bool):
Force x86 (32bit) installation on 64 bit systems. Default is False.
Force x86 (32bit) installation on 64bit systems. Default is
``False``.
package_args (str):
Arguments you want to pass to the package. Default is None.
Arguments you want to pass to the package. Default is ``None``.
allow_multiple (bool):
Allow mulitiple versions of the package to be installed. Do not use
with ``force``. Does not work with all packages. Default is False.
Allow multiple versions of the package to be installed. Do not use
with ``force``. Does not work with all packages. Default is
``False``.
.. versionadded:: 2017.7.0
execution_timeout (str):
Chocolatey execution timeout value you want to pass to the
installation process. Default is None.
installation process. Default is ``None``.
Example:
.. code-block:: yaml
Installsomepackage:
install_some_package:
chocolatey.installed:
- name: packagename
- version: '12.04'
@ -109,9 +114,9 @@ def installed(
# Package not installed
if name.lower() not in [package.lower() for package in pre_install.keys()]:
if version:
ret["changes"] = {name: "Version {} will be installed".format(version)}
ret["comment"] = f"{name} {version} will be installed"
else:
ret["changes"] = {name: "Latest version will be installed"}
ret["comment"] = f"Latest version of {name} will be installed"
# Package installed
else:
@ -124,59 +129,36 @@ def installed(
if name.lower() == pkg.lower():
full_name = pkg
installed_version = version_info[full_name]["installed"][0]
installed_version = version_info[full_name].get("installed")[0]
if version:
if salt.utils.versions.compare(
ver1=installed_version, oper="==", ver2=version
):
if force:
ret["changes"] = {
name: "Version {} will be reinstalled".format(version)
}
ret["comment"] = "Reinstall {} {}".format(full_name, version)
ret["comment"] = f"{name} {version} will be reinstalled"
else:
ret["comment"] = "{} {} is already installed".format(name, version)
if __opts__["test"]:
ret["result"] = None
return ret
ret["comment"] = f"{name} {version} is already installed"
else:
if allow_multiple:
ret["changes"] = {
name: (
"Version {} will be installed side by side with "
"Version {} if supported".format(version, installed_version)
)
}
ret["comment"] = "Install {0} {1} side-by-side with {0} {2}".format(
full_name, version, installed_version
)
ret[
"comment"
] = f"{name} {version} will be installed side by side with {name} {installed_version} if supported"
else:
ret["changes"] = {
name: "Version {} will be installed over Version {}".format(
version, installed_version
)
}
ret["comment"] = "Install {0} {1} over {0} {2}".format(
full_name, version, installed_version
)
ret[
"comment"
] = f"{name} {version} will be installed over {name} {installed_version}"
force = True
else:
version = installed_version
if force:
ret["changes"] = {
name: "Version {} will be reinstalled".format(version)
}
ret["comment"] = "Reinstall {} {}".format(full_name, version)
ret["comment"] = f"{name} {version} will be reinstalled"
else:
ret["comment"] = "{} {} is already installed".format(name, version)
if __opts__["test"]:
ret["result"] = None
ret["comment"] = f"{name} {version} is already installed"
return ret
if __opts__["test"]:
ret["result"] = None
ret["comment"] = "The installation was tested"
return ret
# Install the package
@ -195,13 +177,12 @@ def installed(
)
if "Running chocolatey failed" not in result:
ret["comment"] = f"{name} installed successfully"
ret["result"] = True
else:
ret["comment"] = f"Failed to install {name}"
ret["result"] = False
if not ret["result"]:
ret["comment"] = "Failed to install the package {}".format(name)
# Get list of installed packages after 'chocolatey.install'
post_install = __salt__["chocolatey.list"](local_only=True)
@ -212,32 +193,35 @@ def installed(
def uninstalled(name, version=None, uninstall_args=None, override_args=False):
"""
Uninstalls a package
Uninstalls a chocolatey package
name
The name of the package to be uninstalled
Args:
version
Uninstalls a specific version of the package. Defaults to latest
version installed.
name (str):
The name of the package to be uninstalled. Required.
uninstall_args
A list of uninstall arguments you want to pass to the uninstallation
process i.e product key or feature list
version (str):
Uninstalls a specific version of the package. Defaults to the latest
version installed.
override_args
Set to true if you want to override the original uninstall arguments (
for the native uninstaller)in the package and use your own.
When this is set to False uninstall_args will be appended to the end of
the default arguments
uninstall_args (str):
A list of uninstall arguments you want to pass to the uninstallation
process, i.e. product key or feature list
override_args (str):
Set to ``True`` if you want to override the original uninstall
arguments (for the native uninstaller) in the package and use your
own. When this is set to ``False``, uninstall_args will be appended
to the end of the default arguments
Example:
.. code-block:: yaml
Removemypackage:
remove_my_package:
chocolatey.uninstalled:
- name: mypackage
- version: '21.5'
"""
ret = {"name": name, "result": True, "changes": {}, "comment": ""}
@ -248,20 +232,15 @@ def uninstalled(name, version=None, uninstall_args=None, override_args=False):
# Determine if package is installed
if name.lower() in [package.lower() for package in pre_uninstall.keys()]:
try:
ret["changes"] = {
name: "{} version {} will be removed".format(
name, pre_uninstall[name][0]
)
}
ret["comment"] = f"{name} {pre_uninstall[name][0]} will be removed"
except KeyError:
ret["changes"] = {name: "{} will be removed".format(name)}
ret["comment"] = f"{name} will be removed"
else:
ret["comment"] = "The package {} is not installed".format(name)
ret["comment"] = f"The package {name} is not installed"
return ret
if __opts__["test"]:
ret["result"] = None
ret["comment"] = "The uninstall was tested"
return ret
# Uninstall the package
@ -270,13 +249,12 @@ def uninstalled(name, version=None, uninstall_args=None, override_args=False):
)
if "Running chocolatey failed" not in result:
ret["comment"] = f"{name} uninstalled successfully"
ret["result"] = True
else:
ret["comment"] = f"Failed to uninstall {name}"
ret["result"] = False
if not ret["result"]:
ret["comment"] = "Failed to uninstall the package {}".format(name)
# Get list of installed packages after 'chocolatey.uninstall'
post_uninstall = __salt__["chocolatey.list"](local_only=True)
@ -297,7 +275,7 @@ def upgraded(
package_args=None,
):
"""
Upgrades a package. Will install the package if not installed.
Upgrades a chocolatey package. Will install the package if not installed.
.. versionadded:: 2018.3.0
@ -320,7 +298,7 @@ def upgraded(
Default is ``False``.
pre_versions (bool):
``True`` will nclude pre-release packages. Default is ``False``.
``True`` will include pre-release packages. Default is ``False``.
install_args (str):
Install arguments you want to pass to the installation process, i.e
@ -333,12 +311,14 @@ def upgraded(
the default arguments. Default is ``False``.
force_x86 (bool):
``True`` forces 32bit installation on 64 bit systems. Default is
``True`` forces 32bit installation on 64bit systems. Default is
``False``.
package_args (str):
Arguments you want to pass to the package. Default is ``None``.
Example:
.. code-block:: yaml
upgrade_some_package:
@ -356,15 +336,15 @@ def upgraded(
# Package not installed
if name.lower() not in [package.lower() for package in pre_install.keys()]:
if version:
ret["changes"][name] = "Version {} will be installed".format(version)
ret["comment"] = "Install version {}".format(version)
ret["comment"] = f"{name} {version} will be installed"
else:
ret["changes"][name] = "Latest version will be installed"
ret["comment"] = "Install latest version"
ret["comment"] = f"Latest version of {name} will be installed"
# Package installed
else:
version_info = __salt__["chocolatey.version"](name, check_remote=True)
version_info = __salt__["chocolatey.version"](
name=name, check_remote=True, source=source
)
# Get the actual full name out of version_info
full_name = name
@ -385,40 +365,29 @@ def upgraded(
ver1=installed_version, oper="==", ver2=version
):
if force:
ret["changes"][name] = "Version {} will be reinstalled".format(
version
)
ret["comment"] = "Reinstall {} {}".format(full_name, version)
ret["comment"] = f"{name} {version} will be reinstalled"
else:
ret["comment"] = "{} {} is already installed".format(
name, installed_version
)
ret["comment"] = f"{name} {version} is already installed"
return ret
else:
# If installed version is older than new version
if salt.utils.versions.compare(
ver1=installed_version, oper="<", ver2=version
):
ret["changes"][
name
] = "Version {} will be upgraded to Version {}".format(
installed_version, version
)
ret["comment"] = "Upgrade {} {} to {}".format(
full_name, installed_version, version
)
ret[
"comment"
] = f"{name} {installed_version} will be upgraded to version {version}"
# If installed version is newer than new version
else:
ret["comment"] = "{} {} (newer) is already installed".format(
name, installed_version
)
ret[
"comment"
] = f"{name} {installed_version} (newer) is already installed"
return ret
# Catch all for a condition where version is not passed and there is no
# available version
else:
ret["comment"] = "No version found to install"
# Return if there are no changes to be made
if not ret["changes"]:
return ret
return ret
# Return if running in test mode
if __opts__["test"]:
@ -439,10 +408,10 @@ def upgraded(
)
if "Running chocolatey failed" not in result:
ret["comment"] = "Package {} upgraded successfully".format(name)
ret["comment"] = f"{name} upgraded successfully"
ret["result"] = True
else:
ret["comment"] = "Failed to upgrade the package {}".format(name)
ret["comment"] = f"Failed to upgrade {name}"
ret["result"] = False
# Get list of installed packages after 'chocolatey.install'
@ -460,33 +429,35 @@ def source_present(
name, source_location, username=None, password=None, force=False, priority=None
):
"""
Instructs Chocolatey to add a source if not already present.
Adds a Chocolatey source if not already present.
name
The name of the source to be added as a chocolatey repository.
Args:
source
Location of the source you want to work with.
name (str):
The name of the source to be added as a chocolatey repository.
username
Provide username for chocolatey sources that need authentication
credentials.
source (str):
Location of the source you want to work with.
password
Provide password for chocolatey sources that need authentication
credentials.
username (str):
The username for a chocolatey source that needs authentication
credentials.
force
Salt will not modify a existing repository with the same name. Set this
option to true to update an existing repository.
password (str):
The password for a chocolatey source that needx authentication
credentials.
priority
The priority order of this source as compared to other sources,
lower is better. Defaults to 0 (no priority). All priorities
above 0 will be evaluated first, then zero-based values will be
evaluated in config file order.
force (bool):
Salt will not modify an existing repository with the same name. Set
this option to ``True`` to update an existing repository.
CLI Example:
priority (int):
The priority order of this source as compared to other sources.
Lower is better. Defaults to 0 (no priority). All priorities
above 0 will be evaluated first, then zero-based values will be
evaluated in config file order.
Example:
.. code-block:: yaml
@ -506,21 +477,18 @@ def source_present(
# Determine action
# Source with same name not present
if name.lower() not in [present.lower() for present in pre_install.keys()]:
ret["comment"] = "Add the source {}".format(name)
ret["comment"] = f"{name} will be added"
# Source with same name already present
else:
if force:
ret["comment"] = "Update the source {}".format(name)
ret["comment"] = f"{name} will be updated"
else:
ret["comment"] = "A source with the name {} is already present".format(name)
if __opts__["test"]:
ret["result"] = None
ret["comment"] = f"{name} is already present"
return ret
if __opts__["test"]:
ret["result"] = None
ret["comment"] = "The installation was tested"
return ret
# Add the source
@ -534,10 +502,10 @@ def source_present(
if "Running chocolatey failed" not in result:
ret["result"] = True
ret["comment"] = "Source {} added successfully".format(name)
ret["comment"] = f"Source {name} added successfully"
else:
ret["result"] = False
ret["comment"] = "Failed to add the source {}".format(name)
ret["comment"] = f"Failed to add the source {name}"
# Get list of present sources after 'chocolatey.add_source'
post_install = __salt__["chocolatey.list_sources"]()

View file

@ -2,9 +2,7 @@
Common code shared between the nacl module and runner.
"""
import base64
import logging
import os
import salt.syspaths
@ -15,15 +13,13 @@ import salt.utils.versions
import salt.utils.win_dacl
import salt.utils.win_functions
log = logging.getLogger(__name__)
REQ_ERROR = None
try:
import libnacl.sealed
import libnacl.secret
import nacl.public
import nacl.secret
except (ImportError, OSError) as e:
REQ_ERROR = (
"libnacl import error, perhaps missing python libnacl package or should update."
"PyNaCl import error, perhaps missing python PyNaCl package or should update."
)
__virtualname__ = "nacl"
@ -62,7 +58,7 @@ def _get_config(**kwargs):
"pk_file": pk_file,
}
config_key = "{}.config".format(__virtualname__)
config_key = f"{__virtualname__}.config"
try:
config.update(__salt__["config.get"](config_key, {}))
except (NameError, KeyError) as e:
@ -113,7 +109,7 @@ def _get_pk(**kwargs):
def keygen(sk_file=None, pk_file=None, **kwargs):
"""
Use libnacl to generate a keypair.
Use PyNaCl to generate a keypair.
If no `sk_file` is defined return a keypair.
@ -143,17 +139,20 @@ def keygen(sk_file=None, pk_file=None, **kwargs):
sk_file = kwargs["keyfile"]
if sk_file is None:
kp = libnacl.public.SecretKey()
return {"sk": base64.b64encode(kp.sk), "pk": base64.b64encode(kp.pk)}
kp = nacl.public.PrivateKey.generate()
return {
"sk": base64.b64encode(kp.encode()),
"pk": base64.b64encode(kp.public_key.encode()),
}
if pk_file is None:
pk_file = "{}.pub".format(sk_file)
pk_file = f"{sk_file}.pub"
if sk_file and pk_file is None:
if not os.path.isfile(sk_file):
kp = libnacl.public.SecretKey()
kp = nacl.public.PrivateKey.generate()
with salt.utils.files.fopen(sk_file, "wb") as keyf:
keyf.write(base64.b64encode(kp.sk))
keyf.write(base64.b64encode(kp.encode()))
if salt.utils.platform.is_windows():
cur_user = salt.utils.win_functions.get_current_user()
salt.utils.win_dacl.set_owner(sk_file, cur_user)
@ -168,31 +167,29 @@ def keygen(sk_file=None, pk_file=None, **kwargs):
else:
# chmod 0600 file
os.chmod(sk_file, 1536)
return "saved sk_file: {}".format(sk_file)
return f"saved sk_file: {sk_file}"
else:
raise Exception("sk_file:{} already exist.".format(sk_file))
raise Exception(f"sk_file:{sk_file} already exist.")
if sk_file is None and pk_file:
raise Exception("sk_file: Must be set inorder to generate a public key.")
if os.path.isfile(sk_file) and os.path.isfile(pk_file):
raise Exception(
"sk_file:{} and pk_file:{} already exist.".format(sk_file, pk_file)
)
raise Exception(f"sk_file:{sk_file} and pk_file:{pk_file} already exist.")
if os.path.isfile(sk_file) and not os.path.isfile(pk_file):
# generate pk using the sk
with salt.utils.files.fopen(sk_file, "rb") as keyf:
sk = salt.utils.stringutils.to_unicode(keyf.read()).rstrip("\n")
sk = base64.b64decode(sk)
kp = libnacl.public.SecretKey(sk)
kp = nacl.public.PublicKey(sk)
with salt.utils.files.fopen(pk_file, "wb") as keyf:
keyf.write(base64.b64encode(kp.pk))
return "saved pk_file: {}".format(pk_file)
keyf.write(base64.b64encode(kp.encode()))
return f"saved pk_file: {pk_file}"
kp = libnacl.public.SecretKey()
kp = nacl.public.PublicKey.generate()
with salt.utils.files.fopen(sk_file, "wb") as keyf:
keyf.write(base64.b64encode(kp.sk))
keyf.write(base64.b64encode(kp.encode()))
if salt.utils.platform.is_windows():
cur_user = salt.utils.win_functions.get_current_user()
salt.utils.win_dacl.set_owner(sk_file, cur_user)
@ -203,8 +200,8 @@ def keygen(sk_file=None, pk_file=None, **kwargs):
# chmod 0600 file
os.chmod(sk_file, 1536)
with salt.utils.files.fopen(pk_file, "wb") as keyf:
keyf.write(base64.b64encode(kp.pk))
return "saved sk_file:{} pk_file: {}".format(sk_file, pk_file)
keyf.write(base64.b64encode(kp.encode()))
return f"saved sk_file:{sk_file} pk_file: {pk_file}"
def enc(data, **kwargs):
@ -271,10 +268,10 @@ def enc_file(name, out=None, **kwargs):
d = enc(data, **kwargs)
if out:
if os.path.isfile(out):
raise Exception("file:{} already exist.".format(out))
raise Exception(f"file:{out} already exist.")
with salt.utils.files.fopen(out, "wb") as f:
f.write(salt.utils.stringutils.to_bytes(d))
return "Wrote: {}".format(out)
return f"Wrote: {out}"
return d
@ -313,6 +310,7 @@ def dec(data, **kwargs):
box_type = _get_config(**kwargs)["box_type"]
if box_type == "secretbox":
return secretbox_decrypt(data, **kwargs)
return sealedbox_decrypt(data, **kwargs)
@ -342,10 +340,10 @@ def dec_file(name, out=None, **kwargs):
d = dec(data, **kwargs)
if out:
if os.path.isfile(out):
raise Exception("file:{} already exist.".format(out))
raise Exception(f"file:{out} already exist.")
with salt.utils.files.fopen(out, "wb") as f:
f.write(salt.utils.stringutils.to_bytes(d))
return "Wrote: {}".format(out)
return f"Wrote: {out}"
return d
@ -366,7 +364,8 @@ def sealedbox_encrypt(data, **kwargs):
data = salt.utils.stringutils.to_bytes(data)
pk = _get_pk(**kwargs)
b = libnacl.sealed.SealedBox(pk)
keypair = nacl.public.PublicKey(pk)
b = nacl.public.SealedBox(keypair)
return base64.b64encode(b.encrypt(data))
@ -389,8 +388,8 @@ def sealedbox_decrypt(data, **kwargs):
data = salt.utils.stringutils.to_bytes(data)
sk = _get_sk(**kwargs)
keypair = libnacl.public.SecretKey(sk)
b = libnacl.sealed.SealedBox(keypair)
keypair = nacl.public.PrivateKey(sk)
b = nacl.public.SealedBox(keypair)
return b.decrypt(base64.b64decode(data))
@ -411,7 +410,7 @@ def secretbox_encrypt(data, **kwargs):
data = salt.utils.stringutils.to_bytes(data)
sk = _get_sk(**kwargs)
b = libnacl.secret.SecretBox(sk)
b = nacl.secret.SecretBox(sk)
return base64.b64encode(b.encrypt(data))
@ -435,6 +434,5 @@ def secretbox_decrypt(data, **kwargs):
data = salt.utils.stringutils.to_bytes(data)
key = _get_sk(**kwargs)
b = libnacl.secret.SecretBox(key=key)
b = nacl.secret.SecretBox(key=key)
return b.decrypt(base64.b64decode(data))

View file

@ -1,200 +0,0 @@
"""
Tests for the salt-run command
"""
import logging
import sys
import pytest
from tests.support.case import ShellCase
try:
import libnacl.sealed # pylint: disable=unused-import
import libnacl.secret # pylint: disable=unused-import
HAS_LIBNACL = True
except (ImportError, OSError, AttributeError):
HAS_LIBNACL = False
log = logging.getLogger(__name__)
@pytest.mark.skipif(
not HAS_LIBNACL, reason="skipping test_nacl, reason=libnacl is unavailable"
)
@pytest.mark.skipif(sys.version_info >= (3, 10), reason="Segfaults with python 3")
@pytest.mark.windows_whitelisted
class NaclTest(ShellCase):
"""
Test the nacl runner
"""
@pytest.mark.slow_test
def test_keygen(self):
"""
Test keygen
"""
# Store the data
ret = self.run_run_plus(
"nacl.keygen",
)
self.assertIn("pk", ret["return"])
self.assertIn("sk", ret["return"])
@pytest.mark.slow_test
def test_enc(self):
"""
Test keygen
"""
# Store the data
ret = self.run_run_plus(
"nacl.keygen",
)
self.assertIn("pk", ret["return"])
self.assertIn("sk", ret["return"])
pk = ret["return"]["pk"]
sk = ret["return"]["sk"]
unencrypted_data = "hello"
# Encrypt with pk
ret = self.run_run_plus(
"nacl.enc",
data=unencrypted_data,
pk=pk,
)
self.assertIn("return", ret)
@pytest.mark.slow_test
def test_enc_dec(self):
"""
Store, list, fetch, then flush data
"""
# Store the data
ret = self.run_run_plus(
"nacl.keygen",
)
self.assertIn("pk", ret["return"])
self.assertIn("sk", ret["return"])
pk = ret["return"]["pk"]
sk = ret["return"]["sk"]
unencrypted_data = b"hello"
# Encrypt with pk
ret = self.run_run_plus(
"nacl.enc",
data=unencrypted_data,
pk=pk,
)
self.assertIn("return", ret)
encrypted_data = ret["return"]
# Decrypt with sk
ret = self.run_run_plus(
"nacl.dec",
data=encrypted_data,
sk=sk,
)
self.assertIn("return", ret)
self.assertEqual(unencrypted_data, ret["return"])
@pytest.mark.slow_test
def test_sealedbox_enc_dec(self):
"""
Generate keys, encrypt, then decrypt.
"""
# Store the data
ret = self.run_run_plus(
"nacl.keygen",
)
self.assertIn("pk", ret["return"])
self.assertIn("sk", ret["return"])
pk = ret["return"]["pk"]
sk = ret["return"]["sk"]
unencrypted_data = b"hello"
# Encrypt with pk
ret = self.run_run_plus(
"nacl.sealedbox_encrypt",
data=unencrypted_data,
pk=pk,
)
encrypted_data = ret["return"]
# Decrypt with sk
ret = self.run_run_plus(
"nacl.sealedbox_decrypt",
data=encrypted_data,
sk=sk,
)
self.assertEqual(unencrypted_data, ret["return"])
@pytest.mark.slow_test
def test_secretbox_enc_dec(self):
"""
Generate keys, encrypt, then decrypt.
"""
# Store the data
ret = self.run_run_plus(
"nacl.keygen",
)
self.assertIn("pk", ret["return"])
self.assertIn("sk", ret["return"])
pk = ret["return"]["pk"]
sk = ret["return"]["sk"]
unencrypted_data = b"hello"
# Encrypt with pk
ret = self.run_run_plus(
"nacl.secretbox_encrypt",
data=unencrypted_data,
sk=sk,
)
encrypted_data = ret["return"]
# Decrypt with sk
ret = self.run_run_plus(
"nacl.secretbox_decrypt",
data=encrypted_data,
sk=sk,
)
self.assertEqual(unencrypted_data, ret["return"])
@pytest.mark.slow_test
def test_enc_dec_no_pk_no_sk(self):
"""
Store, list, fetch, then flush data
"""
# Store the data
ret = self.run_run_plus(
"nacl.keygen",
)
self.assertIn("pk", ret["return"])
self.assertIn("sk", ret["return"])
pk = ret["return"]["pk"]
sk = ret["return"]["sk"]
unencrypted_data = b"hello"
# Encrypt with pk
ret = self.run_run_plus(
"nacl.enc",
data=unencrypted_data,
pk=None,
)
self.assertIn("Exception: no pubkey or pk_file found", ret["return"])
self.assertIn("return", ret)
encrypted_data = ret["return"]
# Decrypt with sk
ret = self.run_run_plus(
"nacl.dec",
data=encrypted_data,
sk=None,
)
self.assertIn("Exception: no key or sk_file found", ret["return"])

View file

@ -0,0 +1,128 @@
"""
Functional tests for chocolatey state
"""
import os
import pathlib
import pytest
import salt.utils.path
pytestmark = [
pytest.mark.windows_whitelisted,
pytest.mark.skip_unless_on_windows,
pytest.mark.slow_test,
pytest.mark.destructive_test,
]
@pytest.fixture(scope="module")
def chocolatey(states):
yield states.chocolatey
@pytest.fixture(scope="module")
def chocolatey_mod(modules):
url = "https://packages.chocolatey.org/chocolatey.1.2.1.nupkg"
with pytest.helpers.temp_file(name="choco.nupkg") as nupkg:
choco_pkg = pathlib.Path(str(nupkg))
choco_dir = choco_pkg.parent / "choco_dir"
choco_script = choco_dir / "tools" / "chocolateyInstall.ps1"
def install():
# Install Chocolatey 1.2.1
# Download Package
modules.cp.get_url(path=url, dest=str(choco_pkg))
# Unzip Package
modules.archive.unzip(
zip_file=str(choco_pkg),
dest=str(choco_dir),
extract_perms=False,
)
# Run installer script
assert choco_script.exists()
result = modules.cmd.script(
source=str(choco_script),
cwd=str(choco_script.parent),
shell="powershell",
python_shell=True,
)
assert result["retcode"] == 0
def uninstall():
choco_dir = os.environ.get("ChocolateyInstall", False)
if choco_dir:
# Remove Chocolatey Directory
modules.file.remove(path=choco_dir, force=True)
# Remove Chocolatey Environment Variables
for env_var in modules.environ.items():
if env_var.lower().startswith("chocolatey"):
modules.environ.setval(
key=env_var, val=False, false_unsets=True, permanent="HKLM"
)
modules.environ.setval(
key=env_var, val=False, false_unsets=True, permanent="HKCU"
)
# Remove Chocolatey from the Path
for path in modules.win_path.get_path():
if "chocolatey" in path.lower():
modules.win_path.remove(path=path, rehash=True)
# Remove unknown version
if salt.utils.path.which("choco.exe"):
uninstall()
# Install known version
install()
yield modules.chocolatey
# Remove
uninstall()
@pytest.fixture(scope="function")
def clean(chocolatey_mod):
chocolatey_mod.uninstall(name="vim", force=True)
yield
chocolatey_mod.uninstall(name="vim", force=True)
@pytest.fixture(scope="function")
def vim(chocolatey_mod):
chocolatey_mod.install(name="vim", version="9.0.1672")
yield
chocolatey_mod.uninstall(name="vim", force=True)
def test_installed_latest(clean, chocolatey, chocolatey_mod):
chocolatey.installed(name="vim")
result = chocolatey_mod.version(name="vim")
assert "vim" in result
def test_installed_version(clean, chocolatey, chocolatey_mod):
chocolatey.installed(name="vim", version="9.0.1672")
result = chocolatey_mod.version(name="vim")
assert "vim" in result
assert result["vim"]["installed"][0] == "9.0.1672"
def test_uninstalled(vim, chocolatey, chocolatey_mod):
chocolatey.uninstalled(name="vim")
result = chocolatey_mod.version(name="vim")
assert "vim" not in result
def test_upgraded(vim, chocolatey, chocolatey_mod):
result = chocolatey_mod.version(name="vim")
assert "vim" in result
assert result["vim"]["installed"][0] == "9.0.1672"
chocolatey.upgraded(name="vim", version="9.0.1677")
result = chocolatey_mod.version(name="vim")
assert "vim" in result
assert result["vim"]["installed"][0] == "9.0.1677"

View file

@ -0,0 +1,128 @@
"""
Functional tests for chocolatey state
"""
import os
import pathlib
import pytest
import salt.utils.path
pytestmark = [
pytest.mark.windows_whitelisted,
pytest.mark.skip_unless_on_windows,
pytest.mark.slow_test,
pytest.mark.destructive_test,
]
@pytest.fixture(scope="module")
def chocolatey(states):
yield states.chocolatey
@pytest.fixture(scope="module")
def chocolatey_mod(modules):
url = "https://community.chocolatey.org/api/v2/package/chocolatey/"
with pytest.helpers.temp_file(name="choco.nupkg") as nupkg:
choco_pkg = pathlib.Path(str(nupkg))
choco_dir = choco_pkg.parent / "choco_dir"
choco_script = choco_dir / "tools" / "chocolateyInstall.ps1"
def install():
# Install Chocolatey 1.2.1
# Download Package
modules.cp.get_url(path=url, dest=str(choco_pkg))
# Unzip Package
modules.archive.unzip(
zip_file=str(choco_pkg),
dest=str(choco_dir),
extract_perms=False,
)
# Run installer script
assert choco_script.exists()
result = modules.cmd.script(
source=str(choco_script),
cwd=str(choco_script.parent),
shell="powershell",
python_shell=True,
)
assert result["retcode"] == 0
def uninstall():
choco_dir = os.environ.get("ChocolateyInstall", False)
if choco_dir:
# Remove Chocolatey Directory
modules.file.remove(path=choco_dir, force=True)
# Remove Chocolatey Environment Variables
for env_var in modules.environ.items():
if env_var.lower().startswith("chocolatey"):
modules.environ.setval(
key=env_var, val=False, false_unsets=True, permanent="HKLM"
)
modules.environ.setval(
key=env_var, val=False, false_unsets=True, permanent="HKCU"
)
# Remove Chocolatey from the Path
for path in modules.win_path.get_path():
if "chocolatey" in path.lower():
modules.win_path.remove(path=path, rehash=True)
# Remove unknown version
if salt.utils.path.which("choco.exe"):
uninstall()
# Install known version
install()
yield modules.chocolatey
# Remove
uninstall()
@pytest.fixture(scope="function")
def clean(chocolatey_mod):
chocolatey_mod.uninstall(name="vim", force=True)
yield
chocolatey_mod.uninstall(name="vim", force=True)
@pytest.fixture(scope="function")
def vim(chocolatey_mod):
chocolatey_mod.install(name="vim", version="9.0.1672")
yield
chocolatey_mod.uninstall(name="vim", force=True)
def test_installed_latest(clean, chocolatey, chocolatey_mod):
chocolatey.installed(name="vim")
result = chocolatey_mod.version(name="vim")
assert "vim" in result
def test_installed_version(clean, chocolatey, chocolatey_mod):
chocolatey.installed(name="vim", version="9.0.1672")
result = chocolatey_mod.version(name="vim")
assert "vim" in result
assert result["vim"]["installed"][0] == "9.0.1672"
def test_uninstalled(vim, chocolatey, chocolatey_mod):
chocolatey.uninstalled(name="vim")
result = chocolatey_mod.version(name="vim")
assert "vim" not in result
def test_upgraded(vim, chocolatey, chocolatey_mod):
result = chocolatey_mod.version(name="vim")
assert "vim" in result
assert result["vim"]["installed"][0] == "9.0.1672"
chocolatey.upgraded(name="vim", version="9.0.1677")
result = chocolatey_mod.version(name="vim")
assert "vim" in result
assert result["vim"]["installed"][0] == "9.0.1677"

View file

@ -50,3 +50,66 @@ def test_publish_retry(salt_master, salt_minion_retry, salt_cli, salt_run_cli):
assert salt_minion_retry.id in data
assert data[salt_minion_retry.id] is True
@pytest.mark.slow_test
def test_pillar_timeout(salt_master_factory):
cmd = """
python -c "import time; time.sleep(2.5); print('{\\"foo\\": \\"bar\\"}');\"
""".strip()
master_overrides = {
"ext_pillar": [
{"cmd_json": cmd},
],
"auto_accept": True,
"worker_threads": 3,
"peer": True,
}
minion_overrides = {
"auth_timeout": 20,
"request_channel_timeout": 5,
"request_channel_tries": 1,
}
sls_name = "issue-50221"
sls_contents = """
custom_test_state:
test.configurable_test_state:
- name: example
- changes: True
- result: True
- comment: "Nothing has acutally been changed"
"""
master = salt_master_factory.salt_master_daemon(
"pillar-timeout-master",
overrides=master_overrides,
)
minion1 = master.salt_minion_daemon(
random_string("pillar-timeout-1-"),
overrides=minion_overrides,
)
minion2 = master.salt_minion_daemon(
random_string("pillar-timeout-2-"),
overrides=minion_overrides,
)
minion3 = master.salt_minion_daemon(
random_string("pillar-timeout-3-"),
overrides=minion_overrides,
)
minion4 = master.salt_minion_daemon(
random_string("pillar-timeout-4-"),
overrides=minion_overrides,
)
cli = master.salt_cli()
sls_tempfile = master.state_tree.base.temp_file(f"{sls_name}.sls", sls_contents)
with master.started(), minion1.started(), minion2.started(), minion3.started(), minion4.started(), sls_tempfile:
proc = cli.run("state.sls", sls_name, minion_tgt="*")
# At least one minion should have a Pillar timeout
assert proc.returncode == 1
minion_timed_out = False
# Find the minion that has a Pillar timeout
for key in proc.data:
if isinstance(proc.data[key], str):
if "Pillar timed out" in proc.data[key]:
minion_timed_out = True
break
assert minion_timed_out is True

View file

@ -0,0 +1,165 @@
"""
Tests for the nacl runner
"""
import pytest
import salt.config
import salt.utils.stringutils
from tests.support.mock import patch
pytest.importorskip("nacl.public")
pytest.importorskip("nacl.secret")
import salt.runners.nacl as nacl
pytestmark = [
pytest.mark.windows_whitelisted,
]
@pytest.fixture(scope="module")
def minion_opts():
return salt.config.minion_config(None)
@pytest.fixture
def test_data():
unencrypted_data = salt.utils.stringutils.to_bytes("hello")
return unencrypted_data
def test_keygen(minion_opts):
"""
Test keygen
"""
# Store the data
with patch("salt.runners.nacl.__opts__", minion_opts, create=True):
ret = nacl.keygen()
assert "pk" in ret
assert "sk" in ret
def test_enc(test_data, minion_opts):
"""
Test keygen
"""
# Store the data
with patch("salt.runners.nacl.__opts__", minion_opts, create=True):
ret = nacl.keygen()
assert "pk" in ret
assert "sk" in ret
pk = ret["pk"]
sk = ret["sk"]
# Encrypt with pk
ret = nacl.enc(
data=test_data,
pk=pk,
)
def test_enc_dec(test_data, minion_opts):
"""
Store, list, fetch, then flush data
"""
# Store the data
with patch("salt.runners.nacl.__opts__", minion_opts, create=True):
ret = nacl.keygen()
assert "pk" in ret
assert "sk" in ret
pk = ret["pk"]
sk = ret["sk"]
# Encrypt with pk
encrypted_data = nacl.enc(
data=test_data,
pk=pk,
)
# Decrypt with sk
ret = nacl.dec(
data=encrypted_data,
sk=sk,
)
assert test_data == ret
def test_sealedbox_enc_dec(test_data, minion_opts):
"""
Generate keys, encrypt, then decrypt.
"""
# Store the data
with patch("salt.runners.nacl.__opts__", minion_opts, create=True):
ret = nacl.keygen()
assert "pk" in ret
assert "sk" in ret
pk = ret["pk"]
sk = ret["sk"]
# Encrypt with pk
encrypted_data = nacl.sealedbox_encrypt(
data=test_data,
pk=pk,
)
# Decrypt with sk
ret = nacl.sealedbox_decrypt(
data=encrypted_data,
sk=sk,
)
assert test_data == ret
def test_secretbox_enc_dec(test_data, minion_opts):
"""
Generate keys, encrypt, then decrypt.
"""
# Store the data
with patch("salt.runners.nacl.__opts__", minion_opts, create=True):
ret = nacl.keygen()
assert "pk" in ret
assert "sk" in ret
pk = ret["pk"]
sk = ret["sk"]
# Encrypt with pk
encrypted_data = nacl.secretbox_encrypt(
data=test_data,
sk=sk,
)
# Decrypt with sk
ret = nacl.secretbox_decrypt(
data=encrypted_data,
sk=sk,
)
assert test_data == ret
def test_enc_dec_no_pk_no_sk(test_data, minion_opts):
"""
Store, list, fetch, then flush data
"""
# Store the data
with patch("salt.runners.nacl.__opts__", minion_opts, create=True):
ret = nacl.keygen()
assert "pk" in ret
assert "sk" in ret
pk = ret["pk"]
sk = ret["sk"]
# Encrypt with pk
with pytest.raises(Exception, match="no pubkey or pk_file found"):
ret = nacl.enc(
data=test_data,
pk=None,
)
encrypted_data = test_data # dummy data, should get exception
# Decrypt with sk
with pytest.raises(Exception, match="no key or sk_file found"):
ret = nacl.dec(
data=encrypted_data,
sk=None,
)

View file

@ -1,8 +1,6 @@
"""
Test for the chocolatey module
"""
import os
import pytest
@ -190,7 +188,7 @@ def test_version_check_remote_false():
"""
list_return_value = {"ack": ["3.1.1"]}
with patch.object(chocolatey, "list_", return_value=list_return_value):
expected = {"ack": ["3.1.1"]}
expected = {"ack": {"installed": ["3.1.1"]}}
result = chocolatey.version("ack", check_remote=False)
assert result == expected

View file

@ -1,10 +1,44 @@
"""
Unit tests for the salt.modules.nacl module
"""
import pytest
import salt.modules.nacl
import salt.utils.stringutils
from tests.support.mock import patch
pytest.importorskip("nacl.public")
pytest.importorskip("nacl.secret")
import salt.modules.nacl as nacl
@pytest.fixture
def configure_loader_modules(minion_opts):
utils = salt.loader.utils(minion_opts)
funcs = salt.loader.minion_mods(minion_opts, utils=utils)
return {
nacl: {
"__opts__": minion_opts,
"__utils__": utils,
"__salt__": funcs,
},
}
@pytest.fixture
def test_keys():
# Generate the keys
ret = nacl.keygen()
assert "pk" in ret
assert "sk" in ret
return ret["pk"], ret["sk"]
@pytest.fixture
def test_data():
unencrypted_data = salt.utils.stringutils.to_bytes("hello")
return unencrypted_data
def test_fips_mode():
"""
@ -14,3 +48,53 @@ def test_fips_mode():
with patch("salt.modules.nacl.__opts__", opts, create=True):
ret = salt.modules.nacl.__virtual__()
assert ret == (False, "nacl module not available in FIPS mode")
def test_keygen(test_keys):
"""
Test keygen
"""
test_pk, test_sk = test_keys
assert len(test_pk) == 44
assert len(test_sk) == 44
def test_enc_dec(test_data, test_keys):
"""
Generate keys, encrypt, then decrypt.
"""
# Encrypt with pk
test_pk, test_sk = test_keys
encrypted_data = nacl.enc(data=test_data, pk=test_pk)
# Decrypt with sk
decrypted_data = nacl.dec(data=encrypted_data, sk=test_sk)
assert test_data == decrypted_data
def test_sealedbox_enc_dec(test_data, test_keys):
"""
Generate keys, encrypt, then decrypt.
"""
# Encrypt with pk
test_pk, test_sk = test_keys
encrypted_data = nacl.sealedbox_encrypt(data=test_data, pk=test_pk)
# Decrypt with sk
decrypted_data = nacl.sealedbox_decrypt(data=encrypted_data, sk=test_sk)
assert test_data == decrypted_data
def test_secretbox_enc_dec(test_data, test_keys):
"""
Generate keys, encrypt, then decrypt.
"""
# Encrypt with sk
test_pk, test_sk = test_keys
encrypted_data = nacl.secretbox_encrypt(data=test_data, sk=test_sk)
# Decrypt with sk
decrypted_data = nacl.secretbox_decrypt(data=encrypted_data, sk=test_sk)
assert test_data == decrypted_data

View file

@ -7,6 +7,7 @@ import salt.loader
import salt.pillar
import salt.utils.cache
from salt.utils.odict import OrderedDict
from tests.support.mock import MagicMock
@pytest.mark.parametrize(
@ -157,3 +158,20 @@ def test_pillar_get_cache_disk(temp_salt_minion, caplog):
in caplog.messages
)
assert fresh_pillar == {}
def test_remote_pillar_timeout(temp_salt_minion, tmp_path):
opts = temp_salt_minion.config.copy()
opts["master_uri"] = "tcp://127.0.0.1:12323"
grains = salt.loader.grains(opts)
pillar = salt.pillar.RemotePillar(
opts,
grains,
temp_salt_minion.id,
"base",
)
mock = MagicMock()
mock.side_effect = salt.exceptions.SaltReqTimeoutError()
pillar.channel.crypted_transfer_decode_dictentry = mock
with pytest.raises(salt.exceptions.SaltClientError):
pillar.compile_pillar()

View file

@ -1,3 +1,6 @@
"""
Unit tests for chocolatey state
"""
import logging
import pytest
@ -74,6 +77,7 @@ def test_source_present(list_sources):
chocolatey.__salt__,
{
"chocolatey.list_sources": list_sources_sideeffect,
"chocolatey.add_source": chocolatey_mod.add_source,
},
):
@ -84,11 +88,6 @@ def test_source_present(list_sources):
cmd_run_all_mock = MagicMock(return_value={"retcode": 0, "stdout": stdout_ret})
cmd_run_which_mock = MagicMock(return_value=choco_path)
with patch.dict(
chocolatey.__salt__,
{
"chocolatey.add_source": chocolatey_mod.add_source,
},
), patch.dict(
chocolatey_mod.__salt__,
{
"cmd.which": cmd_run_which_mock,

View file

@ -1,5 +1,7 @@
import pytest
import salt.fileclient
from tests.support.mock import patch
from tests.support.mock import Mock, patch
class MockReqChannel:
@ -13,36 +15,74 @@ class MockReqChannel:
return self
def test_fileclient_context_manager_closes(temp_salt_minion, temp_salt_master):
def test_fileclient_context_manager_closes(minion_opts, master_opts):
"""
ensure fileclient channel closes
when used with a context manager
"""
opts = temp_salt_minion.config.copy()
opts.update(
minion_opts.update(
{
"id": "root",
"transport": "zeromq",
"auth_tries": 1,
"auth_timeout": 5,
"master_ip": "127.0.0.1",
"master_port": temp_salt_master.config["ret_port"],
"master_uri": "tcp://127.0.0.1:{}".format(
temp_salt_master.config["ret_port"]
),
"master_port": master_opts["ret_port"],
"master_uri": "tcp://127.0.0.1:{}".format(master_opts["ret_port"]),
"request_channel_timeout": 1,
"request_channel_tries": 1,
}
)
master_uri = "tcp://{master_ip}:{master_port}".format(
master_ip="localhost", master_port=opts["master_port"]
master_ip="localhost", master_port=minion_opts["master_port"]
)
mock_reqchannel = MockReqChannel()
patch_reqchannel = patch.object(
salt.channel.client, "ReqChannel", return_value=mock_reqchannel
)
with patch_reqchannel:
with salt.fileclient.get_file_client(opts) as client:
with salt.fileclient.get_file_client(minion_opts) as client:
client.master_opts()
assert not client._closing
assert client._closing
assert client.channel.close.called
@pytest.mark.slow_test
def test_fileclient_timeout(minion_opts, master_opts):
"""
ensure fileclient channel closes
when used with a context manager
"""
minion_opts.update(
{
"id": "root",
"transport": "zeromq",
"auth_tries": 1,
"auth_timeout": 5,
"master_ip": "127.0.0.1",
"master_port": master_opts["ret_port"],
"master_uri": "tcp://127.0.0.1:{}".format(master_opts["ret_port"]),
"request_channel_timeout": 1,
"request_channel_tries": 1,
}
)
master_uri = "tcp://{master_ip}:{master_port}".format(
master_ip="localhost", master_port=minion_opts["master_port"]
)
async def mock_auth():
return True
def mock_dumps(*args):
return b"meh"
with salt.fileclient.get_file_client(minion_opts) as client:
# Authenticate must return true
client.auth.authenticate = mock_auth
# Crypticla must return bytes to pass to transport.RequestClient.send
client.auth._crypticle = Mock()
client.auth._crypticle.dumps = mock_dumps
with pytest.raises(salt.exceptions.SaltClientError):
client.file_list()

View file

@ -1,10 +1,40 @@
"""
Unit tests for the salt.utils.nacl module
"""
import os
import salt.utils.nacl
import pytest
import salt.modules.config as config
import salt.utils.files
from tests.support.mock import patch
pytest.importorskip("nacl.public")
pytest.importorskip("nacl.secret")
import salt.utils.nacl as nacl
@pytest.fixture
def configure_loader_modules():
return {
nacl: {"__salt__": {"config.get": config.get}},
config: {"__opts__": {}},
}
@pytest.fixture(scope="module")
def test_keygen():
"""
test nacl.keygen function
Note: nacl.keygen returns base64 encoded values
"""
ret = nacl.keygen()
assert "sk" in ret
assert "pk" in ret
return ret
def test_fips_mode():
"""
@ -14,3 +44,122 @@ def test_fips_mode():
with patch("salt.utils.nacl.__opts__", opts, create=True):
ret = salt.utils.nacl.__virtual__()
assert ret == (False, "nacl utils not available in FIPS mode")
def test_keygen_sk_file(test_keygen):
"""
test nacl.keygen function
with sk_file set
"""
with pytest.helpers.temp_file("test_keygen_sk_file") as fpath:
with salt.utils.files.fopen(fpath, "wb") as wfh:
wfh.write(test_keygen["sk"])
# test sk_file
ret = nacl.keygen(sk_file=fpath)
assert f"saved pk_file: {fpath}.pub" == ret
salt.utils.files.remove(str(fpath) + ".pub")
def test_keygen_keyfile(test_keygen):
"""
test nacl.keygen function
with keyfile set
"""
with pytest.helpers.temp_file("test_keygen_keyfile") as fpath:
with salt.utils.files.fopen(fpath, "wb") as wfh:
wfh.write(test_keygen["sk"])
ret = nacl.keygen(keyfile=fpath)
assert f"saved pk_file: {fpath}.pub" == ret
salt.utils.files.remove(str(fpath) + ".pub")
def test_enc_keyfile(test_keygen):
"""
test nacl.enc function
with keyfile and pk_file set
"""
with pytest.helpers.temp_file("test_enc_keyfile") as fpath:
with salt.utils.files.fopen(fpath, "wb") as wfh:
wfh.write(test_keygen["sk"])
with salt.utils.files.fopen(str(fpath) + ".pub", "wb") as wfhpub:
wfhpub.write(test_keygen["pk"])
kwargs = {
"opts": {"pki_dir": os.path.dirname(fpath)},
"keyfile": str(fpath),
"pk_file": str(fpath) + ".pub",
}
ret = nacl.enc("blah", **kwargs)
assert isinstance(ret, bytes)
salt.utils.files.remove(str(fpath) + ".pub")
def test_enc_sk_file(test_keygen):
"""
test nacl.enc function
with sk_file and pk_file set
"""
with pytest.helpers.temp_file("test_enc_sk_file") as fpath:
with salt.utils.files.fopen(fpath, "wb") as wfh:
wfh.write(test_keygen["sk"])
with salt.utils.files.fopen(str(fpath) + ".pub", "wb") as wfhpub:
wfhpub.write(test_keygen["pk"])
kwargs = {
"opts": {"pki_dir": os.path.dirname(fpath)},
"sk_file": str(fpath),
"pk_file": str(fpath) + ".pub",
}
ret = nacl.enc("blah", **kwargs)
assert isinstance(ret, bytes)
salt.utils.files.remove(str(fpath) + ".pub")
def test_dec_keyfile(test_keygen):
"""
test nacl.dec function
with keyfile and pk_file set
"""
with pytest.helpers.temp_file("test_dec_keyfile") as fpath:
with salt.utils.files.fopen(fpath, "wb") as wfh:
wfh.write(test_keygen["sk"])
with salt.utils.files.fopen(str(fpath) + ".pub", "wb") as wfhpub:
wfhpub.write(test_keygen["pk"])
kwargs = {
"opts": {"pki_dir": os.path.dirname(fpath)},
"keyfile": str(fpath),
"pk_file": str(fpath) + ".pub",
}
enc_data = nacl.enc("blah", **kwargs)
ret = nacl.dec(enc_data, **kwargs)
assert isinstance(ret, bytes)
assert ret == b"blah"
salt.utils.files.remove(str(fpath) + ".pub")
def test_dec_sk_file(test_keygen):
"""
test nacl.dec function
with sk_file and pk_file set
"""
with pytest.helpers.temp_file("test_dec_sk_file") as fpath:
with salt.utils.files.fopen(fpath, "wb") as wfh:
wfh.write(test_keygen["sk"])
with salt.utils.files.fopen(str(fpath) + ".pub", "wb") as wfhpub:
wfhpub.write(test_keygen["pk"])
kwargs = {
"opts": {"pki_dir": os.path.dirname(fpath)},
"sk_file": str(fpath),
"pk_file": str(fpath) + ".pub",
}
enc_data = nacl.enc("blah", **kwargs)
ret = nacl.dec(enc_data, **kwargs)
assert isinstance(ret, bytes)
assert ret == b"blah"
salt.utils.files.remove(str(fpath) + ".pub")

View file

@ -1,91 +0,0 @@
"""
Tests for the nacl execution module
"""
import sys
import pytest
import salt.utils.stringutils
from tests.support.mixins import LoaderModuleMockMixin
from tests.support.unit import TestCase
try:
import libnacl.sealed # pylint: disable=unused-import
import libnacl.secret # pylint: disable=unused-import
import salt.modules.nacl as nacl
HAS_LIBNACL = True
except (ImportError, OSError, AttributeError):
HAS_LIBNACL = False
@pytest.mark.skipif(sys.version_info >= (3, 10), reason="Segfaults with python 3.10")
@pytest.mark.skipif(
not HAS_LIBNACL, reason="skipping test_nacl, reason=libnacl is unavailable"
)
class NaclTest(TestCase, LoaderModuleMockMixin):
"""
Test the nacl runner
"""
def setup_loader_modules(self):
self.unencrypted_data = salt.utils.stringutils.to_bytes("hello")
self.opts = salt.config.DEFAULT_MINION_OPTS.copy()
utils = salt.loader.utils(self.opts)
funcs = salt.loader.minion_mods(self.opts, utils=utils, whitelist=["nacl"])
return {
nacl: {"__opts__": self.opts, "__utils__": utils, "__salt__": funcs},
}
def setUp(self):
# Generate the keys
ret = nacl.keygen()
self.assertIn("pk", ret)
self.assertIn("sk", ret)
self.pk = ret["pk"]
self.sk = ret["sk"]
def test_keygen(self):
"""
Test keygen
"""
self.assertEqual(len(self.pk), 44)
self.assertEqual(len(self.sk), 44)
def test_enc_dec(self):
"""
Generate keys, encrypt, then decrypt.
"""
# Encrypt with pk
encrypted_data = nacl.enc(data=self.unencrypted_data, pk=self.pk)
# Decrypt with sk
decrypted_data = nacl.dec(data=encrypted_data, sk=self.sk)
self.assertEqual(self.unencrypted_data, decrypted_data)
def test_sealedbox_enc_dec(self):
"""
Generate keys, encrypt, then decrypt.
"""
# Encrypt with pk
encrypted_data = nacl.sealedbox_encrypt(data=self.unencrypted_data, pk=self.pk)
# Decrypt with sk
decrypted_data = nacl.sealedbox_decrypt(data=encrypted_data, sk=self.sk)
self.assertEqual(self.unencrypted_data, decrypted_data)
def test_secretbox_enc_dec(self):
"""
Generate keys, encrypt, then decrypt.
"""
# Encrypt with sk
encrypted_data = nacl.secretbox_encrypt(data=self.unencrypted_data, sk=self.sk)
# Decrypt with sk
decrypted_data = nacl.secretbox_decrypt(data=encrypted_data, sk=self.sk)
self.assertEqual(self.unencrypted_data, decrypted_data)

View file

@ -1,149 +0,0 @@
import os
import sys
import pytest
import salt.modules.config as config
import salt.utils.files
from tests.support.helpers import with_tempfile
from tests.support.mixins import LoaderModuleMockMixin
from tests.support.unit import TestCase
try:
import libnacl.sealed # pylint: disable=unused-import
import libnacl.secret # pylint: disable=unused-import
import salt.utils.nacl as nacl
HAS_LIBNACL = True
except (ImportError, OSError, AttributeError):
HAS_LIBNACL = False
@pytest.mark.skipif(sys.version_info >= (3, 10), reason="Segfaults with python 3.10")
@pytest.mark.skipif(
not HAS_LIBNACL, reason="skipping test_nacl, reason=libnacl is unavailable"
)
class NaclUtilsTests(TestCase, LoaderModuleMockMixin):
def setup_loader_modules(self):
return {
nacl: {"__salt__": {"config.get": config.get}},
config: {"__opts__": {}},
}
def setUp(self):
self.key = "C16NxgBhw8cqbhvPCDAn2pirwW1A1WEVLUexCsoUD2Y="
self.pub = "+XWFfZXnfItS++a4gQf8Adu1aUlTgHWyTfsglbTdXyg="
def test_keygen(self):
"""
test nacl.keygen function
"""
ret = nacl.keygen()
assert all(key in ret for key in ret.keys())
@with_tempfile()
def test_keygen_sk_file(self, fpath):
"""
test nacl.keygen function
with sk_file set
"""
with salt.utils.files.fopen(fpath, "w") as wfh:
wfh.write(self.key)
# test sk_file
ret = nacl.keygen(sk_file=fpath)
assert "saved pk_file: {}.pub".format(fpath) == ret
@with_tempfile()
def test_keygen_keyfile(self, fpath):
"""
test nacl.keygen function
with keyfile set
"""
with salt.utils.files.fopen(fpath, "w") as wfh:
wfh.write(self.key)
ret = nacl.keygen(keyfile=fpath)
assert "saved pk_file: {}.pub".format(fpath) == ret
@with_tempfile()
def test_enc_keyfile(self, fpath):
"""
test nacl.enc function
with keyfile and pk_file set
"""
with salt.utils.files.fopen(fpath, "w") as wfh:
wfh.write(self.key)
with salt.utils.files.fopen(fpath + ".pub", "w") as wfh:
wfh.write(self.pub)
kwargs = {
"opts": {"pki_dir": os.path.dirname(fpath)},
"keyfile": fpath,
"pk_file": fpath + ".pub",
}
ret = nacl.enc("blah", **kwargs)
assert isinstance(ret, bytes)
@with_tempfile()
def test_enc_sk_file(self, fpath):
"""
test nacl.enc function
with sk_file and pk_file set
"""
with salt.utils.files.fopen(fpath, "w") as wfh:
wfh.write(self.key)
with salt.utils.files.fopen(fpath + ".pub", "w") as wfh:
wfh.write(self.pub)
kwargs = {
"opts": {"pki_dir": os.path.dirname(fpath)},
"sk_file": fpath,
"pk_file": fpath + ".pub",
}
ret = nacl.enc("blah", **kwargs)
assert isinstance(ret, bytes)
@with_tempfile()
def test_dec_keyfile(self, fpath):
"""
test nacl.dec function
with keyfile and pk_file set
"""
with salt.utils.files.fopen(fpath, "w") as wfh:
wfh.write(self.key)
with salt.utils.files.fopen(fpath + ".pub", "w") as wfh:
wfh.write(self.pub)
kwargs = {
"opts": {"pki_dir": os.path.dirname(fpath)},
"keyfile": fpath,
"pk_file": fpath + ".pub",
}
enc_data = nacl.enc("blah", **kwargs)
ret = nacl.dec(enc_data, **kwargs)
assert isinstance(ret, bytes)
assert ret == b"blah"
@with_tempfile()
def test_dec_sk_file(self, fpath):
"""
test nacl.dec function
with sk_file and pk_file set
"""
with salt.utils.files.fopen(fpath, "w") as wfh:
wfh.write(self.key)
with salt.utils.files.fopen(fpath + ".pub", "w") as wfh:
wfh.write(self.pub)
kwargs = {
"opts": {"pki_dir": os.path.dirname(fpath)},
"sk_file": fpath,
"pk_file": fpath + ".pub",
}
enc_data = nacl.enc("blah", **kwargs)
ret = nacl.dec(enc_data, **kwargs)
assert isinstance(ret, bytes)
assert ret == b"blah"

View file

@ -78,7 +78,7 @@ vm.add_argument("--region", help="The AWS region.", default=AWS_REGION)
"choices": list(AMIS),
},
"key_name": {
"help": "The SSH key name.",
"help": "The SSH key name. Will default to TOOLS_KEY_NAME in environment",
},
"instance_type": {
"help": "The instance type to use.",
@ -110,7 +110,7 @@ vm.add_argument("--region", help="The AWS region.", default=AWS_REGION)
def create(
ctx: Context,
name: str,
key_name: str = os.environ.get("RUNNER_NAME"), # type: ignore[assignment]
key_name: str = os.environ.get("RUNNER_NAME") or os.environ.get("TOOLS_KEY_NAME"), # type: ignore[assignment]
instance_type: str = None,
no_delete: bool = False,
no_destroy_on_failure: bool = False,
@ -566,7 +566,9 @@ def download_artifacts(ctx: Context, name: str):
@vm.command(
name="sync-cache",
arguments={
"key_name": {"help": "The SSH key name."},
"key_name": {
"help": "The SSH key name. Will default to TOOLS_KEY_NAME in environment"
},
"delete": {
"help": "Delete the entries in the cache that don't align with ec2",
"action": "store_true",
@ -575,7 +577,7 @@ def download_artifacts(ctx: Context, name: str):
)
def sync_cache(
ctx: Context,
key_name: str = os.environ.get("RUNNER_NAME"), # type: ignore[assignment]
key_name: str = os.environ.get("RUNNER_NAME") or os.environ.get("TOOLS_KEY_NAME"), # type: ignore[assignment]
delete: bool = False,
):
"""
@ -626,7 +628,9 @@ def sync_cache(
@vm.command(
name="list",
arguments={
"key_name": {"help": "The SSH key name."},
"key_name": {
"help": "The SSH key name. Will default to TOOLS_KEY_NAME in environment"
},
"states": {
"help": "The instance state to filter by.",
"flags": ["-s", "-state"],
@ -636,7 +640,7 @@ def sync_cache(
)
def list_vms(
ctx: Context,
key_name: str = os.environ.get("RUNNER_NAME"), # type: ignore[assignment]
key_name: str = os.environ.get("RUNNER_NAME") or os.environ.get("TOOLS_KEY_NAME"), # type: ignore[assignment]
states: set[str] = None,
):
"""