Merge remote-tracking branch 'upstream/3002.4'

This commit is contained in:
Pedro Algarvio 2021-02-25 17:31:33 +00:00
commit b76442e8f3
No known key found for this signature in database
GPG key ID: BB36BF6584A298FF
64 changed files with 3371 additions and 813 deletions

View file

@ -261,7 +261,7 @@ repos:
- id: pip-tools-compile
alias: compile-ci-linux-py3.5-zmq-requirements
name: Linux CI Py3.5 ZeroMQ Requirements
files: ^requirements/((base|zeromq|pytest)\.txt|static/((ci|pkg)/(linux|common)\.in|pkg/py3\.5/linux\.txt))$
files: ^requirements/((base|zeromq|pytest)\.txt|static/((ci|pkg)/(linux\.in|git-sources\.txt)|pkg/py3\.5/linux\.txt))$
pass_filenames: false
args:
- -v
@ -270,12 +270,13 @@ repos:
- --include=requirements/static/pkg/py{py_version}/linux.txt
- --include=requirements/pytest.txt
- --include=requirements/static/ci/common.in
- --include=requirements/static/ci/git-sources.txt
- requirements/static/ci/linux.in
- id: pip-tools-compile
alias: compile-ci-linux-py3.6-zmq-requirements
name: Linux CI Py3.6 ZeroMQ Requirements
files: ^requirements/((base|zeromq|pytest)\.txt|static/((ci|pkg)/(linux|common)\.in|pkg/py3\.6/linux\.txt))$
files: ^requirements/((base|zeromq|pytest)\.txt|static/((ci|pkg)/(linux\.in|git-sources\.txt)|pkg/py3\.6/linux\.txt))$
pass_filenames: false
args:
- -v
@ -284,12 +285,13 @@ repos:
- --include=requirements/static/pkg/py{py_version}/linux.txt
- --include=requirements/pytest.txt
- --include=requirements/static/ci/common.in
- --include=requirements/static/ci/git-sources.txt
- requirements/static/ci/linux.in
- id: pip-tools-compile
alias: compile-ci-linux-py3.7-zmq-requirements
name: Linux CI Py3.7 ZeroMQ Requirements
files: ^requirements/((base|zeromq|pytest)\.txt|static/((ci|pkg)/(linux|common)\.in|pkg/py3\.7/linux\.txt))$
files: ^requirements/((base|zeromq|pytest)\.txt|static/((ci|pkg)/(linux\.in|git-sources\.txt)|pkg/py3\.7/linux\.txt))$
pass_filenames: false
args:
- -v
@ -298,12 +300,13 @@ repos:
- --include=requirements/static/pkg/py{py_version}/linux.txt
- --include=requirements/pytest.txt
- --include=requirements/static/ci/common.in
- --include=requirements/static/ci/git-sources.txt
- requirements/static/ci/linux.in
- id: pip-tools-compile
alias: compile-ci-linux-py3.8-zmq-requirements
name: Linux CI Py3.8 ZeroMQ Requirements
files: ^requirements/((base|zeromq|pytest)\.txt|static/((ci|pkg)/(linux|common)\.in|pkg/py3\.8/linux\.txt))$
files: ^requirements/((base|zeromq|pytest)\.txt|static/((ci|pkg)/(linux\.in|git-sources\.txt)|pkg/py3\.8/linux\.txt))$
pass_filenames: false
args:
- -v
@ -312,12 +315,13 @@ repos:
- --include=requirements/static/pkg/py{py_version}/linux.txt
- --include=requirements/pytest.txt
- --include=requirements/static/ci/common.in
- --include=requirements/static/ci/git-sources.txt
- requirements/static/ci/linux.in
- id: pip-tools-compile
alias: compile-ci-linux-py3.9-zmq-requirements
name: Linux CI Py3.9 ZeroMQ Requirements
files: ^requirements/((base|zeromq|pytest)\.txt|static/((ci|pkg)/(linux|common)\.in|pkg/py3\.9/linux\.txt))$
files: ^requirements/((base|zeromq|pytest)\.txt|static/((ci|pkg)/(linux\.in|git-sources\.txt)|pkg/py3\.9/linux\.txt))$
pass_filenames: false
args:
- -v
@ -326,6 +330,7 @@ repos:
- --include=requirements/static/pkg/py{py_version}/linux.txt
- --include=requirements/pytest.txt
- --include=requirements/static/ci/common.in
- --include=requirements/static/ci/git-sources.txt
- requirements/static/ci/linux.in
- id: pip-tools-compile

View file

@ -7,6 +7,42 @@ Versions are `MAJOR.PATCH`.
# Changelog
Salt 3002.4 (2021-02-09)
========================
Fixed
-----
- Fix runners that broke when patching for CVE-2021-25281
- Fix issue with runners in SSE
Salt 3002.3 (2021-01-25)
========================
Fixed
-----
- CVE-2020-28243 - Fix local privilege escalation in the restartcheck module. (CVE-2020-28243)
- CVE-2020-28972 - Ensure authentication to vcenter, vsphere, and esxi server
validates the SSL/TLS certificate by default. If you want to skip SSL verification
you can use `verify_ssl: False`. (CVE-2020-28972)
- CVE-2020-35662 - Ensure the asam runner, qingcloud, splunk returner, panos
proxy, cimc proxy, zenoss module, esxi module, vsphere module, glassfish
module, bigip module, and keystone module validate SSL by default. If you want
to skip SSL verification you can use `verify_ssl: False`. (CVE-2020-35662)
- CVE-2021-25281 - Fix salt-api so it honors eauth credentials for the
wheel_async client. (CVE-2021-25281)
- CVE-2021-25282 - Fix the salt.wheel.pillar_roots.write method so it is not
vulnerable to directory traversal. (CVE-2021-25282)
- CVE-2021-25283 - Fix the jinja render to protect against server side template
injection attacks. (CVE-2021-25283)
- CVE-2021-25284 - Fix cmdmod so it will not log credentials to log levels info
and error. (CVE-2021-25284)
- CVE-2021-3144 - Fix eauth tokens can be used once after expiration. (CVE-2021-3144)
- CVE-2021-3148 - Fix a command injection in the Salt-API when using the Salt-SSH client. (CVE-2021-3148)
- CVE-2021-3197 - Fix ssh client to remove ProxyCommand from arguments provided
by cli and netapi. (CVE-2021-3197)
Salt 3002.2 (2020-11-16)
========================
@ -273,6 +309,43 @@ Added
This flag will be deprecated in the Phosphorus release when this functionality
becomes the default. (#58652)
Salt 3001.6 (2021-02-09)
========================
Fixed
-----
- Fix runners that broke when patching for CVE-2021-25281
- Fix issue with runners in SSE
Salt 3001.5
===========
Fixed
-----
- CVE-2020-28243 - Fix local privilege escalation in the restartcheck module. (CVE-2020-28243)
- CVE-2020-28972 - Ensure authentication to vcenter, vsphere, and esxi server
validates the SSL/TLS certificate by default. If you want to skip SSL verification
you can use `verify_ssl: False`. (CVE-2020-28972)
- CVE-2020-35662 - Ensure the asam runner, qingcloud, splunk returner, panos
proxy, cimc proxy, zenoss module, esxi module, vsphere module, glassfish
module, bigip module, and keystone module validate SSL by default. If you want
to skip SSL verification you can use `verify_ssl: False`. (CVE-2020-35662)
- CVE-2021-25281 - Fix salt-api so it honors eauth credentials for the
wheel_async client. (CVE-2021-25281)
- CVE-2021-25282 - Fix the salt.wheel.pillar_roots.write method so it is not
vulnerable to directory traversal. (CVE-2021-25282)
- CVE-2021-25283 - Fix the jinja render to protect against server side template
injection attacks. (CVE-2021-25283)
- CVE-2021-25284 - Fix cmdmod so it will not log credentials to log levels info
and error. (CVE-2021-25284)
- CVE-2021-3144 - Fix eauth tokens can be used once after expiration. (CVE-2021-3144)
- CVE-2021-3148 - Fix a command injection in the Salt-API when using the Salt-SSH client. (CVE-2021-3148)
- CVE-2021-3197 - Fix ssh client to remove ProxyCommand from arguments provided
by cli and netapi. (CVE-2021-3197)
Salt 3001.4
===========
@ -727,6 +800,42 @@ Added
- [#56637](https://github.com/saltstack/salt/pull/56637) - Add ``win_wua.installed`` to the ``win_wua`` execution module
- Clarify how to get the master fingerprint (#54699)
Salt 3000.8 (2021-02-09)
========================
Fixed
-----
- Fix runners that broke when patching for CVE-2021-25281
- Fix issue with runners in SSE
Salt 3000.7
===========
Fixed
-----
- CVE-2020-28243 - Fix local privilege escalation in the restartcheck module. (CVE-2020-28243)
- CVE-2020-28972 - Ensure authentication to vcenter, vsphere, and esxi server
validates the SSL/TLS certificate by default. If you want to skip SSL verification
you can use `verify_ssl: False`. (CVE-2020-28972)
- CVE-2020-35662 - Ensure the asam runner, qingcloud, splunk returner, panos
proxy, cimc proxy, zenoss module, esxi module, vsphere module, glassfish
module, bigip module, and keystone module validate SSL by default. If you want
to skip SSL verification you can use `verify_ssl: False`. (CVE-2020-35662)
- CVE-2021-25281 - Fix salt-api so it honors eauth credentials for the
wheel_async client. (CVE-2021-25281)
- CVE-2021-25282 - Fix the salt.wheel.pillar_roots.write method so it is not
vulnerable to directory traversal. (CVE-2021-25282)
- CVE-2021-25283 - Fix the jinja render to protect against server side template
injection attacks. (CVE-2021-25283)
- CVE-2021-25284 - Fix cmdmod so it will not log credentials to log levels info
and error. (CVE-2021-25284)
- CVE-2021-3144 - Fix eauth tokens can be used once after expiration. (CVE-2021-3144)
- CVE-2021-3148 - Fix a command injection in the Salt-API when using the Salt-SSH client. (CVE-2021-3148)
- CVE-2021-3197 - Fix ssh client to remove ProxyCommand from arguments provided
by cli and netapi. (CVE-2021-3197)
Salt 3000.6
===========

View file

@ -0,0 +1,41 @@
.. _release-3000-7:
=========================
Salt 3000.7 Release Notes
=========================
Version 3000.7 is a CVE fix release for :ref:`3000 <release-3000>`.
Fixed
-----
- CVE-2020-28243 - Fix local privilege escalation in the restartcheck module.
- CVE-2020-28972 - Ensure authentication to vcenter, vsphere, and esxi server
validates the SSL/TLS certificate by default. If you want to skip SSL verification
you can use `verify_ssl: False`.
- CVE-2020-35662 - Ensure the asam runner, qingcloud, splunk returner, panos
proxy, cimc proxy, zenoss module, esxi module, vsphere module, glassfish
module, bigip module, and keystone module validate SSL by default. If you want
to skip SSL verification you can use `verify_ssl: False`.
- CVE-2021-3148 - Fix a command injection in the Salt-API when using the
Salt-SSH client.
- CVE-2021-3144 - Fix eauth tokens can be used once after expiration
- CVE-2021-25281 - Fix salt-api so it honors eauth credentials for the
wheel_async client.
- CVE-2021-25282 - Fix the salt.wheel.pillar_roots.write method so it is not
vulnerable to directory traversal.
- CVE-2021-25283 - Fix the jinja render to protect against server side template
injection attacks.
- CVE-2021-25284 - Fix cmdmod so it will not log credentials to log levels info
and error.
- CVE-2021-3197 - Fix ssh client to remove ProxyCommand from arguments provided
by cli and netapi.

View file

@ -0,0 +1,13 @@
.. _release-3000-8:
=========================
Salt 3000.8 Release Notes
=========================
Version 3000.8 is a bug fix release for :ref:`3000 <release-3000>`.
Fixed
-----
- Fix runners that broke when patching for CVE-2021-25281
- Fix issue with runners in SSE

View file

@ -0,0 +1,41 @@
.. _release-3001-5:
=========================
Salt 3001.5 Release Notes
=========================
Version 3001.5 is a CVE fix release for :ref:`3001 <release-3001>`.
Fixed
-----
- CVE-2020-28243 - Fix local privilege escalation in the restartcheck module.
- CVE-2020-28972 - Ensure authentication to vcenter, vsphere, and esxi server
validates the SSL/TLS certificate by default. If you want to skip SSL verification
you can use `verify_ssl: False`.
- CVE-2020-35662 - Ensure the asam runner, qingcloud, splunk returner, panos
proxy, cimc proxy, zenoss module, esxi module, vsphere module, glassfish
module, bigip module, and keystone module validate SSL by default. If you want
to skip SSL verification you can use `verify_ssl: False`.
- CVE-2021-3148 - Fix a command injection in the Salt-API when using the
Salt-SSH client.
- CVE-2021-3144 - Fix eauth tokens can be used once after expiration
- CVE-2021-25281 - Fix salt-api so it honors eauth credentials for the
wheel_async client.
- CVE-2021-25282 - Fix the salt.wheel.pillar_roots.write method so it is not
vulnerable to directory traversal.
- CVE-2021-25283 - Fix the jinja render to protect against server side template
injection attacks.
- CVE-2021-25284 - Fix cmdmod so it will not log credentials to log levels info
and error.
- CVE-2021-3197 - Fix ssh client to remove ProxyCommand from arguments provided
by cli and netapi.

View file

@ -0,0 +1,13 @@
.. _release-3001-6:
=========================
Salt 3001.6 Release Notes
=========================
Version 3001.6 is a bug fix release for :ref:`3001 <release-3001>`.
Fixed
-----
- Fix runners that broke when patching for CVE-2021-25281
- Fix issue with runners in SSE

View file

@ -0,0 +1,41 @@
.. _release-3002-3:
=========================
Salt 3002.3 Release Notes
=========================
Version 3002.3 is a CVE fix release for :ref:`3002 <release-3002>`.
Fixed
-----
- CVE-2020-28243 - Fix local privilege escalation in the restartcheck module.
- CVE-2020-28972 - Ensure authentication to vcenter, vsphere, and esxi server
validates the SSL/TLS certificate by default. If you want to skip SSL verification
you can use `verify_ssl: False`.
- CVE-2020-35662 - Ensure the asam runner, qingcloud, splunk returner, panos
proxy, cimc proxy, zenoss module, esxi module, vsphere module, glassfish
module, bigip module, and keystone module validate SSL by default. If you want
to skip SSL verification you can use `verify_ssl: False`.
- CVE-2021-3148 - Fix a command injection in the Salt-API when using the
Salt-SSH client.
- CVE-2021-3144 - Fix eauth tokens can be used once after expiration
- CVE-2021-25281 - Fix salt-api so it honors eauth credentials for the
wheel_async client.
- CVE-2021-25282 - Fix the salt.wheel.pillar_roots.write method so it is not
vulnerable to directory traversal.
- CVE-2021-25283 - Fix the jinja render to protect against server side template
injection attacks.
- CVE-2021-25284 - Fix cmdmod so it will not log credentials to log levels info
and error.
- CVE-2021-3197 - Fix ssh client to remove ProxyCommand from arguments provided
by cli and netapi.

View file

@ -0,0 +1,13 @@
.. _release-3002-4:
=========================
Salt 3002.4 Release Notes
=========================
Version 3002.4 is a bug fix release for :ref:`3002 <release-3002>`.
Fixed
-----
- Fix runners that broke when patching for CVE-2021-25281
- Fix issue with runners in SSE

View file

@ -0,0 +1,2 @@
--extra-index-url=https://cdn.githubraw.com/saltstack/vsphere-automation-sdk-python/master/lib/
vSphere-Automation-SDK>=1.46.0

View file

View file

@ -2,8 +2,10 @@
# This file is autogenerated by pip-compile
# To update, run:
#
# pip-compile -o requirements/static/ci/py3.5/linux.txt -v requirements/static/pkg/py3.5/linux.txt requirements/pytest.txt requirements/static/ci/common.in requirements/static/ci/linux.in
# pip-compile -o requirements/static/ci/py3.5/linux.txt -v requirements/static/pkg/py3.5/linux.txt requirements/pytest.txt requirements/static/ci/common.in requirements/static/ci/git-sources.txt requirements/static/ci/linux.in
#
--extra-index-url https://cdn.githubraw.com/saltstack/vsphere-automation-sdk-python/master/lib/
adal==1.2.3 # via azure-datalake-store, msrestazure
apache-libcloud==2.5.0 ; sys_platform != "win32"
appdirs==1.4.4 # via virtualenv
@ -154,7 +156,7 @@ kazoo==2.6.1 ; sys_platform != "win32" and sys_platform != "darwin"
keyring==5.7.1
kubernetes==3.0.0
libnacl==1.7.1 ; sys_platform != "win32" and sys_platform != "darwin"
lxml==4.6.2 # via junos-eznc, ncclient
lxml==4.6.2 # via junos-eznc, ncclient, vsphere-automation-sdk
mako==1.1.0
markupsafe==1.1.1
mock==3.0.5
@ -166,6 +168,10 @@ msrestazure==0.6.3 # via azure-batch, azure-eventgrid, azure-graphrbac, a
ncclient==0.6.4 # via junos-eznc
netaddr==0.7.19 # via junos-eznc
networkx==2.4 # via cfn-lint
nsx-policy-python-sdk==3.0.2.0.0.16837625 # via vsphere-automation-sdk
nsx-python-sdk==3.0.2.0.0.16837625 # via vsphere-automation-sdk
nsx-vmc-aws-integration-python-sdk==3.0.2.0.0.16837625 # via vsphere-automation-sdk
nsx-vmc-policy-python-sdk==3.0.2.0.0.16837625 # via vsphere-automation-sdk
ntc-templates==1.4.0 # via junos-eznc
oauthlib==3.1.0 # via requests-oauthlib
oscrypto==1.2.0 # via certvalidator
@ -218,6 +224,7 @@ smmap==3.0.4 # via gitdb
sqlparse==0.4.1
sshpubkeys==3.1.0 # via moto
strict-rfc3339==0.7
suds-jurko==0.6 # via vsphere-automation-sdk
tempora==1.14.1
terminal==0.4.0 # via ntc-templates
textfsm==1.1.0 # via ntc-templates
@ -225,8 +232,14 @@ timelib==0.2.5
toml==0.10.2
transitions==0.8.1 # via junos-eznc
urllib3==1.24.2
vapi-client-bindings==3.5.0 # via vsphere-automation-sdk
vapi-common-client==2.19.0 # via nsx-policy-python-sdk, nsx-python-sdk, nsx-vmc-aws-integration-python-sdk, nsx-vmc-policy-python-sdk, vmc-client-bindings, vmc-draas-client-bindings, vsphere-automation-sdk
vapi-runtime==2.19.0 # via nsx-policy-python-sdk, nsx-python-sdk, nsx-vmc-aws-integration-python-sdk, nsx-vmc-policy-python-sdk, vapi-client-bindings, vapi-common-client, vmc-client-bindings, vmc-draas-client-bindings, vsphere-automation-sdk
vcert==0.7.3 ; sys_platform != "win32"
virtualenv==20.0.20
vmc-client-bindings==1.32.0 # via vsphere-automation-sdk
vmc-draas-client-bindings==1.17.0 # via vsphere-automation-sdk
vsphere-automation-sdk==1.46.0
watchdog==0.9.0
websocket-client==0.40.0 # via docker, kubernetes
werkzeug==0.15.6 # via moto

View file

View file

@ -2,8 +2,10 @@
# This file is autogenerated by pip-compile
# To update, run:
#
# pip-compile -o requirements/static/ci/py3.6/linux.txt -v requirements/static/pkg/py3.6/linux.txt requirements/pytest.txt requirements/static/ci/common.in requirements/static/ci/linux.in
# pip-compile -o requirements/static/ci/py3.6/linux.txt -v requirements/static/pkg/py3.6/linux.txt requirements/pytest.txt requirements/static/ci/common.in requirements/static/ci/git-sources.txt requirements/static/ci/linux.in
#
--extra-index-url https://cdn.githubraw.com/saltstack/vsphere-automation-sdk-python/master/lib/
adal==1.2.3 # via azure-datalake-store, msrestazure
apache-libcloud==2.5.0 ; sys_platform != "win32"
appdirs==1.4.4 # via virtualenv
@ -154,7 +156,7 @@ kazoo==2.6.1 ; sys_platform != "win32" and sys_platform != "darwin"
keyring==5.7.1
kubernetes==3.0.0
libnacl==1.7.1 ; sys_platform != "win32" and sys_platform != "darwin"
lxml==4.6.2 # via junos-eznc, ncclient
lxml==4.6.2 # via junos-eznc, ncclient, vsphere-automation-sdk
mako==1.1.0
markupsafe==1.1.1
mock==3.0.5
@ -166,6 +168,10 @@ msrestazure==0.6.3 # via azure-batch, azure-eventgrid, azure-graphrbac, a
ncclient==0.6.4 # via junos-eznc
netaddr==0.7.19 # via junos-eznc
networkx==2.5 # via cfn-lint
nsx-policy-python-sdk==3.0.2.0.0.16837625 # via vsphere-automation-sdk
nsx-python-sdk==3.0.2.0.0.16837625 # via vsphere-automation-sdk
nsx-vmc-aws-integration-python-sdk==3.0.2.0.0.16837625 # via vsphere-automation-sdk
nsx-vmc-policy-python-sdk==3.0.2.0.0.16837625 # via vsphere-automation-sdk
ntc-templates==1.4.0 # via junos-eznc
oauthlib==3.1.0 # via requests-oauthlib
oscrypto==1.2.0 # via certvalidator
@ -217,6 +223,7 @@ smmap==3.0.4 # via gitdb
sqlparse==0.4.1
sshpubkeys==3.1.0 # via moto
strict-rfc3339==0.7
suds-jurko==0.6 # via vsphere-automation-sdk
tempora==1.14.1
terminal==0.4.0 # via ntc-templates
textfsm==1.1.0 # via ntc-templates
@ -224,8 +231,14 @@ timelib==0.2.5
toml==0.10.2
transitions==0.8.1 # via junos-eznc
urllib3==1.24.2
vapi-client-bindings==3.5.0 # via vsphere-automation-sdk
vapi-common-client==2.19.0 # via nsx-policy-python-sdk, nsx-python-sdk, nsx-vmc-aws-integration-python-sdk, nsx-vmc-policy-python-sdk, vmc-client-bindings, vmc-draas-client-bindings, vsphere-automation-sdk
vapi-runtime==2.19.0 # via nsx-policy-python-sdk, nsx-python-sdk, nsx-vmc-aws-integration-python-sdk, nsx-vmc-policy-python-sdk, vapi-client-bindings, vapi-common-client, vmc-client-bindings, vmc-draas-client-bindings, vsphere-automation-sdk
vcert==0.7.3 ; sys_platform != "win32"
virtualenv==20.0.20
vmc-client-bindings==1.32.0 # via vsphere-automation-sdk
vmc-draas-client-bindings==1.17.0 # via vsphere-automation-sdk
vsphere-automation-sdk==1.46.0
watchdog==0.9.0
websocket-client==0.40.0 # via docker, kubernetes
werkzeug==0.15.6 # via moto

View file

@ -2,8 +2,10 @@
# This file is autogenerated by pip-compile
# To update, run:
#
# pip-compile -o requirements/static/ci/py3.7/linux.txt -v requirements/static/pkg/py3.7/linux.txt requirements/pytest.txt requirements/static/ci/common.in requirements/static/ci/linux.in
# pip-compile -o requirements/static/ci/py3.7/linux.txt -v requirements/static/pkg/py3.7/linux.txt requirements/pytest.txt requirements/static/ci/common.in requirements/static/ci/git-sources.txt requirements/static/ci/linux.in
#
--extra-index-url https://cdn.githubraw.com/saltstack/vsphere-automation-sdk-python/master/lib/
adal==1.2.3 # via azure-datalake-store, msrestazure
apache-libcloud==2.5.0 ; sys_platform != "win32"
appdirs==1.4.4 # via virtualenv
@ -152,7 +154,7 @@ kazoo==2.6.1 ; sys_platform != "win32" and sys_platform != "darwin"
keyring==5.7.1
kubernetes==3.0.0
libnacl==1.7.1 ; sys_platform != "win32" and sys_platform != "darwin"
lxml==4.6.2 # via junos-eznc, napalm, ncclient
lxml==4.6.2 # via junos-eznc, napalm, ncclient, vsphere-automation-sdk
mako==1.1.0
markupsafe==1.1.1
mock==3.0.5
@ -166,6 +168,10 @@ ncclient==0.6.4 # via junos-eznc
netaddr==0.7.19 # via junos-eznc, napalm, pyeapi
netmiko==3.2.0 # via napalm
networkx==2.5 # via cfn-lint
nsx-policy-python-sdk==3.0.2.0.0.16837625 # via vsphere-automation-sdk
nsx-python-sdk==3.0.2.0.0.16837625 # via vsphere-automation-sdk
nsx-vmc-aws-integration-python-sdk==3.0.2.0.0.16837625 # via vsphere-automation-sdk
nsx-vmc-policy-python-sdk==3.0.2.0.0.16837625 # via vsphere-automation-sdk
ntc-templates==1.4.0 # via junos-eznc
oauthlib==3.1.0 # via requests-oauthlib
oscrypto==1.2.0 # via certvalidator
@ -218,6 +224,7 @@ smmap==3.0.4 # via gitdb
sqlparse==0.4.1
sshpubkeys==3.1.0 # via moto
strict-rfc3339==0.7
suds-jurko==0.6 # via vsphere-automation-sdk
tempora==1.14.1
terminal==0.4.0 # via ntc-templates
textfsm==1.1.0 # via napalm, netmiko, ntc-templates
@ -225,8 +232,14 @@ timelib==0.2.5
toml==0.10.2
transitions==0.8.1 # via junos-eznc
urllib3==1.24.2
vapi-client-bindings==3.5.0 # via vsphere-automation-sdk
vapi-common-client==2.19.0 # via nsx-policy-python-sdk, nsx-python-sdk, nsx-vmc-aws-integration-python-sdk, nsx-vmc-policy-python-sdk, vmc-client-bindings, vmc-draas-client-bindings, vsphere-automation-sdk
vapi-runtime==2.19.0 # via nsx-policy-python-sdk, nsx-python-sdk, nsx-vmc-aws-integration-python-sdk, nsx-vmc-policy-python-sdk, vapi-client-bindings, vapi-common-client, vmc-client-bindings, vmc-draas-client-bindings, vsphere-automation-sdk
vcert==0.7.3 ; sys_platform != "win32"
virtualenv==20.0.20
vmc-client-bindings==1.32.0 # via vsphere-automation-sdk
vmc-draas-client-bindings==1.17.0 # via vsphere-automation-sdk
vsphere-automation-sdk==1.46.0
watchdog==0.9.0
websocket-client==0.40.0 # via docker, kubernetes
werkzeug==0.15.6 # via moto

View file

@ -2,8 +2,10 @@
# This file is autogenerated by pip-compile
# To update, run:
#
# pip-compile -o requirements/static/ci/py3.8/linux.txt -v requirements/static/pkg/py3.8/linux.txt requirements/pytest.txt requirements/static/ci/common.in requirements/static/ci/linux.in
# pip-compile -o requirements/static/ci/py3.8/linux.txt -v requirements/static/pkg/py3.8/linux.txt requirements/pytest.txt requirements/static/ci/common.in requirements/static/ci/git-sources.txt requirements/static/ci/linux.in
#
--extra-index-url https://cdn.githubraw.com/saltstack/vsphere-automation-sdk-python/master/lib/
adal==1.2.3 # via azure-datalake-store, msrestazure
apache-libcloud==2.5.0 ; sys_platform != "win32"
appdirs==1.4.4 # via virtualenv
@ -151,7 +153,7 @@ kazoo==2.6.1 ; sys_platform != "win32" and sys_platform != "darwin"
keyring==5.7.1
kubernetes==3.0.0
libnacl==1.7.1 ; sys_platform != "win32" and sys_platform != "darwin"
lxml==4.6.2 # via junos-eznc, napalm, ncclient
lxml==4.6.2 # via junos-eznc, napalm, ncclient, vsphere-automation-sdk
mako==1.1.0
markupsafe==1.1.1
mock==3.0.5
@ -165,6 +167,10 @@ ncclient==0.6.4 # via junos-eznc
netaddr==0.7.19 # via junos-eznc, napalm, pyeapi
netmiko==3.2.0 # via napalm
networkx==2.5 # via cfn-lint
nsx-policy-python-sdk==3.0.2.0.0.16837625 # via vsphere-automation-sdk
nsx-python-sdk==3.0.2.0.0.16837625 # via vsphere-automation-sdk
nsx-vmc-aws-integration-python-sdk==3.0.2.0.0.16837625 # via vsphere-automation-sdk
nsx-vmc-policy-python-sdk==3.0.2.0.0.16837625 # via vsphere-automation-sdk
ntc-templates==1.4.1 # via junos-eznc
oauthlib==3.1.0 # via requests-oauthlib
oscrypto==1.2.0 # via certvalidator
@ -217,6 +223,7 @@ smmap==3.0.4 # via gitdb
sqlparse==0.4.1
sshpubkeys==3.1.0 # via moto
strict-rfc3339==0.7
suds-jurko==0.6 # via vsphere-automation-sdk
tempora==1.14.1
terminal==0.4.0 # via ntc-templates
textfsm==1.1.0 # via napalm, netmiko, ntc-templates
@ -224,8 +231,14 @@ timelib==0.2.5
toml==0.10.2
transitions==0.8.1 # via junos-eznc
urllib3==1.24.2
vapi-client-bindings==3.5.0 # via vsphere-automation-sdk
vapi-common-client==2.19.0 # via nsx-policy-python-sdk, nsx-python-sdk, nsx-vmc-aws-integration-python-sdk, nsx-vmc-policy-python-sdk, vmc-client-bindings, vmc-draas-client-bindings, vsphere-automation-sdk
vapi-runtime==2.19.0 # via nsx-policy-python-sdk, nsx-python-sdk, nsx-vmc-aws-integration-python-sdk, nsx-vmc-policy-python-sdk, vapi-client-bindings, vapi-common-client, vmc-client-bindings, vmc-draas-client-bindings, vsphere-automation-sdk
vcert==0.7.3 ; sys_platform != "win32"
virtualenv==20.0.20
vmc-client-bindings==1.32.0 # via vsphere-automation-sdk
vmc-draas-client-bindings==1.17.0 # via vsphere-automation-sdk
vsphere-automation-sdk==1.46.0
watchdog==0.9.0
websocket-client==0.40.0 # via docker, kubernetes
werkzeug==0.15.6 # via moto

View file

@ -2,8 +2,10 @@
# This file is autogenerated by pip-compile
# To update, run:
#
# pip-compile -o requirements/static/ci/py3.9/linux.txt -v requirements/static/pkg/py3.9/linux.txt requirements/pytest.txt requirements/static/ci/common.in requirements/static/ci/linux.in
# pip-compile -o requirements/static/ci/py3.9/linux.txt -v requirements/static/pkg/py3.9/linux.txt requirements/pytest.txt requirements/static/ci/common.in requirements/static/ci/git-sources.txt requirements/static/ci/linux.in
#
--extra-index-url https://cdn.githubraw.com/saltstack/vsphere-automation-sdk-python/master/lib/
adal==1.2.3 # via azure-datalake-store, msrestazure
apache-libcloud==2.5.0 ; sys_platform != "win32"
appdirs==1.4.4 # via virtualenv
@ -152,7 +154,7 @@ kazoo==2.6.1 ; sys_platform != "win32" and sys_platform != "darwin"
keyring==5.7.1
kubernetes==3.0.0
libnacl==1.7.1 ; sys_platform != "win32" and sys_platform != "darwin"
lxml==4.6.2 # via junos-eznc, napalm, ncclient
lxml==4.6.2 # via junos-eznc, napalm, ncclient, vsphere-automation-sdk
mako==1.1.0
markupsafe==1.1.1
mock==3.0.5
@ -166,6 +168,10 @@ ncclient==0.6.4 # via junos-eznc
netaddr==0.7.19 # via junos-eznc, napalm, pyeapi
netmiko==3.2.0 # via napalm
networkx==2.5 # via cfn-lint
nsx-policy-python-sdk==3.0.2.0.0.16837625 # via vsphere-automation-sdk
nsx-python-sdk==3.0.2.0.0.16837625 # via vsphere-automation-sdk
nsx-vmc-aws-integration-python-sdk==3.0.2.0.0.16837625 # via vsphere-automation-sdk
nsx-vmc-policy-python-sdk==3.0.2.0.0.16837625 # via vsphere-automation-sdk
ntc-templates==1.4.1 # via junos-eznc
oauthlib==3.1.0 # via requests-oauthlib
oscrypto==1.2.0 # via certvalidator
@ -218,6 +224,7 @@ smmap==3.0.4 # via gitdb
sqlparse==0.4.1
sshpubkeys==3.1.0 # via moto
strict-rfc3339==0.7
suds-jurko==0.6 # via vsphere-automation-sdk
tempora==1.14.1
terminal==0.4.0 # via ntc-templates
textfsm==1.1.0 # via napalm, netmiko, ntc-templates
@ -225,8 +232,14 @@ timelib==0.2.5
toml==0.10.2
transitions==0.8.1 # via junos-eznc
urllib3==1.24.2
vapi-client-bindings==3.5.0 # via vsphere-automation-sdk
vapi-common-client==2.19.0 # via nsx-policy-python-sdk, nsx-python-sdk, nsx-vmc-aws-integration-python-sdk, nsx-vmc-policy-python-sdk, vmc-client-bindings, vmc-draas-client-bindings, vsphere-automation-sdk
vapi-runtime==2.19.0 # via nsx-policy-python-sdk, nsx-python-sdk, nsx-vmc-aws-integration-python-sdk, nsx-vmc-policy-python-sdk, vapi-client-bindings, vapi-common-client, vmc-client-bindings, vmc-draas-client-bindings, vsphere-automation-sdk
vcert==0.7.3 ; sys_platform != "win32"
virtualenv==20.0.20
vmc-client-bindings==1.32.0 # via vsphere-automation-sdk
vmc-draas-client-bindings==1.17.0 # via vsphere-automation-sdk
vsphere-automation-sdk==1.46.0
watchdog==0.9.0
websocket-client==0.40.0 # via docker, kubernetes
werkzeug==0.15.6 # via moto

View file

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""
Salt's pluggable authentication system
@ -13,9 +12,6 @@ so that any external authentication system can be used inside of Salt
# 5. Cache auth token with relative data opts['token_dir']
# 6. Interface to verify tokens
from __future__ import absolute_import, print_function, unicode_literals
import collections
import getpass
import logging
import random
@ -34,8 +30,6 @@ import salt.utils.minions
import salt.utils.user
import salt.utils.versions
import salt.utils.zeromq
from salt.ext import six
from salt.ext.six.moves import input
log = logging.getLogger(__name__)
@ -56,7 +50,7 @@ AUTH_INTERNAL_KEYWORDS = frozenset(
)
class LoadAuth(object):
class LoadAuth:
"""
Wrap the authentication system to handle peripheral components
"""
@ -76,7 +70,7 @@ class LoadAuth(object):
"""
if "eauth" not in load:
return ""
fstr = "{0}.auth".format(load["eauth"])
fstr = "{}.auth".format(load["eauth"])
if fstr not in self.auth:
return ""
try:
@ -94,7 +88,7 @@ class LoadAuth(object):
"""
if "eauth" not in load:
return False
fstr = "{0}.auth".format(load["eauth"])
fstr = "{}.auth".format(load["eauth"])
if fstr not in self.auth:
return False
# When making auth calls, only username, password, auth, and token
@ -144,7 +138,7 @@ class LoadAuth(object):
mod = self.opts["eauth_acl_module"]
if not mod:
mod = load["eauth"]
fstr = "{0}.acl".format(mod)
fstr = "{}.acl".format(mod)
if fstr not in self.auth:
return None
fcall = salt.utils.args.format_call(
@ -163,7 +157,7 @@ class LoadAuth(object):
"""
if "eauth" not in load:
return auth_list
fstr = "{0}.process_acl".format(load["eauth"])
fstr = "{}.process_acl".format(load["eauth"])
if fstr not in self.auth:
return auth_list
try:
@ -179,7 +173,7 @@ class LoadAuth(object):
"""
if "eauth" not in load:
return False
fstr = "{0}.groups".format(load["eauth"])
fstr = "{}.groups".format(load["eauth"])
if fstr not in self.auth:
return False
fcall = salt.utils.args.format_call(
@ -237,7 +231,7 @@ class LoadAuth(object):
if groups:
tdata["groups"] = groups
return self.tokens["{0}.mk_token".format(self.opts["eauth_tokens"])](
return self.tokens["{}.mk_token".format(self.opts["eauth_tokens"])](
self.opts, tdata
)
@ -248,7 +242,7 @@ class LoadAuth(object):
"""
tdata = {}
try:
tdata = self.tokens["{0}.get_token".format(self.opts["eauth_tokens"])](
tdata = self.tokens["{}.get_token".format(self.opts["eauth_tokens"])](
self.opts, tok
)
except salt.exceptions.SaltDeserializationError:
@ -268,6 +262,7 @@ class LoadAuth(object):
if rm_tok:
self.rm_token(tok)
return {}
return tdata
@ -275,7 +270,7 @@ class LoadAuth(object):
"""
List all tokens in eauth_tokn storage.
"""
return self.tokens["{0}.list_tokens".format(self.opts["eauth_tokens"])](
return self.tokens["{}.list_tokens".format(self.opts["eauth_tokens"])](
self.opts
)
@ -283,7 +278,7 @@ class LoadAuth(object):
"""
Remove the given token from token storage.
"""
self.tokens["{0}.rm_token".format(self.opts["eauth_tokens"])](self.opts, tok)
self.tokens["{}.rm_token".format(self.opts["eauth_tokens"])](self.opts, tok)
def authenticate_token(self, load):
"""
@ -459,7 +454,7 @@ class LoadAuth(object):
ret["error"] = {
"name": "EauthAuthenticationError",
"message": 'Authentication failure of type "eauth" occurred for '
"user {0}.".format(username),
"user {}.".format(username),
}
return ret
@ -469,7 +464,7 @@ class LoadAuth(object):
msg = 'Authentication failure of type "user" occurred'
if not auth_ret: # auth_ret can be a boolean or the effective user id
if show_username:
msg = "{0} for user {1}.".format(msg, username)
msg = "{} for user {}.".format(msg, username)
ret["error"] = {"name": "UserAuthenticationError", "message": msg}
return ret
@ -501,7 +496,7 @@ class LoadAuth(object):
return ret
class Resolver(object):
class Resolver:
"""
The class used to resolve options for the command line and for generic
interactive interfaces
@ -514,7 +509,7 @@ class Resolver(object):
def _send_token_request(self, load):
master_uri = "tcp://{}:{}".format(
salt.utils.zeromq.ip_bracket(self.opts["interface"]),
six.text_type(self.opts["ret_port"]),
str(self.opts["ret_port"]),
)
with salt.transport.client.ReqChannel.factory(
self.opts, crypt="clear", master_uri=master_uri
@ -530,16 +525,16 @@ class Resolver(object):
if not eauth:
print("External authentication system has not been specified")
return ret
fstr = "{0}.auth".format(eauth)
fstr = "{}.auth".format(eauth)
if fstr not in self.auth:
print(
(
'The specified external authentication system "{0}" is '
'The specified external authentication system "{}" is '
"not available"
).format(eauth)
)
print(
"Available eauth types: {0}".format(
"Available eauth types: {}".format(
", ".join([k[:-5] for k in self.auth if k.endswith(".auth")])
)
)
@ -550,14 +545,14 @@ class Resolver(object):
if arg in self.opts:
ret[arg] = self.opts[arg]
elif arg.startswith("pass"):
ret[arg] = getpass.getpass("{0}: ".format(arg))
ret[arg] = getpass.getpass("{}: ".format(arg))
else:
ret[arg] = input("{0}: ".format(arg))
ret[arg] = input("{}: ".format(arg))
for kwarg, default in list(args["kwargs"].items()):
if kwarg in self.opts:
ret["kwarg"] = self.opts[kwarg]
else:
ret[kwarg] = input("{0} [{1}]: ".format(kwarg, default))
ret[kwarg] = input("{} [{}]: ".format(kwarg, default))
# Use current user if empty
if "username" in ret and not ret["username"]:
@ -579,7 +574,7 @@ class Resolver(object):
with salt.utils.files.set_umask(0o177):
with salt.utils.files.fopen(self.opts["token_file"], "w+") as fp_:
fp_.write(tdata["token"])
except (IOError, OSError):
except OSError:
pass
return tdata
@ -602,7 +597,7 @@ class Resolver(object):
return tdata
class AuthUser(object):
class AuthUser:
"""
Represents a user requesting authentication to the salt master
"""

View file

@ -478,10 +478,10 @@ class AsyncClientMixin:
client = None
tag_prefix = None
def _proc_function(self, fun, low, user, tag, jid, daemonize=True):
def _proc_function_remote(self, fun, low, user, tag, jid, daemonize=True):
"""
Run this method in a multiprocess target to execute the function in a
multiprocess and fire the return data on the event bus
Run this method in a multiprocess target to execute the function on the
master and fire the return data on the event bus
"""
if daemonize and not salt.utils.platform.is_windows():
# Shutdown the multiprocessing before daemonizing
@ -497,7 +497,52 @@ class AsyncClientMixin:
low["__user__"] = user
low["__tag__"] = tag
return self.low(fun, low, full_return=False)
try:
return self.cmd_sync(low)
except salt.exceptions.EauthAuthenticationError as exc:
log.error(exc)
def _proc_function(self, fun, low, user, tag, jid, daemonize=True):
"""
Run this method in a multiprocess target to execute the function
locally and fire the return data on the event bus
"""
if daemonize and not salt.utils.platform.is_windows():
# Shutdown the multiprocessing before daemonizing
salt.log.setup.shutdown_multiprocessing_logging()
salt.utils.process.daemonize()
# Reconfigure multiprocessing logging after daemonizing
salt.log.setup.setup_multiprocessing_logging()
# pack a few things into low
low["__jid__"] = jid
low["__user__"] = user
low["__tag__"] = tag
return self.low(fun, low)
def _proc_function_local(self, fun, low, user, tag, jid, daemonize=True):
"""
Run this method in a multiprocess target to execute the function
locally and fire the return data on the event bus
"""
if daemonize and not salt.utils.platform.is_windows():
# Shutdown the multiprocessing before daemonizing
salt.log.setup.shutdown_multiprocessing_logging()
salt.utils.process.daemonize()
# Reconfigure multiprocessing logging after daemonizing
salt.log.setup.setup_multiprocessing_logging()
# pack a few things into low
low["__jid__"] = jid
low["__user__"] = user
low["__tag__"] = tag
return self.low(fun, low)
def cmd_async(self, low):
"""
@ -525,14 +570,18 @@ class AsyncClientMixin:
tag = salt.utils.event.tagify(jid, prefix=self.tag_prefix)
return {"tag": tag, "jid": jid}
def asynchronous(self, fun, low, user="UNKNOWN", pub=None):
def asynchronous(self, fun, low, user="UNKNOWN", pub=None, local=True):
"""
Execute the function in a multiprocess and return the event tag to use
to watch for the return
"""
if local:
proc_func = self._proc_function
else:
proc_func = self._proc_function_remote
async_pub = pub if pub is not None else self._gen_async_pub()
proc = salt.utils.process.SignalHandlingProcess(
target=self._proc_function,
target=proc_func,
name="ProcessFunc",
args=(fun, low, user, async_pub["tag"], async_pub["jid"]),
)

View file

@ -39,12 +39,58 @@ class SSHClient:
# Salt API should never offer a custom roster!
self.opts["__disable_custom_roster"] = disable_custom_roster
def sanitize_kwargs(self, kwargs):
roster_vals = [
("host", str),
("ssh_user", str),
("ssh_passwd", str),
("ssh_port", int),
("ssh_sudo", bool),
("ssh_sudo_user", str),
("ssh_priv", str),
("ssh_priv_passwd", str),
("ssh_identities_only", bool),
("ssh_remote_port_forwards", str),
("ssh_options", list),
("roster_file", str),
("rosters", list),
("ignore_host_keys", bool),
("raw_shell", bool),
]
sane_kwargs = {}
for name, kind in roster_vals:
if name not in kwargs:
continue
try:
val = kind(kwargs[name])
except ValueError:
log.warn("Unable to cast kwarg %s", name)
continue
if kind is bool or kind is int:
sane_kwargs[name] = val
elif kind is str:
if val.find("ProxyCommand") != -1:
log.warn("Filter unsafe value for kwarg %s", name)
continue
sane_kwargs[name] = val
elif kind is list:
sane_val = []
for item in val:
# This assumes the values are strings
if item.find("ProxyCommand") != -1:
log.warn("Filter unsafe value for kwarg %s", name)
continue
sane_val.append(item)
sane_kwargs[name] = sane_val
return sane_kwargs
def _prep_ssh(
self, tgt, fun, arg=(), timeout=None, tgt_type="glob", kwarg=None, **kwargs
):
"""
Prepare the arguments
"""
kwargs = self.sanitize_kwargs(kwargs)
opts = copy.deepcopy(self.opts)
opts.update(kwargs)
if timeout:

View file

@ -141,6 +141,14 @@ def query(params=None):
"secret_access_key", get_configured_provider(), __opts__, search_global=False
)
verify_ssl = config.get_cloud_config_value(
"verify_ssl",
get_configured_provider(),
__opts__,
default=True,
search_global=False,
)
# public interface parameters
real_parameters = {
"access_key_id": access_key_id,
@ -171,7 +179,7 @@ def query(params=None):
# print('parameters:')
# pprint.pprint(real_parameters)
request = requests.get(path, params=real_parameters, verify=False)
request = requests.get(path, params=real_parameters, verify=verify_ssl)
# print('url:')
# print(request.url)

View file

@ -257,9 +257,15 @@ def _get_si():
port = config.get_cloud_config_value(
"port", get_configured_provider(), __opts__, search_global=False, default=443
)
verify_ssl = config.get_cloud_config_value(
"verify_ssl",
get_configured_provider(),
__opts__,
search_global=False,
default=True,
)
return salt.utils.vmware.get_service_instance(
url, username, password, protocol=protocol, port=port
url, username, password, protocol=protocol, port=port, verify_ssl=verify_ssl
)

View file

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""
:codeauthor: :email:`Rod McKenzie (roderick.mckenzie@morganstanley.com)`
:codeauthor: :email:`Alexandru Bleotu (alexandru.bleotu@morganstanley.com)`
@ -9,11 +8,7 @@
VCenter configuration schemas
"""
# Import Python libs
from __future__ import absolute_import, print_function, unicode_literals
# Import Salt libs
from salt.utils.schema import ArrayItem, IntegerItem, Schema, StringItem
from salt.utils.schema import ArrayItem, BooleanItem, IntegerItem, Schema, StringItem
class VCenterEntitySchema(Schema):
@ -48,6 +43,8 @@ class VCenterProxySchema(Schema):
mechanism = StringItem(required=True, enum=["userpass", "sspi"])
username = StringItem()
passwords = ArrayItem(min_items=1, items=StringItem(), unique_items=True)
verify_ssl = BooleanItem()
ca_bundle = StringItem()
domain = StringItem()
principal = StringItem(default="host")

View file

@ -2063,7 +2063,7 @@ class ClearFuncs(TransportMethods):
fun = clear_load.pop("fun")
runner_client = salt.runner.RunnerClient(self.opts)
return runner_client.asynchronous(
fun, clear_load.get("kwarg", {}), username
fun, clear_load.get("kwarg", {}), username, local=True
)
except Exception as exc: # pylint: disable=broad-except
log.error("Exception occurred while introspecting %s: %s", fun, exc)

View file

@ -4,7 +4,6 @@ An execution module which can manipulate an f5 bigip via iControl REST
:platform: f5_bigip_11.6
"""
import salt.exceptions
import salt.utils.json
@ -44,7 +43,7 @@ def _build_session(username, password, trans_label=None):
bigip = requests.session()
bigip.auth = (username, password)
bigip.verify = False
bigip.verify = True
bigip.headers.update({"Content-Type": "application/json"})
if trans_label:

View file

@ -78,6 +78,12 @@ def __virtual__():
return __virtualname__
def _log_cmd(cmd):
if not isinstance(cmd, list):
return cmd.split()[0].strip()
return cmd[0].strip()
def _check_cb(cb_):
"""
If the callback is None or is not callable, return a lambda that returns
@ -387,22 +393,13 @@ def _run(
)
env[bad_env_key] = ""
def _get_stripped(cmd):
# Return stripped command string copies to improve logging.
if isinstance(cmd, list):
return [x.strip() if isinstance(x, str) else x for x in cmd]
elif isinstance(cmd, str):
return cmd.strip()
else:
return cmd
if output_loglevel is not None:
# Always log the shell commands at INFO unless quiet logging is
# requested. The command output is what will be controlled by the
# 'loglevel' parameter.
msg = "Executing command {}{}{} {}{}in directory '{}'{}".format(
"'" if not isinstance(cmd, list) else "",
_get_stripped(cmd),
_log_cmd(cmd),
"'" if not isinstance(cmd, list) else "",
"as user '{}' ".format(runas) if runas else "",
"in group '{}' ".format(group) if group else "",
@ -728,7 +725,7 @@ def _run(
log.error(
"Failed to decode stdout from command %s, non-decodable "
"characters have been replaced",
cmd,
_log_cmd(cmd),
)
try:
@ -746,7 +743,7 @@ def _run(
log.error(
"Failed to decode stderr from command %s, non-decodable "
"characters have been replaced",
cmd,
_log_cmd(cmd),
)
if rstrip:
@ -846,7 +843,9 @@ def _run(
if not ignore_retcode and ret["retcode"] != 0:
if output_loglevel < LOG_LEVELS["error"]:
output_loglevel = LOG_LEVELS["error"]
msg = "Command '{}' failed with return code: {}".format(cmd, ret["retcode"])
msg = "Command '{}' failed with return code: {}".format(
_log_cmd(cmd), ret["retcode"]
)
log.error(log_callback(msg))
if ret["stdout"]:
log.log(output_loglevel, "stdout: %s", log_callback(ret["stdout"]))
@ -1220,7 +1219,9 @@ def run(
if not ignore_retcode and ret["retcode"] != 0:
if lvl < LOG_LEVELS["error"]:
lvl = LOG_LEVELS["error"]
msg = "Command '{}' failed with return code: {}".format(cmd, ret["retcode"])
msg = "Command '{}' failed with return code: {}".format(
_log_cmd(cmd), ret["retcode"]
)
log.error(log_callback(msg))
if raise_err:
raise CommandExecutionError(

View file

@ -124,7 +124,7 @@ def _api_get(path, server=None):
url=_get_url(server["ssl"], server["url"], server["port"], path),
auth=_get_auth(server["user"], server["password"]),
headers=_get_headers(),
verify=False,
verify=True,
)
return _api_response(response)
@ -139,7 +139,7 @@ def _api_post(path, data, server=None):
auth=_get_auth(server["user"], server["password"]),
headers=_get_headers(),
data=salt.utils.json.dumps(data),
verify=False,
verify=True,
)
return _api_response(response)
@ -154,7 +154,7 @@ def _api_delete(path, data, server=None):
auth=_get_auth(server["user"], server["password"]),
headers=_get_headers(),
params=data,
verify=False,
verify=True,
)
return _api_response(response)

View file

@ -12,6 +12,7 @@ Module for handling openstack keystone calls.
keystone.tenant: admin
keystone.tenant_id: f80919baedab48ec8931f200c65a50df
keystone.auth_url: 'http://127.0.0.1:5000/v2.0/'
keystone.verify_ssl: True
OR (for token based authentication)
@ -31,6 +32,7 @@ Module for handling openstack keystone calls.
keystone.tenant: admin
keystone.tenant_id: f80919baedab48ec8931f200c65a50df
keystone.auth_url: 'http://127.0.0.1:5000/v2.0/'
keystone.verify_ssl: True
openstack2:
keystone.user: admin
@ -38,6 +40,7 @@ Module for handling openstack keystone calls.
keystone.tenant: admin
keystone.tenant_id: f80919baedab48ec8931f200c65a50df
keystone.auth_url: 'http://127.0.0.2:5000/v2.0/'
keystone.verify_ssl: True
With this configuration in place, any of the keystone functions can make use
of a configuration profile by declaring it explicitly.
@ -117,6 +120,7 @@ def _get_kwargs(profile=None, **connection_args):
endpoint = get("endpoint", "http://127.0.0.1:35357/v2.0")
user_domain_name = get("user_domain_name", "Default")
project_domain_name = get("project_domain_name", "Default")
verify_ssl = get("verify_ssl", True)
if token:
kwargs = {"token": token, "endpoint": endpoint}
else:
@ -133,6 +137,7 @@ def _get_kwargs(profile=None, **connection_args):
# this ensures it's only passed in when defined
if insecure:
kwargs["insecure"] = True
kwargs["verify_ssl"] = verify_ssl
return kwargs
@ -150,7 +155,7 @@ def api_version(profile=None, **connection_args):
auth_url = kwargs.get("auth_url", kwargs.get("endpoint", None))
try:
return salt.utils.http.query(
auth_url, decode=True, decode_type="json", verify_ssl=False
auth_url, decode=True, decode_type="json", verify_ssl=kwargs["verify_ssl"]
)["dict"]["version"]["id"]
except KeyError:
return None
@ -392,7 +397,7 @@ def endpoint_list(profile=None, **connection_args):
value: getattr(endpoint, value)
for value in dir(endpoint)
if not value.startswith("_")
and isinstance(getattr(endpoint, value), ((str,), dict, bool))
and isinstance(getattr(endpoint, value), (str, dict, bool))
}
return ret
@ -559,7 +564,7 @@ def role_list(profile=None, **connection_args):
value: getattr(role, value)
for value in dir(role)
if not value.startswith("_")
and isinstance(getattr(role, value), ((str,), dict, bool))
and isinstance(getattr(role, value), (str, dict, bool))
}
return ret
@ -628,7 +633,7 @@ def service_get(service_id=None, name=None, profile=None, **connection_args):
value: getattr(service, value)
for value in dir(service)
if not value.startswith("_")
and isinstance(getattr(service, value), ((str,), dict, bool))
and isinstance(getattr(service, value), (str, dict, bool))
}
return ret
@ -650,7 +655,7 @@ def service_list(profile=None, **connection_args):
value: getattr(service, value)
for value in dir(service)
if not value.startswith("_")
and isinstance(getattr(service, value), ((str,), dict, bool))
and isinstance(getattr(service, value), (str, dict, bool))
}
return ret
@ -800,7 +805,7 @@ def tenant_get(tenant_id=None, name=None, profile=None, **connection_args):
value: getattr(tenant, value)
for value in dir(tenant)
if not value.startswith("_")
and isinstance(getattr(tenant, value), ((str,), dict, bool))
and isinstance(getattr(tenant, value), (str, dict, bool))
}
return ret
@ -858,7 +863,7 @@ def tenant_list(profile=None, **connection_args):
value: getattr(tenant, value)
for value in dir(tenant)
if not value.startswith("_")
and isinstance(getattr(tenant, value), ((str,), dict, bool))
and isinstance(getattr(tenant, value), (str, dict, bool))
}
return ret
@ -933,7 +938,7 @@ def tenant_update(
value: getattr(updated, value)
for value in dir(updated)
if not value.startswith("_")
and isinstance(getattr(updated, value), ((str,), dict, bool))
and isinstance(getattr(updated, value), (str, dict, bool))
}
@ -1029,7 +1034,7 @@ def user_list(profile=None, **connection_args):
value: getattr(user, value, None)
for value in dir(user)
if not value.startswith("_")
and isinstance(getattr(user, value, None), ((str,), dict, bool))
and isinstance(getattr(user, value, None), (str, dict, bool))
}
tenant_id = getattr(user, "tenantId", None)
if tenant_id:
@ -1069,7 +1074,7 @@ def user_get(user_id=None, name=None, profile=None, **connection_args):
value: getattr(user, value, None)
for value in dir(user)
if not value.startswith("_")
and isinstance(getattr(user, value, None), ((str,), dict, bool))
and isinstance(getattr(user, value, None), (str, dict, bool))
}
tenant_id = getattr(user, "tenantId", None)
@ -1499,7 +1504,7 @@ tenant_id=7167a092ece84bae8cead4bf9d15bb3b
value: getattr(role, value)
for value in dir(role)
if not value.startswith("_")
and isinstance(getattr(role, value), ((str,), dict, bool))
and isinstance(getattr(role, value), (str, dict, bool))
}
else:
for role in kstone.roles.roles_for_user(user=user_id, tenant=tenant_id):

View file

@ -11,6 +11,7 @@ https://packages.debian.org/debian-goodies) and psdel by Sam Morris.
"""
import os
import re
import shlex
import subprocess
import sys
import time
@ -613,7 +614,8 @@ def restartcheck(ignorelist=None, blacklist=None, excludepid=None, **kwargs):
for package in packages:
_check_timeout(start_time, timeout)
cmd = cmd_pkg_query + package
paths = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
cmd = shlex.split(cmd)
paths = subprocess.Popen(cmd, stdout=subprocess.PIPE)
while True:
_check_timeout(start_time, timeout)

File diff suppressed because it is too large Load diff

View file

@ -3,8 +3,6 @@ Module for working with the Zenoss API
.. versionadded:: 2016.3.0
:depends: requests
:configuration: This module requires a 'zenoss' entry in the master/minion config.
For example:
@ -15,26 +13,16 @@ Module for working with the Zenoss API
hostname: https://zenoss.example.com
username: admin
password: admin123
verify_ssl: True
ca_bundle: /etc/ssl/certs/ca-certificates.crt
"""
import logging
import re
import salt.utils.http
import salt.utils.json
try:
import requests
HAS_LIBS = True
except ImportError:
HAS_LIBS = False
# Disable INFO level logs from requests/urllib3
urllib3_logger = logging.getLogger("urllib3")
urllib3_logger.setLevel(logging.WARNING)
log = logging.getLogger(__name__)
__virtualname__ = "zenoss"
@ -44,14 +32,7 @@ def __virtual__():
"""
Only load if requests is installed
"""
if HAS_LIBS:
return __virtualname__
else:
return (
False,
"The '{}' module could not be loaded: "
"'requests' is not installed.".format(__virtualname__),
)
return __virtualname__
ROUTERS = {
@ -75,11 +56,13 @@ def _session():
"""
config = __salt__["config.option"]("zenoss")
session = requests.session()
session.auth = (config.get("username"), config.get("password"))
session.verify = False
session.headers.update({"Content-type": "application/json; charset=utf-8"})
return session
return salt.utils.http.session(
user=config.get("username"),
password=config.get("password"),
verify_ssl=config.get("verify_ssl", True),
ca_bundle=config.get("ca_bundle"),
headers={"Content-type": "application/json; charset=utf-8"},
)
def _router_request(router, method, data=None):

View file

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""
Pillar data from vCenter or an ESXi host
@ -142,18 +141,12 @@ Optionally, the following keyword arguments can be passed to the ext_pillar for
part of the pillar regardless of this setting.
"""
from __future__ import absolute_import, print_function, unicode_literals
# Import python libs
import logging
# Import salt libs
import salt.utils.dictupdate as dictupdate
import salt.utils.vmware
# Import 3rd-party libs
from salt.ext import six
try:
# pylint: disable=no-name-in-module
from pyVmomi import vim
@ -370,7 +363,12 @@ def ext_pillar(minion_id, pillar, **kwargs): # pylint: disable=W0613
vmware_pillar[pillar_key] = {}
try:
_conn = salt.utils.vmware.get_service_instance(
host, username, password, protocol, port
host,
username,
password,
protocol,
port,
verify_ssl=kwargs.get("verify_ssl", True),
)
if _conn:
data = None
@ -410,12 +408,10 @@ def ext_pillar(minion_id, pillar, **kwargs): # pylint: disable=W0613
)
except RuntimeError:
log.error(
(
"A runtime error occurred in the vmware_pillar, "
"this is likely caused by an infinite recursion in "
"a requested attribute. Verify your requested attributes "
"and reconfigure the pillar."
)
"A runtime error occurred in the vmware_pillar, "
"this is likely caused by an infinite recursion in "
"a requested attribute. Verify your requested attributes "
"and reconfigure the pillar."
)
return vmware_pillar
@ -435,7 +431,7 @@ def _recurse_config_to_dict(t_data):
return t_list
elif isinstance(t_data, dict):
t_dict = {}
for k, v in six.iteritems(t_data):
for k, v in t_data.items():
t_dict[k] = _recurse_config_to_dict(v)
return t_dict
else:

View file

@ -39,6 +39,7 @@ the ID.
host: <ip or dns name of cimc host>
username: <cimc username>
password: <cimc password>
verify_ssl: True
proxytype
^^^^^^^^^
@ -129,6 +130,10 @@ def init(opts):
DETAILS["host"] = opts["proxy"]["host"]
DETAILS["username"] = opts["proxy"].get("username")
DETAILS["password"] = opts["proxy"].get("password")
verify_ssl = opts["proxy"].get("verify_ssl")
if verify_ssl is None:
verify_ssl = True
DETAILS["verify_ssl"] = verify_ssl
# Ensure connectivity to the device
log.debug("Attempting to connect to cimc proxy host.")
@ -160,7 +165,7 @@ def set_config_modify(dn=None, inconfig=None, hierarchical=False):
method="POST",
decode_type="plain",
decode=True,
verify_ssl=False,
verify_ssl=DETAILS["verify_ssl"],
raise_error=True,
status=True,
headers=DETAILS["headers"],
@ -197,7 +202,7 @@ def get_config_resolver_class(cid=None, hierarchical=False):
method="POST",
decode_type="plain",
decode=True,
verify_ssl=False,
verify_ssl=DETAILS["verify_ssl"],
raise_error=True,
status=True,
headers=DETAILS["headers"],
@ -228,7 +233,7 @@ def logon():
method="POST",
decode_type="plain",
decode=True,
verify_ssl=False,
verify_ssl=DETAILS["verify_ssl"],
raise_error=False,
status=True,
headers=DETAILS["headers"],
@ -258,7 +263,7 @@ def logout(cookie=None):
method="POST",
decode_type="plain",
decode=True,
verify_ssl=False,
verify_ssl=DETAILS["verify_ssl"],
raise_error=True,
headers=DETAILS["headers"],
)

View file

@ -52,6 +52,7 @@ the device with username and password.
host: <ip or dns name of panos host>
username: <panos username>
password: <panos password>
verify_ssl: True
proxytype
^^^^^^^^^
@ -267,6 +268,7 @@ def init(opts):
# Set configuration details
DETAILS["host"] = opts["proxy"]["host"]
DETAILS["verify_ssl"] = opts["proxy"].get("verify_ssl", True)
if "serial" in opts["proxy"]:
DETAILS["serial"] = opts["proxy"].get("serial")
if "apikey" in opts["proxy"]:
@ -314,7 +316,7 @@ def call(payload=None):
method="POST",
decode_type="plain",
decode=True,
verify_ssl=False,
verify_ssl=DETAILS["verify_ssl"],
status=True,
raise_error=True,
)
@ -328,7 +330,7 @@ def call(payload=None):
method="POST",
decode_type="plain",
decode=True,
verify_ssl=False,
verify_ssl=DETAILS["verify_ssl"],
status=True,
raise_error=True,
)
@ -345,7 +347,7 @@ def call(payload=None):
method="POST",
decode_type="plain",
decode=True,
verify_ssl=False,
verify_ssl=DETAILS["verify_ssl"],
status=True,
raise_error=True,
)
@ -361,7 +363,7 @@ def call(payload=None):
method="POST",
decode_type="plain",
decode=True,
verify_ssl=False,
verify_ssl=DETAILS["verify_ssl"],
status=True,
raise_error=True,
)

View file

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""
Proxy Minion interface module for managing VMWare vCenters.
@ -182,13 +181,9 @@ and that host would reach out over the network and communicate with the ESXi
host.
"""
# Import Python Libs
from __future__ import absolute_import, print_function, unicode_literals
import logging
import os
# Import Salt Libs
import salt.exceptions
from salt.config.schemas.vcenter import VCenterProxySchema
from salt.utils.dictupdate import merge
@ -277,6 +272,8 @@ def init(opts):
# Save optional
DETAILS["protocol"] = proxy_conf.get("protocol")
DETAILS["port"] = proxy_conf.get("port")
DETAILS["verify_ssl"] = proxy_conf.get("verify_ssl")
DETAILS["ca_bundle"] = proxy_conf.get("ca_bundle")
# Test connection
if DETAILS["mechanism"] == "userpass":

View file

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""
Send json response data to Splunk via the HTTP Event Collector
@ -11,29 +10,22 @@ Requires the following config values to be specified in config or pillar:
indexer: <hostname/IP of Splunk indexer>
sourcetype: <Destination sourcetype for data>
index: <Destination index for data>
verify_ssl: true
Run a test by using ``salt-call test.ping --return splunk``
Written by Scott Pack (github.com/scottjpack)
"""
# Import Python libs
from __future__ import absolute_import, print_function, unicode_literals
import logging
import socket
import time
import requests
# Import salt libs
import salt.utils.json
# Import 3rd-party libs
from salt.ext import six
_max_content_bytes = 100000
http_event_collector_SSL_verify = False
http_event_collector_debug = False
log = logging.getLogger(__name__)
@ -62,6 +54,9 @@ def _get_options():
indexer = __salt__["config.get"]("splunk_http_forwarder:indexer")
sourcetype = __salt__["config.get"]("splunk_http_forwarder:sourcetype")
index = __salt__["config.get"]("splunk_http_forwarder:index")
verify_ssl = __salt__["config.get"](
"splunk_http_forwarder:verify_ssl", default=True
)
except Exception: # pylint: disable=broad-except
log.error("Splunk HTTP Forwarder parameters not present in config.")
return None
@ -70,6 +65,7 @@ def _get_options():
"indexer": indexer,
"sourcetype": sourcetype,
"index": index,
"verify_ssl": verify_ssl,
}
return splunk_opts
@ -84,14 +80,16 @@ def _send_splunk(event, index_override=None, sourcetype_override=None):
# Get Splunk Options
opts = _get_options()
log.info(
str("Options: %s"), # future lint: disable=blacklisted-function
salt.utils.json.dumps(opts),
"Options: %s", salt.utils.json.dumps(opts),
)
http_event_collector_key = opts["token"]
http_event_collector_host = opts["indexer"]
http_event_collector_verify_ssl = opts["verify_ssl"]
# Set up the collector
splunk_event = http_event_collector(
http_event_collector_key, http_event_collector_host
http_event_collector_key,
http_event_collector_host,
verify_ssl=http_event_collector_verify_ssl,
)
# init the payload
payload = {}
@ -109,8 +107,7 @@ def _send_splunk(event, index_override=None, sourcetype_override=None):
# Add the event
payload.update({"event": event})
log.info(
str("Payload: %s"), # future lint: disable=blacklisted-function
salt.utils.json.dumps(payload),
"Payload: %s", salt.utils.json.dumps(payload),
)
# Fire it off
splunk_event.sendEvent(payload)
@ -120,7 +117,7 @@ def _send_splunk(event, index_override=None, sourcetype_override=None):
# Thanks to George Starcher for the http_event_collector class (https://github.com/georgestarcher/)
class http_event_collector(object):
class http_event_collector:
def __init__(
self,
token,
@ -129,11 +126,13 @@ class http_event_collector(object):
http_event_port="8088",
http_event_server_ssl=True,
max_bytes=_max_content_bytes,
verify_ssl=True,
):
self.token = token
self.batchEvents = []
self.maxByteLength = max_bytes
self.currentByteLength = 0
self.verify_ssl = verify_ssl
# Set host to specified value or default to localhostname if no value provided
if host:
@ -164,7 +163,7 @@ class http_event_collector(object):
# If eventtime in epoch not passed as optional argument use current system time in epoch
if not eventtime:
eventtime = six.text_type(int(time.time()))
eventtime = str(int(time.time()))
# Fill in local hostname if not manually populated
if "host" not in payload:
@ -179,7 +178,7 @@ class http_event_collector(object):
self.server_uri,
data=salt.utils.json.dumps(data),
headers=headers,
verify=http_event_collector_SSL_verify,
verify=self.verify_ssl,
)
# Print debug info if flag set
@ -207,7 +206,7 @@ class http_event_collector(object):
# If eventtime in epoch not passed as optional argument use current system time in epoch
if not eventtime:
eventtime = six.text_type(int(time.time()))
eventtime = str(int(time.time()))
# Update time value on payload if need to use system time
data = {"time": eventtime}
@ -224,7 +223,7 @@ class http_event_collector(object):
self.server_uri,
data=" ".join(self.batchEvents),
headers=headers,
verify=http_event_collector_SSL_verify,
verify=self.verify_ssl,
)
self.batchEvents = []
self.currentByteLength = 0

View file

@ -2,7 +2,6 @@
Execute salt convenience routines
"""
import logging
import os
@ -279,7 +278,7 @@ class Runner(RunnerClient):
outputter = None
display_output(ret, outputter, self.opts)
else:
ret = self._proc_function(
ret = self._proc_function_local(
self.opts["fun"],
low,
user,

View file

@ -17,9 +17,11 @@ master configuration at ``/etc/salt/master`` or ``/etc/salt/master.d/asam.conf``
prov1.domain.com
username: "testuser"
password: "verybadpass"
verify_ssl: true
prov2.domain.com
username: "testuser"
password: "verybadpass"
verify_ssl: true
.. note::
@ -84,6 +86,10 @@ def _get_asam_configuration(driver_url=""):
password = service_config.get("password", None)
protocol = service_config.get("protocol", "https")
port = service_config.get("port", 3451)
verify_ssl = service_config.get("verify_ssl")
if verify_ssl is None:
verify_ssl = True
if not username or not password:
log.error(
@ -108,6 +114,7 @@ def _get_asam_configuration(driver_url=""):
),
"username": username,
"password": password,
"verify_ssl": verify_ssl,
}
if (not driver_url) or (driver_url == asam_server):
@ -206,7 +213,7 @@ def remove_platform(name, server_url):
auth = (config["username"], config["password"])
try:
html_content = _make_post_request(url, data, auth, verify=False)
html_content = _make_post_request(url, data, auth, verify=config["verify_ssl"])
except Exception as exc: # pylint: disable=broad-except
err_msg = "Failed to look up existing platforms on {}".format(server_url)
log.error("%s:\n%s", err_msg, exc)
@ -222,7 +229,9 @@ def remove_platform(name, server_url):
data["postType"] = "platformRemove"
data["Submit"] = "Yes"
try:
html_content = _make_post_request(url, data, auth, verify=False)
html_content = _make_post_request(
url, data, auth, verify=config["verify_ssl"]
)
except Exception as exc: # pylint: disable=broad-except
err_msg = "Failed to delete platform from {}".format(server_url)
log.error("%s:\n%s", err_msg, exc)
@ -261,7 +270,7 @@ def list_platforms(server_url):
auth = (config["username"], config["password"])
try:
html_content = _make_post_request(url, data, auth, verify=False)
html_content = _make_post_request(url, data, auth, verify=config["verify_ssl"])
except Exception as exc: # pylint: disable=broad-except
err_msg = "Failed to look up existing platforms"
log.error("%s:\n%s", err_msg, exc)
@ -299,7 +308,7 @@ def list_platform_sets(server_url):
auth = (config["username"], config["password"])
try:
html_content = _make_post_request(url, data, auth, verify=False)
html_content = _make_post_request(url, data, auth, verify=config["verify_ssl"])
except Exception as exc: # pylint: disable=broad-except
err_msg = "Failed to look up existing platform sets"
log.error("%s:\n%s", err_msg, exc)
@ -351,7 +360,7 @@ def add_platform(name, platform_set, server_url):
auth = (config["username"], config["password"])
try:
html_content = _make_post_request(url, data, auth, verify=False)
html_content = _make_post_request(url, data, auth, verify=config["verify_ssl"])
except Exception as exc: # pylint: disable=broad-except
err_msg = "Failed to add platform on {}".format(server_url)
log.error("%s:\n%s", err_msg, exc)

View file

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""
Manage VMware ESXi Hosts.
@ -91,8 +90,6 @@ configuration examples, dependency installation instructions, how to run remote
execution functions against ESXi hosts via a Salt Proxy Minion, and a larger state
example.
"""
# Import Python Libs
from __future__ import absolute_import, print_function, unicode_literals
import logging
import re
@ -108,9 +105,6 @@ from salt.exceptions import (
VMwareObjectRetrievalError,
VMwareSaltError,
)
# Import Salt Libs
from salt.ext import six
from salt.utils.decorators import depends
# External libraries
@ -201,7 +195,7 @@ def coredump_configured(name, enabled, dump_ip, host_vnic="vmk0", dump_port=6500
current_config = __salt__[esxi_cmd]("get_coredump_network_config").get(host)
error = current_config.get("Error")
if error:
ret["comment"] = "Error: {0}".format(error)
ret["comment"] = "Error: {}".format(error)
return ret
current_config = current_config.get("Coredump Config")
@ -217,7 +211,7 @@ def coredump_configured(name, enabled, dump_ip, host_vnic="vmk0", dump_port=6500
).get(host)
error = response.get("Error")
if error:
ret["comment"] = "Error: {0}".format(error)
ret["comment"] = "Error: {}".format(error)
return ret
# Allow users to disable core dump, but then return since
@ -252,9 +246,9 @@ def coredump_configured(name, enabled, dump_ip, host_vnic="vmk0", dump_port=6500
changes = True
current_port = current_config.get("port")
if current_port != six.text_type(dump_port):
if current_port != str(dump_port):
ret["changes"].update(
{"dump_port": {"old": current_port, "new": six.text_type(dump_port)}}
{"dump_port": {"old": current_port, "new": str(dump_port)}}
)
changes = True
@ -270,7 +264,7 @@ def coredump_configured(name, enabled, dump_ip, host_vnic="vmk0", dump_port=6500
msg = response.get("stderr")
if not msg:
msg = response.get("stdout")
ret["comment"] = "Error: {0}".format(msg)
ret["comment"] = "Error: {}".format(msg)
return ret
ret["result"] = True
@ -328,7 +322,7 @@ def password_present(name, password):
__salt__[esxi_cmd]("update_host_password", new_password=password)
except CommandExecutionError as err:
ret["result"] = False
ret["comment"] = "Error: {0}".format(err)
ret["comment"] = "Error: {}".format(err)
return ret
return ret
@ -400,7 +394,7 @@ def ntp_configured(
ntp_running = __salt__[esxi_cmd]("get_service_running", service_name=ntpd).get(host)
error = ntp_running.get("Error")
if error:
ret["comment"] = "Error: {0}".format(error)
ret["comment"] = "Error: {}".format(error)
return ret
ntp_running = ntp_running.get(ntpd)
@ -413,7 +407,7 @@ def ntp_configured(
).get(host)
error = response.get("Error")
if error:
ret["comment"] = "Error: {0}".format(error)
ret["comment"] = "Error: {}".format(error)
return ret
# Set changes dictionary for ntp_servers
ret["changes"].update({"ntp_servers": {"old": ntp_config, "new": ntp_servers}})
@ -429,7 +423,7 @@ def ntp_configured(
)
error = response.get("Error")
if error:
ret["comment"] = "Error: {0}".format(error)
ret["comment"] = "Error: {}".format(error)
return ret
# Stop ntpd if service_running=False
else:
@ -438,7 +432,7 @@ def ntp_configured(
)
error = response.get("Error")
if error:
ret["comment"] = "Error: {0}".format(error)
ret["comment"] = "Error: {}".format(error)
return ret
ret["changes"].update(
{"service_running": {"old": ntp_running, "new": service_running}}
@ -451,7 +445,7 @@ def ntp_configured(
).get(host)
error = current_service_policy.get("Error")
if error:
ret["comment"] = "Error: {0}".format(error)
ret["comment"] = "Error: {}".format(error)
return ret
current_service_policy = current_service_policy.get(ntpd)
@ -465,7 +459,7 @@ def ntp_configured(
).get(host)
error = response.get("Error")
if error:
ret["comment"] = "Error: {0}".format(error)
ret["comment"] = "Error: {}".format(error)
return ret
ret["changes"].update(
{
@ -483,7 +477,7 @@ def ntp_configured(
response = __salt__[esxi_cmd]("update_host_datetime").get(host)
error = response.get("Error")
if error:
ret["comment"] = "Error: {0}".format(error)
ret["comment"] = "Error: {}".format(error)
return ret
ret["changes"].update(
{"update_datetime": {"old": "", "new": "Host datetime was updated."}}
@ -498,7 +492,7 @@ def ntp_configured(
)
error = response.get("Error")
if error:
ret["comment"] = "Error: {0}".format(error)
ret["comment"] = "Error: {}".format(error)
return ret
ret["changes"].update(
{"service_restart": {"old": "", "new": "NTP Daemon Restarted."}}
@ -559,14 +553,14 @@ def vmotion_configured(name, enabled, device="vmk0"):
response = __salt__[esxi_cmd]("vmotion_enable", device=device).get(host)
error = response.get("Error")
if error:
ret["comment"] = "Error: {0}".format(error)
ret["comment"] = "Error: {}".format(error)
return ret
# Disable VMotion if enabled=False
else:
response = __salt__[esxi_cmd]("vmotion_disable").get(host)
error = response.get("Error")
if error:
ret["comment"] = "Error: {0}".format(error)
ret["comment"] = "Error: {}".format(error)
return ret
ret["changes"].update(
{"enabled": {"old": current_vmotion_enabled, "new": enabled}}
@ -618,7 +612,7 @@ def vsan_configured(name, enabled, add_disks_to_vsan=False):
current_vsan_enabled = __salt__[esxi_cmd]("get_vsan_enabled").get(host)
error = current_vsan_enabled.get("Error")
if error:
ret["comment"] = "Error: {0}".format(error)
ret["comment"] = "Error: {}".format(error)
return ret
current_vsan_enabled = current_vsan_enabled.get("VSAN Enabled")
@ -631,14 +625,14 @@ def vsan_configured(name, enabled, add_disks_to_vsan=False):
response = __salt__[esxi_cmd]("vsan_enable").get(host)
error = response.get("Error")
if error:
ret["comment"] = "Error: {0}".format(error)
ret["comment"] = "Error: {}".format(error)
return ret
# Disable VSAN if enabled=False
else:
response = __salt__[esxi_cmd]("vsan_disable").get(host)
error = response.get("Error")
if error:
ret["comment"] = "Error: {0}".format(error)
ret["comment"] = "Error: {}".format(error)
return ret
ret["changes"].update(
{"enabled": {"old": current_vsan_enabled, "new": enabled}}
@ -649,7 +643,7 @@ def vsan_configured(name, enabled, add_disks_to_vsan=False):
current_eligible_disks = __salt__[esxi_cmd]("get_vsan_eligible_disks").get(host)
error = current_eligible_disks.get("Error")
if error:
ret["comment"] = "Error: {0}".format(error)
ret["comment"] = "Error: {}".format(error)
return ret
disks = current_eligible_disks.get("Eligible")
@ -659,7 +653,7 @@ def vsan_configured(name, enabled, add_disks_to_vsan=False):
response = __salt__[esxi_cmd]("vsan_add_disks").get(host)
error = response.get("Error")
if error:
ret["comment"] = "Error: {0}".format(error)
ret["comment"] = "Error: {}".format(error)
return ret
ret["changes"].update({"add_disks_to_vsan": {"old": "", "new": disks}})
@ -683,7 +677,7 @@ def ssh_configured(
ssh_key_file=None,
service_policy=None,
service_restart=False,
certificate_verify=False,
certificate_verify=None,
):
"""
Manage the SSH configuration for a host including whether or not SSH is running or
@ -724,7 +718,7 @@ def ssh_configured(
certificate_verify
If set to ``True``, the SSL connection must present a valid certificate.
Default is ``False``.
Default is ``True``.
Example:
@ -739,6 +733,8 @@ def ssh_configured(
- certificate_verify: True
"""
if certificate_verify is None:
certificate_verify = True
ret = {"name": name, "result": False, "changes": {}, "comment": ""}
esxi_cmd = "esxi.cmd"
host = __pillar__["proxy"]["host"]
@ -747,7 +743,7 @@ def ssh_configured(
ssh_running = __salt__[esxi_cmd]("get_service_running", service_name=ssh).get(host)
error = ssh_running.get("Error")
if error:
ret["comment"] = "Error: {0}".format(error)
ret["comment"] = "Error: {}".format(error)
return ret
ssh_running = ssh_running.get(ssh)
@ -760,14 +756,14 @@ def ssh_configured(
enable = __salt__[esxi_cmd]("service_start", service_name=ssh).get(host)
error = enable.get("Error")
if error:
ret["comment"] = "Error: {0}".format(error)
ret["comment"] = "Error: {}".format(error)
return ret
# Disable SSH if service_running=False
else:
disable = __salt__[esxi_cmd]("service_stop", service_name=ssh).get(host)
error = disable.get("Error")
if error:
ret["comment"] = "Error: {0}".format(error)
ret["comment"] = "Error: {}".format(error)
return ret
ret["changes"].update(
@ -783,7 +779,7 @@ def ssh_configured(
)
error = current_ssh_key.get("Error")
if error:
ret["comment"] = "Error: {0}".format(error)
ret["comment"] = "Error: {}".format(error)
return ret
current_ssh_key = current_ssh_key.get("key")
if current_ssh_key:
@ -822,7 +818,7 @@ def ssh_configured(
)
error = response.get("Error")
if error:
ret["comment"] = "Error: {0}".format(error)
ret["comment"] = "Error: {}".format(error)
return ret
ret["changes"].update(
{
@ -840,7 +836,7 @@ def ssh_configured(
).get(host)
error = current_service_policy.get("Error")
if error:
ret["comment"] = "Error: {0}".format(error)
ret["comment"] = "Error: {}".format(error)
return ret
current_service_policy = current_service_policy.get(ssh)
@ -854,7 +850,7 @@ def ssh_configured(
).get(host)
error = response.get("Error")
if error:
ret["comment"] = "Error: {0}".format(error)
ret["comment"] = "Error: {}".format(error)
return ret
ret["changes"].update(
{
@ -872,7 +868,7 @@ def ssh_configured(
response = __salt__[esxi_cmd]("service_restart", service_name=ssh).get(host)
error = response.get("Error")
if error:
ret["comment"] = "Error: {0}".format(error)
ret["comment"] = "Error: {}".format(error)
return ret
ret["changes"].update(
{"service_restart": {"old": "", "new": "SSH service restarted."}}
@ -965,17 +961,17 @@ def syslog_configured(
reset = __salt__[esxi_cmd](
"reset_syslog_config", syslog_config=reset_configs
).get(host)
for key, val in six.iteritems(reset):
for key, val in reset.items():
if isinstance(val, bool):
continue
if not val.get("success"):
msg = val.get("message")
if not msg:
msg = (
"There was an error resetting a syslog config '{0}'."
"There was an error resetting a syslog config '{}'."
"Please check debug logs.".format(val)
)
ret["comment"] = "Error: {0}".format(msg)
ret["comment"] = "Error: {}".format(msg)
return ret
ret["changes"].update(
@ -985,7 +981,7 @@ def syslog_configured(
current_firewall = __salt__[esxi_cmd]("get_firewall_status").get(host)
error = current_firewall.get("Error")
if error:
ret["comment"] = "Error: {0}".format(error)
ret["comment"] = "Error: {}".format(error)
return ret
current_firewall = current_firewall.get("rulesets").get("syslog")
@ -1000,23 +996,23 @@ def syslog_configured(
if enabled.get("retcode") != 0:
err = enabled.get("stderr")
out = enabled.get("stdout")
ret["comment"] = "Error: {0}".format(err if err else out)
ret["comment"] = "Error: {}".format(err if err else out)
return ret
ret["changes"].update({"firewall": {"old": current_firewall, "new": firewall}})
current_syslog_config = __salt__[esxi_cmd]("get_syslog_config").get(host)
for key, val in six.iteritems(syslog_configs):
for key, val in syslog_configs.items():
# The output of get_syslog_config has different keys than the keys
# Used to set syslog_config values. We need to look them up first.
try:
lookup_key = _lookup_syslog_config(key)
except KeyError:
ret["comment"] = "'{0}' is not a valid config variable.".format(key)
ret["comment"] = "'{}' is not a valid config variable.".format(key)
return ret
current_val = current_syslog_config[lookup_key]
if six.text_type(current_val) != six.text_type(val):
if str(current_val) != str(val):
# Only run the command if not using test=True
if not __opts__["test"]:
response = __salt__[esxi_cmd](
@ -1031,7 +1027,7 @@ def syslog_configured(
msg = response.get(key).get("message")
if not msg:
msg = (
"There was an error setting syslog config '{0}'. "
"There was an error setting syslog config '{}'. "
"Please check debug logs.".format(key)
)
ret["comment"] = msg
@ -1101,7 +1097,7 @@ def diskgroups_configured(name, diskgroups, erase_disks=False):
if not proxy_details.get("vcenter")
else proxy_details["esxi_host"]
)
log.info("Running state {0} for host '{1}'".format(name, hostname))
log.info("Running state %s for host '%s'", name, hostname)
# Variable used to return the result of the invocation
ret = {"name": name, "result": None, "changes": {}, "comments": None}
# Signals if errors have been encountered
@ -1124,23 +1120,20 @@ def diskgroups_configured(name, diskgroups, erase_disks=False):
host_disks = __salt__["vsphere.list_disks"](service_instance=si)
if not host_disks:
raise VMwareObjectRetrievalError(
"No disks retrieved from host '{0}'".format(hostname)
"No disks retrieved from host '{}'".format(hostname)
)
scsi_addr_to_disk_map = {d["scsi_address"]: d for d in host_disks}
log.trace("scsi_addr_to_disk_map = {0}".format(scsi_addr_to_disk_map))
log.trace("scsi_addr_to_disk_map = %s", scsi_addr_to_disk_map)
existing_diskgroups = __salt__["vsphere.list_diskgroups"](service_instance=si)
cache_disk_to_existing_diskgroup_map = {
dg["cache_disk"]: dg for dg in existing_diskgroups
}
except CommandExecutionError as err:
log.error("Error: {0}".format(err))
log.error("Error: %s", err)
if si:
__salt__["vsphere.disconnect"](si)
ret.update(
{
"result": False if not __opts__["test"] else None,
"comment": six.text_type(err),
}
{"result": False if not __opts__["test"] else None, "comment": str(err)}
)
return ret
@ -1149,8 +1142,9 @@ def diskgroups_configured(name, diskgroups, erase_disks=False):
# Check for cache disk
if not dg["cache_scsi_addr"] in scsi_addr_to_disk_map:
comments.append(
"No cache disk with scsi address '{0}' was "
"found.".format(dg["cache_scsi_addr"])
"No cache disk with scsi address '{}' was found.".format(
dg["cache_scsi_addr"]
)
)
log.error(comments[-1])
errors = True
@ -1158,7 +1152,7 @@ def diskgroups_configured(name, diskgroups, erase_disks=False):
# Check for capacity disks
cache_disk_id = scsi_addr_to_disk_map[dg["cache_scsi_addr"]]["id"]
cache_disk_display = "{0} (id:{1})".format(dg["cache_scsi_addr"], cache_disk_id)
cache_disk_display = "{} (id:{})".format(dg["cache_scsi_addr"], cache_disk_id)
bad_scsi_addrs = []
capacity_disk_ids = []
capacity_disk_displays = []
@ -1168,13 +1162,14 @@ def diskgroups_configured(name, diskgroups, erase_disks=False):
continue
capacity_disk_ids.append(scsi_addr_to_disk_map[scsi_addr]["id"])
capacity_disk_displays.append(
"{0} (id:{1})".format(scsi_addr, capacity_disk_ids[-1])
"{} (id:{})".format(scsi_addr, capacity_disk_ids[-1])
)
if bad_scsi_addrs:
comments.append(
"Error in diskgroup #{0}: capacity disks with "
"scsi addresses {1} were not found."
"".format(idx, ", ".join(["'{0}'".format(a) for a in bad_scsi_addrs]))
"Error in diskgroup #{}: capacity disks with scsi addresses {} "
"were not found.".format(
idx, ", ".join(["'{}'".format(a) for a in bad_scsi_addrs])
)
)
log.error(comments[-1])
errors = True
@ -1182,14 +1177,14 @@ def diskgroups_configured(name, diskgroups, erase_disks=False):
if not cache_disk_to_existing_diskgroup_map.get(cache_disk_id):
# A new diskgroup needs to be created
log.trace("erase_disks = {0}".format(erase_disks))
log.trace("erase_disks = %s", erase_disks)
if erase_disks:
if __opts__["test"]:
comments.append(
"State {0} will "
"erase all disks of disk group #{1}; "
"cache disk: '{2}', "
"capacity disk(s): {3}."
"State {} will "
"erase all disks of disk group #{}; "
"cache disk: '{}', "
"capacity disk(s): {}."
"".format(
name,
idx,
@ -1206,13 +1201,13 @@ def diskgroups_configured(name, diskgroups, erase_disks=False):
disk_id=disk_id, service_instance=si
)
comments.append(
"Erased disks of diskgroup #{0}; "
"cache disk: '{1}', capacity disk(s): "
"{2}".format(
"Erased disks of diskgroup #{}; "
"cache disk: '{}', capacity disk(s): "
"{}".format(
idx,
cache_disk_display,
", ".join(
["'{0}'".format(a) for a in capacity_disk_displays]
["'{}'".format(a) for a in capacity_disk_displays]
),
)
)
@ -1220,13 +1215,13 @@ def diskgroups_configured(name, diskgroups, erase_disks=False):
if __opts__["test"]:
comments.append(
"State {0} will create "
"the disk group #{1}; cache disk: '{2}', "
"capacity disk(s): {3}.".format(
"State {} will create "
"the disk group #{}; cache disk: '{}', "
"capacity disk(s): {}.".format(
name,
idx,
cache_disk_display,
", ".join(["'{0}'".format(a) for a in capacity_disk_displays]),
", ".join(["'{}'".format(a) for a in capacity_disk_displays]),
)
)
log.info(comments[-1])
@ -1240,16 +1235,14 @@ def diskgroups_configured(name, diskgroups, erase_disks=False):
service_instance=si,
)
except VMwareSaltError as err:
comments.append(
"Error creating disk group #{0}: " "{1}.".format(idx, err)
)
comments.append("Error creating disk group #{}: {}.".format(idx, err))
log.error(comments[-1])
errors = True
continue
comments.append("Created disk group #'{0}'.".format(idx))
comments.append("Created disk group #'{}'.".format(idx))
log.info(comments[-1])
diskgroup_changes[six.text_type(idx)] = {
diskgroup_changes[str(idx)] = {
"new": {"cache": cache_disk_display, "capacity": capacity_disk_displays}
}
changes = True
@ -1257,12 +1250,13 @@ def diskgroups_configured(name, diskgroups, erase_disks=False):
# The diskgroup exists; checking the capacity disks
log.debug(
"Disk group #{0} exists. Checking capacity disks: "
"{1}.".format(idx, capacity_disk_displays)
"Disk group #%s exists. Checking capacity disks: %s.",
idx,
capacity_disk_displays,
)
existing_diskgroup = cache_disk_to_existing_diskgroup_map.get(cache_disk_id)
existing_capacity_disk_displays = [
"{0} (id:{1})".format(
"{} (id:{})".format(
[d["scsi_address"] for d in host_disks if d["id"] == disk_id][0],
disk_id,
)
@ -1280,7 +1274,7 @@ def diskgroups_configured(name, diskgroups, erase_disks=False):
][0]
added_capacity_disk_ids.append(disk_id)
added_capacity_disk_displays.append(
"{0} (id:{1})".format(disk_scsi_addr, disk_id)
"{} (id:{})".format(disk_scsi_addr, disk_id)
)
for disk_id in existing_diskgroup["capacity_disks"]:
if disk_id not in capacity_disk_ids:
@ -1289,28 +1283,26 @@ def diskgroups_configured(name, diskgroups, erase_disks=False):
][0]
removed_capacity_disk_ids.append(disk_id)
removed_capacity_disk_displays.append(
"{0} (id:{1})".format(disk_scsi_addr, disk_id)
"{} (id:{})".format(disk_scsi_addr, disk_id)
)
log.debug(
"Disk group #{0}: existing capacity disk ids: {1}; added "
"capacity disk ids: {2}; removed capacity disk ids: {3}"
"".format(
idx,
existing_capacity_disk_displays,
added_capacity_disk_displays,
removed_capacity_disk_displays,
)
"Disk group #%s: existing capacity disk ids: %s; added "
"capacity disk ids: %s; removed capacity disk ids: %s",
idx,
existing_capacity_disk_displays,
added_capacity_disk_displays,
removed_capacity_disk_displays,
)
# TODO revisit this when removing capacity disks is supported
if removed_capacity_disk_ids:
comments.append(
"Error removing capacity disk(s) {0} from disk group #{1}; "
"Error removing capacity disk(s) {} from disk group #{}; "
"operation is not supported."
"".format(
", ".join(
["'{0}'".format(id) for id in removed_capacity_disk_displays]
["'{}'".format(id) for id in removed_capacity_disk_displays]
),
idx,
)
@ -1324,11 +1316,11 @@ def diskgroups_configured(name, diskgroups, erase_disks=False):
# Building a string representation of the capacity disks
# that need to be added
s = ", ".join(["'{0}'".format(id) for id in added_capacity_disk_displays])
s = ", ".join(["'{}'".format(id) for id in added_capacity_disk_displays])
if __opts__["test"]:
comments.append(
"State {0} will add "
"capacity disk(s) {1} to disk group #{2}."
"State {} will add "
"capacity disk(s) {} to disk group #{}."
"".format(name, s, idx)
)
log.info(comments[-1])
@ -1343,17 +1335,17 @@ def diskgroups_configured(name, diskgroups, erase_disks=False):
)
except VMwareSaltError as err:
comments.append(
"Error adding capacity disk(s) {0} to "
"disk group #{1}: {2}.".format(s, idx, err)
"Error adding capacity disk(s) {} to "
"disk group #{}: {}.".format(s, idx, err)
)
log.error(comments[-1])
errors = True
continue
com = "Added capacity disk(s) {0} to disk group #{1}" "".format(s, idx)
com = "Added capacity disk(s) {} to disk group #{}" "".format(s, idx)
log.info(com)
comments.append(com)
diskgroup_changes[six.text_type(idx)] = {
diskgroup_changes[str(idx)] = {
"new": {
"cache": cache_disk_display,
"capacity": capacity_disk_displays,
@ -1367,9 +1359,7 @@ def diskgroups_configured(name, diskgroups, erase_disks=False):
continue
# No capacity needs to be added
s = "Disk group #{0} is correctly configured. Nothing to be done." "".format(
idx
)
s = "Disk group #{} is correctly configured. Nothing to be done." "".format(idx)
log.info(s)
comments.append(s)
__salt__["vsphere.disconnect"](si)
@ -1532,11 +1522,11 @@ def host_cache_configured(
)
if not existing_disks:
raise VMwareObjectRetrievalError(
"Disk with scsi address '{0}' was not found in host '{1}'"
"Disk with scsi address '{}' was not found in host '{}'"
"".format(datastore["backing_disk_scsi_addr"], hostname)
)
backing_disk = existing_disks[0]
backing_disk_display = "{0} (id:{1})".format(
backing_disk_display = "{} (id:{})".format(
backing_disk["scsi_address"], backing_disk["id"]
)
log.trace("backing_disk = %s", backing_disk_display)
@ -1547,9 +1537,9 @@ def host_cache_configured(
if erase_backing_disk:
if __opts__["test"]:
comments.append(
"State {0} will erase "
"the backing disk '{1}' on host '{2}'."
"".format(name, backing_disk_display, hostname)
"State {} will erase the backing disk '{}' on host '{}'.".format(
name, backing_disk_display, hostname
)
)
log.info(comments[-1])
else:
@ -1558,17 +1548,18 @@ def host_cache_configured(
disk_id=backing_disk["id"], service_instance=si
)
comments.append(
"Erased backing disk '{0}' on host "
"'{1}'.".format(backing_disk_display, hostname)
"Erased backing disk '{}' on host '{}'.".format(
backing_disk_display, hostname
)
)
log.info(comments[-1])
# Create the datastore
if __opts__["test"]:
comments.append(
"State {0} will create "
"the datastore '{1}', with backing disk "
"'{2}', on host '{3}'."
"".format(name, datastore["name"], backing_disk_display, hostname)
"State {} will create the datastore '{}', with backing disk "
"'{}', on host '{}'.".format(
name, datastore["name"], backing_disk_display, hostname
)
)
log.info(comments[-1])
else:
@ -1582,8 +1573,9 @@ def host_cache_configured(
non_mbr_partitions = [p for p in partitions if p["format"] != "mbr"]
if len(non_mbr_partitions) > 0:
raise VMwareApiError(
"Backing disk '{0}' has unexpected partitions"
"".format(backing_disk_display)
"Backing disk '{}' has unexpected partitions".format(
backing_disk_display
)
)
__salt__["vsphere.create_vmfs_datastore"](
datastore["name"],
@ -1592,9 +1584,10 @@ def host_cache_configured(
service_instance=si,
)
comments.append(
"Created vmfs datastore '{0}', backed by "
"disk '{1}', on host '{2}'."
"".format(datastore["name"], backing_disk_display, hostname)
"Created vmfs datastore '{}', backed by "
"disk '{}', on host '{}'.".format(
datastore["name"], backing_disk_display, hostname
)
)
log.info(comments[-1])
changes.update(
@ -1615,21 +1608,20 @@ def host_cache_configured(
# Check datastore is backed by the correct disk
if not existing_datastores[0].get("backing_disk_ids"):
raise VMwareSaltError(
"Datastore '{0}' doesn't have a "
"backing disk"
"".format(datastore["name"])
"Datastore '{}' doesn't have a backing disk".format(
datastore["name"]
)
)
if backing_disk["id"] not in existing_datastores[0]["backing_disk_ids"]:
raise VMwareSaltError(
"Datastore '{0}' is not backed by the correct disk: "
"expected '{1}'; got {2}"
"".format(
"Datastore '{}' is not backed by the correct disk: "
"expected '{}'; got {}".format(
datastore["name"],
backing_disk["id"],
", ".join(
[
"'{0}'".format(disk)
"'{}'".format(disk)
for disk in existing_datastores[0]["backing_disk_ids"]
]
),
@ -1637,8 +1629,8 @@ def host_cache_configured(
)
comments.append(
"Datastore '{0}' already exists on host '{1}' "
"and is backed by disk '{2}'. Nothing to be "
"Datastore '{}' already exists on host '{}' "
"and is backed by disk '{}'. Nothing to be "
"done.".format(datastore["name"], hostname, backing_disk_display)
)
existing_datastore = existing_datastores[0]
@ -1686,9 +1678,7 @@ def host_cache_configured(
if needs_setting:
if __opts__["test"]:
comments.append(
"State {0} will configure "
"the host cache on host '{1}' to: {2}."
"".format(
"State {} will configure the host cache on host '{}' to: {}.".format(
name,
hostname,
{
@ -1702,9 +1692,8 @@ def host_cache_configured(
if (existing_datastore["capacity"] / 1024.0 ** 2) < swap_size_MiB:
raise ArgumentValueError(
"Capacity of host cache datastore '{0}' ({1} MiB) is "
"smaller than the required swap size ({2} MiB)"
"".format(
"Capacity of host cache datastore '{}' ({} MiB) is "
"smaller than the required swap size ({} MiB)".format(
existing_datastore["name"],
existing_datastore["capacity"] / 1024.0 ** 2,
swap_size_MiB,
@ -1717,11 +1706,11 @@ def host_cache_configured(
service_instance=si,
)
comments.append(
"Host cache configured on host " "'{0}'.".format(hostname)
"Host cache configured on host " "'{}'.".format(hostname)
)
else:
comments.append(
"Host cache on host '{0}' is already correctly "
"Host cache on host '{}' is already correctly "
"configured. Nothing to be done.".format(hostname)
)
result = True

View file

@ -7,6 +7,8 @@ and the like, but also useful for basic HTTP testing.
import cgi
import gzip
import http.client
import http.cookiejar
import io
import logging
import os
@ -14,13 +16,13 @@ import pprint
import re
import socket
import ssl
import urllib.error
import urllib.parse
import urllib.request
import xml.etree.ElementTree as ET
import zlib
import salt.config
import salt.ext.six.moves.http_client
import salt.ext.six.moves.http_cookiejar
import salt.ext.six.moves.urllib.request as urllib_request
import salt.ext.tornado.httputil
import salt.ext.tornado.simple_httpclient
import salt.loader
@ -36,12 +38,6 @@ import salt.utils.stringutils
import salt.utils.xmlutil as xml
import salt.utils.yaml
import salt.version
from salt.ext import six
from salt.ext.six.moves import StringIO
from salt.ext.six.moves.urllib.error import URLError
from salt.ext.six.moves.urllib.parse import splitquery
from salt.ext.six.moves.urllib.parse import urlencode as _urlencode
from salt.ext.six.moves.urllib.parse import urlparse
from salt.ext.tornado.httpclient import HTTPClient
from salt.template import compile_template
from salt.utils.decorators.jinja import jinja_filter
@ -317,11 +313,9 @@ def query(
if cookies is not None:
if cookie_format == "mozilla":
sess_cookies = salt.ext.six.moves.http_cookiejar.MozillaCookieJar(
cookie_jar
)
sess_cookies = http.cookiejar.MozillaCookieJar(cookie_jar)
else:
sess_cookies = salt.ext.six.moves.http_cookiejar.LWPCookieJar(cookie_jar)
sess_cookies = http.cookiejar.LWPCookieJar(cookie_jar)
if not os.path.isfile(cookie_jar):
sess_cookies.save()
sess_cookies.load()
@ -366,7 +360,7 @@ def query(
method,
url,
params=params,
files={formdata_fieldname: (formdata_filename, StringIO(data))},
files={formdata_fieldname: (formdata_filename, io.StringIO(data))},
**req_kwargs
)
else:
@ -400,15 +394,15 @@ def query(
body = body.decode(result.encoding or "utf-8")
ret["body"] = body
elif backend == "urllib2":
request = urllib_request.Request(url_full, data)
request = urllib.request.Request(url_full, data)
handlers = [
urllib_request.HTTPHandler,
urllib_request.HTTPCookieProcessor(sess_cookies),
urllib.request.HTTPHandler,
urllib.request.HTTPCookieProcessor(sess_cookies),
]
if url.startswith("https"):
hostname = request.get_host()
handlers[0] = urllib_request.HTTPSHandler(1)
handlers[0] = urllib.request.HTTPSHandler(1)
if not HAS_MATCHHOSTNAME:
log.warning(
"match_hostname() not available, SSL hostname checking "
@ -459,7 +453,7 @@ def query(
# Python >= 2.7.9
context = ssl.SSLContext.load_cert_chain(*cert_chain)
handlers.append(
urllib_request.HTTPSHandler(context=context)
urllib.request.HTTPSHandler(context=context)
) # pylint: disable=E1123
else:
# Python < 2.7.9
@ -470,17 +464,15 @@ def query(
}
if len(cert_chain) > 1:
cert_kwargs["key_file"] = cert_chain[1]
handlers[0] = salt.ext.six.moves.http_client.HTTPSConnection(
**cert_kwargs
)
handlers[0] = http.client.HTTPSConnection(**cert_kwargs)
opener = urllib_request.build_opener(*handlers)
opener = urllib.request.build_opener(*handlers)
for header in header_dict:
request.add_header(header, header_dict[header])
request.get_method = lambda: method
try:
result = opener.open(request)
except URLError as exc:
except urllib.error.URLError as exc:
return {"Error": str(exc)}
if stream is True or handle is True:
return {
@ -501,7 +493,7 @@ def query(
and not isinstance(result_text, str)
):
result_text = result_text.decode(res_params["charset"])
if six.PY3 and isinstance(result_text, bytes) and decode_body:
if isinstance(result_text, bytes) and decode_body:
result_text = result_text.decode("utf-8")
ret["body"] = result_text
else:
@ -525,7 +517,7 @@ def query(
)
if isinstance(data, dict):
data = _urlencode(data)
data = urllib.parse.urlencode(data)
if verify_ssl:
req_kwargs["ca_certs"] = ca_bundle
@ -561,7 +553,7 @@ def query(
# Since tornado doesnt support no_proxy, we'll always hand it empty proxies or valid ones
# except we remove the valid ones if a url has a no_proxy hostname in it
if urlparse(url_full).hostname in no_proxy:
if urllib.parse.urlparse(url_full).hostname in no_proxy:
proxy_host = None
proxy_port = None
proxy_username = None
@ -655,7 +647,7 @@ def query(
and not isinstance(result_text, str)
):
result_text = result_text.decode(res_params["charset"])
if six.PY3 and isinstance(result_text, bytes) and decode_body:
if isinstance(result_text, bytes) and decode_body:
result_text = result_text.decode("utf-8")
ret["body"] = result_text
if "Set-Cookie" in result_headers and cookies is not None:
@ -994,9 +986,7 @@ def parse_cookie_header(header):
# cookielib.Cookie() requires an epoch
if "expires" in cookie:
cookie["expires"] = salt.ext.six.moves.http_cookiejar.http2time(
cookie["expires"]
)
cookie["expires"] = http.cookiejar.http2time(cookie["expires"])
# Fill in missing required fields
for req in reqd:
@ -1012,9 +1002,7 @@ def parse_cookie_header(header):
# Remove attribs that don't apply to Cookie objects
cookie.pop("httponly", None)
cookie.pop("samesite", None)
ret.append(
salt.ext.six.moves.http_cookiejar.Cookie(name=name, value=value, **cookie)
)
ret.append(http.cookiejar.Cookie(name=name, value=value, **cookie))
return ret
@ -1024,7 +1012,7 @@ def sanitize_url(url, hide_fields):
Make sure no secret fields show up in logs
"""
if isinstance(hide_fields, list):
url_comps = splitquery(url)
url_comps = urllib.parse.splitquery(url)
log_url = url_comps[0]
if len(url_comps) > 1:
log_url += "?"
@ -1057,3 +1045,23 @@ def _sanitize_url_components(comp_list, field):
ret = "{}&".format(comp_list[0])
comp_list.remove(comp_list[0])
return ret + _sanitize_url_components(comp_list, field)
def session(user=None, password=None, verify_ssl=True, ca_bundle=None, headers=None):
"""
create a requests session
"""
session = requests.session()
if user and password:
session.auth = (user, password)
if ca_bundle and not verify_ssl:
log.error("You cannot use both ca_bundle and verify_ssl False together")
return False
if ca_bundle:
opts = {"ca_bundle": ca_bundle}
session.verify = get_ca_bundle(opts)
if not verify_ssl:
session.verify = False
if headers:
session.headers.update(headers)
return session

View file

@ -228,8 +228,8 @@ def get_tops_python(py_ver, exclude=None, ext_py_ver=None):
"{} does not exist. Could not auto detect dependencies".format(py_ver)
)
return {}
py_shell_cmd = "{0} -c 'import {1}; print({1}.__file__)'".format(py_ver, mod)
cmd = subprocess.Popen(py_shell_cmd, stdout=subprocess.PIPE, shell=True)
py_shell_cmd = [py_ver, "-c", "import {0}; print({0}.__file__)".format(mod)]
cmd = subprocess.Popen(py_shell_cmd, stdout=subprocess.PIPE)
stdout, _ = cmd.communicate()
mod_file = os.path.abspath(salt.utils.data.decode(stdout).rstrip("\n"))

View file

@ -72,7 +72,6 @@ You should see output related to the ESXi host's syslog configuration.
"""
import atexit
import errno
import logging
@ -80,7 +79,6 @@ import ssl
import time
from http.client import BadStatusLine
import requests
import salt.exceptions
import salt.modules.cmdmod
import salt.utils.path
@ -170,11 +168,8 @@ def esxcli(
host, user, pwd, protocol, port, cmd
)
else:
esx_cmd += (
" -s {} -h {} -u {} -p '{}' "
"--protocol={} --portnumber={} {}".format(
host, esxi_host, user, pwd, protocol, port, cmd
)
esx_cmd += " -s {} -h {} -u {} -p '{}' --protocol={} --portnumber={} {}".format(
host, esxi_host, user, pwd, protocol, port, cmd
)
ret = salt.modules.cmdmod.run_all(esx_cmd, output_loglevel="quiet")
@ -182,7 +177,9 @@ def esxcli(
return ret
def get_vsphere_client(server, username, password, session=None):
def get_vsphere_client(
server, username, password, session=None, verify_ssl=True, ca_bundle=None
):
"""
Internal helper method to create an instance of the vSphere API client.
Please provide username and password to authenticate.
@ -196,6 +193,10 @@ def get_vsphere_client(server, username, password, session=None):
:param Session session:
Request HTTP session instance. If not specified, one
is automatically created and used
:param boolean verify_ssl:
Verify the SSL certificate. Default: True
:param basestring ca_bundle:
Path to the ca bundle to use when verifying SSL certificates.
:returns:
Vsphere Client instance
@ -204,9 +205,7 @@ def get_vsphere_client(server, username, password, session=None):
"""
if not session:
# Create an https session to be used for a vSphere client
session = requests.session()
# If client uses own SSL cert, session should not verify
session.verify = False
session = salt.utils.http.session(verify_ssl=verify_ssl, ca_bundle=ca_bundle)
client = None
try:
client = create_vsphere_client(
@ -218,7 +217,15 @@ def get_vsphere_client(server, username, password, session=None):
def _get_service_instance(
host, username, password, protocol, port, mechanism, principal, domain
host,
username,
password,
protocol,
port,
mechanism,
principal,
domain,
verify_ssl=True,
):
"""
Internal method to authenticate with a vCenter server or ESX/ESXi host
@ -253,21 +260,26 @@ def _get_service_instance(
raise salt.exceptions.CommandExecutionError(
"Unsupported mechanism: '{}'".format(mechanism)
)
log.trace(
"Connecting using the '%s' mechanism, with username '%s'", mechanism, username,
)
default_msg = (
"Could not connect to host '{}'. "
"Please check the debug log for more information.".format(host)
)
try:
log.trace(
"Connecting using the '%s' mechanism, with username '%s'",
mechanism,
username,
)
service_instance = SmartConnect(
host=host,
user=username,
pwd=password,
protocol=protocol,
port=port,
b64token=token,
mechanism=mechanism,
)
if verify_ssl:
service_instance = SmartConnect(
host=host,
user=username,
pwd=password,
protocol=protocol,
port=port,
b64token=token,
mechanism=mechanism,
)
except TypeError as exc:
if "unexpected keyword argument" in exc.message:
log.error(
@ -280,30 +292,33 @@ def _get_service_instance(
raise
except Exception as exc: # pylint: disable=broad-except
# pyVmomi's SmartConnect() actually raises Exception in some cases.
default_msg = (
"Could not connect to host '{}'. "
"Please check the debug log for more information.".format(host)
)
if (
isinstance(exc, vim.fault.HostConnectFault)
and "[SSL: CERTIFICATE_VERIFY_FAILED]" in exc.msg
) or "[SSL: CERTIFICATE_VERIFY_FAILED]" in str(exc):
err_msg = (
"Could not verify the SSL certificate. You can use "
"verify_ssl: False if you do not want to verify the "
"SSL certificate. This is not recommended as it is "
"considered insecure."
)
else:
log.exception(exc)
err_msg = exc.msg if hasattr(exc, "msg") else default_msg
raise salt.exceptions.VMwareConnectionError(err_msg)
if not verify_ssl:
try:
if (
isinstance(exc, vim.fault.HostConnectFault)
and "[SSL: CERTIFICATE_VERIFY_FAILED]" in exc.msg
) or "[SSL: CERTIFICATE_VERIFY_FAILED]" in str(exc):
service_instance = SmartConnect(
host=host,
user=username,
pwd=password,
protocol=protocol,
port=port,
sslContext=ssl._create_unverified_context(),
b64token=token,
mechanism=mechanism,
)
else:
log.exception(exc)
err_msg = exc.msg if hasattr(exc, "msg") else default_msg
raise salt.exceptions.VMwareConnectionError(err_msg)
service_instance = SmartConnect(
host=host,
user=username,
pwd=password,
protocol=protocol,
port=port,
sslContext=ssl._create_unverified_context(),
b64token=token,
mechanism=mechanism,
)
except Exception as exc: # pylint: disable=broad-except
# pyVmomi's SmartConnect() actually raises Exception in some cases.
if "certificate verify failed" in str(exc):
@ -330,6 +345,7 @@ def _get_service_instance(
err_msg = exc.msg if hasattr(exc, "msg") else default_msg
log.trace(exc)
raise salt.exceptions.VMwareConnectionError(err_msg)
atexit.register(Disconnect, service_instance)
return service_instance
@ -384,6 +400,7 @@ def get_service_instance(
mechanism="userpass",
principal=None,
domain=None,
verify_ssl=True,
):
"""
Authenticate with a vCenter server or ESX/ESXi host and return the service instance object.
@ -416,6 +433,9 @@ def get_service_instance(
domain
Kerberos user domain. Required if mechanism is ``sspi``
verify_ssl
Verify the SSL certificate. Default: True
"""
if protocol is None:
@ -438,7 +458,15 @@ def get_service_instance(
if not service_instance:
service_instance = _get_service_instance(
host, username, password, protocol, port, mechanism, principal, domain
host,
username,
password,
protocol,
port,
mechanism,
principal,
domain,
verify_ssl=verify_ssl,
)
# Test if data can actually be retrieved or connection has gone stale
@ -449,7 +477,15 @@ def get_service_instance(
log.trace("Session no longer authenticating. Reconnecting")
Disconnect(service_instance)
service_instance = _get_service_instance(
host, username, password, protocol, port, mechanism, principal, domain
host,
username,
password,
protocol,
port,
mechanism,
principal,
domain,
verify_ssl=verify_ssl,
)
except vim.fault.NoPermission as exc:
log.exception(exc)

View file

@ -1,8 +1,6 @@
# -*- coding: utf-8 -*-
"""
Modules used to control the master itself
"""
from __future__ import absolute_import, print_function, unicode_literals
from collections.abc import Mapping
@ -15,7 +13,7 @@ import salt.utils.zeromq
class WheelClient(
salt.client.mixins.SyncClientMixin, salt.client.mixins.AsyncClientMixin, object
salt.client.mixins.SyncClientMixin, salt.client.mixins.AsyncClientMixin
):
"""
An interface to Salt's wheel modules
@ -123,8 +121,8 @@ class WheelClient(
})
{'jid': '20131219224744416681', 'tag': 'salt/wheel/20131219224744416681'}
"""
fun = low.pop("fun")
return self.asynchronous(fun, low)
fun = low.get("fun")
return self.asynchronous(fun, low, local=False)
def cmd(
self,
@ -143,9 +141,7 @@ class WheelClient(
>>> wheel.cmd('key.finger', ['jerry'])
{'minions': {'jerry': '5d:f6:79:43:5e:d4:42:3f:57:b8:45:a8:7e:a4:6e:ca'}}
"""
return super(WheelClient, self).cmd(
fun, arg, pub_data, kwarg, print_event, full_return
)
return super().cmd(fun, arg, pub_data, kwarg, print_event, full_return)
Wheel = WheelClient # for backward-compat

View file

@ -1,20 +1,13 @@
# -*- coding: utf-8 -*-
"""
The `pillar_roots` wheel module is used to manage files under the pillar roots
directories on the master server.
"""
# Import python libs
from __future__ import absolute_import, print_function, unicode_literals
import os
# Import salt libs
import salt.utils.files
import salt.utils.path
# Import 3rd-party libs
from salt.ext import six
import salt.utils.verify
def find(path, saltenv="base"):
@ -86,7 +79,7 @@ def read(path, saltenv="base"):
ret = []
files = find(path, saltenv)
for fn_ in files:
full = next(six.iterkeys(fn_))
full = next(iter(fn_.keys()))
form = fn_[full]
if form == "txt":
with salt.utils.files.fopen(full, "rb") as fp_:
@ -100,19 +93,23 @@ def write(data, path, saltenv="base", index=0):
index of the file can be specified to write to a lower priority file root
"""
if saltenv not in __opts__["pillar_roots"]:
return "Named environment {0} is not present".format(saltenv)
return "Named environment {} is not present".format(saltenv)
if len(__opts__["pillar_roots"][saltenv]) <= index:
return "Specified index {0} in environment {1} is not present".format(
return "Specified index {} in environment {} is not present".format(
index, saltenv
)
if os.path.isabs(path):
return (
"The path passed in {0} is not relative to the environment " "{1}"
).format(path, saltenv)
return "The path passed in {} is not relative to the environment " "{}".format(
path, saltenv
)
roots_dir = __opts__["pillar_roots"][saltenv][index]
dest = os.path.join(roots_dir, path)
if not salt.utils.verify.clean_path(roots_dir, dest):
return "Invalid path"
dest = os.path.join(__opts__["pillar_roots"][saltenv][index], path)
dest_dir = os.path.dirname(dest)
if not os.path.isdir(dest_dir):
os.makedirs(dest_dir)
with salt.utils.files.fopen(dest, "w+") as fp_:
fp_.write(salt.utils.stringutils.to_str(data))
return "Wrote data to file {0}".format(dest)
return "Wrote data to file {}".format(dest)

View file

@ -76,3 +76,20 @@ class VMWareTest(CloudTest):
self.assertIn(s_ret_str, str(create_snapshot))
self.assertDestroyInstance()
def test_verify_ssl_false(self):
"""
Tests creating and deleting an instance on vmware when using
verify_ssl: False
"""
profile_name = "vmware_verify_ssl"
self.add_profile_config(
"vmware-test", {"verify_ssl": False}, "vmware.conf", profile_name
)
# create the instance
ret_val = self.run_cloud(
"-p {} {}".format(profile_name, self.instance_name), timeout=TIMEOUT
)
# check if instance returned with salt installed
self.assertInstanceExists(ret_val)
self.assertDestroyInstance()

View file

@ -9,6 +9,7 @@ import shutil
from time import sleep
import pytest
import salt.utils.files
from salt.config import cloud_config, cloud_providers_config
from salt.utils.yaml import safe_load
from tests.support.case import ShellCase
@ -195,6 +196,18 @@ class CloudTest(ShellCase):
def profile_str(self):
return self.PROVIDER + "-config"
def add_profile_config(self, name, data, conf, new_profile):
"""
copy the current profile and add a new profile in the same file
"""
conf_path = os.path.join(RUNTIME_VARS.TMP_CONF_DIR, "cloud.profiles.d", conf)
with salt.utils.files.fopen(conf_path, "r") as fp:
conf = safe_load(fp)
conf[new_profile] = conf[name].copy()
conf[new_profile].update(data)
with salt.utils.files.fopen(conf_path, "w") as fp:
salt.utils.yaml.safe_dump(conf, fp)
def setUp(self):
"""
Sets up the test requirements. In child classes, define PROVIDER and REQUIRED_PROVIDER_CONFIG_ITEMS or this will fail

View file

@ -452,11 +452,48 @@ class NetapiSSHClientAuthTest(SSHCase):
except AssertionError:
self.mod_case.run_function("user.delete", [self.USERA], remove=True)
self.skipTest("Could not add user or password, skipping test")
self.expfile = os.path.join(RUNTIME_VARS.TMP, "exploited")
def tearDown(self):
try:
os.remove(self.expfile)
except OSError:
pass
del self.expfile
del self.netapi
self.mod_case.run_function("user.delete", [self.USERA], remove=True)
@staticmethod
def cleanup_file(path):
try:
os.remove(path)
except OSError:
pass
@pytest.mark.slow_test
def test_extra_mods(self):
"""
validate input from extra_mods
"""
path = os.path.join(RUNTIME_VARS.TMP, "test_extra_mods")
self.addCleanup(self.cleanup_file, path)
low = {
"client": "ssh",
"tgt": "localhost",
"fun": "test.ping",
"roster_file": "roster",
"rosters": [self.rosters],
"ssh_priv": self.priv_file,
"eauth": "pam",
"username": self.USERA,
"password": self.USERA_PWD,
"regen_thin": True,
"thin_extra_mods": "';touch {};'".format(path),
}
ret = self.netapi.run(low)
self.assertFalse(os.path.exists(path))
@classmethod
def setUpClass(cls):
cls.post_webserver = Webserver(handler=SaveRequestsPostHandler)
@ -571,3 +608,34 @@ class NetapiSSHClientAuthTest(SSHCase):
ret = self.netapi.run(low)
assert "localhost" in ret
assert ret["localhost"]["return"] is True
def test_ssh_cve_2021_3197_a(self):
assert not os.path.exists(self.expfile)
low = {
"eauth": "auto",
"username": self.USERA,
"password": self.USERA_PWD,
"client": "ssh",
"tgt": "localhost",
"fun": "test.ping",
"ssh_port": '22 -o ProxyCommand="touch {}"'.format(self.expfile),
"ssh_priv": self.priv_file,
}
ret = self.netapi.run(low)
assert not os.path.exists(self.expfile)
def test_ssh_cve_2021_3197_b(self):
assert not os.path.exists(self.expfile)
low = {
"eauth": "auto",
"username": self.USERA,
"password": self.USERA_PWD,
"client": "ssh",
"tgt": "localhost",
"fun": "test.ping",
"ssh_port": 22,
"ssh_priv": self.priv_file,
"ssh_options": ['ProxyCommand="touch {}"'.format(self.expfile)],
}
ret = self.netapi.run(low)
assert not os.path.exists(self.expfile)

View file

@ -0,0 +1,37 @@
import os
import salt.wheel
from tests.support.mixins import AdaptedConfigurationTestCaseMixin
from tests.support.unit import TestCase
class WheelPillarRootsTest(TestCase, AdaptedConfigurationTestCaseMixin):
def setUp(self):
self.wheel = salt.wheel.Wheel(dict(self.get_config("client_config")))
self.pillar_dir = self.wheel.opts["pillar_roots"]["base"][0]
self.traversed_dir = os.path.dirname(self.pillar_dir)
def tearDown(self):
try:
os.remove(os.path.join(self.pillar_dir, "foo"))
except OSError:
pass
try:
os.remove(os.path.join(self.traversed_dir, "foo"))
except OSError:
pass
del self.wheel
def test_write(self):
ret = self.wheel.cmd(
"pillar_roots.write", kwarg={"data": "foo: bar", "path": "foo"}
)
assert os.path.exists(os.path.join(self.pillar_dir, "foo"))
assert ret.find("Wrote data to file") != -1
def test_cvr_2021_25282(self):
ret = self.wheel.cmd(
"pillar_roots.write", kwarg={"data": "foo", "path": "../foo"}
)
assert not os.path.exists(os.path.join(self.traversed_dir, "foo"))
assert ret.find("Invalid path") != -1

View file

@ -0,0 +1,52 @@
import pytest
import requests
import salt.utils.http
from tests.support.mock import MagicMock, patch
def test_requests_session_verify_ssl_false(ssl_webserver, integration_files_dir):
"""
test salt.utils.http.session when using verify_ssl
"""
for verify in [True, False, None]:
kwargs = {"verify_ssl": verify}
if verify is None:
kwargs.pop("verify_ssl")
if verify is True or verify is None:
with pytest.raises(requests.exceptions.SSLError) as excinfo:
session = salt.utils.http.session(**kwargs)
ret = session.get(ssl_webserver.url("this.txt"))
else:
session = salt.utils.http.session(**kwargs)
ret = session.get(ssl_webserver.url("this.txt"))
assert ret.status_code == 200
def test_session_ca_bundle_verify_false():
"""
test salt.utils.http.session when using
both ca_bunlde and verify_ssl false
"""
ret = salt.utils.http.session(ca_bundle="/tmp/test_bundle", verify_ssl=False)
assert ret is False
def test_session_headers():
"""
test salt.utils.http.session when setting
headers
"""
ret = salt.utils.http.session(headers={"Content-Type": "application/json"})
assert ret.headers["Content-Type"] == "application/json"
def test_session_ca_bundle():
"""
test salt.utils.https.session when setting ca_bundle
"""
fpath = "/tmp/test_bundle"
patch_os = patch("os.path.exists", MagicMock(return_value=True))
with patch_os:
ret = salt.utils.http.session(ca_bundle=fpath)
assert ret.verify == fpath

View file

@ -35,11 +35,11 @@ def test_get_tops_python(version):
with patch_proc, patch_which:
salt.utils.thin.get_tops_python("python2", ext_py_ver=version)
cmds = [x[0][0] for x in mock_popen.call_args_list]
assert [x for x in cmds if "jinja2" in x]
assert [x for x in cmds if "jinja2" in x[2]]
if python3:
assert [x for x in cmds if "distro" in x]
assert [x for x in cmds if "distro" in x[2]]
else:
assert not [x for x in cmds if "distro" in x]
assert not [x for x in cmds if "distro" in x[2]]
@pytest.mark.parametrize("version", [[2, 7], [3, 0], [3, 7]])

View file

@ -0,0 +1,35 @@
import os
import time
import salt.auth
import salt.config
from tests.support.runtests import RUNTIME_VARS
from tests.support.unit import TestCase
class AuthTest(TestCase):
def test_cve_2021_3244(self):
opts = {
"extension_modules": "",
"optimization_order": [0, 1, 2],
"token_expire": 1,
"keep_acl_in_token": False,
"eauth_tokens": "localfs",
"token_dir": RUNTIME_VARS.TMP,
"token_expire_user_override": True,
"external_auth": {"auto": {"foo": []}},
}
auth = salt.auth.LoadAuth(opts)
load = {
"eauth": "auto",
"username": "foo",
"password": "foo",
"token_expire": -1,
}
t_data = auth.mk_token(load)
assert t_data["expire"] < time.time()
token_file = os.path.join(RUNTIME_VARS.TMP, t_data["token"])
assert os.path.exists(token_file)
t_data = auth.get_tok(t_data["token"])
assert not os.path.exists(token_file)
assert t_data == {}

View file

@ -0,0 +1,59 @@
import copy
from salt.cloud.clouds import qingcloud
from tests.support.mixins import LoaderModuleMockMixin
from tests.support.mock import MagicMock, patch
from tests.support.unit import TestCase
class QingCloudTestCase(TestCase, LoaderModuleMockMixin):
"""
Unit TestCase for salt.cloud.clouds.qingcloud module.
"""
def setUp(self):
self.provider = {
"providers": {
"qingcloud": {
"qingcloud": {
"access_key_id": "key_1234",
"secret_access_key": "1234",
"zone": "test_zone",
"key_filename": "/testfilename",
"driver": "qingcloud",
}
}
}
}
def setup_loader_modules(self):
return {
qingcloud: {
"__opts__": {
"providers": {"qingcloud": {}},
"profiles": {"qingcloud": {}},
},
"__active_provider_name__": "qingcloud:qingcloud",
},
}
def test_qingcloud_verify_ssl(self):
"""
test qinglcoud when using verify_ssl
"""
patch_sig = patch("salt.cloud.clouds.qingcloud._compute_signature", MagicMock())
for verify in [True, False, None]:
mock_requests = MagicMock()
mock_requests.return_value.status_code = 200
mock_requests.return_value.text = '{"ret_code": 0}'
patch_requests = patch("requests.get", mock_requests)
opts = copy.deepcopy(self.provider)
opts["providers"]["qingcloud"]["qingcloud"]["verify_ssl"] = verify
patch_opts = patch.dict(qingcloud.__opts__, opts)
with patch_sig, patch_requests, patch_opts:
ret = qingcloud.query()
self.assertEqual(ret["ret_code"], 0)
self.assertEqual(
mock_requests.call_args_list[0].kwargs["verify"], verify
)

View file

@ -0,0 +1,37 @@
"""
tests.unit.modules.test_bigip
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Unit tests for the bigip module
"""
import logging
import salt.modules.bigip as bigip
from tests.support.mixins import LoaderModuleMockMixin
from tests.support.mock import MagicMock, patch
from tests.support.unit import TestCase
log = logging.getLogger(__name__)
class RequestsSession:
def __init__(self):
self.auth = None
self.verify = None
self.headers = {}
class BigipModuleTest(TestCase, LoaderModuleMockMixin):
def setup_loader_modules(self):
return {bigip: {}}
def test__build_session_verify_ssl(self):
requests_session = RequestsSession()
with patch(
"salt.modules.bigip.requests.sessions.Session",
MagicMock(return_value=requests_session),
):
bigip._build_session("username", "password")
self.assertEqual(requests_session.auth, ("username", "password"))
assert requests_session.verify is True

View file

@ -2,7 +2,7 @@
:codeauthor: Nicole Thomas <nicole@saltstack.com>
"""
import builtins
import os
import sys
import tempfile
@ -12,7 +12,6 @@ import salt.utils.files
import salt.utils.platform
import salt.utils.stringutils
from salt.exceptions import CommandExecutionError
from salt.ext.six.moves import builtins # pylint: disable=import-error
from salt.log import LOG_LEVELS
from tests.support.helpers import TstSuiteLoggingHandler
from tests.support.mixins import LoaderModuleMockMixin
@ -640,3 +639,16 @@ class CMDMODTestCase(TestCase, LoaderModuleMockMixin):
umask=None,
use_vt=False,
)
def test_cve_2021_25284(self):
proc = MagicMock(
return_value=MockTimedProc(stdout=b"foo", stderr=b"wtf", returncode=2)
)
with patch("salt.utils.timed_subprocess.TimedProc", proc):
with TstSuiteLoggingHandler() as log_handler:
cmdmod.run("testcmd -p ImAPassword", output_loglevel="error")
for x in log_handler.messages:
if x.find("Executing command") > -1:
assert x.find("ImAPassword") == -1, x
if x.find("faild with return code") > -1:
assert x.find("ImAPassword") == -1, x

View file

@ -0,0 +1,69 @@
"""
tests.unit.modules.test_glassfish
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Unit tests for the glassfish module
"""
import logging
import salt.modules.glassfish as glassfish
from tests.support.mixins import LoaderModuleMockMixin
from tests.support.mock import MagicMock, patch
from tests.support.unit import TestCase
log = logging.getLogger(__name__)
class GlassFishTest(TestCase, LoaderModuleMockMixin):
def setup_loader_modules(self):
return {glassfish: {}}
def test__api_get(self):
get_mock = MagicMock()
with patch("salt.modules.glassfish.requests.get", get_mock):
glassfish._api_get("ThePath", server=glassfish.DEFAULT_SERVER)
get_mock.assert_called_once_with(
headers={
"Accept": "application/json",
"Content-Type": "application/json",
"X-Requested-By": "GlassFish REST HTML interface",
},
url="http://localhost:4848/management/domain/ThePath",
verify=True,
auth=None,
)
def test__api_post(self):
post_mock = MagicMock()
with patch("salt.modules.glassfish.requests.post", post_mock):
glassfish._api_post("ThePath", {1: 1}, server=glassfish.DEFAULT_SERVER)
post_mock.assert_called_once_with(
headers={
"Accept": "application/json",
"Content-Type": "application/json",
"X-Requested-By": "GlassFish REST HTML interface",
},
url="http://localhost:4848/management/domain/ThePath",
verify=True,
auth=None,
data='{"1": 1}',
)
def test__api_delete(self):
delete_mock = MagicMock()
with patch("salt.modules.glassfish.requests.delete", delete_mock):
glassfish._api_delete("ThePath", {1: 1}, server=glassfish.DEFAULT_SERVER)
delete_mock.assert_called_once_with(
headers={
"Accept": "application/json",
"Content-Type": "application/json",
"X-Requested-By": "GlassFish REST HTML interface",
},
url="http://localhost:4848/management/domain/ThePath",
verify=True,
auth=None,
params={1: 1},
)

View file

@ -1,21 +1,15 @@
# -*- coding: utf-8 -*-
"""
:codeauthor: Jayesh Kariya <jayeshk@saltstack.com>
"""
# Import Python Libs
from __future__ import absolute_import, print_function, unicode_literals
# Import Salt Libs
import salt.modules.config as config
import salt.modules.keystone as keystone
# Import Salt Testing Libs
from tests.support.mixins import LoaderModuleMockMixin
from tests.support.mock import MagicMock, patch
from tests.support.mock import MagicMock, call, patch
from tests.support.unit import TestCase
class MockEC2(object):
class MockEC2:
"""
Mock of EC2 class
"""
@ -68,7 +62,7 @@ class MockEC2(object):
return [cr_ec2]
class MockEndpoints(object):
class MockEndpoints:
"""
Mock of Endpoints class
"""
@ -103,7 +97,7 @@ class MockEndpoints(object):
return id
class MockServices(object):
class MockServices:
"""
Mock of Services class
"""
@ -159,7 +153,7 @@ class MockServices(object):
return service_id
class MockRoles(object):
class MockRoles:
"""
Mock of Roles class
"""
@ -229,7 +223,7 @@ class MockRoles(object):
return [role]
class MockTenants(object):
class MockTenants:
"""
Mock of Tenants class
"""
@ -279,7 +273,7 @@ class MockTenants(object):
return tenant_id
class MockServiceCatalog(object):
class MockServiceCatalog:
"""
Mock of ServiceCatalog class
"""
@ -302,7 +296,7 @@ class MockServiceCatalog(object):
}
class MockUsers(object):
class MockUsers:
"""
Mock of Users class
"""
@ -375,7 +369,7 @@ class Unauthorized(Exception):
"""
def __init__(self, message="Test"):
super(Unauthorized, self).__init__(message)
super().__init__(message)
self.msg = message
@ -385,11 +379,11 @@ class AuthorizationFailure(Exception):
"""
def __init__(self, message="Test"):
super(AuthorizationFailure, self).__init__(message)
super().__init__(message)
self.msg = message
class MockExceptions(object):
class MockExceptions:
"""
Mock of exceptions class
"""
@ -399,7 +393,7 @@ class MockExceptions(object):
self.AuthorizationFailure = AuthorizationFailure
class MockKeystoneClient(object):
class MockKeystoneClient:
"""
Mock of keystoneclient module
"""
@ -408,7 +402,7 @@ class MockKeystoneClient(object):
self.exceptions = MockExceptions()
class MockClient(object):
class MockClient:
"""
Mock of Client class
"""
@ -444,7 +438,10 @@ class KeystoneTestCase(TestCase, LoaderModuleMockMixin):
"auth": MockClient,
"client": MockClient(),
"keystoneclient": MockKeystoneClient(),
}
"__salt__": {"config.get": config.get},
"__opts__": {},
},
config: {"__opts__": {}},
}
# 'ec2_credentials_create' function tests: 1
@ -1053,3 +1050,41 @@ class KeystoneTestCase(TestCase, LoaderModuleMockMixin):
}
},
)
def test_api_version_verify_ssl(self):
"""
test api_version when using verify_ssl
"""
test_verify = [True, False, None]
conn_args = {
"keystone.user": "admin",
"connection_password": "password",
"connection_tenant": "admin",
"connection_tenant_id": "id",
"connection_auth_url": "https://127.0.0.1/v2.0/",
"connection_verify_ssl": True,
}
http_ret = {"dict": {"version": {"id": "id_test"}}}
for verify in test_verify:
mock_http = MagicMock(return_value=http_ret)
patch_http = patch("salt.utils.http.query", mock_http)
conn_args["connection_verify_ssl"] = verify
if verify is None:
conn_args.pop("connection_verify_ssl")
verify = True
with patch_http:
ret = keystone.api_version(**conn_args)
self.assertEqual(
mock_http.call_args_list,
[
call(
"https://127.0.0.1/v2.0/",
decode=True,
decode_type="json",
verify_ssl=verify,
)
],
)

View file

@ -1,22 +1,16 @@
# -*- coding: utf-8 -*-
"""
:codeauthor: :email:`David Homolka <david.homolka@ultimum.io>`
"""
# Import Python Libs
from __future__ import absolute_import, print_function, unicode_literals
import os
# Import Salt Libsrestartcheck
import salt.modules.restartcheck as restartcheck
# Import Salt Testing Libs
import salt.utils.path
from tests.support.mixins import LoaderModuleMockMixin
from tests.support.mock import MagicMock, patch
from tests.support.runtests import RUNTIME_VARS
from tests.support.unit import TestCase
# import salt.utils.files
# from salt.exceptions import CommandExecutionError
class RestartcheckTestCase(TestCase, LoaderModuleMockMixin):
"""
@ -329,3 +323,61 @@ class RestartcheckTestCase(TestCase, LoaderModuleMockMixin):
self.assertFalse(restartcheck._valid_deleted_file("/SYSV/test"))
self.assertFalse(restartcheck._valid_deleted_file("/SYSV/test (deleted)"))
self.assertFalse(restartcheck._valid_deleted_file("/SYSV/test (path inode=1)"))
def test_valid_command(self):
"""
test for CVE-2020-28243
"""
create_file = os.path.join(RUNTIME_VARS.TMP, "created_file")
patch_kernel = patch(
"salt.modules.restartcheck._kernel_versions_redhat",
return_value=["3.10.0-1127.el7.x86_64"],
)
services = {
"NetworkManager": {"ExecMainPID": 123},
"auditd": {"ExecMainPID": 456},
"crond": {"ExecMainPID": 789},
}
patch_salt = patch.dict(
restartcheck.__salt__,
{
"cmd.run": MagicMock(
return_value="Linux localhost.localdomain 3.10.0-1127.el7.x86_64"
),
"service.get_running": MagicMock(return_value=list(services.keys())),
"service.show": MagicMock(side_effect=list(services.values())),
"pkg.owner": MagicMock(return_value=""),
"service.available": MagicMock(return_value=True),
},
)
patch_deleted = patch(
"salt.modules.restartcheck._deleted_files",
MagicMock(
return_value=[
(";touch {};".format(create_file), 123, "/root/ (deleted)")
]
),
)
patch_readlink = patch(
"os.readlink", return_value="/root/;touch {};".format(create_file)
)
check_error = True
if salt.utils.path.which("repoquery"):
check_error = False
patch_grains = patch.dict(restartcheck.__grains__, {"os_family": "RedHat"})
with patch_kernel, patch_salt, patch_deleted, patch_readlink, patch_grains:
if check_error:
with self.assertRaises(FileNotFoundError):
restartcheck.restartcheck()
else:
ret = restartcheck.restartcheck()
self.assertIn(
"Found 1 processes using old versions of upgraded files", ret
)
self.assertFalse(os.path.exists(create_file))

View file

@ -1100,6 +1100,34 @@ class _GetProxyConnectionDetailsTestCase(TestCase, LoaderModuleMockMixin):
"'unsupported' proxy is not supported", excinfo.exception.strerror
)
def test_vcenter_proxy_details_verify_ssl(self):
for verify_ssl in [True, False]:
details = self.vcenter_details.copy()
details["verify_ssl"] = verify_ssl
with patch(
"salt.modules.vsphere.get_proxy_type", MagicMock(return_value="vcenter")
):
with patch.dict(
vsphere.__salt__,
{"vcenter.get_details": MagicMock(return_value=details)},
):
ret = vsphere._get_proxy_connection_details()
self.assertEqual(
(
"fake_vcenter",
"fake_username",
"fake_password",
"fake_protocol",
"fake_port",
"fake_mechanism",
"fake_principal",
"fake_domain",
verify_ssl,
),
ret,
)
class GetsServiceInstanceViaProxyTestCase(TestCase, LoaderModuleMockMixin):
"""
@ -2602,52 +2630,70 @@ class TestVSphereTagging(TestCase, LoaderModuleMockMixin):
self.assertEqual(ret, {"Category created": None})
def test_create_tag_category_client(self):
get_details = MagicMock(return_value=self.details)
for verify_ssl in [True, False, None]:
details = self.details.copy()
if verify_ssl is None:
verify_ssl = True
else:
details["verify_ssl"] = verify_ssl
get_details = MagicMock(return_value=details)
# Mock CreateSpec object and create objects
mock_client = Mock(
tagging=Mock(
Category=Mock(
CreateSpec=Mock(return_value=Mock()),
create=Mock(
return_value=self.create_tag_category["Category created"]
),
# Mock CreateSpec object and create objects
mock_client = Mock(
tagging=Mock(
Category=Mock(
CreateSpec=Mock(return_value=Mock()),
create=Mock(
return_value=self.create_tag_category["Category created"]
),
)
)
)
)
# Start patching each external API return with Mock Objects
with patch.object(
vsphere, "get_proxy_type", return_value="vcenter"
) as get_proxy_type:
# Start patching each external API return with Mock Objects
with patch.object(
vsphere, "_get_proxy_connection_details", return_value=[]
) as get_proxy_connection:
vsphere, "get_proxy_type", return_value="vcenter"
) as get_proxy_type:
with patch.object(
salt.utils.vmware, "get_service_instance", return_value=None
) as get_service_instance:
with patch.dict(
vsphere.__salt__,
{"vcenter.get_details": get_details},
clear=True,
) as get_vcenter_details:
with patch.object(
salt.utils.vmware,
"get_vsphere_client",
return_value=mock_client,
) as get_vsphere_client:
ret = vsphere.create_tag_category(
self.func_attrs["name"],
self.func_attrs["description"],
self.func_attrs["cardinality"],
)
vsphere, "_get_proxy_connection_details", return_value=[]
) as get_proxy_connection:
with patch.object(
salt.utils.vmware, "get_service_instance", return_value=None
) as get_service_instance:
with patch.dict(
vsphere.__salt__,
{"vcenter.get_details": get_details},
clear=True,
) as get_vcenter_details:
with patch.object(
salt.utils.vmware,
"get_vsphere_client",
return_value=mock_client,
) as get_vsphere_client:
ret = vsphere.create_tag_category(
self.func_attrs["name"],
self.func_attrs["description"],
self.func_attrs["cardinality"],
)
# Check function calls and return data
get_proxy_type.assert_called_once()
get_proxy_connection.assert_called_once()
get_service_instance.assert_called_once()
get_vsphere_client.assert_called_once()
self.assertEqual(ret, self.create_tag_category)
# Check function calls and return data
get_proxy_type.assert_called_once()
get_proxy_connection.assert_called_once()
get_service_instance.assert_called_once()
get_vsphere_client.assert_called_once()
self.assertEqual(ret, self.create_tag_category)
self.assertEqual(
get_vsphere_client.call_args_list,
[
call(
ca_bundle=None,
password=None,
server=None,
username=None,
verify_ssl=verify_ssl,
)
],
)
def test_create_tag_client_none(self):
get_details = MagicMock(return_value=self.details)
@ -2759,49 +2805,67 @@ class TestVSphereTagging(TestCase, LoaderModuleMockMixin):
self.assertEqual(ret, {"Category deleted": None})
def test_delete_tag_category_client(self):
get_details = MagicMock(return_value=self.details)
for verify_ssl in [True, False, None]:
details = self.details.copy()
if verify_ssl is None:
verify_ssl = True
else:
details["verify_ssl"] = verify_ssl
get_details = MagicMock(return_value=details)
# Mock CreateSpec object and create objects
mock_client = Mock(
tagging=Mock(
Category=Mock(
delete=Mock(
return_value=self.delete_tag_category["Category deleted"]
# Mock CreateSpec object and create objects
mock_client = Mock(
tagging=Mock(
Category=Mock(
delete=Mock(
return_value=self.delete_tag_category["Category deleted"]
)
)
)
)
)
# Start patching each external API return with Mock Objects
with patch.object(
vsphere, "get_proxy_type", return_value="vcenter"
) as get_proxy_type:
# Start patching each external API return with Mock Objects
with patch.object(
vsphere, "_get_proxy_connection_details", return_value=[]
) as get_proxy_connection:
vsphere, "get_proxy_type", return_value="vcenter"
) as get_proxy_type:
with patch.object(
salt.utils.vmware, "get_service_instance", return_value=None
) as get_service_instance:
with patch.dict(
vsphere.__salt__,
{"vcenter.get_details": get_details},
clear=True,
) as get_vcenter_details:
with patch.object(
salt.utils.vmware,
"get_vsphere_client",
return_value=mock_client,
) as get_vsphere_client:
ret = vsphere.delete_tag_category(
self.func_attrs["category_id"]
)
vsphere, "_get_proxy_connection_details", return_value=[]
) as get_proxy_connection:
with patch.object(
salt.utils.vmware, "get_service_instance", return_value=None
) as get_service_instance:
with patch.dict(
vsphere.__salt__,
{"vcenter.get_details": get_details},
clear=True,
) as get_vcenter_details:
with patch.object(
salt.utils.vmware,
"get_vsphere_client",
return_value=mock_client,
) as get_vsphere_client:
ret = vsphere.delete_tag_category(
self.func_attrs["category_id"]
)
# Check function calls and return data
get_proxy_type.assert_called_once()
get_proxy_connection.assert_called_once()
get_service_instance.assert_called_once()
get_vsphere_client.assert_called_once()
self.assertEqual(ret, self.delete_tag_category)
# Check function calls and return data
get_proxy_type.assert_called_once()
get_proxy_connection.assert_called_once()
get_service_instance.assert_called_once()
get_vsphere_client.assert_called_once()
self.assertEqual(ret, self.delete_tag_category)
self.assertEqual(
get_vsphere_client.call_args_list,
[
call(
ca_bundle=None,
password=None,
server=None,
username=None,
verify_ssl=verify_ssl,
)
],
)
def test_delete_tag_client_none(self):
get_details = MagicMock(return_value=self.details)
@ -2901,44 +2965,64 @@ class TestVSphereTagging(TestCase, LoaderModuleMockMixin):
self.assertEqual(ret, {"Categories": None})
def test_list_tag_categories_client(self):
get_details = MagicMock(return_value=self.details)
for verify_ssl in [True, False, None]:
details = self.details.copy()
if verify_ssl is not None:
details["verify_ssl"] = verify_ssl
else:
verify_ssl = True
get_details = MagicMock(return_value=details)
# Mock CreateSpec object and create objects
mock_client = Mock(
tagging=Mock(
Category=Mock(list=Mock(return_value=self.list_tag_categories_return))
# Mock CreateSpec object and create objects
mock_client = Mock(
tagging=Mock(
Category=Mock(
list=Mock(return_value=self.list_tag_categories_return)
)
)
)
)
# Start patching each external API return with Mock Objects
with patch.object(
vsphere, "get_proxy_type", return_value="vcenter"
) as get_proxy_type:
# Start patching each external API return with Mock Objects
with patch.object(
vsphere, "_get_proxy_connection_details", return_value=[]
) as get_proxy_connection:
vsphere, "get_proxy_type", return_value="vcenter"
) as get_proxy_type:
with patch.object(
salt.utils.vmware, "get_service_instance", return_value=None
) as get_service_instance:
with patch.dict(
vsphere.__salt__,
{"vcenter.get_details": get_details},
clear=True,
) as get_vcenter_details:
with patch.object(
salt.utils.vmware,
"get_vsphere_client",
return_value=mock_client,
) as get_vsphere_client:
ret = vsphere.list_tag_categories()
vsphere, "_get_proxy_connection_details", return_value=[]
) as get_proxy_connection:
with patch.object(
salt.utils.vmware, "get_service_instance", return_value=None
) as get_service_instance:
with patch.dict(
vsphere.__salt__,
{"vcenter.get_details": get_details},
clear=True,
) as get_vcenter_details:
with patch.object(
salt.utils.vmware,
"get_vsphere_client",
return_value=mock_client,
) as get_vsphere_client:
ret = vsphere.list_tag_categories()
get_proxy_type.assert_called_once()
get_proxy_connection.assert_called_once()
get_service_instance.assert_called_once()
get_vsphere_client.assert_called_once()
self.assertEqual(
ret, {"Categories": self.list_tag_categories_return}
)
get_proxy_type.assert_called_once()
get_proxy_connection.assert_called_once()
get_service_instance.assert_called_once()
get_vsphere_client.assert_called_once()
self.assertEqual(
get_vsphere_client.call_args_list,
[
call(
ca_bundle=None,
password=None,
server=None,
username=None,
verify_ssl=verify_ssl,
)
],
)
self.assertEqual(
ret, {"Categories": self.list_tag_categories_return}
)
def test_list_tags_client_none(self):
get_details = MagicMock(return_value=self.details)
@ -3005,6 +3089,56 @@ class TestVSphereTagging(TestCase, LoaderModuleMockMixin):
get_vsphere_client.assert_called_once()
self.assertEqual(ret, {"Tags": self.list_tags_return})
def test_list_tags_client_verify_ssl(self):
for verify_ssl in [True, False]:
details = self.details.copy()
if verify_ssl is not None:
details["verify_ssl"] = verify_ssl
else:
verify_ssl = True
get_details = MagicMock(return_value=details)
# Mock CreateSpec object and create objects
mock_client = Mock(
tagging=Mock(Tag=Mock(list=Mock(return_value=self.list_tags_return)))
)
# Start patching each external API return with Mock Objects
with patch.object(
vsphere, "get_proxy_type", return_value="vcenter"
) as get_proxy_type:
with patch.object(
vsphere, "_get_proxy_connection_details", return_value=[]
) as get_proxy_connection:
with patch.object(
salt.utils.vmware, "get_service_instance", return_value=None
) as get_service_instance:
with patch.dict(
vsphere.__salt__,
{"vcenter.get_details": get_details},
clear=True,
) as get_vcenter_details:
with patch.object(
salt.utils.vmware,
"get_vsphere_client",
return_value=mock_client,
) as get_vsphere_client:
# Check function calls and return
ret = vsphere.list_tags()
self.assertEqual(ret, {"Tags": self.list_tags_return})
self.assertEqual(
get_vsphere_client.call_args_list,
[
call(
ca_bundle=None,
password=None,
server=None,
username=None,
verify_ssl=verify_ssl,
)
],
)
def test_list_attached_tags_client_none(self):
get_details = MagicMock(return_value=self.details)
@ -3036,50 +3170,72 @@ class TestVSphereTagging(TestCase, LoaderModuleMockMixin):
self.assertEqual(ret, {"Attached tags": None})
def test_list_attached_tags_client(self):
get_details = MagicMock(return_value=self.details)
for verify_ssl in [True, False, None]:
details = self.details.copy()
if verify_ssl is None:
verify_ssl = True
else:
details["verify_ssl"] = verify_ssl
get_details = MagicMock(return_value=details)
# Mock CreateSpec object and create objects
mock_client = Mock(
tagging=Mock(
TagAssociation=Mock(
list_attached_tags=Mock(return_value=self.list_attached_tags_return)
# Mock CreateSpec object and create objects
mock_client = Mock(
tagging=Mock(
TagAssociation=Mock(
list_attached_tags=Mock(
return_value=self.list_attached_tags_return
)
)
)
)
)
# Start patching each external API return with Mock Objects
with patch.object(
vsphere, "get_proxy_type", return_value="vcenter"
) as get_proxy_type:
# Start patching each external API return with Mock Objects
with patch.object(
vsphere, "_get_proxy_connection_details", return_value=[]
) as get_proxy_connection:
vsphere, "get_proxy_type", return_value="vcenter"
) as get_proxy_type:
with patch.object(
salt.utils.vmware, "get_service_instance", return_value=None
) as get_service_instance:
with patch.dict(
vsphere.__salt__,
{"vcenter.get_details": get_details},
clear=True,
) as get_vcenter_details:
with patch.object(
salt.utils.vmware,
"get_vsphere_client",
return_value=mock_client,
) as get_vsphere_client:
with patch.object(vsphere, "DynamicID") as dynamic_id:
# Check function calls and return
ret = vsphere.list_attached_tags(
self.func_attrs["object_id"]
)
get_proxy_type.assert_called_once()
get_proxy_connection.assert_called_once()
get_service_instance.assert_called_once()
get_vsphere_client.assert_called_once()
self.assertEqual(
ret,
{"Attached tags": self.list_attached_tags_return},
)
vsphere, "_get_proxy_connection_details", return_value=[]
) as get_proxy_connection:
with patch.object(
salt.utils.vmware, "get_service_instance", return_value=None
) as get_service_instance:
with patch.dict(
vsphere.__salt__,
{"vcenter.get_details": get_details},
clear=True,
) as get_vcenter_details:
with patch.object(
salt.utils.vmware,
"get_vsphere_client",
return_value=mock_client,
) as get_vsphere_client:
with patch.object(vsphere, "DynamicID") as dynamic_id:
# Check function calls and return
ret = vsphere.list_attached_tags(
self.func_attrs["object_id"]
)
get_proxy_type.assert_called_once()
get_proxy_connection.assert_called_once()
get_service_instance.assert_called_once()
get_vsphere_client.assert_called_once()
self.assertEqual(
ret,
{
"Attached tags": self.list_attached_tags_return
},
)
self.assertEqual(
get_vsphere_client.call_args_list,
[
call(
ca_bundle=None,
password=None,
server=None,
username=None,
verify_ssl=verify_ssl,
)
],
)
def test_attach_tags_client_none(self):
get_details = MagicMock(return_value=self.details)
@ -3114,48 +3270,266 @@ class TestVSphereTagging(TestCase, LoaderModuleMockMixin):
self.assertEqual(ret, {"Tag attached": None})
def test_attach_tags_client(self):
get_details = MagicMock(return_value=self.details)
for verify_ssl in [True, False, None]:
details = self.details.copy()
if verify_ssl is None:
verify_ssl = True
else:
details["verify_ssl"] = verify_ssl
get_details = MagicMock(return_value=details)
# Mock CreateSpec object and create objects
mock_client = Mock(
tagging=Mock(
TagAssociation=Mock(
attach=Mock(return_value=self.list_attached_tags_return)
# Mock CreateSpec object and create objects
mock_client = Mock(
tagging=Mock(
TagAssociation=Mock(
attach=Mock(return_value=self.list_attached_tags_return)
)
)
)
# Start patching each external API return with Mock Objects
with patch.object(
vsphere, "get_proxy_type", return_value="vcenter"
) as get_proxy_type:
with patch.object(
vsphere, "_get_proxy_connection_details", return_value=[]
) as get_proxy_connection:
with patch.object(
salt.utils.vmware, "get_service_instance", return_value=None
) as get_service_instance:
with patch.dict(
vsphere.__salt__,
{"vcenter.get_details": get_details},
clear=True,
) as get_vcenter_details:
with patch.object(
salt.utils.vmware,
"get_vsphere_client",
return_value=mock_client,
) as get_vsphere_client:
with patch.object(vsphere, "DynamicID") as dynamic_id:
# Check function calls and return
ret = vsphere.attach_tag(
object_id=self.func_attrs["object_id"],
tag_id=self.func_attrs["tag_id"],
)
get_proxy_type.assert_called_once()
get_proxy_connection.assert_called_once()
get_service_instance.assert_called_once()
get_vsphere_client.assert_called_once()
self.assertEqual(
get_vsphere_client.call_args_list,
[
call(
ca_bundle=None,
password=None,
server=None,
username=None,
verify_ssl=verify_ssl,
)
],
)
self.assertEqual(
ret,
{
"Tag attached": self.list_attached_tags_return
},
)
def test_get_client(self):
"""
test get_client when verify_ssl and ca_bundle are not passed
"""
mock_client = MagicMock(return_value=None)
patch_client = patch("salt.utils.vmware.get_vsphere_client", mock_client)
cert_path = "/test/ca-certificates.crt"
mock_ca = MagicMock(return_value=cert_path)
patch_ca = patch("salt.utils.http.get_ca_bundle", mock_ca)
mock_details = MagicMock(return_value=self.details)
patch_details = patch.dict(
vsphere.__salt__, {"vcenter.get_details": mock_details}
)
# Start patching each external API return with Mock Objects
with patch.object(
vsphere, "get_proxy_type", return_value="vcenter"
) as get_proxy_type:
with patch.object(
vsphere, "_get_proxy_connection_details", return_value=[]
) as get_proxy_connection:
with patch.object(
salt.utils.vmware, "get_service_instance", return_value=None
) as get_service_instance:
with patch.dict(
vsphere.__salt__,
{"vcenter.get_details": get_details},
clear=True,
) as get_vcenter_details:
with patch.object(
salt.utils.vmware,
"get_vsphere_client",
return_value=mock_client,
) as get_vsphere_client:
with patch.object(vsphere, "DynamicID") as dynamic_id:
# Check function calls and return
ret = vsphere.attach_tag(
object_id=self.func_attrs["object_id"],
tag_id=self.func_attrs["tag_id"],
)
get_proxy_type.assert_called_once()
get_proxy_connection.assert_called_once()
get_service_instance.assert_called_once()
get_vsphere_client.assert_called_once()
self.assertEqual(
ret,
{"Tag attached": self.list_attached_tags_return},
)
with patch_client, patch_ca, patch_details:
vsphere._get_client(
server="localhost", username="testuser", password="testpassword"
)
self.assertEqual(
mock_client.call_args_list,
[
call(
ca_bundle=None,
password="testpassword",
server="localhost",
username="testuser",
verify_ssl=True,
)
],
)
self.assertEqual(mock_details.assert_called_once(), None)
self.assertEqual(mock_ca.assert_not_called(), None)
def test_get_client_verify_ssl_false(self):
"""
test get_client when verify_ssl=False is set
"""
details = self.details.copy()
details["verify_ssl"] = False
mock_client = MagicMock(return_value=None)
patch_client = patch("salt.utils.vmware.get_vsphere_client", mock_client)
cert_path = "/test/ca-certificates.crt"
mock_ca = MagicMock(return_value=cert_path)
patch_ca = patch("salt.utils.http.get_ca_bundle", mock_ca)
mock_details = MagicMock(return_value=details)
patch_details = patch.dict(
vsphere.__salt__, {"vcenter.get_details": mock_details}
)
with patch_client, patch_ca, patch_details:
vsphere._get_client(
server="localhost", username="testuser", password="testpassword"
)
self.assertEqual(
mock_client.call_args_list,
[
call(
ca_bundle=None,
password="testpassword",
server="localhost",
username="testuser",
verify_ssl=False,
)
],
)
self.assertEqual(mock_details.assert_called_once(), None)
self.assertEqual(mock_ca.assert_not_called(), None)
def test_get_client_verify_ssl_false_ca_bundle(self):
"""
test get_client when verify_ssl=False and ca_bundle set
"""
details = self.details.copy()
details["verify_ssl"] = False
details["ca_bundle"] = "/tmp/test"
mock_client = MagicMock(return_value=None)
patch_client = patch("salt.utils.vmware.get_vsphere_client", mock_client)
cert_path = "/test/ca-certificates.crt"
mock_ca = MagicMock(return_value=cert_path)
patch_ca = patch("salt.utils.http.get_ca_bundle", mock_ca)
mock_details = MagicMock(return_value=details)
patch_details = patch.dict(
vsphere.__salt__, {"vcenter.get_details": mock_details}
)
with patch_client, patch_ca, patch_details:
self.assertFalse(
vsphere._get_client(
server="localhost", username="testuser", password="testpassword"
)
)
self.assertEqual(mock_details.assert_called_once(), None)
self.assertEqual(mock_ca.assert_not_called(), None)
def test_get_client_ca_bundle(self):
"""
test get_client when verify_ssl=False and ca_bundle set
"""
cert_path = "/test/ca-certificates.crt"
details = self.details.copy()
details["ca_bundle"] = cert_path
mock_client = MagicMock(return_value=None)
patch_client = patch("salt.utils.vmware.get_vsphere_client", mock_client)
mock_ca = MagicMock(return_value=cert_path)
patch_ca = patch("salt.utils.http.get_ca_bundle", mock_ca)
mock_details = MagicMock(return_value=details)
patch_details = patch.dict(
vsphere.__salt__, {"vcenter.get_details": mock_details}
)
with patch_client, patch_ca, patch_details:
vsphere._get_client(
server="localhost", username="testuser", password="testpassword"
)
self.assertEqual(
mock_client.call_args_list,
[
call(
ca_bundle=cert_path,
password="testpassword",
server="localhost",
username="testuser",
verify_ssl=True,
)
],
)
self.assertEqual(mock_details.assert_called_once(), None)
self.assertEqual(mock_ca.assert_called_once(), None)
self.assertEqual(mock_ca.call_args_list, [call({"ca_bundle": cert_path})])
class TestCertificateVerify(TestCase, LoaderModuleMockMixin):
def setup_loader_modules(self):
return {vsphere: {}}
def test_upload_ssh_key(self):
kwargs_values = [
("ssh_key", "TheSSHKeyFile"),
("ssh_key_file", "TheSSHKeyFile"),
]
certificate_verify_values = (None, True, False)
for kw_key, kw_value in kwargs_values:
kwargs = {kw_key: kw_value}
if kw_key == "ssh_key":
expected_kwargs = {"data": kw_value}
else:
expected_kwargs = {"data_file": kw_value, "data_render": False}
for certificate_verify_value in certificate_verify_values:
http_query_mock = MagicMock()
if certificate_verify_value is None:
certificate_verify_value = True
with patch("salt.utils.http.query", http_query_mock):
vsphere.upload_ssh_key(
HOST,
USER,
PASSWORD,
certificate_verify=certificate_verify_value,
**kwargs
)
http_query_mock.assert_called_once_with(
"https://1.2.3.4:443/host/ssh_root_authorized_keys",
method="PUT",
password="SuperSecret!",
status=True,
text=True,
username="root",
verify_ssl=certificate_verify_value,
**expected_kwargs
)
def test_get_ssh_key(self):
certificate_verify_values = (None, True, False)
for certificate_verify_value in certificate_verify_values:
http_query_mock = MagicMock()
if certificate_verify_value is None:
certificate_verify_value = True
with patch("salt.utils.http.query", http_query_mock):
vsphere.get_ssh_key(
HOST, USER, PASSWORD, certificate_verify=certificate_verify_value
)
http_query_mock.assert_called_once_with(
"https://1.2.3.4:443/host/ssh_root_authorized_keys",
method="GET",
password="SuperSecret!",
status=True,
text=True,
username="root",
verify_ssl=certificate_verify_value,
)

View file

@ -0,0 +1,54 @@
import salt.modules.config as config
import salt.modules.zenoss as zenoss
from tests.support.mixins import LoaderModuleMockMixin
from tests.support.mock import MagicMock, call, patch
from tests.support.unit import TestCase
class ZenossTestCase(TestCase, LoaderModuleMockMixin):
"""
Test cases for salt.modules.keystone
"""
def setup_loader_modules(self):
return {
zenoss: {"__salt__": {"config.option": config.option}},
config: {"__opts__": {}},
}
def test_zenoss_session(self):
"""
test zenoss._session when using verify_ssl
"""
zenoss_conf = {
"zenoss": {
"hostname": "https://test.zenoss.com",
"username": "admin",
"password": "test123",
}
}
for verify in [True, False, None]:
zenoss_conf["zenoss"]["verify_ssl"] = verify
if verify is None:
zenoss_conf["zenoss"].pop("verify_ssl")
verify = True
patch_opts = patch.dict(config.__opts__, zenoss_conf)
mock_http = MagicMock(return_value=None)
patch_http = patch("salt.utils.http.session", mock_http)
with patch_http, patch_opts:
zenoss._session()
self.assertEqual(
mock_http.call_args_list,
[
call(
ca_bundle=None,
headers={"Content-type": "application/json; charset=utf-8"},
password="test123",
user="admin",
verify_ssl=verify,
)
],
)

View file

@ -1,20 +1,114 @@
"""
tests.unit.proxy.test_cimc
~~~~~~~~~~~~~~~~~~~~~~~~~~
Unit tests for the cimc proxy module
"""
import logging
import salt.exceptions
import salt.proxy.cimc as cimc
from tests.support.mixins import LoaderModuleMockMixin
from tests.support.mock import patch
from tests.support.mock import MagicMock, patch
from tests.support.unit import TestCase
log = logging.getLogger(__name__)
LOGIN_RESPONSE = """\
<aaaLogin
response="yes"
outCookie="real-cookie"
outRefreshPeriod="600"
outPriv="admin">
</aaaLogin>"""
LOGOUT_RESPONSE = """\
<aaaLogout
cookie="real-cookie"
response="yes"
outStatus="success">
</aaaLogout>
"""
CONFIG_RESOLVE_CLASS_RESPONSE = """\
<configResolveClass
cookie="real-cookie"
response="yes"
classId="computeRackUnit">
<outConfig>
<computeRackUnit
dn="sys/rack-unit-1"
adminPower="policy"
availableMemory="16384"
model="R210-2121605W"
memorySpeed="1067"
name="UCS C210 M2"
numOfAdaptors="2"
numOfCores="8"
numOfCoresEnabled="8"
numOfCpus="2"
numOfEthHostIfs="5"
numOfFcHostIfs="2"
numOfThreads="16"
operPower="on"
originalUuid="00C9DE3C-370D-DF11-1186-6DD1393A608B"
presence="equipped"
serverID="1"
serial="QCI140205Z2"
totalMemory="16384"
usrLbl="C210 Row-B Rack-10"
uuid="00C9DE3C-370D-DF11-1186-6DD1393A608B"
vendor="Cisco Systems Inc" >
</computeRackUnit>
</outConfig>
</configResolveClass>
"""
CONFIG_CON_MO_RESPONSE = """\
<configConfMo
dn="sys/rack-unit-1/locator-led"
cookie="real-cookie"
response="yes">
<outConfig>
<equipmentLocatorLed
dn="sys/rack-unit-1/locator-led"
adminState="inactive"
color="unknown"
id="1"
name=""
operState="off">
</equipmentLocatorLed>
</outConfig>
</configConfMo>
"""
def http_query_response(*args, data=None, **kwargs):
log.debug(
"http_query_response side_effect; ARGS: %s // KWARGS: %s // DATA: %s",
args,
kwargs,
data,
)
if data.startswith("<aaaLogin"):
response = LOGIN_RESPONSE
elif data.startswith("<aaaLogout"):
response = LOGOUT_RESPONSE
elif data.startswith("<configResolveClass"):
response = CONFIG_RESOLVE_CLASS_RESPONSE
elif data.startswith("<configConfMo"):
response = CONFIG_CON_MO_RESPONSE
else:
response = ""
return {"text": response, "status": 200}
class CIMCProxyTestCase(TestCase, LoaderModuleMockMixin):
def setup_loader_modules(self):
return {cimc: {"DETAILS": {}, "__pillar__": {}}}
def setUp(self):
self.opts = {"proxy": {"username": "xxxx", "password": "xxx", "host": "cimc"}}
self.addCleanup(delattr, self, "opts")
def test_init(self):
# No host, returns False
@ -56,3 +150,294 @@ class CIMCProxyTestCase(TestCase, LoaderModuleMockMixin):
):
cimc._validate_response_code("404", "9zVG5U8DFZNsTR")
mock_logout.assert_called_once_with("9zVG5U8DFZNsTR")
class ValidateSSLTestCase(TestCase, LoaderModuleMockMixin):
def setup_loader_modules(self):
return {cimc: {}}
def setUp(self):
cimc.DETAILS.clear()
def test_init(self):
verify_ssl_values = (None, True, False)
for verify_ssl_value in verify_ssl_values:
cimc.DETAILS.clear()
opts = {
"proxy": {
"host": "TheHost",
"username": "TheUsername",
"password": "ThePassword",
"verify_ssl": verify_ssl_value,
}
}
http_query_mock = MagicMock(side_effect=http_query_response)
if verify_ssl_value is None:
expected_verify_ssl_value = True
else:
expected_verify_ssl_value = verify_ssl_value
log.debug(
"verify_ssl: %s // expected verify_ssl: %s",
verify_ssl_value,
expected_verify_ssl_value,
)
with patch.dict(cimc.__utils__, {"http.query": http_query_mock}):
cimc.init(opts)
for idx, call in enumerate(http_query_mock.mock_calls, 1):
condition = call.kwargs["verify_ssl"] is expected_verify_ssl_value
condition_error = "{} != {}; Call(number={}): {}".format(
idx, call, call.kwargs["verify_ssl"], expected_verify_ssl_value
)
self.assertTrue(condition, msg=condition_error)
def test_logon(self):
verify_ssl_values = (None, True, False)
for verify_ssl_value in verify_ssl_values:
cimc.DETAILS.clear()
opts = {
"proxy": {
"host": "TheHost",
"username": "TheUsername",
"password": "ThePassword",
"verify_ssl": verify_ssl_value,
}
}
http_query_mock = MagicMock(side_effect=http_query_response)
if verify_ssl_value is None:
expected_verify_ssl_value = True
else:
expected_verify_ssl_value = verify_ssl_value
# Let's init the proxy and ignore it's actions, this test is not about them
with patch(
"salt.proxy.cimc.get_config_resolver_class",
MagicMock(return_value=True),
):
cimc.init(opts)
log.debug(
"verify_ssl: %s // expected verify_ssl: %s",
verify_ssl_value,
expected_verify_ssl_value,
)
with patch.dict(cimc.__utils__, {"http.query": http_query_mock}):
cimc.logon()
for idx, call in enumerate(http_query_mock.mock_calls, 1):
condition = call.kwargs["verify_ssl"] is expected_verify_ssl_value
condition_error = "{} != {}; Call(number={}): {}".format(
idx, call, call.kwargs["verify_ssl"], expected_verify_ssl_value
)
self.assertTrue(condition, msg=condition_error)
def test_logout(self):
verify_ssl_values = (None, True, False)
for verify_ssl_value in verify_ssl_values:
cimc.DETAILS.clear()
opts = {
"proxy": {
"host": "TheHost",
"username": "TheUsername",
"password": "ThePassword",
"verify_ssl": verify_ssl_value,
}
}
http_query_mock = MagicMock(side_effect=http_query_response)
if verify_ssl_value is None:
expected_verify_ssl_value = True
else:
expected_verify_ssl_value = verify_ssl_value
# Let's init the proxy and ignore it's actions, this test is not about them
with patch(
"salt.proxy.cimc.get_config_resolver_class",
MagicMock(return_value=True),
):
cimc.init(opts)
log.debug(
"verify_ssl: %s // expected verify_ssl: %s",
verify_ssl_value,
expected_verify_ssl_value,
)
with patch.dict(cimc.__utils__, {"http.query": http_query_mock}):
cimc.logout()
for idx, call in enumerate(http_query_mock.mock_calls, 1):
condition = call.kwargs["verify_ssl"] is expected_verify_ssl_value
condition_error = "{} != {}; Call(number={}): {}".format(
idx, call, call.kwargs["verify_ssl"], expected_verify_ssl_value
)
self.assertTrue(condition, msg=condition_error)
def test_grains(self):
verify_ssl_values = (None, True, False)
for verify_ssl_value in verify_ssl_values:
cimc.DETAILS.clear()
opts = {
"proxy": {
"host": "TheHost",
"username": "TheUsername",
"password": "ThePassword",
"verify_ssl": verify_ssl_value,
}
}
http_query_mock = MagicMock(side_effect=http_query_response)
if verify_ssl_value is None:
expected_verify_ssl_value = True
else:
expected_verify_ssl_value = verify_ssl_value
# Let's init the proxy and ignore it's actions, this test is not about them
with patch(
"salt.proxy.cimc.get_config_resolver_class",
MagicMock(return_value=True),
):
cimc.init(opts)
log.debug(
"verify_ssl: %s // expected verify_ssl: %s",
verify_ssl_value,
expected_verify_ssl_value,
)
with patch.dict(cimc.__utils__, {"http.query": http_query_mock}):
cimc.grains()
for idx, call in enumerate(http_query_mock.mock_calls, 1):
condition = call.kwargs["verify_ssl"] is expected_verify_ssl_value
condition_error = "{} != {}; Call(number={}): {}".format(
idx, call, call.kwargs["verify_ssl"], expected_verify_ssl_value
)
self.assertTrue(condition, msg=condition_error)
def test_grains_refresh(self):
verify_ssl_values = (None, True, False)
for verify_ssl_value in verify_ssl_values:
cimc.DETAILS.clear()
opts = {
"proxy": {
"host": "TheHost",
"username": "TheUsername",
"password": "ThePassword",
"verify_ssl": verify_ssl_value,
}
}
http_query_mock = MagicMock(side_effect=http_query_response)
if verify_ssl_value is None:
expected_verify_ssl_value = True
else:
expected_verify_ssl_value = verify_ssl_value
# Let's init the proxy and ignore it's actions, this test is not about them
with patch(
"salt.proxy.cimc.get_config_resolver_class",
MagicMock(return_value=True),
):
cimc.init(opts)
log.debug(
"verify_ssl: %s // expected verify_ssl: %s",
verify_ssl_value,
expected_verify_ssl_value,
)
with patch.dict(cimc.__utils__, {"http.query": http_query_mock}):
cimc.grains_refresh()
for idx, call in enumerate(http_query_mock.mock_calls, 1):
condition = call.kwargs["verify_ssl"] is expected_verify_ssl_value
condition_error = "{} != {}; Call(number={}): {}".format(
idx, call, call.kwargs["verify_ssl"], expected_verify_ssl_value
)
self.assertTrue(condition, msg=condition_error)
def test_ping(self):
verify_ssl_values = (None, True, False)
for verify_ssl_value in verify_ssl_values:
cimc.DETAILS.clear()
opts = {
"proxy": {
"host": "TheHost",
"username": "TheUsername",
"password": "ThePassword",
"verify_ssl": verify_ssl_value,
}
}
http_query_mock = MagicMock(side_effect=http_query_response)
if verify_ssl_value is None:
expected_verify_ssl_value = True
else:
expected_verify_ssl_value = verify_ssl_value
# Let's init the proxy and ignore it's actions, this test is not about them
with patch(
"salt.proxy.cimc.get_config_resolver_class",
MagicMock(return_value=True),
):
cimc.init(opts)
log.debug(
"verify_ssl: %s // expected verify_ssl: %s",
verify_ssl_value,
expected_verify_ssl_value,
)
with patch.dict(cimc.__utils__, {"http.query": http_query_mock}):
cimc.ping()
for idx, call in enumerate(http_query_mock.mock_calls, 1):
condition = call.kwargs["verify_ssl"] is expected_verify_ssl_value
condition_error = "{} != {}; Call(number={}): {}".format(
idx, call, call.kwargs["verify_ssl"], expected_verify_ssl_value
)
self.assertTrue(condition, msg=condition_error)
def test_set_config_modify(self):
verify_ssl_values = (None, True, False)
for verify_ssl_value in verify_ssl_values:
cimc.DETAILS.clear()
opts = {
"proxy": {
"host": "TheHost",
"username": "TheUsername",
"password": "ThePassword",
"verify_ssl": verify_ssl_value,
}
}
http_query_mock = MagicMock(side_effect=http_query_response)
if verify_ssl_value is None:
expected_verify_ssl_value = True
else:
expected_verify_ssl_value = verify_ssl_value
# Let's init the proxy and ignore it's actions, this test is not about them
with patch(
"salt.proxy.cimc.get_config_resolver_class",
MagicMock(return_value=True),
):
cimc.init(opts)
log.debug(
"verify_ssl: %s // expected verify_ssl: %s",
verify_ssl_value,
expected_verify_ssl_value,
)
with patch.dict(cimc.__utils__, {"http.query": http_query_mock}):
cimc.set_config_modify(
dn="sys/rack-unit-1/locator-led",
inconfig="<inConfig><equipmentLocatorLed adminState='on' dn='sys/rack-unit-1/locator-led'></equipmentLocatorLed></inConfig>",
)
for idx, call in enumerate(http_query_mock.mock_calls, 1):
condition = call.kwargs["verify_ssl"] is expected_verify_ssl_value
condition_error = "{} != {}; Call(number={}): {}".format(
idx, call, call.kwargs["verify_ssl"], expected_verify_ssl_value
)
self.assertTrue(condition, msg=condition_error)

View file

@ -0,0 +1,46 @@
import salt.proxy.panos as panos
from tests.support.mixins import LoaderModuleMockMixin
from tests.support.mock import MagicMock, call, patch
from tests.support.unit import TestCase
class PanosProxyTestCase(TestCase, LoaderModuleMockMixin):
def setup_loader_modules(self):
return {panos: {"DETAILS": {}, "__pillar__": {}}}
def setUp(self):
self.opts = {
"proxy": {"proxytype": "panos", "host": "hosturl.com", "apikey": "api_key"}
}
def test_init(self):
for verify in [True, False, None]:
self.opts["proxy"]["verify_ssl"] = verify
if verify is None:
self.opts["proxy"].pop("verify_ssl")
verify = True
mock_http = MagicMock(
return_value={"status": 200, "text": "<data>some_test_data</data>"}
)
patch_http = patch.dict(panos.__utils__, {"http.query": mock_http})
with patch_http:
panos.init(self.opts)
self.assertEqual(
mock_http.call_args_list,
[
call(
"https://hosturl.com/api/",
data={
"type": "op",
"cmd": "<show><system><info></info></system></show>",
"key": "api_key",
},
decode=True,
decode_type="plain",
method="POST",
raise_error=True,
status=True,
verify_ssl=verify,
)
],
)

View file

@ -0,0 +1,98 @@
"""
tests.unit.returners.test_splunk
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Unit tests for the splunk returner
"""
import json
import logging
import salt.modules.config as config
import salt.returners.splunk as splunk
from tests.support.mixins import LoaderModuleMockMixin
from tests.support.mock import MagicMock, patch
from tests.support.unit import TestCase
log = logging.getLogger(__name__)
class SplunkReturnerTest(TestCase, LoaderModuleMockMixin):
def setup_loader_modules(self):
opts = {
"splunk_http_forwarder": {
"token": "TheToken",
"indexer": "the.splunk.domain",
"index": "TheIndex",
"sourcetype": "TheSourceType",
}
}
return {
splunk: {"__opts__": opts, "__salt__": {"config.get": config.get}},
config: {"__opts__": opts},
}
def test_verify_ssl_defaults_to_true(self):
payload = {"some": "payload"}
requests_post = MagicMock()
ts = 1234565789
host = "TheHostName"
data = {
"time": str(ts),
"index": "TheIndex",
"sourcetype": "TheSourceType",
"event": payload,
"host": host,
}
with patch(
"salt.returners.splunk.time.time", MagicMock(return_value=ts)
), patch(
"salt.returners.splunk.socket.gethostname", MagicMock(return_value=host)
), patch(
"requests.post", requests_post
):
splunk.returner(payload.copy())
assert json.loads(requests_post.call_args_list[0][1]["data"]) == data
assert requests_post.call_args_list[0][1]["verify"]
assert requests_post.call_args_list[0][1]["headers"] == {
"Authorization": "Splunk TheToken"
}
assert (
requests_post.call_args_list[0][0][0]
== "https://the.splunk.domain:8088/services/collector/event"
)
def test_verify_ssl(self):
payload = {"some": "payload"}
verify_ssl_values = [True, False, None]
payload = {"some": "payload"}
ts = 1234565789
host = "TheHostName"
data = {
"time": str(ts),
"index": "TheIndex",
"sourcetype": "TheSourceType",
"event": payload,
"host": host,
}
for verify_ssl in verify_ssl_values:
requests_post = MagicMock()
with patch(
"salt.returners.splunk.time.time", MagicMock(return_value=ts)
), patch(
"salt.returners.splunk.socket.gethostname", MagicMock(return_value=host)
), patch(
"requests.post", requests_post
), patch.dict(
splunk.__opts__["splunk_http_forwarder"], verify_ssl=verify_ssl
):
splunk.returner(payload.copy())
assert json.loads(requests_post.call_args_list[0][1]["data"]) == data
assert requests_post.call_args_list[0][1]["verify"] == verify_ssl
assert requests_post.call_args_list[0][1]["headers"] == {
"Authorization": "Splunk TheToken"
}
assert (
requests_post.call_args_list[0][0][0]
== "https://the.splunk.domain:8088/services/collector/event"
)

View file

@ -0,0 +1,106 @@
"""
tests.unit.runners.test_asam
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Unit tests for the asam runner
"""
import logging
import salt.runners.asam as asam
from tests.support.mixins import LoaderModuleMockMixin
from tests.support.mock import MagicMock, patch
from tests.support.unit import TestCase
log = logging.getLogger(__name__)
class AsamRunnerVerifySslTest(TestCase, LoaderModuleMockMixin):
def setup_loader_modules(self):
opts = {
"asam": {
"prov1.domain.com": {
"username": "TheUsername",
"password": "ThePassword",
}
}
}
return {asam: {"__opts__": opts}}
def test_add_platform(self):
parse_html_content = MagicMock()
get_platform_set_name = MagicMock(return_value="plat-foo")
requests_mock = MagicMock()
# remove_platform
with patch("salt.runners.asam._parse_html_content", parse_html_content), patch(
"salt.runners.asam._get_platformset_name", get_platform_set_name
), patch("salt.runners.asam.requests.post", requests_mock):
asam.add_platform("plat-foo-2", "plat-foo", "prov1.domain.com")
requests_mock.assert_called_with(
"https://prov1.domain.com:3451/config/PlatformSetConfig.html",
auth=("TheUsername", "ThePassword"),
data={"manual": "false"},
verify=True,
)
def test_remove_platform(self):
parse_html_content = MagicMock()
get_platform_set_name = MagicMock(return_value="plat-foo")
requests_mock = MagicMock()
# remove_platform
with patch("salt.runners.asam._parse_html_content", parse_html_content), patch(
"salt.runners.asam._get_platformset_name", get_platform_set_name
), patch("salt.runners.asam.requests.post", requests_mock):
asam.remove_platform("plat-foo", "prov1.domain.com")
requests_mock.assert_called_with(
"https://prov1.domain.com:3451/config/PlatformConfig.html",
auth=("TheUsername", "ThePassword"),
data={
"manual": "false",
"platformName": "plat-foo",
"platformSetName": "plat-foo",
"postType": "platformRemove",
"Submit": "Yes",
},
verify=True,
)
def test_list_platforms(self):
parse_html_content = MagicMock()
get_platforms = MagicMock(return_value=["plat-foo", "plat-bar"])
requests_mock = MagicMock()
# remove_platform
with patch("salt.runners.asam._parse_html_content", parse_html_content), patch(
"salt.runners.asam._get_platforms", get_platforms
), patch("salt.runners.asam.requests.post", requests_mock):
asam.list_platforms("prov1.domain.com")
requests_mock.assert_called_with(
"https://prov1.domain.com:3451/config/PlatformConfig.html",
auth=("TheUsername", "ThePassword"),
data={"manual": "false"},
verify=True,
)
def test_list_platform_sets(self):
parse_html_content = MagicMock()
get_platform_sets = MagicMock(return_value=["plat-foo", "plat-bar"])
requests_mock = MagicMock()
# remove_platform
with patch("salt.runners.asam._parse_html_content", parse_html_content), patch(
"salt.runners.asam._get_platforms", get_platform_sets
), patch("salt.runners.asam.requests.post", requests_mock):
asam.list_platform_sets("prov1.domain.com")
requests_mock.assert_called_with(
"https://prov1.domain.com:3451/config/PlatformSetConfig.html",
auth=("TheUsername", "ThePassword"),
data={"manual": "false"},
verify=True,
)

View file

@ -0,0 +1,72 @@
"""
tests.unit.states.test_esxi
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Unit tests for the esxi state module
"""
import salt.modules.vsphere as vsphere
import salt.states.esxi as esxi
from tests.support.case import TestCase
from tests.support.mixins import LoaderModuleMockMixin
from tests.support.mock import MagicMock, patch
class TestCertificateVerify(TestCase, LoaderModuleMockMixin):
def setup_loader_modules(self):
return {
esxi: {
"__opts__": {"test": False},
"__pillar__": {"proxy": {"host": "hostname", "proxytype": "esxi"}},
},
vsphere: {},
}
def test_certificate_verify(self):
kwargs_values = [
("ssh_key", "TheSSHKeyFile"),
("ssh_key_file", "TheSSHKeyFile"),
]
certificate_verify_values = (None, True, False)
for kw_key, kw_value in kwargs_values:
def esxi_cmd_wrapper(target, *args, **kwargs):
# The esxi salt module just wraps the call to the esxi proxy
# module which in turn calls the target method on the vsphere
# execution moduile.
# That would be a TON of mocking, so we just bypass all of that
# wrapping
if target == "upload_ssh_key":
return vsphere.upload_ssh_key(
"1.2.3.4", "root", "SuperSecret!", *args, **kwargs
)
return {"hostname": {}}
service_running = patch.dict(esxi.__salt__, {"esxi.cmd": esxi_cmd_wrapper})
kwargs = {kw_key: kw_value}
if kw_key == "ssh_key":
expected_kwargs = {"data": kw_value}
else:
expected_kwargs = {"data_file": kw_value, "data_render": False}
for certificate_verify_value in certificate_verify_values:
http_query_mock = MagicMock()
if certificate_verify_value is None:
certificate_verify_value = True
with patch("salt.utils.http.query", http_query_mock), service_running:
esxi.ssh_configured(
"blah",
service_running=True,
service_restart=False,
certificate_verify=certificate_verify_value,
**kwargs
)
http_query_mock.assert_called_once_with(
"https://1.2.3.4:443/host/ssh_root_authorized_keys",
method="PUT",
password="SuperSecret!",
status=True,
text=True,
username="root",
verify_ssl=certificate_verify_value,
**expected_kwargs
)

View file

@ -4,7 +4,6 @@
Tests for cluster related functions in salt.utils.vmware
"""
import base64
import logging
import ssl
@ -1690,13 +1689,13 @@ class PrivateGetServiceInstanceTestCase(TestCase):
mechanism="sspi",
)
def test_second_attempt_successful_connection(self):
def test_first_attempt_successful_connection_verify_ssl_false(self):
with patch("ssl.SSLContext", MagicMock()), patch(
"ssl._create_unverified_context", MagicMock()
):
exc = vim.fault.HostConnectFault()
exc.msg = "[SSL: CERTIFICATE_VERIFY_FAILED]"
mock_sc = MagicMock(side_effect=[exc, None])
mock_sc = MagicMock(side_effect=[None])
mock_ssl = MagicMock()
with patch("salt.utils.vmware.SmartConnect", mock_sc):
@ -1711,19 +1710,11 @@ class PrivateGetServiceInstanceTestCase(TestCase):
mechanism="sspi",
principal="fake_principal",
domain="fake_domain",
verify_ssl=False,
)
mock_ssl.assert_called_once_with()
calls = [
call(
host="fake_host.fqdn",
user="fake_username",
pwd="fake_password",
protocol="fake_protocol",
port=1,
b64token="fake_token",
mechanism="sspi",
),
call(
host="fake_host.fqdn",
user="fake_username",
@ -1737,21 +1728,18 @@ class PrivateGetServiceInstanceTestCase(TestCase):
]
mock_sc.assert_has_calls(calls)
def test_third_attempt_successful_connection(self):
def test_second_attempt_successful_connection_verify_ssl_false(self):
with patch("ssl.SSLContext", MagicMock()), patch(
"ssl._create_unverified_context", MagicMock()
):
exc = vim.fault.HostConnectFault()
exc.msg = "[SSL: CERTIFICATE_VERIFY_FAILED]"
exc2 = Exception("certificate verify failed")
mock_sc = MagicMock(side_effect=[exc, exc2, None])
exc = Exception("certificate verify failed")
mock_sc = MagicMock(side_effect=[exc, None])
mock_ssl_unverif = MagicMock()
mock_ssl_context = MagicMock()
with patch("salt.utils.vmware.SmartConnect", mock_sc):
with patch("ssl._create_unverified_context", mock_ssl_unverif):
with patch("ssl.SSLContext", mock_ssl_context):
salt.utils.vmware._get_service_instance(
host="fake_host.fqdn",
username="fake_username",
@ -1761,20 +1749,12 @@ class PrivateGetServiceInstanceTestCase(TestCase):
mechanism="sspi",
principal="fake_principal",
domain="fake_domain",
verify_ssl=False,
)
mock_ssl_context.assert_called_once_with(ssl.PROTOCOL_TLSv1)
mock_ssl_unverif.assert_called_once_with()
calls = [
call(
host="fake_host.fqdn",
user="fake_username",
pwd="fake_password",
protocol="fake_protocol",
port=1,
b64token="fake_token",
mechanism="sspi",
),
call(
host="fake_host.fqdn",
user="fake_username",
@ -1798,7 +1778,7 @@ class PrivateGetServiceInstanceTestCase(TestCase):
]
mock_sc.assert_has_calls(calls)
def test_first_attempt_unsuccessful_connection_default_error(self):
def test_attempt_unsuccessful_connection_default_error(self):
exc = Exception("Exception")
mock_sc = MagicMock(side_effect=exc)
@ -1815,13 +1795,12 @@ class PrivateGetServiceInstanceTestCase(TestCase):
domain="fake_domain",
)
self.assertEqual(mock_sc.call_count, 1)
self.assertIn(
"Could not connect to host 'fake_host.fqdn'",
excinfo.Exception.message,
)
self.assertEqual(mock_sc.call_count, 1)
self.assertIn(
"Could not connect to host 'fake_host.fqdn'", excinfo.exception.message,
)
def test_first_attempt_unsuccessful_connection_vim_fault(self):
def test_attempt_unsuccessful_connection_vim_fault(self):
exc = vim.fault.VimFault()
exc.msg = "VimFault"
mock_sc = MagicMock(side_effect=exc)
@ -1839,15 +1818,15 @@ class PrivateGetServiceInstanceTestCase(TestCase):
domain="fake_domain",
)
self.assertEqual(mock_sc.call_count, 1)
self.assertEqual("VimFault", excinfo.Exception.message)
self.assertEqual(mock_sc.call_count, 1)
self.assertEqual("VimFault", excinfo.exception.message)
def test_second_attempt_unsuccsessful_connection_default_error(self):
def test_first_attempt_unsuccsessful_connection_default_error(self):
with patch("ssl.SSLContext", MagicMock()), patch(
"ssl._create_unverified_context", MagicMock()
):
exc = vim.fault.HostConnectFault()
exc.msg = "[SSL: CERTIFICATE_VERIFY_FAILED]"
exc.msg = "certificate verify failed"
exc2 = Exception("Exception")
mock_sc = MagicMock(side_effect=[exc, exc2])
@ -1862,22 +1841,47 @@ class PrivateGetServiceInstanceTestCase(TestCase):
mechanism="sspi",
principal="fake_principal",
domain="fake_domain",
verify_ssl=False,
)
self.assertEqual(mock_sc.call_count, 2)
self.assertIn(
"Could not connect to host 'fake_host.fqdn'",
excinfo.Exception.message,
self.assertEqual(mock_sc.call_count, 2)
self.assertIn(
"Could not connect to host 'fake_host.fqdn'", excinfo.exception.message
)
def test_first_attempt_unsuccsessful_cannot_vim_fault_verify_ssl(self):
with patch("ssl.SSLContext", MagicMock()), patch(
"ssl._create_unverified_context", MagicMock()
):
exc = vim.fault.VimFault()
exc.msg = "VimFault"
mock_sc = MagicMock(side_effect=[exc])
with patch("salt.utils.vmware.SmartConnect", mock_sc):
with self.assertRaises(VMwareConnectionError) as excinfo:
salt.utils.vmware._get_service_instance(
host="fake_host.fqdn",
username="fake_username",
password="fake_password",
protocol="fake_protocol",
port=1,
mechanism="sspi",
principal="fake_principal",
domain="fake_domain",
verify_ssl=False,
)
def test_second_attempt_unsuccsessful_connection_vim_fault(self):
self.assertEqual(mock_sc.call_count, 1)
self.assertIn("VimFault", excinfo.exception.message)
def test_third_attempt_unsuccessful_connection_detault_error(self):
with patch("ssl.SSLContext", MagicMock()), patch(
"ssl._create_unverified_context", MagicMock()
):
exc = vim.fault.HostConnectFault()
exc.msg = "[SSL: CERTIFICATE_VERIFY_FAILED]"
exc2 = vim.fault.VimFault()
exc2.msg = "VimFault"
exc.msg = "certificate verify failed"
exc2 = Exception("Exception")
mock_sc = MagicMock(side_effect=[exc, exc2])
with patch("salt.utils.vmware.SmartConnect", mock_sc):
@ -1891,20 +1895,21 @@ class PrivateGetServiceInstanceTestCase(TestCase):
mechanism="sspi",
principal="fake_principal",
domain="fake_domain",
verify_ssl=False,
)
self.assertEqual(mock_sc.call_count, 2)
self.assertIn("VimFault", excinfo.Exception.message)
self.assertEqual(mock_sc.call_count, 2)
self.assertIn(
"Could not connect to host 'fake_host.fqdn", excinfo.exception.message
)
def test_third_attempt_unsuccessful_connection_detault_error(self):
def test_second_attempt_unsuccessful_connection_vim_fault(self):
with patch("ssl.SSLContext", MagicMock()), patch(
"ssl._create_unverified_context", MagicMock()
):
exc = vim.fault.HostConnectFault()
exc.msg = "[SSL: CERTIFICATE_VERIFY_FAILED]"
exc2 = Exception("certificate verify failed")
exc3 = Exception("Exception")
mock_sc = MagicMock(side_effect=[exc, exc2, exc3])
exc = vim.fault.VimFault()
exc.msg = "VimFault"
mock_sc = MagicMock(side_effect=[exc])
with patch("salt.utils.vmware.SmartConnect", mock_sc):
with self.assertRaises(VMwareConnectionError) as excinfo:
@ -1917,37 +1922,11 @@ class PrivateGetServiceInstanceTestCase(TestCase):
mechanism="sspi",
principal="fake_principal",
domain="fake_domain",
verify_ssl=False,
)
self.assertEqual(mock_sc.call_count, 3)
self.assertIn("Exception", excinfo.Exception.message)
def test_third_attempt_unsuccessful_connection_vim_fault(self):
with patch("ssl.SSLContext", MagicMock()), patch(
"ssl._create_unverified_context", MagicMock()
):
exc = vim.fault.HostConnectFault()
exc.msg = "[SSL: CERTIFICATE_VERIFY_FAILED]"
exc2 = Exception("certificate verify failed")
exc3 = vim.fault.VimFault()
exc3.msg = "VimFault"
mock_sc = MagicMock(side_effect=[exc, exc2, exc3])
with patch("salt.utils.vmware.SmartConnect", mock_sc):
with self.assertRaises(VMwareConnectionError) as excinfo:
salt.utils.vmware._get_service_instance(
host="fake_host.fqdn",
username="fake_username",
password="fake_password",
protocol="fake_protocol",
port=1,
mechanism="sspi",
principal="fake_principal",
domain="fake_domain",
)
self.assertEqual(mock_sc.call_count, 3)
self.assertIn("VimFault", excinfo.Exception.message)
self.assertEqual(mock_sc.call_count, 1)
self.assertIn("VimFault", excinfo.exception.message)
@skipIf(not HAS_PYVMOMI, "The 'pyvmomi' library is missing")
@ -1974,7 +1953,15 @@ class GetServiceInstanceTestCase(TestCase):
with patch("salt.utils.vmware._get_service_instance", mock_get_si):
salt.utils.vmware.get_service_instance(host="fake_host")
mock_get_si.assert_called_once_with(
"fake_host", None, None, "https", 443, "userpass", None, None
"fake_host",
None,
None,
"https",
443,
"userpass",
None,
None,
verify_ssl=True,
)
def test_no_cached_service_instance_same_host_on_proxy(self):
@ -2001,6 +1988,7 @@ class GetServiceInstanceTestCase(TestCase):
"fake_mechanism",
"fake_principal",
"fake_domain",
verify_ssl=True,
)
def test_cached_service_instance_different_host(self):
@ -2038,6 +2026,7 @@ class GetServiceInstanceTestCase(TestCase):
mechanism="fake_mechanism",
principal="fake_principal",
domain="fake_domain",
verify_ssl=True,
)
mock_get_si.assert_called_once_with(
"fake_host",
@ -2048,6 +2037,7 @@ class GetServiceInstanceTestCase(TestCase):
"fake_mechanism",
"fake_principal",
"fake_domain",
verify_ssl=True,
)
def test_unauthenticated_service_instance(self):