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