Merge branch '2018.3' into fix-broken-thing

This commit is contained in:
Gareth J. Greenaway 2019-02-13 18:36:59 -08:00 committed by GitHub
commit 298ad5c0aa
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
145 changed files with 8655 additions and 969 deletions

49
.codecov.yml Normal file
View 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
View 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

View file

@ -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

11
Pipfile
View file

@ -20,17 +20,18 @@ boto = ">=2.32.1"
boto3 = ">=1.2.1"
moto = ">=0.3.6"
SaltPyLint = ">=v2017.3.6"
pytest = ">=3.5.0"
pytest = ">=4.0.1"
pytest-cov = "*"
pytest-salt = "==2018.12.8"
pytest-timeout = ">=1.3.3"
pytest-tempdir = ">=2018.8.11"
pytest-helpers-namespace = ">=2017.11.11"
[packages.futures]
# Required by Tornado to handle threads stuff.
version = ">=2.0"
markers = "python_version < '3.0'"
[dev-packages.pytest-salt]
git = "git://github.com/saltstack/pytest-salt.git"
ref = "master"
[dev-packages.httpretty]
# httpretty Needs to be here for now even though it's a dependency of boto.
# A pip install on a fresh system will decide to target httpretty 0.8.10 to

View file

@ -2,7 +2,7 @@
What is SaltStack?
==================
SaltStack makes software for complex systems management at scale.
SaltStack makes software for complex systems management at scale.
SaltStack is the company that created and maintains the Salt Open
project and develops and sells SaltStack Enterprise software, services
and support. Easy enough to get running in minutes, scalable enough to

View file

@ -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]-->

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SALT-API" "1" "Sep 21, 2018" "2018.3.3" "Salt"
.TH "SALT-API" "1" "Sep 21, 2018" "2018.3.4" "Salt"
.SH NAME
salt-api \- salt-api Command
.

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SALT-CALL" "1" "Sep 21, 2018" "2018.3.3" "Salt"
.TH "SALT-CALL" "1" "Sep 21, 2018" "2018.3.4" "Salt"
.SH NAME
salt-call \- salt-call Documentation
.

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SALT-CLOUD" "1" "Sep 21, 2018" "2018.3.3" "Salt"
.TH "SALT-CLOUD" "1" "Sep 21, 2018" "2018.3.4" "Salt"
.SH NAME
salt-cloud \- Salt Cloud Command
.

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SALT-CP" "1" "Sep 21, 2018" "2018.3.3" "Salt"
.TH "SALT-CP" "1" "Sep 21, 2018" "2018.3.4" "Salt"
.SH NAME
salt-cp \- salt-cp Documentation
.

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SALT-KEY" "1" "Sep 21, 2018" "2018.3.3" "Salt"
.TH "SALT-KEY" "1" "Sep 21, 2018" "2018.3.4" "Salt"
.SH NAME
salt-key \- salt-key Documentation
.

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SALT-MASTER" "1" "Sep 21, 2018" "2018.3.3" "Salt"
.TH "SALT-MASTER" "1" "Sep 21, 2018" "2018.3.4" "Salt"
.SH NAME
salt-master \- salt-master Documentation
.

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SALT-MINION" "1" "Sep 21, 2018" "2018.3.3" "Salt"
.TH "SALT-MINION" "1" "Sep 21, 2018" "2018.3.4" "Salt"
.SH NAME
salt-minion \- salt-minion Documentation
.

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SALT-PROXY" "1" "Sep 21, 2018" "2018.3.3" "Salt"
.TH "SALT-PROXY" "1" "Sep 21, 2018" "2018.3.4" "Salt"
.SH NAME
salt-proxy \- salt-proxy Documentation
.

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SALT-RUN" "1" "Sep 21, 2018" "2018.3.3" "Salt"
.TH "SALT-RUN" "1" "Sep 21, 2018" "2018.3.4" "Salt"
.SH NAME
salt-run \- salt-run Documentation
.

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SALT-SSH" "1" "Sep 21, 2018" "2018.3.3" "Salt"
.TH "SALT-SSH" "1" "Sep 21, 2018" "2018.3.4" "Salt"
.SH NAME
salt-ssh \- salt-ssh Documentation
.

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SALT-SYNDIC" "1" "Sep 21, 2018" "2018.3.3" "Salt"
.TH "SALT-SYNDIC" "1" "Sep 21, 2018" "2018.3.4" "Salt"
.SH NAME
salt-syndic \- salt-syndic Documentation
.

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SALT-UNITY" "1" "Sep 21, 2018" "2018.3.3" "Salt"
.TH "SALT-UNITY" "1" "Sep 21, 2018" "2018.3.4" "Salt"
.SH NAME
salt-unity \- salt-unity Command
.

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SALT" "1" "Sep 21, 2018" "2018.3.3" "Salt"
.TH "SALT" "1" "Sep 21, 2018" "2018.3.4" "Salt"
.SH NAME
salt \- salt
.

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SALT" "7" "Sep 21, 2018" "2018.3.3" "Salt"
.TH "SALT" "7" "Sep 21, 2018" "2018.3.4" "Salt"
.SH NAME
salt \- Salt Documentation
.

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SPM" "1" "Sep 21, 2018" "2018.3.3" "Salt"
.TH "SPM" "1" "Sep 21, 2018" "2018.3.4" "Salt"
.SH NAME
spm \- Salt Package Manager Command
.

View file

@ -2599,6 +2599,8 @@ can have multiple root directories. The subdirectories in the multiple file
roots cannot match, otherwise the downloaded files will not be able to be
reliably ensured. A base environment is required to house the top file.
As of 2018.3.5 and 2019.2.1, it is possible to have `__env__` as a catch-all environment.
Example:
.. code-block:: yaml
@ -2612,6 +2614,8 @@ Example:
prod:
- /srv/salt/prod/services
- /srv/salt/prod/states
__env__:
- /srv/salt/default
.. note::
For masterless Salt, this parameter must be specified in the minion config

View file

@ -803,6 +803,23 @@ A value of 10 minutes is a reasonable default.
grains_refresh_every: 0
.. conf_minion:: metadata_server_grains
``metadata_server_grains``
--------------------------
.. versionadded:: 2017.7.0
Default: ``False``
Set this option to enable gathering of cloud metadata from
``http://169.254.169.254/latest`` for use in grains (see :py:mod:`here
<salt.grains.metadata>` for more information).
.. code-block:: yaml
metadata_server_grains: True
.. conf_minion:: fibre_channel_grains
``fibre_channel_grains``

View file

@ -532,7 +532,7 @@ services. For more information on service certificates, see the following link:
* `Manage Certificates`__
.. __: https://msdn.microsoft.com/en-us/library/azure/gg981929.aspx
.. __: https://docs.microsoft.com/en-us/azure/cloud-services/cloud-services-certs-create
The following functions are available.

View file

@ -235,3 +235,17 @@ Defined in: State
__sdb__
-------
Defined in: SDB
Additional Globals
==================
Defined for: Runners, Execution Modules, Wheels
* ``__jid__``: The job ID
* ``__user__``: The user
* ``__tag__``: The jid tag
* ``__jid_event__``: A :py:class:`salt.utils.event.NamespacedEvent`.
:py:class:`NamespacedEvent <salt.utils.event.NamespacedEvent>` defines a single
method :py:meth:`fire_event <salt.utils.event.NamespacedEvent.fire_event>`, that takes data and tag. The :ref:`Runner docs <runners>` has examples.

View file

@ -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
----

View file

@ -163,10 +163,10 @@ A few examples of salt states from the community:
* https://github.com/bclermont/states
* https://github.com/pcrews/salt-data
Follow on ohloh
===============
Follow on Open Hub
==================
https://www.ohloh.net/p/salt
https://www.openhub.net/p/salt
Other community links
=====================
@ -178,6 +178,7 @@ Other community links
- `Facebook <https://www.facebook.com/SaltStack>`_
- `Twitter <https://twitter.com/SaltStackInc>`_
- `Wikipedia page <http://en.wikipedia.org/wiki/Salt_(software)>`_
- `Stack Overflow <https://stackoverflow.com/questions/tagged/salt-stack>`_
Hack the Source
===============

View file

@ -87,6 +87,13 @@ the context into the included file is required:
.. code-block:: jinja
{% from 'lib.sls' import test with context %}
Includes must use full paths, like so:
.. code-block:: jinja
:caption: spam/eggs.jinja
{% include 'spam/foobar.jinja' %}
Including Context During Include/Import
---------------------------------------

File diff suppressed because it is too large Load diff

View file

@ -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
@ -728,6 +734,19 @@ Then the ``roots`` backend (the default backend of files in ``/srv/salt``) will
be searched first for the requested file; then, if it is not found on the
master, each configured git remote will be searched.
.. note::
This can be used together with `file_roots` accepting `__env__` as a catch-all
environment, since 2018.3.5 and 2019.2.1:
.. code-block:: yaml
file_roots:
base:
- /srv/salt
__env__:
- /srv/salt
Branches, Environments, and Top Files
=====================================

View file

@ -177,7 +177,7 @@ $MAKE install
############################################################################
echo -n -e "\033]0;Build_Env: libsodium: download\007"
PKGURL="https://download.libsodium.org/libsodium/releases/libsodium-1.0.15.tar.gz"
PKGURL="https://download.libsodium.org/libsodium/releases/old/libsodium-1.0.15.tar.gz"
PKGDIR="libsodium-1.0.15"
download $PKGURL

View file

@ -158,13 +158,20 @@ echo -n -e "\033]0;Build_Pkg: Add Version to .xml\007"
if [ "$PYVER" == "2" ]; then
TITLE="Salt $VERSION"
DESC="Salt $VERSION with Python 2"
SEDSTR="s/@PY2@/_py2/g"
else
TITLE="Salt $VERSION (Python 3)"
DESC="Salt $VERSION with Python 3"
SEDSTR="s/@PY2@//g"
fi
cd $PKGRESOURCES
cp distribution.xml.dist distribution.xml
# Select the appropriate welcome text
# This is only necessary until Sodium, then this can be removed
sed -E -i '' "$SEDSTR" distribution.xml
SEDSTR="s/@TITLE@/$TITLE/g"
sed -E -i '' "$SEDSTR" distribution.xml

View file

@ -16,7 +16,7 @@
mime-type="image/png"
scaling="proportional" />
<!-- Define documents displayed at various steps -->
<welcome file="welcome.rtf"
<welcome file="welcome@PY2@.rtf"
mime-type="text/rtf" />
<license file="license.rtf"
mime-type="text/rtf" />

View file

@ -0,0 +1,32 @@
{\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf340
{\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\froman\fcharset0 Times-Roman;\f2\fnil\fcharset0 PTMono-Regular;
}
{\colortbl;\red255\green255\blue255;\red0\green0\blue233;}
\vieww28300\viewh14680\viewkind0
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0
\f0\fs24 \cf0 WARNING: Python 2 Support will be discontinued in Sodium. Salt will only ship Python 3 installers starting with the Sodium release.\
\
\pard\pardeftab720\sl280\sa240\partightenfactor0
{\field{\*\fldinst{HYPERLINK "http://saltstack.com/"}}{\fldrslt
\f1 \cf2 \expnd0\expndtw0\kerning0
\ul \ulc2 SaltStack}}
\f1 \expnd0\expndtw0\kerning0
is extremely fast and scalable systems and configuration management software for predictive orchestration, cloud and data center automation, server provisioning, application deployment and more. \
Documentation for Salt is available at {\field{\*\fldinst{HYPERLINK "http://docs.saltstack.com/"}}{\fldrslt \cf2 \ul \ulc2 http://docs.saltstack.com}} \
This package will install Salt on your Mac. Salt installs into
\f2\fs22 /opt/salt
\f1\fs24 .\
Sample configuration files (
\f2\fs22 master.dist
\f1\fs24 and
\f2\fs22 minion.dist
\f1\fs24 ) will be installed to
\f2\fs22 /etc/salt
\f1\fs24 . Create copies of them without the '
\f2\fs22 .dist
\f1\fs24 ' in the filename and edit as you see fit.\
This Salt package uses a custom-built Python. To install additional Python modules for Salt, use the associated 'pip' binary. For example, if you need LDAP support in Salt you will need the 'python-ldap' module. Install it with
\f2\fs22 /opt/salt/bin/pip install python-ldap
\f1\fs24 \
Note that some Python modules need a compiler available. Installing Apple's Xcode Command Line Tools should provide the necessary utilities. Alternatively, {\field{\*\fldinst{HYPERLINK "http://macports.org/"}}{\fldrslt \cf2 \ul \ulc2 MacPorts}}, {\field{\*\fldinst{HYPERLINK "http://finkproject.org/"}}{\fldrslt \cf2 \ul \ulc2 Fink}}, or {\field{\*\fldinst{HYPERLINK "http://brew.sh/"}}{\fldrslt \cf2 \ul \ulc2 Homebrew}} may provide what you need.}

View file

@ -22,22 +22,10 @@
# Load parameters
param(
[switch]$Silent
[switch]$Silent,
[switch]$NoPipDependencies
)
Write-Output "================================================================="
Write-Output ""
Write-Output " Development Environment Installation"
Write-Output ""
Write-Output " - Installs All Salt Dependencies"
Write-Output " - Detects 32/64 bit Architectures"
Write-Output ""
Write-Output " To run silently add -Silent"
Write-Output " eg: dev_env.ps1 -Silent"
Write-Output ""
Write-Output "================================================================="
Write-Output ""
#==============================================================================
# Get the Directory of actual script
#==============================================================================
@ -49,6 +37,22 @@ $script_path = $script_path.DirectoryName
#==============================================================================
$script_name = $MyInvocation.MyCommand.Name
Write-Output "================================================================="
Write-Output ""
Write-Output " Development Environment Installation"
Write-Output ""
Write-Output " - Installs All Salt Dependencies"
Write-Output " - Detects 32/64 bit Architectures"
Write-Output ""
Write-Output " To run silently add -Silent"
Write-Output " eg: ${script_name} -Silent"
Write-Output ""
Write-Output " To run skip installing pip dependencies add -NoPipDependencies"
Write-Output " eg: ${script_name} -NoPipDependencies"
Write-Output ""
Write-Output "================================================================="
Write-Output ""
#==============================================================================
# Import Modules
#==============================================================================
@ -211,25 +215,46 @@ if ( ! [bool]$Env:SALT_PIP_LOCAL_CACHE) {
}
#==============================================================================
# Install pypi resources using pip
# Install windows specific pypi resources using pip
# caching depends on environment variable SALT_REQ_LOCAL_CACHE
#==============================================================================
Write-Output " ----------------------------------------------------------------"
Write-Output " - $script_name :: Installing pypi resources using pip . . ."
Write-Output " - $script_name :: Installing windows specific pypi resources using pip . . ."
Write-Output " ----------------------------------------------------------------"
if ( ! [bool]$Env:SALT_REQ_LOCAL_CACHE) {
Start_Process_and_test_exitcode "cmd" "/c $($ini['Settings']['Python2Dir'])\python.exe -m pip --disable-pip-version-check --no-cache-dir install -r $($script_path)\req.txt" "pip install"
Start_Process_and_test_exitcode "cmd" "/c $($ini['Settings']['Python2Dir'])\python.exe -m pip --disable-pip-version-check --no-cache-dir install -r $($script_path)\req_win.txt" "pip install"
} else {
if ( (Get-ChildItem $Env:SALT_REQ_LOCAL_CACHE | Measure-Object).Count -eq 0 ) {
# folder empty
Write-Output " pip download from req.txt into empty local cache SALT_REQ $Env:SALT_REQ_LOCAL_CACHE"
Start_Process_and_test_exitcode "cmd" "/c $($ini['Settings']['Python2Dir'])\python.exe -m pip --disable-pip-version-check download --dest $Env:SALT_REQ_LOCAL_CACHE -r $($script_path)\req.txt" "pip download"
Write-Output " pip download from req_win.txt into empty local cache SALT_REQ $Env:SALT_REQ_LOCAL_CACHE"
Start_Process_and_test_exitcode "cmd" "/c $($ini['Settings']['Python2Dir'])\python.exe -m pip --disable-pip-version-check download --dest $Env:SALT_REQ_LOCAL_CACHE -r $($script_path)\req_win.txt" "pip download"
}
Write-Output " reading from local pip cache $Env:SALT_REQ_LOCAL_CACHE"
Write-Output " If a (new) resource is missing, please delete all files in this cache, go online and repeat"
Start_Process_and_test_exitcode "cmd" "/c $($ini['Settings']['Python2Dir'])\python.exe -m pip --disable-pip-version-check install --no-index --find-links=$Env:SALT_REQ_LOCAL_CACHE -r $($script_path)\req.txt" "pip install"
Start_Process_and_test_exitcode "cmd" "/c $($ini['Settings']['Python2Dir'])\python.exe -m pip --disable-pip-version-check install --no-index --find-links=$Env:SALT_REQ_LOCAL_CACHE -r $($script_path)\req_win.txt" "pip install"
}
#==============================================================================
# Install pypi resources using pip
# caching depends on environment variable SALT_REQ_LOCAL_CACHE
#==============================================================================
If ($NoPipDependencies -eq $false) {
Write-Output " ----------------------------------------------------------------"
Write-Output " - $script_name :: Installing pypi resources using pip . . ."
Write-Output " ----------------------------------------------------------------"
if ( ! [bool]$Env:SALT_REQ_LOCAL_CACHE) {
Start_Process_and_test_exitcode "cmd" "/c $($ini['Settings']['Python2Dir'])\python.exe -m pip --disable-pip-version-check --no-cache-dir install -r $($script_path)\req.txt" "pip install"
} else {
if ( (Get-ChildItem $Env:SALT_REQ_LOCAL_CACHE | Measure-Object).Count -eq 0 ) {
# folder empty
Write-Output " pip download from req.txt into empty local cache SALT_REQ $Env:SALT_REQ_LOCAL_CACHE"
Start_Process_and_test_exitcode "cmd" "/c $($ini['Settings']['Python2Dir'])\python.exe -m pip --disable-pip-version-check download --dest $Env:SALT_REQ_LOCAL_CACHE -r $($script_path)\req.txt" "pip download"
}
Write-Output " reading from local pip cache $Env:SALT_REQ_LOCAL_CACHE"
Write-Output " If a (new) resource is missing, please delete all files in this cache, go online and repeat"
Start_Process_and_test_exitcode "cmd" "/c $($ini['Settings']['Python2Dir'])\python.exe -m pip --disable-pip-version-check install --no-index --find-links=$Env:SALT_REQ_LOCAL_CACHE -r $($script_path)\req.txt" "pip install"
}
}
#==============================================================================
# Cleaning Up PyWin32
#==============================================================================

View file

@ -22,22 +22,10 @@
# Load parameters
param(
[switch]$Silent
[switch]$Silent,
[switch]$NoPipDependencies
)
Write-Output "================================================================="
Write-Output ""
Write-Output " Development Environment Installation"
Write-Output ""
Write-Output " - Installs All Salt Dependencies"
Write-Output " - Detects 32/64 bit Architectures"
Write-Output ""
Write-Output " To run silently add -Silent"
Write-Output " eg: dev_env.ps1 -Silent"
Write-Output ""
Write-Output "================================================================="
Write-Output ""
#==============================================================================
# Get the Directory of actual script
#==============================================================================
@ -49,6 +37,22 @@ $script_path = $script_path.DirectoryName
#==============================================================================
$script_name = $MyInvocation.MyCommand.Name
Write-Output "================================================================="
Write-Output ""
Write-Output " Development Environment Installation"
Write-Output ""
Write-Output " - Installs All Salt Dependencies"
Write-Output " - Detects 32/64 bit Architectures"
Write-Output ""
Write-Output " To run silently add -Silent"
Write-Output " eg: ${script_name} -Silent"
Write-Output ""
Write-Output " To run skip installing pip dependencies add -NoPipDependencies"
Write-Output " eg: ${script_name} -NoPipDependencies"
Write-Output ""
Write-Output "================================================================="
Write-Output ""
#==============================================================================
# Import Modules
#==============================================================================
@ -211,23 +215,45 @@ if ( ! [bool]$Env:SALT_PIP_LOCAL_CACHE) {
}
#==============================================================================
# Install pypi resources using pip
# Install windows specific pypi resources using pip
# caching depends on environment variable SALT_REQ_LOCAL_CACHE
#==============================================================================
Write-Output " ----------------------------------------------------------------"
Write-Output " - $script_name :: Installing pypi resources using pip . . ."
Write-Output " - $script_name :: Installing windows specific pypi resources using pip . . ."
Write-Output " ----------------------------------------------------------------"
if ( ! [bool]$Env:SALT_REQ_LOCAL_CACHE) {
Start_Process_and_test_exitcode "cmd" "/c $($ini['Settings']['Python3Dir'])\python.exe -m pip --disable-pip-version-check --no-cache-dir install -r $($script_path)\req.txt" "pip install"
Start_Process_and_test_exitcode "cmd" "/c $($ini['Settings']['Python3Dir'])\python.exe -m pip --disable-pip-version-check --no-cache-dir install -r $($script_path)\req_win.txt" "pip install"
} else {
if ( (Get-ChildItem $Env:SALT_REQ_LOCAL_CACHE | Measure-Object).Count -eq 0 ) {
# folder empty
Write-Output " pip download from req.txt into empty local cache SALT_REQ $Env:SALT_REQ_LOCAL_CACHE"
Start_Process_and_test_exitcode "cmd" "/c $($ini['Settings']['Python3Dir'])\python.exe -m pip --disable-pip-version-check download --dest $Env:SALT_REQ_LOCAL_CACHE -r $($script_path)\req.txt" "pip download"
Write-Output " pip download from req_win.txt into empty local cache SALT_REQ $Env:SALT_REQ_LOCAL_CACHE"
Start_Process_and_test_exitcode "cmd" "/c $($ini['Settings']['Python3Dir'])\python.exe -m pip --disable-pip-version-check download --dest $Env:SALT_REQ_LOCAL_CACHE -r $($script_path)\req_win.txt" "pip download"
}
Write-Output " reading from local pip cache $Env:SALT_REQ_LOCAL_CACHE"
Write-Output " If a (new) resource is missing, please delete all files in this cache, go online and repeat"
Start_Process_and_test_exitcode "cmd" "/c $($ini['Settings']['Python3Dir'])\python.exe -m pip --disable-pip-version-check install --no-index --find-links=$Env:SALT_REQ_LOCAL_CACHE -r $($script_path)\req.txt" "pip install"
Start_Process_and_test_exitcode "cmd" "/c $($ini['Settings']['Python3Dir'])\python.exe -m pip --disable-pip-version-check install --no-index --find-links=$Env:SALT_REQ_LOCAL_CACHE -r $($script_path)\req_win.txt" "pip install"
}
#==============================================================================
# Install pypi resources using pip
# caching depends on environment variable SALT_REQ_LOCAL_CACHE
#==============================================================================
If ($NoPipDependencies -eq $false) {
Write-Output " ----------------------------------------------------------------"
Write-Output " - $script_name :: Installing pypi resources using pip . . ."
Write-Output " ----------------------------------------------------------------"
if ( ! [bool]$Env:SALT_REQ_LOCAL_CACHE) {
Start_Process_and_test_exitcode "cmd" "/c $($ini['Settings']['Python3Dir'])\python.exe -m pip --disable-pip-version-check --no-cache-dir install -r $($script_path)\req.txt" "pip install"
} else {
if ( (Get-ChildItem $Env:SALT_REQ_LOCAL_CACHE | Measure-Object).Count -eq 0 ) {
# folder empty
Write-Output " pip download from req.txt into empty local cache SALT_REQ $Env:SALT_REQ_LOCAL_CACHE"
Start_Process_and_test_exitcode "cmd" "/c $($ini['Settings']['Python3Dir'])\python.exe -m pip --disable-pip-version-check download --dest $Env:SALT_REQ_LOCAL_CACHE -r $($script_path)\req.txt" "pip download"
}
Write-Output " reading from local pip cache $Env:SALT_REQ_LOCAL_CACHE"
Write-Output " If a (new) resource is missing, please delete all files in this cache, go online and repeat"
Start_Process_and_test_exitcode "cmd" "/c $($ini['Settings']['Python3Dir'])\python.exe -m pip --disable-pip-version-check install --no-index --find-links=$Env:SALT_REQ_LOCAL_CACHE -r $($script_path)\req.txt" "pip install"
}
}
#==============================================================================
@ -262,11 +288,13 @@ Remove-Item "$($ini['Settings']['Scripts3Dir'])\pywin32_*" -Force -Recurse
#==============================================================================
# Fix PyCrypto
#==============================================================================
Write-Output " ----------------------------------------------------------------"
Write-Output " - $script_name :: Fixing PyCrypto . . ."
Write-Output " ----------------------------------------------------------------"
$nt_file = "$($ini['Settings']['Python3Dir'])\Lib\site-packages\Crypto\Random\OSRNG\nt.py"
(Get-Content $nt_file) | Foreach-Object {$_ -replace '^import winrandom$', 'from Crypto.Random.OSRNG import winrandom'} | Set-Content $nt_file
If ($NoPipDependencies -eq $false) {
Write-Output " ----------------------------------------------------------------"
Write-Output " - $script_name :: Fixing PyCrypto . . ."
Write-Output " ----------------------------------------------------------------"
$nt_file = "$($ini['Settings']['Python3Dir'])\Lib\site-packages\Crypto\Random\OSRNG\nt.py"
(Get-Content $nt_file) | Foreach-Object {$_ -replace '^import winrandom$', 'from Crypto.Random.OSRNG import winrandom'} | Set-Content $nt_file
}
#==============================================================================
# Copy DLLs to Python Directory

View file

@ -70,6 +70,22 @@ ${StrStrAdv}
!define MUI_ICON "salt.ico"
!define MUI_UNICON "salt.ico"
!define MUI_WELCOMEFINISHPAGE_BITMAP "panel.bmp"
!define MUI_UNWELCOMEFINISHPAGE_BITMAP "panel.bmp"
# This entire if block can be removed for the Sodium release... including the !define MUI_WELCOMEPAGE_TEXT
# NSIS will just use the default like it does for Python 3, which should be the same test
!if "${PYTHON_VERSION}" == "2"
!define MUI_WELCOMEPAGE_TEXT "\
WARNING: Python 2 Support will be discontinued in Sodium. Salt will only ship Python 3 \
installers starting with the Sodium release.$\r$\n\
$\r$\n\
Setup will guide you through the installation of ${PRODUCT_NAME} ${PRODUCT_VERSION}.$\r$\n\
$\r$\n\
It is recommended that you close all other applications before starting Setup. This will make it possible to \
update relevant system files without having to reboot your computer.$\r$\n\
$\r$\n\
Click Next to continue."
!endif
# Welcome page
!insertmacro MUI_PAGE_WELCOME

View file

@ -1,3 +1,4 @@
-r req_win.txt
backports-abc==0.5
backports.ssl-match-hostname==3.5.0.1
certifi
@ -28,7 +29,6 @@ pyOpenSSL==17.5.0
python-dateutil==2.6.1
python-gnupg==0.4.1
pythonnet==2.3.0
pywin32==223
PyYAML==3.12
pyzmq==16.0.3
requests==2.21.0
@ -37,4 +37,3 @@ smmap==0.9.0
timelib==0.2.4
tornado==4.5.1
wheel==0.30.0a0
WMI==1.4.9

2
pkg/windows/req_win.txt Normal file
View file

@ -0,0 +1,2 @@
pywin32==223
WMI==1.4.9

View file

@ -2,8 +2,6 @@
mock>=2.0.0
SaltPyLint>=v2017.3.6
pytest>=3.5.0
git+https://github.com/saltstack/pytest-salt.git@master#egg=pytest-salt
testinfra>=1.7.0,!=1.17.0
# httpretty Needs to be here for now even though it's a dependency of boto.

View file

@ -1,4 +1,8 @@
pytest>=3.5.0
pytest-helpers-namespace
pytest-tempdir
# PyTest
pytest >= 4.0.1
pytest-cov
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

View file

@ -23,13 +23,11 @@ pyvmomi
setproctitle
cherrypy>=3.2.2,<18.0.0; python_version < '3.5' and sys.platform != 'win32' and sys.platform != 'darwin'
cherrypy>=3.2.2; python_version >= '3.5' and sys.platform != 'win32' and sys.platform != 'darwin'
ldap; sys.platform != 'win32' and sys.platform != 'darwin'
pyinotify; sys.platform != 'win32' and sys.platform != 'darwin'
PyMySQL; sys.platform != 'win32' and sys.platform != 'darwin'
jsonschema
strict_rfc3339
rfc3987
jinja2
pyOpenSSL
ioflo
dnspython

View file

@ -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.

View file

@ -329,7 +329,7 @@ class SyncClientMixin(object):
print_func=print_func
)
# TODO: document these, and test that they exist
# TODO: test that they exist
# TODO: Other things to inject??
func_globals = {'__jid__': jid,
'__user__': data['user'],

View file

@ -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,

View file

@ -1938,15 +1938,10 @@ PROVIDER_CONFIG_DEFAULTS = {
# <---- Salt Cloud Configuration Defaults ------------------------------------
def _validate_file_roots(file_roots):
def _normalize_roots(file_roots):
'''
If the file_roots option has a key that is None then we will error out,
just replace it with an empty list
Normalize file or pillar roots.
'''
if not isinstance(file_roots, dict):
log.warning('The file_roots parameter is not properly formatted,'
' using defaults')
return {'base': _expand_glob_path([salt.syspaths.BASE_FILE_ROOTS_DIR])}
for saltenv, dirs in six.iteritems(file_roots):
normalized_saltenv = six.text_type(saltenv)
if normalized_saltenv != saltenv:
@ -1958,6 +1953,30 @@ def _validate_file_roots(file_roots):
return file_roots
def _validate_pillar_roots(pillar_roots):
'''
If the pillar_roots option has a key that is None then we will error out,
just replace it with an empty list
'''
if not isinstance(pillar_roots, dict):
log.warning('The pillar_roots parameter is not properly formatted,'
' using defaults')
return {'base': _expand_glob_path([salt.syspaths.BASE_PILLAR_ROOTS_DIR])}
return _normalize_roots(pillar_roots)
def _validate_file_roots(file_roots):
'''
If the file_roots option has a key that is None then we will error out,
just replace it with an empty list
'''
if not isinstance(file_roots, dict):
log.warning('The file_roots parameter is not properly formatted,'
' using defaults')
return {'base': _expand_glob_path([salt.syspaths.BASE_FILE_ROOTS_DIR])}
return _normalize_roots(file_roots)
def _expand_glob_path(file_roots):
'''
Applies shell globbing to a set of directories and returns
@ -3767,7 +3786,7 @@ def apply_minion_config(overrides=None,
# nothing else!
opts['open_mode'] = opts['open_mode'] is True
opts['file_roots'] = _validate_file_roots(opts['file_roots'])
opts['pillar_roots'] = _validate_file_roots(opts['pillar_roots'])
opts['pillar_roots'] = _validate_pillar_roots(opts['pillar_roots'])
# Make sure ext_mods gets set if it is an untrue value
# (here to catch older bad configs)
opts['extension_modules'] = (

View file

@ -51,7 +51,11 @@ def find_file(path, saltenv='base', **kwargs):
if os.path.isabs(path):
return fnd
if saltenv not in __opts__['file_roots']:
return fnd
if '__env__' in __opts__['file_roots']:
log.debug("salt environment '%s' maps to __env__ file_roots directory", saltenv)
saltenv = '__env__'
else:
return fnd
def _add_file_stat(fnd):
'''
@ -220,6 +224,9 @@ def file_hash(load, fnd):
if 'path' not in load or 'saltenv' not in load:
return ''
path = fnd['path']
saltenv = load['saltenv']
if saltenv not in __opts__['file_roots'] and '__env__' in __opts__['file_roots']:
saltenv = '__env__'
ret = {}
# if the file doesn't exist, we can't get a hash
@ -234,7 +241,7 @@ def file_hash(load, fnd):
cache_path = os.path.join(__opts__['cachedir'],
'roots',
'hash',
load['saltenv'],
saltenv,
'{0}.hash.{1}'.format(fnd['rel'],
__opts__['hash_type']))
# if we have a cache, serve that if the mtime hasn't changed
@ -293,8 +300,13 @@ def _file_lists(load, form):
# "env" is not supported; Use "saltenv".
load.pop('env')
if load['saltenv'] not in __opts__['file_roots']:
return []
saltenv = load['saltenv']
if saltenv not in __opts__['file_roots']:
if '__env__' in __opts__['file_roots']:
log.debug("salt environment '%s' maps to __env__ file_roots directory", saltenv)
saltenv = '__env__'
else:
return []
list_cachedir = os.path.join(__opts__['cachedir'], 'file_lists', 'roots')
if not os.path.isdir(list_cachedir):
@ -303,8 +315,8 @@ def _file_lists(load, form):
except os.error:
log.critical('Unable to make cachedir %s', list_cachedir)
return []
list_cache = os.path.join(list_cachedir, '{0}.p'.format(load['saltenv']))
w_lock = os.path.join(list_cachedir, '.{0}.w'.format(load['saltenv']))
list_cache = os.path.join(list_cachedir, '{0}.p'.format(salt.utils.files.safe_filename_leaf(saltenv)))
w_lock = os.path.join(list_cachedir, '.{0}.w'.format(salt.utils.files.safe_filename_leaf(saltenv)))
cache_match, refresh_cache, save_cache = \
salt.fileserver.check_file_list_cache(
__opts__, form, list_cache, w_lock
@ -390,7 +402,7 @@ def _file_lists(load, form):
# (i.e. the "path" variable)
ret['links'][rel_path] = link_dest
for path in __opts__['file_roots'][load['saltenv']]:
for path in __opts__['file_roots'][saltenv]:
for root, dirs, files in salt.utils.path.os_walk(
path,
followlinks=__opts__['fileserver_followsymlinks']):
@ -445,7 +457,7 @@ def symlink_list(load):
load.pop('env')
ret = {}
if load['saltenv'] not in __opts__['file_roots']:
if load['saltenv'] not in __opts__['file_roots'] and '__env__' not in __opts__['file_roots']:
return ret
if 'prefix' in load:

View file

@ -22,6 +22,7 @@ import locale
import uuid
from errno import EACCES, EPERM
import datetime
import warnings
__proxyenabled__ = ['*']
__FQDN__ = None
@ -34,7 +35,12 @@ _supported_dists += ('arch', 'mageia', 'meego', 'vmware', 'bluewhite64',
# linux_distribution deprecated in py3.7
try:
from platform import linux_distribution
from platform import linux_distribution as _deprecated_linux_distribution
def linux_distribution(**kwargs):
with warnings.catch_warnings():
warnings.simplefilter("ignore")
return _deprecated_linux_distribution(**kwargs)
except ImportError:
from distro import linux_distribution
@ -1389,7 +1395,9 @@ _OS_FAMILY_MAP = {
'KDE neon': 'Debian',
'Void': 'Void',
'IDMS': 'Debian',
'AIX': 'AIX'
'Funtoo': 'Gentoo',
'AIX': 'AIX',
'TurnKey': 'Debian',
}
# Matches any possible format:

View file

@ -1582,7 +1582,7 @@ def _split_repo_str(repo):
Return APT source entry as a tuple.
'''
split = sourceslist.SourceEntry(repo)
return split.type, split.uri, split.dist, split.comps
return split.type, split.architectures, split.uri, split.dist, split.comps
def _consolidate_repo_sources(sources):
@ -1771,7 +1771,7 @@ def get_repo(repo, **kwargs):
if repos:
try:
repo_type, repo_uri, repo_dist, repo_comps = _split_repo_str(repo)
repo_type, repo_architectures, repo_uri, repo_dist, repo_comps = _split_repo_str(repo)
if ppa_auth:
uri_match = re.search('(http[s]?://)(.+)', repo_uri)
if uri_match:
@ -1844,7 +1844,11 @@ def del_repo(repo, **kwargs):
if repos:
deleted_from = dict()
try:
repo_type, repo_uri, repo_dist, repo_comps = _split_repo_str(repo)
repo_type, \
repo_architectures, \
repo_uri, \
repo_dist, \
repo_comps = _split_repo_str(repo)
except SyntaxError:
raise SaltInvocationError(
'Error: repo \'{0}\' not a well formatted definition'
@ -1852,8 +1856,10 @@ def del_repo(repo, **kwargs):
)
for source in repos:
if (source.type == repo_type and source.uri == repo_uri and
source.dist == repo_dist):
if (source.type == repo_type
and source.architectures == repo_architectures
and source.uri == repo_uri
and source.dist == repo_dist):
s_comps = set(source.comps)
r_comps = set(repo_comps)
@ -2319,7 +2325,11 @@ def mod_repo(repo, saltenv='base', **kwargs):
repos = [s for s in sources if not s.invalid]
mod_source = None
try:
repo_type, repo_uri, repo_dist, repo_comps = _split_repo_str(repo)
repo_type, \
repo_architectures, \
repo_uri, \
repo_dist, \
repo_comps = _split_repo_str(repo)
except SyntaxError:
raise SyntaxError(
'Error: repo \'{0}\' not a well formatted definition'.format(repo)
@ -2387,6 +2397,8 @@ def mod_repo(repo, saltenv='base', **kwargs):
if 'architectures' in kwargs:
kwargs['architectures'] = kwargs['architectures'].split(',')
else:
kwargs['architectures'] = repo_architectures
if 'disabled' in kwargs:
kwargs['disabled'] = salt.utils.data.is_true(kwargs['disabled'])
@ -2408,6 +2420,8 @@ def mod_repo(repo, saltenv='base', **kwargs):
mod_source = source
if not source.comps:
mod_source = source
if kwargs['architectures'] != source.architectures:
mod_source = source
if mod_source:
break

View file

@ -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

View file

@ -19,8 +19,7 @@ The firewall configuration is generated by Capirca_.
.. _Capirca: https://github.com/google/capirca
Capirca is not yet available on PyPI threrefore it has to be installed
directly form Git: ``pip install -e git+git@github.com:google/capirca.git#egg=aclgen``.
To install Capirca, execute: ``pip install capirca``.
'''
from __future__ import absolute_import, print_function, unicode_literals
@ -34,7 +33,10 @@ log = logging.getLogger(__file__)
# Import third party libs
from salt.ext import six
try:
import aclgen
import capirca
import capirca.aclgen
import capirca.lib.policy
import capirca.lib.aclgenerator
HAS_CAPIRCA = True
except ImportError:
HAS_CAPIRCA = False
@ -69,10 +71,12 @@ def __virtual__():
# module globals
# ------------------------------------------------------------------------------
# define the default values for all possible term fields
# we could also extract them from the `policy` module, inspecting the `Policy`
# class, but that might be overkill & it would make the code less obvious.
# we can revisit this later if necessary.
_TERM_FIELDS = {
'action': [],
'address': [],
@ -161,7 +165,19 @@ _SERVICES = {}
if HAS_CAPIRCA:
class _Policy(aclgen.policy.Policy):
_TempTerm = capirca.lib.policy.Term
def _add_object(self, obj):
return
setattr(_TempTerm, 'AddObject', _add_object)
dumy_term = _TempTerm(None)
for item in dir(dumy_term):
if hasattr(item, '__func__') or item.startswith('_') or item != item.lower():
continue
_TERM_FIELDS[item] = getattr(dumy_term, item)
class _Policy(capirca.lib.policy.Policy):
'''
Extending the Capirca Policy class to allow inserting custom filters.
'''
@ -169,7 +185,7 @@ if HAS_CAPIRCA:
self.filters = []
self.filename = ''
class _Term(aclgen.policy.Term):
class _Term(capirca.lib.policy.Term):
'''
Extending the Capirca Term class to allow setting field valued on the fly.
'''
@ -186,10 +202,10 @@ def _import_platform_generator(platform):
for a class inheriting the `ACLGenerator` class.
'''
log.debug('Using platform: {plat}'.format(plat=platform))
for mod_name, mod_obj in inspect.getmembers(aclgen):
for mod_name, mod_obj in inspect.getmembers(capirca.aclgen):
if mod_name == platform and inspect.ismodule(mod_obj):
for plat_obj_name, plat_obj in inspect.getmembers(mod_obj): # pylint: disable=unused-variable
if inspect.isclass(plat_obj) and issubclass(plat_obj, aclgen.aclgenerator.ACLGenerator):
if inspect.isclass(plat_obj) and issubclass(plat_obj, capirca.lib.aclgenerator.ACLGenerator):
log.debug('Identified Capirca class {cls} for {plat}'.format(
cls=plat_obj,
plat=platform))
@ -366,7 +382,11 @@ def _clean_term_opts(term_opts):
# IP-type fields need to be transformed
ip_values = []
for addr in value:
ip_values.append(aclgen.policy.nacaddr.IP(addr))
if six.PY2:
addr = six.text_type(addr)
# Adding this, as ipaddress would complain about valid
# addresses not being valid. #pythonIsFun
ip_values.append(capirca.lib.policy.nacaddr.IP(addr))
value = ip_values[:]
clean_opts[field] = value
return clean_opts
@ -427,7 +447,7 @@ def _merge_list_of_dict(first, second, prepend=True):
if first and not second:
return first
# Determine overlaps
# So we don't change the position of the existing terms/filters
# So we dont change the position of the existing terms/filters
overlaps = []
merged = []
appended = []
@ -514,7 +534,7 @@ def _get_policy_object(platform,
continue # go to the next filter
filter_name = filter_.keys()[0]
filter_config = filter_.values()[0]
header = aclgen.policy.Header() # same header everywhere
header = capirca.lib.policy.Header() # same header everywhere
target_opts = [
platform,
filter_name
@ -524,7 +544,7 @@ def _get_policy_object(platform,
filter_options = _make_it_list({}, filter_name, filter_options)
# make sure the filter options are sent as list
target_opts.extend(filter_options)
target = aclgen.policy.Target(target_opts)
target = capirca.lib.policy.Target(target_opts)
header.AddObject(target)
filter_terms = []
for term_ in filter_config.get('terms', []):

View file

@ -280,7 +280,7 @@ def _run(cmd,
'''
if 'pillar' in kwargs and not pillar_override:
pillar_override = kwargs['pillar']
if _is_valid_shell(shell) is False:
if output_loglevel != 'quiet' and _is_valid_shell(shell) is False:
log.warning(
'Attempt to run a shell command with what may be an invalid shell! '
'Check to ensure that the shell <%s> is valid for this user.',

View file

@ -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']

View file

@ -91,8 +91,12 @@ def install(gems, # pylint: disable=C0103
Doesn't play nice with multiple gems at once
:param rdoc: boolean : False
Generate RDoc documentation for the gem(s).
For rubygems > 3 this is interpreted as the --no-document arg and the
ri option will then be ignored
:param ri: boolean : False
Generate RI documentation for the gem(s).
For rubygems > 3 this is interpreted as the --no-document arg and the
rdoc option will then be ignored
:param pre_releases: boolean : False
Include pre-releases in the available versions
:param proxy: string : None
@ -119,12 +123,18 @@ def install(gems, # pylint: disable=C0103
options = []
if version:
options.extend(['--version', version])
if not rdoc:
options.append('--no-rdoc')
if not ri:
options.append('--no-ri')
if pre_releases:
options.append('--pre')
if _has_rubygems_3(ruby=ruby, runas=runas, gem_bin=gem_bin):
if not rdoc or not ri:
options.append('--no-document')
if pre_releases:
options.append('--prerelease')
else:
if not rdoc:
options.append('--no-rdoc')
if not ri:
options.append('--no-ri')
if pre_releases:
options.append('--pre')
if proxy:
options.extend(['-p', proxy])
if source:
@ -224,6 +234,45 @@ def update_system(version='', ruby=None, runas=None, gem_bin=None):
runas=runas)
def version(ruby=None, runas=None, gem_bin=None):
'''
Print out the version of gem
:param gem_bin: string : None
Full path to ``gem`` binary to use.
:param ruby: string : None
If RVM or rbenv are installed, the ruby version and gemset to use.
Ignored if ``gem_bin`` is specified.
:param runas: string : None
The user to run gem as.
CLI Example:
.. code-block:: bash
salt '*' gem.version
'''
cmd = ['--version']
stdout = _gem(cmd,
ruby,
gem_bin=gem_bin,
runas=runas)
ret = {}
for line in salt.utils.itertools.split(stdout, '\n'):
match = re.match(r'[.0-9]+', line)
if match:
ret = line
break
return ret
def _has_rubygems_3(ruby=None, runas=None, gem_bin=None):
match = re.match(r'^3\..*', version(ruby=ruby, runas=runas, gem_bin=gem_bin))
if match:
return True
return False
def list_(prefix='', ruby=None, runas=None, gem_bin=None):
'''
List locally installed gems.

View file

@ -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

View file

@ -226,6 +226,7 @@ def _resolve_user_group_names(opts):
if _info and _param in _info:
_id = _info[_param]
opts[ind] = _param + '=' + six.text_type(_id)
opts[ind] = opts[ind].replace('\\040', '\\ ')
return opts
@ -727,7 +728,7 @@ def set_fstab(
'name': name,
'device': device.replace('\\ ', '\\040'),
'fstype': fstype,
'opts': opts,
'opts': opts.replace('\\ ', '\\040'),
'dump': dump,
'pass_num': pass_num,
}

View file

@ -1266,6 +1266,7 @@ def user_exists(user,
'''
run_verify = False
server_version = version(**connection_args)
compare_version = '10.2.0' if 'MariaDB' in server_version else '8.0.11'
dbc = _connect(**connection_args)
# Did we fail to connect with the user we are checking
# Its password might have previously change with the same command/state
@ -1297,7 +1298,7 @@ def user_exists(user,
else:
qry += ' AND ' + password_column + ' = \'\''
elif password:
if salt.utils.versions.version_cmp(server_version, '8.0.11') >= 0:
if salt.utils.versions.version_cmp(server_version, compare_version) >= 0:
run_verify = True
else:
_password = password
@ -1404,6 +1405,7 @@ def user_create(user,
salt '*' mysql.user_create 'username' 'hostname' allow_passwordless=True
'''
server_version = version(**connection_args)
compare_version = '10.2.0' if 'MariaDB' in server_version else '8.0.11'
if user_exists(user, host, **connection_args):
log.info('User \'%s\'@\'%s\' already exists', user, host)
return False
@ -1424,7 +1426,7 @@ def user_create(user,
qry += ' IDENTIFIED BY %(password)s'
args['password'] = six.text_type(password)
elif password_hash is not None:
if salt.utils.versions.version_cmp(server_version, '8.0.11') >= 0:
if salt.utils.versions.version_cmp(server_version, compare_version) >= 0:
qry += ' IDENTIFIED BY %(password)s'
else:
qry += ' IDENTIFIED BY PASSWORD %(password)s'
@ -1508,9 +1510,10 @@ def user_chpass(user,
salt '*' mysql.user_chpass frank localhost allow_passwordless=True
'''
server_version = version(**connection_args)
compare_version = '10.2.0' if 'MariaDB' in server_version else '8.0.11'
args = {}
if password is not None:
if salt.utils.versions.version_cmp(server_version, '8.0.11') >= 0:
if salt.utils.versions.version_cmp(server_version, compare_version) >= 0:
password_sql = '%(password)s'
else:
password_sql = 'PASSWORD(%(password)s)'
@ -1533,28 +1536,23 @@ def user_chpass(user,
password_column = __password_column(**connection_args)
cur = dbc.cursor()
if salt.utils.versions.version_cmp(server_version, '8.0.11') >= 0:
qry = ("ALTER USER '" + user + "'@'" + host + "'"
" IDENTIFIED BY '" + password + "';")
args = {}
args['user'] = user
args['host'] = host
if salt.utils.versions.version_cmp(server_version, compare_version) >= 0:
qry = "ALTER USER %(user)s@%(host)s IDENTIFIED BY %(password)s;"
else:
qry = ('UPDATE mysql.user SET ' + password_column + '='
+ password_sql +
qry = ('UPDATE mysql.user SET ' + password_column + '=' + password_sql +
' WHERE User=%(user)s AND Host = %(host)s;')
args['user'] = user
args['host'] = host
if salt.utils.data.is_true(allow_passwordless) and \
salt.utils.data.is_true(unix_socket):
if host == 'localhost':
if salt.utils.versions.version_cmp(server_version, '8.0.11') >= 0:
qry = ("ALTER USER '" + user + "'@'" + host + "'"
" IDENTIFIED BY '" + password + "';")
args = {}
args['unix_socket'] = 'auth_socket'
if salt.utils.versions.version_cmp(server_version, compare_version) >= 0:
qry = "ALTER USER %(user)s@%(host)s IDENTIFIED WITH %(unix_socket)s AS %(user)s;"
else:
qry = ('UPDATE mysql.user SET ' + password_column + '='
+ password_sql + ', plugin=%(unix_socket)s' +
' WHERE User=%(user)s AND Host = %(host)s;')
args['unix_socket'] = 'unix_socket'
else:
log.error('Auth via unix_socket can be set only for host=localhost')
try:
@ -1565,7 +1563,7 @@ def user_chpass(user,
log.error(err)
return False
if salt.utils.versions.version_cmp(server_version, '8.0.11') >= 0:
if salt.utils.versions.version_cmp(server_version, compare_version) >= 0:
_execute(cur, 'FLUSH PRIVILEGES;')
log.info(
'Password for user \'%s\'@\'%s\' has been %s',
@ -1869,7 +1867,8 @@ def grant_exists(grant,
server_version = version(**connection_args)
if 'ALL' in grant:
if salt.utils.versions.version_cmp(server_version, '8.0') >= 0:
if salt.utils.versions.version_cmp(server_version, '8.0') >= 0 and \
'MariaDB' not in server_version:
grant = ','.join([i for i in __all_privileges__])
else:
grant = 'ALL PRIVILEGES'

View file

@ -19,6 +19,8 @@ The firewall configuration is generated by Capirca_.
.. _Capirca: https://github.com/google/capirca
To install Capirca, execute: ``pip install capirca``.
To be able to load configuration on network devices,
it requires NAPALM_ library to be installed: ``pip install napalm``.
Please check Installation_ for complete details.
@ -34,7 +36,10 @@ log = logging.getLogger(__file__)
# Import third party libs
try:
# pylint: disable=W0611
import aclgen
import capirca
import capirca.aclgen
import capirca.lib.policy
import capirca.lib.aclgenerator
HAS_CAPIRCA = True
# pylint: enable=W0611
except ImportError:

View file

@ -1620,7 +1620,7 @@ def set_authentication_profile(profile=None, deploy=False):
'''
if not profile:
CommandExecutionError("Profile name option must not be none.")
raise CommandExecutionError("Profile name option must not be none.")
ret = {}
@ -1657,7 +1657,7 @@ def set_hostname(hostname=None, deploy=False):
'''
if not hostname:
CommandExecutionError("Hostname option must not be none.")
raise CommandExecutionError("Hostname option must not be none.")
ret = {}
@ -1697,7 +1697,7 @@ def set_management_icmp(enabled=True, deploy=False):
elif enabled is False:
value = "yes"
else:
CommandExecutionError("Invalid option provided for service enabled option.")
raise CommandExecutionError("Invalid option provided for service enabled option.")
ret = {}
@ -1737,7 +1737,7 @@ def set_management_http(enabled=True, deploy=False):
elif enabled is False:
value = "yes"
else:
CommandExecutionError("Invalid option provided for service enabled option.")
raise CommandExecutionError("Invalid option provided for service enabled option.")
ret = {}
@ -1777,7 +1777,7 @@ def set_management_https(enabled=True, deploy=False):
elif enabled is False:
value = "yes"
else:
CommandExecutionError("Invalid option provided for service enabled option.")
raise CommandExecutionError("Invalid option provided for service enabled option.")
ret = {}
@ -1817,7 +1817,7 @@ def set_management_ocsp(enabled=True, deploy=False):
elif enabled is False:
value = "yes"
else:
CommandExecutionError("Invalid option provided for service enabled option.")
raise CommandExecutionError("Invalid option provided for service enabled option.")
ret = {}
@ -1857,7 +1857,7 @@ def set_management_snmp(enabled=True, deploy=False):
elif enabled is False:
value = "yes"
else:
CommandExecutionError("Invalid option provided for service enabled option.")
raise CommandExecutionError("Invalid option provided for service enabled option.")
ret = {}
@ -1897,7 +1897,7 @@ def set_management_ssh(enabled=True, deploy=False):
elif enabled is False:
value = "yes"
else:
CommandExecutionError("Invalid option provided for service enabled option.")
raise CommandExecutionError("Invalid option provided for service enabled option.")
ret = {}
@ -1937,7 +1937,7 @@ def set_management_telnet(enabled=True, deploy=False):
elif enabled is False:
value = "yes"
else:
CommandExecutionError("Invalid option provided for service enabled option.")
raise CommandExecutionError("Invalid option provided for service enabled option.")
ret = {}
@ -2130,7 +2130,7 @@ def set_permitted_ip(address=None, deploy=False):
'''
if not address:
CommandExecutionError("Address option must not be empty.")
raise CommandExecutionError("Address option must not be empty.")
ret = {}
@ -2166,7 +2166,7 @@ def set_timezone(tz=None, deploy=False):
'''
if not tz:
CommandExecutionError("Timezone name option must not be none.")
raise CommandExecutionError("Timezone name option must not be none.")
ret = {}

View file

@ -10,7 +10,6 @@ import collections
# Import third party libs
import copy
import os
import copy
import logging
from salt.ext import six
@ -157,7 +156,7 @@ def get(key,
'skipped.', default, ret, type(ret).__name__
)
elif isinstance(default, list):
ret = salt.utils.data.traverse_dict_and_list(
ret = salt.utils.data.traverse_dict_and_list( # pylint: disable=redefined-variable-type
pillar_dict,
key,
[],
@ -345,7 +344,7 @@ def ls(*args):
salt '*' pillar.ls
'''
return list(items(*args).keys())
return list(items(*args))
def item(*args, **kwargs):
@ -544,7 +543,7 @@ def keys(key, delimiter=DEFAULT_TARGET_DELIM):
if not isinstance(ret, dict):
raise ValueError("Pillar value in key {0} is not a dict".format(key))
return ret.keys()
return list(ret)
def file_exists(path, saltenv=None):

View file

@ -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():

View file

@ -46,6 +46,7 @@ import salt.utils.data
import salt.utils.functools
import salt.utils.path
import salt.utils.pkg
from salt.ext.six import string_types
from salt.exceptions import CommandExecutionError
# Define the module's virtual name
@ -474,12 +475,16 @@ def install(name=None, refresh=False, pkgs=None, version=None, test=False, **kwa
pkg2inst = ''
if pkgs: # multiple packages specified
pkg2inst = []
for pkg in pkgs:
if list(pkg.items())[0][1]: # version specified
pkg2inst += '{0}@{1} '.format(list(pkg.items())[0][0],
list(pkg.items())[0][1])
if getattr(pkg, 'items', False):
if list(pkg.items())[0][1]: # version specified
pkg2inst.append('{0}@{1}'.format(list(pkg.items())[0][0],
list(pkg.items())[0][1]))
else:
pkg2inst.append(list(pkg.items())[0][0])
else:
pkg2inst += '{0} '.format(list(pkg.items())[0][0])
pkg2inst.append("{0}".format(pkg))
log.debug('Installing these packages instead of %s: %s',
name, pkg2inst)
@ -499,7 +504,10 @@ def install(name=None, refresh=False, pkgs=None, version=None, test=False, **kwa
# Install or upgrade the package
# If package is already installed
cmd.append(pkg2inst)
if isinstance(pkg2inst, string_types):
cmd.append(pkg2inst)
elif isinstance(pkg2inst, list):
cmd = cmd + pkg2inst
out = __salt__['cmd.run_all'](cmd, output_loglevel='trace')

View file

@ -19,7 +19,6 @@ import re
import subprocess
# Import salt libs
from salt.ext import six
import salt.utils.decorators.path
import salt.utils.data
import salt.utils.files
@ -44,9 +43,8 @@ if six.PY3:
def __virtual__():
# TODO: This could work on windows with some love
if salt.utils.platform.is_windows():
return (False, 'The module cannot be loaded on windows.')
if not salt.utils.path.which('ssh'):
return False, 'The module requires the ssh binary.'
return True
@ -753,9 +751,10 @@ def set_auth_key(
if not os.path.isdir(os.path.dirname(fconfig)):
dpath = os.path.dirname(fconfig)
os.makedirs(dpath)
if os.geteuid() == 0:
os.chown(dpath, uinfo['uid'], uinfo['gid'])
os.chmod(dpath, 448)
if not salt.utils.platform.is_windows():
if os.geteuid() == 0:
os.chown(dpath, uinfo['uid'], uinfo['gid'])
os.chmod(dpath, 448)
# If SELINUX is available run a restorecon on the file
rcon = salt.utils.path.which('restorecon')
if rcon:
@ -784,9 +783,10 @@ def set_auth_key(
raise CommandExecutionError(msg.format(exc))
if new_file:
if os.geteuid() == 0:
os.chown(fconfig, uinfo['uid'], uinfo['gid'])
os.chmod(fconfig, 384)
if not salt.utils.platform.is_windows():
if os.geteuid() == 0:
os.chown(fconfig, uinfo['uid'], uinfo['gid'])
os.chmod(fconfig, 384)
# If SELINUX is available run a restorecon on the file
rcon = salt.utils.path.which('restorecon')
if rcon:
@ -1104,10 +1104,11 @@ def rm_known_host(user=None, hostname=None, config=None, port=None):
ssh_hostname = _hostname_and_port_to_ssh_hostname(hostname, port)
cmd = ['ssh-keygen', '-R', ssh_hostname, '-f', full]
cmd_result = __salt__['cmd.run'](cmd, python_shell=False)
# ssh-keygen creates a new file, thus a chown is required.
if os.geteuid() == 0 and user:
uinfo = __salt__['user.info'](user)
os.chown(full, uinfo['uid'], uinfo['gid'])
if not salt.utils.platform.is_windows():
# ssh-keygen creates a new file, thus a chown is required.
if os.geteuid() == 0 and user:
uinfo = __salt__['user.info'](user)
os.chown(full, uinfo['uid'], uinfo['gid'])
return {'status': 'removed', 'comment': cmd_result}
@ -1317,12 +1318,13 @@ def set_known_host(user=None,
"Couldn't append to known hosts file: '{0}'".format(exception)
)
if os.geteuid() == 0 and user:
os.chown(full, uinfo['uid'], uinfo['gid'])
if origmode:
os.chmod(full, origmode)
else:
os.chmod(full, 0o600)
if not salt.utils.platform.is_windows():
if os.geteuid() == 0 and user:
os.chown(full, uinfo['uid'], uinfo['gid'])
if origmode:
os.chmod(full, origmode)
else:
os.chmod(full, 0o600)
if key and hash_known_hosts:
cmd_result = __salt__['ssh.hash_known_hosts'](user=user, config=full)
@ -1446,10 +1448,11 @@ def hash_known_hosts(user=None, config=None):
cmd = ['ssh-keygen', '-H', '-f', full]
cmd_result = __salt__['cmd.run'](cmd, python_shell=False)
os.chmod(full, origmode)
# ssh-keygen creates a new file, thus a chown is required.
if os.geteuid() == 0 and user:
uinfo = __salt__['user.info'](user)
os.chown(full, uinfo['uid'], uinfo['gid'])
if not salt.utils.platform.is_windows():
# ssh-keygen creates a new file, thus a chown is required.
if os.geteuid() == 0 and user:
uinfo = __salt__['user.info'](user)
os.chown(full, uinfo['uid'], uinfo['gid'])
return {'status': 'updated', 'comment': cmd_result}

View file

@ -739,7 +739,7 @@ def set_lcm_config(config_mode=None,
cmd += ' RefreshFrequencyMins = {0};'.format(refresh_freq)
if reboot_if_needed is not None:
if not isinstance(reboot_if_needed, bool):
SaltInvocationError('reboot_if_needed must be a boolean value')
raise SaltInvocationError('reboot_if_needed must be a boolean value')
if reboot_if_needed:
reboot_if_needed = '$true'
else:

File diff suppressed because it is too large Load diff

View file

@ -205,17 +205,22 @@ def get_zone():
Returns:
str: Timezone in unix format
Raises:
CommandExecutionError: If timezone could not be gathered
CLI Example:
.. code-block:: bash
salt '*' timezone.get_zone
'''
win_zone = __utils__['reg.read_value'](
hive='HKLM',
key='SYSTEM\\CurrentControlSet\\Control\\TimeZoneInformation',
vname='TimeZoneKeyName')['vdata']
return mapper.get_unix(win_zone.lower(), 'Unknown')
cmd = ['tzutil', '/g']
res = __salt__['cmd.run_all'](cmd, python_shell=False)
if res['retcode'] or not res['stdout']:
raise CommandExecutionError('tzutil encountered an error getting '
'timezone',
info=res)
return mapper.get_unix(res['stdout'].lower(), 'Unknown')
def get_offset():

View file

@ -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

View file

@ -34,6 +34,11 @@ import salt.utils.odict
import salt.utils.stringutils
from salt.ext import six
try:
from collections.abc import Mapping
except ImportError:
from collections import Mapping
class NestDisplay(object):
'''
@ -142,7 +147,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 +155,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:

View file

@ -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

View file

@ -2,26 +2,36 @@
'''
Retrieve EC2 instance data for minions for ec2_tags and ec2_tags_list
The minion id must be the AWS instance-id or value in 'tag_match_key'.
For example set 'tag_match_key' to 'Name', to have the minion-id matched against the
tag 'Name'. The tag contents must be unique. The value of tag_match_value can
be 'uqdn' or 'asis'. if 'uqdn' strips any domain before comparison.
The minion id must be the AWS instance-id or value in ``tag_match_key``. For
example set ``tag_match_key`` to ``Name`` to have the minion-id matched against
the tag 'Name'. The tag contents must be unique. The value of
``tag_match_value`` can be 'uqdn' or 'asis'. if 'uqdn', then the domain will be
stripped before comparison.
The option use_grain can be set to True. This allows the use of an
instance-id grain instead of the minion-id. Since this is a potential
security risk, the configuration can be further expanded to include
a list of minions that are trusted to only allow the alternate id
of the instances to specific hosts. There is no glob matching at
this time.
Additionally, the ``use_grain`` option can be set to ``True``. This allows the
use of an instance-id grain instead of the minion-id. Since this is a potential
security risk, the configuration can be further expanded to include a list of
minions that are trusted to only allow the alternate id of the instances to
specific hosts. There is no glob matching at this time.
The optional 'tag_list_key' indicates which keys should be added to
'ec2_tags_list' and be split by tag_list_sep (default `;`). If a tag key is
included in 'tag_list_key' it is removed from ec2_tags. If a tag does not
exist it is still included as an empty list.
.. note::
If you are using ``use_grain: True`` in the configuration for this external
pillar module, the minion must have :conf_minion:`metadata_server_grains`
enabled in the minion config file (see also :py:mod:`here
<salt.grains.metadata>`).
It is important to also note that enabling the ``use_grain`` option allows
the minion to manipulate the pillar data returned, as described above.
The optional ``tag_list_key`` indicates which keys should be added to
``ec2_tags_list`` and be split by ``tag_list_sep`` (by default ``;``). If a tag
key is included in ``tag_list_key`` it is removed from ec2_tags. If a tag does
not exist it is still included as an empty list.
Note: restart the salt-master for changes to take effect.
..note::
As with any master configuration change, restart the salt-master daemon for
changes to take effect.
.. code-block:: yaml
@ -38,11 +48,10 @@ exist it is still included as an empty list.
- trusted-minion-2
- trusted-minion-3
This is a very simple pillar that simply retrieves the instance data
from AWS. Currently the only portion implemented are EC2 tags, which
returns a list of key/value pairs for all of the EC2 tags assigned to
the instance.
This is a very simple pillar configuration that simply retrieves the instance
data from AWS. Currently the only portion implemented are EC2 tags, which
returns a list of key/value pairs for all of the EC2 tags assigned to the
instance.
'''
# Import python libs

View file

@ -225,8 +225,7 @@ def returner(ret):
'functions', job_id, job_fun
)
return
if ret.get('return', None) is None:
if ret.get('data', None) is None and ret.get('return') is None:
log.info(
'Won\'t push new data to Elasticsearch, job with jid=%s was '
'not successful', job_id

View file

@ -77,6 +77,9 @@ def _walk_through(job_dir):
except Exception:
log.exception('Failed to deserialize %s', load_path)
continue
if not job:
log.error('Deserialization of job succeded but there is no data in %s', load_path)
continue
jid = job['jid']
yield jid, job, t_path, final

View file

@ -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))

View file

@ -209,7 +209,7 @@ def orchestrate_high(data, test=None, queue=False, pillar=None, **kwargs):
def orchestrate_show_sls(mods,
saltenv='base',
test=None,
exclude=None,
queue=False,
pillar=None,
pillarenv=None,
pillar_enc=None):
@ -234,12 +234,12 @@ def orchestrate_show_sls(mods,
minion = salt.minion.MasterMinion(__opts__)
running = minion.functions['state.show_sls'](
mods,
saltenv,
test,
exclude,
queue,
pillar=pillar,
pillarenv=pillarenv,
pillar_enc=pillar_enc)
pillar_enc=pillar_enc,
saltenv=saltenv)
ret = {minion.opts['id']: running}
return ret

View file

@ -3767,12 +3767,14 @@ class BaseHighState(object):
statefiles = []
for saltenv, states in six.iteritems(matches):
for sls_match in states:
try:
if saltenv in self.avail:
statefiles = fnmatch.filter(self.avail[saltenv], sls_match)
except KeyError:
all_errors.extend(
['No matching salt environment for environment '
'\'{0}\' found'.format(saltenv)]
elif '__env__' in self.avail:
statefiles = fnmatch.filter(self.avail['__env__'], sls_match)
else:
all_errors.append(
'No matching salt environment for environment '
'\'{0}\' found'.format(saltenv)
)
# if we did not found any sls in the fileserver listing, this
# may be because the sls was generated or added later, we can

View file

@ -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:
@ -2503,6 +2503,7 @@ def managed(name,
ret, 'Defaults must be formed as a dict')
if not replace and os.path.exists(name):
ret_perms = {}
# Check and set the permissions if necessary
if salt.utils.platform.is_windows():
ret = __salt__['file.check_perms'](
@ -2514,10 +2515,19 @@ def managed(name,
inheritance=win_inheritance,
reset=win_perms_reset)
else:
ret, _ = __salt__['file.check_perms'](
ret, ret_perms = __salt__['file.check_perms'](
name, ret, user, group, mode, attrs, follow_symlinks)
if __opts__['test']:
ret['comment'] = 'File {0} not updated'.format(name)
if isinstance(ret_perms, dict) and \
'lmode' in ret_perms and \
mode != ret_perms['lmode']:
ret['comment'] = ('File {0} will be updated with permissions '
'{1} from its current '
'state of {2}'.format(name,
mode,
ret_perms['lmode']))
else:
ret['comment'] = 'File {0} not updated'.format(name)
elif not ret['changes'] and ret['result']:
ret['comment'] = ('File {0} exists with proper permissions. '
'No changes made.'.format(name))
@ -3266,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:

View file

@ -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)

View file

@ -3,7 +3,7 @@
Network ACL
===========
Manage the firewall configuration on the network device namaged through NAPALM.
Manage the firewall configuration on the network device managed through NAPALM.
The firewall configuration is generated by Capirca_.
.. _Capirca: https://github.com/google/capirca
@ -18,7 +18,13 @@ The firewall configuration is generated by Capirca_.
Dependencies
------------
Capirca: ``pip install -e git+git@github.com:google/capirca.git#egg=aclgen``
Capirca
~~~~~~~
To install Capirca, execute: ``pip install capirca``.
NAPALM
~~~~~~
To be able to load configuration on network devices,
it requires NAPALM_ library to be installed: ``pip install napalm``.
@ -35,7 +41,10 @@ log = logging.getLogger(__file__)
# Import third party libs
try:
# pylint: disable=W0611
import aclgen
import capirca
import capirca.aclgen
import capirca.lib.policy
import capirca.lib.aclgenerator
HAS_CAPIRCA = True
# pylint: enable=W0611
except ImportError:

View file

@ -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'

View file

@ -457,6 +457,9 @@ def managed(name, ppa=None, **kwargs):
sanitizedkwargs[kwarg])
if precomments != kwargcomments:
break
elif kwarg == 'architectures' and sanitizedkwargs[kwarg]:
if set(sanitizedkwargs[kwarg]) != set(pre[kwarg]):
break
else:
if __grains__['os_family'] in ('RedHat', 'Suse') \
and any(isinstance(x, bool) for x in
@ -476,11 +479,18 @@ def managed(name, ppa=None, **kwargs):
if __opts__['test']:
ret['comment'] = (
'Package repo \'{0}\' will be configured. This may cause pkg '
'Package repo \'{0}\' would be configured. This may cause pkg '
'states to behave differently than stated if this action is '
'repeated without test=True, due to the differences in the '
'configured repositories.'.format(name)
)
if pre:
for kwarg in sanitizedkwargs:
if sanitizedkwargs.get(kwarg) != pre.get(kwarg):
ret['changes'][kwarg] = {'new': sanitizedkwargs.get(kwarg),
'old': pre.get(kwarg)}
else:
ret['changes']['repo'] = name
return ret
# empty file before configure
@ -509,9 +519,8 @@ def managed(name, ppa=None, **kwargs):
if pre:
for kwarg in sanitizedkwargs:
if post.get(kwarg) != pre.get(kwarg):
change = {'new': post[kwarg],
'old': pre.get(kwarg)}
ret['changes'][kwarg] = change
ret['changes'][kwarg] = {'new': post.get(kwarg),
'old': pre.get(kwarg)}
else:
ret['changes'] = {'repo': repo}

View file

@ -284,6 +284,8 @@ def state(name,
cmd_kw['tgt_type'] = tgt_type
cmd_kw['ssh'] = ssh
if 'roster' in kwargs:
cmd_kw['roster'] = kwargs['roster']
cmd_kw['expect_minions'] = expect_minions
if highstate:
fun = 'state.highstate'

View file

@ -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:

View file

@ -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):

View file

@ -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)

View file

@ -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):
'''

View file

@ -23,6 +23,7 @@ import shlex
import socket
import ssl
import string
import functools
# Import Salt libs
import salt.utils.files
@ -45,6 +46,7 @@ try:
except ImportError:
HAS_DNSPYTHON = False
HAS_DIG = salt.utils.path.which('dig') is not None
DIG_OPTIONS = '+search +fail +noall +answer +nocl +nottl'
HAS_DRILL = salt.utils.path.which('drill') is not None
HAS_HOST = salt.utils.path.which('host') is not None
HAS_NSLOOKUP = salt.utils.path.which('nslookup') is not None
@ -229,7 +231,7 @@ def _lookup_dig(name, rdtype, timeout=None, servers=None, secure=None):
:param servers: [] of servers to use
:return: [] of records or False if error
'''
cmd = 'dig +search +fail +noall +answer +noclass +nottl -t {0} '.format(rdtype)
cmd = 'dig {0} -t {1} '.format(DIG_OPTIONS, rdtype)
if servers:
cmd += ''.join(['@{0} '.format(srv) for srv in servers])
if timeout is not None:
@ -364,12 +366,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 +383,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 +567,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]

View file

@ -11,8 +11,8 @@
from __future__ import absolute_import, unicode_literals, print_function
# Import salt libs
from salt.ext import six
import salt.utils.files
import salt.utils.stringutils
from salt.exceptions import SaltException
@ -85,14 +85,11 @@ class BufferedReader(object):
multiplier = 1
self.__buffered = self.__buffered[self.__chunk_size:]
if six.PY3:
# Data is a byte object in Python 3
# Decode it in order to append to self.__buffered str later
data = self.__file.read(self.__chunk_size * multiplier).decode(
__salt_system_encoding__
)
else:
data = self.__file.read(self.__chunk_size * multiplier)
data = self.__file.read(self.__chunk_size * multiplier)
# Data is a byte object in Python 3
# Decode it in order to append to self.__buffered str later
# Use the salt util in case it's already a string (Windows)
data = salt.utils.stringutils.to_str(data)
if not data:
self.__file.close()

View file

@ -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

View file

@ -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
@ -2993,7 +3006,11 @@ class GitPillar(GitBase):
elif repo.env:
env = repo.env
else:
env = 'base' if repo.branch == repo.base else repo.get_checkout_target()
if repo.branch == repo.base:
env = 'base'
else:
tgt = repo.get_checkout_target()
env = 'base' if tgt == repo.base else tgt
if repo._mountpoint:
if self.link_mountpoint(repo):
self.pillar_dirs[repo.linkdir] = env

View file

@ -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.

View file

@ -1984,7 +1984,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:
@ -2002,7 +2002,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)

View file

@ -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

View file

@ -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 = '\''

View file

@ -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

View file

@ -66,6 +66,7 @@ import re
import tempfile
# Import Salt libs
import salt.modules.cmdmod
import salt.utils.files
import salt.utils.platform
from salt.exceptions import CommandExecutionError
@ -117,8 +118,8 @@ def _auditpol_cmd(cmd):
Raises:
CommandExecutionError: If the command encounters an error
'''
ret = __salt__['cmd.run_all'](cmd='auditpol {0}'.format(cmd),
python_shell=True)
ret = salt.modules.cmdmod.run_all(cmd='auditpol {0}'.format(cmd),
python_shell=True)
if ret['retcode'] == 0:
return ret['stdout'].splitlines()

View file

@ -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

View file

@ -8,10 +8,16 @@ from __future__ import absolute_import, print_function, unicode_literals
import re
import sys
import platform
import warnings
# linux_distribution deprecated in py3.7
try:
from platform import linux_distribution
from platform import linux_distribution as _deprecated_linux_distribution
def linux_distribution(**kwargs):
with warnings.catch_warnings():
warnings.simplefilter("ignore")
return _deprecated_linux_distribution(**kwargs)
except ImportError:
from distro import linux_distribution

View file

@ -874,7 +874,10 @@ class SaltDistribution(distutils.dist.Distribution):
self.name = 'salt-ssh' if PACKAGED_FOR_SALT_SSH else 'salt'
self.salt_version = __version__ # pylint: disable=undefined-variable
self.description = 'Portable, distributed, remote execution and configuration management system'
with open(SALT_LONG_DESCRIPTION_FILE) as f:
kwargs = {}
if IS_PY3:
kwargs['encoding'] = 'utf-8'
with open(SALT_LONG_DESCRIPTION_FILE, **kwargs) as f:
self.long_description = f.read()
self.long_description_content_type = 'text/x-rst'
self.author = 'Thomas S Hatch'

View file

@ -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']

View file

@ -183,7 +183,7 @@ class TestDaemon(object):
'''
Set up the master and minion daemons, and run related cases
'''
MINIONS_CONNECT_TIMEOUT = MINIONS_SYNC_TIMEOUT = 120
MINIONS_CONNECT_TIMEOUT = MINIONS_SYNC_TIMEOUT = 300
def __init__(self, parser):
self.parser = parser
@ -219,6 +219,8 @@ class TestDaemon(object):
if getattr(self.parser.options, 'ssh', False):
self.prep_ssh()
self.wait_for_minions(time.time(), self.MINIONS_CONNECT_TIMEOUT)
if self.parser.options.sysinfo:
try:
print_header(
@ -743,6 +745,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
@ -1179,84 +1187,6 @@ class TestDaemon(object):
k for (k, v) in six.iteritems(running) if v and v[0]['jid'] == jid
]
def wait_for_minion_connections(self, targets, timeout):
salt.utils.process.appendproctitle('WaitForMinionConnections')
sys.stdout.write(
' {LIGHT_BLUE}*{ENDC} Waiting at most {0} for minions({1}) to '
'connect back\n'.format(
(timeout > 60 and
timedelta(seconds=timeout) or
'{0} secs'.format(timeout)),
', '.join(targets),
**self.colors
)
)
sys.stdout.flush()
expected_connections = set(targets)
now = datetime.now()
expire = now + timedelta(seconds=timeout)
while now <= expire:
sys.stdout.write(
'\r{0}\r'.format(
' ' * getattr(self.parser.options, 'output_columns', PNUM)
)
)
sys.stdout.write(
' * {LIGHT_YELLOW}[Quit in {0}]{ENDC} Waiting for {1}'.format(
'{0}'.format(expire - now).rsplit('.', 1)[0],
', '.join(expected_connections),
**self.colors
)
)
sys.stdout.flush()
try:
responses = self.client.cmd(
list(expected_connections), 'test.ping', tgt_type='list',
)
# we'll get this exception if the master process hasn't finished starting yet
except SaltClientError:
time.sleep(0.1)
now = datetime.now()
continue
for target in responses:
if target not in expected_connections:
# Someone(minion) else "listening"?
continue
expected_connections.remove(target)
sys.stdout.write(
'\r{0}\r'.format(
' ' * getattr(self.parser.options, 'output_columns',
PNUM)
)
)
sys.stdout.write(
' {LIGHT_GREEN}*{ENDC} {0} connected.\n'.format(
target, **self.colors
)
)
sys.stdout.flush()
if not expected_connections:
return
time.sleep(1)
now = datetime.now()
else: # pylint: disable=W0120
print(
'\n {LIGHT_RED}*{ENDC} WARNING: Minions failed to connect '
'back. Tests requiring them WILL fail'.format(**self.colors)
)
try:
print_header(
'=', sep='=', inline=True,
width=getattr(self.parser.options, 'output_columns', PNUM)
)
except TypeError:
print_header('=', sep='=', inline=True)
raise SystemExit()
def sync_minion_modules_(self, modules_kind, targets, timeout=None):
if not timeout:
timeout = 120
@ -1333,3 +1263,20 @@ class TestDaemon(object):
def sync_minion_grains(self, targets, timeout=None):
salt.utils.process.appendproctitle('SyncMinionGrains')
self.sync_minion_modules_('grains', targets, timeout=timeout)
def wait_for_minions(self, start, timeout, sleep=5):
'''
Ensure all minions and masters (including sub-masters) are connected.
'''
while True:
try:
ret = self.client.run_job('*', 'test.ping')
except salt.exceptions.SaltClientError:
ret = None
if ret and 'minions' not in ret:
continue
if ret and sorted(ret['minions']) == ['minion', 'sub_minion']:
break
if time.time() - start >= timeout:
raise RuntimeError("Ping Minions Failed")
time.sleep(sleep)

Some files were not shown because too many files have changed in this diff Show more