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 - id: pip-tools-compile
alias: compile-ci-linux-py3.5-zmq-requirements alias: compile-ci-linux-py3.5-zmq-requirements
name: Linux CI Py3.5 ZeroMQ 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 pass_filenames: false
args: args:
- -v - -v
@ -270,12 +270,13 @@ repos:
- --include=requirements/static/pkg/py{py_version}/linux.txt - --include=requirements/static/pkg/py{py_version}/linux.txt
- --include=requirements/pytest.txt - --include=requirements/pytest.txt
- --include=requirements/static/ci/common.in - --include=requirements/static/ci/common.in
- --include=requirements/static/ci/git-sources.txt
- requirements/static/ci/linux.in - requirements/static/ci/linux.in
- id: pip-tools-compile - id: pip-tools-compile
alias: compile-ci-linux-py3.6-zmq-requirements alias: compile-ci-linux-py3.6-zmq-requirements
name: Linux CI Py3.6 ZeroMQ 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 pass_filenames: false
args: args:
- -v - -v
@ -284,12 +285,13 @@ repos:
- --include=requirements/static/pkg/py{py_version}/linux.txt - --include=requirements/static/pkg/py{py_version}/linux.txt
- --include=requirements/pytest.txt - --include=requirements/pytest.txt
- --include=requirements/static/ci/common.in - --include=requirements/static/ci/common.in
- --include=requirements/static/ci/git-sources.txt
- requirements/static/ci/linux.in - requirements/static/ci/linux.in
- id: pip-tools-compile - id: pip-tools-compile
alias: compile-ci-linux-py3.7-zmq-requirements alias: compile-ci-linux-py3.7-zmq-requirements
name: Linux CI Py3.7 ZeroMQ 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 pass_filenames: false
args: args:
- -v - -v
@ -298,12 +300,13 @@ repos:
- --include=requirements/static/pkg/py{py_version}/linux.txt - --include=requirements/static/pkg/py{py_version}/linux.txt
- --include=requirements/pytest.txt - --include=requirements/pytest.txt
- --include=requirements/static/ci/common.in - --include=requirements/static/ci/common.in
- --include=requirements/static/ci/git-sources.txt
- requirements/static/ci/linux.in - requirements/static/ci/linux.in
- id: pip-tools-compile - id: pip-tools-compile
alias: compile-ci-linux-py3.8-zmq-requirements alias: compile-ci-linux-py3.8-zmq-requirements
name: Linux CI Py3.8 ZeroMQ 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 pass_filenames: false
args: args:
- -v - -v
@ -312,12 +315,13 @@ repos:
- --include=requirements/static/pkg/py{py_version}/linux.txt - --include=requirements/static/pkg/py{py_version}/linux.txt
- --include=requirements/pytest.txt - --include=requirements/pytest.txt
- --include=requirements/static/ci/common.in - --include=requirements/static/ci/common.in
- --include=requirements/static/ci/git-sources.txt
- requirements/static/ci/linux.in - requirements/static/ci/linux.in
- id: pip-tools-compile - id: pip-tools-compile
alias: compile-ci-linux-py3.9-zmq-requirements alias: compile-ci-linux-py3.9-zmq-requirements
name: Linux CI Py3.9 ZeroMQ 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 pass_filenames: false
args: args:
- -v - -v
@ -326,6 +330,7 @@ repos:
- --include=requirements/static/pkg/py{py_version}/linux.txt - --include=requirements/static/pkg/py{py_version}/linux.txt
- --include=requirements/pytest.txt - --include=requirements/pytest.txt
- --include=requirements/static/ci/common.in - --include=requirements/static/ci/common.in
- --include=requirements/static/ci/git-sources.txt
- requirements/static/ci/linux.in - requirements/static/ci/linux.in
- id: pip-tools-compile - id: pip-tools-compile

View file

@ -7,6 +7,42 @@ Versions are `MAJOR.PATCH`.
# Changelog # 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) Salt 3002.2 (2020-11-16)
======================== ========================
@ -273,6 +309,43 @@ Added
This flag will be deprecated in the Phosphorus release when this functionality This flag will be deprecated in the Phosphorus release when this functionality
becomes the default. (#58652) 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 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 - [#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) - 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 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 # This file is autogenerated by pip-compile
# To update, run: # 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 adal==1.2.3 # via azure-datalake-store, msrestazure
apache-libcloud==2.5.0 ; sys_platform != "win32" apache-libcloud==2.5.0 ; sys_platform != "win32"
appdirs==1.4.4 # via virtualenv 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 keyring==5.7.1
kubernetes==3.0.0 kubernetes==3.0.0
libnacl==1.7.1 ; sys_platform != "win32" and sys_platform != "darwin" 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 mako==1.1.0
markupsafe==1.1.1 markupsafe==1.1.1
mock==3.0.5 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 ncclient==0.6.4 # via junos-eznc
netaddr==0.7.19 # via junos-eznc netaddr==0.7.19 # via junos-eznc
networkx==2.4 # via cfn-lint 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 ntc-templates==1.4.0 # via junos-eznc
oauthlib==3.1.0 # via requests-oauthlib oauthlib==3.1.0 # via requests-oauthlib
oscrypto==1.2.0 # via certvalidator oscrypto==1.2.0 # via certvalidator
@ -218,6 +224,7 @@ smmap==3.0.4 # via gitdb
sqlparse==0.4.1 sqlparse==0.4.1
sshpubkeys==3.1.0 # via moto sshpubkeys==3.1.0 # via moto
strict-rfc3339==0.7 strict-rfc3339==0.7
suds-jurko==0.6 # via vsphere-automation-sdk
tempora==1.14.1 tempora==1.14.1
terminal==0.4.0 # via ntc-templates terminal==0.4.0 # via ntc-templates
textfsm==1.1.0 # via ntc-templates textfsm==1.1.0 # via ntc-templates
@ -225,8 +232,14 @@ timelib==0.2.5
toml==0.10.2 toml==0.10.2
transitions==0.8.1 # via junos-eznc transitions==0.8.1 # via junos-eznc
urllib3==1.24.2 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" vcert==0.7.3 ; sys_platform != "win32"
virtualenv==20.0.20 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 watchdog==0.9.0
websocket-client==0.40.0 # via docker, kubernetes websocket-client==0.40.0 # via docker, kubernetes
werkzeug==0.15.6 # via moto werkzeug==0.15.6 # via moto

View file

View file

@ -2,8 +2,10 @@
# This file is autogenerated by pip-compile # This file is autogenerated by pip-compile
# To update, run: # 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 adal==1.2.3 # via azure-datalake-store, msrestazure
apache-libcloud==2.5.0 ; sys_platform != "win32" apache-libcloud==2.5.0 ; sys_platform != "win32"
appdirs==1.4.4 # via virtualenv 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 keyring==5.7.1
kubernetes==3.0.0 kubernetes==3.0.0
libnacl==1.7.1 ; sys_platform != "win32" and sys_platform != "darwin" 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 mako==1.1.0
markupsafe==1.1.1 markupsafe==1.1.1
mock==3.0.5 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 ncclient==0.6.4 # via junos-eznc
netaddr==0.7.19 # via junos-eznc netaddr==0.7.19 # via junos-eznc
networkx==2.5 # via cfn-lint 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 ntc-templates==1.4.0 # via junos-eznc
oauthlib==3.1.0 # via requests-oauthlib oauthlib==3.1.0 # via requests-oauthlib
oscrypto==1.2.0 # via certvalidator oscrypto==1.2.0 # via certvalidator
@ -217,6 +223,7 @@ smmap==3.0.4 # via gitdb
sqlparse==0.4.1 sqlparse==0.4.1
sshpubkeys==3.1.0 # via moto sshpubkeys==3.1.0 # via moto
strict-rfc3339==0.7 strict-rfc3339==0.7
suds-jurko==0.6 # via vsphere-automation-sdk
tempora==1.14.1 tempora==1.14.1
terminal==0.4.0 # via ntc-templates terminal==0.4.0 # via ntc-templates
textfsm==1.1.0 # via ntc-templates textfsm==1.1.0 # via ntc-templates
@ -224,8 +231,14 @@ timelib==0.2.5
toml==0.10.2 toml==0.10.2
transitions==0.8.1 # via junos-eznc transitions==0.8.1 # via junos-eznc
urllib3==1.24.2 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" vcert==0.7.3 ; sys_platform != "win32"
virtualenv==20.0.20 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 watchdog==0.9.0
websocket-client==0.40.0 # via docker, kubernetes websocket-client==0.40.0 # via docker, kubernetes
werkzeug==0.15.6 # via moto werkzeug==0.15.6 # via moto

View file

@ -2,8 +2,10 @@
# This file is autogenerated by pip-compile # This file is autogenerated by pip-compile
# To update, run: # 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 adal==1.2.3 # via azure-datalake-store, msrestazure
apache-libcloud==2.5.0 ; sys_platform != "win32" apache-libcloud==2.5.0 ; sys_platform != "win32"
appdirs==1.4.4 # via virtualenv 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 keyring==5.7.1
kubernetes==3.0.0 kubernetes==3.0.0
libnacl==1.7.1 ; sys_platform != "win32" and sys_platform != "darwin" 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 mako==1.1.0
markupsafe==1.1.1 markupsafe==1.1.1
mock==3.0.5 mock==3.0.5
@ -166,6 +168,10 @@ ncclient==0.6.4 # via junos-eznc
netaddr==0.7.19 # via junos-eznc, napalm, pyeapi netaddr==0.7.19 # via junos-eznc, napalm, pyeapi
netmiko==3.2.0 # via napalm netmiko==3.2.0 # via napalm
networkx==2.5 # via cfn-lint 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 ntc-templates==1.4.0 # via junos-eznc
oauthlib==3.1.0 # via requests-oauthlib oauthlib==3.1.0 # via requests-oauthlib
oscrypto==1.2.0 # via certvalidator oscrypto==1.2.0 # via certvalidator
@ -218,6 +224,7 @@ smmap==3.0.4 # via gitdb
sqlparse==0.4.1 sqlparse==0.4.1
sshpubkeys==3.1.0 # via moto sshpubkeys==3.1.0 # via moto
strict-rfc3339==0.7 strict-rfc3339==0.7
suds-jurko==0.6 # via vsphere-automation-sdk
tempora==1.14.1 tempora==1.14.1
terminal==0.4.0 # via ntc-templates terminal==0.4.0 # via ntc-templates
textfsm==1.1.0 # via napalm, netmiko, ntc-templates textfsm==1.1.0 # via napalm, netmiko, ntc-templates
@ -225,8 +232,14 @@ timelib==0.2.5
toml==0.10.2 toml==0.10.2
transitions==0.8.1 # via junos-eznc transitions==0.8.1 # via junos-eznc
urllib3==1.24.2 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" vcert==0.7.3 ; sys_platform != "win32"
virtualenv==20.0.20 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 watchdog==0.9.0
websocket-client==0.40.0 # via docker, kubernetes websocket-client==0.40.0 # via docker, kubernetes
werkzeug==0.15.6 # via moto werkzeug==0.15.6 # via moto

View file

@ -2,8 +2,10 @@
# This file is autogenerated by pip-compile # This file is autogenerated by pip-compile
# To update, run: # 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 adal==1.2.3 # via azure-datalake-store, msrestazure
apache-libcloud==2.5.0 ; sys_platform != "win32" apache-libcloud==2.5.0 ; sys_platform != "win32"
appdirs==1.4.4 # via virtualenv 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 keyring==5.7.1
kubernetes==3.0.0 kubernetes==3.0.0
libnacl==1.7.1 ; sys_platform != "win32" and sys_platform != "darwin" 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 mako==1.1.0
markupsafe==1.1.1 markupsafe==1.1.1
mock==3.0.5 mock==3.0.5
@ -165,6 +167,10 @@ ncclient==0.6.4 # via junos-eznc
netaddr==0.7.19 # via junos-eznc, napalm, pyeapi netaddr==0.7.19 # via junos-eznc, napalm, pyeapi
netmiko==3.2.0 # via napalm netmiko==3.2.0 # via napalm
networkx==2.5 # via cfn-lint 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 ntc-templates==1.4.1 # via junos-eznc
oauthlib==3.1.0 # via requests-oauthlib oauthlib==3.1.0 # via requests-oauthlib
oscrypto==1.2.0 # via certvalidator oscrypto==1.2.0 # via certvalidator
@ -217,6 +223,7 @@ smmap==3.0.4 # via gitdb
sqlparse==0.4.1 sqlparse==0.4.1
sshpubkeys==3.1.0 # via moto sshpubkeys==3.1.0 # via moto
strict-rfc3339==0.7 strict-rfc3339==0.7
suds-jurko==0.6 # via vsphere-automation-sdk
tempora==1.14.1 tempora==1.14.1
terminal==0.4.0 # via ntc-templates terminal==0.4.0 # via ntc-templates
textfsm==1.1.0 # via napalm, netmiko, ntc-templates textfsm==1.1.0 # via napalm, netmiko, ntc-templates
@ -224,8 +231,14 @@ timelib==0.2.5
toml==0.10.2 toml==0.10.2
transitions==0.8.1 # via junos-eznc transitions==0.8.1 # via junos-eznc
urllib3==1.24.2 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" vcert==0.7.3 ; sys_platform != "win32"
virtualenv==20.0.20 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 watchdog==0.9.0
websocket-client==0.40.0 # via docker, kubernetes websocket-client==0.40.0 # via docker, kubernetes
werkzeug==0.15.6 # via moto werkzeug==0.15.6 # via moto

View file

@ -2,8 +2,10 @@
# This file is autogenerated by pip-compile # This file is autogenerated by pip-compile
# To update, run: # 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 adal==1.2.3 # via azure-datalake-store, msrestazure
apache-libcloud==2.5.0 ; sys_platform != "win32" apache-libcloud==2.5.0 ; sys_platform != "win32"
appdirs==1.4.4 # via virtualenv 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 keyring==5.7.1
kubernetes==3.0.0 kubernetes==3.0.0
libnacl==1.7.1 ; sys_platform != "win32" and sys_platform != "darwin" 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 mako==1.1.0
markupsafe==1.1.1 markupsafe==1.1.1
mock==3.0.5 mock==3.0.5
@ -166,6 +168,10 @@ ncclient==0.6.4 # via junos-eznc
netaddr==0.7.19 # via junos-eznc, napalm, pyeapi netaddr==0.7.19 # via junos-eznc, napalm, pyeapi
netmiko==3.2.0 # via napalm netmiko==3.2.0 # via napalm
networkx==2.5 # via cfn-lint 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 ntc-templates==1.4.1 # via junos-eznc
oauthlib==3.1.0 # via requests-oauthlib oauthlib==3.1.0 # via requests-oauthlib
oscrypto==1.2.0 # via certvalidator oscrypto==1.2.0 # via certvalidator
@ -218,6 +224,7 @@ smmap==3.0.4 # via gitdb
sqlparse==0.4.1 sqlparse==0.4.1
sshpubkeys==3.1.0 # via moto sshpubkeys==3.1.0 # via moto
strict-rfc3339==0.7 strict-rfc3339==0.7
suds-jurko==0.6 # via vsphere-automation-sdk
tempora==1.14.1 tempora==1.14.1
terminal==0.4.0 # via ntc-templates terminal==0.4.0 # via ntc-templates
textfsm==1.1.0 # via napalm, netmiko, ntc-templates textfsm==1.1.0 # via napalm, netmiko, ntc-templates
@ -225,8 +232,14 @@ timelib==0.2.5
toml==0.10.2 toml==0.10.2
transitions==0.8.1 # via junos-eznc transitions==0.8.1 # via junos-eznc
urllib3==1.24.2 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" vcert==0.7.3 ; sys_platform != "win32"
virtualenv==20.0.20 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 watchdog==0.9.0
websocket-client==0.40.0 # via docker, kubernetes websocket-client==0.40.0 # via docker, kubernetes
werkzeug==0.15.6 # via moto werkzeug==0.15.6 # via moto

View file

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

View file

@ -478,10 +478,10 @@ class AsyncClientMixin:
client = None client = None
tag_prefix = 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 Run this method in a multiprocess target to execute the function on the
multiprocess and fire the return data on the event bus master and fire the return data on the event bus
""" """
if daemonize and not salt.utils.platform.is_windows(): if daemonize and not salt.utils.platform.is_windows():
# Shutdown the multiprocessing before daemonizing # Shutdown the multiprocessing before daemonizing
@ -497,7 +497,52 @@ class AsyncClientMixin:
low["__user__"] = user low["__user__"] = user
low["__tag__"] = tag 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): def cmd_async(self, low):
""" """
@ -525,14 +570,18 @@ class AsyncClientMixin:
tag = salt.utils.event.tagify(jid, prefix=self.tag_prefix) tag = salt.utils.event.tagify(jid, prefix=self.tag_prefix)
return {"tag": tag, "jid": jid} 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 Execute the function in a multiprocess and return the event tag to use
to watch for the return 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() async_pub = pub if pub is not None else self._gen_async_pub()
proc = salt.utils.process.SignalHandlingProcess( proc = salt.utils.process.SignalHandlingProcess(
target=self._proc_function, target=proc_func,
name="ProcessFunc", name="ProcessFunc",
args=(fun, low, user, async_pub["tag"], async_pub["jid"]), 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! # Salt API should never offer a custom roster!
self.opts["__disable_custom_roster"] = disable_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( def _prep_ssh(
self, tgt, fun, arg=(), timeout=None, tgt_type="glob", kwarg=None, **kwargs self, tgt, fun, arg=(), timeout=None, tgt_type="glob", kwarg=None, **kwargs
): ):
""" """
Prepare the arguments Prepare the arguments
""" """
kwargs = self.sanitize_kwargs(kwargs)
opts = copy.deepcopy(self.opts) opts = copy.deepcopy(self.opts)
opts.update(kwargs) opts.update(kwargs)
if timeout: if timeout:

View file

@ -141,6 +141,14 @@ def query(params=None):
"secret_access_key", get_configured_provider(), __opts__, search_global=False "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 # public interface parameters
real_parameters = { real_parameters = {
"access_key_id": access_key_id, "access_key_id": access_key_id,
@ -171,7 +179,7 @@ def query(params=None):
# print('parameters:') # print('parameters:')
# pprint.pprint(real_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('url:')
# print(request.url) # print(request.url)

View file

@ -257,9 +257,15 @@ def _get_si():
port = config.get_cloud_config_value( port = config.get_cloud_config_value(
"port", get_configured_provider(), __opts__, search_global=False, default=443 "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( 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:`Rod McKenzie (roderick.mckenzie@morganstanley.com)`
:codeauthor: :email:`Alexandru Bleotu (alexandru.bleotu@morganstanley.com)` :codeauthor: :email:`Alexandru Bleotu (alexandru.bleotu@morganstanley.com)`
@ -9,11 +8,7 @@
VCenter configuration schemas VCenter configuration schemas
""" """
# Import Python libs from salt.utils.schema import ArrayItem, BooleanItem, IntegerItem, Schema, StringItem
from __future__ import absolute_import, print_function, unicode_literals
# Import Salt libs
from salt.utils.schema import ArrayItem, IntegerItem, Schema, StringItem
class VCenterEntitySchema(Schema): class VCenterEntitySchema(Schema):
@ -48,6 +43,8 @@ class VCenterProxySchema(Schema):
mechanism = StringItem(required=True, enum=["userpass", "sspi"]) mechanism = StringItem(required=True, enum=["userpass", "sspi"])
username = StringItem() username = StringItem()
passwords = ArrayItem(min_items=1, items=StringItem(), unique_items=True) passwords = ArrayItem(min_items=1, items=StringItem(), unique_items=True)
verify_ssl = BooleanItem()
ca_bundle = StringItem()
domain = StringItem() domain = StringItem()
principal = StringItem(default="host") principal = StringItem(default="host")

View file

@ -2063,7 +2063,7 @@ class ClearFuncs(TransportMethods):
fun = clear_load.pop("fun") fun = clear_load.pop("fun")
runner_client = salt.runner.RunnerClient(self.opts) runner_client = salt.runner.RunnerClient(self.opts)
return runner_client.asynchronous( 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 except Exception as exc: # pylint: disable=broad-except
log.error("Exception occurred while introspecting %s: %s", fun, exc) 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 :platform: f5_bigip_11.6
""" """
import salt.exceptions import salt.exceptions
import salt.utils.json import salt.utils.json
@ -44,7 +43,7 @@ def _build_session(username, password, trans_label=None):
bigip = requests.session() bigip = requests.session()
bigip.auth = (username, password) bigip.auth = (username, password)
bigip.verify = False bigip.verify = True
bigip.headers.update({"Content-Type": "application/json"}) bigip.headers.update({"Content-Type": "application/json"})
if trans_label: if trans_label:

View file

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

View file

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

View file

@ -12,6 +12,7 @@ Module for handling openstack keystone calls.
keystone.tenant: admin keystone.tenant: admin
keystone.tenant_id: f80919baedab48ec8931f200c65a50df keystone.tenant_id: f80919baedab48ec8931f200c65a50df
keystone.auth_url: 'http://127.0.0.1:5000/v2.0/' keystone.auth_url: 'http://127.0.0.1:5000/v2.0/'
keystone.verify_ssl: True
OR (for token based authentication) OR (for token based authentication)
@ -31,6 +32,7 @@ Module for handling openstack keystone calls.
keystone.tenant: admin keystone.tenant: admin
keystone.tenant_id: f80919baedab48ec8931f200c65a50df keystone.tenant_id: f80919baedab48ec8931f200c65a50df
keystone.auth_url: 'http://127.0.0.1:5000/v2.0/' keystone.auth_url: 'http://127.0.0.1:5000/v2.0/'
keystone.verify_ssl: True
openstack2: openstack2:
keystone.user: admin keystone.user: admin
@ -38,6 +40,7 @@ Module for handling openstack keystone calls.
keystone.tenant: admin keystone.tenant: admin
keystone.tenant_id: f80919baedab48ec8931f200c65a50df keystone.tenant_id: f80919baedab48ec8931f200c65a50df
keystone.auth_url: 'http://127.0.0.2:5000/v2.0/' 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 With this configuration in place, any of the keystone functions can make use
of a configuration profile by declaring it explicitly. 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") endpoint = get("endpoint", "http://127.0.0.1:35357/v2.0")
user_domain_name = get("user_domain_name", "Default") user_domain_name = get("user_domain_name", "Default")
project_domain_name = get("project_domain_name", "Default") project_domain_name = get("project_domain_name", "Default")
verify_ssl = get("verify_ssl", True)
if token: if token:
kwargs = {"token": token, "endpoint": endpoint} kwargs = {"token": token, "endpoint": endpoint}
else: else:
@ -133,6 +137,7 @@ def _get_kwargs(profile=None, **connection_args):
# this ensures it's only passed in when defined # this ensures it's only passed in when defined
if insecure: if insecure:
kwargs["insecure"] = True kwargs["insecure"] = True
kwargs["verify_ssl"] = verify_ssl
return kwargs return kwargs
@ -150,7 +155,7 @@ def api_version(profile=None, **connection_args):
auth_url = kwargs.get("auth_url", kwargs.get("endpoint", None)) auth_url = kwargs.get("auth_url", kwargs.get("endpoint", None))
try: try:
return salt.utils.http.query( 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"] )["dict"]["version"]["id"]
except KeyError: except KeyError:
return None return None
@ -392,7 +397,7 @@ def endpoint_list(profile=None, **connection_args):
value: getattr(endpoint, value) value: getattr(endpoint, value)
for value in dir(endpoint) for value in dir(endpoint)
if not value.startswith("_") if not value.startswith("_")
and isinstance(getattr(endpoint, value), ((str,), dict, bool)) and isinstance(getattr(endpoint, value), (str, dict, bool))
} }
return ret return ret
@ -559,7 +564,7 @@ def role_list(profile=None, **connection_args):
value: getattr(role, value) value: getattr(role, value)
for value in dir(role) for value in dir(role)
if not value.startswith("_") if not value.startswith("_")
and isinstance(getattr(role, value), ((str,), dict, bool)) and isinstance(getattr(role, value), (str, dict, bool))
} }
return ret return ret
@ -628,7 +633,7 @@ def service_get(service_id=None, name=None, profile=None, **connection_args):
value: getattr(service, value) value: getattr(service, value)
for value in dir(service) for value in dir(service)
if not value.startswith("_") if not value.startswith("_")
and isinstance(getattr(service, value), ((str,), dict, bool)) and isinstance(getattr(service, value), (str, dict, bool))
} }
return ret return ret
@ -650,7 +655,7 @@ def service_list(profile=None, **connection_args):
value: getattr(service, value) value: getattr(service, value)
for value in dir(service) for value in dir(service)
if not value.startswith("_") if not value.startswith("_")
and isinstance(getattr(service, value), ((str,), dict, bool)) and isinstance(getattr(service, value), (str, dict, bool))
} }
return ret return ret
@ -800,7 +805,7 @@ def tenant_get(tenant_id=None, name=None, profile=None, **connection_args):
value: getattr(tenant, value) value: getattr(tenant, value)
for value in dir(tenant) for value in dir(tenant)
if not value.startswith("_") if not value.startswith("_")
and isinstance(getattr(tenant, value), ((str,), dict, bool)) and isinstance(getattr(tenant, value), (str, dict, bool))
} }
return ret return ret
@ -858,7 +863,7 @@ def tenant_list(profile=None, **connection_args):
value: getattr(tenant, value) value: getattr(tenant, value)
for value in dir(tenant) for value in dir(tenant)
if not value.startswith("_") if not value.startswith("_")
and isinstance(getattr(tenant, value), ((str,), dict, bool)) and isinstance(getattr(tenant, value), (str, dict, bool))
} }
return ret return ret
@ -933,7 +938,7 @@ def tenant_update(
value: getattr(updated, value) value: getattr(updated, value)
for value in dir(updated) for value in dir(updated)
if not value.startswith("_") 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) value: getattr(user, value, None)
for value in dir(user) for value in dir(user)
if not value.startswith("_") 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) tenant_id = getattr(user, "tenantId", None)
if tenant_id: if tenant_id:
@ -1069,7 +1074,7 @@ def user_get(user_id=None, name=None, profile=None, **connection_args):
value: getattr(user, value, None) value: getattr(user, value, None)
for value in dir(user) for value in dir(user)
if not value.startswith("_") 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) tenant_id = getattr(user, "tenantId", None)
@ -1499,7 +1504,7 @@ tenant_id=7167a092ece84bae8cead4bf9d15bb3b
value: getattr(role, value) value: getattr(role, value)
for value in dir(role) for value in dir(role)
if not value.startswith("_") if not value.startswith("_")
and isinstance(getattr(role, value), ((str,), dict, bool)) and isinstance(getattr(role, value), (str, dict, bool))
} }
else: else:
for role in kstone.roles.roles_for_user(user=user_id, tenant=tenant_id): 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 os
import re import re
import shlex
import subprocess import subprocess
import sys import sys
import time import time
@ -613,7 +614,8 @@ def restartcheck(ignorelist=None, blacklist=None, excludepid=None, **kwargs):
for package in packages: for package in packages:
_check_timeout(start_time, timeout) _check_timeout(start_time, timeout)
cmd = cmd_pkg_query + package 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: while True:
_check_timeout(start_time, timeout) _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 .. versionadded:: 2016.3.0
:depends: requests
:configuration: This module requires a 'zenoss' entry in the master/minion config. :configuration: This module requires a 'zenoss' entry in the master/minion config.
For example: For example:
@ -15,26 +13,16 @@ Module for working with the Zenoss API
hostname: https://zenoss.example.com hostname: https://zenoss.example.com
username: admin username: admin
password: admin123 password: admin123
verify_ssl: True
ca_bundle: /etc/ssl/certs/ca-certificates.crt
""" """
import logging import logging
import re import re
import salt.utils.http
import salt.utils.json 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__) log = logging.getLogger(__name__)
__virtualname__ = "zenoss" __virtualname__ = "zenoss"
@ -44,14 +32,7 @@ def __virtual__():
""" """
Only load if requests is installed Only load if requests is installed
""" """
if HAS_LIBS: return __virtualname__
return __virtualname__
else:
return (
False,
"The '{}' module could not be loaded: "
"'requests' is not installed.".format(__virtualname__),
)
ROUTERS = { ROUTERS = {
@ -75,11 +56,13 @@ def _session():
""" """
config = __salt__["config.option"]("zenoss") config = __salt__["config.option"]("zenoss")
session = requests.session() return salt.utils.http.session(
session.auth = (config.get("username"), config.get("password")) user=config.get("username"),
session.verify = False password=config.get("password"),
session.headers.update({"Content-type": "application/json; charset=utf-8"}) verify_ssl=config.get("verify_ssl", True),
return session ca_bundle=config.get("ca_bundle"),
headers={"Content-type": "application/json; charset=utf-8"},
)
def _router_request(router, method, data=None): def _router_request(router, method, data=None):

View file

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

View file

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

View file

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

View file

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
""" """
Proxy Minion interface module for managing VMWare vCenters. 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. host.
""" """
# Import Python Libs
from __future__ import absolute_import, print_function, unicode_literals
import logging import logging
import os import os
# Import Salt Libs
import salt.exceptions import salt.exceptions
from salt.config.schemas.vcenter import VCenterProxySchema from salt.config.schemas.vcenter import VCenterProxySchema
from salt.utils.dictupdate import merge from salt.utils.dictupdate import merge
@ -277,6 +272,8 @@ def init(opts):
# Save optional # Save optional
DETAILS["protocol"] = proxy_conf.get("protocol") DETAILS["protocol"] = proxy_conf.get("protocol")
DETAILS["port"] = proxy_conf.get("port") DETAILS["port"] = proxy_conf.get("port")
DETAILS["verify_ssl"] = proxy_conf.get("verify_ssl")
DETAILS["ca_bundle"] = proxy_conf.get("ca_bundle")
# Test connection # Test connection
if DETAILS["mechanism"] == "userpass": if DETAILS["mechanism"] == "userpass":

View file

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

View file

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

View file

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

View file

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

View file

@ -7,6 +7,8 @@ and the like, but also useful for basic HTTP testing.
import cgi import cgi
import gzip import gzip
import http.client
import http.cookiejar
import io import io
import logging import logging
import os import os
@ -14,13 +16,13 @@ import pprint
import re import re
import socket import socket
import ssl import ssl
import urllib.error
import urllib.parse
import urllib.request
import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET
import zlib import zlib
import salt.config 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.httputil
import salt.ext.tornado.simple_httpclient import salt.ext.tornado.simple_httpclient
import salt.loader import salt.loader
@ -36,12 +38,6 @@ import salt.utils.stringutils
import salt.utils.xmlutil as xml import salt.utils.xmlutil as xml
import salt.utils.yaml import salt.utils.yaml
import salt.version 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.ext.tornado.httpclient import HTTPClient
from salt.template import compile_template from salt.template import compile_template
from salt.utils.decorators.jinja import jinja_filter from salt.utils.decorators.jinja import jinja_filter
@ -317,11 +313,9 @@ def query(
if cookies is not None: if cookies is not None:
if cookie_format == "mozilla": if cookie_format == "mozilla":
sess_cookies = salt.ext.six.moves.http_cookiejar.MozillaCookieJar( sess_cookies = http.cookiejar.MozillaCookieJar(cookie_jar)
cookie_jar
)
else: 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): if not os.path.isfile(cookie_jar):
sess_cookies.save() sess_cookies.save()
sess_cookies.load() sess_cookies.load()
@ -366,7 +360,7 @@ def query(
method, method,
url, url,
params=params, params=params,
files={formdata_fieldname: (formdata_filename, StringIO(data))}, files={formdata_fieldname: (formdata_filename, io.StringIO(data))},
**req_kwargs **req_kwargs
) )
else: else:
@ -400,15 +394,15 @@ def query(
body = body.decode(result.encoding or "utf-8") body = body.decode(result.encoding or "utf-8")
ret["body"] = body ret["body"] = body
elif backend == "urllib2": elif backend == "urllib2":
request = urllib_request.Request(url_full, data) request = urllib.request.Request(url_full, data)
handlers = [ handlers = [
urllib_request.HTTPHandler, urllib.request.HTTPHandler,
urllib_request.HTTPCookieProcessor(sess_cookies), urllib.request.HTTPCookieProcessor(sess_cookies),
] ]
if url.startswith("https"): if url.startswith("https"):
hostname = request.get_host() hostname = request.get_host()
handlers[0] = urllib_request.HTTPSHandler(1) handlers[0] = urllib.request.HTTPSHandler(1)
if not HAS_MATCHHOSTNAME: if not HAS_MATCHHOSTNAME:
log.warning( log.warning(
"match_hostname() not available, SSL hostname checking " "match_hostname() not available, SSL hostname checking "
@ -459,7 +453,7 @@ def query(
# Python >= 2.7.9 # Python >= 2.7.9
context = ssl.SSLContext.load_cert_chain(*cert_chain) context = ssl.SSLContext.load_cert_chain(*cert_chain)
handlers.append( handlers.append(
urllib_request.HTTPSHandler(context=context) urllib.request.HTTPSHandler(context=context)
) # pylint: disable=E1123 ) # pylint: disable=E1123
else: else:
# Python < 2.7.9 # Python < 2.7.9
@ -470,17 +464,15 @@ def query(
} }
if len(cert_chain) > 1: if len(cert_chain) > 1:
cert_kwargs["key_file"] = cert_chain[1] cert_kwargs["key_file"] = cert_chain[1]
handlers[0] = salt.ext.six.moves.http_client.HTTPSConnection( handlers[0] = http.client.HTTPSConnection(**cert_kwargs)
**cert_kwargs
)
opener = urllib_request.build_opener(*handlers) opener = urllib.request.build_opener(*handlers)
for header in header_dict: for header in header_dict:
request.add_header(header, header_dict[header]) request.add_header(header, header_dict[header])
request.get_method = lambda: method request.get_method = lambda: method
try: try:
result = opener.open(request) result = opener.open(request)
except URLError as exc: except urllib.error.URLError as exc:
return {"Error": str(exc)} return {"Error": str(exc)}
if stream is True or handle is True: if stream is True or handle is True:
return { return {
@ -501,7 +493,7 @@ def query(
and not isinstance(result_text, str) and not isinstance(result_text, str)
): ):
result_text = result_text.decode(res_params["charset"]) 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") result_text = result_text.decode("utf-8")
ret["body"] = result_text ret["body"] = result_text
else: else:
@ -525,7 +517,7 @@ def query(
) )
if isinstance(data, dict): if isinstance(data, dict):
data = _urlencode(data) data = urllib.parse.urlencode(data)
if verify_ssl: if verify_ssl:
req_kwargs["ca_certs"] = ca_bundle 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 # 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 # 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_host = None
proxy_port = None proxy_port = None
proxy_username = None proxy_username = None
@ -655,7 +647,7 @@ def query(
and not isinstance(result_text, str) and not isinstance(result_text, str)
): ):
result_text = result_text.decode(res_params["charset"]) 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") result_text = result_text.decode("utf-8")
ret["body"] = result_text ret["body"] = result_text
if "Set-Cookie" in result_headers and cookies is not None: 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 # cookielib.Cookie() requires an epoch
if "expires" in cookie: if "expires" in cookie:
cookie["expires"] = salt.ext.six.moves.http_cookiejar.http2time( cookie["expires"] = http.cookiejar.http2time(cookie["expires"])
cookie["expires"]
)
# Fill in missing required fields # Fill in missing required fields
for req in reqd: for req in reqd:
@ -1012,9 +1002,7 @@ def parse_cookie_header(header):
# Remove attribs that don't apply to Cookie objects # Remove attribs that don't apply to Cookie objects
cookie.pop("httponly", None) cookie.pop("httponly", None)
cookie.pop("samesite", None) cookie.pop("samesite", None)
ret.append( ret.append(http.cookiejar.Cookie(name=name, value=value, **cookie))
salt.ext.six.moves.http_cookiejar.Cookie(name=name, value=value, **cookie)
)
return ret return ret
@ -1024,7 +1012,7 @@ def sanitize_url(url, hide_fields):
Make sure no secret fields show up in logs Make sure no secret fields show up in logs
""" """
if isinstance(hide_fields, list): if isinstance(hide_fields, list):
url_comps = splitquery(url) url_comps = urllib.parse.splitquery(url)
log_url = url_comps[0] log_url = url_comps[0]
if len(url_comps) > 1: if len(url_comps) > 1:
log_url += "?" log_url += "?"
@ -1057,3 +1045,23 @@ def _sanitize_url_components(comp_list, field):
ret = "{}&".format(comp_list[0]) ret = "{}&".format(comp_list[0])
comp_list.remove(comp_list[0]) comp_list.remove(comp_list[0])
return ret + _sanitize_url_components(comp_list, field) 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) "{} does not exist. Could not auto detect dependencies".format(py_ver)
) )
return {} return {}
py_shell_cmd = "{0} -c 'import {1}; print({1}.__file__)'".format(py_ver, mod) py_shell_cmd = [py_ver, "-c", "import {0}; print({0}.__file__)".format(mod)]
cmd = subprocess.Popen(py_shell_cmd, stdout=subprocess.PIPE, shell=True) cmd = subprocess.Popen(py_shell_cmd, stdout=subprocess.PIPE)
stdout, _ = cmd.communicate() stdout, _ = cmd.communicate()
mod_file = os.path.abspath(salt.utils.data.decode(stdout).rstrip("\n")) 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 atexit
import errno import errno
import logging import logging
@ -80,7 +79,6 @@ import ssl
import time import time
from http.client import BadStatusLine from http.client import BadStatusLine
import requests
import salt.exceptions import salt.exceptions
import salt.modules.cmdmod import salt.modules.cmdmod
import salt.utils.path import salt.utils.path
@ -170,11 +168,8 @@ def esxcli(
host, user, pwd, protocol, port, cmd host, user, pwd, protocol, port, cmd
) )
else: else:
esx_cmd += ( esx_cmd += " -s {} -h {} -u {} -p '{}' --protocol={} --portnumber={} {}".format(
" -s {} -h {} -u {} -p '{}' " host, esxi_host, user, pwd, protocol, port, cmd
"--protocol={} --portnumber={} {}".format(
host, esxi_host, user, pwd, protocol, port, cmd
)
) )
ret = salt.modules.cmdmod.run_all(esx_cmd, output_loglevel="quiet") ret = salt.modules.cmdmod.run_all(esx_cmd, output_loglevel="quiet")
@ -182,7 +177,9 @@ def esxcli(
return ret 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. Internal helper method to create an instance of the vSphere API client.
Please provide username and password to authenticate. Please provide username and password to authenticate.
@ -196,6 +193,10 @@ def get_vsphere_client(server, username, password, session=None):
:param Session session: :param Session session:
Request HTTP session instance. If not specified, one Request HTTP session instance. If not specified, one
is automatically created and used 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: :returns:
Vsphere Client instance Vsphere Client instance
@ -204,9 +205,7 @@ def get_vsphere_client(server, username, password, session=None):
""" """
if not session: if not session:
# Create an https session to be used for a vSphere client # Create an https session to be used for a vSphere client
session = requests.session() session = salt.utils.http.session(verify_ssl=verify_ssl, ca_bundle=ca_bundle)
# If client uses own SSL cert, session should not verify
session.verify = False
client = None client = None
try: try:
client = create_vsphere_client( client = create_vsphere_client(
@ -218,7 +217,15 @@ def get_vsphere_client(server, username, password, session=None):
def _get_service_instance( 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 Internal method to authenticate with a vCenter server or ESX/ESXi host
@ -253,21 +260,26 @@ def _get_service_instance(
raise salt.exceptions.CommandExecutionError( raise salt.exceptions.CommandExecutionError(
"Unsupported mechanism: '{}'".format(mechanism) "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: try:
log.trace( if verify_ssl:
"Connecting using the '%s' mechanism, with username '%s'", service_instance = SmartConnect(
mechanism, host=host,
username, user=username,
) pwd=password,
service_instance = SmartConnect( protocol=protocol,
host=host, port=port,
user=username, b64token=token,
pwd=password, mechanism=mechanism,
protocol=protocol, )
port=port,
b64token=token,
mechanism=mechanism,
)
except TypeError as exc: except TypeError as exc:
if "unexpected keyword argument" in exc.message: if "unexpected keyword argument" in exc.message:
log.error( log.error(
@ -280,30 +292,33 @@ def _get_service_instance(
raise raise
except Exception as exc: # pylint: disable=broad-except except Exception as exc: # pylint: disable=broad-except
# pyVmomi's SmartConnect() actually raises Exception in some cases. # pyVmomi's SmartConnect() actually raises Exception in some cases.
default_msg = ( if (
"Could not connect to host '{}'. " isinstance(exc, vim.fault.HostConnectFault)
"Please check the debug log for more information.".format(host) 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: try:
if ( service_instance = SmartConnect(
isinstance(exc, vim.fault.HostConnectFault) host=host,
and "[SSL: CERTIFICATE_VERIFY_FAILED]" in exc.msg user=username,
) or "[SSL: CERTIFICATE_VERIFY_FAILED]" in str(exc): pwd=password,
service_instance = SmartConnect( protocol=protocol,
host=host, port=port,
user=username, sslContext=ssl._create_unverified_context(),
pwd=password, b64token=token,
protocol=protocol, mechanism=mechanism,
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)
except Exception as exc: # pylint: disable=broad-except except Exception as exc: # pylint: disable=broad-except
# pyVmomi's SmartConnect() actually raises Exception in some cases. # pyVmomi's SmartConnect() actually raises Exception in some cases.
if "certificate verify failed" in str(exc): 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 err_msg = exc.msg if hasattr(exc, "msg") else default_msg
log.trace(exc) log.trace(exc)
raise salt.exceptions.VMwareConnectionError(err_msg) raise salt.exceptions.VMwareConnectionError(err_msg)
atexit.register(Disconnect, service_instance) atexit.register(Disconnect, service_instance)
return service_instance return service_instance
@ -384,6 +400,7 @@ def get_service_instance(
mechanism="userpass", mechanism="userpass",
principal=None, principal=None,
domain=None, domain=None,
verify_ssl=True,
): ):
""" """
Authenticate with a vCenter server or ESX/ESXi host and return the service instance object. Authenticate with a vCenter server or ESX/ESXi host and return the service instance object.
@ -416,6 +433,9 @@ def get_service_instance(
domain domain
Kerberos user domain. Required if mechanism is ``sspi`` Kerberos user domain. Required if mechanism is ``sspi``
verify_ssl
Verify the SSL certificate. Default: True
""" """
if protocol is None: if protocol is None:
@ -438,7 +458,15 @@ def get_service_instance(
if not service_instance: if not service_instance:
service_instance = _get_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 # 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") log.trace("Session no longer authenticating. Reconnecting")
Disconnect(service_instance) Disconnect(service_instance)
service_instance = _get_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: except vim.fault.NoPermission as exc:
log.exception(exc) log.exception(exc)

View file

@ -1,8 +1,6 @@
# -*- coding: utf-8 -*-
""" """
Modules used to control the master itself Modules used to control the master itself
""" """
from __future__ import absolute_import, print_function, unicode_literals
from collections.abc import Mapping from collections.abc import Mapping
@ -15,7 +13,7 @@ import salt.utils.zeromq
class WheelClient( 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 An interface to Salt's wheel modules
@ -123,8 +121,8 @@ class WheelClient(
}) })
{'jid': '20131219224744416681', 'tag': 'salt/wheel/20131219224744416681'} {'jid': '20131219224744416681', 'tag': 'salt/wheel/20131219224744416681'}
""" """
fun = low.pop("fun") fun = low.get("fun")
return self.asynchronous(fun, low) return self.asynchronous(fun, low, local=False)
def cmd( def cmd(
self, self,
@ -143,9 +141,7 @@ class WheelClient(
>>> wheel.cmd('key.finger', ['jerry']) >>> wheel.cmd('key.finger', ['jerry'])
{'minions': {'jerry': '5d:f6:79:43:5e:d4:42:3f:57:b8:45:a8:7e:a4:6e:ca'}} {'minions': {'jerry': '5d:f6:79:43:5e:d4:42:3f:57:b8:45:a8:7e:a4:6e:ca'}}
""" """
return super(WheelClient, self).cmd( return super().cmd(fun, arg, pub_data, kwarg, print_event, full_return)
fun, arg, pub_data, kwarg, print_event, full_return
)
Wheel = WheelClient # for backward-compat 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 The `pillar_roots` wheel module is used to manage files under the pillar roots
directories on the master server. directories on the master server.
""" """
# Import python libs
from __future__ import absolute_import, print_function, unicode_literals
import os import os
# Import salt libs
import salt.utils.files import salt.utils.files
import salt.utils.path import salt.utils.path
import salt.utils.verify
# Import 3rd-party libs
from salt.ext import six
def find(path, saltenv="base"): def find(path, saltenv="base"):
@ -86,7 +79,7 @@ def read(path, saltenv="base"):
ret = [] ret = []
files = find(path, saltenv) files = find(path, saltenv)
for fn_ in files: for fn_ in files:
full = next(six.iterkeys(fn_)) full = next(iter(fn_.keys()))
form = fn_[full] form = fn_[full]
if form == "txt": if form == "txt":
with salt.utils.files.fopen(full, "rb") as fp_: 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 index of the file can be specified to write to a lower priority file root
""" """
if saltenv not in __opts__["pillar_roots"]: 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: 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 index, saltenv
) )
if os.path.isabs(path): if os.path.isabs(path):
return ( return "The path passed in {} is not relative to the environment " "{}".format(
"The path passed in {0} is not relative to the environment " "{1}" path, saltenv
).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 = os.path.join(__opts__["pillar_roots"][saltenv][index], path)
dest_dir = os.path.dirname(dest) dest_dir = os.path.dirname(dest)
if not os.path.isdir(dest_dir): if not os.path.isdir(dest_dir):
os.makedirs(dest_dir) os.makedirs(dest_dir)
with salt.utils.files.fopen(dest, "w+") as fp_: with salt.utils.files.fopen(dest, "w+") as fp_:
fp_.write(salt.utils.stringutils.to_str(data)) 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.assertIn(s_ret_str, str(create_snapshot))
self.assertDestroyInstance() 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 from time import sleep
import pytest import pytest
import salt.utils.files
from salt.config import cloud_config, cloud_providers_config from salt.config import cloud_config, cloud_providers_config
from salt.utils.yaml import safe_load from salt.utils.yaml import safe_load
from tests.support.case import ShellCase from tests.support.case import ShellCase
@ -195,6 +196,18 @@ class CloudTest(ShellCase):
def profile_str(self): def profile_str(self):
return self.PROVIDER + "-config" 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): def setUp(self):
""" """
Sets up the test requirements. In child classes, define PROVIDER and REQUIRED_PROVIDER_CONFIG_ITEMS or this will fail 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: except AssertionError:
self.mod_case.run_function("user.delete", [self.USERA], remove=True) self.mod_case.run_function("user.delete", [self.USERA], remove=True)
self.skipTest("Could not add user or password, skipping test") self.skipTest("Could not add user or password, skipping test")
self.expfile = os.path.join(RUNTIME_VARS.TMP, "exploited")
def tearDown(self): def tearDown(self):
try:
os.remove(self.expfile)
except OSError:
pass
del self.expfile
del self.netapi del self.netapi
self.mod_case.run_function("user.delete", [self.USERA], remove=True) 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 @classmethod
def setUpClass(cls): def setUpClass(cls):
cls.post_webserver = Webserver(handler=SaveRequestsPostHandler) cls.post_webserver = Webserver(handler=SaveRequestsPostHandler)
@ -571,3 +608,34 @@ class NetapiSSHClientAuthTest(SSHCase):
ret = self.netapi.run(low) ret = self.netapi.run(low)
assert "localhost" in ret assert "localhost" in ret
assert ret["localhost"]["return"] is True 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: with patch_proc, patch_which:
salt.utils.thin.get_tops_python("python2", ext_py_ver=version) salt.utils.thin.get_tops_python("python2", ext_py_ver=version)
cmds = [x[0][0] for x in mock_popen.call_args_list] 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: if python3:
assert [x for x in cmds if "distro" in x] assert [x for x in cmds if "distro" in x[2]]
else: 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]]) @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> :codeauthor: Nicole Thomas <nicole@saltstack.com>
""" """
import builtins
import os import os
import sys import sys
import tempfile import tempfile
@ -12,7 +12,6 @@ import salt.utils.files
import salt.utils.platform import salt.utils.platform
import salt.utils.stringutils import salt.utils.stringutils
from salt.exceptions import CommandExecutionError from salt.exceptions import CommandExecutionError
from salt.ext.six.moves import builtins # pylint: disable=import-error
from salt.log import LOG_LEVELS from salt.log import LOG_LEVELS
from tests.support.helpers import TstSuiteLoggingHandler from tests.support.helpers import TstSuiteLoggingHandler
from tests.support.mixins import LoaderModuleMockMixin from tests.support.mixins import LoaderModuleMockMixin
@ -640,3 +639,16 @@ class CMDMODTestCase(TestCase, LoaderModuleMockMixin):
umask=None, umask=None,
use_vt=False, 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> :codeauthor: Jayesh Kariya <jayeshk@saltstack.com>
""" """
# Import Python Libs import salt.modules.config as config
from __future__ import absolute_import, print_function, unicode_literals
# Import Salt Libs
import salt.modules.keystone as keystone import salt.modules.keystone as keystone
# Import Salt Testing Libs
from tests.support.mixins import LoaderModuleMockMixin 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 from tests.support.unit import TestCase
class MockEC2(object): class MockEC2:
""" """
Mock of EC2 class Mock of EC2 class
""" """
@ -68,7 +62,7 @@ class MockEC2(object):
return [cr_ec2] return [cr_ec2]
class MockEndpoints(object): class MockEndpoints:
""" """
Mock of Endpoints class Mock of Endpoints class
""" """
@ -103,7 +97,7 @@ class MockEndpoints(object):
return id return id
class MockServices(object): class MockServices:
""" """
Mock of Services class Mock of Services class
""" """
@ -159,7 +153,7 @@ class MockServices(object):
return service_id return service_id
class MockRoles(object): class MockRoles:
""" """
Mock of Roles class Mock of Roles class
""" """
@ -229,7 +223,7 @@ class MockRoles(object):
return [role] return [role]
class MockTenants(object): class MockTenants:
""" """
Mock of Tenants class Mock of Tenants class
""" """
@ -279,7 +273,7 @@ class MockTenants(object):
return tenant_id return tenant_id
class MockServiceCatalog(object): class MockServiceCatalog:
""" """
Mock of ServiceCatalog class Mock of ServiceCatalog class
""" """
@ -302,7 +296,7 @@ class MockServiceCatalog(object):
} }
class MockUsers(object): class MockUsers:
""" """
Mock of Users class Mock of Users class
""" """
@ -375,7 +369,7 @@ class Unauthorized(Exception):
""" """
def __init__(self, message="Test"): def __init__(self, message="Test"):
super(Unauthorized, self).__init__(message) super().__init__(message)
self.msg = message self.msg = message
@ -385,11 +379,11 @@ class AuthorizationFailure(Exception):
""" """
def __init__(self, message="Test"): def __init__(self, message="Test"):
super(AuthorizationFailure, self).__init__(message) super().__init__(message)
self.msg = message self.msg = message
class MockExceptions(object): class MockExceptions:
""" """
Mock of exceptions class Mock of exceptions class
""" """
@ -399,7 +393,7 @@ class MockExceptions(object):
self.AuthorizationFailure = AuthorizationFailure self.AuthorizationFailure = AuthorizationFailure
class MockKeystoneClient(object): class MockKeystoneClient:
""" """
Mock of keystoneclient module Mock of keystoneclient module
""" """
@ -408,7 +402,7 @@ class MockKeystoneClient(object):
self.exceptions = MockExceptions() self.exceptions = MockExceptions()
class MockClient(object): class MockClient:
""" """
Mock of Client class Mock of Client class
""" """
@ -444,7 +438,10 @@ class KeystoneTestCase(TestCase, LoaderModuleMockMixin):
"auth": MockClient, "auth": MockClient,
"client": MockClient(), "client": MockClient(),
"keystoneclient": MockKeystoneClient(), "keystoneclient": MockKeystoneClient(),
} "__salt__": {"config.get": config.get},
"__opts__": {},
},
config: {"__opts__": {}},
} }
# 'ec2_credentials_create' function tests: 1 # '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>` :codeauthor: :email:`David Homolka <david.homolka@ultimum.io>`
""" """
# Import Python Libs import os
from __future__ import absolute_import, print_function, unicode_literals
# Import Salt Libsrestartcheck
import salt.modules.restartcheck as restartcheck import salt.modules.restartcheck as restartcheck
import salt.utils.path
# Import Salt Testing Libs
from tests.support.mixins import LoaderModuleMockMixin from tests.support.mixins import LoaderModuleMockMixin
from tests.support.mock import MagicMock, patch from tests.support.mock import MagicMock, patch
from tests.support.runtests import RUNTIME_VARS
from tests.support.unit import TestCase from tests.support.unit import TestCase
# import salt.utils.files
# from salt.exceptions import CommandExecutionError
class RestartcheckTestCase(TestCase, LoaderModuleMockMixin): 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"))
self.assertFalse(restartcheck._valid_deleted_file("/SYSV/test (deleted)")) self.assertFalse(restartcheck._valid_deleted_file("/SYSV/test (deleted)"))
self.assertFalse(restartcheck._valid_deleted_file("/SYSV/test (path inode=1)")) 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 "'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): class GetsServiceInstanceViaProxyTestCase(TestCase, LoaderModuleMockMixin):
""" """
@ -2602,52 +2630,70 @@ class TestVSphereTagging(TestCase, LoaderModuleMockMixin):
self.assertEqual(ret, {"Category created": None}) self.assertEqual(ret, {"Category created": None})
def test_create_tag_category_client(self): 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 CreateSpec object and create objects
mock_client = Mock( mock_client = Mock(
tagging=Mock( tagging=Mock(
Category=Mock( Category=Mock(
CreateSpec=Mock(return_value=Mock()), CreateSpec=Mock(return_value=Mock()),
create=Mock( create=Mock(
return_value=self.create_tag_category["Category created"] return_value=self.create_tag_category["Category created"]
), ),
)
) )
) )
)
# Start patching each external API return with Mock Objects # 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( with patch.object(
vsphere, "_get_proxy_connection_details", return_value=[] vsphere, "get_proxy_type", return_value="vcenter"
) as get_proxy_connection: ) as get_proxy_type:
with patch.object( with patch.object(
salt.utils.vmware, "get_service_instance", return_value=None vsphere, "_get_proxy_connection_details", return_value=[]
) as get_service_instance: ) as get_proxy_connection:
with patch.dict( with patch.object(
vsphere.__salt__, salt.utils.vmware, "get_service_instance", return_value=None
{"vcenter.get_details": get_details}, ) as get_service_instance:
clear=True, with patch.dict(
) as get_vcenter_details: vsphere.__salt__,
with patch.object( {"vcenter.get_details": get_details},
salt.utils.vmware, clear=True,
"get_vsphere_client", ) as get_vcenter_details:
return_value=mock_client, with patch.object(
) as get_vsphere_client: salt.utils.vmware,
ret = vsphere.create_tag_category( "get_vsphere_client",
self.func_attrs["name"], return_value=mock_client,
self.func_attrs["description"], ) as get_vsphere_client:
self.func_attrs["cardinality"], ret = vsphere.create_tag_category(
) self.func_attrs["name"],
self.func_attrs["description"],
self.func_attrs["cardinality"],
)
# Check function calls and return data # Check function calls and return data
get_proxy_type.assert_called_once() get_proxy_type.assert_called_once()
get_proxy_connection.assert_called_once() get_proxy_connection.assert_called_once()
get_service_instance.assert_called_once() get_service_instance.assert_called_once()
get_vsphere_client.assert_called_once() get_vsphere_client.assert_called_once()
self.assertEqual(ret, self.create_tag_category) 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): def test_create_tag_client_none(self):
get_details = MagicMock(return_value=self.details) get_details = MagicMock(return_value=self.details)
@ -2759,49 +2805,67 @@ class TestVSphereTagging(TestCase, LoaderModuleMockMixin):
self.assertEqual(ret, {"Category deleted": None}) self.assertEqual(ret, {"Category deleted": None})
def test_delete_tag_category_client(self): 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 CreateSpec object and create objects
mock_client = Mock( mock_client = Mock(
tagging=Mock( tagging=Mock(
Category=Mock( Category=Mock(
delete=Mock( delete=Mock(
return_value=self.delete_tag_category["Category deleted"] return_value=self.delete_tag_category["Category deleted"]
)
) )
) )
) )
)
# Start patching each external API return with Mock Objects # 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( with patch.object(
vsphere, "_get_proxy_connection_details", return_value=[] vsphere, "get_proxy_type", return_value="vcenter"
) as get_proxy_connection: ) as get_proxy_type:
with patch.object( with patch.object(
salt.utils.vmware, "get_service_instance", return_value=None vsphere, "_get_proxy_connection_details", return_value=[]
) as get_service_instance: ) as get_proxy_connection:
with patch.dict( with patch.object(
vsphere.__salt__, salt.utils.vmware, "get_service_instance", return_value=None
{"vcenter.get_details": get_details}, ) as get_service_instance:
clear=True, with patch.dict(
) as get_vcenter_details: vsphere.__salt__,
with patch.object( {"vcenter.get_details": get_details},
salt.utils.vmware, clear=True,
"get_vsphere_client", ) as get_vcenter_details:
return_value=mock_client, with patch.object(
) as get_vsphere_client: salt.utils.vmware,
ret = vsphere.delete_tag_category( "get_vsphere_client",
self.func_attrs["category_id"] return_value=mock_client,
) ) as get_vsphere_client:
ret = vsphere.delete_tag_category(
self.func_attrs["category_id"]
)
# Check function calls and return data # Check function calls and return data
get_proxy_type.assert_called_once() get_proxy_type.assert_called_once()
get_proxy_connection.assert_called_once() get_proxy_connection.assert_called_once()
get_service_instance.assert_called_once() get_service_instance.assert_called_once()
get_vsphere_client.assert_called_once() get_vsphere_client.assert_called_once()
self.assertEqual(ret, self.delete_tag_category) 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): def test_delete_tag_client_none(self):
get_details = MagicMock(return_value=self.details) get_details = MagicMock(return_value=self.details)
@ -2901,44 +2965,64 @@ class TestVSphereTagging(TestCase, LoaderModuleMockMixin):
self.assertEqual(ret, {"Categories": None}) self.assertEqual(ret, {"Categories": None})
def test_list_tag_categories_client(self): 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 CreateSpec object and create objects
mock_client = Mock( mock_client = Mock(
tagging=Mock( tagging=Mock(
Category=Mock(list=Mock(return_value=self.list_tag_categories_return)) Category=Mock(
list=Mock(return_value=self.list_tag_categories_return)
)
)
) )
)
# Start patching each external API return with Mock Objects # 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( with patch.object(
vsphere, "_get_proxy_connection_details", return_value=[] vsphere, "get_proxy_type", return_value="vcenter"
) as get_proxy_connection: ) as get_proxy_type:
with patch.object( with patch.object(
salt.utils.vmware, "get_service_instance", return_value=None vsphere, "_get_proxy_connection_details", return_value=[]
) as get_service_instance: ) as get_proxy_connection:
with patch.dict( with patch.object(
vsphere.__salt__, salt.utils.vmware, "get_service_instance", return_value=None
{"vcenter.get_details": get_details}, ) as get_service_instance:
clear=True, with patch.dict(
) as get_vcenter_details: vsphere.__salt__,
with patch.object( {"vcenter.get_details": get_details},
salt.utils.vmware, clear=True,
"get_vsphere_client", ) as get_vcenter_details:
return_value=mock_client, with patch.object(
) as get_vsphere_client: salt.utils.vmware,
ret = vsphere.list_tag_categories() "get_vsphere_client",
return_value=mock_client,
) as get_vsphere_client:
ret = vsphere.list_tag_categories()
get_proxy_type.assert_called_once() get_proxy_type.assert_called_once()
get_proxy_connection.assert_called_once() get_proxy_connection.assert_called_once()
get_service_instance.assert_called_once() get_service_instance.assert_called_once()
get_vsphere_client.assert_called_once() get_vsphere_client.assert_called_once()
self.assertEqual( self.assertEqual(
ret, {"Categories": self.list_tag_categories_return} 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): def test_list_tags_client_none(self):
get_details = MagicMock(return_value=self.details) get_details = MagicMock(return_value=self.details)
@ -3005,6 +3089,56 @@ class TestVSphereTagging(TestCase, LoaderModuleMockMixin):
get_vsphere_client.assert_called_once() get_vsphere_client.assert_called_once()
self.assertEqual(ret, {"Tags": self.list_tags_return}) 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): def test_list_attached_tags_client_none(self):
get_details = MagicMock(return_value=self.details) get_details = MagicMock(return_value=self.details)
@ -3036,50 +3170,72 @@ class TestVSphereTagging(TestCase, LoaderModuleMockMixin):
self.assertEqual(ret, {"Attached tags": None}) self.assertEqual(ret, {"Attached tags": None})
def test_list_attached_tags_client(self): 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 CreateSpec object and create objects
mock_client = Mock( mock_client = Mock(
tagging=Mock( tagging=Mock(
TagAssociation=Mock( TagAssociation=Mock(
list_attached_tags=Mock(return_value=self.list_attached_tags_return) list_attached_tags=Mock(
return_value=self.list_attached_tags_return
)
)
) )
) )
)
# Start patching each external API return with Mock Objects # 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( with patch.object(
vsphere, "_get_proxy_connection_details", return_value=[] vsphere, "get_proxy_type", return_value="vcenter"
) as get_proxy_connection: ) as get_proxy_type:
with patch.object( with patch.object(
salt.utils.vmware, "get_service_instance", return_value=None vsphere, "_get_proxy_connection_details", return_value=[]
) as get_service_instance: ) as get_proxy_connection:
with patch.dict( with patch.object(
vsphere.__salt__, salt.utils.vmware, "get_service_instance", return_value=None
{"vcenter.get_details": get_details}, ) as get_service_instance:
clear=True, with patch.dict(
) as get_vcenter_details: vsphere.__salt__,
with patch.object( {"vcenter.get_details": get_details},
salt.utils.vmware, clear=True,
"get_vsphere_client", ) as get_vcenter_details:
return_value=mock_client, with patch.object(
) as get_vsphere_client: salt.utils.vmware,
with patch.object(vsphere, "DynamicID") as dynamic_id: "get_vsphere_client",
# Check function calls and return return_value=mock_client,
ret = vsphere.list_attached_tags( ) as get_vsphere_client:
self.func_attrs["object_id"] with patch.object(vsphere, "DynamicID") as dynamic_id:
) # Check function calls and return
get_proxy_type.assert_called_once() ret = vsphere.list_attached_tags(
get_proxy_connection.assert_called_once() self.func_attrs["object_id"]
get_service_instance.assert_called_once() )
get_vsphere_client.assert_called_once() get_proxy_type.assert_called_once()
self.assertEqual( get_proxy_connection.assert_called_once()
ret, get_service_instance.assert_called_once()
{"Attached tags": self.list_attached_tags_return}, 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): def test_attach_tags_client_none(self):
get_details = MagicMock(return_value=self.details) get_details = MagicMock(return_value=self.details)
@ -3114,48 +3270,266 @@ class TestVSphereTagging(TestCase, LoaderModuleMockMixin):
self.assertEqual(ret, {"Tag attached": None}) self.assertEqual(ret, {"Tag attached": None})
def test_attach_tags_client(self): 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 CreateSpec object and create objects
mock_client = Mock( mock_client = Mock(
tagging=Mock( tagging=Mock(
TagAssociation=Mock( TagAssociation=Mock(
attach=Mock(return_value=self.list_attached_tags_return) 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_client, patch_ca, patch_details:
with patch.object( vsphere._get_client(
vsphere, "get_proxy_type", return_value="vcenter" server="localhost", username="testuser", password="testpassword"
) as get_proxy_type: )
with patch.object( self.assertEqual(
vsphere, "_get_proxy_connection_details", return_value=[] mock_client.call_args_list,
) as get_proxy_connection: [
with patch.object( call(
salt.utils.vmware, "get_service_instance", return_value=None ca_bundle=None,
) as get_service_instance: password="testpassword",
with patch.dict( server="localhost",
vsphere.__salt__, username="testuser",
{"vcenter.get_details": get_details}, verify_ssl=True,
clear=True, )
) as get_vcenter_details: ],
with patch.object( )
salt.utils.vmware, self.assertEqual(mock_details.assert_called_once(), None)
"get_vsphere_client", self.assertEqual(mock_ca.assert_not_called(), None)
return_value=mock_client,
) as get_vsphere_client: def test_get_client_verify_ssl_false(self):
with patch.object(vsphere, "DynamicID") as dynamic_id: """
# Check function calls and return test get_client when verify_ssl=False is set
ret = vsphere.attach_tag( """
object_id=self.func_attrs["object_id"], details = self.details.copy()
tag_id=self.func_attrs["tag_id"], details["verify_ssl"] = False
) mock_client = MagicMock(return_value=None)
get_proxy_type.assert_called_once() patch_client = patch("salt.utils.vmware.get_vsphere_client", mock_client)
get_proxy_connection.assert_called_once()
get_service_instance.assert_called_once() cert_path = "/test/ca-certificates.crt"
get_vsphere_client.assert_called_once() mock_ca = MagicMock(return_value=cert_path)
self.assertEqual( patch_ca = patch("salt.utils.http.get_ca_bundle", mock_ca)
ret,
{"Tag attached": self.list_attached_tags_return}, 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 logging
import salt.exceptions import salt.exceptions
import salt.proxy.cimc as cimc import salt.proxy.cimc as cimc
from tests.support.mixins import LoaderModuleMockMixin 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 from tests.support.unit import TestCase
log = logging.getLogger(__name__) 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): class CIMCProxyTestCase(TestCase, LoaderModuleMockMixin):
def setup_loader_modules(self): def setup_loader_modules(self):
return {cimc: {"DETAILS": {}, "__pillar__": {}}} return {cimc: {"DETAILS": {}, "__pillar__": {}}}
def setUp(self): def setUp(self):
self.opts = {"proxy": {"username": "xxxx", "password": "xxx", "host": "cimc"}} self.opts = {"proxy": {"username": "xxxx", "password": "xxx", "host": "cimc"}}
self.addCleanup(delattr, self, "opts")
def test_init(self): def test_init(self):
# No host, returns False # No host, returns False
@ -56,3 +150,294 @@ class CIMCProxyTestCase(TestCase, LoaderModuleMockMixin):
): ):
cimc._validate_response_code("404", "9zVG5U8DFZNsTR") cimc._validate_response_code("404", "9zVG5U8DFZNsTR")
mock_logout.assert_called_once_with("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 Tests for cluster related functions in salt.utils.vmware
""" """
import base64 import base64
import logging import logging
import ssl import ssl
@ -1690,13 +1689,13 @@ class PrivateGetServiceInstanceTestCase(TestCase):
mechanism="sspi", 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( with patch("ssl.SSLContext", MagicMock()), patch(
"ssl._create_unverified_context", MagicMock() "ssl._create_unverified_context", MagicMock()
): ):
exc = vim.fault.HostConnectFault() exc = vim.fault.HostConnectFault()
exc.msg = "[SSL: CERTIFICATE_VERIFY_FAILED]" exc.msg = "[SSL: CERTIFICATE_VERIFY_FAILED]"
mock_sc = MagicMock(side_effect=[exc, None]) mock_sc = MagicMock(side_effect=[None])
mock_ssl = MagicMock() mock_ssl = MagicMock()
with patch("salt.utils.vmware.SmartConnect", mock_sc): with patch("salt.utils.vmware.SmartConnect", mock_sc):
@ -1711,19 +1710,11 @@ class PrivateGetServiceInstanceTestCase(TestCase):
mechanism="sspi", mechanism="sspi",
principal="fake_principal", principal="fake_principal",
domain="fake_domain", domain="fake_domain",
verify_ssl=False,
) )
mock_ssl.assert_called_once_with() mock_ssl.assert_called_once_with()
calls = [ calls = [
call(
host="fake_host.fqdn",
user="fake_username",
pwd="fake_password",
protocol="fake_protocol",
port=1,
b64token="fake_token",
mechanism="sspi",
),
call( call(
host="fake_host.fqdn", host="fake_host.fqdn",
user="fake_username", user="fake_username",
@ -1737,21 +1728,18 @@ class PrivateGetServiceInstanceTestCase(TestCase):
] ]
mock_sc.assert_has_calls(calls) 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( with patch("ssl.SSLContext", MagicMock()), patch(
"ssl._create_unverified_context", MagicMock() "ssl._create_unverified_context", MagicMock()
): ):
exc = vim.fault.HostConnectFault() exc = Exception("certificate verify failed")
exc.msg = "[SSL: CERTIFICATE_VERIFY_FAILED]" mock_sc = MagicMock(side_effect=[exc, None])
exc2 = Exception("certificate verify failed")
mock_sc = MagicMock(side_effect=[exc, exc2, None])
mock_ssl_unverif = MagicMock() mock_ssl_unverif = MagicMock()
mock_ssl_context = MagicMock() mock_ssl_context = MagicMock()
with patch("salt.utils.vmware.SmartConnect", mock_sc): with patch("salt.utils.vmware.SmartConnect", mock_sc):
with patch("ssl._create_unverified_context", mock_ssl_unverif): with patch("ssl._create_unverified_context", mock_ssl_unverif):
with patch("ssl.SSLContext", mock_ssl_context): with patch("ssl.SSLContext", mock_ssl_context):
salt.utils.vmware._get_service_instance( salt.utils.vmware._get_service_instance(
host="fake_host.fqdn", host="fake_host.fqdn",
username="fake_username", username="fake_username",
@ -1761,20 +1749,12 @@ class PrivateGetServiceInstanceTestCase(TestCase):
mechanism="sspi", mechanism="sspi",
principal="fake_principal", principal="fake_principal",
domain="fake_domain", domain="fake_domain",
verify_ssl=False,
) )
mock_ssl_context.assert_called_once_with(ssl.PROTOCOL_TLSv1) mock_ssl_context.assert_called_once_with(ssl.PROTOCOL_TLSv1)
mock_ssl_unverif.assert_called_once_with() mock_ssl_unverif.assert_called_once_with()
calls = [ calls = [
call(
host="fake_host.fqdn",
user="fake_username",
pwd="fake_password",
protocol="fake_protocol",
port=1,
b64token="fake_token",
mechanism="sspi",
),
call( call(
host="fake_host.fqdn", host="fake_host.fqdn",
user="fake_username", user="fake_username",
@ -1798,7 +1778,7 @@ class PrivateGetServiceInstanceTestCase(TestCase):
] ]
mock_sc.assert_has_calls(calls) 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") exc = Exception("Exception")
mock_sc = MagicMock(side_effect=exc) mock_sc = MagicMock(side_effect=exc)
@ -1815,13 +1795,12 @@ class PrivateGetServiceInstanceTestCase(TestCase):
domain="fake_domain", domain="fake_domain",
) )
self.assertEqual(mock_sc.call_count, 1) self.assertEqual(mock_sc.call_count, 1)
self.assertIn( self.assertIn(
"Could not connect to host 'fake_host.fqdn'", "Could not connect to host 'fake_host.fqdn'", excinfo.exception.message,
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 = vim.fault.VimFault()
exc.msg = "VimFault" exc.msg = "VimFault"
mock_sc = MagicMock(side_effect=exc) mock_sc = MagicMock(side_effect=exc)
@ -1839,15 +1818,15 @@ class PrivateGetServiceInstanceTestCase(TestCase):
domain="fake_domain", domain="fake_domain",
) )
self.assertEqual(mock_sc.call_count, 1) self.assertEqual(mock_sc.call_count, 1)
self.assertEqual("VimFault", excinfo.Exception.message) 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( with patch("ssl.SSLContext", MagicMock()), patch(
"ssl._create_unverified_context", MagicMock() "ssl._create_unverified_context", MagicMock()
): ):
exc = vim.fault.HostConnectFault() exc = vim.fault.HostConnectFault()
exc.msg = "[SSL: CERTIFICATE_VERIFY_FAILED]" exc.msg = "certificate verify failed"
exc2 = Exception("Exception") exc2 = Exception("Exception")
mock_sc = MagicMock(side_effect=[exc, exc2]) mock_sc = MagicMock(side_effect=[exc, exc2])
@ -1862,22 +1841,47 @@ class PrivateGetServiceInstanceTestCase(TestCase):
mechanism="sspi", mechanism="sspi",
principal="fake_principal", principal="fake_principal",
domain="fake_domain", domain="fake_domain",
verify_ssl=False,
) )
self.assertEqual(mock_sc.call_count, 2) self.assertEqual(mock_sc.call_count, 2)
self.assertIn( self.assertIn(
"Could not connect to host 'fake_host.fqdn'", "Could not connect to host 'fake_host.fqdn'", excinfo.exception.message
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( with patch("ssl.SSLContext", MagicMock()), patch(
"ssl._create_unverified_context", MagicMock() "ssl._create_unverified_context", MagicMock()
): ):
exc = vim.fault.HostConnectFault() exc = vim.fault.HostConnectFault()
exc.msg = "[SSL: CERTIFICATE_VERIFY_FAILED]" exc.msg = "certificate verify failed"
exc2 = vim.fault.VimFault() exc2 = Exception("Exception")
exc2.msg = "VimFault"
mock_sc = MagicMock(side_effect=[exc, exc2]) mock_sc = MagicMock(side_effect=[exc, exc2])
with patch("salt.utils.vmware.SmartConnect", mock_sc): with patch("salt.utils.vmware.SmartConnect", mock_sc):
@ -1891,20 +1895,21 @@ class PrivateGetServiceInstanceTestCase(TestCase):
mechanism="sspi", mechanism="sspi",
principal="fake_principal", principal="fake_principal",
domain="fake_domain", domain="fake_domain",
verify_ssl=False,
) )
self.assertEqual(mock_sc.call_count, 2) self.assertEqual(mock_sc.call_count, 2)
self.assertIn("VimFault", excinfo.Exception.message) 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( with patch("ssl.SSLContext", MagicMock()), patch(
"ssl._create_unverified_context", MagicMock() "ssl._create_unverified_context", MagicMock()
): ):
exc = vim.fault.HostConnectFault() exc = vim.fault.VimFault()
exc.msg = "[SSL: CERTIFICATE_VERIFY_FAILED]" exc.msg = "VimFault"
exc2 = Exception("certificate verify failed") mock_sc = MagicMock(side_effect=[exc])
exc3 = Exception("Exception")
mock_sc = MagicMock(side_effect=[exc, exc2, exc3])
with patch("salt.utils.vmware.SmartConnect", mock_sc): with patch("salt.utils.vmware.SmartConnect", mock_sc):
with self.assertRaises(VMwareConnectionError) as excinfo: with self.assertRaises(VMwareConnectionError) as excinfo:
@ -1917,37 +1922,11 @@ class PrivateGetServiceInstanceTestCase(TestCase):
mechanism="sspi", mechanism="sspi",
principal="fake_principal", principal="fake_principal",
domain="fake_domain", domain="fake_domain",
verify_ssl=False,
) )
self.assertEqual(mock_sc.call_count, 3) self.assertEqual(mock_sc.call_count, 1)
self.assertIn("Exception", excinfo.Exception.message) self.assertIn("VimFault", 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)
@skipIf(not HAS_PYVMOMI, "The 'pyvmomi' library is missing") @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): with patch("salt.utils.vmware._get_service_instance", mock_get_si):
salt.utils.vmware.get_service_instance(host="fake_host") salt.utils.vmware.get_service_instance(host="fake_host")
mock_get_si.assert_called_once_with( 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): def test_no_cached_service_instance_same_host_on_proxy(self):
@ -2001,6 +1988,7 @@ class GetServiceInstanceTestCase(TestCase):
"fake_mechanism", "fake_mechanism",
"fake_principal", "fake_principal",
"fake_domain", "fake_domain",
verify_ssl=True,
) )
def test_cached_service_instance_different_host(self): def test_cached_service_instance_different_host(self):
@ -2038,6 +2026,7 @@ class GetServiceInstanceTestCase(TestCase):
mechanism="fake_mechanism", mechanism="fake_mechanism",
principal="fake_principal", principal="fake_principal",
domain="fake_domain", domain="fake_domain",
verify_ssl=True,
) )
mock_get_si.assert_called_once_with( mock_get_si.assert_called_once_with(
"fake_host", "fake_host",
@ -2048,6 +2037,7 @@ class GetServiceInstanceTestCase(TestCase):
"fake_mechanism", "fake_mechanism",
"fake_principal", "fake_principal",
"fake_domain", "fake_domain",
verify_ssl=True,
) )
def test_unauthenticated_service_instance(self): def test_unauthenticated_service_instance(self):