mirror of
https://github.com/saltstack/salt.git
synced 2025-04-15 17:20:19 +00:00
Merge remote-tracking branch 'upstream/3002.4'
This commit is contained in:
commit
b76442e8f3
64 changed files with 3371 additions and 813 deletions
|
@ -261,7 +261,7 @@ repos:
|
|||
- id: pip-tools-compile
|
||||
alias: compile-ci-linux-py3.5-zmq-requirements
|
||||
name: Linux CI Py3.5 ZeroMQ Requirements
|
||||
files: ^requirements/((base|zeromq|pytest)\.txt|static/((ci|pkg)/(linux|common)\.in|pkg/py3\.5/linux\.txt))$
|
||||
files: ^requirements/((base|zeromq|pytest)\.txt|static/((ci|pkg)/(linux\.in|git-sources\.txt)|pkg/py3\.5/linux\.txt))$
|
||||
pass_filenames: false
|
||||
args:
|
||||
- -v
|
||||
|
@ -270,12 +270,13 @@ repos:
|
|||
- --include=requirements/static/pkg/py{py_version}/linux.txt
|
||||
- --include=requirements/pytest.txt
|
||||
- --include=requirements/static/ci/common.in
|
||||
- --include=requirements/static/ci/git-sources.txt
|
||||
- requirements/static/ci/linux.in
|
||||
|
||||
- id: pip-tools-compile
|
||||
alias: compile-ci-linux-py3.6-zmq-requirements
|
||||
name: Linux CI Py3.6 ZeroMQ Requirements
|
||||
files: ^requirements/((base|zeromq|pytest)\.txt|static/((ci|pkg)/(linux|common)\.in|pkg/py3\.6/linux\.txt))$
|
||||
files: ^requirements/((base|zeromq|pytest)\.txt|static/((ci|pkg)/(linux\.in|git-sources\.txt)|pkg/py3\.6/linux\.txt))$
|
||||
pass_filenames: false
|
||||
args:
|
||||
- -v
|
||||
|
@ -284,12 +285,13 @@ repos:
|
|||
- --include=requirements/static/pkg/py{py_version}/linux.txt
|
||||
- --include=requirements/pytest.txt
|
||||
- --include=requirements/static/ci/common.in
|
||||
- --include=requirements/static/ci/git-sources.txt
|
||||
- requirements/static/ci/linux.in
|
||||
|
||||
- id: pip-tools-compile
|
||||
alias: compile-ci-linux-py3.7-zmq-requirements
|
||||
name: Linux CI Py3.7 ZeroMQ Requirements
|
||||
files: ^requirements/((base|zeromq|pytest)\.txt|static/((ci|pkg)/(linux|common)\.in|pkg/py3\.7/linux\.txt))$
|
||||
files: ^requirements/((base|zeromq|pytest)\.txt|static/((ci|pkg)/(linux\.in|git-sources\.txt)|pkg/py3\.7/linux\.txt))$
|
||||
pass_filenames: false
|
||||
args:
|
||||
- -v
|
||||
|
@ -298,12 +300,13 @@ repos:
|
|||
- --include=requirements/static/pkg/py{py_version}/linux.txt
|
||||
- --include=requirements/pytest.txt
|
||||
- --include=requirements/static/ci/common.in
|
||||
- --include=requirements/static/ci/git-sources.txt
|
||||
- requirements/static/ci/linux.in
|
||||
|
||||
- id: pip-tools-compile
|
||||
alias: compile-ci-linux-py3.8-zmq-requirements
|
||||
name: Linux CI Py3.8 ZeroMQ Requirements
|
||||
files: ^requirements/((base|zeromq|pytest)\.txt|static/((ci|pkg)/(linux|common)\.in|pkg/py3\.8/linux\.txt))$
|
||||
files: ^requirements/((base|zeromq|pytest)\.txt|static/((ci|pkg)/(linux\.in|git-sources\.txt)|pkg/py3\.8/linux\.txt))$
|
||||
pass_filenames: false
|
||||
args:
|
||||
- -v
|
||||
|
@ -312,12 +315,13 @@ repos:
|
|||
- --include=requirements/static/pkg/py{py_version}/linux.txt
|
||||
- --include=requirements/pytest.txt
|
||||
- --include=requirements/static/ci/common.in
|
||||
- --include=requirements/static/ci/git-sources.txt
|
||||
- requirements/static/ci/linux.in
|
||||
|
||||
- id: pip-tools-compile
|
||||
alias: compile-ci-linux-py3.9-zmq-requirements
|
||||
name: Linux CI Py3.9 ZeroMQ Requirements
|
||||
files: ^requirements/((base|zeromq|pytest)\.txt|static/((ci|pkg)/(linux|common)\.in|pkg/py3\.9/linux\.txt))$
|
||||
files: ^requirements/((base|zeromq|pytest)\.txt|static/((ci|pkg)/(linux\.in|git-sources\.txt)|pkg/py3\.9/linux\.txt))$
|
||||
pass_filenames: false
|
||||
args:
|
||||
- -v
|
||||
|
@ -326,6 +330,7 @@ repos:
|
|||
- --include=requirements/static/pkg/py{py_version}/linux.txt
|
||||
- --include=requirements/pytest.txt
|
||||
- --include=requirements/static/ci/common.in
|
||||
- --include=requirements/static/ci/git-sources.txt
|
||||
- requirements/static/ci/linux.in
|
||||
|
||||
- id: pip-tools-compile
|
||||
|
|
109
CHANGELOG.md
109
CHANGELOG.md
|
@ -7,6 +7,42 @@ Versions are `MAJOR.PATCH`.
|
|||
|
||||
# Changelog
|
||||
|
||||
Salt 3002.4 (2021-02-09)
|
||||
========================
|
||||
|
||||
Fixed
|
||||
-----
|
||||
|
||||
- Fix runners that broke when patching for CVE-2021-25281
|
||||
- Fix issue with runners in SSE
|
||||
|
||||
Salt 3002.3 (2021-01-25)
|
||||
========================
|
||||
|
||||
Fixed
|
||||
-----
|
||||
|
||||
- CVE-2020-28243 - Fix local privilege escalation in the restartcheck module. (CVE-2020-28243)
|
||||
- CVE-2020-28972 - Ensure authentication to vcenter, vsphere, and esxi server
|
||||
validates the SSL/TLS certificate by default. If you want to skip SSL verification
|
||||
you can use `verify_ssl: False`. (CVE-2020-28972)
|
||||
- CVE-2020-35662 - Ensure the asam runner, qingcloud, splunk returner, panos
|
||||
proxy, cimc proxy, zenoss module, esxi module, vsphere module, glassfish
|
||||
module, bigip module, and keystone module validate SSL by default. If you want
|
||||
to skip SSL verification you can use `verify_ssl: False`. (CVE-2020-35662)
|
||||
- CVE-2021-25281 - Fix salt-api so it honors eauth credentials for the
|
||||
wheel_async client. (CVE-2021-25281)
|
||||
- CVE-2021-25282 - Fix the salt.wheel.pillar_roots.write method so it is not
|
||||
vulnerable to directory traversal. (CVE-2021-25282)
|
||||
- CVE-2021-25283 - Fix the jinja render to protect against server side template
|
||||
injection attacks. (CVE-2021-25283)
|
||||
- CVE-2021-25284 - Fix cmdmod so it will not log credentials to log levels info
|
||||
and error. (CVE-2021-25284)
|
||||
- CVE-2021-3144 - Fix eauth tokens can be used once after expiration. (CVE-2021-3144)
|
||||
- CVE-2021-3148 - Fix a command injection in the Salt-API when using the Salt-SSH client. (CVE-2021-3148)
|
||||
- CVE-2021-3197 - Fix ssh client to remove ProxyCommand from arguments provided
|
||||
by cli and netapi. (CVE-2021-3197)
|
||||
|
||||
Salt 3002.2 (2020-11-16)
|
||||
========================
|
||||
|
||||
|
@ -273,6 +309,43 @@ Added
|
|||
This flag will be deprecated in the Phosphorus release when this functionality
|
||||
becomes the default. (#58652)
|
||||
|
||||
Salt 3001.6 (2021-02-09)
|
||||
========================
|
||||
|
||||
Fixed
|
||||
-----
|
||||
|
||||
- Fix runners that broke when patching for CVE-2021-25281
|
||||
- Fix issue with runners in SSE
|
||||
|
||||
Salt 3001.5
|
||||
===========
|
||||
|
||||
Fixed
|
||||
-----
|
||||
|
||||
- CVE-2020-28243 - Fix local privilege escalation in the restartcheck module. (CVE-2020-28243)
|
||||
- CVE-2020-28972 - Ensure authentication to vcenter, vsphere, and esxi server
|
||||
validates the SSL/TLS certificate by default. If you want to skip SSL verification
|
||||
you can use `verify_ssl: False`. (CVE-2020-28972)
|
||||
- CVE-2020-35662 - Ensure the asam runner, qingcloud, splunk returner, panos
|
||||
proxy, cimc proxy, zenoss module, esxi module, vsphere module, glassfish
|
||||
module, bigip module, and keystone module validate SSL by default. If you want
|
||||
to skip SSL verification you can use `verify_ssl: False`. (CVE-2020-35662)
|
||||
- CVE-2021-25281 - Fix salt-api so it honors eauth credentials for the
|
||||
wheel_async client. (CVE-2021-25281)
|
||||
- CVE-2021-25282 - Fix the salt.wheel.pillar_roots.write method so it is not
|
||||
vulnerable to directory traversal. (CVE-2021-25282)
|
||||
- CVE-2021-25283 - Fix the jinja render to protect against server side template
|
||||
injection attacks. (CVE-2021-25283)
|
||||
- CVE-2021-25284 - Fix cmdmod so it will not log credentials to log levels info
|
||||
and error. (CVE-2021-25284)
|
||||
- CVE-2021-3144 - Fix eauth tokens can be used once after expiration. (CVE-2021-3144)
|
||||
- CVE-2021-3148 - Fix a command injection in the Salt-API when using the Salt-SSH client. (CVE-2021-3148)
|
||||
- CVE-2021-3197 - Fix ssh client to remove ProxyCommand from arguments provided
|
||||
by cli and netapi. (CVE-2021-3197)
|
||||
|
||||
|
||||
Salt 3001.4
|
||||
===========
|
||||
|
||||
|
@ -727,6 +800,42 @@ Added
|
|||
- [#56637](https://github.com/saltstack/salt/pull/56637) - Add ``win_wua.installed`` to the ``win_wua`` execution module
|
||||
- Clarify how to get the master fingerprint (#54699)
|
||||
|
||||
Salt 3000.8 (2021-02-09)
|
||||
========================
|
||||
|
||||
Fixed
|
||||
-----
|
||||
|
||||
- Fix runners that broke when patching for CVE-2021-25281
|
||||
- Fix issue with runners in SSE
|
||||
|
||||
Salt 3000.7
|
||||
===========
|
||||
|
||||
Fixed
|
||||
-----
|
||||
|
||||
- CVE-2020-28243 - Fix local privilege escalation in the restartcheck module. (CVE-2020-28243)
|
||||
- CVE-2020-28972 - Ensure authentication to vcenter, vsphere, and esxi server
|
||||
validates the SSL/TLS certificate by default. If you want to skip SSL verification
|
||||
you can use `verify_ssl: False`. (CVE-2020-28972)
|
||||
- CVE-2020-35662 - Ensure the asam runner, qingcloud, splunk returner, panos
|
||||
proxy, cimc proxy, zenoss module, esxi module, vsphere module, glassfish
|
||||
module, bigip module, and keystone module validate SSL by default. If you want
|
||||
to skip SSL verification you can use `verify_ssl: False`. (CVE-2020-35662)
|
||||
- CVE-2021-25281 - Fix salt-api so it honors eauth credentials for the
|
||||
wheel_async client. (CVE-2021-25281)
|
||||
- CVE-2021-25282 - Fix the salt.wheel.pillar_roots.write method so it is not
|
||||
vulnerable to directory traversal. (CVE-2021-25282)
|
||||
- CVE-2021-25283 - Fix the jinja render to protect against server side template
|
||||
injection attacks. (CVE-2021-25283)
|
||||
- CVE-2021-25284 - Fix cmdmod so it will not log credentials to log levels info
|
||||
and error. (CVE-2021-25284)
|
||||
- CVE-2021-3144 - Fix eauth tokens can be used once after expiration. (CVE-2021-3144)
|
||||
- CVE-2021-3148 - Fix a command injection in the Salt-API when using the Salt-SSH client. (CVE-2021-3148)
|
||||
- CVE-2021-3197 - Fix ssh client to remove ProxyCommand from arguments provided
|
||||
by cli and netapi. (CVE-2021-3197)
|
||||
|
||||
Salt 3000.6
|
||||
===========
|
||||
|
||||
|
|
41
doc/topics/releases/3000.7.rst
Normal file
41
doc/topics/releases/3000.7.rst
Normal 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.
|
13
doc/topics/releases/3000.8.rst
Normal file
13
doc/topics/releases/3000.8.rst
Normal 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
|
41
doc/topics/releases/3001.5.rst
Normal file
41
doc/topics/releases/3001.5.rst
Normal 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.
|
13
doc/topics/releases/3001.6.rst
Normal file
13
doc/topics/releases/3001.6.rst
Normal 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
|
41
doc/topics/releases/3002.3.rst
Normal file
41
doc/topics/releases/3002.3.rst
Normal 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.
|
13
doc/topics/releases/3002.4.rst
Normal file
13
doc/topics/releases/3002.4.rst
Normal 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
|
2
requirements/static/ci/git-sources.txt
Normal file
2
requirements/static/ci/git-sources.txt
Normal 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
|
0
requirements/static/ci/py3.5/linux.log
Normal file
0
requirements/static/ci/py3.5/linux.log
Normal file
|
@ -2,8 +2,10 @@
|
|||
# This file is autogenerated by pip-compile
|
||||
# To update, run:
|
||||
#
|
||||
# pip-compile -o requirements/static/ci/py3.5/linux.txt -v requirements/static/pkg/py3.5/linux.txt requirements/pytest.txt requirements/static/ci/common.in requirements/static/ci/linux.in
|
||||
# pip-compile -o requirements/static/ci/py3.5/linux.txt -v requirements/static/pkg/py3.5/linux.txt requirements/pytest.txt requirements/static/ci/common.in requirements/static/ci/git-sources.txt requirements/static/ci/linux.in
|
||||
#
|
||||
--extra-index-url https://cdn.githubraw.com/saltstack/vsphere-automation-sdk-python/master/lib/
|
||||
|
||||
adal==1.2.3 # via azure-datalake-store, msrestazure
|
||||
apache-libcloud==2.5.0 ; sys_platform != "win32"
|
||||
appdirs==1.4.4 # via virtualenv
|
||||
|
@ -154,7 +156,7 @@ kazoo==2.6.1 ; sys_platform != "win32" and sys_platform != "darwin"
|
|||
keyring==5.7.1
|
||||
kubernetes==3.0.0
|
||||
libnacl==1.7.1 ; sys_platform != "win32" and sys_platform != "darwin"
|
||||
lxml==4.6.2 # via junos-eznc, ncclient
|
||||
lxml==4.6.2 # via junos-eznc, ncclient, vsphere-automation-sdk
|
||||
mako==1.1.0
|
||||
markupsafe==1.1.1
|
||||
mock==3.0.5
|
||||
|
@ -166,6 +168,10 @@ msrestazure==0.6.3 # via azure-batch, azure-eventgrid, azure-graphrbac, a
|
|||
ncclient==0.6.4 # via junos-eznc
|
||||
netaddr==0.7.19 # via junos-eznc
|
||||
networkx==2.4 # via cfn-lint
|
||||
nsx-policy-python-sdk==3.0.2.0.0.16837625 # via vsphere-automation-sdk
|
||||
nsx-python-sdk==3.0.2.0.0.16837625 # via vsphere-automation-sdk
|
||||
nsx-vmc-aws-integration-python-sdk==3.0.2.0.0.16837625 # via vsphere-automation-sdk
|
||||
nsx-vmc-policy-python-sdk==3.0.2.0.0.16837625 # via vsphere-automation-sdk
|
||||
ntc-templates==1.4.0 # via junos-eznc
|
||||
oauthlib==3.1.0 # via requests-oauthlib
|
||||
oscrypto==1.2.0 # via certvalidator
|
||||
|
@ -218,6 +224,7 @@ smmap==3.0.4 # via gitdb
|
|||
sqlparse==0.4.1
|
||||
sshpubkeys==3.1.0 # via moto
|
||||
strict-rfc3339==0.7
|
||||
suds-jurko==0.6 # via vsphere-automation-sdk
|
||||
tempora==1.14.1
|
||||
terminal==0.4.0 # via ntc-templates
|
||||
textfsm==1.1.0 # via ntc-templates
|
||||
|
@ -225,8 +232,14 @@ timelib==0.2.5
|
|||
toml==0.10.2
|
||||
transitions==0.8.1 # via junos-eznc
|
||||
urllib3==1.24.2
|
||||
vapi-client-bindings==3.5.0 # via vsphere-automation-sdk
|
||||
vapi-common-client==2.19.0 # via nsx-policy-python-sdk, nsx-python-sdk, nsx-vmc-aws-integration-python-sdk, nsx-vmc-policy-python-sdk, vmc-client-bindings, vmc-draas-client-bindings, vsphere-automation-sdk
|
||||
vapi-runtime==2.19.0 # via nsx-policy-python-sdk, nsx-python-sdk, nsx-vmc-aws-integration-python-sdk, nsx-vmc-policy-python-sdk, vapi-client-bindings, vapi-common-client, vmc-client-bindings, vmc-draas-client-bindings, vsphere-automation-sdk
|
||||
vcert==0.7.3 ; sys_platform != "win32"
|
||||
virtualenv==20.0.20
|
||||
vmc-client-bindings==1.32.0 # via vsphere-automation-sdk
|
||||
vmc-draas-client-bindings==1.17.0 # via vsphere-automation-sdk
|
||||
vsphere-automation-sdk==1.46.0
|
||||
watchdog==0.9.0
|
||||
websocket-client==0.40.0 # via docker, kubernetes
|
||||
werkzeug==0.15.6 # via moto
|
||||
|
|
0
requirements/static/ci/py3.6/linux.log
Normal file
0
requirements/static/ci/py3.6/linux.log
Normal file
|
@ -2,8 +2,10 @@
|
|||
# This file is autogenerated by pip-compile
|
||||
# To update, run:
|
||||
#
|
||||
# pip-compile -o requirements/static/ci/py3.6/linux.txt -v requirements/static/pkg/py3.6/linux.txt requirements/pytest.txt requirements/static/ci/common.in requirements/static/ci/linux.in
|
||||
# pip-compile -o requirements/static/ci/py3.6/linux.txt -v requirements/static/pkg/py3.6/linux.txt requirements/pytest.txt requirements/static/ci/common.in requirements/static/ci/git-sources.txt requirements/static/ci/linux.in
|
||||
#
|
||||
--extra-index-url https://cdn.githubraw.com/saltstack/vsphere-automation-sdk-python/master/lib/
|
||||
|
||||
adal==1.2.3 # via azure-datalake-store, msrestazure
|
||||
apache-libcloud==2.5.0 ; sys_platform != "win32"
|
||||
appdirs==1.4.4 # via virtualenv
|
||||
|
@ -154,7 +156,7 @@ kazoo==2.6.1 ; sys_platform != "win32" and sys_platform != "darwin"
|
|||
keyring==5.7.1
|
||||
kubernetes==3.0.0
|
||||
libnacl==1.7.1 ; sys_platform != "win32" and sys_platform != "darwin"
|
||||
lxml==4.6.2 # via junos-eznc, ncclient
|
||||
lxml==4.6.2 # via junos-eznc, ncclient, vsphere-automation-sdk
|
||||
mako==1.1.0
|
||||
markupsafe==1.1.1
|
||||
mock==3.0.5
|
||||
|
@ -166,6 +168,10 @@ msrestazure==0.6.3 # via azure-batch, azure-eventgrid, azure-graphrbac, a
|
|||
ncclient==0.6.4 # via junos-eznc
|
||||
netaddr==0.7.19 # via junos-eznc
|
||||
networkx==2.5 # via cfn-lint
|
||||
nsx-policy-python-sdk==3.0.2.0.0.16837625 # via vsphere-automation-sdk
|
||||
nsx-python-sdk==3.0.2.0.0.16837625 # via vsphere-automation-sdk
|
||||
nsx-vmc-aws-integration-python-sdk==3.0.2.0.0.16837625 # via vsphere-automation-sdk
|
||||
nsx-vmc-policy-python-sdk==3.0.2.0.0.16837625 # via vsphere-automation-sdk
|
||||
ntc-templates==1.4.0 # via junos-eznc
|
||||
oauthlib==3.1.0 # via requests-oauthlib
|
||||
oscrypto==1.2.0 # via certvalidator
|
||||
|
@ -217,6 +223,7 @@ smmap==3.0.4 # via gitdb
|
|||
sqlparse==0.4.1
|
||||
sshpubkeys==3.1.0 # via moto
|
||||
strict-rfc3339==0.7
|
||||
suds-jurko==0.6 # via vsphere-automation-sdk
|
||||
tempora==1.14.1
|
||||
terminal==0.4.0 # via ntc-templates
|
||||
textfsm==1.1.0 # via ntc-templates
|
||||
|
@ -224,8 +231,14 @@ timelib==0.2.5
|
|||
toml==0.10.2
|
||||
transitions==0.8.1 # via junos-eznc
|
||||
urllib3==1.24.2
|
||||
vapi-client-bindings==3.5.0 # via vsphere-automation-sdk
|
||||
vapi-common-client==2.19.0 # via nsx-policy-python-sdk, nsx-python-sdk, nsx-vmc-aws-integration-python-sdk, nsx-vmc-policy-python-sdk, vmc-client-bindings, vmc-draas-client-bindings, vsphere-automation-sdk
|
||||
vapi-runtime==2.19.0 # via nsx-policy-python-sdk, nsx-python-sdk, nsx-vmc-aws-integration-python-sdk, nsx-vmc-policy-python-sdk, vapi-client-bindings, vapi-common-client, vmc-client-bindings, vmc-draas-client-bindings, vsphere-automation-sdk
|
||||
vcert==0.7.3 ; sys_platform != "win32"
|
||||
virtualenv==20.0.20
|
||||
vmc-client-bindings==1.32.0 # via vsphere-automation-sdk
|
||||
vmc-draas-client-bindings==1.17.0 # via vsphere-automation-sdk
|
||||
vsphere-automation-sdk==1.46.0
|
||||
watchdog==0.9.0
|
||||
websocket-client==0.40.0 # via docker, kubernetes
|
||||
werkzeug==0.15.6 # via moto
|
||||
|
|
|
@ -2,8 +2,10 @@
|
|||
# This file is autogenerated by pip-compile
|
||||
# To update, run:
|
||||
#
|
||||
# pip-compile -o requirements/static/ci/py3.7/linux.txt -v requirements/static/pkg/py3.7/linux.txt requirements/pytest.txt requirements/static/ci/common.in requirements/static/ci/linux.in
|
||||
# pip-compile -o requirements/static/ci/py3.7/linux.txt -v requirements/static/pkg/py3.7/linux.txt requirements/pytest.txt requirements/static/ci/common.in requirements/static/ci/git-sources.txt requirements/static/ci/linux.in
|
||||
#
|
||||
--extra-index-url https://cdn.githubraw.com/saltstack/vsphere-automation-sdk-python/master/lib/
|
||||
|
||||
adal==1.2.3 # via azure-datalake-store, msrestazure
|
||||
apache-libcloud==2.5.0 ; sys_platform != "win32"
|
||||
appdirs==1.4.4 # via virtualenv
|
||||
|
@ -152,7 +154,7 @@ kazoo==2.6.1 ; sys_platform != "win32" and sys_platform != "darwin"
|
|||
keyring==5.7.1
|
||||
kubernetes==3.0.0
|
||||
libnacl==1.7.1 ; sys_platform != "win32" and sys_platform != "darwin"
|
||||
lxml==4.6.2 # via junos-eznc, napalm, ncclient
|
||||
lxml==4.6.2 # via junos-eznc, napalm, ncclient, vsphere-automation-sdk
|
||||
mako==1.1.0
|
||||
markupsafe==1.1.1
|
||||
mock==3.0.5
|
||||
|
@ -166,6 +168,10 @@ ncclient==0.6.4 # via junos-eznc
|
|||
netaddr==0.7.19 # via junos-eznc, napalm, pyeapi
|
||||
netmiko==3.2.0 # via napalm
|
||||
networkx==2.5 # via cfn-lint
|
||||
nsx-policy-python-sdk==3.0.2.0.0.16837625 # via vsphere-automation-sdk
|
||||
nsx-python-sdk==3.0.2.0.0.16837625 # via vsphere-automation-sdk
|
||||
nsx-vmc-aws-integration-python-sdk==3.0.2.0.0.16837625 # via vsphere-automation-sdk
|
||||
nsx-vmc-policy-python-sdk==3.0.2.0.0.16837625 # via vsphere-automation-sdk
|
||||
ntc-templates==1.4.0 # via junos-eznc
|
||||
oauthlib==3.1.0 # via requests-oauthlib
|
||||
oscrypto==1.2.0 # via certvalidator
|
||||
|
@ -218,6 +224,7 @@ smmap==3.0.4 # via gitdb
|
|||
sqlparse==0.4.1
|
||||
sshpubkeys==3.1.0 # via moto
|
||||
strict-rfc3339==0.7
|
||||
suds-jurko==0.6 # via vsphere-automation-sdk
|
||||
tempora==1.14.1
|
||||
terminal==0.4.0 # via ntc-templates
|
||||
textfsm==1.1.0 # via napalm, netmiko, ntc-templates
|
||||
|
@ -225,8 +232,14 @@ timelib==0.2.5
|
|||
toml==0.10.2
|
||||
transitions==0.8.1 # via junos-eznc
|
||||
urllib3==1.24.2
|
||||
vapi-client-bindings==3.5.0 # via vsphere-automation-sdk
|
||||
vapi-common-client==2.19.0 # via nsx-policy-python-sdk, nsx-python-sdk, nsx-vmc-aws-integration-python-sdk, nsx-vmc-policy-python-sdk, vmc-client-bindings, vmc-draas-client-bindings, vsphere-automation-sdk
|
||||
vapi-runtime==2.19.0 # via nsx-policy-python-sdk, nsx-python-sdk, nsx-vmc-aws-integration-python-sdk, nsx-vmc-policy-python-sdk, vapi-client-bindings, vapi-common-client, vmc-client-bindings, vmc-draas-client-bindings, vsphere-automation-sdk
|
||||
vcert==0.7.3 ; sys_platform != "win32"
|
||||
virtualenv==20.0.20
|
||||
vmc-client-bindings==1.32.0 # via vsphere-automation-sdk
|
||||
vmc-draas-client-bindings==1.17.0 # via vsphere-automation-sdk
|
||||
vsphere-automation-sdk==1.46.0
|
||||
watchdog==0.9.0
|
||||
websocket-client==0.40.0 # via docker, kubernetes
|
||||
werkzeug==0.15.6 # via moto
|
||||
|
|
|
@ -2,8 +2,10 @@
|
|||
# This file is autogenerated by pip-compile
|
||||
# To update, run:
|
||||
#
|
||||
# pip-compile -o requirements/static/ci/py3.8/linux.txt -v requirements/static/pkg/py3.8/linux.txt requirements/pytest.txt requirements/static/ci/common.in requirements/static/ci/linux.in
|
||||
# pip-compile -o requirements/static/ci/py3.8/linux.txt -v requirements/static/pkg/py3.8/linux.txt requirements/pytest.txt requirements/static/ci/common.in requirements/static/ci/git-sources.txt requirements/static/ci/linux.in
|
||||
#
|
||||
--extra-index-url https://cdn.githubraw.com/saltstack/vsphere-automation-sdk-python/master/lib/
|
||||
|
||||
adal==1.2.3 # via azure-datalake-store, msrestazure
|
||||
apache-libcloud==2.5.0 ; sys_platform != "win32"
|
||||
appdirs==1.4.4 # via virtualenv
|
||||
|
@ -151,7 +153,7 @@ kazoo==2.6.1 ; sys_platform != "win32" and sys_platform != "darwin"
|
|||
keyring==5.7.1
|
||||
kubernetes==3.0.0
|
||||
libnacl==1.7.1 ; sys_platform != "win32" and sys_platform != "darwin"
|
||||
lxml==4.6.2 # via junos-eznc, napalm, ncclient
|
||||
lxml==4.6.2 # via junos-eznc, napalm, ncclient, vsphere-automation-sdk
|
||||
mako==1.1.0
|
||||
markupsafe==1.1.1
|
||||
mock==3.0.5
|
||||
|
@ -165,6 +167,10 @@ ncclient==0.6.4 # via junos-eznc
|
|||
netaddr==0.7.19 # via junos-eznc, napalm, pyeapi
|
||||
netmiko==3.2.0 # via napalm
|
||||
networkx==2.5 # via cfn-lint
|
||||
nsx-policy-python-sdk==3.0.2.0.0.16837625 # via vsphere-automation-sdk
|
||||
nsx-python-sdk==3.0.2.0.0.16837625 # via vsphere-automation-sdk
|
||||
nsx-vmc-aws-integration-python-sdk==3.0.2.0.0.16837625 # via vsphere-automation-sdk
|
||||
nsx-vmc-policy-python-sdk==3.0.2.0.0.16837625 # via vsphere-automation-sdk
|
||||
ntc-templates==1.4.1 # via junos-eznc
|
||||
oauthlib==3.1.0 # via requests-oauthlib
|
||||
oscrypto==1.2.0 # via certvalidator
|
||||
|
@ -217,6 +223,7 @@ smmap==3.0.4 # via gitdb
|
|||
sqlparse==0.4.1
|
||||
sshpubkeys==3.1.0 # via moto
|
||||
strict-rfc3339==0.7
|
||||
suds-jurko==0.6 # via vsphere-automation-sdk
|
||||
tempora==1.14.1
|
||||
terminal==0.4.0 # via ntc-templates
|
||||
textfsm==1.1.0 # via napalm, netmiko, ntc-templates
|
||||
|
@ -224,8 +231,14 @@ timelib==0.2.5
|
|||
toml==0.10.2
|
||||
transitions==0.8.1 # via junos-eznc
|
||||
urllib3==1.24.2
|
||||
vapi-client-bindings==3.5.0 # via vsphere-automation-sdk
|
||||
vapi-common-client==2.19.0 # via nsx-policy-python-sdk, nsx-python-sdk, nsx-vmc-aws-integration-python-sdk, nsx-vmc-policy-python-sdk, vmc-client-bindings, vmc-draas-client-bindings, vsphere-automation-sdk
|
||||
vapi-runtime==2.19.0 # via nsx-policy-python-sdk, nsx-python-sdk, nsx-vmc-aws-integration-python-sdk, nsx-vmc-policy-python-sdk, vapi-client-bindings, vapi-common-client, vmc-client-bindings, vmc-draas-client-bindings, vsphere-automation-sdk
|
||||
vcert==0.7.3 ; sys_platform != "win32"
|
||||
virtualenv==20.0.20
|
||||
vmc-client-bindings==1.32.0 # via vsphere-automation-sdk
|
||||
vmc-draas-client-bindings==1.17.0 # via vsphere-automation-sdk
|
||||
vsphere-automation-sdk==1.46.0
|
||||
watchdog==0.9.0
|
||||
websocket-client==0.40.0 # via docker, kubernetes
|
||||
werkzeug==0.15.6 # via moto
|
||||
|
|
|
@ -2,8 +2,10 @@
|
|||
# This file is autogenerated by pip-compile
|
||||
# To update, run:
|
||||
#
|
||||
# pip-compile -o requirements/static/ci/py3.9/linux.txt -v requirements/static/pkg/py3.9/linux.txt requirements/pytest.txt requirements/static/ci/common.in requirements/static/ci/linux.in
|
||||
# pip-compile -o requirements/static/ci/py3.9/linux.txt -v requirements/static/pkg/py3.9/linux.txt requirements/pytest.txt requirements/static/ci/common.in requirements/static/ci/git-sources.txt requirements/static/ci/linux.in
|
||||
#
|
||||
--extra-index-url https://cdn.githubraw.com/saltstack/vsphere-automation-sdk-python/master/lib/
|
||||
|
||||
adal==1.2.3 # via azure-datalake-store, msrestazure
|
||||
apache-libcloud==2.5.0 ; sys_platform != "win32"
|
||||
appdirs==1.4.4 # via virtualenv
|
||||
|
@ -152,7 +154,7 @@ kazoo==2.6.1 ; sys_platform != "win32" and sys_platform != "darwin"
|
|||
keyring==5.7.1
|
||||
kubernetes==3.0.0
|
||||
libnacl==1.7.1 ; sys_platform != "win32" and sys_platform != "darwin"
|
||||
lxml==4.6.2 # via junos-eznc, napalm, ncclient
|
||||
lxml==4.6.2 # via junos-eznc, napalm, ncclient, vsphere-automation-sdk
|
||||
mako==1.1.0
|
||||
markupsafe==1.1.1
|
||||
mock==3.0.5
|
||||
|
@ -166,6 +168,10 @@ ncclient==0.6.4 # via junos-eznc
|
|||
netaddr==0.7.19 # via junos-eznc, napalm, pyeapi
|
||||
netmiko==3.2.0 # via napalm
|
||||
networkx==2.5 # via cfn-lint
|
||||
nsx-policy-python-sdk==3.0.2.0.0.16837625 # via vsphere-automation-sdk
|
||||
nsx-python-sdk==3.0.2.0.0.16837625 # via vsphere-automation-sdk
|
||||
nsx-vmc-aws-integration-python-sdk==3.0.2.0.0.16837625 # via vsphere-automation-sdk
|
||||
nsx-vmc-policy-python-sdk==3.0.2.0.0.16837625 # via vsphere-automation-sdk
|
||||
ntc-templates==1.4.1 # via junos-eznc
|
||||
oauthlib==3.1.0 # via requests-oauthlib
|
||||
oscrypto==1.2.0 # via certvalidator
|
||||
|
@ -218,6 +224,7 @@ smmap==3.0.4 # via gitdb
|
|||
sqlparse==0.4.1
|
||||
sshpubkeys==3.1.0 # via moto
|
||||
strict-rfc3339==0.7
|
||||
suds-jurko==0.6 # via vsphere-automation-sdk
|
||||
tempora==1.14.1
|
||||
terminal==0.4.0 # via ntc-templates
|
||||
textfsm==1.1.0 # via napalm, netmiko, ntc-templates
|
||||
|
@ -225,8 +232,14 @@ timelib==0.2.5
|
|||
toml==0.10.2
|
||||
transitions==0.8.1 # via junos-eznc
|
||||
urllib3==1.24.2
|
||||
vapi-client-bindings==3.5.0 # via vsphere-automation-sdk
|
||||
vapi-common-client==2.19.0 # via nsx-policy-python-sdk, nsx-python-sdk, nsx-vmc-aws-integration-python-sdk, nsx-vmc-policy-python-sdk, vmc-client-bindings, vmc-draas-client-bindings, vsphere-automation-sdk
|
||||
vapi-runtime==2.19.0 # via nsx-policy-python-sdk, nsx-python-sdk, nsx-vmc-aws-integration-python-sdk, nsx-vmc-policy-python-sdk, vapi-client-bindings, vapi-common-client, vmc-client-bindings, vmc-draas-client-bindings, vsphere-automation-sdk
|
||||
vcert==0.7.3 ; sys_platform != "win32"
|
||||
virtualenv==20.0.20
|
||||
vmc-client-bindings==1.32.0 # via vsphere-automation-sdk
|
||||
vmc-draas-client-bindings==1.17.0 # via vsphere-automation-sdk
|
||||
vsphere-automation-sdk==1.46.0
|
||||
watchdog==0.9.0
|
||||
websocket-client==0.40.0 # via docker, kubernetes
|
||||
werkzeug==0.15.6 # via moto
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Salt's pluggable authentication system
|
||||
|
||||
|
@ -13,9 +12,6 @@ so that any external authentication system can be used inside of Salt
|
|||
# 5. Cache auth token with relative data opts['token_dir']
|
||||
# 6. Interface to verify tokens
|
||||
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
|
||||
import collections
|
||||
import getpass
|
||||
import logging
|
||||
import random
|
||||
|
@ -34,8 +30,6 @@ import salt.utils.minions
|
|||
import salt.utils.user
|
||||
import salt.utils.versions
|
||||
import salt.utils.zeromq
|
||||
from salt.ext import six
|
||||
from salt.ext.six.moves import input
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
@ -56,7 +50,7 @@ AUTH_INTERNAL_KEYWORDS = frozenset(
|
|||
)
|
||||
|
||||
|
||||
class LoadAuth(object):
|
||||
class LoadAuth:
|
||||
"""
|
||||
Wrap the authentication system to handle peripheral components
|
||||
"""
|
||||
|
@ -76,7 +70,7 @@ class LoadAuth(object):
|
|||
"""
|
||||
if "eauth" not in load:
|
||||
return ""
|
||||
fstr = "{0}.auth".format(load["eauth"])
|
||||
fstr = "{}.auth".format(load["eauth"])
|
||||
if fstr not in self.auth:
|
||||
return ""
|
||||
try:
|
||||
|
@ -94,7 +88,7 @@ class LoadAuth(object):
|
|||
"""
|
||||
if "eauth" not in load:
|
||||
return False
|
||||
fstr = "{0}.auth".format(load["eauth"])
|
||||
fstr = "{}.auth".format(load["eauth"])
|
||||
if fstr not in self.auth:
|
||||
return False
|
||||
# When making auth calls, only username, password, auth, and token
|
||||
|
@ -144,7 +138,7 @@ class LoadAuth(object):
|
|||
mod = self.opts["eauth_acl_module"]
|
||||
if not mod:
|
||||
mod = load["eauth"]
|
||||
fstr = "{0}.acl".format(mod)
|
||||
fstr = "{}.acl".format(mod)
|
||||
if fstr not in self.auth:
|
||||
return None
|
||||
fcall = salt.utils.args.format_call(
|
||||
|
@ -163,7 +157,7 @@ class LoadAuth(object):
|
|||
"""
|
||||
if "eauth" not in load:
|
||||
return auth_list
|
||||
fstr = "{0}.process_acl".format(load["eauth"])
|
||||
fstr = "{}.process_acl".format(load["eauth"])
|
||||
if fstr not in self.auth:
|
||||
return auth_list
|
||||
try:
|
||||
|
@ -179,7 +173,7 @@ class LoadAuth(object):
|
|||
"""
|
||||
if "eauth" not in load:
|
||||
return False
|
||||
fstr = "{0}.groups".format(load["eauth"])
|
||||
fstr = "{}.groups".format(load["eauth"])
|
||||
if fstr not in self.auth:
|
||||
return False
|
||||
fcall = salt.utils.args.format_call(
|
||||
|
@ -237,7 +231,7 @@ class LoadAuth(object):
|
|||
if groups:
|
||||
tdata["groups"] = groups
|
||||
|
||||
return self.tokens["{0}.mk_token".format(self.opts["eauth_tokens"])](
|
||||
return self.tokens["{}.mk_token".format(self.opts["eauth_tokens"])](
|
||||
self.opts, tdata
|
||||
)
|
||||
|
||||
|
@ -248,7 +242,7 @@ class LoadAuth(object):
|
|||
"""
|
||||
tdata = {}
|
||||
try:
|
||||
tdata = self.tokens["{0}.get_token".format(self.opts["eauth_tokens"])](
|
||||
tdata = self.tokens["{}.get_token".format(self.opts["eauth_tokens"])](
|
||||
self.opts, tok
|
||||
)
|
||||
except salt.exceptions.SaltDeserializationError:
|
||||
|
@ -268,6 +262,7 @@ class LoadAuth(object):
|
|||
|
||||
if rm_tok:
|
||||
self.rm_token(tok)
|
||||
return {}
|
||||
|
||||
return tdata
|
||||
|
||||
|
@ -275,7 +270,7 @@ class LoadAuth(object):
|
|||
"""
|
||||
List all tokens in eauth_tokn storage.
|
||||
"""
|
||||
return self.tokens["{0}.list_tokens".format(self.opts["eauth_tokens"])](
|
||||
return self.tokens["{}.list_tokens".format(self.opts["eauth_tokens"])](
|
||||
self.opts
|
||||
)
|
||||
|
||||
|
@ -283,7 +278,7 @@ class LoadAuth(object):
|
|||
"""
|
||||
Remove the given token from token storage.
|
||||
"""
|
||||
self.tokens["{0}.rm_token".format(self.opts["eauth_tokens"])](self.opts, tok)
|
||||
self.tokens["{}.rm_token".format(self.opts["eauth_tokens"])](self.opts, tok)
|
||||
|
||||
def authenticate_token(self, load):
|
||||
"""
|
||||
|
@ -459,7 +454,7 @@ class LoadAuth(object):
|
|||
ret["error"] = {
|
||||
"name": "EauthAuthenticationError",
|
||||
"message": 'Authentication failure of type "eauth" occurred for '
|
||||
"user {0}.".format(username),
|
||||
"user {}.".format(username),
|
||||
}
|
||||
return ret
|
||||
|
||||
|
@ -469,7 +464,7 @@ class LoadAuth(object):
|
|||
msg = 'Authentication failure of type "user" occurred'
|
||||
if not auth_ret: # auth_ret can be a boolean or the effective user id
|
||||
if show_username:
|
||||
msg = "{0} for user {1}.".format(msg, username)
|
||||
msg = "{} for user {}.".format(msg, username)
|
||||
ret["error"] = {"name": "UserAuthenticationError", "message": msg}
|
||||
return ret
|
||||
|
||||
|
@ -501,7 +496,7 @@ class LoadAuth(object):
|
|||
return ret
|
||||
|
||||
|
||||
class Resolver(object):
|
||||
class Resolver:
|
||||
"""
|
||||
The class used to resolve options for the command line and for generic
|
||||
interactive interfaces
|
||||
|
@ -514,7 +509,7 @@ class Resolver(object):
|
|||
def _send_token_request(self, load):
|
||||
master_uri = "tcp://{}:{}".format(
|
||||
salt.utils.zeromq.ip_bracket(self.opts["interface"]),
|
||||
six.text_type(self.opts["ret_port"]),
|
||||
str(self.opts["ret_port"]),
|
||||
)
|
||||
with salt.transport.client.ReqChannel.factory(
|
||||
self.opts, crypt="clear", master_uri=master_uri
|
||||
|
@ -530,16 +525,16 @@ class Resolver(object):
|
|||
if not eauth:
|
||||
print("External authentication system has not been specified")
|
||||
return ret
|
||||
fstr = "{0}.auth".format(eauth)
|
||||
fstr = "{}.auth".format(eauth)
|
||||
if fstr not in self.auth:
|
||||
print(
|
||||
(
|
||||
'The specified external authentication system "{0}" is '
|
||||
'The specified external authentication system "{}" is '
|
||||
"not available"
|
||||
).format(eauth)
|
||||
)
|
||||
print(
|
||||
"Available eauth types: {0}".format(
|
||||
"Available eauth types: {}".format(
|
||||
", ".join([k[:-5] for k in self.auth if k.endswith(".auth")])
|
||||
)
|
||||
)
|
||||
|
@ -550,14 +545,14 @@ class Resolver(object):
|
|||
if arg in self.opts:
|
||||
ret[arg] = self.opts[arg]
|
||||
elif arg.startswith("pass"):
|
||||
ret[arg] = getpass.getpass("{0}: ".format(arg))
|
||||
ret[arg] = getpass.getpass("{}: ".format(arg))
|
||||
else:
|
||||
ret[arg] = input("{0}: ".format(arg))
|
||||
ret[arg] = input("{}: ".format(arg))
|
||||
for kwarg, default in list(args["kwargs"].items()):
|
||||
if kwarg in self.opts:
|
||||
ret["kwarg"] = self.opts[kwarg]
|
||||
else:
|
||||
ret[kwarg] = input("{0} [{1}]: ".format(kwarg, default))
|
||||
ret[kwarg] = input("{} [{}]: ".format(kwarg, default))
|
||||
|
||||
# Use current user if empty
|
||||
if "username" in ret and not ret["username"]:
|
||||
|
@ -579,7 +574,7 @@ class Resolver(object):
|
|||
with salt.utils.files.set_umask(0o177):
|
||||
with salt.utils.files.fopen(self.opts["token_file"], "w+") as fp_:
|
||||
fp_.write(tdata["token"])
|
||||
except (IOError, OSError):
|
||||
except OSError:
|
||||
pass
|
||||
return tdata
|
||||
|
||||
|
@ -602,7 +597,7 @@ class Resolver(object):
|
|||
return tdata
|
||||
|
||||
|
||||
class AuthUser(object):
|
||||
class AuthUser:
|
||||
"""
|
||||
Represents a user requesting authentication to the salt master
|
||||
"""
|
||||
|
|
|
@ -478,10 +478,10 @@ class AsyncClientMixin:
|
|||
client = None
|
||||
tag_prefix = None
|
||||
|
||||
def _proc_function(self, fun, low, user, tag, jid, daemonize=True):
|
||||
def _proc_function_remote(self, fun, low, user, tag, jid, daemonize=True):
|
||||
"""
|
||||
Run this method in a multiprocess target to execute the function in a
|
||||
multiprocess and fire the return data on the event bus
|
||||
Run this method in a multiprocess target to execute the function on the
|
||||
master and fire the return data on the event bus
|
||||
"""
|
||||
if daemonize and not salt.utils.platform.is_windows():
|
||||
# Shutdown the multiprocessing before daemonizing
|
||||
|
@ -497,7 +497,52 @@ class AsyncClientMixin:
|
|||
low["__user__"] = user
|
||||
low["__tag__"] = tag
|
||||
|
||||
return self.low(fun, low, full_return=False)
|
||||
try:
|
||||
return self.cmd_sync(low)
|
||||
except salt.exceptions.EauthAuthenticationError as exc:
|
||||
log.error(exc)
|
||||
|
||||
def _proc_function(self, fun, low, user, tag, jid, daemonize=True):
|
||||
"""
|
||||
Run this method in a multiprocess target to execute the function
|
||||
locally and fire the return data on the event bus
|
||||
"""
|
||||
if daemonize and not salt.utils.platform.is_windows():
|
||||
# Shutdown the multiprocessing before daemonizing
|
||||
salt.log.setup.shutdown_multiprocessing_logging()
|
||||
|
||||
salt.utils.process.daemonize()
|
||||
|
||||
# Reconfigure multiprocessing logging after daemonizing
|
||||
salt.log.setup.setup_multiprocessing_logging()
|
||||
|
||||
# pack a few things into low
|
||||
low["__jid__"] = jid
|
||||
low["__user__"] = user
|
||||
low["__tag__"] = tag
|
||||
|
||||
return self.low(fun, low)
|
||||
|
||||
def _proc_function_local(self, fun, low, user, tag, jid, daemonize=True):
|
||||
"""
|
||||
Run this method in a multiprocess target to execute the function
|
||||
locally and fire the return data on the event bus
|
||||
"""
|
||||
if daemonize and not salt.utils.platform.is_windows():
|
||||
# Shutdown the multiprocessing before daemonizing
|
||||
salt.log.setup.shutdown_multiprocessing_logging()
|
||||
|
||||
salt.utils.process.daemonize()
|
||||
|
||||
# Reconfigure multiprocessing logging after daemonizing
|
||||
salt.log.setup.setup_multiprocessing_logging()
|
||||
|
||||
# pack a few things into low
|
||||
low["__jid__"] = jid
|
||||
low["__user__"] = user
|
||||
low["__tag__"] = tag
|
||||
|
||||
return self.low(fun, low)
|
||||
|
||||
def cmd_async(self, low):
|
||||
"""
|
||||
|
@ -525,14 +570,18 @@ class AsyncClientMixin:
|
|||
tag = salt.utils.event.tagify(jid, prefix=self.tag_prefix)
|
||||
return {"tag": tag, "jid": jid}
|
||||
|
||||
def asynchronous(self, fun, low, user="UNKNOWN", pub=None):
|
||||
def asynchronous(self, fun, low, user="UNKNOWN", pub=None, local=True):
|
||||
"""
|
||||
Execute the function in a multiprocess and return the event tag to use
|
||||
to watch for the return
|
||||
"""
|
||||
if local:
|
||||
proc_func = self._proc_function
|
||||
else:
|
||||
proc_func = self._proc_function_remote
|
||||
async_pub = pub if pub is not None else self._gen_async_pub()
|
||||
proc = salt.utils.process.SignalHandlingProcess(
|
||||
target=self._proc_function,
|
||||
target=proc_func,
|
||||
name="ProcessFunc",
|
||||
args=(fun, low, user, async_pub["tag"], async_pub["jid"]),
|
||||
)
|
||||
|
|
|
@ -39,12 +39,58 @@ class SSHClient:
|
|||
# Salt API should never offer a custom roster!
|
||||
self.opts["__disable_custom_roster"] = disable_custom_roster
|
||||
|
||||
def sanitize_kwargs(self, kwargs):
|
||||
roster_vals = [
|
||||
("host", str),
|
||||
("ssh_user", str),
|
||||
("ssh_passwd", str),
|
||||
("ssh_port", int),
|
||||
("ssh_sudo", bool),
|
||||
("ssh_sudo_user", str),
|
||||
("ssh_priv", str),
|
||||
("ssh_priv_passwd", str),
|
||||
("ssh_identities_only", bool),
|
||||
("ssh_remote_port_forwards", str),
|
||||
("ssh_options", list),
|
||||
("roster_file", str),
|
||||
("rosters", list),
|
||||
("ignore_host_keys", bool),
|
||||
("raw_shell", bool),
|
||||
]
|
||||
sane_kwargs = {}
|
||||
for name, kind in roster_vals:
|
||||
if name not in kwargs:
|
||||
continue
|
||||
try:
|
||||
val = kind(kwargs[name])
|
||||
except ValueError:
|
||||
log.warn("Unable to cast kwarg %s", name)
|
||||
continue
|
||||
if kind is bool or kind is int:
|
||||
sane_kwargs[name] = val
|
||||
elif kind is str:
|
||||
if val.find("ProxyCommand") != -1:
|
||||
log.warn("Filter unsafe value for kwarg %s", name)
|
||||
continue
|
||||
sane_kwargs[name] = val
|
||||
elif kind is list:
|
||||
sane_val = []
|
||||
for item in val:
|
||||
# This assumes the values are strings
|
||||
if item.find("ProxyCommand") != -1:
|
||||
log.warn("Filter unsafe value for kwarg %s", name)
|
||||
continue
|
||||
sane_val.append(item)
|
||||
sane_kwargs[name] = sane_val
|
||||
return sane_kwargs
|
||||
|
||||
def _prep_ssh(
|
||||
self, tgt, fun, arg=(), timeout=None, tgt_type="glob", kwarg=None, **kwargs
|
||||
):
|
||||
"""
|
||||
Prepare the arguments
|
||||
"""
|
||||
kwargs = self.sanitize_kwargs(kwargs)
|
||||
opts = copy.deepcopy(self.opts)
|
||||
opts.update(kwargs)
|
||||
if timeout:
|
||||
|
|
|
@ -141,6 +141,14 @@ def query(params=None):
|
|||
"secret_access_key", get_configured_provider(), __opts__, search_global=False
|
||||
)
|
||||
|
||||
verify_ssl = config.get_cloud_config_value(
|
||||
"verify_ssl",
|
||||
get_configured_provider(),
|
||||
__opts__,
|
||||
default=True,
|
||||
search_global=False,
|
||||
)
|
||||
|
||||
# public interface parameters
|
||||
real_parameters = {
|
||||
"access_key_id": access_key_id,
|
||||
|
@ -171,7 +179,7 @@ def query(params=None):
|
|||
# print('parameters:')
|
||||
# pprint.pprint(real_parameters)
|
||||
|
||||
request = requests.get(path, params=real_parameters, verify=False)
|
||||
request = requests.get(path, params=real_parameters, verify=verify_ssl)
|
||||
|
||||
# print('url:')
|
||||
# print(request.url)
|
||||
|
|
|
@ -257,9 +257,15 @@ def _get_si():
|
|||
port = config.get_cloud_config_value(
|
||||
"port", get_configured_provider(), __opts__, search_global=False, default=443
|
||||
)
|
||||
|
||||
verify_ssl = config.get_cloud_config_value(
|
||||
"verify_ssl",
|
||||
get_configured_provider(),
|
||||
__opts__,
|
||||
search_global=False,
|
||||
default=True,
|
||||
)
|
||||
return salt.utils.vmware.get_service_instance(
|
||||
url, username, password, protocol=protocol, port=port
|
||||
url, username, password, protocol=protocol, port=port, verify_ssl=verify_ssl
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
:codeauthor: :email:`Rod McKenzie (roderick.mckenzie@morganstanley.com)`
|
||||
:codeauthor: :email:`Alexandru Bleotu (alexandru.bleotu@morganstanley.com)`
|
||||
|
@ -9,11 +8,7 @@
|
|||
VCenter configuration schemas
|
||||
"""
|
||||
|
||||
# Import Python libs
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
|
||||
# Import Salt libs
|
||||
from salt.utils.schema import ArrayItem, IntegerItem, Schema, StringItem
|
||||
from salt.utils.schema import ArrayItem, BooleanItem, IntegerItem, Schema, StringItem
|
||||
|
||||
|
||||
class VCenterEntitySchema(Schema):
|
||||
|
@ -48,6 +43,8 @@ class VCenterProxySchema(Schema):
|
|||
mechanism = StringItem(required=True, enum=["userpass", "sspi"])
|
||||
username = StringItem()
|
||||
passwords = ArrayItem(min_items=1, items=StringItem(), unique_items=True)
|
||||
verify_ssl = BooleanItem()
|
||||
ca_bundle = StringItem()
|
||||
|
||||
domain = StringItem()
|
||||
principal = StringItem(default="host")
|
||||
|
|
|
@ -2063,7 +2063,7 @@ class ClearFuncs(TransportMethods):
|
|||
fun = clear_load.pop("fun")
|
||||
runner_client = salt.runner.RunnerClient(self.opts)
|
||||
return runner_client.asynchronous(
|
||||
fun, clear_load.get("kwarg", {}), username
|
||||
fun, clear_load.get("kwarg", {}), username, local=True
|
||||
)
|
||||
except Exception as exc: # pylint: disable=broad-except
|
||||
log.error("Exception occurred while introspecting %s: %s", fun, exc)
|
||||
|
|
|
@ -4,7 +4,6 @@ An execution module which can manipulate an f5 bigip via iControl REST
|
|||
:platform: f5_bigip_11.6
|
||||
"""
|
||||
|
||||
|
||||
import salt.exceptions
|
||||
import salt.utils.json
|
||||
|
||||
|
@ -44,7 +43,7 @@ def _build_session(username, password, trans_label=None):
|
|||
|
||||
bigip = requests.session()
|
||||
bigip.auth = (username, password)
|
||||
bigip.verify = False
|
||||
bigip.verify = True
|
||||
bigip.headers.update({"Content-Type": "application/json"})
|
||||
|
||||
if trans_label:
|
||||
|
|
|
@ -78,6 +78,12 @@ def __virtual__():
|
|||
return __virtualname__
|
||||
|
||||
|
||||
def _log_cmd(cmd):
|
||||
if not isinstance(cmd, list):
|
||||
return cmd.split()[0].strip()
|
||||
return cmd[0].strip()
|
||||
|
||||
|
||||
def _check_cb(cb_):
|
||||
"""
|
||||
If the callback is None or is not callable, return a lambda that returns
|
||||
|
@ -387,22 +393,13 @@ def _run(
|
|||
)
|
||||
env[bad_env_key] = ""
|
||||
|
||||
def _get_stripped(cmd):
|
||||
# Return stripped command string copies to improve logging.
|
||||
if isinstance(cmd, list):
|
||||
return [x.strip() if isinstance(x, str) else x for x in cmd]
|
||||
elif isinstance(cmd, str):
|
||||
return cmd.strip()
|
||||
else:
|
||||
return cmd
|
||||
|
||||
if output_loglevel is not None:
|
||||
# Always log the shell commands at INFO unless quiet logging is
|
||||
# requested. The command output is what will be controlled by the
|
||||
# 'loglevel' parameter.
|
||||
msg = "Executing command {}{}{} {}{}in directory '{}'{}".format(
|
||||
"'" if not isinstance(cmd, list) else "",
|
||||
_get_stripped(cmd),
|
||||
_log_cmd(cmd),
|
||||
"'" if not isinstance(cmd, list) else "",
|
||||
"as user '{}' ".format(runas) if runas else "",
|
||||
"in group '{}' ".format(group) if group else "",
|
||||
|
@ -728,7 +725,7 @@ def _run(
|
|||
log.error(
|
||||
"Failed to decode stdout from command %s, non-decodable "
|
||||
"characters have been replaced",
|
||||
cmd,
|
||||
_log_cmd(cmd),
|
||||
)
|
||||
|
||||
try:
|
||||
|
@ -746,7 +743,7 @@ def _run(
|
|||
log.error(
|
||||
"Failed to decode stderr from command %s, non-decodable "
|
||||
"characters have been replaced",
|
||||
cmd,
|
||||
_log_cmd(cmd),
|
||||
)
|
||||
|
||||
if rstrip:
|
||||
|
@ -846,7 +843,9 @@ def _run(
|
|||
if not ignore_retcode and ret["retcode"] != 0:
|
||||
if output_loglevel < LOG_LEVELS["error"]:
|
||||
output_loglevel = LOG_LEVELS["error"]
|
||||
msg = "Command '{}' failed with return code: {}".format(cmd, ret["retcode"])
|
||||
msg = "Command '{}' failed with return code: {}".format(
|
||||
_log_cmd(cmd), ret["retcode"]
|
||||
)
|
||||
log.error(log_callback(msg))
|
||||
if ret["stdout"]:
|
||||
log.log(output_loglevel, "stdout: %s", log_callback(ret["stdout"]))
|
||||
|
@ -1220,7 +1219,9 @@ def run(
|
|||
if not ignore_retcode and ret["retcode"] != 0:
|
||||
if lvl < LOG_LEVELS["error"]:
|
||||
lvl = LOG_LEVELS["error"]
|
||||
msg = "Command '{}' failed with return code: {}".format(cmd, ret["retcode"])
|
||||
msg = "Command '{}' failed with return code: {}".format(
|
||||
_log_cmd(cmd), ret["retcode"]
|
||||
)
|
||||
log.error(log_callback(msg))
|
||||
if raise_err:
|
||||
raise CommandExecutionError(
|
||||
|
|
|
@ -124,7 +124,7 @@ def _api_get(path, server=None):
|
|||
url=_get_url(server["ssl"], server["url"], server["port"], path),
|
||||
auth=_get_auth(server["user"], server["password"]),
|
||||
headers=_get_headers(),
|
||||
verify=False,
|
||||
verify=True,
|
||||
)
|
||||
return _api_response(response)
|
||||
|
||||
|
@ -139,7 +139,7 @@ def _api_post(path, data, server=None):
|
|||
auth=_get_auth(server["user"], server["password"]),
|
||||
headers=_get_headers(),
|
||||
data=salt.utils.json.dumps(data),
|
||||
verify=False,
|
||||
verify=True,
|
||||
)
|
||||
return _api_response(response)
|
||||
|
||||
|
@ -154,7 +154,7 @@ def _api_delete(path, data, server=None):
|
|||
auth=_get_auth(server["user"], server["password"]),
|
||||
headers=_get_headers(),
|
||||
params=data,
|
||||
verify=False,
|
||||
verify=True,
|
||||
)
|
||||
return _api_response(response)
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ Module for handling openstack keystone calls.
|
|||
keystone.tenant: admin
|
||||
keystone.tenant_id: f80919baedab48ec8931f200c65a50df
|
||||
keystone.auth_url: 'http://127.0.0.1:5000/v2.0/'
|
||||
keystone.verify_ssl: True
|
||||
|
||||
OR (for token based authentication)
|
||||
|
||||
|
@ -31,6 +32,7 @@ Module for handling openstack keystone calls.
|
|||
keystone.tenant: admin
|
||||
keystone.tenant_id: f80919baedab48ec8931f200c65a50df
|
||||
keystone.auth_url: 'http://127.0.0.1:5000/v2.0/'
|
||||
keystone.verify_ssl: True
|
||||
|
||||
openstack2:
|
||||
keystone.user: admin
|
||||
|
@ -38,6 +40,7 @@ Module for handling openstack keystone calls.
|
|||
keystone.tenant: admin
|
||||
keystone.tenant_id: f80919baedab48ec8931f200c65a50df
|
||||
keystone.auth_url: 'http://127.0.0.2:5000/v2.0/'
|
||||
keystone.verify_ssl: True
|
||||
|
||||
With this configuration in place, any of the keystone functions can make use
|
||||
of a configuration profile by declaring it explicitly.
|
||||
|
@ -117,6 +120,7 @@ def _get_kwargs(profile=None, **connection_args):
|
|||
endpoint = get("endpoint", "http://127.0.0.1:35357/v2.0")
|
||||
user_domain_name = get("user_domain_name", "Default")
|
||||
project_domain_name = get("project_domain_name", "Default")
|
||||
verify_ssl = get("verify_ssl", True)
|
||||
if token:
|
||||
kwargs = {"token": token, "endpoint": endpoint}
|
||||
else:
|
||||
|
@ -133,6 +137,7 @@ def _get_kwargs(profile=None, **connection_args):
|
|||
# this ensures it's only passed in when defined
|
||||
if insecure:
|
||||
kwargs["insecure"] = True
|
||||
kwargs["verify_ssl"] = verify_ssl
|
||||
return kwargs
|
||||
|
||||
|
||||
|
@ -150,7 +155,7 @@ def api_version(profile=None, **connection_args):
|
|||
auth_url = kwargs.get("auth_url", kwargs.get("endpoint", None))
|
||||
try:
|
||||
return salt.utils.http.query(
|
||||
auth_url, decode=True, decode_type="json", verify_ssl=False
|
||||
auth_url, decode=True, decode_type="json", verify_ssl=kwargs["verify_ssl"]
|
||||
)["dict"]["version"]["id"]
|
||||
except KeyError:
|
||||
return None
|
||||
|
@ -392,7 +397,7 @@ def endpoint_list(profile=None, **connection_args):
|
|||
value: getattr(endpoint, value)
|
||||
for value in dir(endpoint)
|
||||
if not value.startswith("_")
|
||||
and isinstance(getattr(endpoint, value), ((str,), dict, bool))
|
||||
and isinstance(getattr(endpoint, value), (str, dict, bool))
|
||||
}
|
||||
return ret
|
||||
|
||||
|
@ -559,7 +564,7 @@ def role_list(profile=None, **connection_args):
|
|||
value: getattr(role, value)
|
||||
for value in dir(role)
|
||||
if not value.startswith("_")
|
||||
and isinstance(getattr(role, value), ((str,), dict, bool))
|
||||
and isinstance(getattr(role, value), (str, dict, bool))
|
||||
}
|
||||
return ret
|
||||
|
||||
|
@ -628,7 +633,7 @@ def service_get(service_id=None, name=None, profile=None, **connection_args):
|
|||
value: getattr(service, value)
|
||||
for value in dir(service)
|
||||
if not value.startswith("_")
|
||||
and isinstance(getattr(service, value), ((str,), dict, bool))
|
||||
and isinstance(getattr(service, value), (str, dict, bool))
|
||||
}
|
||||
return ret
|
||||
|
||||
|
@ -650,7 +655,7 @@ def service_list(profile=None, **connection_args):
|
|||
value: getattr(service, value)
|
||||
for value in dir(service)
|
||||
if not value.startswith("_")
|
||||
and isinstance(getattr(service, value), ((str,), dict, bool))
|
||||
and isinstance(getattr(service, value), (str, dict, bool))
|
||||
}
|
||||
return ret
|
||||
|
||||
|
@ -800,7 +805,7 @@ def tenant_get(tenant_id=None, name=None, profile=None, **connection_args):
|
|||
value: getattr(tenant, value)
|
||||
for value in dir(tenant)
|
||||
if not value.startswith("_")
|
||||
and isinstance(getattr(tenant, value), ((str,), dict, bool))
|
||||
and isinstance(getattr(tenant, value), (str, dict, bool))
|
||||
}
|
||||
return ret
|
||||
|
||||
|
@ -858,7 +863,7 @@ def tenant_list(profile=None, **connection_args):
|
|||
value: getattr(tenant, value)
|
||||
for value in dir(tenant)
|
||||
if not value.startswith("_")
|
||||
and isinstance(getattr(tenant, value), ((str,), dict, bool))
|
||||
and isinstance(getattr(tenant, value), (str, dict, bool))
|
||||
}
|
||||
return ret
|
||||
|
||||
|
@ -933,7 +938,7 @@ def tenant_update(
|
|||
value: getattr(updated, value)
|
||||
for value in dir(updated)
|
||||
if not value.startswith("_")
|
||||
and isinstance(getattr(updated, value), ((str,), dict, bool))
|
||||
and isinstance(getattr(updated, value), (str, dict, bool))
|
||||
}
|
||||
|
||||
|
||||
|
@ -1029,7 +1034,7 @@ def user_list(profile=None, **connection_args):
|
|||
value: getattr(user, value, None)
|
||||
for value in dir(user)
|
||||
if not value.startswith("_")
|
||||
and isinstance(getattr(user, value, None), ((str,), dict, bool))
|
||||
and isinstance(getattr(user, value, None), (str, dict, bool))
|
||||
}
|
||||
tenant_id = getattr(user, "tenantId", None)
|
||||
if tenant_id:
|
||||
|
@ -1069,7 +1074,7 @@ def user_get(user_id=None, name=None, profile=None, **connection_args):
|
|||
value: getattr(user, value, None)
|
||||
for value in dir(user)
|
||||
if not value.startswith("_")
|
||||
and isinstance(getattr(user, value, None), ((str,), dict, bool))
|
||||
and isinstance(getattr(user, value, None), (str, dict, bool))
|
||||
}
|
||||
|
||||
tenant_id = getattr(user, "tenantId", None)
|
||||
|
@ -1499,7 +1504,7 @@ tenant_id=7167a092ece84bae8cead4bf9d15bb3b
|
|||
value: getattr(role, value)
|
||||
for value in dir(role)
|
||||
if not value.startswith("_")
|
||||
and isinstance(getattr(role, value), ((str,), dict, bool))
|
||||
and isinstance(getattr(role, value), (str, dict, bool))
|
||||
}
|
||||
else:
|
||||
for role in kstone.roles.roles_for_user(user=user_id, tenant=tenant_id):
|
||||
|
|
|
@ -11,6 +11,7 @@ https://packages.debian.org/debian-goodies) and psdel by Sam Morris.
|
|||
"""
|
||||
import os
|
||||
import re
|
||||
import shlex
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
|
@ -613,7 +614,8 @@ def restartcheck(ignorelist=None, blacklist=None, excludepid=None, **kwargs):
|
|||
for package in packages:
|
||||
_check_timeout(start_time, timeout)
|
||||
cmd = cmd_pkg_query + package
|
||||
paths = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
|
||||
cmd = shlex.split(cmd)
|
||||
paths = subprocess.Popen(cmd, stdout=subprocess.PIPE)
|
||||
|
||||
while True:
|
||||
_check_timeout(start_time, timeout)
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -3,8 +3,6 @@ Module for working with the Zenoss API
|
|||
|
||||
.. versionadded:: 2016.3.0
|
||||
|
||||
:depends: requests
|
||||
|
||||
:configuration: This module requires a 'zenoss' entry in the master/minion config.
|
||||
|
||||
For example:
|
||||
|
@ -15,26 +13,16 @@ Module for working with the Zenoss API
|
|||
hostname: https://zenoss.example.com
|
||||
username: admin
|
||||
password: admin123
|
||||
verify_ssl: True
|
||||
ca_bundle: /etc/ssl/certs/ca-certificates.crt
|
||||
"""
|
||||
|
||||
import logging
|
||||
import re
|
||||
|
||||
import salt.utils.http
|
||||
import salt.utils.json
|
||||
|
||||
try:
|
||||
import requests
|
||||
|
||||
HAS_LIBS = True
|
||||
except ImportError:
|
||||
HAS_LIBS = False
|
||||
|
||||
|
||||
# Disable INFO level logs from requests/urllib3
|
||||
urllib3_logger = logging.getLogger("urllib3")
|
||||
urllib3_logger.setLevel(logging.WARNING)
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
__virtualname__ = "zenoss"
|
||||
|
@ -44,14 +32,7 @@ def __virtual__():
|
|||
"""
|
||||
Only load if requests is installed
|
||||
"""
|
||||
if HAS_LIBS:
|
||||
return __virtualname__
|
||||
else:
|
||||
return (
|
||||
False,
|
||||
"The '{}' module could not be loaded: "
|
||||
"'requests' is not installed.".format(__virtualname__),
|
||||
)
|
||||
return __virtualname__
|
||||
|
||||
|
||||
ROUTERS = {
|
||||
|
@ -75,11 +56,13 @@ def _session():
|
|||
"""
|
||||
|
||||
config = __salt__["config.option"]("zenoss")
|
||||
session = requests.session()
|
||||
session.auth = (config.get("username"), config.get("password"))
|
||||
session.verify = False
|
||||
session.headers.update({"Content-type": "application/json; charset=utf-8"})
|
||||
return session
|
||||
return salt.utils.http.session(
|
||||
user=config.get("username"),
|
||||
password=config.get("password"),
|
||||
verify_ssl=config.get("verify_ssl", True),
|
||||
ca_bundle=config.get("ca_bundle"),
|
||||
headers={"Content-type": "application/json; charset=utf-8"},
|
||||
)
|
||||
|
||||
|
||||
def _router_request(router, method, data=None):
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Pillar data from vCenter or an ESXi host
|
||||
|
||||
|
@ -142,18 +141,12 @@ Optionally, the following keyword arguments can be passed to the ext_pillar for
|
|||
part of the pillar regardless of this setting.
|
||||
|
||||
"""
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
|
||||
# Import python libs
|
||||
import logging
|
||||
|
||||
# Import salt libs
|
||||
import salt.utils.dictupdate as dictupdate
|
||||
import salt.utils.vmware
|
||||
|
||||
# Import 3rd-party libs
|
||||
from salt.ext import six
|
||||
|
||||
try:
|
||||
# pylint: disable=no-name-in-module
|
||||
from pyVmomi import vim
|
||||
|
@ -370,7 +363,12 @@ def ext_pillar(minion_id, pillar, **kwargs): # pylint: disable=W0613
|
|||
vmware_pillar[pillar_key] = {}
|
||||
try:
|
||||
_conn = salt.utils.vmware.get_service_instance(
|
||||
host, username, password, protocol, port
|
||||
host,
|
||||
username,
|
||||
password,
|
||||
protocol,
|
||||
port,
|
||||
verify_ssl=kwargs.get("verify_ssl", True),
|
||||
)
|
||||
if _conn:
|
||||
data = None
|
||||
|
@ -410,12 +408,10 @@ def ext_pillar(minion_id, pillar, **kwargs): # pylint: disable=W0613
|
|||
)
|
||||
except RuntimeError:
|
||||
log.error(
|
||||
(
|
||||
"A runtime error occurred in the vmware_pillar, "
|
||||
"this is likely caused by an infinite recursion in "
|
||||
"a requested attribute. Verify your requested attributes "
|
||||
"and reconfigure the pillar."
|
||||
)
|
||||
"A runtime error occurred in the vmware_pillar, "
|
||||
"this is likely caused by an infinite recursion in "
|
||||
"a requested attribute. Verify your requested attributes "
|
||||
"and reconfigure the pillar."
|
||||
)
|
||||
|
||||
return vmware_pillar
|
||||
|
@ -435,7 +431,7 @@ def _recurse_config_to_dict(t_data):
|
|||
return t_list
|
||||
elif isinstance(t_data, dict):
|
||||
t_dict = {}
|
||||
for k, v in six.iteritems(t_data):
|
||||
for k, v in t_data.items():
|
||||
t_dict[k] = _recurse_config_to_dict(v)
|
||||
return t_dict
|
||||
else:
|
||||
|
|
|
@ -39,6 +39,7 @@ the ID.
|
|||
host: <ip or dns name of cimc host>
|
||||
username: <cimc username>
|
||||
password: <cimc password>
|
||||
verify_ssl: True
|
||||
|
||||
proxytype
|
||||
^^^^^^^^^
|
||||
|
@ -129,6 +130,10 @@ def init(opts):
|
|||
DETAILS["host"] = opts["proxy"]["host"]
|
||||
DETAILS["username"] = opts["proxy"].get("username")
|
||||
DETAILS["password"] = opts["proxy"].get("password")
|
||||
verify_ssl = opts["proxy"].get("verify_ssl")
|
||||
if verify_ssl is None:
|
||||
verify_ssl = True
|
||||
DETAILS["verify_ssl"] = verify_ssl
|
||||
|
||||
# Ensure connectivity to the device
|
||||
log.debug("Attempting to connect to cimc proxy host.")
|
||||
|
@ -160,7 +165,7 @@ def set_config_modify(dn=None, inconfig=None, hierarchical=False):
|
|||
method="POST",
|
||||
decode_type="plain",
|
||||
decode=True,
|
||||
verify_ssl=False,
|
||||
verify_ssl=DETAILS["verify_ssl"],
|
||||
raise_error=True,
|
||||
status=True,
|
||||
headers=DETAILS["headers"],
|
||||
|
@ -197,7 +202,7 @@ def get_config_resolver_class(cid=None, hierarchical=False):
|
|||
method="POST",
|
||||
decode_type="plain",
|
||||
decode=True,
|
||||
verify_ssl=False,
|
||||
verify_ssl=DETAILS["verify_ssl"],
|
||||
raise_error=True,
|
||||
status=True,
|
||||
headers=DETAILS["headers"],
|
||||
|
@ -228,7 +233,7 @@ def logon():
|
|||
method="POST",
|
||||
decode_type="plain",
|
||||
decode=True,
|
||||
verify_ssl=False,
|
||||
verify_ssl=DETAILS["verify_ssl"],
|
||||
raise_error=False,
|
||||
status=True,
|
||||
headers=DETAILS["headers"],
|
||||
|
@ -258,7 +263,7 @@ def logout(cookie=None):
|
|||
method="POST",
|
||||
decode_type="plain",
|
||||
decode=True,
|
||||
verify_ssl=False,
|
||||
verify_ssl=DETAILS["verify_ssl"],
|
||||
raise_error=True,
|
||||
headers=DETAILS["headers"],
|
||||
)
|
||||
|
|
|
@ -52,6 +52,7 @@ the device with username and password.
|
|||
host: <ip or dns name of panos host>
|
||||
username: <panos username>
|
||||
password: <panos password>
|
||||
verify_ssl: True
|
||||
|
||||
proxytype
|
||||
^^^^^^^^^
|
||||
|
@ -267,6 +268,7 @@ def init(opts):
|
|||
|
||||
# Set configuration details
|
||||
DETAILS["host"] = opts["proxy"]["host"]
|
||||
DETAILS["verify_ssl"] = opts["proxy"].get("verify_ssl", True)
|
||||
if "serial" in opts["proxy"]:
|
||||
DETAILS["serial"] = opts["proxy"].get("serial")
|
||||
if "apikey" in opts["proxy"]:
|
||||
|
@ -314,7 +316,7 @@ def call(payload=None):
|
|||
method="POST",
|
||||
decode_type="plain",
|
||||
decode=True,
|
||||
verify_ssl=False,
|
||||
verify_ssl=DETAILS["verify_ssl"],
|
||||
status=True,
|
||||
raise_error=True,
|
||||
)
|
||||
|
@ -328,7 +330,7 @@ def call(payload=None):
|
|||
method="POST",
|
||||
decode_type="plain",
|
||||
decode=True,
|
||||
verify_ssl=False,
|
||||
verify_ssl=DETAILS["verify_ssl"],
|
||||
status=True,
|
||||
raise_error=True,
|
||||
)
|
||||
|
@ -345,7 +347,7 @@ def call(payload=None):
|
|||
method="POST",
|
||||
decode_type="plain",
|
||||
decode=True,
|
||||
verify_ssl=False,
|
||||
verify_ssl=DETAILS["verify_ssl"],
|
||||
status=True,
|
||||
raise_error=True,
|
||||
)
|
||||
|
@ -361,7 +363,7 @@ def call(payload=None):
|
|||
method="POST",
|
||||
decode_type="plain",
|
||||
decode=True,
|
||||
verify_ssl=False,
|
||||
verify_ssl=DETAILS["verify_ssl"],
|
||||
status=True,
|
||||
raise_error=True,
|
||||
)
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Proxy Minion interface module for managing VMWare vCenters.
|
||||
|
||||
|
@ -182,13 +181,9 @@ and that host would reach out over the network and communicate with the ESXi
|
|||
host.
|
||||
"""
|
||||
|
||||
# Import Python Libs
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
|
||||
import logging
|
||||
import os
|
||||
|
||||
# Import Salt Libs
|
||||
import salt.exceptions
|
||||
from salt.config.schemas.vcenter import VCenterProxySchema
|
||||
from salt.utils.dictupdate import merge
|
||||
|
@ -277,6 +272,8 @@ def init(opts):
|
|||
# Save optional
|
||||
DETAILS["protocol"] = proxy_conf.get("protocol")
|
||||
DETAILS["port"] = proxy_conf.get("port")
|
||||
DETAILS["verify_ssl"] = proxy_conf.get("verify_ssl")
|
||||
DETAILS["ca_bundle"] = proxy_conf.get("ca_bundle")
|
||||
|
||||
# Test connection
|
||||
if DETAILS["mechanism"] == "userpass":
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
|
||||
Send json response data to Splunk via the HTTP Event Collector
|
||||
|
@ -11,29 +10,22 @@ Requires the following config values to be specified in config or pillar:
|
|||
indexer: <hostname/IP of Splunk indexer>
|
||||
sourcetype: <Destination sourcetype for data>
|
||||
index: <Destination index for data>
|
||||
verify_ssl: true
|
||||
|
||||
Run a test by using ``salt-call test.ping --return splunk``
|
||||
|
||||
Written by Scott Pack (github.com/scottjpack)
|
||||
|
||||
"""
|
||||
# Import Python libs
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
|
||||
import logging
|
||||
import socket
|
||||
import time
|
||||
|
||||
import requests
|
||||
|
||||
# Import salt libs
|
||||
import salt.utils.json
|
||||
|
||||
# Import 3rd-party libs
|
||||
from salt.ext import six
|
||||
|
||||
_max_content_bytes = 100000
|
||||
http_event_collector_SSL_verify = False
|
||||
http_event_collector_debug = False
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
@ -62,6 +54,9 @@ def _get_options():
|
|||
indexer = __salt__["config.get"]("splunk_http_forwarder:indexer")
|
||||
sourcetype = __salt__["config.get"]("splunk_http_forwarder:sourcetype")
|
||||
index = __salt__["config.get"]("splunk_http_forwarder:index")
|
||||
verify_ssl = __salt__["config.get"](
|
||||
"splunk_http_forwarder:verify_ssl", default=True
|
||||
)
|
||||
except Exception: # pylint: disable=broad-except
|
||||
log.error("Splunk HTTP Forwarder parameters not present in config.")
|
||||
return None
|
||||
|
@ -70,6 +65,7 @@ def _get_options():
|
|||
"indexer": indexer,
|
||||
"sourcetype": sourcetype,
|
||||
"index": index,
|
||||
"verify_ssl": verify_ssl,
|
||||
}
|
||||
return splunk_opts
|
||||
|
||||
|
@ -84,14 +80,16 @@ def _send_splunk(event, index_override=None, sourcetype_override=None):
|
|||
# Get Splunk Options
|
||||
opts = _get_options()
|
||||
log.info(
|
||||
str("Options: %s"), # future lint: disable=blacklisted-function
|
||||
salt.utils.json.dumps(opts),
|
||||
"Options: %s", salt.utils.json.dumps(opts),
|
||||
)
|
||||
http_event_collector_key = opts["token"]
|
||||
http_event_collector_host = opts["indexer"]
|
||||
http_event_collector_verify_ssl = opts["verify_ssl"]
|
||||
# Set up the collector
|
||||
splunk_event = http_event_collector(
|
||||
http_event_collector_key, http_event_collector_host
|
||||
http_event_collector_key,
|
||||
http_event_collector_host,
|
||||
verify_ssl=http_event_collector_verify_ssl,
|
||||
)
|
||||
# init the payload
|
||||
payload = {}
|
||||
|
@ -109,8 +107,7 @@ def _send_splunk(event, index_override=None, sourcetype_override=None):
|
|||
# Add the event
|
||||
payload.update({"event": event})
|
||||
log.info(
|
||||
str("Payload: %s"), # future lint: disable=blacklisted-function
|
||||
salt.utils.json.dumps(payload),
|
||||
"Payload: %s", salt.utils.json.dumps(payload),
|
||||
)
|
||||
# Fire it off
|
||||
splunk_event.sendEvent(payload)
|
||||
|
@ -120,7 +117,7 @@ def _send_splunk(event, index_override=None, sourcetype_override=None):
|
|||
# Thanks to George Starcher for the http_event_collector class (https://github.com/georgestarcher/)
|
||||
|
||||
|
||||
class http_event_collector(object):
|
||||
class http_event_collector:
|
||||
def __init__(
|
||||
self,
|
||||
token,
|
||||
|
@ -129,11 +126,13 @@ class http_event_collector(object):
|
|||
http_event_port="8088",
|
||||
http_event_server_ssl=True,
|
||||
max_bytes=_max_content_bytes,
|
||||
verify_ssl=True,
|
||||
):
|
||||
self.token = token
|
||||
self.batchEvents = []
|
||||
self.maxByteLength = max_bytes
|
||||
self.currentByteLength = 0
|
||||
self.verify_ssl = verify_ssl
|
||||
|
||||
# Set host to specified value or default to localhostname if no value provided
|
||||
if host:
|
||||
|
@ -164,7 +163,7 @@ class http_event_collector(object):
|
|||
|
||||
# If eventtime in epoch not passed as optional argument use current system time in epoch
|
||||
if not eventtime:
|
||||
eventtime = six.text_type(int(time.time()))
|
||||
eventtime = str(int(time.time()))
|
||||
|
||||
# Fill in local hostname if not manually populated
|
||||
if "host" not in payload:
|
||||
|
@ -179,7 +178,7 @@ class http_event_collector(object):
|
|||
self.server_uri,
|
||||
data=salt.utils.json.dumps(data),
|
||||
headers=headers,
|
||||
verify=http_event_collector_SSL_verify,
|
||||
verify=self.verify_ssl,
|
||||
)
|
||||
|
||||
# Print debug info if flag set
|
||||
|
@ -207,7 +206,7 @@ class http_event_collector(object):
|
|||
|
||||
# If eventtime in epoch not passed as optional argument use current system time in epoch
|
||||
if not eventtime:
|
||||
eventtime = six.text_type(int(time.time()))
|
||||
eventtime = str(int(time.time()))
|
||||
|
||||
# Update time value on payload if need to use system time
|
||||
data = {"time": eventtime}
|
||||
|
@ -224,7 +223,7 @@ class http_event_collector(object):
|
|||
self.server_uri,
|
||||
data=" ".join(self.batchEvents),
|
||||
headers=headers,
|
||||
verify=http_event_collector_SSL_verify,
|
||||
verify=self.verify_ssl,
|
||||
)
|
||||
self.batchEvents = []
|
||||
self.currentByteLength = 0
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
Execute salt convenience routines
|
||||
"""
|
||||
|
||||
|
||||
import logging
|
||||
import os
|
||||
|
||||
|
@ -279,7 +278,7 @@ class Runner(RunnerClient):
|
|||
outputter = None
|
||||
display_output(ret, outputter, self.opts)
|
||||
else:
|
||||
ret = self._proc_function(
|
||||
ret = self._proc_function_local(
|
||||
self.opts["fun"],
|
||||
low,
|
||||
user,
|
||||
|
|
|
@ -17,9 +17,11 @@ master configuration at ``/etc/salt/master`` or ``/etc/salt/master.d/asam.conf``
|
|||
prov1.domain.com
|
||||
username: "testuser"
|
||||
password: "verybadpass"
|
||||
verify_ssl: true
|
||||
prov2.domain.com
|
||||
username: "testuser"
|
||||
password: "verybadpass"
|
||||
verify_ssl: true
|
||||
|
||||
.. note::
|
||||
|
||||
|
@ -84,6 +86,10 @@ def _get_asam_configuration(driver_url=""):
|
|||
password = service_config.get("password", None)
|
||||
protocol = service_config.get("protocol", "https")
|
||||
port = service_config.get("port", 3451)
|
||||
verify_ssl = service_config.get("verify_ssl")
|
||||
|
||||
if verify_ssl is None:
|
||||
verify_ssl = True
|
||||
|
||||
if not username or not password:
|
||||
log.error(
|
||||
|
@ -108,6 +114,7 @@ def _get_asam_configuration(driver_url=""):
|
|||
),
|
||||
"username": username,
|
||||
"password": password,
|
||||
"verify_ssl": verify_ssl,
|
||||
}
|
||||
|
||||
if (not driver_url) or (driver_url == asam_server):
|
||||
|
@ -206,7 +213,7 @@ def remove_platform(name, server_url):
|
|||
auth = (config["username"], config["password"])
|
||||
|
||||
try:
|
||||
html_content = _make_post_request(url, data, auth, verify=False)
|
||||
html_content = _make_post_request(url, data, auth, verify=config["verify_ssl"])
|
||||
except Exception as exc: # pylint: disable=broad-except
|
||||
err_msg = "Failed to look up existing platforms on {}".format(server_url)
|
||||
log.error("%s:\n%s", err_msg, exc)
|
||||
|
@ -222,7 +229,9 @@ def remove_platform(name, server_url):
|
|||
data["postType"] = "platformRemove"
|
||||
data["Submit"] = "Yes"
|
||||
try:
|
||||
html_content = _make_post_request(url, data, auth, verify=False)
|
||||
html_content = _make_post_request(
|
||||
url, data, auth, verify=config["verify_ssl"]
|
||||
)
|
||||
except Exception as exc: # pylint: disable=broad-except
|
||||
err_msg = "Failed to delete platform from {}".format(server_url)
|
||||
log.error("%s:\n%s", err_msg, exc)
|
||||
|
@ -261,7 +270,7 @@ def list_platforms(server_url):
|
|||
auth = (config["username"], config["password"])
|
||||
|
||||
try:
|
||||
html_content = _make_post_request(url, data, auth, verify=False)
|
||||
html_content = _make_post_request(url, data, auth, verify=config["verify_ssl"])
|
||||
except Exception as exc: # pylint: disable=broad-except
|
||||
err_msg = "Failed to look up existing platforms"
|
||||
log.error("%s:\n%s", err_msg, exc)
|
||||
|
@ -299,7 +308,7 @@ def list_platform_sets(server_url):
|
|||
auth = (config["username"], config["password"])
|
||||
|
||||
try:
|
||||
html_content = _make_post_request(url, data, auth, verify=False)
|
||||
html_content = _make_post_request(url, data, auth, verify=config["verify_ssl"])
|
||||
except Exception as exc: # pylint: disable=broad-except
|
||||
err_msg = "Failed to look up existing platform sets"
|
||||
log.error("%s:\n%s", err_msg, exc)
|
||||
|
@ -351,7 +360,7 @@ def add_platform(name, platform_set, server_url):
|
|||
auth = (config["username"], config["password"])
|
||||
|
||||
try:
|
||||
html_content = _make_post_request(url, data, auth, verify=False)
|
||||
html_content = _make_post_request(url, data, auth, verify=config["verify_ssl"])
|
||||
except Exception as exc: # pylint: disable=broad-except
|
||||
err_msg = "Failed to add platform on {}".format(server_url)
|
||||
log.error("%s:\n%s", err_msg, exc)
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Manage VMware ESXi Hosts.
|
||||
|
||||
|
@ -91,8 +90,6 @@ configuration examples, dependency installation instructions, how to run remote
|
|||
execution functions against ESXi hosts via a Salt Proxy Minion, and a larger state
|
||||
example.
|
||||
"""
|
||||
# Import Python Libs
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
|
||||
import logging
|
||||
import re
|
||||
|
@ -108,9 +105,6 @@ from salt.exceptions import (
|
|||
VMwareObjectRetrievalError,
|
||||
VMwareSaltError,
|
||||
)
|
||||
|
||||
# Import Salt Libs
|
||||
from salt.ext import six
|
||||
from salt.utils.decorators import depends
|
||||
|
||||
# External libraries
|
||||
|
@ -201,7 +195,7 @@ def coredump_configured(name, enabled, dump_ip, host_vnic="vmk0", dump_port=6500
|
|||
current_config = __salt__[esxi_cmd]("get_coredump_network_config").get(host)
|
||||
error = current_config.get("Error")
|
||||
if error:
|
||||
ret["comment"] = "Error: {0}".format(error)
|
||||
ret["comment"] = "Error: {}".format(error)
|
||||
return ret
|
||||
|
||||
current_config = current_config.get("Coredump Config")
|
||||
|
@ -217,7 +211,7 @@ def coredump_configured(name, enabled, dump_ip, host_vnic="vmk0", dump_port=6500
|
|||
).get(host)
|
||||
error = response.get("Error")
|
||||
if error:
|
||||
ret["comment"] = "Error: {0}".format(error)
|
||||
ret["comment"] = "Error: {}".format(error)
|
||||
return ret
|
||||
|
||||
# Allow users to disable core dump, but then return since
|
||||
|
@ -252,9 +246,9 @@ def coredump_configured(name, enabled, dump_ip, host_vnic="vmk0", dump_port=6500
|
|||
changes = True
|
||||
|
||||
current_port = current_config.get("port")
|
||||
if current_port != six.text_type(dump_port):
|
||||
if current_port != str(dump_port):
|
||||
ret["changes"].update(
|
||||
{"dump_port": {"old": current_port, "new": six.text_type(dump_port)}}
|
||||
{"dump_port": {"old": current_port, "new": str(dump_port)}}
|
||||
)
|
||||
changes = True
|
||||
|
||||
|
@ -270,7 +264,7 @@ def coredump_configured(name, enabled, dump_ip, host_vnic="vmk0", dump_port=6500
|
|||
msg = response.get("stderr")
|
||||
if not msg:
|
||||
msg = response.get("stdout")
|
||||
ret["comment"] = "Error: {0}".format(msg)
|
||||
ret["comment"] = "Error: {}".format(msg)
|
||||
return ret
|
||||
|
||||
ret["result"] = True
|
||||
|
@ -328,7 +322,7 @@ def password_present(name, password):
|
|||
__salt__[esxi_cmd]("update_host_password", new_password=password)
|
||||
except CommandExecutionError as err:
|
||||
ret["result"] = False
|
||||
ret["comment"] = "Error: {0}".format(err)
|
||||
ret["comment"] = "Error: {}".format(err)
|
||||
return ret
|
||||
|
||||
return ret
|
||||
|
@ -400,7 +394,7 @@ def ntp_configured(
|
|||
ntp_running = __salt__[esxi_cmd]("get_service_running", service_name=ntpd).get(host)
|
||||
error = ntp_running.get("Error")
|
||||
if error:
|
||||
ret["comment"] = "Error: {0}".format(error)
|
||||
ret["comment"] = "Error: {}".format(error)
|
||||
return ret
|
||||
ntp_running = ntp_running.get(ntpd)
|
||||
|
||||
|
@ -413,7 +407,7 @@ def ntp_configured(
|
|||
).get(host)
|
||||
error = response.get("Error")
|
||||
if error:
|
||||
ret["comment"] = "Error: {0}".format(error)
|
||||
ret["comment"] = "Error: {}".format(error)
|
||||
return ret
|
||||
# Set changes dictionary for ntp_servers
|
||||
ret["changes"].update({"ntp_servers": {"old": ntp_config, "new": ntp_servers}})
|
||||
|
@ -429,7 +423,7 @@ def ntp_configured(
|
|||
)
|
||||
error = response.get("Error")
|
||||
if error:
|
||||
ret["comment"] = "Error: {0}".format(error)
|
||||
ret["comment"] = "Error: {}".format(error)
|
||||
return ret
|
||||
# Stop ntpd if service_running=False
|
||||
else:
|
||||
|
@ -438,7 +432,7 @@ def ntp_configured(
|
|||
)
|
||||
error = response.get("Error")
|
||||
if error:
|
||||
ret["comment"] = "Error: {0}".format(error)
|
||||
ret["comment"] = "Error: {}".format(error)
|
||||
return ret
|
||||
ret["changes"].update(
|
||||
{"service_running": {"old": ntp_running, "new": service_running}}
|
||||
|
@ -451,7 +445,7 @@ def ntp_configured(
|
|||
).get(host)
|
||||
error = current_service_policy.get("Error")
|
||||
if error:
|
||||
ret["comment"] = "Error: {0}".format(error)
|
||||
ret["comment"] = "Error: {}".format(error)
|
||||
return ret
|
||||
current_service_policy = current_service_policy.get(ntpd)
|
||||
|
||||
|
@ -465,7 +459,7 @@ def ntp_configured(
|
|||
).get(host)
|
||||
error = response.get("Error")
|
||||
if error:
|
||||
ret["comment"] = "Error: {0}".format(error)
|
||||
ret["comment"] = "Error: {}".format(error)
|
||||
return ret
|
||||
ret["changes"].update(
|
||||
{
|
||||
|
@ -483,7 +477,7 @@ def ntp_configured(
|
|||
response = __salt__[esxi_cmd]("update_host_datetime").get(host)
|
||||
error = response.get("Error")
|
||||
if error:
|
||||
ret["comment"] = "Error: {0}".format(error)
|
||||
ret["comment"] = "Error: {}".format(error)
|
||||
return ret
|
||||
ret["changes"].update(
|
||||
{"update_datetime": {"old": "", "new": "Host datetime was updated."}}
|
||||
|
@ -498,7 +492,7 @@ def ntp_configured(
|
|||
)
|
||||
error = response.get("Error")
|
||||
if error:
|
||||
ret["comment"] = "Error: {0}".format(error)
|
||||
ret["comment"] = "Error: {}".format(error)
|
||||
return ret
|
||||
ret["changes"].update(
|
||||
{"service_restart": {"old": "", "new": "NTP Daemon Restarted."}}
|
||||
|
@ -559,14 +553,14 @@ def vmotion_configured(name, enabled, device="vmk0"):
|
|||
response = __salt__[esxi_cmd]("vmotion_enable", device=device).get(host)
|
||||
error = response.get("Error")
|
||||
if error:
|
||||
ret["comment"] = "Error: {0}".format(error)
|
||||
ret["comment"] = "Error: {}".format(error)
|
||||
return ret
|
||||
# Disable VMotion if enabled=False
|
||||
else:
|
||||
response = __salt__[esxi_cmd]("vmotion_disable").get(host)
|
||||
error = response.get("Error")
|
||||
if error:
|
||||
ret["comment"] = "Error: {0}".format(error)
|
||||
ret["comment"] = "Error: {}".format(error)
|
||||
return ret
|
||||
ret["changes"].update(
|
||||
{"enabled": {"old": current_vmotion_enabled, "new": enabled}}
|
||||
|
@ -618,7 +612,7 @@ def vsan_configured(name, enabled, add_disks_to_vsan=False):
|
|||
current_vsan_enabled = __salt__[esxi_cmd]("get_vsan_enabled").get(host)
|
||||
error = current_vsan_enabled.get("Error")
|
||||
if error:
|
||||
ret["comment"] = "Error: {0}".format(error)
|
||||
ret["comment"] = "Error: {}".format(error)
|
||||
return ret
|
||||
current_vsan_enabled = current_vsan_enabled.get("VSAN Enabled")
|
||||
|
||||
|
@ -631,14 +625,14 @@ def vsan_configured(name, enabled, add_disks_to_vsan=False):
|
|||
response = __salt__[esxi_cmd]("vsan_enable").get(host)
|
||||
error = response.get("Error")
|
||||
if error:
|
||||
ret["comment"] = "Error: {0}".format(error)
|
||||
ret["comment"] = "Error: {}".format(error)
|
||||
return ret
|
||||
# Disable VSAN if enabled=False
|
||||
else:
|
||||
response = __salt__[esxi_cmd]("vsan_disable").get(host)
|
||||
error = response.get("Error")
|
||||
if error:
|
||||
ret["comment"] = "Error: {0}".format(error)
|
||||
ret["comment"] = "Error: {}".format(error)
|
||||
return ret
|
||||
ret["changes"].update(
|
||||
{"enabled": {"old": current_vsan_enabled, "new": enabled}}
|
||||
|
@ -649,7 +643,7 @@ def vsan_configured(name, enabled, add_disks_to_vsan=False):
|
|||
current_eligible_disks = __salt__[esxi_cmd]("get_vsan_eligible_disks").get(host)
|
||||
error = current_eligible_disks.get("Error")
|
||||
if error:
|
||||
ret["comment"] = "Error: {0}".format(error)
|
||||
ret["comment"] = "Error: {}".format(error)
|
||||
return ret
|
||||
|
||||
disks = current_eligible_disks.get("Eligible")
|
||||
|
@ -659,7 +653,7 @@ def vsan_configured(name, enabled, add_disks_to_vsan=False):
|
|||
response = __salt__[esxi_cmd]("vsan_add_disks").get(host)
|
||||
error = response.get("Error")
|
||||
if error:
|
||||
ret["comment"] = "Error: {0}".format(error)
|
||||
ret["comment"] = "Error: {}".format(error)
|
||||
return ret
|
||||
|
||||
ret["changes"].update({"add_disks_to_vsan": {"old": "", "new": disks}})
|
||||
|
@ -683,7 +677,7 @@ def ssh_configured(
|
|||
ssh_key_file=None,
|
||||
service_policy=None,
|
||||
service_restart=False,
|
||||
certificate_verify=False,
|
||||
certificate_verify=None,
|
||||
):
|
||||
"""
|
||||
Manage the SSH configuration for a host including whether or not SSH is running or
|
||||
|
@ -724,7 +718,7 @@ def ssh_configured(
|
|||
|
||||
certificate_verify
|
||||
If set to ``True``, the SSL connection must present a valid certificate.
|
||||
Default is ``False``.
|
||||
Default is ``True``.
|
||||
|
||||
Example:
|
||||
|
||||
|
@ -739,6 +733,8 @@ def ssh_configured(
|
|||
- certificate_verify: True
|
||||
|
||||
"""
|
||||
if certificate_verify is None:
|
||||
certificate_verify = True
|
||||
ret = {"name": name, "result": False, "changes": {}, "comment": ""}
|
||||
esxi_cmd = "esxi.cmd"
|
||||
host = __pillar__["proxy"]["host"]
|
||||
|
@ -747,7 +743,7 @@ def ssh_configured(
|
|||
ssh_running = __salt__[esxi_cmd]("get_service_running", service_name=ssh).get(host)
|
||||
error = ssh_running.get("Error")
|
||||
if error:
|
||||
ret["comment"] = "Error: {0}".format(error)
|
||||
ret["comment"] = "Error: {}".format(error)
|
||||
return ret
|
||||
ssh_running = ssh_running.get(ssh)
|
||||
|
||||
|
@ -760,14 +756,14 @@ def ssh_configured(
|
|||
enable = __salt__[esxi_cmd]("service_start", service_name=ssh).get(host)
|
||||
error = enable.get("Error")
|
||||
if error:
|
||||
ret["comment"] = "Error: {0}".format(error)
|
||||
ret["comment"] = "Error: {}".format(error)
|
||||
return ret
|
||||
# Disable SSH if service_running=False
|
||||
else:
|
||||
disable = __salt__[esxi_cmd]("service_stop", service_name=ssh).get(host)
|
||||
error = disable.get("Error")
|
||||
if error:
|
||||
ret["comment"] = "Error: {0}".format(error)
|
||||
ret["comment"] = "Error: {}".format(error)
|
||||
return ret
|
||||
|
||||
ret["changes"].update(
|
||||
|
@ -783,7 +779,7 @@ def ssh_configured(
|
|||
)
|
||||
error = current_ssh_key.get("Error")
|
||||
if error:
|
||||
ret["comment"] = "Error: {0}".format(error)
|
||||
ret["comment"] = "Error: {}".format(error)
|
||||
return ret
|
||||
current_ssh_key = current_ssh_key.get("key")
|
||||
if current_ssh_key:
|
||||
|
@ -822,7 +818,7 @@ def ssh_configured(
|
|||
)
|
||||
error = response.get("Error")
|
||||
if error:
|
||||
ret["comment"] = "Error: {0}".format(error)
|
||||
ret["comment"] = "Error: {}".format(error)
|
||||
return ret
|
||||
ret["changes"].update(
|
||||
{
|
||||
|
@ -840,7 +836,7 @@ def ssh_configured(
|
|||
).get(host)
|
||||
error = current_service_policy.get("Error")
|
||||
if error:
|
||||
ret["comment"] = "Error: {0}".format(error)
|
||||
ret["comment"] = "Error: {}".format(error)
|
||||
return ret
|
||||
current_service_policy = current_service_policy.get(ssh)
|
||||
|
||||
|
@ -854,7 +850,7 @@ def ssh_configured(
|
|||
).get(host)
|
||||
error = response.get("Error")
|
||||
if error:
|
||||
ret["comment"] = "Error: {0}".format(error)
|
||||
ret["comment"] = "Error: {}".format(error)
|
||||
return ret
|
||||
ret["changes"].update(
|
||||
{
|
||||
|
@ -872,7 +868,7 @@ def ssh_configured(
|
|||
response = __salt__[esxi_cmd]("service_restart", service_name=ssh).get(host)
|
||||
error = response.get("Error")
|
||||
if error:
|
||||
ret["comment"] = "Error: {0}".format(error)
|
||||
ret["comment"] = "Error: {}".format(error)
|
||||
return ret
|
||||
ret["changes"].update(
|
||||
{"service_restart": {"old": "", "new": "SSH service restarted."}}
|
||||
|
@ -965,17 +961,17 @@ def syslog_configured(
|
|||
reset = __salt__[esxi_cmd](
|
||||
"reset_syslog_config", syslog_config=reset_configs
|
||||
).get(host)
|
||||
for key, val in six.iteritems(reset):
|
||||
for key, val in reset.items():
|
||||
if isinstance(val, bool):
|
||||
continue
|
||||
if not val.get("success"):
|
||||
msg = val.get("message")
|
||||
if not msg:
|
||||
msg = (
|
||||
"There was an error resetting a syslog config '{0}'."
|
||||
"There was an error resetting a syslog config '{}'."
|
||||
"Please check debug logs.".format(val)
|
||||
)
|
||||
ret["comment"] = "Error: {0}".format(msg)
|
||||
ret["comment"] = "Error: {}".format(msg)
|
||||
return ret
|
||||
|
||||
ret["changes"].update(
|
||||
|
@ -985,7 +981,7 @@ def syslog_configured(
|
|||
current_firewall = __salt__[esxi_cmd]("get_firewall_status").get(host)
|
||||
error = current_firewall.get("Error")
|
||||
if error:
|
||||
ret["comment"] = "Error: {0}".format(error)
|
||||
ret["comment"] = "Error: {}".format(error)
|
||||
return ret
|
||||
|
||||
current_firewall = current_firewall.get("rulesets").get("syslog")
|
||||
|
@ -1000,23 +996,23 @@ def syslog_configured(
|
|||
if enabled.get("retcode") != 0:
|
||||
err = enabled.get("stderr")
|
||||
out = enabled.get("stdout")
|
||||
ret["comment"] = "Error: {0}".format(err if err else out)
|
||||
ret["comment"] = "Error: {}".format(err if err else out)
|
||||
return ret
|
||||
|
||||
ret["changes"].update({"firewall": {"old": current_firewall, "new": firewall}})
|
||||
|
||||
current_syslog_config = __salt__[esxi_cmd]("get_syslog_config").get(host)
|
||||
for key, val in six.iteritems(syslog_configs):
|
||||
for key, val in syslog_configs.items():
|
||||
# The output of get_syslog_config has different keys than the keys
|
||||
# Used to set syslog_config values. We need to look them up first.
|
||||
try:
|
||||
lookup_key = _lookup_syslog_config(key)
|
||||
except KeyError:
|
||||
ret["comment"] = "'{0}' is not a valid config variable.".format(key)
|
||||
ret["comment"] = "'{}' is not a valid config variable.".format(key)
|
||||
return ret
|
||||
|
||||
current_val = current_syslog_config[lookup_key]
|
||||
if six.text_type(current_val) != six.text_type(val):
|
||||
if str(current_val) != str(val):
|
||||
# Only run the command if not using test=True
|
||||
if not __opts__["test"]:
|
||||
response = __salt__[esxi_cmd](
|
||||
|
@ -1031,7 +1027,7 @@ def syslog_configured(
|
|||
msg = response.get(key).get("message")
|
||||
if not msg:
|
||||
msg = (
|
||||
"There was an error setting syslog config '{0}'. "
|
||||
"There was an error setting syslog config '{}'. "
|
||||
"Please check debug logs.".format(key)
|
||||
)
|
||||
ret["comment"] = msg
|
||||
|
@ -1101,7 +1097,7 @@ def diskgroups_configured(name, diskgroups, erase_disks=False):
|
|||
if not proxy_details.get("vcenter")
|
||||
else proxy_details["esxi_host"]
|
||||
)
|
||||
log.info("Running state {0} for host '{1}'".format(name, hostname))
|
||||
log.info("Running state %s for host '%s'", name, hostname)
|
||||
# Variable used to return the result of the invocation
|
||||
ret = {"name": name, "result": None, "changes": {}, "comments": None}
|
||||
# Signals if errors have been encountered
|
||||
|
@ -1124,23 +1120,20 @@ def diskgroups_configured(name, diskgroups, erase_disks=False):
|
|||
host_disks = __salt__["vsphere.list_disks"](service_instance=si)
|
||||
if not host_disks:
|
||||
raise VMwareObjectRetrievalError(
|
||||
"No disks retrieved from host '{0}'".format(hostname)
|
||||
"No disks retrieved from host '{}'".format(hostname)
|
||||
)
|
||||
scsi_addr_to_disk_map = {d["scsi_address"]: d for d in host_disks}
|
||||
log.trace("scsi_addr_to_disk_map = {0}".format(scsi_addr_to_disk_map))
|
||||
log.trace("scsi_addr_to_disk_map = %s", scsi_addr_to_disk_map)
|
||||
existing_diskgroups = __salt__["vsphere.list_diskgroups"](service_instance=si)
|
||||
cache_disk_to_existing_diskgroup_map = {
|
||||
dg["cache_disk"]: dg for dg in existing_diskgroups
|
||||
}
|
||||
except CommandExecutionError as err:
|
||||
log.error("Error: {0}".format(err))
|
||||
log.error("Error: %s", err)
|
||||
if si:
|
||||
__salt__["vsphere.disconnect"](si)
|
||||
ret.update(
|
||||
{
|
||||
"result": False if not __opts__["test"] else None,
|
||||
"comment": six.text_type(err),
|
||||
}
|
||||
{"result": False if not __opts__["test"] else None, "comment": str(err)}
|
||||
)
|
||||
return ret
|
||||
|
||||
|
@ -1149,8 +1142,9 @@ def diskgroups_configured(name, diskgroups, erase_disks=False):
|
|||
# Check for cache disk
|
||||
if not dg["cache_scsi_addr"] in scsi_addr_to_disk_map:
|
||||
comments.append(
|
||||
"No cache disk with scsi address '{0}' was "
|
||||
"found.".format(dg["cache_scsi_addr"])
|
||||
"No cache disk with scsi address '{}' was found.".format(
|
||||
dg["cache_scsi_addr"]
|
||||
)
|
||||
)
|
||||
log.error(comments[-1])
|
||||
errors = True
|
||||
|
@ -1158,7 +1152,7 @@ def diskgroups_configured(name, diskgroups, erase_disks=False):
|
|||
|
||||
# Check for capacity disks
|
||||
cache_disk_id = scsi_addr_to_disk_map[dg["cache_scsi_addr"]]["id"]
|
||||
cache_disk_display = "{0} (id:{1})".format(dg["cache_scsi_addr"], cache_disk_id)
|
||||
cache_disk_display = "{} (id:{})".format(dg["cache_scsi_addr"], cache_disk_id)
|
||||
bad_scsi_addrs = []
|
||||
capacity_disk_ids = []
|
||||
capacity_disk_displays = []
|
||||
|
@ -1168,13 +1162,14 @@ def diskgroups_configured(name, diskgroups, erase_disks=False):
|
|||
continue
|
||||
capacity_disk_ids.append(scsi_addr_to_disk_map[scsi_addr]["id"])
|
||||
capacity_disk_displays.append(
|
||||
"{0} (id:{1})".format(scsi_addr, capacity_disk_ids[-1])
|
||||
"{} (id:{})".format(scsi_addr, capacity_disk_ids[-1])
|
||||
)
|
||||
if bad_scsi_addrs:
|
||||
comments.append(
|
||||
"Error in diskgroup #{0}: capacity disks with "
|
||||
"scsi addresses {1} were not found."
|
||||
"".format(idx, ", ".join(["'{0}'".format(a) for a in bad_scsi_addrs]))
|
||||
"Error in diskgroup #{}: capacity disks with scsi addresses {} "
|
||||
"were not found.".format(
|
||||
idx, ", ".join(["'{}'".format(a) for a in bad_scsi_addrs])
|
||||
)
|
||||
)
|
||||
log.error(comments[-1])
|
||||
errors = True
|
||||
|
@ -1182,14 +1177,14 @@ def diskgroups_configured(name, diskgroups, erase_disks=False):
|
|||
|
||||
if not cache_disk_to_existing_diskgroup_map.get(cache_disk_id):
|
||||
# A new diskgroup needs to be created
|
||||
log.trace("erase_disks = {0}".format(erase_disks))
|
||||
log.trace("erase_disks = %s", erase_disks)
|
||||
if erase_disks:
|
||||
if __opts__["test"]:
|
||||
comments.append(
|
||||
"State {0} will "
|
||||
"erase all disks of disk group #{1}; "
|
||||
"cache disk: '{2}', "
|
||||
"capacity disk(s): {3}."
|
||||
"State {} will "
|
||||
"erase all disks of disk group #{}; "
|
||||
"cache disk: '{}', "
|
||||
"capacity disk(s): {}."
|
||||
"".format(
|
||||
name,
|
||||
idx,
|
||||
|
@ -1206,13 +1201,13 @@ def diskgroups_configured(name, diskgroups, erase_disks=False):
|
|||
disk_id=disk_id, service_instance=si
|
||||
)
|
||||
comments.append(
|
||||
"Erased disks of diskgroup #{0}; "
|
||||
"cache disk: '{1}', capacity disk(s): "
|
||||
"{2}".format(
|
||||
"Erased disks of diskgroup #{}; "
|
||||
"cache disk: '{}', capacity disk(s): "
|
||||
"{}".format(
|
||||
idx,
|
||||
cache_disk_display,
|
||||
", ".join(
|
||||
["'{0}'".format(a) for a in capacity_disk_displays]
|
||||
["'{}'".format(a) for a in capacity_disk_displays]
|
||||
),
|
||||
)
|
||||
)
|
||||
|
@ -1220,13 +1215,13 @@ def diskgroups_configured(name, diskgroups, erase_disks=False):
|
|||
|
||||
if __opts__["test"]:
|
||||
comments.append(
|
||||
"State {0} will create "
|
||||
"the disk group #{1}; cache disk: '{2}', "
|
||||
"capacity disk(s): {3}.".format(
|
||||
"State {} will create "
|
||||
"the disk group #{}; cache disk: '{}', "
|
||||
"capacity disk(s): {}.".format(
|
||||
name,
|
||||
idx,
|
||||
cache_disk_display,
|
||||
", ".join(["'{0}'".format(a) for a in capacity_disk_displays]),
|
||||
", ".join(["'{}'".format(a) for a in capacity_disk_displays]),
|
||||
)
|
||||
)
|
||||
log.info(comments[-1])
|
||||
|
@ -1240,16 +1235,14 @@ def diskgroups_configured(name, diskgroups, erase_disks=False):
|
|||
service_instance=si,
|
||||
)
|
||||
except VMwareSaltError as err:
|
||||
comments.append(
|
||||
"Error creating disk group #{0}: " "{1}.".format(idx, err)
|
||||
)
|
||||
comments.append("Error creating disk group #{}: {}.".format(idx, err))
|
||||
log.error(comments[-1])
|
||||
errors = True
|
||||
continue
|
||||
|
||||
comments.append("Created disk group #'{0}'.".format(idx))
|
||||
comments.append("Created disk group #'{}'.".format(idx))
|
||||
log.info(comments[-1])
|
||||
diskgroup_changes[six.text_type(idx)] = {
|
||||
diskgroup_changes[str(idx)] = {
|
||||
"new": {"cache": cache_disk_display, "capacity": capacity_disk_displays}
|
||||
}
|
||||
changes = True
|
||||
|
@ -1257,12 +1250,13 @@ def diskgroups_configured(name, diskgroups, erase_disks=False):
|
|||
|
||||
# The diskgroup exists; checking the capacity disks
|
||||
log.debug(
|
||||
"Disk group #{0} exists. Checking capacity disks: "
|
||||
"{1}.".format(idx, capacity_disk_displays)
|
||||
"Disk group #%s exists. Checking capacity disks: %s.",
|
||||
idx,
|
||||
capacity_disk_displays,
|
||||
)
|
||||
existing_diskgroup = cache_disk_to_existing_diskgroup_map.get(cache_disk_id)
|
||||
existing_capacity_disk_displays = [
|
||||
"{0} (id:{1})".format(
|
||||
"{} (id:{})".format(
|
||||
[d["scsi_address"] for d in host_disks if d["id"] == disk_id][0],
|
||||
disk_id,
|
||||
)
|
||||
|
@ -1280,7 +1274,7 @@ def diskgroups_configured(name, diskgroups, erase_disks=False):
|
|||
][0]
|
||||
added_capacity_disk_ids.append(disk_id)
|
||||
added_capacity_disk_displays.append(
|
||||
"{0} (id:{1})".format(disk_scsi_addr, disk_id)
|
||||
"{} (id:{})".format(disk_scsi_addr, disk_id)
|
||||
)
|
||||
for disk_id in existing_diskgroup["capacity_disks"]:
|
||||
if disk_id not in capacity_disk_ids:
|
||||
|
@ -1289,28 +1283,26 @@ def diskgroups_configured(name, diskgroups, erase_disks=False):
|
|||
][0]
|
||||
removed_capacity_disk_ids.append(disk_id)
|
||||
removed_capacity_disk_displays.append(
|
||||
"{0} (id:{1})".format(disk_scsi_addr, disk_id)
|
||||
"{} (id:{})".format(disk_scsi_addr, disk_id)
|
||||
)
|
||||
|
||||
log.debug(
|
||||
"Disk group #{0}: existing capacity disk ids: {1}; added "
|
||||
"capacity disk ids: {2}; removed capacity disk ids: {3}"
|
||||
"".format(
|
||||
idx,
|
||||
existing_capacity_disk_displays,
|
||||
added_capacity_disk_displays,
|
||||
removed_capacity_disk_displays,
|
||||
)
|
||||
"Disk group #%s: existing capacity disk ids: %s; added "
|
||||
"capacity disk ids: %s; removed capacity disk ids: %s",
|
||||
idx,
|
||||
existing_capacity_disk_displays,
|
||||
added_capacity_disk_displays,
|
||||
removed_capacity_disk_displays,
|
||||
)
|
||||
|
||||
# TODO revisit this when removing capacity disks is supported
|
||||
if removed_capacity_disk_ids:
|
||||
comments.append(
|
||||
"Error removing capacity disk(s) {0} from disk group #{1}; "
|
||||
"Error removing capacity disk(s) {} from disk group #{}; "
|
||||
"operation is not supported."
|
||||
"".format(
|
||||
", ".join(
|
||||
["'{0}'".format(id) for id in removed_capacity_disk_displays]
|
||||
["'{}'".format(id) for id in removed_capacity_disk_displays]
|
||||
),
|
||||
idx,
|
||||
)
|
||||
|
@ -1324,11 +1316,11 @@ def diskgroups_configured(name, diskgroups, erase_disks=False):
|
|||
|
||||
# Building a string representation of the capacity disks
|
||||
# that need to be added
|
||||
s = ", ".join(["'{0}'".format(id) for id in added_capacity_disk_displays])
|
||||
s = ", ".join(["'{}'".format(id) for id in added_capacity_disk_displays])
|
||||
if __opts__["test"]:
|
||||
comments.append(
|
||||
"State {0} will add "
|
||||
"capacity disk(s) {1} to disk group #{2}."
|
||||
"State {} will add "
|
||||
"capacity disk(s) {} to disk group #{}."
|
||||
"".format(name, s, idx)
|
||||
)
|
||||
log.info(comments[-1])
|
||||
|
@ -1343,17 +1335,17 @@ def diskgroups_configured(name, diskgroups, erase_disks=False):
|
|||
)
|
||||
except VMwareSaltError as err:
|
||||
comments.append(
|
||||
"Error adding capacity disk(s) {0} to "
|
||||
"disk group #{1}: {2}.".format(s, idx, err)
|
||||
"Error adding capacity disk(s) {} to "
|
||||
"disk group #{}: {}.".format(s, idx, err)
|
||||
)
|
||||
log.error(comments[-1])
|
||||
errors = True
|
||||
continue
|
||||
|
||||
com = "Added capacity disk(s) {0} to disk group #{1}" "".format(s, idx)
|
||||
com = "Added capacity disk(s) {} to disk group #{}" "".format(s, idx)
|
||||
log.info(com)
|
||||
comments.append(com)
|
||||
diskgroup_changes[six.text_type(idx)] = {
|
||||
diskgroup_changes[str(idx)] = {
|
||||
"new": {
|
||||
"cache": cache_disk_display,
|
||||
"capacity": capacity_disk_displays,
|
||||
|
@ -1367,9 +1359,7 @@ def diskgroups_configured(name, diskgroups, erase_disks=False):
|
|||
continue
|
||||
|
||||
# No capacity needs to be added
|
||||
s = "Disk group #{0} is correctly configured. Nothing to be done." "".format(
|
||||
idx
|
||||
)
|
||||
s = "Disk group #{} is correctly configured. Nothing to be done." "".format(idx)
|
||||
log.info(s)
|
||||
comments.append(s)
|
||||
__salt__["vsphere.disconnect"](si)
|
||||
|
@ -1532,11 +1522,11 @@ def host_cache_configured(
|
|||
)
|
||||
if not existing_disks:
|
||||
raise VMwareObjectRetrievalError(
|
||||
"Disk with scsi address '{0}' was not found in host '{1}'"
|
||||
"Disk with scsi address '{}' was not found in host '{}'"
|
||||
"".format(datastore["backing_disk_scsi_addr"], hostname)
|
||||
)
|
||||
backing_disk = existing_disks[0]
|
||||
backing_disk_display = "{0} (id:{1})".format(
|
||||
backing_disk_display = "{} (id:{})".format(
|
||||
backing_disk["scsi_address"], backing_disk["id"]
|
||||
)
|
||||
log.trace("backing_disk = %s", backing_disk_display)
|
||||
|
@ -1547,9 +1537,9 @@ def host_cache_configured(
|
|||
if erase_backing_disk:
|
||||
if __opts__["test"]:
|
||||
comments.append(
|
||||
"State {0} will erase "
|
||||
"the backing disk '{1}' on host '{2}'."
|
||||
"".format(name, backing_disk_display, hostname)
|
||||
"State {} will erase the backing disk '{}' on host '{}'.".format(
|
||||
name, backing_disk_display, hostname
|
||||
)
|
||||
)
|
||||
log.info(comments[-1])
|
||||
else:
|
||||
|
@ -1558,17 +1548,18 @@ def host_cache_configured(
|
|||
disk_id=backing_disk["id"], service_instance=si
|
||||
)
|
||||
comments.append(
|
||||
"Erased backing disk '{0}' on host "
|
||||
"'{1}'.".format(backing_disk_display, hostname)
|
||||
"Erased backing disk '{}' on host '{}'.".format(
|
||||
backing_disk_display, hostname
|
||||
)
|
||||
)
|
||||
log.info(comments[-1])
|
||||
# Create the datastore
|
||||
if __opts__["test"]:
|
||||
comments.append(
|
||||
"State {0} will create "
|
||||
"the datastore '{1}', with backing disk "
|
||||
"'{2}', on host '{3}'."
|
||||
"".format(name, datastore["name"], backing_disk_display, hostname)
|
||||
"State {} will create the datastore '{}', with backing disk "
|
||||
"'{}', on host '{}'.".format(
|
||||
name, datastore["name"], backing_disk_display, hostname
|
||||
)
|
||||
)
|
||||
log.info(comments[-1])
|
||||
else:
|
||||
|
@ -1582,8 +1573,9 @@ def host_cache_configured(
|
|||
non_mbr_partitions = [p for p in partitions if p["format"] != "mbr"]
|
||||
if len(non_mbr_partitions) > 0:
|
||||
raise VMwareApiError(
|
||||
"Backing disk '{0}' has unexpected partitions"
|
||||
"".format(backing_disk_display)
|
||||
"Backing disk '{}' has unexpected partitions".format(
|
||||
backing_disk_display
|
||||
)
|
||||
)
|
||||
__salt__["vsphere.create_vmfs_datastore"](
|
||||
datastore["name"],
|
||||
|
@ -1592,9 +1584,10 @@ def host_cache_configured(
|
|||
service_instance=si,
|
||||
)
|
||||
comments.append(
|
||||
"Created vmfs datastore '{0}', backed by "
|
||||
"disk '{1}', on host '{2}'."
|
||||
"".format(datastore["name"], backing_disk_display, hostname)
|
||||
"Created vmfs datastore '{}', backed by "
|
||||
"disk '{}', on host '{}'.".format(
|
||||
datastore["name"], backing_disk_display, hostname
|
||||
)
|
||||
)
|
||||
log.info(comments[-1])
|
||||
changes.update(
|
||||
|
@ -1615,21 +1608,20 @@ def host_cache_configured(
|
|||
# Check datastore is backed by the correct disk
|
||||
if not existing_datastores[0].get("backing_disk_ids"):
|
||||
raise VMwareSaltError(
|
||||
"Datastore '{0}' doesn't have a "
|
||||
"backing disk"
|
||||
"".format(datastore["name"])
|
||||
"Datastore '{}' doesn't have a backing disk".format(
|
||||
datastore["name"]
|
||||
)
|
||||
)
|
||||
if backing_disk["id"] not in existing_datastores[0]["backing_disk_ids"]:
|
||||
|
||||
raise VMwareSaltError(
|
||||
"Datastore '{0}' is not backed by the correct disk: "
|
||||
"expected '{1}'; got {2}"
|
||||
"".format(
|
||||
"Datastore '{}' is not backed by the correct disk: "
|
||||
"expected '{}'; got {}".format(
|
||||
datastore["name"],
|
||||
backing_disk["id"],
|
||||
", ".join(
|
||||
[
|
||||
"'{0}'".format(disk)
|
||||
"'{}'".format(disk)
|
||||
for disk in existing_datastores[0]["backing_disk_ids"]
|
||||
]
|
||||
),
|
||||
|
@ -1637,8 +1629,8 @@ def host_cache_configured(
|
|||
)
|
||||
|
||||
comments.append(
|
||||
"Datastore '{0}' already exists on host '{1}' "
|
||||
"and is backed by disk '{2}'. Nothing to be "
|
||||
"Datastore '{}' already exists on host '{}' "
|
||||
"and is backed by disk '{}'. Nothing to be "
|
||||
"done.".format(datastore["name"], hostname, backing_disk_display)
|
||||
)
|
||||
existing_datastore = existing_datastores[0]
|
||||
|
@ -1686,9 +1678,7 @@ def host_cache_configured(
|
|||
if needs_setting:
|
||||
if __opts__["test"]:
|
||||
comments.append(
|
||||
"State {0} will configure "
|
||||
"the host cache on host '{1}' to: {2}."
|
||||
"".format(
|
||||
"State {} will configure the host cache on host '{}' to: {}.".format(
|
||||
name,
|
||||
hostname,
|
||||
{
|
||||
|
@ -1702,9 +1692,8 @@ def host_cache_configured(
|
|||
if (existing_datastore["capacity"] / 1024.0 ** 2) < swap_size_MiB:
|
||||
|
||||
raise ArgumentValueError(
|
||||
"Capacity of host cache datastore '{0}' ({1} MiB) is "
|
||||
"smaller than the required swap size ({2} MiB)"
|
||||
"".format(
|
||||
"Capacity of host cache datastore '{}' ({} MiB) is "
|
||||
"smaller than the required swap size ({} MiB)".format(
|
||||
existing_datastore["name"],
|
||||
existing_datastore["capacity"] / 1024.0 ** 2,
|
||||
swap_size_MiB,
|
||||
|
@ -1717,11 +1706,11 @@ def host_cache_configured(
|
|||
service_instance=si,
|
||||
)
|
||||
comments.append(
|
||||
"Host cache configured on host " "'{0}'.".format(hostname)
|
||||
"Host cache configured on host " "'{}'.".format(hostname)
|
||||
)
|
||||
else:
|
||||
comments.append(
|
||||
"Host cache on host '{0}' is already correctly "
|
||||
"Host cache on host '{}' is already correctly "
|
||||
"configured. Nothing to be done.".format(hostname)
|
||||
)
|
||||
result = True
|
||||
|
|
|
@ -7,6 +7,8 @@ and the like, but also useful for basic HTTP testing.
|
|||
|
||||
import cgi
|
||||
import gzip
|
||||
import http.client
|
||||
import http.cookiejar
|
||||
import io
|
||||
import logging
|
||||
import os
|
||||
|
@ -14,13 +16,13 @@ import pprint
|
|||
import re
|
||||
import socket
|
||||
import ssl
|
||||
import urllib.error
|
||||
import urllib.parse
|
||||
import urllib.request
|
||||
import xml.etree.ElementTree as ET
|
||||
import zlib
|
||||
|
||||
import salt.config
|
||||
import salt.ext.six.moves.http_client
|
||||
import salt.ext.six.moves.http_cookiejar
|
||||
import salt.ext.six.moves.urllib.request as urllib_request
|
||||
import salt.ext.tornado.httputil
|
||||
import salt.ext.tornado.simple_httpclient
|
||||
import salt.loader
|
||||
|
@ -36,12 +38,6 @@ import salt.utils.stringutils
|
|||
import salt.utils.xmlutil as xml
|
||||
import salt.utils.yaml
|
||||
import salt.version
|
||||
from salt.ext import six
|
||||
from salt.ext.six.moves import StringIO
|
||||
from salt.ext.six.moves.urllib.error import URLError
|
||||
from salt.ext.six.moves.urllib.parse import splitquery
|
||||
from salt.ext.six.moves.urllib.parse import urlencode as _urlencode
|
||||
from salt.ext.six.moves.urllib.parse import urlparse
|
||||
from salt.ext.tornado.httpclient import HTTPClient
|
||||
from salt.template import compile_template
|
||||
from salt.utils.decorators.jinja import jinja_filter
|
||||
|
@ -317,11 +313,9 @@ def query(
|
|||
|
||||
if cookies is not None:
|
||||
if cookie_format == "mozilla":
|
||||
sess_cookies = salt.ext.six.moves.http_cookiejar.MozillaCookieJar(
|
||||
cookie_jar
|
||||
)
|
||||
sess_cookies = http.cookiejar.MozillaCookieJar(cookie_jar)
|
||||
else:
|
||||
sess_cookies = salt.ext.six.moves.http_cookiejar.LWPCookieJar(cookie_jar)
|
||||
sess_cookies = http.cookiejar.LWPCookieJar(cookie_jar)
|
||||
if not os.path.isfile(cookie_jar):
|
||||
sess_cookies.save()
|
||||
sess_cookies.load()
|
||||
|
@ -366,7 +360,7 @@ def query(
|
|||
method,
|
||||
url,
|
||||
params=params,
|
||||
files={formdata_fieldname: (formdata_filename, StringIO(data))},
|
||||
files={formdata_fieldname: (formdata_filename, io.StringIO(data))},
|
||||
**req_kwargs
|
||||
)
|
||||
else:
|
||||
|
@ -400,15 +394,15 @@ def query(
|
|||
body = body.decode(result.encoding or "utf-8")
|
||||
ret["body"] = body
|
||||
elif backend == "urllib2":
|
||||
request = urllib_request.Request(url_full, data)
|
||||
request = urllib.request.Request(url_full, data)
|
||||
handlers = [
|
||||
urllib_request.HTTPHandler,
|
||||
urllib_request.HTTPCookieProcessor(sess_cookies),
|
||||
urllib.request.HTTPHandler,
|
||||
urllib.request.HTTPCookieProcessor(sess_cookies),
|
||||
]
|
||||
|
||||
if url.startswith("https"):
|
||||
hostname = request.get_host()
|
||||
handlers[0] = urllib_request.HTTPSHandler(1)
|
||||
handlers[0] = urllib.request.HTTPSHandler(1)
|
||||
if not HAS_MATCHHOSTNAME:
|
||||
log.warning(
|
||||
"match_hostname() not available, SSL hostname checking "
|
||||
|
@ -459,7 +453,7 @@ def query(
|
|||
# Python >= 2.7.9
|
||||
context = ssl.SSLContext.load_cert_chain(*cert_chain)
|
||||
handlers.append(
|
||||
urllib_request.HTTPSHandler(context=context)
|
||||
urllib.request.HTTPSHandler(context=context)
|
||||
) # pylint: disable=E1123
|
||||
else:
|
||||
# Python < 2.7.9
|
||||
|
@ -470,17 +464,15 @@ def query(
|
|||
}
|
||||
if len(cert_chain) > 1:
|
||||
cert_kwargs["key_file"] = cert_chain[1]
|
||||
handlers[0] = salt.ext.six.moves.http_client.HTTPSConnection(
|
||||
**cert_kwargs
|
||||
)
|
||||
handlers[0] = http.client.HTTPSConnection(**cert_kwargs)
|
||||
|
||||
opener = urllib_request.build_opener(*handlers)
|
||||
opener = urllib.request.build_opener(*handlers)
|
||||
for header in header_dict:
|
||||
request.add_header(header, header_dict[header])
|
||||
request.get_method = lambda: method
|
||||
try:
|
||||
result = opener.open(request)
|
||||
except URLError as exc:
|
||||
except urllib.error.URLError as exc:
|
||||
return {"Error": str(exc)}
|
||||
if stream is True or handle is True:
|
||||
return {
|
||||
|
@ -501,7 +493,7 @@ def query(
|
|||
and not isinstance(result_text, str)
|
||||
):
|
||||
result_text = result_text.decode(res_params["charset"])
|
||||
if six.PY3 and isinstance(result_text, bytes) and decode_body:
|
||||
if isinstance(result_text, bytes) and decode_body:
|
||||
result_text = result_text.decode("utf-8")
|
||||
ret["body"] = result_text
|
||||
else:
|
||||
|
@ -525,7 +517,7 @@ def query(
|
|||
)
|
||||
|
||||
if isinstance(data, dict):
|
||||
data = _urlencode(data)
|
||||
data = urllib.parse.urlencode(data)
|
||||
|
||||
if verify_ssl:
|
||||
req_kwargs["ca_certs"] = ca_bundle
|
||||
|
@ -561,7 +553,7 @@ def query(
|
|||
|
||||
# Since tornado doesnt support no_proxy, we'll always hand it empty proxies or valid ones
|
||||
# except we remove the valid ones if a url has a no_proxy hostname in it
|
||||
if urlparse(url_full).hostname in no_proxy:
|
||||
if urllib.parse.urlparse(url_full).hostname in no_proxy:
|
||||
proxy_host = None
|
||||
proxy_port = None
|
||||
proxy_username = None
|
||||
|
@ -655,7 +647,7 @@ def query(
|
|||
and not isinstance(result_text, str)
|
||||
):
|
||||
result_text = result_text.decode(res_params["charset"])
|
||||
if six.PY3 and isinstance(result_text, bytes) and decode_body:
|
||||
if isinstance(result_text, bytes) and decode_body:
|
||||
result_text = result_text.decode("utf-8")
|
||||
ret["body"] = result_text
|
||||
if "Set-Cookie" in result_headers and cookies is not None:
|
||||
|
@ -994,9 +986,7 @@ def parse_cookie_header(header):
|
|||
|
||||
# cookielib.Cookie() requires an epoch
|
||||
if "expires" in cookie:
|
||||
cookie["expires"] = salt.ext.six.moves.http_cookiejar.http2time(
|
||||
cookie["expires"]
|
||||
)
|
||||
cookie["expires"] = http.cookiejar.http2time(cookie["expires"])
|
||||
|
||||
# Fill in missing required fields
|
||||
for req in reqd:
|
||||
|
@ -1012,9 +1002,7 @@ def parse_cookie_header(header):
|
|||
# Remove attribs that don't apply to Cookie objects
|
||||
cookie.pop("httponly", None)
|
||||
cookie.pop("samesite", None)
|
||||
ret.append(
|
||||
salt.ext.six.moves.http_cookiejar.Cookie(name=name, value=value, **cookie)
|
||||
)
|
||||
ret.append(http.cookiejar.Cookie(name=name, value=value, **cookie))
|
||||
|
||||
return ret
|
||||
|
||||
|
@ -1024,7 +1012,7 @@ def sanitize_url(url, hide_fields):
|
|||
Make sure no secret fields show up in logs
|
||||
"""
|
||||
if isinstance(hide_fields, list):
|
||||
url_comps = splitquery(url)
|
||||
url_comps = urllib.parse.splitquery(url)
|
||||
log_url = url_comps[0]
|
||||
if len(url_comps) > 1:
|
||||
log_url += "?"
|
||||
|
@ -1057,3 +1045,23 @@ def _sanitize_url_components(comp_list, field):
|
|||
ret = "{}&".format(comp_list[0])
|
||||
comp_list.remove(comp_list[0])
|
||||
return ret + _sanitize_url_components(comp_list, field)
|
||||
|
||||
|
||||
def session(user=None, password=None, verify_ssl=True, ca_bundle=None, headers=None):
|
||||
"""
|
||||
create a requests session
|
||||
"""
|
||||
session = requests.session()
|
||||
if user and password:
|
||||
session.auth = (user, password)
|
||||
if ca_bundle and not verify_ssl:
|
||||
log.error("You cannot use both ca_bundle and verify_ssl False together")
|
||||
return False
|
||||
if ca_bundle:
|
||||
opts = {"ca_bundle": ca_bundle}
|
||||
session.verify = get_ca_bundle(opts)
|
||||
if not verify_ssl:
|
||||
session.verify = False
|
||||
if headers:
|
||||
session.headers.update(headers)
|
||||
return session
|
||||
|
|
|
@ -228,8 +228,8 @@ def get_tops_python(py_ver, exclude=None, ext_py_ver=None):
|
|||
"{} does not exist. Could not auto detect dependencies".format(py_ver)
|
||||
)
|
||||
return {}
|
||||
py_shell_cmd = "{0} -c 'import {1}; print({1}.__file__)'".format(py_ver, mod)
|
||||
cmd = subprocess.Popen(py_shell_cmd, stdout=subprocess.PIPE, shell=True)
|
||||
py_shell_cmd = [py_ver, "-c", "import {0}; print({0}.__file__)".format(mod)]
|
||||
cmd = subprocess.Popen(py_shell_cmd, stdout=subprocess.PIPE)
|
||||
stdout, _ = cmd.communicate()
|
||||
mod_file = os.path.abspath(salt.utils.data.decode(stdout).rstrip("\n"))
|
||||
|
||||
|
|
|
@ -72,7 +72,6 @@ You should see output related to the ESXi host's syslog configuration.
|
|||
|
||||
"""
|
||||
|
||||
|
||||
import atexit
|
||||
import errno
|
||||
import logging
|
||||
|
@ -80,7 +79,6 @@ import ssl
|
|||
import time
|
||||
from http.client import BadStatusLine
|
||||
|
||||
import requests
|
||||
import salt.exceptions
|
||||
import salt.modules.cmdmod
|
||||
import salt.utils.path
|
||||
|
@ -170,11 +168,8 @@ def esxcli(
|
|||
host, user, pwd, protocol, port, cmd
|
||||
)
|
||||
else:
|
||||
esx_cmd += (
|
||||
" -s {} -h {} -u {} -p '{}' "
|
||||
"--protocol={} --portnumber={} {}".format(
|
||||
host, esxi_host, user, pwd, protocol, port, cmd
|
||||
)
|
||||
esx_cmd += " -s {} -h {} -u {} -p '{}' --protocol={} --portnumber={} {}".format(
|
||||
host, esxi_host, user, pwd, protocol, port, cmd
|
||||
)
|
||||
|
||||
ret = salt.modules.cmdmod.run_all(esx_cmd, output_loglevel="quiet")
|
||||
|
@ -182,7 +177,9 @@ def esxcli(
|
|||
return ret
|
||||
|
||||
|
||||
def get_vsphere_client(server, username, password, session=None):
|
||||
def get_vsphere_client(
|
||||
server, username, password, session=None, verify_ssl=True, ca_bundle=None
|
||||
):
|
||||
"""
|
||||
Internal helper method to create an instance of the vSphere API client.
|
||||
Please provide username and password to authenticate.
|
||||
|
@ -196,6 +193,10 @@ def get_vsphere_client(server, username, password, session=None):
|
|||
:param Session session:
|
||||
Request HTTP session instance. If not specified, one
|
||||
is automatically created and used
|
||||
:param boolean verify_ssl:
|
||||
Verify the SSL certificate. Default: True
|
||||
:param basestring ca_bundle:
|
||||
Path to the ca bundle to use when verifying SSL certificates.
|
||||
|
||||
:returns:
|
||||
Vsphere Client instance
|
||||
|
@ -204,9 +205,7 @@ def get_vsphere_client(server, username, password, session=None):
|
|||
"""
|
||||
if not session:
|
||||
# Create an https session to be used for a vSphere client
|
||||
session = requests.session()
|
||||
# If client uses own SSL cert, session should not verify
|
||||
session.verify = False
|
||||
session = salt.utils.http.session(verify_ssl=verify_ssl, ca_bundle=ca_bundle)
|
||||
client = None
|
||||
try:
|
||||
client = create_vsphere_client(
|
||||
|
@ -218,7 +217,15 @@ def get_vsphere_client(server, username, password, session=None):
|
|||
|
||||
|
||||
def _get_service_instance(
|
||||
host, username, password, protocol, port, mechanism, principal, domain
|
||||
host,
|
||||
username,
|
||||
password,
|
||||
protocol,
|
||||
port,
|
||||
mechanism,
|
||||
principal,
|
||||
domain,
|
||||
verify_ssl=True,
|
||||
):
|
||||
"""
|
||||
Internal method to authenticate with a vCenter server or ESX/ESXi host
|
||||
|
@ -253,21 +260,26 @@ def _get_service_instance(
|
|||
raise salt.exceptions.CommandExecutionError(
|
||||
"Unsupported mechanism: '{}'".format(mechanism)
|
||||
)
|
||||
|
||||
log.trace(
|
||||
"Connecting using the '%s' mechanism, with username '%s'", mechanism, username,
|
||||
)
|
||||
default_msg = (
|
||||
"Could not connect to host '{}'. "
|
||||
"Please check the debug log for more information.".format(host)
|
||||
)
|
||||
|
||||
try:
|
||||
log.trace(
|
||||
"Connecting using the '%s' mechanism, with username '%s'",
|
||||
mechanism,
|
||||
username,
|
||||
)
|
||||
service_instance = SmartConnect(
|
||||
host=host,
|
||||
user=username,
|
||||
pwd=password,
|
||||
protocol=protocol,
|
||||
port=port,
|
||||
b64token=token,
|
||||
mechanism=mechanism,
|
||||
)
|
||||
if verify_ssl:
|
||||
service_instance = SmartConnect(
|
||||
host=host,
|
||||
user=username,
|
||||
pwd=password,
|
||||
protocol=protocol,
|
||||
port=port,
|
||||
b64token=token,
|
||||
mechanism=mechanism,
|
||||
)
|
||||
except TypeError as exc:
|
||||
if "unexpected keyword argument" in exc.message:
|
||||
log.error(
|
||||
|
@ -280,30 +292,33 @@ def _get_service_instance(
|
|||
raise
|
||||
except Exception as exc: # pylint: disable=broad-except
|
||||
# pyVmomi's SmartConnect() actually raises Exception in some cases.
|
||||
default_msg = (
|
||||
"Could not connect to host '{}'. "
|
||||
"Please check the debug log for more information.".format(host)
|
||||
)
|
||||
if (
|
||||
isinstance(exc, vim.fault.HostConnectFault)
|
||||
and "[SSL: CERTIFICATE_VERIFY_FAILED]" in exc.msg
|
||||
) or "[SSL: CERTIFICATE_VERIFY_FAILED]" in str(exc):
|
||||
err_msg = (
|
||||
"Could not verify the SSL certificate. You can use "
|
||||
"verify_ssl: False if you do not want to verify the "
|
||||
"SSL certificate. This is not recommended as it is "
|
||||
"considered insecure."
|
||||
)
|
||||
else:
|
||||
log.exception(exc)
|
||||
err_msg = exc.msg if hasattr(exc, "msg") else default_msg
|
||||
raise salt.exceptions.VMwareConnectionError(err_msg)
|
||||
|
||||
if not verify_ssl:
|
||||
try:
|
||||
if (
|
||||
isinstance(exc, vim.fault.HostConnectFault)
|
||||
and "[SSL: CERTIFICATE_VERIFY_FAILED]" in exc.msg
|
||||
) or "[SSL: CERTIFICATE_VERIFY_FAILED]" in str(exc):
|
||||
service_instance = SmartConnect(
|
||||
host=host,
|
||||
user=username,
|
||||
pwd=password,
|
||||
protocol=protocol,
|
||||
port=port,
|
||||
sslContext=ssl._create_unverified_context(),
|
||||
b64token=token,
|
||||
mechanism=mechanism,
|
||||
)
|
||||
else:
|
||||
log.exception(exc)
|
||||
err_msg = exc.msg if hasattr(exc, "msg") else default_msg
|
||||
raise salt.exceptions.VMwareConnectionError(err_msg)
|
||||
service_instance = SmartConnect(
|
||||
host=host,
|
||||
user=username,
|
||||
pwd=password,
|
||||
protocol=protocol,
|
||||
port=port,
|
||||
sslContext=ssl._create_unverified_context(),
|
||||
b64token=token,
|
||||
mechanism=mechanism,
|
||||
)
|
||||
except Exception as exc: # pylint: disable=broad-except
|
||||
# pyVmomi's SmartConnect() actually raises Exception in some cases.
|
||||
if "certificate verify failed" in str(exc):
|
||||
|
@ -330,6 +345,7 @@ def _get_service_instance(
|
|||
err_msg = exc.msg if hasattr(exc, "msg") else default_msg
|
||||
log.trace(exc)
|
||||
raise salt.exceptions.VMwareConnectionError(err_msg)
|
||||
|
||||
atexit.register(Disconnect, service_instance)
|
||||
return service_instance
|
||||
|
||||
|
@ -384,6 +400,7 @@ def get_service_instance(
|
|||
mechanism="userpass",
|
||||
principal=None,
|
||||
domain=None,
|
||||
verify_ssl=True,
|
||||
):
|
||||
"""
|
||||
Authenticate with a vCenter server or ESX/ESXi host and return the service instance object.
|
||||
|
@ -416,6 +433,9 @@ def get_service_instance(
|
|||
|
||||
domain
|
||||
Kerberos user domain. Required if mechanism is ``sspi``
|
||||
|
||||
verify_ssl
|
||||
Verify the SSL certificate. Default: True
|
||||
"""
|
||||
|
||||
if protocol is None:
|
||||
|
@ -438,7 +458,15 @@ def get_service_instance(
|
|||
|
||||
if not service_instance:
|
||||
service_instance = _get_service_instance(
|
||||
host, username, password, protocol, port, mechanism, principal, domain
|
||||
host,
|
||||
username,
|
||||
password,
|
||||
protocol,
|
||||
port,
|
||||
mechanism,
|
||||
principal,
|
||||
domain,
|
||||
verify_ssl=verify_ssl,
|
||||
)
|
||||
|
||||
# Test if data can actually be retrieved or connection has gone stale
|
||||
|
@ -449,7 +477,15 @@ def get_service_instance(
|
|||
log.trace("Session no longer authenticating. Reconnecting")
|
||||
Disconnect(service_instance)
|
||||
service_instance = _get_service_instance(
|
||||
host, username, password, protocol, port, mechanism, principal, domain
|
||||
host,
|
||||
username,
|
||||
password,
|
||||
protocol,
|
||||
port,
|
||||
mechanism,
|
||||
principal,
|
||||
domain,
|
||||
verify_ssl=verify_ssl,
|
||||
)
|
||||
except vim.fault.NoPermission as exc:
|
||||
log.exception(exc)
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Modules used to control the master itself
|
||||
"""
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
|
||||
from collections.abc import Mapping
|
||||
|
||||
|
@ -15,7 +13,7 @@ import salt.utils.zeromq
|
|||
|
||||
|
||||
class WheelClient(
|
||||
salt.client.mixins.SyncClientMixin, salt.client.mixins.AsyncClientMixin, object
|
||||
salt.client.mixins.SyncClientMixin, salt.client.mixins.AsyncClientMixin
|
||||
):
|
||||
"""
|
||||
An interface to Salt's wheel modules
|
||||
|
@ -123,8 +121,8 @@ class WheelClient(
|
|||
})
|
||||
{'jid': '20131219224744416681', 'tag': 'salt/wheel/20131219224744416681'}
|
||||
"""
|
||||
fun = low.pop("fun")
|
||||
return self.asynchronous(fun, low)
|
||||
fun = low.get("fun")
|
||||
return self.asynchronous(fun, low, local=False)
|
||||
|
||||
def cmd(
|
||||
self,
|
||||
|
@ -143,9 +141,7 @@ class WheelClient(
|
|||
>>> wheel.cmd('key.finger', ['jerry'])
|
||||
{'minions': {'jerry': '5d:f6:79:43:5e:d4:42:3f:57:b8:45:a8:7e:a4:6e:ca'}}
|
||||
"""
|
||||
return super(WheelClient, self).cmd(
|
||||
fun, arg, pub_data, kwarg, print_event, full_return
|
||||
)
|
||||
return super().cmd(fun, arg, pub_data, kwarg, print_event, full_return)
|
||||
|
||||
|
||||
Wheel = WheelClient # for backward-compat
|
||||
|
|
|
@ -1,20 +1,13 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
The `pillar_roots` wheel module is used to manage files under the pillar roots
|
||||
directories on the master server.
|
||||
"""
|
||||
|
||||
# Import python libs
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
|
||||
import os
|
||||
|
||||
# Import salt libs
|
||||
import salt.utils.files
|
||||
import salt.utils.path
|
||||
|
||||
# Import 3rd-party libs
|
||||
from salt.ext import six
|
||||
import salt.utils.verify
|
||||
|
||||
|
||||
def find(path, saltenv="base"):
|
||||
|
@ -86,7 +79,7 @@ def read(path, saltenv="base"):
|
|||
ret = []
|
||||
files = find(path, saltenv)
|
||||
for fn_ in files:
|
||||
full = next(six.iterkeys(fn_))
|
||||
full = next(iter(fn_.keys()))
|
||||
form = fn_[full]
|
||||
if form == "txt":
|
||||
with salt.utils.files.fopen(full, "rb") as fp_:
|
||||
|
@ -100,19 +93,23 @@ def write(data, path, saltenv="base", index=0):
|
|||
index of the file can be specified to write to a lower priority file root
|
||||
"""
|
||||
if saltenv not in __opts__["pillar_roots"]:
|
||||
return "Named environment {0} is not present".format(saltenv)
|
||||
return "Named environment {} is not present".format(saltenv)
|
||||
if len(__opts__["pillar_roots"][saltenv]) <= index:
|
||||
return "Specified index {0} in environment {1} is not present".format(
|
||||
return "Specified index {} in environment {} is not present".format(
|
||||
index, saltenv
|
||||
)
|
||||
if os.path.isabs(path):
|
||||
return (
|
||||
"The path passed in {0} is not relative to the environment " "{1}"
|
||||
).format(path, saltenv)
|
||||
return "The path passed in {} is not relative to the environment " "{}".format(
|
||||
path, saltenv
|
||||
)
|
||||
roots_dir = __opts__["pillar_roots"][saltenv][index]
|
||||
dest = os.path.join(roots_dir, path)
|
||||
if not salt.utils.verify.clean_path(roots_dir, dest):
|
||||
return "Invalid path"
|
||||
dest = os.path.join(__opts__["pillar_roots"][saltenv][index], path)
|
||||
dest_dir = os.path.dirname(dest)
|
||||
if not os.path.isdir(dest_dir):
|
||||
os.makedirs(dest_dir)
|
||||
with salt.utils.files.fopen(dest, "w+") as fp_:
|
||||
fp_.write(salt.utils.stringutils.to_str(data))
|
||||
return "Wrote data to file {0}".format(dest)
|
||||
return "Wrote data to file {}".format(dest)
|
||||
|
|
|
@ -76,3 +76,20 @@ class VMWareTest(CloudTest):
|
|||
self.assertIn(s_ret_str, str(create_snapshot))
|
||||
|
||||
self.assertDestroyInstance()
|
||||
|
||||
def test_verify_ssl_false(self):
|
||||
"""
|
||||
Tests creating and deleting an instance on vmware when using
|
||||
verify_ssl: False
|
||||
"""
|
||||
profile_name = "vmware_verify_ssl"
|
||||
self.add_profile_config(
|
||||
"vmware-test", {"verify_ssl": False}, "vmware.conf", profile_name
|
||||
)
|
||||
# create the instance
|
||||
ret_val = self.run_cloud(
|
||||
"-p {} {}".format(profile_name, self.instance_name), timeout=TIMEOUT
|
||||
)
|
||||
# check if instance returned with salt installed
|
||||
self.assertInstanceExists(ret_val)
|
||||
self.assertDestroyInstance()
|
||||
|
|
|
@ -9,6 +9,7 @@ import shutil
|
|||
from time import sleep
|
||||
|
||||
import pytest
|
||||
import salt.utils.files
|
||||
from salt.config import cloud_config, cloud_providers_config
|
||||
from salt.utils.yaml import safe_load
|
||||
from tests.support.case import ShellCase
|
||||
|
@ -195,6 +196,18 @@ class CloudTest(ShellCase):
|
|||
def profile_str(self):
|
||||
return self.PROVIDER + "-config"
|
||||
|
||||
def add_profile_config(self, name, data, conf, new_profile):
|
||||
"""
|
||||
copy the current profile and add a new profile in the same file
|
||||
"""
|
||||
conf_path = os.path.join(RUNTIME_VARS.TMP_CONF_DIR, "cloud.profiles.d", conf)
|
||||
with salt.utils.files.fopen(conf_path, "r") as fp:
|
||||
conf = safe_load(fp)
|
||||
conf[new_profile] = conf[name].copy()
|
||||
conf[new_profile].update(data)
|
||||
with salt.utils.files.fopen(conf_path, "w") as fp:
|
||||
salt.utils.yaml.safe_dump(conf, fp)
|
||||
|
||||
def setUp(self):
|
||||
"""
|
||||
Sets up the test requirements. In child classes, define PROVIDER and REQUIRED_PROVIDER_CONFIG_ITEMS or this will fail
|
||||
|
|
|
@ -452,11 +452,48 @@ class NetapiSSHClientAuthTest(SSHCase):
|
|||
except AssertionError:
|
||||
self.mod_case.run_function("user.delete", [self.USERA], remove=True)
|
||||
self.skipTest("Could not add user or password, skipping test")
|
||||
self.expfile = os.path.join(RUNTIME_VARS.TMP, "exploited")
|
||||
|
||||
def tearDown(self):
|
||||
try:
|
||||
os.remove(self.expfile)
|
||||
except OSError:
|
||||
pass
|
||||
del self.expfile
|
||||
del self.netapi
|
||||
self.mod_case.run_function("user.delete", [self.USERA], remove=True)
|
||||
|
||||
@staticmethod
|
||||
def cleanup_file(path):
|
||||
try:
|
||||
os.remove(path)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
@pytest.mark.slow_test
|
||||
def test_extra_mods(self):
|
||||
"""
|
||||
validate input from extra_mods
|
||||
"""
|
||||
path = os.path.join(RUNTIME_VARS.TMP, "test_extra_mods")
|
||||
self.addCleanup(self.cleanup_file, path)
|
||||
low = {
|
||||
"client": "ssh",
|
||||
"tgt": "localhost",
|
||||
"fun": "test.ping",
|
||||
"roster_file": "roster",
|
||||
"rosters": [self.rosters],
|
||||
"ssh_priv": self.priv_file,
|
||||
"eauth": "pam",
|
||||
"username": self.USERA,
|
||||
"password": self.USERA_PWD,
|
||||
"regen_thin": True,
|
||||
"thin_extra_mods": "';touch {};'".format(path),
|
||||
}
|
||||
|
||||
ret = self.netapi.run(low)
|
||||
self.assertFalse(os.path.exists(path))
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.post_webserver = Webserver(handler=SaveRequestsPostHandler)
|
||||
|
@ -571,3 +608,34 @@ class NetapiSSHClientAuthTest(SSHCase):
|
|||
ret = self.netapi.run(low)
|
||||
assert "localhost" in ret
|
||||
assert ret["localhost"]["return"] is True
|
||||
|
||||
def test_ssh_cve_2021_3197_a(self):
|
||||
assert not os.path.exists(self.expfile)
|
||||
low = {
|
||||
"eauth": "auto",
|
||||
"username": self.USERA,
|
||||
"password": self.USERA_PWD,
|
||||
"client": "ssh",
|
||||
"tgt": "localhost",
|
||||
"fun": "test.ping",
|
||||
"ssh_port": '22 -o ProxyCommand="touch {}"'.format(self.expfile),
|
||||
"ssh_priv": self.priv_file,
|
||||
}
|
||||
ret = self.netapi.run(low)
|
||||
assert not os.path.exists(self.expfile)
|
||||
|
||||
def test_ssh_cve_2021_3197_b(self):
|
||||
assert not os.path.exists(self.expfile)
|
||||
low = {
|
||||
"eauth": "auto",
|
||||
"username": self.USERA,
|
||||
"password": self.USERA_PWD,
|
||||
"client": "ssh",
|
||||
"tgt": "localhost",
|
||||
"fun": "test.ping",
|
||||
"ssh_port": 22,
|
||||
"ssh_priv": self.priv_file,
|
||||
"ssh_options": ['ProxyCommand="touch {}"'.format(self.expfile)],
|
||||
}
|
||||
ret = self.netapi.run(low)
|
||||
assert not os.path.exists(self.expfile)
|
||||
|
|
37
tests/integration/wheel/test_pillar_roots.py
Normal file
37
tests/integration/wheel/test_pillar_roots.py
Normal 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
|
52
tests/pytests/unit/utils/test_http.py
Normal file
52
tests/pytests/unit/utils/test_http.py
Normal 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
|
|
@ -35,11 +35,11 @@ def test_get_tops_python(version):
|
|||
with patch_proc, patch_which:
|
||||
salt.utils.thin.get_tops_python("python2", ext_py_ver=version)
|
||||
cmds = [x[0][0] for x in mock_popen.call_args_list]
|
||||
assert [x for x in cmds if "jinja2" in x]
|
||||
assert [x for x in cmds if "jinja2" in x[2]]
|
||||
if python3:
|
||||
assert [x for x in cmds if "distro" in x]
|
||||
assert [x for x in cmds if "distro" in x[2]]
|
||||
else:
|
||||
assert not [x for x in cmds if "distro" in x]
|
||||
assert not [x for x in cmds if "distro" in x[2]]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("version", [[2, 7], [3, 0], [3, 7]])
|
||||
|
|
35
tests/unit/auth/test_auth.py
Normal file
35
tests/unit/auth/test_auth.py
Normal 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 == {}
|
59
tests/unit/cloud/clouds/test_qingcloud.py
Normal file
59
tests/unit/cloud/clouds/test_qingcloud.py
Normal 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
|
||||
)
|
37
tests/unit/modules/test_bigip.py
Normal file
37
tests/unit/modules/test_bigip.py
Normal 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
|
|
@ -2,7 +2,7 @@
|
|||
:codeauthor: Nicole Thomas <nicole@saltstack.com>
|
||||
"""
|
||||
|
||||
|
||||
import builtins
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
|
@ -12,7 +12,6 @@ import salt.utils.files
|
|||
import salt.utils.platform
|
||||
import salt.utils.stringutils
|
||||
from salt.exceptions import CommandExecutionError
|
||||
from salt.ext.six.moves import builtins # pylint: disable=import-error
|
||||
from salt.log import LOG_LEVELS
|
||||
from tests.support.helpers import TstSuiteLoggingHandler
|
||||
from tests.support.mixins import LoaderModuleMockMixin
|
||||
|
@ -640,3 +639,16 @@ class CMDMODTestCase(TestCase, LoaderModuleMockMixin):
|
|||
umask=None,
|
||||
use_vt=False,
|
||||
)
|
||||
|
||||
def test_cve_2021_25284(self):
|
||||
proc = MagicMock(
|
||||
return_value=MockTimedProc(stdout=b"foo", stderr=b"wtf", returncode=2)
|
||||
)
|
||||
with patch("salt.utils.timed_subprocess.TimedProc", proc):
|
||||
with TstSuiteLoggingHandler() as log_handler:
|
||||
cmdmod.run("testcmd -p ImAPassword", output_loglevel="error")
|
||||
for x in log_handler.messages:
|
||||
if x.find("Executing command") > -1:
|
||||
assert x.find("ImAPassword") == -1, x
|
||||
if x.find("faild with return code") > -1:
|
||||
assert x.find("ImAPassword") == -1, x
|
||||
|
|
69
tests/unit/modules/test_glassfish.py
Normal file
69
tests/unit/modules/test_glassfish.py
Normal 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},
|
||||
)
|
|
@ -1,21 +1,15 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
:codeauthor: Jayesh Kariya <jayeshk@saltstack.com>
|
||||
"""
|
||||
|
||||
# Import Python Libs
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
|
||||
# Import Salt Libs
|
||||
import salt.modules.config as config
|
||||
import salt.modules.keystone as keystone
|
||||
|
||||
# Import Salt Testing Libs
|
||||
from tests.support.mixins import LoaderModuleMockMixin
|
||||
from tests.support.mock import MagicMock, patch
|
||||
from tests.support.mock import MagicMock, call, patch
|
||||
from tests.support.unit import TestCase
|
||||
|
||||
|
||||
class MockEC2(object):
|
||||
class MockEC2:
|
||||
"""
|
||||
Mock of EC2 class
|
||||
"""
|
||||
|
@ -68,7 +62,7 @@ class MockEC2(object):
|
|||
return [cr_ec2]
|
||||
|
||||
|
||||
class MockEndpoints(object):
|
||||
class MockEndpoints:
|
||||
"""
|
||||
Mock of Endpoints class
|
||||
"""
|
||||
|
@ -103,7 +97,7 @@ class MockEndpoints(object):
|
|||
return id
|
||||
|
||||
|
||||
class MockServices(object):
|
||||
class MockServices:
|
||||
"""
|
||||
Mock of Services class
|
||||
"""
|
||||
|
@ -159,7 +153,7 @@ class MockServices(object):
|
|||
return service_id
|
||||
|
||||
|
||||
class MockRoles(object):
|
||||
class MockRoles:
|
||||
"""
|
||||
Mock of Roles class
|
||||
"""
|
||||
|
@ -229,7 +223,7 @@ class MockRoles(object):
|
|||
return [role]
|
||||
|
||||
|
||||
class MockTenants(object):
|
||||
class MockTenants:
|
||||
"""
|
||||
Mock of Tenants class
|
||||
"""
|
||||
|
@ -279,7 +273,7 @@ class MockTenants(object):
|
|||
return tenant_id
|
||||
|
||||
|
||||
class MockServiceCatalog(object):
|
||||
class MockServiceCatalog:
|
||||
"""
|
||||
Mock of ServiceCatalog class
|
||||
"""
|
||||
|
@ -302,7 +296,7 @@ class MockServiceCatalog(object):
|
|||
}
|
||||
|
||||
|
||||
class MockUsers(object):
|
||||
class MockUsers:
|
||||
"""
|
||||
Mock of Users class
|
||||
"""
|
||||
|
@ -375,7 +369,7 @@ class Unauthorized(Exception):
|
|||
"""
|
||||
|
||||
def __init__(self, message="Test"):
|
||||
super(Unauthorized, self).__init__(message)
|
||||
super().__init__(message)
|
||||
self.msg = message
|
||||
|
||||
|
||||
|
@ -385,11 +379,11 @@ class AuthorizationFailure(Exception):
|
|||
"""
|
||||
|
||||
def __init__(self, message="Test"):
|
||||
super(AuthorizationFailure, self).__init__(message)
|
||||
super().__init__(message)
|
||||
self.msg = message
|
||||
|
||||
|
||||
class MockExceptions(object):
|
||||
class MockExceptions:
|
||||
"""
|
||||
Mock of exceptions class
|
||||
"""
|
||||
|
@ -399,7 +393,7 @@ class MockExceptions(object):
|
|||
self.AuthorizationFailure = AuthorizationFailure
|
||||
|
||||
|
||||
class MockKeystoneClient(object):
|
||||
class MockKeystoneClient:
|
||||
"""
|
||||
Mock of keystoneclient module
|
||||
"""
|
||||
|
@ -408,7 +402,7 @@ class MockKeystoneClient(object):
|
|||
self.exceptions = MockExceptions()
|
||||
|
||||
|
||||
class MockClient(object):
|
||||
class MockClient:
|
||||
"""
|
||||
Mock of Client class
|
||||
"""
|
||||
|
@ -444,7 +438,10 @@ class KeystoneTestCase(TestCase, LoaderModuleMockMixin):
|
|||
"auth": MockClient,
|
||||
"client": MockClient(),
|
||||
"keystoneclient": MockKeystoneClient(),
|
||||
}
|
||||
"__salt__": {"config.get": config.get},
|
||||
"__opts__": {},
|
||||
},
|
||||
config: {"__opts__": {}},
|
||||
}
|
||||
|
||||
# 'ec2_credentials_create' function tests: 1
|
||||
|
@ -1053,3 +1050,41 @@ class KeystoneTestCase(TestCase, LoaderModuleMockMixin):
|
|||
}
|
||||
},
|
||||
)
|
||||
|
||||
def test_api_version_verify_ssl(self):
|
||||
"""
|
||||
test api_version when using verify_ssl
|
||||
"""
|
||||
test_verify = [True, False, None]
|
||||
conn_args = {
|
||||
"keystone.user": "admin",
|
||||
"connection_password": "password",
|
||||
"connection_tenant": "admin",
|
||||
"connection_tenant_id": "id",
|
||||
"connection_auth_url": "https://127.0.0.1/v2.0/",
|
||||
"connection_verify_ssl": True,
|
||||
}
|
||||
|
||||
http_ret = {"dict": {"version": {"id": "id_test"}}}
|
||||
for verify in test_verify:
|
||||
mock_http = MagicMock(return_value=http_ret)
|
||||
patch_http = patch("salt.utils.http.query", mock_http)
|
||||
conn_args["connection_verify_ssl"] = verify
|
||||
if verify is None:
|
||||
conn_args.pop("connection_verify_ssl")
|
||||
verify = True
|
||||
|
||||
with patch_http:
|
||||
ret = keystone.api_version(**conn_args)
|
||||
|
||||
self.assertEqual(
|
||||
mock_http.call_args_list,
|
||||
[
|
||||
call(
|
||||
"https://127.0.0.1/v2.0/",
|
||||
decode=True,
|
||||
decode_type="json",
|
||||
verify_ssl=verify,
|
||||
)
|
||||
],
|
||||
)
|
||||
|
|
|
@ -1,22 +1,16 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
:codeauthor: :email:`David Homolka <david.homolka@ultimum.io>`
|
||||
"""
|
||||
|
||||
# Import Python Libs
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
import os
|
||||
|
||||
# Import Salt Libsrestartcheck
|
||||
import salt.modules.restartcheck as restartcheck
|
||||
|
||||
# Import Salt Testing Libs
|
||||
import salt.utils.path
|
||||
from tests.support.mixins import LoaderModuleMockMixin
|
||||
from tests.support.mock import MagicMock, patch
|
||||
from tests.support.runtests import RUNTIME_VARS
|
||||
from tests.support.unit import TestCase
|
||||
|
||||
# import salt.utils.files
|
||||
# from salt.exceptions import CommandExecutionError
|
||||
|
||||
|
||||
class RestartcheckTestCase(TestCase, LoaderModuleMockMixin):
|
||||
"""
|
||||
|
@ -329,3 +323,61 @@ class RestartcheckTestCase(TestCase, LoaderModuleMockMixin):
|
|||
self.assertFalse(restartcheck._valid_deleted_file("/SYSV/test"))
|
||||
self.assertFalse(restartcheck._valid_deleted_file("/SYSV/test (deleted)"))
|
||||
self.assertFalse(restartcheck._valid_deleted_file("/SYSV/test (path inode=1)"))
|
||||
|
||||
def test_valid_command(self):
|
||||
"""
|
||||
test for CVE-2020-28243
|
||||
"""
|
||||
create_file = os.path.join(RUNTIME_VARS.TMP, "created_file")
|
||||
|
||||
patch_kernel = patch(
|
||||
"salt.modules.restartcheck._kernel_versions_redhat",
|
||||
return_value=["3.10.0-1127.el7.x86_64"],
|
||||
)
|
||||
services = {
|
||||
"NetworkManager": {"ExecMainPID": 123},
|
||||
"auditd": {"ExecMainPID": 456},
|
||||
"crond": {"ExecMainPID": 789},
|
||||
}
|
||||
|
||||
patch_salt = patch.dict(
|
||||
restartcheck.__salt__,
|
||||
{
|
||||
"cmd.run": MagicMock(
|
||||
return_value="Linux localhost.localdomain 3.10.0-1127.el7.x86_64"
|
||||
),
|
||||
"service.get_running": MagicMock(return_value=list(services.keys())),
|
||||
"service.show": MagicMock(side_effect=list(services.values())),
|
||||
"pkg.owner": MagicMock(return_value=""),
|
||||
"service.available": MagicMock(return_value=True),
|
||||
},
|
||||
)
|
||||
|
||||
patch_deleted = patch(
|
||||
"salt.modules.restartcheck._deleted_files",
|
||||
MagicMock(
|
||||
return_value=[
|
||||
(";touch {};".format(create_file), 123, "/root/ (deleted)")
|
||||
]
|
||||
),
|
||||
)
|
||||
|
||||
patch_readlink = patch(
|
||||
"os.readlink", return_value="/root/;touch {};".format(create_file)
|
||||
)
|
||||
|
||||
check_error = True
|
||||
if salt.utils.path.which("repoquery"):
|
||||
check_error = False
|
||||
|
||||
patch_grains = patch.dict(restartcheck.__grains__, {"os_family": "RedHat"})
|
||||
with patch_kernel, patch_salt, patch_deleted, patch_readlink, patch_grains:
|
||||
if check_error:
|
||||
with self.assertRaises(FileNotFoundError):
|
||||
restartcheck.restartcheck()
|
||||
else:
|
||||
ret = restartcheck.restartcheck()
|
||||
self.assertIn(
|
||||
"Found 1 processes using old versions of upgraded files", ret
|
||||
)
|
||||
self.assertFalse(os.path.exists(create_file))
|
||||
|
|
|
@ -1100,6 +1100,34 @@ class _GetProxyConnectionDetailsTestCase(TestCase, LoaderModuleMockMixin):
|
|||
"'unsupported' proxy is not supported", excinfo.exception.strerror
|
||||
)
|
||||
|
||||
def test_vcenter_proxy_details_verify_ssl(self):
|
||||
for verify_ssl in [True, False]:
|
||||
details = self.vcenter_details.copy()
|
||||
details["verify_ssl"] = verify_ssl
|
||||
|
||||
with patch(
|
||||
"salt.modules.vsphere.get_proxy_type", MagicMock(return_value="vcenter")
|
||||
):
|
||||
with patch.dict(
|
||||
vsphere.__salt__,
|
||||
{"vcenter.get_details": MagicMock(return_value=details)},
|
||||
):
|
||||
ret = vsphere._get_proxy_connection_details()
|
||||
self.assertEqual(
|
||||
(
|
||||
"fake_vcenter",
|
||||
"fake_username",
|
||||
"fake_password",
|
||||
"fake_protocol",
|
||||
"fake_port",
|
||||
"fake_mechanism",
|
||||
"fake_principal",
|
||||
"fake_domain",
|
||||
verify_ssl,
|
||||
),
|
||||
ret,
|
||||
)
|
||||
|
||||
|
||||
class GetsServiceInstanceViaProxyTestCase(TestCase, LoaderModuleMockMixin):
|
||||
"""
|
||||
|
@ -2602,52 +2630,70 @@ class TestVSphereTagging(TestCase, LoaderModuleMockMixin):
|
|||
self.assertEqual(ret, {"Category created": None})
|
||||
|
||||
def test_create_tag_category_client(self):
|
||||
get_details = MagicMock(return_value=self.details)
|
||||
for verify_ssl in [True, False, None]:
|
||||
details = self.details.copy()
|
||||
if verify_ssl is None:
|
||||
verify_ssl = True
|
||||
else:
|
||||
details["verify_ssl"] = verify_ssl
|
||||
get_details = MagicMock(return_value=details)
|
||||
|
||||
# Mock CreateSpec object and create objects
|
||||
mock_client = Mock(
|
||||
tagging=Mock(
|
||||
Category=Mock(
|
||||
CreateSpec=Mock(return_value=Mock()),
|
||||
create=Mock(
|
||||
return_value=self.create_tag_category["Category created"]
|
||||
),
|
||||
# Mock CreateSpec object and create objects
|
||||
mock_client = Mock(
|
||||
tagging=Mock(
|
||||
Category=Mock(
|
||||
CreateSpec=Mock(return_value=Mock()),
|
||||
create=Mock(
|
||||
return_value=self.create_tag_category["Category created"]
|
||||
),
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
# Start patching each external API return with Mock Objects
|
||||
with patch.object(
|
||||
vsphere, "get_proxy_type", return_value="vcenter"
|
||||
) as get_proxy_type:
|
||||
# Start patching each external API return with Mock Objects
|
||||
with patch.object(
|
||||
vsphere, "_get_proxy_connection_details", return_value=[]
|
||||
) as get_proxy_connection:
|
||||
vsphere, "get_proxy_type", return_value="vcenter"
|
||||
) as get_proxy_type:
|
||||
with patch.object(
|
||||
salt.utils.vmware, "get_service_instance", return_value=None
|
||||
) as get_service_instance:
|
||||
with patch.dict(
|
||||
vsphere.__salt__,
|
||||
{"vcenter.get_details": get_details},
|
||||
clear=True,
|
||||
) as get_vcenter_details:
|
||||
with patch.object(
|
||||
salt.utils.vmware,
|
||||
"get_vsphere_client",
|
||||
return_value=mock_client,
|
||||
) as get_vsphere_client:
|
||||
ret = vsphere.create_tag_category(
|
||||
self.func_attrs["name"],
|
||||
self.func_attrs["description"],
|
||||
self.func_attrs["cardinality"],
|
||||
)
|
||||
vsphere, "_get_proxy_connection_details", return_value=[]
|
||||
) as get_proxy_connection:
|
||||
with patch.object(
|
||||
salt.utils.vmware, "get_service_instance", return_value=None
|
||||
) as get_service_instance:
|
||||
with patch.dict(
|
||||
vsphere.__salt__,
|
||||
{"vcenter.get_details": get_details},
|
||||
clear=True,
|
||||
) as get_vcenter_details:
|
||||
with patch.object(
|
||||
salt.utils.vmware,
|
||||
"get_vsphere_client",
|
||||
return_value=mock_client,
|
||||
) as get_vsphere_client:
|
||||
ret = vsphere.create_tag_category(
|
||||
self.func_attrs["name"],
|
||||
self.func_attrs["description"],
|
||||
self.func_attrs["cardinality"],
|
||||
)
|
||||
|
||||
# Check function calls and return data
|
||||
get_proxy_type.assert_called_once()
|
||||
get_proxy_connection.assert_called_once()
|
||||
get_service_instance.assert_called_once()
|
||||
get_vsphere_client.assert_called_once()
|
||||
self.assertEqual(ret, self.create_tag_category)
|
||||
# Check function calls and return data
|
||||
get_proxy_type.assert_called_once()
|
||||
get_proxy_connection.assert_called_once()
|
||||
get_service_instance.assert_called_once()
|
||||
get_vsphere_client.assert_called_once()
|
||||
self.assertEqual(ret, self.create_tag_category)
|
||||
self.assertEqual(
|
||||
get_vsphere_client.call_args_list,
|
||||
[
|
||||
call(
|
||||
ca_bundle=None,
|
||||
password=None,
|
||||
server=None,
|
||||
username=None,
|
||||
verify_ssl=verify_ssl,
|
||||
)
|
||||
],
|
||||
)
|
||||
|
||||
def test_create_tag_client_none(self):
|
||||
get_details = MagicMock(return_value=self.details)
|
||||
|
@ -2759,49 +2805,67 @@ class TestVSphereTagging(TestCase, LoaderModuleMockMixin):
|
|||
self.assertEqual(ret, {"Category deleted": None})
|
||||
|
||||
def test_delete_tag_category_client(self):
|
||||
get_details = MagicMock(return_value=self.details)
|
||||
for verify_ssl in [True, False, None]:
|
||||
details = self.details.copy()
|
||||
if verify_ssl is None:
|
||||
verify_ssl = True
|
||||
else:
|
||||
details["verify_ssl"] = verify_ssl
|
||||
get_details = MagicMock(return_value=details)
|
||||
|
||||
# Mock CreateSpec object and create objects
|
||||
mock_client = Mock(
|
||||
tagging=Mock(
|
||||
Category=Mock(
|
||||
delete=Mock(
|
||||
return_value=self.delete_tag_category["Category deleted"]
|
||||
# Mock CreateSpec object and create objects
|
||||
mock_client = Mock(
|
||||
tagging=Mock(
|
||||
Category=Mock(
|
||||
delete=Mock(
|
||||
return_value=self.delete_tag_category["Category deleted"]
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
# Start patching each external API return with Mock Objects
|
||||
with patch.object(
|
||||
vsphere, "get_proxy_type", return_value="vcenter"
|
||||
) as get_proxy_type:
|
||||
# Start patching each external API return with Mock Objects
|
||||
with patch.object(
|
||||
vsphere, "_get_proxy_connection_details", return_value=[]
|
||||
) as get_proxy_connection:
|
||||
vsphere, "get_proxy_type", return_value="vcenter"
|
||||
) as get_proxy_type:
|
||||
with patch.object(
|
||||
salt.utils.vmware, "get_service_instance", return_value=None
|
||||
) as get_service_instance:
|
||||
with patch.dict(
|
||||
vsphere.__salt__,
|
||||
{"vcenter.get_details": get_details},
|
||||
clear=True,
|
||||
) as get_vcenter_details:
|
||||
with patch.object(
|
||||
salt.utils.vmware,
|
||||
"get_vsphere_client",
|
||||
return_value=mock_client,
|
||||
) as get_vsphere_client:
|
||||
ret = vsphere.delete_tag_category(
|
||||
self.func_attrs["category_id"]
|
||||
)
|
||||
vsphere, "_get_proxy_connection_details", return_value=[]
|
||||
) as get_proxy_connection:
|
||||
with patch.object(
|
||||
salt.utils.vmware, "get_service_instance", return_value=None
|
||||
) as get_service_instance:
|
||||
with patch.dict(
|
||||
vsphere.__salt__,
|
||||
{"vcenter.get_details": get_details},
|
||||
clear=True,
|
||||
) as get_vcenter_details:
|
||||
with patch.object(
|
||||
salt.utils.vmware,
|
||||
"get_vsphere_client",
|
||||
return_value=mock_client,
|
||||
) as get_vsphere_client:
|
||||
ret = vsphere.delete_tag_category(
|
||||
self.func_attrs["category_id"]
|
||||
)
|
||||
|
||||
# Check function calls and return data
|
||||
get_proxy_type.assert_called_once()
|
||||
get_proxy_connection.assert_called_once()
|
||||
get_service_instance.assert_called_once()
|
||||
get_vsphere_client.assert_called_once()
|
||||
self.assertEqual(ret, self.delete_tag_category)
|
||||
# Check function calls and return data
|
||||
get_proxy_type.assert_called_once()
|
||||
get_proxy_connection.assert_called_once()
|
||||
get_service_instance.assert_called_once()
|
||||
get_vsphere_client.assert_called_once()
|
||||
self.assertEqual(ret, self.delete_tag_category)
|
||||
self.assertEqual(
|
||||
get_vsphere_client.call_args_list,
|
||||
[
|
||||
call(
|
||||
ca_bundle=None,
|
||||
password=None,
|
||||
server=None,
|
||||
username=None,
|
||||
verify_ssl=verify_ssl,
|
||||
)
|
||||
],
|
||||
)
|
||||
|
||||
def test_delete_tag_client_none(self):
|
||||
get_details = MagicMock(return_value=self.details)
|
||||
|
@ -2901,44 +2965,64 @@ class TestVSphereTagging(TestCase, LoaderModuleMockMixin):
|
|||
self.assertEqual(ret, {"Categories": None})
|
||||
|
||||
def test_list_tag_categories_client(self):
|
||||
get_details = MagicMock(return_value=self.details)
|
||||
for verify_ssl in [True, False, None]:
|
||||
details = self.details.copy()
|
||||
if verify_ssl is not None:
|
||||
details["verify_ssl"] = verify_ssl
|
||||
else:
|
||||
verify_ssl = True
|
||||
get_details = MagicMock(return_value=details)
|
||||
|
||||
# Mock CreateSpec object and create objects
|
||||
mock_client = Mock(
|
||||
tagging=Mock(
|
||||
Category=Mock(list=Mock(return_value=self.list_tag_categories_return))
|
||||
# Mock CreateSpec object and create objects
|
||||
mock_client = Mock(
|
||||
tagging=Mock(
|
||||
Category=Mock(
|
||||
list=Mock(return_value=self.list_tag_categories_return)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
# Start patching each external API return with Mock Objects
|
||||
with patch.object(
|
||||
vsphere, "get_proxy_type", return_value="vcenter"
|
||||
) as get_proxy_type:
|
||||
# Start patching each external API return with Mock Objects
|
||||
with patch.object(
|
||||
vsphere, "_get_proxy_connection_details", return_value=[]
|
||||
) as get_proxy_connection:
|
||||
vsphere, "get_proxy_type", return_value="vcenter"
|
||||
) as get_proxy_type:
|
||||
with patch.object(
|
||||
salt.utils.vmware, "get_service_instance", return_value=None
|
||||
) as get_service_instance:
|
||||
with patch.dict(
|
||||
vsphere.__salt__,
|
||||
{"vcenter.get_details": get_details},
|
||||
clear=True,
|
||||
) as get_vcenter_details:
|
||||
with patch.object(
|
||||
salt.utils.vmware,
|
||||
"get_vsphere_client",
|
||||
return_value=mock_client,
|
||||
) as get_vsphere_client:
|
||||
ret = vsphere.list_tag_categories()
|
||||
vsphere, "_get_proxy_connection_details", return_value=[]
|
||||
) as get_proxy_connection:
|
||||
with patch.object(
|
||||
salt.utils.vmware, "get_service_instance", return_value=None
|
||||
) as get_service_instance:
|
||||
with patch.dict(
|
||||
vsphere.__salt__,
|
||||
{"vcenter.get_details": get_details},
|
||||
clear=True,
|
||||
) as get_vcenter_details:
|
||||
with patch.object(
|
||||
salt.utils.vmware,
|
||||
"get_vsphere_client",
|
||||
return_value=mock_client,
|
||||
) as get_vsphere_client:
|
||||
ret = vsphere.list_tag_categories()
|
||||
|
||||
get_proxy_type.assert_called_once()
|
||||
get_proxy_connection.assert_called_once()
|
||||
get_service_instance.assert_called_once()
|
||||
get_vsphere_client.assert_called_once()
|
||||
self.assertEqual(
|
||||
ret, {"Categories": self.list_tag_categories_return}
|
||||
)
|
||||
get_proxy_type.assert_called_once()
|
||||
get_proxy_connection.assert_called_once()
|
||||
get_service_instance.assert_called_once()
|
||||
get_vsphere_client.assert_called_once()
|
||||
self.assertEqual(
|
||||
get_vsphere_client.call_args_list,
|
||||
[
|
||||
call(
|
||||
ca_bundle=None,
|
||||
password=None,
|
||||
server=None,
|
||||
username=None,
|
||||
verify_ssl=verify_ssl,
|
||||
)
|
||||
],
|
||||
)
|
||||
self.assertEqual(
|
||||
ret, {"Categories": self.list_tag_categories_return}
|
||||
)
|
||||
|
||||
def test_list_tags_client_none(self):
|
||||
get_details = MagicMock(return_value=self.details)
|
||||
|
@ -3005,6 +3089,56 @@ class TestVSphereTagging(TestCase, LoaderModuleMockMixin):
|
|||
get_vsphere_client.assert_called_once()
|
||||
self.assertEqual(ret, {"Tags": self.list_tags_return})
|
||||
|
||||
def test_list_tags_client_verify_ssl(self):
|
||||
for verify_ssl in [True, False]:
|
||||
details = self.details.copy()
|
||||
if verify_ssl is not None:
|
||||
details["verify_ssl"] = verify_ssl
|
||||
else:
|
||||
verify_ssl = True
|
||||
get_details = MagicMock(return_value=details)
|
||||
|
||||
# Mock CreateSpec object and create objects
|
||||
mock_client = Mock(
|
||||
tagging=Mock(Tag=Mock(list=Mock(return_value=self.list_tags_return)))
|
||||
)
|
||||
|
||||
# Start patching each external API return with Mock Objects
|
||||
with patch.object(
|
||||
vsphere, "get_proxy_type", return_value="vcenter"
|
||||
) as get_proxy_type:
|
||||
with patch.object(
|
||||
vsphere, "_get_proxy_connection_details", return_value=[]
|
||||
) as get_proxy_connection:
|
||||
with patch.object(
|
||||
salt.utils.vmware, "get_service_instance", return_value=None
|
||||
) as get_service_instance:
|
||||
with patch.dict(
|
||||
vsphere.__salt__,
|
||||
{"vcenter.get_details": get_details},
|
||||
clear=True,
|
||||
) as get_vcenter_details:
|
||||
with patch.object(
|
||||
salt.utils.vmware,
|
||||
"get_vsphere_client",
|
||||
return_value=mock_client,
|
||||
) as get_vsphere_client:
|
||||
# Check function calls and return
|
||||
ret = vsphere.list_tags()
|
||||
self.assertEqual(ret, {"Tags": self.list_tags_return})
|
||||
self.assertEqual(
|
||||
get_vsphere_client.call_args_list,
|
||||
[
|
||||
call(
|
||||
ca_bundle=None,
|
||||
password=None,
|
||||
server=None,
|
||||
username=None,
|
||||
verify_ssl=verify_ssl,
|
||||
)
|
||||
],
|
||||
)
|
||||
|
||||
def test_list_attached_tags_client_none(self):
|
||||
get_details = MagicMock(return_value=self.details)
|
||||
|
||||
|
@ -3036,50 +3170,72 @@ class TestVSphereTagging(TestCase, LoaderModuleMockMixin):
|
|||
self.assertEqual(ret, {"Attached tags": None})
|
||||
|
||||
def test_list_attached_tags_client(self):
|
||||
get_details = MagicMock(return_value=self.details)
|
||||
for verify_ssl in [True, False, None]:
|
||||
details = self.details.copy()
|
||||
if verify_ssl is None:
|
||||
verify_ssl = True
|
||||
else:
|
||||
details["verify_ssl"] = verify_ssl
|
||||
get_details = MagicMock(return_value=details)
|
||||
|
||||
# Mock CreateSpec object and create objects
|
||||
mock_client = Mock(
|
||||
tagging=Mock(
|
||||
TagAssociation=Mock(
|
||||
list_attached_tags=Mock(return_value=self.list_attached_tags_return)
|
||||
# Mock CreateSpec object and create objects
|
||||
mock_client = Mock(
|
||||
tagging=Mock(
|
||||
TagAssociation=Mock(
|
||||
list_attached_tags=Mock(
|
||||
return_value=self.list_attached_tags_return
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
# Start patching each external API return with Mock Objects
|
||||
with patch.object(
|
||||
vsphere, "get_proxy_type", return_value="vcenter"
|
||||
) as get_proxy_type:
|
||||
# Start patching each external API return with Mock Objects
|
||||
with patch.object(
|
||||
vsphere, "_get_proxy_connection_details", return_value=[]
|
||||
) as get_proxy_connection:
|
||||
vsphere, "get_proxy_type", return_value="vcenter"
|
||||
) as get_proxy_type:
|
||||
with patch.object(
|
||||
salt.utils.vmware, "get_service_instance", return_value=None
|
||||
) as get_service_instance:
|
||||
with patch.dict(
|
||||
vsphere.__salt__,
|
||||
{"vcenter.get_details": get_details},
|
||||
clear=True,
|
||||
) as get_vcenter_details:
|
||||
with patch.object(
|
||||
salt.utils.vmware,
|
||||
"get_vsphere_client",
|
||||
return_value=mock_client,
|
||||
) as get_vsphere_client:
|
||||
with patch.object(vsphere, "DynamicID") as dynamic_id:
|
||||
# Check function calls and return
|
||||
ret = vsphere.list_attached_tags(
|
||||
self.func_attrs["object_id"]
|
||||
)
|
||||
get_proxy_type.assert_called_once()
|
||||
get_proxy_connection.assert_called_once()
|
||||
get_service_instance.assert_called_once()
|
||||
get_vsphere_client.assert_called_once()
|
||||
self.assertEqual(
|
||||
ret,
|
||||
{"Attached tags": self.list_attached_tags_return},
|
||||
)
|
||||
vsphere, "_get_proxy_connection_details", return_value=[]
|
||||
) as get_proxy_connection:
|
||||
with patch.object(
|
||||
salt.utils.vmware, "get_service_instance", return_value=None
|
||||
) as get_service_instance:
|
||||
with patch.dict(
|
||||
vsphere.__salt__,
|
||||
{"vcenter.get_details": get_details},
|
||||
clear=True,
|
||||
) as get_vcenter_details:
|
||||
with patch.object(
|
||||
salt.utils.vmware,
|
||||
"get_vsphere_client",
|
||||
return_value=mock_client,
|
||||
) as get_vsphere_client:
|
||||
with patch.object(vsphere, "DynamicID") as dynamic_id:
|
||||
# Check function calls and return
|
||||
ret = vsphere.list_attached_tags(
|
||||
self.func_attrs["object_id"]
|
||||
)
|
||||
get_proxy_type.assert_called_once()
|
||||
get_proxy_connection.assert_called_once()
|
||||
get_service_instance.assert_called_once()
|
||||
get_vsphere_client.assert_called_once()
|
||||
self.assertEqual(
|
||||
ret,
|
||||
{
|
||||
"Attached tags": self.list_attached_tags_return
|
||||
},
|
||||
)
|
||||
self.assertEqual(
|
||||
get_vsphere_client.call_args_list,
|
||||
[
|
||||
call(
|
||||
ca_bundle=None,
|
||||
password=None,
|
||||
server=None,
|
||||
username=None,
|
||||
verify_ssl=verify_ssl,
|
||||
)
|
||||
],
|
||||
)
|
||||
|
||||
def test_attach_tags_client_none(self):
|
||||
get_details = MagicMock(return_value=self.details)
|
||||
|
@ -3114,48 +3270,266 @@ class TestVSphereTagging(TestCase, LoaderModuleMockMixin):
|
|||
self.assertEqual(ret, {"Tag attached": None})
|
||||
|
||||
def test_attach_tags_client(self):
|
||||
get_details = MagicMock(return_value=self.details)
|
||||
for verify_ssl in [True, False, None]:
|
||||
details = self.details.copy()
|
||||
if verify_ssl is None:
|
||||
verify_ssl = True
|
||||
else:
|
||||
details["verify_ssl"] = verify_ssl
|
||||
get_details = MagicMock(return_value=details)
|
||||
|
||||
# Mock CreateSpec object and create objects
|
||||
mock_client = Mock(
|
||||
tagging=Mock(
|
||||
TagAssociation=Mock(
|
||||
attach=Mock(return_value=self.list_attached_tags_return)
|
||||
# Mock CreateSpec object and create objects
|
||||
mock_client = Mock(
|
||||
tagging=Mock(
|
||||
TagAssociation=Mock(
|
||||
attach=Mock(return_value=self.list_attached_tags_return)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
# Start patching each external API return with Mock Objects
|
||||
with patch.object(
|
||||
vsphere, "get_proxy_type", return_value="vcenter"
|
||||
) as get_proxy_type:
|
||||
with patch.object(
|
||||
vsphere, "_get_proxy_connection_details", return_value=[]
|
||||
) as get_proxy_connection:
|
||||
with patch.object(
|
||||
salt.utils.vmware, "get_service_instance", return_value=None
|
||||
) as get_service_instance:
|
||||
with patch.dict(
|
||||
vsphere.__salt__,
|
||||
{"vcenter.get_details": get_details},
|
||||
clear=True,
|
||||
) as get_vcenter_details:
|
||||
with patch.object(
|
||||
salt.utils.vmware,
|
||||
"get_vsphere_client",
|
||||
return_value=mock_client,
|
||||
) as get_vsphere_client:
|
||||
with patch.object(vsphere, "DynamicID") as dynamic_id:
|
||||
# Check function calls and return
|
||||
ret = vsphere.attach_tag(
|
||||
object_id=self.func_attrs["object_id"],
|
||||
tag_id=self.func_attrs["tag_id"],
|
||||
)
|
||||
get_proxy_type.assert_called_once()
|
||||
get_proxy_connection.assert_called_once()
|
||||
get_service_instance.assert_called_once()
|
||||
get_vsphere_client.assert_called_once()
|
||||
self.assertEqual(
|
||||
get_vsphere_client.call_args_list,
|
||||
[
|
||||
call(
|
||||
ca_bundle=None,
|
||||
password=None,
|
||||
server=None,
|
||||
username=None,
|
||||
verify_ssl=verify_ssl,
|
||||
)
|
||||
],
|
||||
)
|
||||
self.assertEqual(
|
||||
ret,
|
||||
{
|
||||
"Tag attached": self.list_attached_tags_return
|
||||
},
|
||||
)
|
||||
|
||||
def test_get_client(self):
|
||||
"""
|
||||
test get_client when verify_ssl and ca_bundle are not passed
|
||||
"""
|
||||
mock_client = MagicMock(return_value=None)
|
||||
patch_client = patch("salt.utils.vmware.get_vsphere_client", mock_client)
|
||||
|
||||
cert_path = "/test/ca-certificates.crt"
|
||||
mock_ca = MagicMock(return_value=cert_path)
|
||||
patch_ca = patch("salt.utils.http.get_ca_bundle", mock_ca)
|
||||
|
||||
mock_details = MagicMock(return_value=self.details)
|
||||
patch_details = patch.dict(
|
||||
vsphere.__salt__, {"vcenter.get_details": mock_details}
|
||||
)
|
||||
|
||||
# Start patching each external API return with Mock Objects
|
||||
with patch.object(
|
||||
vsphere, "get_proxy_type", return_value="vcenter"
|
||||
) as get_proxy_type:
|
||||
with patch.object(
|
||||
vsphere, "_get_proxy_connection_details", return_value=[]
|
||||
) as get_proxy_connection:
|
||||
with patch.object(
|
||||
salt.utils.vmware, "get_service_instance", return_value=None
|
||||
) as get_service_instance:
|
||||
with patch.dict(
|
||||
vsphere.__salt__,
|
||||
{"vcenter.get_details": get_details},
|
||||
clear=True,
|
||||
) as get_vcenter_details:
|
||||
with patch.object(
|
||||
salt.utils.vmware,
|
||||
"get_vsphere_client",
|
||||
return_value=mock_client,
|
||||
) as get_vsphere_client:
|
||||
with patch.object(vsphere, "DynamicID") as dynamic_id:
|
||||
# Check function calls and return
|
||||
ret = vsphere.attach_tag(
|
||||
object_id=self.func_attrs["object_id"],
|
||||
tag_id=self.func_attrs["tag_id"],
|
||||
)
|
||||
get_proxy_type.assert_called_once()
|
||||
get_proxy_connection.assert_called_once()
|
||||
get_service_instance.assert_called_once()
|
||||
get_vsphere_client.assert_called_once()
|
||||
self.assertEqual(
|
||||
ret,
|
||||
{"Tag attached": self.list_attached_tags_return},
|
||||
)
|
||||
with patch_client, patch_ca, patch_details:
|
||||
vsphere._get_client(
|
||||
server="localhost", username="testuser", password="testpassword"
|
||||
)
|
||||
self.assertEqual(
|
||||
mock_client.call_args_list,
|
||||
[
|
||||
call(
|
||||
ca_bundle=None,
|
||||
password="testpassword",
|
||||
server="localhost",
|
||||
username="testuser",
|
||||
verify_ssl=True,
|
||||
)
|
||||
],
|
||||
)
|
||||
self.assertEqual(mock_details.assert_called_once(), None)
|
||||
self.assertEqual(mock_ca.assert_not_called(), None)
|
||||
|
||||
def test_get_client_verify_ssl_false(self):
|
||||
"""
|
||||
test get_client when verify_ssl=False is set
|
||||
"""
|
||||
details = self.details.copy()
|
||||
details["verify_ssl"] = False
|
||||
mock_client = MagicMock(return_value=None)
|
||||
patch_client = patch("salt.utils.vmware.get_vsphere_client", mock_client)
|
||||
|
||||
cert_path = "/test/ca-certificates.crt"
|
||||
mock_ca = MagicMock(return_value=cert_path)
|
||||
patch_ca = patch("salt.utils.http.get_ca_bundle", mock_ca)
|
||||
|
||||
mock_details = MagicMock(return_value=details)
|
||||
patch_details = patch.dict(
|
||||
vsphere.__salt__, {"vcenter.get_details": mock_details}
|
||||
)
|
||||
|
||||
with patch_client, patch_ca, patch_details:
|
||||
vsphere._get_client(
|
||||
server="localhost", username="testuser", password="testpassword"
|
||||
)
|
||||
self.assertEqual(
|
||||
mock_client.call_args_list,
|
||||
[
|
||||
call(
|
||||
ca_bundle=None,
|
||||
password="testpassword",
|
||||
server="localhost",
|
||||
username="testuser",
|
||||
verify_ssl=False,
|
||||
)
|
||||
],
|
||||
)
|
||||
self.assertEqual(mock_details.assert_called_once(), None)
|
||||
self.assertEqual(mock_ca.assert_not_called(), None)
|
||||
|
||||
def test_get_client_verify_ssl_false_ca_bundle(self):
|
||||
"""
|
||||
test get_client when verify_ssl=False and ca_bundle set
|
||||
"""
|
||||
details = self.details.copy()
|
||||
details["verify_ssl"] = False
|
||||
details["ca_bundle"] = "/tmp/test"
|
||||
mock_client = MagicMock(return_value=None)
|
||||
patch_client = patch("salt.utils.vmware.get_vsphere_client", mock_client)
|
||||
|
||||
cert_path = "/test/ca-certificates.crt"
|
||||
mock_ca = MagicMock(return_value=cert_path)
|
||||
patch_ca = patch("salt.utils.http.get_ca_bundle", mock_ca)
|
||||
|
||||
mock_details = MagicMock(return_value=details)
|
||||
patch_details = patch.dict(
|
||||
vsphere.__salt__, {"vcenter.get_details": mock_details}
|
||||
)
|
||||
|
||||
with patch_client, patch_ca, patch_details:
|
||||
self.assertFalse(
|
||||
vsphere._get_client(
|
||||
server="localhost", username="testuser", password="testpassword"
|
||||
)
|
||||
)
|
||||
self.assertEqual(mock_details.assert_called_once(), None)
|
||||
self.assertEqual(mock_ca.assert_not_called(), None)
|
||||
|
||||
def test_get_client_ca_bundle(self):
|
||||
"""
|
||||
test get_client when verify_ssl=False and ca_bundle set
|
||||
"""
|
||||
cert_path = "/test/ca-certificates.crt"
|
||||
details = self.details.copy()
|
||||
details["ca_bundle"] = cert_path
|
||||
mock_client = MagicMock(return_value=None)
|
||||
patch_client = patch("salt.utils.vmware.get_vsphere_client", mock_client)
|
||||
|
||||
mock_ca = MagicMock(return_value=cert_path)
|
||||
patch_ca = patch("salt.utils.http.get_ca_bundle", mock_ca)
|
||||
|
||||
mock_details = MagicMock(return_value=details)
|
||||
patch_details = patch.dict(
|
||||
vsphere.__salt__, {"vcenter.get_details": mock_details}
|
||||
)
|
||||
|
||||
with patch_client, patch_ca, patch_details:
|
||||
vsphere._get_client(
|
||||
server="localhost", username="testuser", password="testpassword"
|
||||
)
|
||||
self.assertEqual(
|
||||
mock_client.call_args_list,
|
||||
[
|
||||
call(
|
||||
ca_bundle=cert_path,
|
||||
password="testpassword",
|
||||
server="localhost",
|
||||
username="testuser",
|
||||
verify_ssl=True,
|
||||
)
|
||||
],
|
||||
)
|
||||
self.assertEqual(mock_details.assert_called_once(), None)
|
||||
self.assertEqual(mock_ca.assert_called_once(), None)
|
||||
self.assertEqual(mock_ca.call_args_list, [call({"ca_bundle": cert_path})])
|
||||
|
||||
|
||||
class TestCertificateVerify(TestCase, LoaderModuleMockMixin):
|
||||
def setup_loader_modules(self):
|
||||
return {vsphere: {}}
|
||||
|
||||
def test_upload_ssh_key(self):
|
||||
kwargs_values = [
|
||||
("ssh_key", "TheSSHKeyFile"),
|
||||
("ssh_key_file", "TheSSHKeyFile"),
|
||||
]
|
||||
certificate_verify_values = (None, True, False)
|
||||
for kw_key, kw_value in kwargs_values:
|
||||
kwargs = {kw_key: kw_value}
|
||||
if kw_key == "ssh_key":
|
||||
expected_kwargs = {"data": kw_value}
|
||||
else:
|
||||
expected_kwargs = {"data_file": kw_value, "data_render": False}
|
||||
for certificate_verify_value in certificate_verify_values:
|
||||
http_query_mock = MagicMock()
|
||||
if certificate_verify_value is None:
|
||||
certificate_verify_value = True
|
||||
with patch("salt.utils.http.query", http_query_mock):
|
||||
vsphere.upload_ssh_key(
|
||||
HOST,
|
||||
USER,
|
||||
PASSWORD,
|
||||
certificate_verify=certificate_verify_value,
|
||||
**kwargs
|
||||
)
|
||||
http_query_mock.assert_called_once_with(
|
||||
"https://1.2.3.4:443/host/ssh_root_authorized_keys",
|
||||
method="PUT",
|
||||
password="SuperSecret!",
|
||||
status=True,
|
||||
text=True,
|
||||
username="root",
|
||||
verify_ssl=certificate_verify_value,
|
||||
**expected_kwargs
|
||||
)
|
||||
|
||||
def test_get_ssh_key(self):
|
||||
certificate_verify_values = (None, True, False)
|
||||
for certificate_verify_value in certificate_verify_values:
|
||||
http_query_mock = MagicMock()
|
||||
if certificate_verify_value is None:
|
||||
certificate_verify_value = True
|
||||
with patch("salt.utils.http.query", http_query_mock):
|
||||
vsphere.get_ssh_key(
|
||||
HOST, USER, PASSWORD, certificate_verify=certificate_verify_value
|
||||
)
|
||||
http_query_mock.assert_called_once_with(
|
||||
"https://1.2.3.4:443/host/ssh_root_authorized_keys",
|
||||
method="GET",
|
||||
password="SuperSecret!",
|
||||
status=True,
|
||||
text=True,
|
||||
username="root",
|
||||
verify_ssl=certificate_verify_value,
|
||||
)
|
||||
|
|
54
tests/unit/modules/test_zenoss.py
Normal file
54
tests/unit/modules/test_zenoss.py
Normal 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,
|
||||
)
|
||||
],
|
||||
)
|
|
@ -1,20 +1,114 @@
|
|||
"""
|
||||
tests.unit.proxy.test_cimc
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Unit tests for the cimc proxy module
|
||||
"""
|
||||
|
||||
import logging
|
||||
|
||||
import salt.exceptions
|
||||
import salt.proxy.cimc as cimc
|
||||
from tests.support.mixins import LoaderModuleMockMixin
|
||||
from tests.support.mock import patch
|
||||
from tests.support.mock import MagicMock, patch
|
||||
from tests.support.unit import TestCase
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
LOGIN_RESPONSE = """\
|
||||
<aaaLogin
|
||||
response="yes"
|
||||
outCookie="real-cookie"
|
||||
outRefreshPeriod="600"
|
||||
outPriv="admin">
|
||||
</aaaLogin>"""
|
||||
LOGOUT_RESPONSE = """\
|
||||
<aaaLogout
|
||||
cookie="real-cookie"
|
||||
response="yes"
|
||||
outStatus="success">
|
||||
</aaaLogout>
|
||||
"""
|
||||
CONFIG_RESOLVE_CLASS_RESPONSE = """\
|
||||
<configResolveClass
|
||||
cookie="real-cookie"
|
||||
response="yes"
|
||||
classId="computeRackUnit">
|
||||
<outConfig>
|
||||
<computeRackUnit
|
||||
dn="sys/rack-unit-1"
|
||||
adminPower="policy"
|
||||
availableMemory="16384"
|
||||
model="R210-2121605W"
|
||||
memorySpeed="1067"
|
||||
name="UCS C210 M2"
|
||||
numOfAdaptors="2"
|
||||
numOfCores="8"
|
||||
numOfCoresEnabled="8"
|
||||
numOfCpus="2"
|
||||
numOfEthHostIfs="5"
|
||||
numOfFcHostIfs="2"
|
||||
numOfThreads="16"
|
||||
operPower="on"
|
||||
originalUuid="00C9DE3C-370D-DF11-1186-6DD1393A608B"
|
||||
presence="equipped"
|
||||
serverID="1"
|
||||
serial="QCI140205Z2"
|
||||
totalMemory="16384"
|
||||
usrLbl="C210 Row-B Rack-10"
|
||||
uuid="00C9DE3C-370D-DF11-1186-6DD1393A608B"
|
||||
vendor="Cisco Systems Inc" >
|
||||
</computeRackUnit>
|
||||
</outConfig>
|
||||
</configResolveClass>
|
||||
"""
|
||||
CONFIG_CON_MO_RESPONSE = """\
|
||||
<configConfMo
|
||||
dn="sys/rack-unit-1/locator-led"
|
||||
cookie="real-cookie"
|
||||
response="yes">
|
||||
<outConfig>
|
||||
<equipmentLocatorLed
|
||||
dn="sys/rack-unit-1/locator-led"
|
||||
adminState="inactive"
|
||||
color="unknown"
|
||||
id="1"
|
||||
name=""
|
||||
operState="off">
|
||||
</equipmentLocatorLed>
|
||||
</outConfig>
|
||||
</configConfMo>
|
||||
"""
|
||||
|
||||
|
||||
def http_query_response(*args, data=None, **kwargs):
|
||||
log.debug(
|
||||
"http_query_response side_effect; ARGS: %s // KWARGS: %s // DATA: %s",
|
||||
args,
|
||||
kwargs,
|
||||
data,
|
||||
)
|
||||
if data.startswith("<aaaLogin"):
|
||||
response = LOGIN_RESPONSE
|
||||
elif data.startswith("<aaaLogout"):
|
||||
response = LOGOUT_RESPONSE
|
||||
elif data.startswith("<configResolveClass"):
|
||||
response = CONFIG_RESOLVE_CLASS_RESPONSE
|
||||
elif data.startswith("<configConfMo"):
|
||||
response = CONFIG_CON_MO_RESPONSE
|
||||
else:
|
||||
response = ""
|
||||
return {"text": response, "status": 200}
|
||||
|
||||
|
||||
class CIMCProxyTestCase(TestCase, LoaderModuleMockMixin):
|
||||
def setup_loader_modules(self):
|
||||
return {cimc: {"DETAILS": {}, "__pillar__": {}}}
|
||||
|
||||
def setUp(self):
|
||||
self.opts = {"proxy": {"username": "xxxx", "password": "xxx", "host": "cimc"}}
|
||||
self.addCleanup(delattr, self, "opts")
|
||||
|
||||
def test_init(self):
|
||||
# No host, returns False
|
||||
|
@ -56,3 +150,294 @@ class CIMCProxyTestCase(TestCase, LoaderModuleMockMixin):
|
|||
):
|
||||
cimc._validate_response_code("404", "9zVG5U8DFZNsTR")
|
||||
mock_logout.assert_called_once_with("9zVG5U8DFZNsTR")
|
||||
|
||||
|
||||
class ValidateSSLTestCase(TestCase, LoaderModuleMockMixin):
|
||||
def setup_loader_modules(self):
|
||||
return {cimc: {}}
|
||||
|
||||
def setUp(self):
|
||||
cimc.DETAILS.clear()
|
||||
|
||||
def test_init(self):
|
||||
verify_ssl_values = (None, True, False)
|
||||
for verify_ssl_value in verify_ssl_values:
|
||||
cimc.DETAILS.clear()
|
||||
opts = {
|
||||
"proxy": {
|
||||
"host": "TheHost",
|
||||
"username": "TheUsername",
|
||||
"password": "ThePassword",
|
||||
"verify_ssl": verify_ssl_value,
|
||||
}
|
||||
}
|
||||
http_query_mock = MagicMock(side_effect=http_query_response)
|
||||
if verify_ssl_value is None:
|
||||
expected_verify_ssl_value = True
|
||||
else:
|
||||
expected_verify_ssl_value = verify_ssl_value
|
||||
|
||||
log.debug(
|
||||
"verify_ssl: %s // expected verify_ssl: %s",
|
||||
verify_ssl_value,
|
||||
expected_verify_ssl_value,
|
||||
)
|
||||
|
||||
with patch.dict(cimc.__utils__, {"http.query": http_query_mock}):
|
||||
cimc.init(opts)
|
||||
|
||||
for idx, call in enumerate(http_query_mock.mock_calls, 1):
|
||||
condition = call.kwargs["verify_ssl"] is expected_verify_ssl_value
|
||||
condition_error = "{} != {}; Call(number={}): {}".format(
|
||||
idx, call, call.kwargs["verify_ssl"], expected_verify_ssl_value
|
||||
)
|
||||
self.assertTrue(condition, msg=condition_error)
|
||||
|
||||
def test_logon(self):
|
||||
verify_ssl_values = (None, True, False)
|
||||
for verify_ssl_value in verify_ssl_values:
|
||||
cimc.DETAILS.clear()
|
||||
opts = {
|
||||
"proxy": {
|
||||
"host": "TheHost",
|
||||
"username": "TheUsername",
|
||||
"password": "ThePassword",
|
||||
"verify_ssl": verify_ssl_value,
|
||||
}
|
||||
}
|
||||
http_query_mock = MagicMock(side_effect=http_query_response)
|
||||
if verify_ssl_value is None:
|
||||
expected_verify_ssl_value = True
|
||||
else:
|
||||
expected_verify_ssl_value = verify_ssl_value
|
||||
|
||||
# Let's init the proxy and ignore it's actions, this test is not about them
|
||||
with patch(
|
||||
"salt.proxy.cimc.get_config_resolver_class",
|
||||
MagicMock(return_value=True),
|
||||
):
|
||||
cimc.init(opts)
|
||||
|
||||
log.debug(
|
||||
"verify_ssl: %s // expected verify_ssl: %s",
|
||||
verify_ssl_value,
|
||||
expected_verify_ssl_value,
|
||||
)
|
||||
|
||||
with patch.dict(cimc.__utils__, {"http.query": http_query_mock}):
|
||||
cimc.logon()
|
||||
|
||||
for idx, call in enumerate(http_query_mock.mock_calls, 1):
|
||||
condition = call.kwargs["verify_ssl"] is expected_verify_ssl_value
|
||||
condition_error = "{} != {}; Call(number={}): {}".format(
|
||||
idx, call, call.kwargs["verify_ssl"], expected_verify_ssl_value
|
||||
)
|
||||
self.assertTrue(condition, msg=condition_error)
|
||||
|
||||
def test_logout(self):
|
||||
verify_ssl_values = (None, True, False)
|
||||
for verify_ssl_value in verify_ssl_values:
|
||||
cimc.DETAILS.clear()
|
||||
opts = {
|
||||
"proxy": {
|
||||
"host": "TheHost",
|
||||
"username": "TheUsername",
|
||||
"password": "ThePassword",
|
||||
"verify_ssl": verify_ssl_value,
|
||||
}
|
||||
}
|
||||
http_query_mock = MagicMock(side_effect=http_query_response)
|
||||
if verify_ssl_value is None:
|
||||
expected_verify_ssl_value = True
|
||||
else:
|
||||
expected_verify_ssl_value = verify_ssl_value
|
||||
|
||||
# Let's init the proxy and ignore it's actions, this test is not about them
|
||||
with patch(
|
||||
"salt.proxy.cimc.get_config_resolver_class",
|
||||
MagicMock(return_value=True),
|
||||
):
|
||||
cimc.init(opts)
|
||||
|
||||
log.debug(
|
||||
"verify_ssl: %s // expected verify_ssl: %s",
|
||||
verify_ssl_value,
|
||||
expected_verify_ssl_value,
|
||||
)
|
||||
|
||||
with patch.dict(cimc.__utils__, {"http.query": http_query_mock}):
|
||||
cimc.logout()
|
||||
|
||||
for idx, call in enumerate(http_query_mock.mock_calls, 1):
|
||||
condition = call.kwargs["verify_ssl"] is expected_verify_ssl_value
|
||||
condition_error = "{} != {}; Call(number={}): {}".format(
|
||||
idx, call, call.kwargs["verify_ssl"], expected_verify_ssl_value
|
||||
)
|
||||
self.assertTrue(condition, msg=condition_error)
|
||||
|
||||
def test_grains(self):
|
||||
verify_ssl_values = (None, True, False)
|
||||
for verify_ssl_value in verify_ssl_values:
|
||||
cimc.DETAILS.clear()
|
||||
opts = {
|
||||
"proxy": {
|
||||
"host": "TheHost",
|
||||
"username": "TheUsername",
|
||||
"password": "ThePassword",
|
||||
"verify_ssl": verify_ssl_value,
|
||||
}
|
||||
}
|
||||
http_query_mock = MagicMock(side_effect=http_query_response)
|
||||
if verify_ssl_value is None:
|
||||
expected_verify_ssl_value = True
|
||||
else:
|
||||
expected_verify_ssl_value = verify_ssl_value
|
||||
|
||||
# Let's init the proxy and ignore it's actions, this test is not about them
|
||||
with patch(
|
||||
"salt.proxy.cimc.get_config_resolver_class",
|
||||
MagicMock(return_value=True),
|
||||
):
|
||||
cimc.init(opts)
|
||||
|
||||
log.debug(
|
||||
"verify_ssl: %s // expected verify_ssl: %s",
|
||||
verify_ssl_value,
|
||||
expected_verify_ssl_value,
|
||||
)
|
||||
|
||||
with patch.dict(cimc.__utils__, {"http.query": http_query_mock}):
|
||||
cimc.grains()
|
||||
|
||||
for idx, call in enumerate(http_query_mock.mock_calls, 1):
|
||||
condition = call.kwargs["verify_ssl"] is expected_verify_ssl_value
|
||||
condition_error = "{} != {}; Call(number={}): {}".format(
|
||||
idx, call, call.kwargs["verify_ssl"], expected_verify_ssl_value
|
||||
)
|
||||
self.assertTrue(condition, msg=condition_error)
|
||||
|
||||
def test_grains_refresh(self):
|
||||
verify_ssl_values = (None, True, False)
|
||||
for verify_ssl_value in verify_ssl_values:
|
||||
cimc.DETAILS.clear()
|
||||
opts = {
|
||||
"proxy": {
|
||||
"host": "TheHost",
|
||||
"username": "TheUsername",
|
||||
"password": "ThePassword",
|
||||
"verify_ssl": verify_ssl_value,
|
||||
}
|
||||
}
|
||||
http_query_mock = MagicMock(side_effect=http_query_response)
|
||||
if verify_ssl_value is None:
|
||||
expected_verify_ssl_value = True
|
||||
else:
|
||||
expected_verify_ssl_value = verify_ssl_value
|
||||
|
||||
# Let's init the proxy and ignore it's actions, this test is not about them
|
||||
with patch(
|
||||
"salt.proxy.cimc.get_config_resolver_class",
|
||||
MagicMock(return_value=True),
|
||||
):
|
||||
cimc.init(opts)
|
||||
|
||||
log.debug(
|
||||
"verify_ssl: %s // expected verify_ssl: %s",
|
||||
verify_ssl_value,
|
||||
expected_verify_ssl_value,
|
||||
)
|
||||
|
||||
with patch.dict(cimc.__utils__, {"http.query": http_query_mock}):
|
||||
cimc.grains_refresh()
|
||||
|
||||
for idx, call in enumerate(http_query_mock.mock_calls, 1):
|
||||
condition = call.kwargs["verify_ssl"] is expected_verify_ssl_value
|
||||
condition_error = "{} != {}; Call(number={}): {}".format(
|
||||
idx, call, call.kwargs["verify_ssl"], expected_verify_ssl_value
|
||||
)
|
||||
self.assertTrue(condition, msg=condition_error)
|
||||
|
||||
def test_ping(self):
|
||||
verify_ssl_values = (None, True, False)
|
||||
for verify_ssl_value in verify_ssl_values:
|
||||
cimc.DETAILS.clear()
|
||||
opts = {
|
||||
"proxy": {
|
||||
"host": "TheHost",
|
||||
"username": "TheUsername",
|
||||
"password": "ThePassword",
|
||||
"verify_ssl": verify_ssl_value,
|
||||
}
|
||||
}
|
||||
http_query_mock = MagicMock(side_effect=http_query_response)
|
||||
if verify_ssl_value is None:
|
||||
expected_verify_ssl_value = True
|
||||
else:
|
||||
expected_verify_ssl_value = verify_ssl_value
|
||||
|
||||
# Let's init the proxy and ignore it's actions, this test is not about them
|
||||
with patch(
|
||||
"salt.proxy.cimc.get_config_resolver_class",
|
||||
MagicMock(return_value=True),
|
||||
):
|
||||
cimc.init(opts)
|
||||
|
||||
log.debug(
|
||||
"verify_ssl: %s // expected verify_ssl: %s",
|
||||
verify_ssl_value,
|
||||
expected_verify_ssl_value,
|
||||
)
|
||||
|
||||
with patch.dict(cimc.__utils__, {"http.query": http_query_mock}):
|
||||
cimc.ping()
|
||||
|
||||
for idx, call in enumerate(http_query_mock.mock_calls, 1):
|
||||
condition = call.kwargs["verify_ssl"] is expected_verify_ssl_value
|
||||
condition_error = "{} != {}; Call(number={}): {}".format(
|
||||
idx, call, call.kwargs["verify_ssl"], expected_verify_ssl_value
|
||||
)
|
||||
self.assertTrue(condition, msg=condition_error)
|
||||
|
||||
def test_set_config_modify(self):
|
||||
verify_ssl_values = (None, True, False)
|
||||
for verify_ssl_value in verify_ssl_values:
|
||||
cimc.DETAILS.clear()
|
||||
opts = {
|
||||
"proxy": {
|
||||
"host": "TheHost",
|
||||
"username": "TheUsername",
|
||||
"password": "ThePassword",
|
||||
"verify_ssl": verify_ssl_value,
|
||||
}
|
||||
}
|
||||
http_query_mock = MagicMock(side_effect=http_query_response)
|
||||
if verify_ssl_value is None:
|
||||
expected_verify_ssl_value = True
|
||||
else:
|
||||
expected_verify_ssl_value = verify_ssl_value
|
||||
|
||||
# Let's init the proxy and ignore it's actions, this test is not about them
|
||||
with patch(
|
||||
"salt.proxy.cimc.get_config_resolver_class",
|
||||
MagicMock(return_value=True),
|
||||
):
|
||||
cimc.init(opts)
|
||||
|
||||
log.debug(
|
||||
"verify_ssl: %s // expected verify_ssl: %s",
|
||||
verify_ssl_value,
|
||||
expected_verify_ssl_value,
|
||||
)
|
||||
|
||||
with patch.dict(cimc.__utils__, {"http.query": http_query_mock}):
|
||||
cimc.set_config_modify(
|
||||
dn="sys/rack-unit-1/locator-led",
|
||||
inconfig="<inConfig><equipmentLocatorLed adminState='on' dn='sys/rack-unit-1/locator-led'></equipmentLocatorLed></inConfig>",
|
||||
)
|
||||
|
||||
for idx, call in enumerate(http_query_mock.mock_calls, 1):
|
||||
condition = call.kwargs["verify_ssl"] is expected_verify_ssl_value
|
||||
condition_error = "{} != {}; Call(number={}): {}".format(
|
||||
idx, call, call.kwargs["verify_ssl"], expected_verify_ssl_value
|
||||
)
|
||||
self.assertTrue(condition, msg=condition_error)
|
||||
|
|
46
tests/unit/proxy/test_panos.py
Normal file
46
tests/unit/proxy/test_panos.py
Normal 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,
|
||||
)
|
||||
],
|
||||
)
|
98
tests/unit/returners/test_splunk.py
Normal file
98
tests/unit/returners/test_splunk.py
Normal 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"
|
||||
)
|
106
tests/unit/runners/test_asam.py
Normal file
106
tests/unit/runners/test_asam.py
Normal 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,
|
||||
)
|
72
tests/unit/states/test_esxi.py
Normal file
72
tests/unit/states/test_esxi.py
Normal 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
|
||||
)
|
|
@ -4,7 +4,6 @@
|
|||
Tests for cluster related functions in salt.utils.vmware
|
||||
"""
|
||||
|
||||
|
||||
import base64
|
||||
import logging
|
||||
import ssl
|
||||
|
@ -1690,13 +1689,13 @@ class PrivateGetServiceInstanceTestCase(TestCase):
|
|||
mechanism="sspi",
|
||||
)
|
||||
|
||||
def test_second_attempt_successful_connection(self):
|
||||
def test_first_attempt_successful_connection_verify_ssl_false(self):
|
||||
with patch("ssl.SSLContext", MagicMock()), patch(
|
||||
"ssl._create_unverified_context", MagicMock()
|
||||
):
|
||||
exc = vim.fault.HostConnectFault()
|
||||
exc.msg = "[SSL: CERTIFICATE_VERIFY_FAILED]"
|
||||
mock_sc = MagicMock(side_effect=[exc, None])
|
||||
mock_sc = MagicMock(side_effect=[None])
|
||||
mock_ssl = MagicMock()
|
||||
|
||||
with patch("salt.utils.vmware.SmartConnect", mock_sc):
|
||||
|
@ -1711,19 +1710,11 @@ class PrivateGetServiceInstanceTestCase(TestCase):
|
|||
mechanism="sspi",
|
||||
principal="fake_principal",
|
||||
domain="fake_domain",
|
||||
verify_ssl=False,
|
||||
)
|
||||
|
||||
mock_ssl.assert_called_once_with()
|
||||
calls = [
|
||||
call(
|
||||
host="fake_host.fqdn",
|
||||
user="fake_username",
|
||||
pwd="fake_password",
|
||||
protocol="fake_protocol",
|
||||
port=1,
|
||||
b64token="fake_token",
|
||||
mechanism="sspi",
|
||||
),
|
||||
call(
|
||||
host="fake_host.fqdn",
|
||||
user="fake_username",
|
||||
|
@ -1737,21 +1728,18 @@ class PrivateGetServiceInstanceTestCase(TestCase):
|
|||
]
|
||||
mock_sc.assert_has_calls(calls)
|
||||
|
||||
def test_third_attempt_successful_connection(self):
|
||||
def test_second_attempt_successful_connection_verify_ssl_false(self):
|
||||
with patch("ssl.SSLContext", MagicMock()), patch(
|
||||
"ssl._create_unverified_context", MagicMock()
|
||||
):
|
||||
exc = vim.fault.HostConnectFault()
|
||||
exc.msg = "[SSL: CERTIFICATE_VERIFY_FAILED]"
|
||||
exc2 = Exception("certificate verify failed")
|
||||
mock_sc = MagicMock(side_effect=[exc, exc2, None])
|
||||
exc = Exception("certificate verify failed")
|
||||
mock_sc = MagicMock(side_effect=[exc, None])
|
||||
mock_ssl_unverif = MagicMock()
|
||||
mock_ssl_context = MagicMock()
|
||||
|
||||
with patch("salt.utils.vmware.SmartConnect", mock_sc):
|
||||
with patch("ssl._create_unverified_context", mock_ssl_unverif):
|
||||
with patch("ssl.SSLContext", mock_ssl_context):
|
||||
|
||||
salt.utils.vmware._get_service_instance(
|
||||
host="fake_host.fqdn",
|
||||
username="fake_username",
|
||||
|
@ -1761,20 +1749,12 @@ class PrivateGetServiceInstanceTestCase(TestCase):
|
|||
mechanism="sspi",
|
||||
principal="fake_principal",
|
||||
domain="fake_domain",
|
||||
verify_ssl=False,
|
||||
)
|
||||
|
||||
mock_ssl_context.assert_called_once_with(ssl.PROTOCOL_TLSv1)
|
||||
mock_ssl_unverif.assert_called_once_with()
|
||||
calls = [
|
||||
call(
|
||||
host="fake_host.fqdn",
|
||||
user="fake_username",
|
||||
pwd="fake_password",
|
||||
protocol="fake_protocol",
|
||||
port=1,
|
||||
b64token="fake_token",
|
||||
mechanism="sspi",
|
||||
),
|
||||
call(
|
||||
host="fake_host.fqdn",
|
||||
user="fake_username",
|
||||
|
@ -1798,7 +1778,7 @@ class PrivateGetServiceInstanceTestCase(TestCase):
|
|||
]
|
||||
mock_sc.assert_has_calls(calls)
|
||||
|
||||
def test_first_attempt_unsuccessful_connection_default_error(self):
|
||||
def test_attempt_unsuccessful_connection_default_error(self):
|
||||
exc = Exception("Exception")
|
||||
mock_sc = MagicMock(side_effect=exc)
|
||||
|
||||
|
@ -1815,13 +1795,12 @@ class PrivateGetServiceInstanceTestCase(TestCase):
|
|||
domain="fake_domain",
|
||||
)
|
||||
|
||||
self.assertEqual(mock_sc.call_count, 1)
|
||||
self.assertIn(
|
||||
"Could not connect to host 'fake_host.fqdn'",
|
||||
excinfo.Exception.message,
|
||||
)
|
||||
self.assertEqual(mock_sc.call_count, 1)
|
||||
self.assertIn(
|
||||
"Could not connect to host 'fake_host.fqdn'", excinfo.exception.message,
|
||||
)
|
||||
|
||||
def test_first_attempt_unsuccessful_connection_vim_fault(self):
|
||||
def test_attempt_unsuccessful_connection_vim_fault(self):
|
||||
exc = vim.fault.VimFault()
|
||||
exc.msg = "VimFault"
|
||||
mock_sc = MagicMock(side_effect=exc)
|
||||
|
@ -1839,15 +1818,15 @@ class PrivateGetServiceInstanceTestCase(TestCase):
|
|||
domain="fake_domain",
|
||||
)
|
||||
|
||||
self.assertEqual(mock_sc.call_count, 1)
|
||||
self.assertEqual("VimFault", excinfo.Exception.message)
|
||||
self.assertEqual(mock_sc.call_count, 1)
|
||||
self.assertEqual("VimFault", excinfo.exception.message)
|
||||
|
||||
def test_second_attempt_unsuccsessful_connection_default_error(self):
|
||||
def test_first_attempt_unsuccsessful_connection_default_error(self):
|
||||
with patch("ssl.SSLContext", MagicMock()), patch(
|
||||
"ssl._create_unverified_context", MagicMock()
|
||||
):
|
||||
exc = vim.fault.HostConnectFault()
|
||||
exc.msg = "[SSL: CERTIFICATE_VERIFY_FAILED]"
|
||||
exc.msg = "certificate verify failed"
|
||||
exc2 = Exception("Exception")
|
||||
mock_sc = MagicMock(side_effect=[exc, exc2])
|
||||
|
||||
|
@ -1862,22 +1841,47 @@ class PrivateGetServiceInstanceTestCase(TestCase):
|
|||
mechanism="sspi",
|
||||
principal="fake_principal",
|
||||
domain="fake_domain",
|
||||
verify_ssl=False,
|
||||
)
|
||||
|
||||
self.assertEqual(mock_sc.call_count, 2)
|
||||
self.assertIn(
|
||||
"Could not connect to host 'fake_host.fqdn'",
|
||||
excinfo.Exception.message,
|
||||
self.assertEqual(mock_sc.call_count, 2)
|
||||
self.assertIn(
|
||||
"Could not connect to host 'fake_host.fqdn'", excinfo.exception.message
|
||||
)
|
||||
|
||||
def test_first_attempt_unsuccsessful_cannot_vim_fault_verify_ssl(self):
|
||||
with patch("ssl.SSLContext", MagicMock()), patch(
|
||||
"ssl._create_unverified_context", MagicMock()
|
||||
):
|
||||
exc = vim.fault.VimFault()
|
||||
exc.msg = "VimFault"
|
||||
|
||||
mock_sc = MagicMock(side_effect=[exc])
|
||||
|
||||
with patch("salt.utils.vmware.SmartConnect", mock_sc):
|
||||
with self.assertRaises(VMwareConnectionError) as excinfo:
|
||||
salt.utils.vmware._get_service_instance(
|
||||
host="fake_host.fqdn",
|
||||
username="fake_username",
|
||||
password="fake_password",
|
||||
protocol="fake_protocol",
|
||||
port=1,
|
||||
mechanism="sspi",
|
||||
principal="fake_principal",
|
||||
domain="fake_domain",
|
||||
verify_ssl=False,
|
||||
)
|
||||
|
||||
def test_second_attempt_unsuccsessful_connection_vim_fault(self):
|
||||
self.assertEqual(mock_sc.call_count, 1)
|
||||
self.assertIn("VimFault", excinfo.exception.message)
|
||||
|
||||
def test_third_attempt_unsuccessful_connection_detault_error(self):
|
||||
with patch("ssl.SSLContext", MagicMock()), patch(
|
||||
"ssl._create_unverified_context", MagicMock()
|
||||
):
|
||||
exc = vim.fault.HostConnectFault()
|
||||
exc.msg = "[SSL: CERTIFICATE_VERIFY_FAILED]"
|
||||
exc2 = vim.fault.VimFault()
|
||||
exc2.msg = "VimFault"
|
||||
exc.msg = "certificate verify failed"
|
||||
exc2 = Exception("Exception")
|
||||
mock_sc = MagicMock(side_effect=[exc, exc2])
|
||||
|
||||
with patch("salt.utils.vmware.SmartConnect", mock_sc):
|
||||
|
@ -1891,20 +1895,21 @@ class PrivateGetServiceInstanceTestCase(TestCase):
|
|||
mechanism="sspi",
|
||||
principal="fake_principal",
|
||||
domain="fake_domain",
|
||||
verify_ssl=False,
|
||||
)
|
||||
|
||||
self.assertEqual(mock_sc.call_count, 2)
|
||||
self.assertIn("VimFault", excinfo.Exception.message)
|
||||
self.assertEqual(mock_sc.call_count, 2)
|
||||
self.assertIn(
|
||||
"Could not connect to host 'fake_host.fqdn", excinfo.exception.message
|
||||
)
|
||||
|
||||
def test_third_attempt_unsuccessful_connection_detault_error(self):
|
||||
def test_second_attempt_unsuccessful_connection_vim_fault(self):
|
||||
with patch("ssl.SSLContext", MagicMock()), patch(
|
||||
"ssl._create_unverified_context", MagicMock()
|
||||
):
|
||||
exc = vim.fault.HostConnectFault()
|
||||
exc.msg = "[SSL: CERTIFICATE_VERIFY_FAILED]"
|
||||
exc2 = Exception("certificate verify failed")
|
||||
exc3 = Exception("Exception")
|
||||
mock_sc = MagicMock(side_effect=[exc, exc2, exc3])
|
||||
exc = vim.fault.VimFault()
|
||||
exc.msg = "VimFault"
|
||||
mock_sc = MagicMock(side_effect=[exc])
|
||||
|
||||
with patch("salt.utils.vmware.SmartConnect", mock_sc):
|
||||
with self.assertRaises(VMwareConnectionError) as excinfo:
|
||||
|
@ -1917,37 +1922,11 @@ class PrivateGetServiceInstanceTestCase(TestCase):
|
|||
mechanism="sspi",
|
||||
principal="fake_principal",
|
||||
domain="fake_domain",
|
||||
verify_ssl=False,
|
||||
)
|
||||
|
||||
self.assertEqual(mock_sc.call_count, 3)
|
||||
self.assertIn("Exception", excinfo.Exception.message)
|
||||
|
||||
def test_third_attempt_unsuccessful_connection_vim_fault(self):
|
||||
with patch("ssl.SSLContext", MagicMock()), patch(
|
||||
"ssl._create_unverified_context", MagicMock()
|
||||
):
|
||||
exc = vim.fault.HostConnectFault()
|
||||
exc.msg = "[SSL: CERTIFICATE_VERIFY_FAILED]"
|
||||
exc2 = Exception("certificate verify failed")
|
||||
exc3 = vim.fault.VimFault()
|
||||
exc3.msg = "VimFault"
|
||||
mock_sc = MagicMock(side_effect=[exc, exc2, exc3])
|
||||
|
||||
with patch("salt.utils.vmware.SmartConnect", mock_sc):
|
||||
with self.assertRaises(VMwareConnectionError) as excinfo:
|
||||
salt.utils.vmware._get_service_instance(
|
||||
host="fake_host.fqdn",
|
||||
username="fake_username",
|
||||
password="fake_password",
|
||||
protocol="fake_protocol",
|
||||
port=1,
|
||||
mechanism="sspi",
|
||||
principal="fake_principal",
|
||||
domain="fake_domain",
|
||||
)
|
||||
|
||||
self.assertEqual(mock_sc.call_count, 3)
|
||||
self.assertIn("VimFault", excinfo.Exception.message)
|
||||
self.assertEqual(mock_sc.call_count, 1)
|
||||
self.assertIn("VimFault", excinfo.exception.message)
|
||||
|
||||
|
||||
@skipIf(not HAS_PYVMOMI, "The 'pyvmomi' library is missing")
|
||||
|
@ -1974,7 +1953,15 @@ class GetServiceInstanceTestCase(TestCase):
|
|||
with patch("salt.utils.vmware._get_service_instance", mock_get_si):
|
||||
salt.utils.vmware.get_service_instance(host="fake_host")
|
||||
mock_get_si.assert_called_once_with(
|
||||
"fake_host", None, None, "https", 443, "userpass", None, None
|
||||
"fake_host",
|
||||
None,
|
||||
None,
|
||||
"https",
|
||||
443,
|
||||
"userpass",
|
||||
None,
|
||||
None,
|
||||
verify_ssl=True,
|
||||
)
|
||||
|
||||
def test_no_cached_service_instance_same_host_on_proxy(self):
|
||||
|
@ -2001,6 +1988,7 @@ class GetServiceInstanceTestCase(TestCase):
|
|||
"fake_mechanism",
|
||||
"fake_principal",
|
||||
"fake_domain",
|
||||
verify_ssl=True,
|
||||
)
|
||||
|
||||
def test_cached_service_instance_different_host(self):
|
||||
|
@ -2038,6 +2026,7 @@ class GetServiceInstanceTestCase(TestCase):
|
|||
mechanism="fake_mechanism",
|
||||
principal="fake_principal",
|
||||
domain="fake_domain",
|
||||
verify_ssl=True,
|
||||
)
|
||||
mock_get_si.assert_called_once_with(
|
||||
"fake_host",
|
||||
|
@ -2048,6 +2037,7 @@ class GetServiceInstanceTestCase(TestCase):
|
|||
"fake_mechanism",
|
||||
"fake_principal",
|
||||
"fake_domain",
|
||||
verify_ssl=True,
|
||||
)
|
||||
|
||||
def test_unauthenticated_service_instance(self):
|
||||
|
|
Loading…
Add table
Reference in a new issue