mirror of
https://github.com/valitydev/salt.git
synced 2024-11-07 17:09:03 +00:00
Merge branch '2018.3' into 51069-ri-and-rdoc-removed
This commit is contained in:
commit
f339608a88
49
.codecov.yml
Normal file
49
.codecov.yml
Normal file
@ -0,0 +1,49 @@
|
||||
codecov:
|
||||
ci:
|
||||
- drone.saltstack.com
|
||||
- jenkinsci.saltstack.com
|
||||
|
||||
branch: 2018.3
|
||||
|
||||
notify:
|
||||
require_ci_to_pass: no
|
||||
|
||||
ignore:
|
||||
- ^*.py$
|
||||
- doc/.*
|
||||
- tests/.*
|
||||
|
||||
coverage:
|
||||
round: up
|
||||
range: 70..100
|
||||
precision: 2
|
||||
|
||||
status:
|
||||
project: # measuring the overall project coverage
|
||||
default:
|
||||
enabled: yes # must be yes|true to enable this status
|
||||
if_no_uploads: error # will post commit status of "error" if no coverage reports we uploaded
|
||||
# options: success, error, failure
|
||||
if_not_found: success # if parent is not found report status as success, error, or failure
|
||||
if_ci_failed: success # if ci fails report status as success, error, or failure
|
||||
|
||||
patch: # pull requests only: this commit status will measure the
|
||||
# entire pull requests Coverage Diff. Checking if the lines
|
||||
# adjusted are covered at least X%.
|
||||
default:
|
||||
enabled: no # must be yes|true to enable this status
|
||||
target: 80% # specify the target "X%" coverage to hit
|
||||
if_no_uploads: error # will post commit status of "error" if no coverage reports we uploaded
|
||||
# options: success, error, failure
|
||||
if_not_found: success
|
||||
if_ci_failed: success
|
||||
|
||||
changes: # if there are any unexpected changes in coverage
|
||||
default:
|
||||
enabled: no # must be yes|true to enable this status
|
||||
if_no_uploads: success
|
||||
if_not_found: success
|
||||
if_ci_failed: success
|
||||
|
||||
# No commends because we're not yet running the full test suite on PRs
|
||||
comment: off
|
34
.coveragerc
Normal file
34
.coveragerc
Normal file
@ -0,0 +1,34 @@
|
||||
[run]
|
||||
branch = True
|
||||
cover_pylib = False
|
||||
source =
|
||||
salt
|
||||
parallel = True
|
||||
concurrency = multiprocessing
|
||||
omit =
|
||||
tests/*.py
|
||||
setup.py
|
||||
|
||||
[report]
|
||||
# Regexes for lines to exclude from consideration
|
||||
exclude_lines =
|
||||
# Have to re-enable the standard pragma
|
||||
pragma: no cover
|
||||
|
||||
# Don't complain about missing debug-only code:
|
||||
def __repr__
|
||||
|
||||
# Don't complain if tests don't hit defensive assertion code:
|
||||
raise AssertionError
|
||||
raise NotImplementedError
|
||||
|
||||
# Don't complain if non-runnable code isn't run:
|
||||
if 0:
|
||||
if __name__ == .__main__.:
|
||||
|
||||
|
||||
ignore_errors = True
|
||||
|
||||
[paths]
|
||||
source =
|
||||
salt
|
7
Gemfile
7
Gemfile
@ -2,9 +2,8 @@
|
||||
|
||||
source 'https://rubygems.org'
|
||||
|
||||
# Point this back at the test-kitchen package after 1.23.3 is relased
|
||||
gem 'test-kitchen', :git => 'https://github.com/dwoz/test-kitchen.git', :branch => 'winrm_opts'
|
||||
gem 'kitchen-salt', '~>0.2'
|
||||
gem 'test-kitchen', '~>1.23.3'
|
||||
gem 'kitchen-salt', '~>0.4.1'
|
||||
gem 'kitchen-sync'
|
||||
gem 'git'
|
||||
|
||||
@ -14,7 +13,7 @@ end
|
||||
|
||||
group :windows do
|
||||
gem 'winrm', '~>2.0'
|
||||
gem 'winrm-fs', '~>1.3.1'
|
||||
gem 'winrm-fs', '~>1.3.1'
|
||||
end
|
||||
|
||||
group :ec2 do
|
||||
|
13
doc/_themes/saltstack2/layout.html
vendored
13
doc/_themes/saltstack2/layout.html
vendored
@ -71,6 +71,14 @@
|
||||
{%- endmacro %}
|
||||
<html>
|
||||
<head>
|
||||
<!-- Google Tag Manager -->
|
||||
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
|
||||
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
|
||||
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
|
||||
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
|
||||
})(window,document,'script','dataLayer','GTM-MCK7VL3');</script>
|
||||
<!-- End Google Tag Manager -->
|
||||
|
||||
<meta charset="{{ encoding }}">
|
||||
{{ metatags }}
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
@ -120,6 +128,11 @@
|
||||
</head>
|
||||
|
||||
<body class="index">
|
||||
<!-- Google Tag Manager (noscript) -->
|
||||
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-MCK7VL3"
|
||||
height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
|
||||
<!-- End Google Tag Manager (noscript) -->
|
||||
|
||||
<!--[if lt IE 8]>
|
||||
<p>You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser.</a></p>
|
||||
<![endif]-->
|
||||
|
@ -130,7 +130,7 @@ Cloud ``salt.cloud.clouds`` (:ref:`index <all-salt.clouds>`) ``
|
||||
Engine ``salt.engines`` (:ref:`index <engines>`) ``engines`` ``engines_dirs``
|
||||
Execution ``salt.modules`` (:ref:`index <all-salt.modules>`) ``modules`` ``module_dirs``
|
||||
Executor ``salt.executors`` (:ref:`index <all-salt.executors>`) ``executors`` [#no-fs]_ ``executor_dirs``
|
||||
File Server ``salt.fileserver`` (:ref:`index <file-server>`) ``fileserver`` [#no-fs]_ ``fileserver_dirs``
|
||||
File Server ``salt.fileserver`` (:ref:`index <file-server>`) ``fileserver`` ``fileserver_dirs``
|
||||
Grain ``salt.grains`` (:ref:`index <all-salt.grains>`) ``grains`` ``grains_dirs``
|
||||
Log Handler ``salt.log.handlers`` (:ref:`index <external-logging-handlers>`) ``log_handlers`` ``log_handlers_dirs``
|
||||
Net API ``salt.netapi`` (:ref:`index <all-netapi-modules>`) ``netapi`` [#no-fs]_ ``netapi_dirs``
|
||||
@ -143,13 +143,13 @@ Returner ``salt.returners`` (:ref:`index <all-salt.returners>`) ``
|
||||
Roster ``salt.roster`` (:ref:`index <all-salt.roster>`) ``roster`` ``roster_dirs``
|
||||
Runner ``salt.runners`` (:ref:`index <all-salt.runners>`) ``runners`` ``runner_dirs``
|
||||
SDB ``salt.sdb`` (:ref:`index <all-salt.sdb>`) ``sdb`` ``sdb_dirs``
|
||||
Search ``salt.search`` ``search`` [#no-fs]_ ``search_dirs``
|
||||
Serializer ``salt.serializers`` (:ref:`index <all-salt.serializers>`) ``serializers`` [#no-fs]_ ``serializers_dirs``
|
||||
SPM pkgdb ``salt.spm.pkgdb`` ``pkgdb`` [#no-fs]_ ``pkgdb_dirs``
|
||||
SPM pkgfiles ``salt.spm.pkgfiles`` ``pkgfiles`` [#no-fs]_ ``pkgfiles_dirs``
|
||||
SSH Wrapper ``salt.client.ssh.wrapper`` ``wrapper`` [#no-fs]_ ``wrapper_dirs``
|
||||
State ``salt.states`` (:ref:`index <all-salt.states>`) ``states`` ``states_dirs``
|
||||
Thorium ``salt.thorium`` (:ref:`index <all-salt.thorium>`) ``thorium`` [#no-fs]_ ``thorium_dirs``
|
||||
Thorium ``salt.thorium`` (:ref:`index <all-salt.thorium>`) ``thorium`` ``thorium_dirs``
|
||||
Tokens ``salt.tokens`` ``tokens`` ``tokens_dirs``
|
||||
Top ``salt.tops`` (:ref:`index <all-salt.tops>`) ``tops`` ``top_dirs``
|
||||
Util ``salt.utils`` ``utils`` ``utils_dirs``
|
||||
Wheel ``salt.wheels`` (:ref:`index <all-salt.wheel>`) ``wheel`` ``wheel_dirs``
|
||||
@ -223,6 +223,12 @@ object.
|
||||
Executor
|
||||
--------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:glob:
|
||||
|
||||
/ref/executors/index
|
||||
|
||||
Executors control how execution modules get called. The default is to just call
|
||||
them, but this can be customized.
|
||||
|
||||
@ -322,11 +328,6 @@ SDB
|
||||
SDB is a way to store data that's not associated with a minion. See
|
||||
:ref:`Storing Data in Other Databases <sdb>`.
|
||||
|
||||
Search
|
||||
------
|
||||
|
||||
A system for indexing the file server and pillars. Removed in 2018.3.
|
||||
|
||||
Serializer
|
||||
----------
|
||||
|
||||
@ -375,6 +376,16 @@ Thorium
|
||||
|
||||
Modules for use in the :ref:`Thorium <thorium-reactor>` event reactor.
|
||||
|
||||
Tokens
|
||||
------
|
||||
|
||||
Token stores for :ref:`External Authentication <acl-eauth>`. See the
|
||||
:py:mod:`salt.tokens` docstring for details.
|
||||
|
||||
.. note:
|
||||
The runner to load tokens modules is
|
||||
:py:func:`saltutil.sync_eauth_tokens <salt.runners.saltutil.sync_eauth_tokens>`.
|
||||
|
||||
Tops
|
||||
----
|
||||
|
||||
|
@ -531,7 +531,13 @@ Global Remotes
|
||||
|
||||
The ``all_saltenvs`` per-remote configuration parameter overrides the logic
|
||||
Salt uses to map branches/tags to fileserver environments (i.e. saltenvs). This
|
||||
allows a single branch/tag to appear in *all* saltenvs.
|
||||
allows a single branch/tag to appear in *all* GitFS saltenvs.
|
||||
|
||||
.. note::
|
||||
``all_saltenvs`` only works *within* GitFS. That is, files in a branch
|
||||
configured using ``all_saltenvs`` will *not* show up in a fileserver
|
||||
environment defined via some other fileserver backend (e.g.
|
||||
:conf_master:`file_roots`).
|
||||
|
||||
This is very useful in particular when working with :ref:`salt formulas
|
||||
<conventions-formula>`. Prior to the addition of this feature, it was necessary
|
||||
|
@ -5,3 +5,4 @@ pytest-salt == 2018.12.8
|
||||
pytest-timeout >= 1.3.3
|
||||
pytest-tempdir >= 2018.8.11
|
||||
pytest-helpers-namespace >= 2017.11.11
|
||||
pytest-salt-runtests-bridge >= 2019.1.30
|
||||
|
@ -29,7 +29,6 @@ PyMySQL; sys.platform != 'win32' and sys.platform != 'darwin'
|
||||
jsonschema
|
||||
strict_rfc3339
|
||||
rfc3987
|
||||
jinja2
|
||||
pyOpenSSL
|
||||
ioflo
|
||||
dnspython
|
||||
|
@ -52,8 +52,8 @@ def beacon(config):
|
||||
beacons:
|
||||
service:
|
||||
- services:
|
||||
salt-master:
|
||||
mysql:
|
||||
salt-master: {}
|
||||
mysql: {}
|
||||
|
||||
The config above sets up beacons to check for
|
||||
the salt-master and mysql services.
|
||||
|
@ -1344,6 +1344,24 @@ class Cloud(object):
|
||||
output['ret'] = action_out
|
||||
return output
|
||||
|
||||
@staticmethod
|
||||
def vm_config(name, main, provider, profile, overrides):
|
||||
'''
|
||||
Create vm config.
|
||||
|
||||
:param str name: The name of the vm
|
||||
:param dict main: The main cloud config
|
||||
:param dict provider: The provider config
|
||||
:param dict profile: The profile config
|
||||
:param dict overrides: The vm's config overrides
|
||||
'''
|
||||
vm = main.copy()
|
||||
vm = salt.utils.dictupdate.update(vm, provider)
|
||||
vm = salt.utils.dictupdate.update(vm, profile)
|
||||
vm.update(overrides)
|
||||
vm['name'] = name
|
||||
return vm
|
||||
|
||||
def extras(self, extra_):
|
||||
'''
|
||||
Extra actions
|
||||
@ -1430,12 +1448,13 @@ class Cloud(object):
|
||||
ret[name] = {'Error': msg}
|
||||
continue
|
||||
|
||||
vm_ = main_cloud_config.copy()
|
||||
vm_.update(provider_details)
|
||||
vm_.update(profile_details)
|
||||
vm_.update(vm_overrides)
|
||||
|
||||
vm_['name'] = name
|
||||
vm_ = self.vm_config(
|
||||
name,
|
||||
main_cloud_config,
|
||||
provider_details,
|
||||
profile_details,
|
||||
vm_overrides,
|
||||
)
|
||||
if self.opts['parallel']:
|
||||
process = multiprocessing.Process(
|
||||
target=self.create,
|
||||
|
@ -388,6 +388,9 @@ def _get_snapshot_version_metadata(artifactory_url, repository, group_id, artifa
|
||||
extension = snapshot_version.find('extension').text
|
||||
value = snapshot_version.find('value').text
|
||||
extension_version_dict[extension] = value
|
||||
if snapshot_version.find('classifier') is not None:
|
||||
classifier = snapshot_version.find('classifier').text
|
||||
extension_version_dict[classifier] = value
|
||||
|
||||
return {
|
||||
'snapshot_versions': extension_version_dict
|
||||
|
@ -22,6 +22,7 @@ import re
|
||||
|
||||
# Import salt libs
|
||||
import salt.utils.args
|
||||
import salt.utils.compat
|
||||
import salt.utils.data
|
||||
import salt.utils.functools
|
||||
import salt.utils.path
|
||||
@ -31,9 +32,6 @@ import salt.utils.versions
|
||||
from salt.exceptions import CommandExecutionError, MinionError
|
||||
from salt.ext import six
|
||||
|
||||
# Workaround for 'reload' builtin of py2.7
|
||||
if six.PY3:
|
||||
from importlib import reload # pylint: disable=no-name-in-module
|
||||
|
||||
# Import third party libs
|
||||
HAS_PORTAGE = False
|
||||
@ -69,13 +67,13 @@ def __virtual__():
|
||||
|
||||
def _vartree():
|
||||
import portage # pylint: disable=3rd-party-module-not-gated
|
||||
portage = reload(portage)
|
||||
portage = salt.utils.compat.reload(portage)
|
||||
return portage.db[portage.root]['vartree']
|
||||
|
||||
|
||||
def _porttree():
|
||||
import portage # pylint: disable=3rd-party-module-not-gated
|
||||
portage = reload(portage)
|
||||
portage = salt.utils.compat.reload(portage)
|
||||
return portage.db[portage.root]['porttree']
|
||||
|
||||
|
||||
|
@ -979,7 +979,7 @@ def clone(cwd,
|
||||
information on securing the keypair from the remote side in the
|
||||
``authorized_keys`` file.
|
||||
|
||||
.. _`sshd(8)`: http://www.man7.org/linux/man-pages/man8/sshd.8.html#AUTHORIZED_KEYS_FILE%20FORMAT
|
||||
.. _`sshd(8)`: http://www.man7.org/linux/man-pages/man8/sshd.8.html#AUTHORIZED_KEYS_FILE_FORMAT
|
||||
|
||||
.. versionchanged:: 2015.8.7
|
||||
|
||||
@ -2035,7 +2035,7 @@ def fetch(cwd,
|
||||
information on securing the keypair from the remote side in the
|
||||
``authorized_keys`` file.
|
||||
|
||||
.. _`sshd(8)`: http://www.man7.org/linux/man-pages/man8/sshd.8.html#AUTHORIZED_KEYS_FILE%20FORMAT
|
||||
.. _`sshd(8)`: http://www.man7.org/linux/man-pages/man8/sshd.8.html#AUTHORIZED_KEYS_FILE_FORMAT
|
||||
|
||||
.. versionchanged:: 2015.8.7
|
||||
|
||||
@ -2847,7 +2847,7 @@ def ls_remote(cwd=None,
|
||||
information on securing the keypair from the remote side in the
|
||||
``authorized_keys`` file.
|
||||
|
||||
.. _`sshd(8)`: http://www.man7.org/linux/man-pages/man8/sshd.8.html#AUTHORIZED_KEYS_FILE%20FORMAT
|
||||
.. _`sshd(8)`: http://www.man7.org/linux/man-pages/man8/sshd.8.html#AUTHORIZED_KEYS_FILE_FORMAT
|
||||
|
||||
.. versionchanged:: 2015.8.7
|
||||
|
||||
@ -2940,6 +2940,7 @@ def merge(cwd,
|
||||
git_opts='',
|
||||
user=None,
|
||||
password=None,
|
||||
identity=None,
|
||||
ignore_retcode=False,
|
||||
output_encoding=None,
|
||||
**kwargs):
|
||||
@ -2983,6 +2984,22 @@ def merge(cwd,
|
||||
|
||||
.. versionadded:: 2016.3.4
|
||||
|
||||
identity
|
||||
Path to a private key to use for ssh URLs. Salt will not attempt to use
|
||||
passphrase-protected keys unless invoked from the minion using
|
||||
``salt-call``, to prevent blocking waiting for user input. Key can also
|
||||
be specified as a SaltStack file server URL, eg.
|
||||
``salt://location/identity_file``.
|
||||
|
||||
.. note::
|
||||
For greater security with passphraseless private keys, see the
|
||||
`sshd(8)`_ manpage for information on securing the keypair from the
|
||||
remote side in the ``authorized_keys`` file.
|
||||
|
||||
.. _`sshd(8)`: http://www.man7.org/linux/man-pages/man8/sshd.8.html#AUTHORIZED_KEYS_FILE_FORMAT
|
||||
|
||||
.. versionadded:: 2018.3.5,2019.2.1,Neon
|
||||
|
||||
ignore_retcode : False
|
||||
If ``True``, do not log an error to the minion log if the git command
|
||||
returns a nonzero exit status.
|
||||
@ -3024,10 +3041,12 @@ def merge(cwd,
|
||||
command.extend(_format_opts(opts))
|
||||
if rev:
|
||||
command.append(rev)
|
||||
|
||||
return _git_run(command,
|
||||
cwd=cwd,
|
||||
user=user,
|
||||
password=password,
|
||||
identity=identity,
|
||||
ignore_retcode=ignore_retcode,
|
||||
output_encoding=output_encoding)['stdout']
|
||||
|
||||
@ -3382,7 +3401,7 @@ def pull(cwd,
|
||||
information on securing the keypair from the remote side in the
|
||||
``authorized_keys`` file.
|
||||
|
||||
.. _`sshd(8)`: http://www.man7.org/linux/man-pages/man8/sshd.8.html#AUTHORIZED_KEYS_FILE%20FORMAT
|
||||
.. _`sshd(8)`: http://www.man7.org/linux/man-pages/man8/sshd.8.html#AUTHORIZED_KEYS_FILE_FORMAT
|
||||
|
||||
.. versionchanged:: 2015.8.7
|
||||
|
||||
@ -3508,7 +3527,7 @@ def push(cwd,
|
||||
information on securing the keypair from the remote side in the
|
||||
``authorized_keys`` file.
|
||||
|
||||
.. _`sshd(8)`: http://www.man7.org/linux/man-pages/man8/sshd.8.html#AUTHORIZED_KEYS_FILE%20FORMAT
|
||||
.. _`sshd(8)`: http://www.man7.org/linux/man-pages/man8/sshd.8.html#AUTHORIZED_KEYS_FILE_FORMAT
|
||||
|
||||
.. versionchanged:: 2015.8.7
|
||||
|
||||
@ -3792,7 +3811,7 @@ def remote_refs(url,
|
||||
information on securing the keypair from the remote side in the
|
||||
``authorized_keys`` file.
|
||||
|
||||
.. _`sshd(8)`: http://www.man7.org/linux/man-pages/man8/sshd.8.html#AUTHORIZED_KEYS_FILE%20FORMAT
|
||||
.. _`sshd(8)`: http://www.man7.org/linux/man-pages/man8/sshd.8.html#AUTHORIZED_KEYS_FILE_FORMAT
|
||||
|
||||
.. versionchanged:: 2015.8.7
|
||||
|
||||
@ -4101,6 +4120,7 @@ def reset(cwd,
|
||||
git_opts='',
|
||||
user=None,
|
||||
password=None,
|
||||
identity=None,
|
||||
ignore_retcode=False,
|
||||
output_encoding=None):
|
||||
'''
|
||||
@ -4137,6 +4157,22 @@ def reset(cwd,
|
||||
|
||||
.. versionadded:: 2016.3.4
|
||||
|
||||
identity
|
||||
Path to a private key to use for ssh URLs. Salt will not attempt to use
|
||||
passphrase-protected keys unless invoked from the minion using
|
||||
``salt-call``, to prevent blocking waiting for user input. Key can also
|
||||
be specified as a SaltStack file server URL, eg.
|
||||
``salt://location/identity_file``.
|
||||
|
||||
.. note::
|
||||
For greater security with passphraseless private keys, see the
|
||||
`sshd(8)`_ manpage for information on securing the keypair from the
|
||||
remote side in the ``authorized_keys`` file.
|
||||
|
||||
.. _`sshd(8)`: http://www.man7.org/linux/man-pages/man8/sshd.8.html#AUTHORIZED_KEYS_FILE_FORMAT
|
||||
|
||||
.. versionadded:: 2018.3.5,2019.2.1,Neon
|
||||
|
||||
ignore_retcode : False
|
||||
If ``True``, do not log an error to the minion log if the git command
|
||||
returns a nonzero exit status.
|
||||
@ -4174,6 +4210,7 @@ def reset(cwd,
|
||||
cwd=cwd,
|
||||
user=user,
|
||||
password=password,
|
||||
identity=identity,
|
||||
ignore_retcode=ignore_retcode,
|
||||
output_encoding=output_encoding)['stdout']
|
||||
|
||||
@ -4662,7 +4699,7 @@ def submodule(cwd,
|
||||
information on securing the keypair from the remote side in the
|
||||
``authorized_keys`` file.
|
||||
|
||||
.. _`sshd(8)`: http://www.man7.org/linux/man-pages/man8/sshd.8.html#AUTHORIZED_KEYS_FILE%20FORMAT
|
||||
.. _`sshd(8)`: http://www.man7.org/linux/man-pages/man8/sshd.8.html#AUTHORIZED_KEYS_FILE_FORMAT
|
||||
|
||||
.. versionchanged:: 2015.8.7
|
||||
|
||||
|
@ -10,6 +10,7 @@ import os
|
||||
import shutil
|
||||
|
||||
# Import salt libs
|
||||
import salt.utils.compat
|
||||
import salt.utils.data
|
||||
import salt.utils.files
|
||||
import salt.utils.path
|
||||
@ -57,7 +58,7 @@ def _get_portage():
|
||||
portage module must be reloaded or it can't catch the changes
|
||||
in portage.* which had been added after when the module was loaded
|
||||
'''
|
||||
return reload(portage)
|
||||
return salt.utils.compat.reload(portage)
|
||||
|
||||
|
||||
def _porttree():
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -390,7 +390,7 @@ def _passphrase_callback(passphrase):
|
||||
Returns a callback function used to supply a passphrase for private keys
|
||||
'''
|
||||
def f(*args):
|
||||
return salt.utils.stringutils.to_str(passphrase)
|
||||
return salt.utils.stringutils.to_bytes(passphrase)
|
||||
return f
|
||||
|
||||
|
||||
@ -961,7 +961,7 @@ def create_crl( # pylint: disable=too-many-arguments,too-many-locals
|
||||
|
||||
serial_number = rev_item['serial_number'].replace(':', '')
|
||||
# OpenSSL bindings requires this to be a non-unicode string
|
||||
serial_number = salt.utils.stringutils.to_str(serial_number)
|
||||
serial_number = salt.utils.stringutils.to_bytes(serial_number)
|
||||
|
||||
if 'not_after' in rev_item and not include_expired:
|
||||
not_after = datetime.datetime.strptime(
|
||||
@ -976,6 +976,7 @@ def create_crl( # pylint: disable=too-many-arguments,too-many-locals
|
||||
rev_date = datetime.datetime.strptime(
|
||||
rev_item['revocation_date'], '%Y-%m-%d %H:%M:%S')
|
||||
rev_date = rev_date.strftime('%Y%m%d%H%M%SZ')
|
||||
rev_date = salt.utils.stringutils.to_bytes(rev_date)
|
||||
|
||||
rev = OpenSSL.crypto.Revoked()
|
||||
rev.set_serial(serial_number)
|
||||
@ -1005,7 +1006,7 @@ def create_crl( # pylint: disable=too-many-arguments,too-many-locals
|
||||
'days': days_valid
|
||||
}
|
||||
if digest:
|
||||
export_kwargs['digest'] = bytes(digest)
|
||||
export_kwargs['digest'] = salt.utils.stringutils.to_bytes(digest)
|
||||
else:
|
||||
log.warning('No digest specified. The default md5 digest will be used.')
|
||||
|
||||
@ -1573,7 +1574,7 @@ def create_certificate(
|
||||
pem_type='CERTIFICATE'
|
||||
)
|
||||
else:
|
||||
return cert.as_pem()
|
||||
return salt.utils.stringutils.to_str(cert.as_pem())
|
||||
# pylint: enable=too-many-locals
|
||||
|
||||
|
||||
|
@ -33,6 +33,7 @@ import salt.utils.color
|
||||
import salt.utils.odict
|
||||
import salt.utils.stringutils
|
||||
from salt.ext import six
|
||||
from collections import Mapping
|
||||
|
||||
|
||||
class NestDisplay(object):
|
||||
@ -142,7 +143,7 @@ class NestDisplay(object):
|
||||
if self.retcode != 0:
|
||||
color = self.RED
|
||||
for ind in ret:
|
||||
if isinstance(ind, (list, tuple, dict)):
|
||||
if isinstance(ind, (list, tuple, Mapping)):
|
||||
out.append(
|
||||
self.ustring(
|
||||
indent,
|
||||
@ -150,11 +151,11 @@ class NestDisplay(object):
|
||||
'|_'
|
||||
)
|
||||
)
|
||||
prefix = '' if isinstance(ind, dict) else '- '
|
||||
prefix = '' if isinstance(ind, Mapping) else '- '
|
||||
self.display(ind, indent + 2, prefix, out)
|
||||
else:
|
||||
self.display(ind, indent, '- ', out)
|
||||
elif isinstance(ret, dict):
|
||||
elif isinstance(ret, Mapping):
|
||||
if indent:
|
||||
color = self.CYAN
|
||||
if self.retcode != 0:
|
||||
|
@ -19,6 +19,7 @@ import salt.transport.frame
|
||||
import salt.utils.immutabletypes as immutabletypes
|
||||
import salt.utils.stringutils
|
||||
from salt.exceptions import SaltReqTimeoutError
|
||||
from salt.utils.data import CaseInsensitiveDict
|
||||
|
||||
# Import third party libs
|
||||
from salt.ext import six
|
||||
@ -205,6 +206,8 @@ class Serial(object):
|
||||
elif isinstance(obj, (set, immutabletypes.ImmutableSet)):
|
||||
# msgpack can't handle set so translate it to tuple
|
||||
return tuple(obj)
|
||||
elif isinstance(obj, CaseInsensitiveDict):
|
||||
return dict(obj)
|
||||
# Nothing known exceptions found. Let msgpack raise it's own.
|
||||
return obj
|
||||
|
||||
|
@ -7,10 +7,8 @@ The following Type: "Zabbix trapper" with "Type of information" Text items are r
|
||||
.. code-block:: cfg
|
||||
|
||||
Key: salt.trap.info
|
||||
Key: salt.trap.average
|
||||
Key: salt.trap.warning
|
||||
Key: salt.trap.high
|
||||
Key: salt.trap.disaster
|
||||
|
||||
To use the Zabbix returner, append '--return zabbix' to the salt command. ex:
|
||||
|
||||
@ -21,15 +19,10 @@ To use the Zabbix returner, append '--return zabbix' to the salt command. ex:
|
||||
|
||||
# Import Python libs
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
import logging
|
||||
import os
|
||||
|
||||
# Import Salt libs
|
||||
from salt.ext import six
|
||||
import salt.utils.files
|
||||
|
||||
# Get logging started
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# Define the module's virtual name
|
||||
@ -55,37 +48,24 @@ def zbx():
|
||||
return False
|
||||
|
||||
|
||||
def zabbix_send(key, host, output):
|
||||
with salt.utils.files.fopen(zbx()['zabbix_config'], 'r') as file_handle:
|
||||
for line in file_handle:
|
||||
if "ServerActive" in line:
|
||||
flag = "true"
|
||||
server = line.rsplit('=')
|
||||
server = server[1].rsplit(',')
|
||||
for s in server:
|
||||
cmd = zbx()['sender'] + " -z " + s.replace('\n', '') + " -s " + host + " -k " + key + " -o \"" + output +"\""
|
||||
__salt__['cmd.shell'](cmd)
|
||||
break
|
||||
else:
|
||||
flag = "false"
|
||||
if flag == 'false':
|
||||
cmd = zbx()['sender'] + " -c " + zbx()['config'] + " -s " + host + " -k " + key + " -o \"" + output +"\""
|
||||
def zabbix_send(key, output):
|
||||
cmd = zbx()['sender'] + " -c " + zbx()['config'] + " -k " + key + " -o \"" + output +"\""
|
||||
__salt__['cmd.shell'](cmd)
|
||||
|
||||
|
||||
def returner(ret):
|
||||
changes = False
|
||||
errors = False
|
||||
job_minion_id = ret['id']
|
||||
host = job_minion_id
|
||||
|
||||
if type(ret['return']) is dict:
|
||||
for state, item in six.iteritems(ret['return']):
|
||||
if 'comment' in item and 'name' in item and not item['result']:
|
||||
if 'comment' in item and 'name' in item and item['result'] is False:
|
||||
errors = True
|
||||
zabbix_send("salt.trap.high", host, 'SALT:\nname: {0}\ncomment: {1}'.format(item['name'], item['comment']))
|
||||
if 'comment' in item and 'name' in item and item['changes']:
|
||||
zabbix_send("salt.trap.high", 'SALT:\nname: {0}\ncomment: {1}'.format(item['name'], item['comment']))
|
||||
elif 'comment' in item and 'name' in item and item['changes']:
|
||||
changes = True
|
||||
zabbix_send("salt.trap.warning", host, 'SALT:\nname: {0}\ncomment: {1}'.format(item['name'], item['comment']))
|
||||
zabbix_send("salt.trap.warning", 'SALT:\nname: {0}\ncomment: {1}'.format(item['name'], item['comment']))
|
||||
|
||||
if not changes and not errors:
|
||||
zabbix_send("salt.trap.info", host, 'SALT {0} OK'.format(job_minion_id))
|
||||
zabbix_send("salt.trap.info", 'SALT {0} OK'.format(job_minion_id))
|
||||
|
@ -2421,7 +2421,6 @@ def managed(name,
|
||||
'to True to allow the managed file to be empty.'
|
||||
.format(contents_id)
|
||||
)
|
||||
|
||||
if isinstance(use_contents, six.binary_type) and b'\0' in use_contents:
|
||||
contents = use_contents
|
||||
elif isinstance(use_contents, six.text_type) and str('\0') in use_contents:
|
||||
@ -2435,9 +2434,10 @@ def managed(name,
|
||||
'contents_grains is not a string or list of strings, and '
|
||||
'is not binary data. SLS is likely malformed.'
|
||||
)
|
||||
contents = os.linesep.join(
|
||||
[line.rstrip('\n').rstrip('\r') for line in validated_contents]
|
||||
)
|
||||
contents = ''
|
||||
for part in validated_contents:
|
||||
for line in part.splitlines():
|
||||
contents += line.rstrip('\n').rstrip('\r') + os.linesep
|
||||
if contents_newline and not contents.endswith(os.linesep):
|
||||
contents += os.linesep
|
||||
if template:
|
||||
@ -3276,7 +3276,7 @@ def directory(name,
|
||||
ret, _ = __salt__['file.check_perms'](
|
||||
full, ret, user, group, file_mode, None, follow_symlinks)
|
||||
except CommandExecutionError as exc:
|
||||
if not exc.strerror.endswith('does not exist'):
|
||||
if not exc.strerror.startswith('Path not found'):
|
||||
errors.append(exc.strerror)
|
||||
|
||||
if check_dirs:
|
||||
|
@ -685,6 +685,15 @@ def latest(name,
|
||||
if https_pass is not None and not isinstance(https_pass, six.string_types):
|
||||
https_pass = six.text_type(https_pass)
|
||||
|
||||
# Check for lfs filter settings, and setup lfs_opts accordingly. These opts
|
||||
# will be passed where appropriate to ensure that these commands are
|
||||
# authenticated and that the git LFS plugin can download files.
|
||||
use_lfs = bool(
|
||||
__salt__['git.config_get_regexp'](
|
||||
r'filter\.lfs\.',
|
||||
**{'global': True}))
|
||||
lfs_opts = {'identity': identity} if use_lfs else {}
|
||||
|
||||
if os.path.isfile(target):
|
||||
return _fail(
|
||||
ret,
|
||||
@ -1560,7 +1569,8 @@ def latest(name,
|
||||
opts=['--hard', remote_rev],
|
||||
user=user,
|
||||
password=password,
|
||||
output_encoding=output_encoding)
|
||||
output_encoding=output_encoding,
|
||||
**lfs_opts)
|
||||
ret['changes']['forced update'] = True
|
||||
comments.append(
|
||||
'Repository was hard-reset to {0}'.format(remote_loc)
|
||||
@ -1613,7 +1623,8 @@ def latest(name,
|
||||
opts=merge_opts,
|
||||
user=user,
|
||||
password=password,
|
||||
output_encoding=output_encoding)
|
||||
output_encoding=output_encoding,
|
||||
**lfs_opts)
|
||||
comments.append(
|
||||
'Repository was fast-forwarded to {0}'
|
||||
.format(remote_loc)
|
||||
@ -1633,7 +1644,8 @@ def latest(name,
|
||||
remote_rev if rev == 'HEAD' else rev],
|
||||
user=user,
|
||||
password=password,
|
||||
output_encoding=output_encoding)
|
||||
output_encoding=output_encoding,
|
||||
**lfs_opts)
|
||||
comments.append(
|
||||
'Repository was reset to {0} (fast-forward)'
|
||||
.format(rev)
|
||||
|
@ -30,6 +30,7 @@ except ImportError:
|
||||
HAS_PKG_RESOURCES = False
|
||||
|
||||
# Import salt libs
|
||||
import salt.utils.data
|
||||
import salt.utils.versions
|
||||
from salt.version import SaltStackVersion as _SaltStackVersion
|
||||
from salt.exceptions import CommandExecutionError, CommandNotFoundError
|
||||
@ -87,20 +88,6 @@ def __virtual__():
|
||||
return False
|
||||
|
||||
|
||||
def _find_key(prefix, pip_list):
|
||||
'''
|
||||
Does a case-insensitive match in the pip_list for the desired package.
|
||||
'''
|
||||
try:
|
||||
match = next(
|
||||
iter(x for x in pip_list if x.lower() == prefix.lower())
|
||||
)
|
||||
except StopIteration:
|
||||
return None
|
||||
else:
|
||||
return match
|
||||
|
||||
|
||||
def _fulfills_version_spec(version, version_spec):
|
||||
'''
|
||||
Check version number against version specification info and return a
|
||||
@ -214,23 +201,20 @@ def _check_if_installed(prefix, state_pkg_name, version_spec, ignore_installed,
|
||||
ret = {'result': False, 'comment': None}
|
||||
|
||||
# If we are not passed a pip list, get one:
|
||||
if not pip_list:
|
||||
pip_list = __salt__['pip.list'](prefix, bin_env=bin_env,
|
||||
user=user, cwd=cwd,
|
||||
env_vars=env_vars, **kwargs)
|
||||
|
||||
# Check if the requested package is already installed.
|
||||
prefix_realname = _find_key(prefix, pip_list)
|
||||
pip_list = salt.utils.data.CaseInsensitiveDict(
|
||||
pip_list or __salt__['pip.list'](prefix, bin_env=bin_env,
|
||||
user=user, cwd=cwd,
|
||||
env_vars=env_vars, **kwargs)
|
||||
)
|
||||
|
||||
# If the package was already installed, check
|
||||
# the ignore_installed and force_reinstall flags
|
||||
if ignore_installed is False and prefix_realname is not None:
|
||||
if ignore_installed is False and prefix in pip_list:
|
||||
if force_reinstall is False and not upgrade:
|
||||
# Check desired version (if any) against currently-installed
|
||||
if (
|
||||
any(version_spec) and
|
||||
_fulfills_version_spec(pip_list[prefix_realname],
|
||||
version_spec)
|
||||
_fulfills_version_spec(pip_list[prefix], version_spec)
|
||||
) or (not any(version_spec)):
|
||||
ret['result'] = True
|
||||
ret['comment'] = ('Python package {0} was already '
|
||||
@ -250,7 +234,7 @@ def _check_if_installed(prefix, state_pkg_name, version_spec, ignore_installed,
|
||||
if 'rc' in spec[1]:
|
||||
include_rc = True
|
||||
available_versions = __salt__['pip.list_all_versions'](
|
||||
prefix_realname, bin_env=bin_env, include_alpha=include_alpha,
|
||||
prefix, bin_env=bin_env, include_alpha=include_alpha,
|
||||
include_beta=include_beta, include_rc=include_rc, user=user,
|
||||
cwd=cwd)
|
||||
desired_version = ''
|
||||
@ -266,9 +250,9 @@ def _check_if_installed(prefix, state_pkg_name, version_spec, ignore_installed,
|
||||
ret['comment'] = ('Python package {0} was already '
|
||||
'installed and\nthe available upgrade '
|
||||
'doesn\'t fulfills the version '
|
||||
'requirements'.format(prefix_realname))
|
||||
'requirements'.format(prefix))
|
||||
return ret
|
||||
if _pep440_version_cmp(pip_list[prefix_realname], desired_version) == 0:
|
||||
if _pep440_version_cmp(pip_list[prefix], desired_version) == 0:
|
||||
ret['result'] = True
|
||||
ret['comment'] = ('Python package {0} was already '
|
||||
'installed'.format(state_pkg_name))
|
||||
@ -903,10 +887,12 @@ def installed(name,
|
||||
|
||||
# Case for packages that are not an URL
|
||||
if prefix:
|
||||
pipsearch = __salt__['pip.list'](prefix, bin_env,
|
||||
user=user, cwd=cwd,
|
||||
env_vars=env_vars,
|
||||
**kwargs)
|
||||
pipsearch = salt.utils.data.CaseInsensitiveDict(
|
||||
__salt__['pip.list'](prefix, bin_env,
|
||||
user=user, cwd=cwd,
|
||||
env_vars=env_vars,
|
||||
**kwargs)
|
||||
)
|
||||
|
||||
# If we didn't find the package in the system after
|
||||
# installing it report it
|
||||
@ -917,12 +903,10 @@ def installed(name,
|
||||
'\'pip.freeze\'.'.format(pkg)
|
||||
)
|
||||
else:
|
||||
pkg_name = _find_key(prefix, pipsearch)
|
||||
if pkg_name.lower() in already_installed_packages:
|
||||
continue
|
||||
ver = pipsearch[pkg_name]
|
||||
ret['changes']['{0}=={1}'.format(pkg_name,
|
||||
ver)] = 'Installed'
|
||||
if prefix in pipsearch \
|
||||
and prefix.lower() not in already_installed_packages:
|
||||
ver = pipsearch[prefix]
|
||||
ret['changes']['{0}=={1}'.format(prefix, ver)] = 'Installed'
|
||||
# Case for packages that are an URL
|
||||
else:
|
||||
ret['changes']['{0}==???'.format(state_name)] = 'Installed'
|
||||
|
@ -261,7 +261,7 @@ def set_(name,
|
||||
for p_name in current_policy[policy_data['output_section']]:
|
||||
if policy_name.lower() == p_name.lower():
|
||||
currently_set = True
|
||||
pol_id = policy_name
|
||||
pol_id = p_name
|
||||
break
|
||||
# Check aliases
|
||||
else:
|
||||
|
@ -109,7 +109,15 @@ def creds(provider):
|
||||
__Expiration__ = data['Expiration']
|
||||
return __AccessKeyId__, __SecretAccessKey__, __Token__
|
||||
else:
|
||||
return provider['id'], provider['key'], ''
|
||||
ret_credentials = provider['id'], provider['key'], ''
|
||||
|
||||
if provider.get('role_arn') is not None:
|
||||
provider_shadow = provider.copy()
|
||||
provider_shadow.pop("role_arn", None)
|
||||
log.info("Assuming the role: %s", provider.get('role_arn'))
|
||||
ret_credentials = assumed_creds(provider_shadow, role_arn=provider.get('role_arn'), location='us-east-1')
|
||||
|
||||
return ret_credentials
|
||||
|
||||
|
||||
def sig2(method, endpoint, params, provider, aws_api_version):
|
||||
|
@ -8,6 +8,7 @@ from __future__ import absolute_import, print_function, unicode_literals
|
||||
import sys
|
||||
import copy
|
||||
import types
|
||||
import importlib
|
||||
|
||||
# Import salt libs
|
||||
import salt.loader
|
||||
@ -58,3 +59,13 @@ def cmp(x, y):
|
||||
Return negative if x<y, zero if x==y, positive if x>y.
|
||||
'''
|
||||
return (x > y) - (x < y)
|
||||
|
||||
|
||||
def reload(mod):
|
||||
'''
|
||||
Compatibility helper function to replace the ``reload`` builtin from Python 2.
|
||||
'''
|
||||
try:
|
||||
return importlib.reload(mod)
|
||||
except AttributeError:
|
||||
return reload(mod)
|
||||
|
@ -13,9 +13,9 @@ import logging
|
||||
import re
|
||||
|
||||
try:
|
||||
from collections.abc import Mapping
|
||||
from collections.abc import Mapping, MutableMapping, Sequence
|
||||
except ImportError:
|
||||
from collections import Mapping
|
||||
from collections import Mapping, MutableMapping, Sequence
|
||||
|
||||
# Import Salt libs
|
||||
import salt.utils.dictupdate
|
||||
@ -24,6 +24,7 @@ import salt.utils.yaml
|
||||
from salt.defaults import DEFAULT_TARGET_DELIM
|
||||
from salt.exceptions import SaltException
|
||||
from salt.utils.decorators.jinja import jinja_filter
|
||||
from salt.utils.odict import OrderedDict
|
||||
|
||||
# Import 3rd-party libs
|
||||
from salt.ext import six
|
||||
@ -32,6 +33,87 @@ from salt.ext.six.moves import range # pylint: disable=redefined-builtin
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CaseInsensitiveDict(MutableMapping):
|
||||
'''
|
||||
Inspired by requests' case-insensitive dict implementation, but works with
|
||||
non-string keys as well.
|
||||
'''
|
||||
def __init__(self, init=None, **kwargs):
|
||||
'''
|
||||
Force internal dict to be ordered to ensure a consistent iteration
|
||||
order, irrespective of case.
|
||||
'''
|
||||
self._data = OrderedDict()
|
||||
self.update(init or {}, **kwargs)
|
||||
|
||||
def __len__(self):
|
||||
return len(self._data)
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
# Store the case-sensitive key so it is available for dict iteration
|
||||
self._data[to_lowercase(key)] = (key, value)
|
||||
|
||||
def __delitem__(self, key):
|
||||
del self._data[to_lowercase(key)]
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self._data[to_lowercase(key)][1]
|
||||
|
||||
def __iter__(self):
|
||||
return (item[0] for item in six.itervalues(self._data))
|
||||
|
||||
def __eq__(self, rval):
|
||||
if not isinstance(rval, Mapping):
|
||||
# Comparing to non-mapping type (e.g. int) is always False
|
||||
return False
|
||||
return dict(self.items_lower()) == dict(CaseInsensitiveDict(rval).items_lower())
|
||||
|
||||
def __repr__(self):
|
||||
return repr(dict(six.iteritems(self)))
|
||||
|
||||
def items_lower(self):
|
||||
'''
|
||||
Returns a generator iterating over keys and values, with the keys all
|
||||
being lowercase.
|
||||
'''
|
||||
return ((key, val[1]) for key, val in six.iteritems(self._data))
|
||||
|
||||
def copy(self):
|
||||
'''
|
||||
Returns a copy of the object
|
||||
'''
|
||||
return CaseInsensitiveDict(six.iteritems(self._data))
|
||||
|
||||
|
||||
def __change_case(data, attr, preserve_dict_class=False):
|
||||
try:
|
||||
return getattr(data, attr)()
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
data_type = data.__class__
|
||||
|
||||
if isinstance(data, Mapping):
|
||||
return (data_type if preserve_dict_class else dict)(
|
||||
(__change_case(key, attr, preserve_dict_class),
|
||||
__change_case(val, attr, preserve_dict_class))
|
||||
for key, val in six.iteritems(data)
|
||||
)
|
||||
elif isinstance(data, Sequence):
|
||||
return data_type(
|
||||
__change_case(item, attr, preserve_dict_class) for item in data)
|
||||
else:
|
||||
return data
|
||||
|
||||
|
||||
def to_lowercase(data, preserve_dict_class=False):
|
||||
return __change_case(data, 'lower', preserve_dict_class)
|
||||
|
||||
|
||||
def to_uppercase(data, preserve_dict_class=False):
|
||||
return __change_case(data, 'upper', preserve_dict_class)
|
||||
|
||||
|
||||
@jinja_filter('compare_dicts')
|
||||
def compare_dicts(old=None, new=None):
|
||||
'''
|
||||
|
@ -23,6 +23,7 @@ import shlex
|
||||
import socket
|
||||
import ssl
|
||||
import string
|
||||
import functools
|
||||
|
||||
# Import Salt libs
|
||||
import salt.utils.files
|
||||
@ -364,12 +365,13 @@ def _lookup_host(name, rdtype, timeout=None, server=None):
|
||||
'''
|
||||
cmd = 'host -t {0} '.format(rdtype)
|
||||
|
||||
if server is not None:
|
||||
cmd += '@{0} '.format(server)
|
||||
if timeout:
|
||||
cmd += '-W {0} '.format(int(timeout))
|
||||
cmd += name
|
||||
if server is not None:
|
||||
cmd += ' {0}'.format(server)
|
||||
|
||||
cmd = __salt__['cmd.run_all'](cmd + name, python_shell=False, output_loglevel='quiet')
|
||||
cmd = __salt__['cmd.run_all'](cmd, python_shell=False, output_loglevel='quiet')
|
||||
|
||||
if 'invalid type' in cmd['stderr']:
|
||||
raise ValueError('Invalid DNS type {}'.format(rdtype))
|
||||
@ -380,7 +382,8 @@ def _lookup_host(name, rdtype, timeout=None, server=None):
|
||||
return []
|
||||
|
||||
res = []
|
||||
for line in cmd['stdout'].splitlines():
|
||||
_stdout = cmd['stdout'] if server is None else cmd['stdout'].split('\n\n')[-1]
|
||||
for line in _stdout.splitlines():
|
||||
if rdtype != 'CNAME' and 'is an alias' in line:
|
||||
continue
|
||||
line = line.split(' ', 3)[-1]
|
||||
@ -563,12 +566,15 @@ def lookup(
|
||||
timeout /= len(servers)
|
||||
|
||||
# Inject a wrapper for multi-server behaviour
|
||||
def _multi_srvr(**res_kwargs):
|
||||
for server in servers:
|
||||
s_res = resolver(server=server, **res_kwargs)
|
||||
if s_res:
|
||||
return s_res
|
||||
resolver = _multi_srvr
|
||||
def _multi_srvr(resolv_func):
|
||||
@functools.wraps(resolv_func)
|
||||
def _wrapper(**res_kwargs):
|
||||
for server in servers:
|
||||
s_res = resolv_func(server=server, **res_kwargs)
|
||||
if s_res:
|
||||
return s_res
|
||||
return _wrapper
|
||||
resolver = _multi_srvr(resolver)
|
||||
|
||||
if not walk:
|
||||
name = [name]
|
||||
|
@ -416,11 +416,13 @@ def flopen(*args, **kwargs):
|
||||
'''
|
||||
Shortcut for fopen with lock and context manager.
|
||||
'''
|
||||
with fopen(*args, **kwargs) as f_handle:
|
||||
filename, args = args[0], args[1:]
|
||||
writing = 'wa'
|
||||
with fopen(filename, *args, **kwargs) as f_handle:
|
||||
try:
|
||||
if is_fcntl_available(check_sunos=True):
|
||||
lock_type = fcntl.LOCK_SH
|
||||
if 'w' in args[1] or 'a' in args[1]:
|
||||
if args and any([write in args[0] for write in writing]):
|
||||
lock_type = fcntl.LOCK_EX
|
||||
fcntl.flock(f_handle.fileno(), lock_type)
|
||||
yield f_handle
|
||||
|
@ -1410,6 +1410,19 @@ class Pygit2(GitProvider):
|
||||
override_params, cache_root, role
|
||||
)
|
||||
|
||||
def peel(self, obj):
|
||||
'''
|
||||
Compatibility function for pygit2.Reference objects. Older versions of
|
||||
pygit2 use .get_object() to return the object to which the reference
|
||||
points, while newer versions use .peel(). In pygit2 0.27.4,
|
||||
.get_object() was removed. This function will try .peel() first and
|
||||
fall back to .get_object().
|
||||
'''
|
||||
try:
|
||||
return obj.peel()
|
||||
except AttributeError:
|
||||
return obj.get_object()
|
||||
|
||||
def checkout(self):
|
||||
'''
|
||||
Checkout the configured branch/tag
|
||||
@ -1428,7 +1441,7 @@ class Pygit2(GitProvider):
|
||||
return None
|
||||
|
||||
try:
|
||||
head_sha = local_head.get_object().hex
|
||||
head_sha = self.peel(local_head).hex
|
||||
except AttributeError:
|
||||
# Shouldn't happen, but just in case a future pygit2 API change
|
||||
# breaks things, avoid a traceback and log an error.
|
||||
@ -1477,7 +1490,7 @@ class Pygit2(GitProvider):
|
||||
try:
|
||||
if remote_ref in refs:
|
||||
# Get commit id for the remote ref
|
||||
oid = self.repo.lookup_reference(remote_ref).get_object().id
|
||||
oid = self.peel(self.repo.lookup_reference(remote_ref)).id
|
||||
if local_ref not in refs:
|
||||
# No local branch for this remote, so create one and point
|
||||
# it at the commit id of the remote ref
|
||||
@ -1485,7 +1498,7 @@ class Pygit2(GitProvider):
|
||||
|
||||
try:
|
||||
target_sha = \
|
||||
self.repo.lookup_reference(remote_ref).get_object().hex
|
||||
self.peel(self.repo.lookup_reference(remote_ref)).hex
|
||||
except KeyError:
|
||||
log.error(
|
||||
'pygit2 was unable to get SHA for %s in %s remote '
|
||||
@ -1857,8 +1870,8 @@ class Pygit2(GitProvider):
|
||||
refs/remotes/origin/
|
||||
'''
|
||||
try:
|
||||
return self.repo.lookup_reference(
|
||||
'refs/remotes/origin/{0}'.format(ref)).get_object().tree
|
||||
return self.peel(self.repo.lookup_reference(
|
||||
'refs/remotes/origin/{0}'.format(ref))).tree
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
@ -1867,8 +1880,8 @@ class Pygit2(GitProvider):
|
||||
Return a pygit2.Tree object matching a tag ref fetched into refs/tags/
|
||||
'''
|
||||
try:
|
||||
return self.repo.lookup_reference(
|
||||
'refs/tags/{0}'.format(ref)).get_object().tree
|
||||
return self.peel(self.repo.lookup_reference(
|
||||
'refs/tags/{0}'.format(ref))).tree
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
|
@ -149,7 +149,7 @@ def nodegroup_comp(nodegroup, nodegroups, skip=None, first_call=True):
|
||||
# No compound operators found in nodegroup definition. Check for
|
||||
# group type specifiers
|
||||
group_type_re = re.compile('^[A-Z]@')
|
||||
regex_chars = ['(', '[', '{', '\\', '?''}])']
|
||||
regex_chars = ['(', '[', '{', '\\', '?', '}', ']', ')']
|
||||
if not [x for x in ret if '*' in x or group_type_re.match(x)]:
|
||||
# No group type specifiers and no wildcards.
|
||||
# Treat this as an expression.
|
||||
|
@ -1935,7 +1935,7 @@ def parse_host_port(host_port):
|
||||
if _s_[0] == "[":
|
||||
if "]" in host_port:
|
||||
host, _s_ = _s_.lstrip("[").rsplit("]", 1)
|
||||
host = ipaddress.IPv6Address(host)
|
||||
host = ipaddress.IPv6Address(host).compressed
|
||||
if _s_[0] == ":":
|
||||
port = int(_s_.lstrip(":"))
|
||||
else:
|
||||
@ -1953,7 +1953,7 @@ def parse_host_port(host_port):
|
||||
host = _s_
|
||||
try:
|
||||
if not isinstance(host, ipaddress._BaseAddress):
|
||||
host_ip = ipaddress.ip_address(host)
|
||||
host_ip = ipaddress.ip_address(host).compressed
|
||||
host = host_ip
|
||||
except ValueError:
|
||||
log.debug('"%s" Not an IP address? Assuming it is a hostname.', host)
|
||||
|
@ -806,7 +806,7 @@ def default_signals(*signals):
|
||||
old_signals = {}
|
||||
for signum in signals:
|
||||
try:
|
||||
old_signals[signum] = signal.getsignal(signum)
|
||||
saved_signal = signal.getsignal(signum)
|
||||
signal.signal(signum, signal.SIG_DFL)
|
||||
except ValueError as exc:
|
||||
# This happens when a netapi module attempts to run a function
|
||||
@ -816,6 +816,8 @@ def default_signals(*signals):
|
||||
'Failed to register signal for signum %d: %s',
|
||||
signum, exc
|
||||
)
|
||||
else:
|
||||
old_signals[signum] = saved_signal
|
||||
|
||||
# Do whatever is needed with the reset signals
|
||||
yield
|
||||
|
@ -333,7 +333,9 @@ def build_whitespace_split_regex(text):
|
||||
lexer = shlex.shlex(text)
|
||||
lexer.whitespace_split = True
|
||||
lexer.commenters = ''
|
||||
if '\'' in text:
|
||||
if r"'\"" in text:
|
||||
lexer.quotes = ''
|
||||
elif '\'' in text:
|
||||
lexer.quotes = '"'
|
||||
elif '"' in text:
|
||||
lexer.quotes = '\''
|
||||
|
@ -14,13 +14,11 @@ import re
|
||||
import time
|
||||
|
||||
# Import salt libs
|
||||
import salt.utils.compat
|
||||
import salt.utils.data
|
||||
from salt.utils.timeout import wait_for
|
||||
import salt.ext.six as six
|
||||
|
||||
# Workaround for 'reload' builtin of py2.7
|
||||
if six.PY3:
|
||||
from importlib import reload # pylint: disable=no-name-in-module
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@ -140,7 +138,7 @@ def vb_get_manager():
|
||||
'''
|
||||
global _virtualboxManager
|
||||
if _virtualboxManager is None and HAS_LIBS:
|
||||
reload(vboxapi)
|
||||
salt.utils.compat.reload(vboxapi)
|
||||
_virtualboxManager = vboxapi.VirtualBoxManager(None, None)
|
||||
|
||||
return _virtualboxManager
|
||||
|
@ -3,7 +3,7 @@ r'''
|
||||
A salt util for modifying firewall settings.
|
||||
|
||||
.. versionadded:: 2018.3.4
|
||||
.. versionadded:: Fluorine
|
||||
.. versionadded:: 2019.2.0
|
||||
|
||||
This util allows you to modify firewall settings in the local group policy in
|
||||
addition to the normal firewall settings. Parameters are taken from the
|
||||
|
@ -55,7 +55,7 @@ import salt.log.setup
|
||||
from salt.utils.odict import OrderedDict
|
||||
|
||||
# Define the pytest plugins we rely on
|
||||
pytest_plugins = ['tempdir', 'helpers_namespace'] # pylint: disable=invalid-name
|
||||
pytest_plugins = ['tempdir', 'helpers_namespace', 'salt-from-filenames'] # pylint: disable=invalid-name
|
||||
|
||||
# Define where not to collect tests from
|
||||
collect_ignore = ['setup.py']
|
||||
|
@ -743,6 +743,12 @@ class TestDaemon(object):
|
||||
master_opts['root_dir'] = os.path.join(TMP, 'rootdir')
|
||||
master_opts['pki_dir'] = os.path.join(TMP, 'rootdir', 'pki', 'master')
|
||||
master_opts['syndic_master'] = 'localhost'
|
||||
file_tree = {
|
||||
'root_dir': os.path.join(FILES, 'pillar', 'base', 'file_tree'),
|
||||
'follow_dir_links': False,
|
||||
'keep_newline': True,
|
||||
}
|
||||
master_opts['ext_pillar'].append({'file_tree': file_tree})
|
||||
|
||||
# This is the syndic for master
|
||||
# Let's start with a copy of the syndic master configuration
|
||||
|
3
tests/integration/files/file/base/issue-50221.sls
Normal file
3
tests/integration/files/file/base/issue-50221.sls
Normal file
@ -0,0 +1,3 @@
|
||||
{{ pillar['name'] }}:
|
||||
file.managed:
|
||||
- contents_pillar: issue-50221
|
4
tests/integration/files/file/base/issue-51208.sls
Normal file
4
tests/integration/files/file/base/issue-51208.sls
Normal file
@ -0,0 +1,4 @@
|
||||
/tmp/vimrc:
|
||||
file.append:
|
||||
- sources:
|
||||
- salt://test/files/vimrc.stub
|
8
tests/integration/files/file/base/issue-51208/vimrc.stub
Normal file
8
tests/integration/files/file/base/issue-51208/vimrc.stub
Normal file
@ -0,0 +1,8 @@
|
||||
set number
|
||||
syntax on
|
||||
set paste
|
||||
set ruler
|
||||
if has("autocmd")
|
||||
au BufReadPost * if line("'\"") > 1 && line("'\"") <= line("$") | exe "normal! g'\"" | endif
|
||||
endif
|
||||
|
@ -0,0 +1,3 @@
|
||||
abc
|
||||
|
||||
|
@ -11,34 +11,28 @@ class DataModuleTest(ModuleCase):
|
||||
'''
|
||||
Validate the data module
|
||||
'''
|
||||
def _clear_db(self):
|
||||
'''
|
||||
Clear out the database
|
||||
'''
|
||||
def setUp(self):
|
||||
self.run_function('data.clear')
|
||||
self.addCleanup(self.run_function, 'data.clear')
|
||||
|
||||
def test_load_dump(self):
|
||||
'''
|
||||
data.load
|
||||
data.dump
|
||||
'''
|
||||
self._clear_db()
|
||||
self.assertTrue(self.run_function('data.dump', ['{"foo": "bar"}']))
|
||||
self.assertEqual(self.run_function('data.load'), {'foo': 'bar'})
|
||||
self._clear_db()
|
||||
|
||||
def test_get_update(self):
|
||||
'''
|
||||
data.get
|
||||
data.update
|
||||
'''
|
||||
self._clear_db()
|
||||
self.assertTrue(self.run_function('data.update', ['spam', 'eggs']))
|
||||
self.assertEqual(self.run_function('data.get', ['spam']), 'eggs')
|
||||
|
||||
self.assertTrue(self.run_function('data.update', ['unladen', 'swallow']))
|
||||
self.assertEqual(self.run_function('data.get', ['["spam", "unladen"]']), ['eggs', 'swallow'])
|
||||
self._clear_db()
|
||||
self.assertEqual(self.run_function('data.get', [["spam", "unladen"]]), ['eggs', 'swallow'])
|
||||
|
||||
def test_cas_update(self):
|
||||
'''
|
||||
@ -46,7 +40,6 @@ class DataModuleTest(ModuleCase):
|
||||
data.cas
|
||||
data.get
|
||||
'''
|
||||
self._clear_db()
|
||||
self.assertTrue(self.run_function('data.update', ['spam', 'eggs']))
|
||||
self.assertTrue(self.run_function('data.cas', ['spam', 'green', 'eggs']))
|
||||
self.assertEqual(self.run_function('data.get', ['spam']), 'green')
|
||||
|
@ -222,7 +222,7 @@ class SupervisordModuleTest(ModuleCase):
|
||||
ret = self.run_function(
|
||||
'supervisord.status', [], conf_file=self.supervisor_conf,
|
||||
bin_env=self.venv_dir)
|
||||
self.assertEqual(list(ret.keys()), ['sleep_service', 'sleep_service2'])
|
||||
self.assertEqual(sorted(ret), ['sleep_service', 'sleep_service2'])
|
||||
|
||||
def test_status_one(self):
|
||||
'''
|
||||
|
@ -100,6 +100,11 @@ class TestSaltAPIHandler(_SaltnadoIntegrationTestCase):
|
||||
)
|
||||
response_obj = salt.utils.json.loads(response.body)
|
||||
self.assertEqual(len(response_obj['return']), 1)
|
||||
# If --proxy is set, it will cause an extra minion_id to be in the
|
||||
# response. Since there's not a great way to know if the test
|
||||
# runner's proxy minion is running, and we're not testing proxy
|
||||
# minions here anyway, just remove it from the response.
|
||||
response_obj['return'][0].pop('proxytest', None)
|
||||
self.assertEqual(response_obj['return'][0], {'minion': True, 'sub_minion': True})
|
||||
|
||||
def test_simple_local_post_no_tgt(self):
|
||||
@ -142,6 +147,11 @@ class TestSaltAPIHandler(_SaltnadoIntegrationTestCase):
|
||||
)
|
||||
response_obj = salt.utils.json.loads(response.body)
|
||||
self.assertEqual(len(response_obj['return']), 1)
|
||||
# If --proxy is set, it will cause an extra minion_id to be in the
|
||||
# response. Since there's not a great way to know if the test
|
||||
# runner's proxy minion is running, and we're not testing proxy
|
||||
# minions here anyway, just remove it from the response.
|
||||
response_obj['return'][0].pop('proxytest', None)
|
||||
self.assertEqual(response_obj['return'][0], {'minion': True, 'sub_minion': True})
|
||||
|
||||
def test_simple_local_post_invalid_request(self):
|
||||
@ -175,6 +185,14 @@ class TestSaltAPIHandler(_SaltnadoIntegrationTestCase):
|
||||
response_obj = salt.utils.json.loads(response.body)
|
||||
ret = response_obj['return']
|
||||
ret[0]['minions'] = sorted(ret[0]['minions'])
|
||||
try:
|
||||
# If --proxy is set, it will cause an extra minion_id to be in the
|
||||
# response. Since there's not a great way to know if the test
|
||||
# runner's proxy minion is running, and we're not testing proxy
|
||||
# minions here anyway, just remove it from the response.
|
||||
ret[0]['minions'].remove('proxytest')
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
# TODO: verify pub function? Maybe look at how we test the publisher
|
||||
self.assertEqual(len(ret), 1)
|
||||
@ -201,6 +219,15 @@ class TestSaltAPIHandler(_SaltnadoIntegrationTestCase):
|
||||
ret = response_obj['return']
|
||||
ret[0]['minions'] = sorted(ret[0]['minions'])
|
||||
ret[1]['minions'] = sorted(ret[1]['minions'])
|
||||
try:
|
||||
# If --proxy is set, it will cause an extra minion_id to be in the
|
||||
# response. Since there's not a great way to know if the test
|
||||
# runner's proxy minion is running, and we're not testing proxy
|
||||
# minions here anyway, just remove it from the response.
|
||||
ret[0]['minions'].remove('proxytest')
|
||||
ret[1]['minions'].remove('proxytest')
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
self.assertEqual(len(ret), 2)
|
||||
self.assertIn('jid', ret[0])
|
||||
@ -235,6 +262,15 @@ class TestSaltAPIHandler(_SaltnadoIntegrationTestCase):
|
||||
ret = response_obj['return']
|
||||
ret[0]['minions'] = sorted(ret[0]['minions'])
|
||||
ret[1]['minions'] = sorted(ret[1]['minions'])
|
||||
try:
|
||||
# If --proxy is set, it will cause an extra minion_id to be in the
|
||||
# response. Since there's not a great way to know if the test
|
||||
# runner's proxy minion is running, and we're not testing proxy
|
||||
# minions here anyway, just remove it from the response.
|
||||
ret[0]['minions'].remove('proxytest')
|
||||
ret[1]['minions'].remove('proxytest')
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
self.assertEqual(len(ret), 3) # make sure we got 3 responses
|
||||
self.assertIn('jid', ret[0]) # the first 2 are regular returns
|
||||
@ -279,9 +315,13 @@ class TestSaltAPIHandler(_SaltnadoIntegrationTestCase):
|
||||
request_timeout=30,
|
||||
)
|
||||
response_obj = salt.utils.json.loads(response.body)
|
||||
|
||||
self.application.opts['order_masters'] = []
|
||||
self.application.opts['syndic_wait'] = 5
|
||||
# If --proxy is set, it will cause an extra minion_id to be in the
|
||||
# response. Since there's not a great way to know if the test runner's
|
||||
# proxy minion is running, and we're not testing proxy minions here
|
||||
# anyway, just remove it from the response.
|
||||
response_obj[0]['return'].pop('proxytest', None)
|
||||
self.assertEqual(response_obj['return'], [{'minion': True, 'sub_minion': True}])
|
||||
|
||||
# runner tests
|
||||
@ -299,7 +339,15 @@ class TestSaltAPIHandler(_SaltnadoIntegrationTestCase):
|
||||
)
|
||||
response_obj = salt.utils.json.loads(response.body)
|
||||
self.assertEqual(len(response_obj['return']), 1)
|
||||
self.assertEqual(set(response_obj['return'][0]), set(['minion', 'sub_minion']))
|
||||
try:
|
||||
# If --proxy is set, it will cause an extra minion_id to be in the
|
||||
# response. Since there's not a great way to know if the test
|
||||
# runner's proxy minion is running, and we're not testing proxy
|
||||
# minions here anyway, just remove it from the response.
|
||||
response_obj['return'][0].remove('proxytest')
|
||||
except ValueError:
|
||||
pass
|
||||
self.assertEqual(sorted(response_obj['return'][0]), sorted(['minion', 'sub_minion']))
|
||||
|
||||
# runner_async tests
|
||||
def test_simple_local_runner_async_post(self):
|
||||
|
@ -36,6 +36,11 @@ class NetapiClientTest(TestCase):
|
||||
low.update(self.eauth_creds)
|
||||
|
||||
ret = self.netapi.run(low)
|
||||
# If --proxy is set, it will cause an extra minion_id to be in the
|
||||
# response. Since there's not a great way to know if the test
|
||||
# runner's proxy minion is running, and we're not testing proxy
|
||||
# minions here anyway, just remove it from the response.
|
||||
ret.pop('proxytest', None)
|
||||
self.assertEqual(ret, {'minion': True, 'sub_minion': True})
|
||||
|
||||
def test_local_batch(self):
|
||||
@ -59,6 +64,14 @@ class NetapiClientTest(TestCase):
|
||||
self.assertIn('jid', ret)
|
||||
ret.pop('jid', None)
|
||||
ret['minions'] = sorted(ret['minions'])
|
||||
try:
|
||||
# If --proxy is set, it will cause an extra minion_id to be in the
|
||||
# response. Since there's not a great way to know if the test
|
||||
# runner's proxy minion is running, and we're not testing proxy
|
||||
# minions here anyway, just remove it from the response.
|
||||
ret['minions'].remove('proxytest')
|
||||
except ValueError:
|
||||
pass
|
||||
self.assertEqual(ret, {'minions': sorted(['minion', 'sub_minion'])})
|
||||
|
||||
def test_wheel(self):
|
||||
|
@ -2530,6 +2530,42 @@ class FileTest(ModuleCase, SaltReturnAssertsMixin):
|
||||
'',
|
||||
]).encode('utf-8'))
|
||||
|
||||
@with_tempfile()
|
||||
def test_issue_50221(self, name):
|
||||
expected = 'abc{0}{0}{0}'.format(os.linesep)
|
||||
ret = self.run_function(
|
||||
'pillar.get',
|
||||
['issue-50221']
|
||||
)
|
||||
assert ret == expected
|
||||
ret = self.run_function(
|
||||
'state.apply',
|
||||
['issue-50221'],
|
||||
pillar={
|
||||
'name': name
|
||||
},
|
||||
)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
with salt.utils.files.fopen(name, 'r') as fp:
|
||||
contents = fp.read()
|
||||
assert contents == expected
|
||||
|
||||
def test_managed_file_issue_51208(self):
|
||||
'''
|
||||
Test to ensure we can handle a file with escaped double-quotes
|
||||
'''
|
||||
name = os.path.join(TMP, 'issue_51208.txt')
|
||||
ret = self.run_state(
|
||||
'file.managed', name=name, source='salt://issue-51208/vimrc.stub'
|
||||
)
|
||||
src = os.path.join(BASE_FILES, 'issue-51208', 'vimrc.stub')
|
||||
with salt.utils.files.fopen(src, 'r') as fp_:
|
||||
master_data = fp_.read()
|
||||
with salt.utils.files.fopen(name, 'r') as fp_:
|
||||
minion_data = fp_.read()
|
||||
self.assertEqual(master_data, minion_data)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
|
||||
|
||||
class BlockreplaceTest(ModuleCase, SaltReturnAssertsMixin):
|
||||
marker_start = '# start'
|
||||
|
@ -44,7 +44,7 @@ _PKG_TARGETS = {
|
||||
}
|
||||
|
||||
_PKG_CAP_TARGETS = {
|
||||
'Suse': [('w3m_ssl', 'w3m')],
|
||||
'Suse': [('perl(ZNC)', 'znc-perl')],
|
||||
}
|
||||
|
||||
_PKG_TARGETS_32 = {
|
||||
@ -821,12 +821,14 @@ class PkgTest(ModuleCase, SaltReturnAssertsMixin):
|
||||
self.assertFalse(version)
|
||||
self.assertFalse(realver)
|
||||
|
||||
ret = self.run_state('pkg.installed', name=target, refresh=False, resolve_capabilities=True, test=True)
|
||||
self.assertInSaltComment("The following packages would be installed/updated: {0}".format(realpkg), ret)
|
||||
ret = self.run_state('pkg.installed', name=target, refresh=False, resolve_capabilities=True)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
ret = self.run_state('pkg.removed', name=realpkg)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
try:
|
||||
ret = self.run_state('pkg.installed', name=target, refresh=False, resolve_capabilities=True, test=True)
|
||||
self.assertInSaltComment("The following packages would be installed/updated: {0}".format(realpkg), ret)
|
||||
ret = self.run_state('pkg.installed', name=target, refresh=False, resolve_capabilities=True)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
finally:
|
||||
ret = self.run_state('pkg.removed', name=realpkg)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
|
||||
@skipIf(salt.utils.platform.is_windows(), 'minion is windows')
|
||||
@requires_system_grains
|
||||
@ -853,18 +855,22 @@ class PkgTest(ModuleCase, SaltReturnAssertsMixin):
|
||||
self.assertFalse(version)
|
||||
self.assertFalse(realver)
|
||||
|
||||
# install the package already
|
||||
ret = self.run_state('pkg.installed', name=realpkg, refresh=False)
|
||||
try:
|
||||
# install the package
|
||||
ret = self.run_state('pkg.installed', name=realpkg, refresh=False)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
|
||||
ret = self.run_state('pkg.installed', name=target, refresh=False, resolve_capabilities=True, test=True)
|
||||
self.assertInSaltComment("All specified packages are already installed", ret)
|
||||
# Try to install again. Nothing should be installed this time.
|
||||
ret = self.run_state('pkg.installed', name=target, refresh=False, resolve_capabilities=True, test=True)
|
||||
self.assertInSaltComment("All specified packages are already installed", ret)
|
||||
|
||||
ret = self.run_state('pkg.installed', name=target, refresh=False, resolve_capabilities=True)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
ret = self.run_state('pkg.installed', name=target, refresh=False, resolve_capabilities=True)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
|
||||
self.assertInSaltComment("packages are already installed", ret)
|
||||
ret = self.run_state('pkg.removed', name=realpkg)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
self.assertInSaltComment("packages are already installed", ret)
|
||||
finally:
|
||||
ret = self.run_state('pkg.removed', name=realpkg)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
|
||||
@skipIf(salt.utils.platform.is_windows(), 'minion is windows')
|
||||
@requires_system_grains
|
||||
@ -890,8 +896,8 @@ class PkgTest(ModuleCase, SaltReturnAssertsMixin):
|
||||
# Make sure that we have targets that match the os_family. If this
|
||||
# fails then the _PKG_TARGETS dict above needs to have an entry added,
|
||||
# with two packages that are not installed before these tests are run
|
||||
self.assertTrue(bool(pkg_cap_targets))
|
||||
self.assertTrue(bool(pkg_targets))
|
||||
self.assertTrue(pkg_cap_targets)
|
||||
self.assertTrue(pkg_targets)
|
||||
|
||||
if os_family == 'Arch':
|
||||
for idx in range(13):
|
||||
@ -909,34 +915,36 @@ class PkgTest(ModuleCase, SaltReturnAssertsMixin):
|
||||
# If this assert fails, we need to find new targets, this test needs to
|
||||
# be able to test successful installation of packages, so these
|
||||
# packages need to not be installed before we run the states below
|
||||
self.assertTrue(bool(version))
|
||||
self.assertTrue(bool(realver))
|
||||
self.assertTrue(version)
|
||||
self.assertTrue(realver)
|
||||
|
||||
pkgs = [{pkg_targets[0]: version}, pkg_targets[1], {capability: realver}]
|
||||
ret = self.run_state('pkg.installed',
|
||||
name='test_pkg_cap_003_installed_multipkg_with_version-install',
|
||||
pkgs=pkgs,
|
||||
refresh=False)
|
||||
self.assertSaltFalseReturn(ret)
|
||||
try:
|
||||
pkgs = [{pkg_targets[0]: version}, pkg_targets[1], {capability: realver}]
|
||||
ret = self.run_state('pkg.installed',
|
||||
name='test_pkg_cap_003_installed_multipkg_with_version-install',
|
||||
pkgs=pkgs,
|
||||
refresh=False)
|
||||
self.assertSaltFalseReturn(ret)
|
||||
|
||||
ret = self.run_state('pkg.installed',
|
||||
name='test_pkg_cap_003_installed_multipkg_with_version-install-capability',
|
||||
pkgs=pkgs,
|
||||
refresh=False, resolve_capabilities=True, test=True)
|
||||
self.assertInSaltComment("packages would be installed/updated", ret)
|
||||
self.assertInSaltComment("{0}={1}".format(realpkg, realver), ret)
|
||||
ret = self.run_state('pkg.installed',
|
||||
name='test_pkg_cap_003_installed_multipkg_with_version-install-capability',
|
||||
pkgs=pkgs,
|
||||
refresh=False, resolve_capabilities=True, test=True)
|
||||
self.assertInSaltComment("packages would be installed/updated", ret)
|
||||
self.assertInSaltComment("{0}={1}".format(realpkg, realver), ret)
|
||||
|
||||
ret = self.run_state('pkg.installed',
|
||||
name='test_pkg_cap_003_installed_multipkg_with_version-install-capability',
|
||||
pkgs=pkgs,
|
||||
refresh=False, resolve_capabilities=True)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
cleanup_pkgs = pkg_targets
|
||||
cleanup_pkgs.append(realpkg)
|
||||
ret = self.run_state('pkg.removed',
|
||||
name='test_pkg_cap_003_installed_multipkg_with_version-remove',
|
||||
pkgs=cleanup_pkgs)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
ret = self.run_state('pkg.installed',
|
||||
name='test_pkg_cap_003_installed_multipkg_with_version-install-capability',
|
||||
pkgs=pkgs,
|
||||
refresh=False, resolve_capabilities=True)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
cleanup_pkgs = pkg_targets
|
||||
cleanup_pkgs.append(realpkg)
|
||||
finally:
|
||||
ret = self.run_state('pkg.removed',
|
||||
name='test_pkg_cap_003_installed_multipkg_with_version-remove',
|
||||
pkgs=cleanup_pkgs)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
|
||||
@skipIf(salt.utils.platform.is_windows(), 'minion is windows')
|
||||
@requires_system_grains
|
||||
@ -964,17 +972,18 @@ class PkgTest(ModuleCase, SaltReturnAssertsMixin):
|
||||
self.assertFalse(version)
|
||||
self.assertFalse(realver)
|
||||
|
||||
ret = self.run_state('pkg.latest', name=target, refresh=False, resolve_capabilities=True, test=True)
|
||||
self.assertInSaltComment("The following packages would be installed/upgraded: {0}".format(realpkg), ret)
|
||||
ret = self.run_state('pkg.latest', name=target, refresh=False, resolve_capabilities=True)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
try:
|
||||
ret = self.run_state('pkg.latest', name=target, refresh=False, resolve_capabilities=True, test=True)
|
||||
self.assertInSaltComment("The following packages would be installed/upgraded: {0}".format(realpkg), ret)
|
||||
ret = self.run_state('pkg.latest', name=target, refresh=False, resolve_capabilities=True)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
|
||||
ret = self.run_state('pkg.latest', name=target, refresh=False, resolve_capabilities=True)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
self.assertInSaltComment("is already up-to-date", ret)
|
||||
|
||||
ret = self.run_state('pkg.removed', name=realpkg)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
ret = self.run_state('pkg.latest', name=target, refresh=False, resolve_capabilities=True)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
self.assertInSaltComment("is already up-to-date", ret)
|
||||
finally:
|
||||
ret = self.run_state('pkg.removed', name=realpkg)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
|
||||
@skipIf(salt.utils.platform.is_windows(), 'minion is windows')
|
||||
@requires_system_grains
|
||||
@ -1035,23 +1044,20 @@ class PkgTest(ModuleCase, SaltReturnAssertsMixin):
|
||||
self.assertFalse(version)
|
||||
self.assertFalse(realver)
|
||||
|
||||
ret = self.run_state('pkg.installed', name=target,
|
||||
refresh=False, resolve_capabilities=True)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
ret = self.run_state('pkg.uptodate',
|
||||
name='test_pkg_cap_006_uptodate',
|
||||
pkgs=[target],
|
||||
refresh=False,
|
||||
resolve_capabilities=True)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
self.assertInSaltComment("System is already up-to-date", ret)
|
||||
ret = self.run_state('pkg.removed', name=realpkg)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
ret = self.run_state('pkg.uptodate',
|
||||
name='test_pkg_cap_006_uptodate',
|
||||
refresh=False,
|
||||
test=True)
|
||||
self.assertInSaltComment("System update will be performed", ret)
|
||||
try:
|
||||
ret = self.run_state('pkg.installed', name=target,
|
||||
refresh=False, resolve_capabilities=True)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
ret = self.run_state('pkg.uptodate',
|
||||
name='test_pkg_cap_006_uptodate',
|
||||
pkgs=[target],
|
||||
refresh=False,
|
||||
resolve_capabilities=True)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
self.assertInSaltComment("System is already up-to-date", ret)
|
||||
finally:
|
||||
ret = self.run_state('pkg.removed', name=realpkg)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
|
||||
@requires_salt_modules('pkg.hold', 'pkg.unhold')
|
||||
@requires_system_grains
|
||||
|
@ -267,9 +267,18 @@ class ShellTestCase(TestCase, AdaptedConfigurationTestCaseMixin):
|
||||
script_path = self.get_script_path(script)
|
||||
if not os.path.isfile(script_path):
|
||||
return False
|
||||
popen_kwargs = popen_kwargs or {}
|
||||
|
||||
if salt.utils.platform.is_windows():
|
||||
cmd = 'python '
|
||||
if 'cwd' not in popen_kwargs:
|
||||
popen_kwargs['cwd'] = os.getcwd()
|
||||
if 'env' not in popen_kwargs:
|
||||
popen_kwargs['env'] = os.environ.copy()
|
||||
if sys.version_info[0] < 3:
|
||||
popen_kwargs['env'][b'PYTHONPATH'] = os.getcwd().encode()
|
||||
else:
|
||||
popen_kwargs['env']['PYTHONPATH'] = os.getcwd()
|
||||
else:
|
||||
cmd = 'PYTHONPATH='
|
||||
python_path = os.environ.get('PYTHONPATH', None)
|
||||
@ -286,7 +295,6 @@ class ShellTestCase(TestCase, AdaptedConfigurationTestCaseMixin):
|
||||
|
||||
tmp_file = tempfile.SpooledTemporaryFile()
|
||||
|
||||
popen_kwargs = popen_kwargs or {}
|
||||
popen_kwargs = dict({
|
||||
'shell': True,
|
||||
'stdout': tmp_file,
|
||||
|
11
tests/support/coverage/sitecustomize.py
Normal file
11
tests/support/coverage/sitecustomize.py
Normal file
@ -0,0 +1,11 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Python will always try to import sitecustomize.
|
||||
We use that fact to try and support code coverage for sub-processes
|
||||
'''
|
||||
from __future__ import absolute_import
|
||||
try:
|
||||
import coverage
|
||||
coverage.process_startup()
|
||||
except ImportError:
|
||||
pass
|
44
tests/tox-helper.py
Normal file
44
tests/tox-helper.py
Normal file
@ -0,0 +1,44 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# This script exists so that path handling when running tox works for both Linux and Windows
|
||||
|
||||
# Import Python Libs
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
import os
|
||||
import shutil
|
||||
import argparse
|
||||
import tempfile
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
'--rootdir',
|
||||
default=os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
|
||||
)
|
||||
subparsers = parser.add_subparsers(help='sub-command help', dest='subparser')
|
||||
|
||||
subparsers.add_parser('create-dirs')
|
||||
subparsers.add_parser('move-artifacts')
|
||||
|
||||
options = parser.parse_args()
|
||||
if options.subparser == 'create-dirs':
|
||||
for dirname in ('logs', 'coverage', 'xml-unittests-output'):
|
||||
path = os.path.join(options.rootdir, 'artifacts', dirname)
|
||||
if not os.path.exists(path):
|
||||
os.makedirs(path)
|
||||
|
||||
if options.subparser == 'move-artifacts':
|
||||
tmp_artifacts_dir = os.path.join(tempfile.gettempdir(), 'artifacts')
|
||||
if not os.path.exists(tmp_artifacts_dir):
|
||||
os.makedirs(tmp_artifacts_dir)
|
||||
|
||||
for dirname in ('logs', 'coverage', 'xml-unittests-output'):
|
||||
src = os.path.join(options.rootdir, 'artifacts', dirname)
|
||||
dst = os.path.join(tmp_artifacts_dir, dirname)
|
||||
shutil.copytree(src, dst)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
@ -1 +1,70 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
tests.unit.cloud
|
||||
~~~~~~~~~~~~~~~~
|
||||
'''
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
from tests.support.unit import TestCase
|
||||
|
||||
import salt.cloud
|
||||
|
||||
|
||||
class CloudTest(TestCase):
|
||||
|
||||
def test_vm_config_merger(self):
|
||||
'''
|
||||
Validate the vm's config is generated correctly.
|
||||
|
||||
https://github.com/saltstack/salt/issues/49226
|
||||
'''
|
||||
main = {
|
||||
'minion': {'master': '172.31.39.213'},
|
||||
'log_file': 'var/log/salt/cloud.log',
|
||||
'pool_size': 10
|
||||
}
|
||||
provider = {
|
||||
'private_key': 'dwoz.pem',
|
||||
'grains': {'foo1': 'bar', 'foo2': 'bang'},
|
||||
'availability_zone': 'us-west-2b',
|
||||
'driver': 'ec2',
|
||||
'ssh_interface': 'private_ips',
|
||||
'ssh_username': 'admin',
|
||||
'location': 'us-west-2'
|
||||
}
|
||||
profile = {
|
||||
'profile': 'default',
|
||||
'grains': {'meh2': 'bar', 'meh1': 'foo'},
|
||||
'provider': 'ec2-default:ec2',
|
||||
'ssh_username': 'admin',
|
||||
'image': 'ami-0a1fbca0e5b419fd1',
|
||||
'size': 't2.micro'
|
||||
}
|
||||
vm = salt.cloud.Cloud.vm_config(
|
||||
'test_vm',
|
||||
main,
|
||||
provider,
|
||||
profile,
|
||||
{}
|
||||
)
|
||||
self.assertEqual({
|
||||
'minion': {'master': '172.31.39.213'},
|
||||
'log_file': 'var/log/salt/cloud.log',
|
||||
'pool_size': 10,
|
||||
'private_key': 'dwoz.pem',
|
||||
'grains': {
|
||||
'foo1': 'bar',
|
||||
'foo2': 'bang',
|
||||
'meh2': 'bar',
|
||||
'meh1': 'foo',
|
||||
},
|
||||
'availability_zone': 'us-west-2b',
|
||||
'driver': 'ec2',
|
||||
'ssh_interface': 'private_ips',
|
||||
'ssh_username': 'admin',
|
||||
'location': 'us-west-2',
|
||||
'profile': 'default',
|
||||
'provider': 'ec2-default:ec2',
|
||||
'image': 'ami-0a1fbca0e5b419fd1',
|
||||
'size': 't2.micro',
|
||||
'name': 'test_vm',
|
||||
}, vm)
|
||||
|
@ -135,26 +135,12 @@ class InspectorFSDBTestCase(TestCase):
|
||||
csvdb.open()
|
||||
csvdb.create_table_from_object(FoobarEntity())
|
||||
|
||||
sorted_writable_data = sorted(writable.data[0].strip().split(','))
|
||||
if six.PY2:
|
||||
assert writable.data[0].strip() == "foo:int,bar:unicode,spam:float"
|
||||
sorted_expected_data = sorted("foo:int,bar:unicode,spam:float".split(','))
|
||||
else:
|
||||
# Order in PY3 is not the same for every run
|
||||
writable_data = writable.data[0].strip()
|
||||
assert_order_options = ['bar:str,foo:int,spam:float',
|
||||
'bar:str,spam:float,foo:int',
|
||||
'foo:int,spam:float,bar:str',
|
||||
'foo:int,bar:str,spam:float',
|
||||
'spam:float,foo:int,bar:str',
|
||||
'spam:float,bar:str,foo:int']
|
||||
while assert_order_options:
|
||||
assert_option = assert_order_options.pop()
|
||||
try:
|
||||
assert writable_data == assert_option
|
||||
break
|
||||
except AssertionError:
|
||||
if not assert_order_options:
|
||||
raise
|
||||
continue
|
||||
sorted_expected_data = sorted("foo:int,bar:str,spam:float".split(','))
|
||||
self.assertEqual(sorted_writable_data, sorted_expected_data)
|
||||
|
||||
def test_list_databases(self):
|
||||
'''
|
||||
|
@ -118,9 +118,12 @@ class CassandraTestCase(TestCase, LoaderModuleMockMixin):
|
||||
self.assertCountEqual(cassandra.column_families(),
|
||||
{'A': ['a', 'b'], 'B': ['c', 'd']})
|
||||
else:
|
||||
self.assertEqual(cassandra.column_families('A'),
|
||||
self.assertEqual(sorted(cassandra.column_families('A')),
|
||||
['a', 'b'])
|
||||
self.assertEqual(cassandra.column_families(),
|
||||
column_families = cassandra.column_families()
|
||||
for key in ('A', 'B'):
|
||||
column_families[key] = sorted(column_families[key])
|
||||
self.assertEqual(column_families,
|
||||
{'A': ['a', 'b'], 'B': ['c', 'd']})
|
||||
|
||||
def test_column_family_definition(self):
|
||||
|
@ -54,10 +54,11 @@ class PillarModuleTestCase(TestCase, LoaderModuleMockMixin):
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
def test_ls(self):
|
||||
with patch('salt.modules.pillar.items', MagicMock(return_value=pillar_value_1)):
|
||||
ls = sorted(pillarmod.ls())
|
||||
if six.PY3:
|
||||
self.assertCountEqual(pillarmod.ls(), ['a', 'b'])
|
||||
self.assertCountEqual(ls, ['a', 'b'])
|
||||
else:
|
||||
self.assertEqual(pillarmod.ls(), ['a', 'b'])
|
||||
self.assertEqual(ls, ['a', 'b'])
|
||||
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
def test_pillar_get_default_merge(self):
|
||||
|
@ -136,7 +136,7 @@ c9bcgp7D7xD+TxWWNj4CSXEccJgGr91StV+gFg4ARQ==
|
||||
'''
|
||||
ret = x509.create_private_key(text=True,
|
||||
passphrase='super_secret_passphrase')
|
||||
self.assertIn(b'BEGIN RSA PRIVATE KEY', ret)
|
||||
self.assertIn('BEGIN RSA PRIVATE KEY', ret)
|
||||
|
||||
@skipIf(not HAS_M2CRYPTO, 'Skipping, M2Crypto is unavailble')
|
||||
def test_create_certificate(self):
|
||||
@ -176,7 +176,7 @@ c9bcgp7D7xD+TxWWNj4CSXEccJgGr91StV+gFg4ARQ==
|
||||
authorityKeyIdentifier='keyid,issuer:always',
|
||||
days_valid=3650,
|
||||
days_remaining=0)
|
||||
self.assertIn(b'BEGIN CERTIFICATE', ret)
|
||||
self.assertIn('BEGIN CERTIFICATE', ret)
|
||||
|
||||
@skipIf(not HAS_M2CRYPTO, 'Skipping, M2Crypto is unavailble')
|
||||
def test_create_crl(self):
|
||||
@ -240,7 +240,7 @@ c9bcgp7D7xD+TxWWNj4CSXEccJgGr91StV+gFg4ARQ==
|
||||
os.remove(ca_crl_file.name)
|
||||
|
||||
# Ensure that a CRL was actually created
|
||||
self.assertIn(b'BEGIN X509 CRL', crl)
|
||||
self.assertIn('BEGIN X509 CRL', crl)
|
||||
|
||||
@skipIf(not HAS_M2CRYPTO, 'Skipping, M2Crypto is unavailble')
|
||||
def test_revoke_certificate_with_crl(self):
|
||||
|
@ -152,7 +152,7 @@ class TestSerializers(TestCase):
|
||||
|
||||
# BLAAM! yml_src is not valid !
|
||||
final_obj = OrderedDict(yaml.deserialize(yml_src))
|
||||
assert obj != final_obj
|
||||
assert obj != final_obj, 'Objects matched! {} == {}'.format(obj, final_obj)
|
||||
|
||||
@skipIf(not yamlex.available, SKIP_MESSAGE % 'sls')
|
||||
def test_sls_aggregate(self):
|
||||
|
@ -60,6 +60,7 @@ class GitTestCase(TestCase, LoaderModuleMockMixin):
|
||||
git_diff = Mock()
|
||||
dunder_salt = {
|
||||
'git.current_branch': MagicMock(return_value=branches[0]),
|
||||
'git.config_get_regexp': MagicMock(return_value={}),
|
||||
'git.diff': git_diff,
|
||||
'git.fetch': MagicMock(return_value={}),
|
||||
'git.is_worktree': MagicMock(return_value=False),
|
||||
|
@ -14,9 +14,6 @@ from tests.support.mock import (
|
||||
call
|
||||
)
|
||||
|
||||
# Import 3rd-party libs
|
||||
from salt.ext import six
|
||||
|
||||
# Import Salt Libs
|
||||
import salt.states.proxy as proxy
|
||||
|
||||
@ -70,9 +67,7 @@ class ProxyTestCase(TestCase, LoaderModuleMockMixin):
|
||||
with patch.dict(proxy.__salt__, patches):
|
||||
out = proxy.managed('192.168.0.1', '3128', user='frank', password='passw0rd',
|
||||
bypass_domains=['salt.com', 'test.com'])
|
||||
if six.PY3:
|
||||
# Sorting is different in Py3
|
||||
out['changes']['new'][-1]['bypass_domains'] = sorted(out['changes']['new'][-1]['bypass_domains'])
|
||||
out['changes']['new'][-1]['bypass_domains'] = sorted(out['changes']['new'][-1]['bypass_domains'])
|
||||
|
||||
calls = [
|
||||
call('192.168.0.1', '3128', 'frank', 'passw0rd', 'Ethernet'),
|
||||
|
@ -47,6 +47,7 @@ EXCLUDED_FILES = [
|
||||
os.path.join('tests', 'modparser.py'),
|
||||
os.path.join('tests', 'committer_parser.py'),
|
||||
os.path.join('tests', 'zypp_plugin.py'),
|
||||
os.path.join('tests', 'tox-helper.py'),
|
||||
os.path.join('tests', 'unit', 'transport', 'mixins.py'),
|
||||
os.path.join('tests', 'integration', 'utils', 'testprogram.py'),
|
||||
]
|
||||
|
@ -577,6 +577,7 @@ class PubServerChannel(TestCase, AdaptedConfigurationTestCaseMixin):
|
||||
executor.submit(self._send_small, opts, 3)
|
||||
executor.submit(self._send_large, opts, 4)
|
||||
expect = ['{}-{}'.format(a, b) for a in range(10) for b in (1, 2, 3, 4)]
|
||||
time.sleep(0.1)
|
||||
server_channel.publish({'tgt_type': 'glob', 'tgt': '*', 'stop': True})
|
||||
gather.join()
|
||||
server_channel.pub_close()
|
||||
|
@ -14,6 +14,7 @@ from salt.utils.odict import OrderedDict
|
||||
import salt.utils.dns
|
||||
from salt.utils.dns import _to_port, _tree, _weighted_order, _data2rec, _data2rec_group
|
||||
from salt.utils.dns import _lookup_gai, _lookup_dig, _lookup_drill, _lookup_host, _lookup_nslookup
|
||||
from salt.utils.dns import lookup
|
||||
|
||||
# Testing
|
||||
from tests.support.unit import skipIf, TestCase
|
||||
@ -277,6 +278,46 @@ class DNSlookupsCase(TestCase):
|
||||
msg='Error parsing DNSSEC\'d {0} returns'.format(rec_t)
|
||||
)
|
||||
|
||||
def test_lookup_with_servers(self):
|
||||
rights = {
|
||||
'A': [
|
||||
'Name:\tmocksrvr.example.com\nAddress: 10.1.1.1',
|
||||
'Name:\tmocksrvr.example.com\nAddress: 10.1.1.1\n'
|
||||
'Name:\tweb.example.com\nAddress: 10.2.2.2\n'
|
||||
'Name:\tweb.example.com\nAddress: 10.3.3.3'
|
||||
],
|
||||
'AAAA': [
|
||||
'mocksrvr.example.com\thas AAAA address 2a00:a00:b01:c02:d03:e04:f05:111',
|
||||
'mocksrvr.example.com\tcanonical name = web.example.com.\n'
|
||||
'web.example.com\thas AAAA address 2a00:a00:b01:c02:d03:e04:f05:111\n'
|
||||
'web.example.com\thas AAAA address 2a00:a00:b01:c02:d03:e04:f05:222\n'
|
||||
'web.example.com\thas AAAA address 2a00:a00:b01:c02:d03:e04:f05:333'
|
||||
],
|
||||
'CNAME': [
|
||||
'mocksrvr.example.com\tcanonical name = web.example.com.'
|
||||
],
|
||||
'MX': [
|
||||
'example.com\tmail exchanger = 10 mx1.example.com.',
|
||||
'example.com\tmail exchanger = 10 mx1.example.com.\n'
|
||||
'example.com\tmail exchanger = 20 mx2.example.eu.\n'
|
||||
'example.com\tmail exchanger = 30 mx3.example.nl.'
|
||||
],
|
||||
'TXT': [
|
||||
'example.com\ttext = "v=spf1 a include:_spf4.example.com include:mail.example.eu ip4:10.0.0.0/8 ip6:2a00:a00:b01::/48 ~all"'
|
||||
]
|
||||
}
|
||||
|
||||
for rec_t, tests in rights.items():
|
||||
with self._mock_cmd_ret([dict([('stdout', dres)]) for dres in tests]):
|
||||
for test_res in self.RESULTS[rec_t]:
|
||||
if rec_t in ('A', 'AAAA', 'CNAME'):
|
||||
rec = 'mocksrvr.example.com'
|
||||
else:
|
||||
rec = 'example.com'
|
||||
self.assertEqual(
|
||||
lookup(rec, rec_t, method='nslookup', servers='8.8.8.8'), test_res,
|
||||
)
|
||||
|
||||
def test_dig(self):
|
||||
wrong_type = {'retcode': 0, 'stderr': ';; Warning, ignoring invalid type ABC'}
|
||||
|
||||
@ -442,13 +483,13 @@ class DNSlookupsCase(TestCase):
|
||||
|
||||
empty = {'stdout': 'www.example.com has no MX record'}
|
||||
|
||||
# example returns for dig
|
||||
# example returns for host
|
||||
rights = {
|
||||
'A': [
|
||||
'mocksrvr.example.com has address 10.1.1.1',
|
||||
'web.example.com has address 10.1.1.1\n'
|
||||
'web.example.com has address 10.2.2.2\n'
|
||||
'web.example.com has address 10.3.3.3'
|
||||
'web.example.com has address 10.1.1.1\n'
|
||||
'web.example.com has address 10.2.2.2\n'
|
||||
'web.example.com has address 10.3.3.3'
|
||||
|
||||
],
|
||||
'AAAA': [
|
||||
|
@ -206,12 +206,12 @@ class NetworkTestCase(TestCase):
|
||||
def test_parse_host_port(self):
|
||||
_ip = ipaddress.ip_address
|
||||
good_host_ports = {
|
||||
'10.10.0.3': (_ip('10.10.0.3'), None),
|
||||
'10.10.0.3:1234': (_ip('10.10.0.3'), 1234),
|
||||
'2001:0db8:85a3::8a2e:0370:7334': (_ip('2001:0db8:85a3::8a2e:0370:7334'), None),
|
||||
'[2001:0db8:85a3::8a2e:0370:7334]:1234': (_ip('2001:0db8:85a3::8a2e:0370:7334'), 1234),
|
||||
'2001:0db8:85a3::7334': (_ip('2001:0db8:85a3::7334'), None),
|
||||
'[2001:0db8:85a3::7334]:1234': (_ip('2001:0db8:85a3::7334'), 1234)
|
||||
'10.10.0.3': (_ip('10.10.0.3').compressed, None),
|
||||
'10.10.0.3:1234': (_ip('10.10.0.3').compressed, 1234),
|
||||
'2001:0db8:85a3::8a2e:0370:7334': (_ip('2001:0db8:85a3::8a2e:0370:7334').compressed, None),
|
||||
'[2001:0db8:85a3::8a2e:0370:7334]:1234': (_ip('2001:0db8:85a3::8a2e:0370:7334').compressed, 1234),
|
||||
'2001:0db8:85a3::7334': (_ip('2001:0db8:85a3::7334').compressed, None),
|
||||
'[2001:0db8:85a3::7334]:1234': (_ip('2001:0db8:85a3::7334').compressed, 1234)
|
||||
}
|
||||
bad_host_ports = [
|
||||
'10.10.0.3/24',
|
||||
@ -232,6 +232,54 @@ class NetworkTestCase(TestCase):
|
||||
log.error('bad host_port value: "%s" failed to trigger ValueError exception', host_port)
|
||||
raise _e_
|
||||
|
||||
def test_dns_check(self):
|
||||
class MockSocket(object):
|
||||
def __init__(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
def setsockopt(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
def sendto(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
def connect(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
def close(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
hosts = [
|
||||
{'host': '10.10.0.3',
|
||||
'port': '',
|
||||
'mocked': [(2, 1, 6, '', ('10.10.0.3', 0))],
|
||||
'ret': '10.10.0.3'},
|
||||
{'host': '10.10.0.3',
|
||||
'port': '1234',
|
||||
'mocked': [(2, 1, 6, '', ('10.10.0.3', 0))],
|
||||
'ret': '10.10.0.3'},
|
||||
{'host': '2001:0db8:85a3::8a2e:0370:7334',
|
||||
'port': '',
|
||||
'mocked': [(10, 1, 6, '', ('2001:db8:85a3::8a2e:370:7334', 0, 0, 0))],
|
||||
'ret': '2001:db8:85a3::8a2e:370:7334'},
|
||||
{'host': '2001:0db8:85a3::8a2e:370:7334',
|
||||
'port': '1234',
|
||||
'mocked': [(10, 1, 6, '', ('2001:db8:85a3::8a2e:370:7334', 0, 0, 0))],
|
||||
'ret': '2001:db8:85a3::8a2e:370:7334'},
|
||||
{'host': 'salt-master',
|
||||
'port': '1234',
|
||||
'mocked': [(2, 1, 6, '', ('127.0.0.1', 0))],
|
||||
'ret': '127.0.0.1'},
|
||||
]
|
||||
for host in hosts:
|
||||
with patch.object(socket, 'getaddrinfo', MagicMock(return_value=host['mocked'])):
|
||||
with patch('socket.socket', MockSocket):
|
||||
ret = network.dns_check(host['host'], host['port'])
|
||||
self.assertEqual(ret, host['ret'])
|
||||
|
||||
def test_is_subnet(self):
|
||||
for subnet_data in (IPV4_SUBNETS, IPV6_SUBNETS):
|
||||
for item in subnet_data[True]:
|
||||
|
@ -17,6 +17,7 @@ from tests.support.unit import TestCase, skipIf
|
||||
from tests.support.mock import patch, NO_MOCK, NO_MOCK_REASON
|
||||
|
||||
# Import Salt libs
|
||||
import salt.utils.compat
|
||||
import salt.utils.path
|
||||
import salt.utils.platform
|
||||
from salt.exceptions import CommandNotFoundError
|
||||
@ -125,7 +126,7 @@ class PathJoinTestCase(TestCase):
|
||||
platform.system = lambda: "windows"
|
||||
|
||||
for module in (ntpath, os, os.path, tempfile):
|
||||
reload(module)
|
||||
salt.utils.compat.reload(module)
|
||||
|
||||
def __unpatch_path(self):
|
||||
del sys.modules['nt']
|
||||
@ -133,7 +134,7 @@ class PathJoinTestCase(TestCase):
|
||||
platform.system = self.PLATFORM_FUNC
|
||||
|
||||
for module in (posixpath, os, os.path, tempfile, platform):
|
||||
reload(module)
|
||||
salt.utils.compat.reload(module)
|
||||
|
||||
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
|
210
tox.ini
210
tox.ini
@ -1,13 +1,216 @@
|
||||
[tox]
|
||||
envlist = py27,py34,py35,py36,pylint-salt,pylint-tests
|
||||
envlist =
|
||||
py{27,34,35,36},
|
||||
py{27,34,35,36}-coverage,
|
||||
py{27,34,35,36}-pytest,
|
||||
py{27,34,35,36}-runtests,
|
||||
py{27,34,35,36}-pytest-coverage,
|
||||
py{27,34,35,36}-runtests-coverage,
|
||||
pylint-salt,
|
||||
pylint-tests
|
||||
skip_missing_interpreters = True
|
||||
skipsdist = True
|
||||
|
||||
[testenv]
|
||||
deps = -Ur{toxinidir}/requirements/tests.txt
|
||||
commands = pytest --rootdir {toxinidir} {posargs}
|
||||
changedir = {toxinidir}
|
||||
commands_pre = {envpython} tests/tox-helper.py create-dirs
|
||||
passenv = LANG HOME
|
||||
sitepackages = True
|
||||
commands = {[testenv:runtests]commands}
|
||||
|
||||
[testenv:runtests]
|
||||
deps =
|
||||
{[testenv]deps}
|
||||
unittest-xml-reporting
|
||||
commands = {envpython} {toxinidir}/tests/runtests.py --tests-logfile={toxinidir}/artifacts/logs/runtests.log {posargs}
|
||||
|
||||
[testenv:pytest]
|
||||
commands = pytest --rootdir {toxinidir} --log-file={toxinidir}/artifacts/logs/runtests.log {posargs}
|
||||
|
||||
[testenv:runtests-coverage]
|
||||
# Add tests/support/coverage to PYTHONPATH in order to get code coverage from subprocesses.
|
||||
setenv =
|
||||
PYTHONPATH={toxinidir}/tests/support/coverage
|
||||
commands_pre =
|
||||
- coverage erase
|
||||
commands =
|
||||
coverage run -m tests.runtests {posargs}
|
||||
commands_post =
|
||||
- coverage combine
|
||||
- coverage xml -o {toxinidir}/artifacts/coverage/coverage.xml
|
||||
|
||||
[testenv:pytest-coverage]
|
||||
setenv = {[testenv:runtests-coverage]setenv}
|
||||
commands_pre = {[testenv:runtests-coverage]commands_pre}
|
||||
commands = coverage run -m py.test --rootdir {toxinidir} {posargs}
|
||||
commands_post = {[testenv:runtests-coverage]commands_post}
|
||||
|
||||
[testenv:py2-pytest]
|
||||
commands = {[testenv:pytest]commands}
|
||||
|
||||
[testenv:py2-runtests]
|
||||
deps = {[testenv:runtests]deps}
|
||||
commands = {[testenv:runtests]commands}
|
||||
|
||||
[testenv:py2-coverage]
|
||||
deps = {[testenv:runtests]deps}
|
||||
setenv = {[testenv:runtests-coverage]setenv}
|
||||
commands = {[testenv:runtests-coverage]commands}
|
||||
commands_pre = {[testenv:runtests-coverage]commands_pre}
|
||||
commands_post = {[testenv:runtests-coverage]commands_post}
|
||||
|
||||
[testenv:py2-runtests-coverage]
|
||||
deps = {[testenv:runtests]deps}
|
||||
setenv = {[testenv:runtests-coverage]setenv}
|
||||
commands = {[testenv:runtests-coverage]commands}
|
||||
commands_pre = {[testenv:runtests-coverage]commands_pre}
|
||||
commands_post = {[testenv:runtests-coverage]commands_post}
|
||||
|
||||
[testenv:py2-pytest-coverage]
|
||||
setenv = {[testenv:runtests-coverage]setenv}
|
||||
commands = {[testenv:pytest-coverage]commands}
|
||||
commands_pre = {[testenv:pytest-coverage]commands_pre}
|
||||
commands_post = {[testenv:pytest-coverage]commands_post}
|
||||
|
||||
[testenv:py27-pytest]
|
||||
commands = {[testenv:pytest]commands}
|
||||
|
||||
[testenv:py27-runtests]
|
||||
deps = {[testenv:runtests]deps}
|
||||
commands = {[testenv:runtests]commands}
|
||||
|
||||
[testenv:py27-coverage]
|
||||
deps = {[testenv:runtests]deps}
|
||||
setenv = {[testenv:runtests-coverage]setenv}
|
||||
commands = {[testenv:runtests-coverage]commands}
|
||||
commands_pre = {[testenv:runtests-coverage]commands_pre}
|
||||
commands_post = {[testenv:runtests-coverage]commands_post}
|
||||
|
||||
[testenv:py27-runtests-coverage]
|
||||
deps = {[testenv:runtests]deps}
|
||||
setenv = {[testenv:runtests-coverage]setenv}
|
||||
commands = {[testenv:runtests-coverage]commands}
|
||||
commands_pre = {[testenv:runtests-coverage]commands_pre}
|
||||
commands_post = {[testenv:runtests-coverage]commands_post}
|
||||
|
||||
[testenv:py27-pytest-coverage]
|
||||
setenv = {[testenv:runtests-coverage]setenv}
|
||||
commands = {[testenv:pytest-coverage]commands}
|
||||
commands_pre = {[testenv:pytest-coverage]commands_pre}
|
||||
commands_post = {[testenv:pytest-coverage]commands_post}
|
||||
|
||||
[testenv:py3-pytest]
|
||||
commands = {[testenv:pytest]commands}
|
||||
|
||||
[testenv:py3-runtests]
|
||||
deps = {[testenv:runtests]deps}
|
||||
commands = {[testenv:runtests]commands}
|
||||
|
||||
[testenv:py3-coverage]
|
||||
deps = {[testenv:runtests]deps}
|
||||
setenv = {[testenv:runtests-coverage]setenv}
|
||||
commands = {[testenv:runtests-coverage]commands}
|
||||
commands_pre = {[testenv:runtests-coverage]commands_pre}
|
||||
commands_post = {[testenv:runtests-coverage]commands_post}
|
||||
|
||||
[testenv:py3-runtests-coverage]
|
||||
deps = {[testenv:runtests]deps}
|
||||
setenv = {[testenv:runtests-coverage]setenv}
|
||||
commands = {[testenv:runtests-coverage]commands}
|
||||
commands_pre = {[testenv:runtests-coverage]commands_pre}
|
||||
commands_post = {[testenv:runtests-coverage]commands_post}
|
||||
|
||||
[testenv:py3-pytest-coverage]
|
||||
setenv = {[testenv:runtests-coverage]setenv}
|
||||
commands = {[testenv:pytest-coverage]commands}
|
||||
commands_pre = {[testenv:pytest-coverage]commands_pre}
|
||||
commands_post = {[testenv:pytest-coverage]commands_post}
|
||||
|
||||
|
||||
[testenv:py34-pytest]
|
||||
commands = {[testenv:pytest]commands}
|
||||
|
||||
[testenv:py34-runtests]
|
||||
deps = {[testenv:runtests]deps}
|
||||
commands = {[testenv:runtests]commands}
|
||||
|
||||
[testenv:py34-coverage]
|
||||
deps = {[testenv:runtests]deps}
|
||||
setenv = {[testenv:runtests-coverage]setenv}
|
||||
commands = {[testenv:runtests-coverage]commands}
|
||||
commands_pre = {[testenv:runtests-coverage]commands_pre}
|
||||
commands_post = {[testenv:runtests-coverage]commands_post}
|
||||
|
||||
[testenv:py34-runtests-coverage]
|
||||
deps = {[testenv:runtests]deps}
|
||||
setenv = {[testenv:runtests-coverage]setenv}
|
||||
commands = {[testenv:runtests-coverage]commands}
|
||||
commands_pre = {[testenv:runtests-coverage]commands_pre}
|
||||
commands_post = {[testenv:runtests-coverage]commands_post}
|
||||
|
||||
[testenv:py34-pytest-coverage]
|
||||
setenv = {[testenv:runtests-coverage]setenv}
|
||||
commands = {[testenv:pytest-coverage]commands}
|
||||
commands_pre = {[testenv:pytest-coverage]commands_pre}
|
||||
commands_post = {[testenv:pytest-coverage]commands_post}
|
||||
|
||||
|
||||
[testenv:py35-pytest]
|
||||
commands = {[testenv:pytest]commands}
|
||||
|
||||
[testenv:py35-runtests]
|
||||
deps = {[testenv:runtests]deps}
|
||||
commands = {[testenv:runtests]commands}
|
||||
|
||||
[testenv:py35-coverage]
|
||||
deps = {[testenv:runtests]deps}
|
||||
setenv = {[testenv:runtests-coverage]setenv}
|
||||
commands = {[testenv:runtests-coverage]commands}
|
||||
commands_pre = {[testenv:runtests-coverage]commands_pre}
|
||||
commands_post = {[testenv:runtests-coverage]commands_post}
|
||||
|
||||
[testenv:py35-runtests-coverage]
|
||||
deps = {[testenv:runtests]deps}
|
||||
setenv = {[testenv:runtests-coverage]setenv}
|
||||
commands = {[testenv:runtests-coverage]commands}
|
||||
commands_pre = {[testenv:runtests-coverage]commands_pre}
|
||||
commands_post = {[testenv:runtests-coverage]commands_post}
|
||||
|
||||
[testenv:py35-pytest-coverage]
|
||||
setenv = {[testenv:runtests-coverage]setenv}
|
||||
commands = {[testenv:pytest-coverage]commands}
|
||||
commands_pre = {[testenv:pytest-coverage]commands_pre}
|
||||
commands_post = {[testenv:pytest-coverage]commands_post}
|
||||
|
||||
|
||||
[testenv:py36-pytest]
|
||||
commands = {[testenv:pytest]commands}
|
||||
|
||||
[testenv:py36-runtests]
|
||||
deps = {[testenv:runtests]deps}
|
||||
commands = {[testenv:runtests]commands}
|
||||
|
||||
[testenv:py36-coverage]
|
||||
deps = {[testenv:runtests]deps}
|
||||
setenv = {[testenv:runtests-coverage]setenv}
|
||||
commands = {[testenv:runtests-coverage]commands}
|
||||
commands_pre = {[testenv:runtests-coverage]commands_pre}
|
||||
commands_post = {[testenv:runtests-coverage]commands_post}
|
||||
|
||||
[testenv:py36-runtests-coverage]
|
||||
deps = {[testenv:runtests]deps}
|
||||
setenv = {[testenv:runtests-coverage]setenv}
|
||||
commands = {[testenv:runtests-coverage]commands}
|
||||
commands_pre = {[testenv:runtests-coverage]commands_pre}
|
||||
commands_post = {[testenv:runtests-coverage]commands_post}
|
||||
|
||||
[testenv:py36-pytest-coverage]
|
||||
setenv = {[testenv:runtests-coverage]setenv}
|
||||
commands = {[testenv:pytest-coverage]commands}
|
||||
commands_pre = {[testenv:pytest-coverage]commands_pre}
|
||||
commands_post = {[testenv:pytest-coverage]commands_post}
|
||||
|
||||
|
||||
[testenv:pylint-salt]
|
||||
basepython = python2.7
|
||||
@ -17,6 +220,7 @@ commands =
|
||||
pylint --rcfile=.testing.pylintrc --disable=I,W1307,C0411,C0413,W8410,str-format-in-logging {posargs:setup.py salt/}
|
||||
sitepackages = False
|
||||
|
||||
|
||||
[testenv:pylint-tests]
|
||||
basepython = python2.7
|
||||
deps = -r{toxinidir}/requirements/dev.txt
|
||||
@ -26,6 +230,6 @@ commands =
|
||||
sitepackages = False
|
||||
|
||||
[pytest]
|
||||
addopts = --log-file /tmp/salt-runtests.log --no-print-logs --ssh-tests -ra -sv
|
||||
addopts = --no-print-logs --ssh-tests -ra -sv
|
||||
testpaths = tests
|
||||
norecursedirs = tests/kitchen
|
||||
|
Loading…
Reference in New Issue
Block a user