Merge branch '2017.7' into infra5978

This commit is contained in:
Tom Williams 2017-11-14 16:31:17 -05:00 committed by GitHub
commit ba1d57f5eb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
278 changed files with 11238 additions and 2421 deletions

60
.github/CODEOWNERS vendored Normal file
View File

@ -0,0 +1,60 @@
# SALTSTACK CODE OWNERS
# See https://help.github.com/articles/about-codeowners/
# for more info about CODEOWNERS file
# Lines starting with '#' are comments.
# Each line is a file pattern followed by one or more owners.
# See https://help.github.com/articles/about-codeowners/
# for more info about the CODEOWNERS file
# Team Boto
salt/**/*boto* @saltstack/team-boto
# Team Core
salt/auth/ @saltstack/team-core
salt/cache/ @saltstack/team-core
salt/cli/ @saltstack/team-core
salt/client/* @saltstack/team-core
salt/config/* @saltstack/team-core
salt/daemons/ @saltstack/team-core
salt/pillar/ @saltstack/team-core
salt/loader.py @saltstack/team-core
salt/payload.py @saltstack/team-core
salt/**/master* @saltstack/team-core
salt/**/minion* @saltstack/team-core
# Team Cloud
salt/cloud/ @saltstack/team-cloud
salt/utils/openstack/ @saltstack/team-cloud
salt/utils/aws.py @saltstack/team-cloud
salt/**/*cloud* @saltstack/team-cloud
# Team NetAPI
salt/cli/api.py @saltstack/team-netapi
salt/client/netapi.py @saltstack/team-netapi
salt/netapi/ @saltstack/team-netapi
# Team Network
salt/proxy/ @saltstack/team-proxy
# Team SPM
salt/cli/spm.py @saltstack/team-spm
salt/spm/ @saltstack/team-spm
# Team SSH
salt/cli/ssh.py @saltstack/team-ssh
salt/client/ssh/ @saltstack/team-ssh
salt/runners/ssh.py @saltstack/team-ssh
salt/**/thin.py @saltstack/team-ssh
# Team State
salt/state.py @saltstack/team-state
# Team Transport
salt/transport/ @saltstack/team-transport
salt/utils/zeromq.py @saltstack/team-transport
# Team Windows
salt/**/*win* @saltstack/team-windows

View File

@ -12,4 +12,10 @@ Remove this section if not relevant
Yes/No
### Commits signed with GPG?
Yes/No
Please review [Salt's Contributing Guide](https://docs.saltstack.com/en/latest/topics/development/contributing.html) for best practices.
See GitHub's [page on GPG signing](https://help.github.com/articles/signing-commits-using-gpg/) for more information about signing commits with GPG.

8
.gitignore vendored
View File

@ -88,3 +88,11 @@ tests/integration/cloud/providers/logs
# Private keys from the integration tests
tests/integration/cloud/providers/pki/minions
# Ignore tox virtualenvs
/.tox/
# Ignore kitchen stuff
.kitchen
.bundle
Gemfile.lock

192
.kitchen.yml Normal file
View File

@ -0,0 +1,192 @@
---
<% vagrant = system('which vagrant 2>/dev/null >/dev/null') %>
<% version = '2017.7.1' %>
<% platformsfile = ENV['SALT_KITCHEN_PLATFORMS'] || '.kitchen/platforms.yml' %>
<% driverfile = ENV['SALT_KITCHEN_DRIVER'] || '.kitchen/driver.yml' %>
<% if File.exists?(driverfile) %>
<%= ERB.new(File.read(driverfile)).result %>
<% else %>
driver:
name: docker
use_sudo: false
privileged: true
username: root
volume:
- /var/run/docker.sock:/docker.sock
cap_add:
- sys_admin
disable_upstart: false
provision_command:
- echo 'L /run/docker.sock - - - - /docker.sock' > /etc/tmpfiles.d/docker.conf
transport:
name: sftp
<% end %>
sudo: false
provisioner:
name: salt_solo
salt_install: bootstrap
salt_version: latest
salt_bootstrap_url: https://bootstrap.saltstack.com
salt_bootstrap_options: -X stable <%= version %>
log_level: info
require_chef: false
remote_states:
name: git://github.com/saltstack/salt-jenkins.git
branch: 2017.7
repo: git
testingdir: /testing
salt_copy_filter:
- .bundle
- .git
- .gitignore
- .kitchen
- .kitchen.yml
- Gemfile
- Gemfile.lock
- README.rst
- .travis.yml
state_top:
base:
"*":
- git.salt
- kitchen
<% if File.exists?(platformsfile) %>
<%= ERB.new(File.read(platformsfile)).result %>
<% else %>
platforms:
- name: fedora
driver_config:
image: fedora:latest
run_command: /usr/lib/systemd/systemd
provisioner:
salt_bootstrap_options: -X git v<%= version %> >/dev/null
- name: centos-7
driver_config:
run_command: /usr/lib/systemd/systemd
- name: centos-6
driver_config:
run_command: /sbin/init
provision_command:
- yum install -y upstart
provisioner:
salt_bootstrap_options: -P -y -x python2.7 -X git v<%= version %> >/dev/null
- name: ubuntu-rolling
driver_config:
image: ubuntu:rolling
run_command: /lib/systemd/systemd
provisioner:
salt_bootstrap_url: https://raw.githubusercontent.com/saltstack/salt-bootstrap/develop/bootstrap-salt.sh
- name: ubuntu-16.04
driver_config:
run_command: /lib/systemd/systemd
- name: ubuntu-14.04
driver_config:
run_command: /sbin/init
provision_command:
- rm -f /sbin/initctl
- dpkg-divert --local --rename --remove /sbin/initctl
- name: debian-8
driver_config:
run_command: /lib/systemd/systemd
provision_command:
- apt-get install -y dbus
- echo 'L /run/docker.sock - - - - /docker.sock' > /etc/tmpfiles.d/docker.conf
- name: debian-9
driver_config:
run_command: /lib/systemd/systemd
- name: arch
driver_config:
image: base/archlinux
run_command: /usr/lib/systemd/systemd
provision_command:
- pacman -Syu --noconfirm systemd
- systemctl enable sshd
- echo 'L /run/docker.sock - - - - /docker.sock' > /etc/tmpfiles.d/docker.conf
provisioner:
salt_bootstrap_options: -X git v<%= version %> >/dev/null
- name: opensuse
driver_config:
run_command: /usr/lib/systemd/systemd
provision_command:
- systemctl enable sshd.service
- echo 'L /run/docker.sock - - - - /docker.sock' > /etc/tmpfiles.d/docker.conf
provisioner:
salt_bootstrap_options: -X git v<%= version %> >/dev/null
<% if vagrant != false %>
- name: windows-2012r2
driver:
box: mwrock/Windows2012R2
communicator: winrm
name: vagrant
gui: true
username: administrator
password: Pass@word1
provisioner:
init_environment: |
Clear-Host
$AddedLocation ="c:\salt"
$Reg = "Registry::HKLM\System\CurrentControlSet\Control\Session Manager\Environment"
$OldPath = (Get-ItemProperty -Path "$Reg" -Name PATH).Path
$NewPath= $OldPath + ; + $AddedLocation
Set-ItemProperty -Path "$Reg" -Name PATH Value $NewPath
salt_bootstrap_url: https://raw.githubusercontent.com/saltstack/salt-bootstrap/develop/bootstrap-salt.ps1
salt_bootstrap_options: ''
- name: windows-2016
driver:
box: mwrock/Windows2016
communicator: winrm
name: vagrant
username: Vagrant
password: vagrant
gui: true
provisioner:
init_environment: |
Clear-Host
$AddedLocation ="c:\salt;c:\salt\bin\Scripts"
$Reg = "Registry::HKLM\System\CurrentControlSet\Control\Session Manager\Environment"
$OldPath = (Get-ItemProperty -Path "$Reg" -Name PATH).Path
$NewPath= $OldPath + ; + $AddedLocation
Set-ItemProperty -Path "$Reg" -Name PATH Value $NewPath
salt_bootstrap_url: https://raw.githubusercontent.com/saltstack/salt-bootstrap/develop/bootstrap-salt.ps1
salt_bootstrap_options: ''
<% end %>
<% end %>
suites:
- name: py2
provisioner:
pillars:
top.sls:
base:
"*":
- jenkins
jenkins.sls:
testing_dir: /tmp/kitchen/testing
clone_repo: false
salttesting_namespec: salttesting==2017.6.1
- name: py3
excludes:
- centos-6
- ubuntu-14.04
provisioner:
pillars:
top.sls:
base:
"*":
- jenkins
jenkins.sls:
testing_dir: /tmp/kitchen/testing
clone_repo: false
py3: true
salttesting_namespec: salttesting==2017.6.1
verifier:
name: shell
remote_exec: true
sudo: false
live_stream: {}
<% if ENV['TESTOPTS'].nil? %>
command: '$(kitchen) /tmp/kitchen/testing/tests/runtests.py --run-destructive --sysinfo --transport=zeromq --output-columns=80 --ssh --coverage-xml=/tmp/coverage.xml --xml=/tmp/xml-unittests-output'
<% else %>
command: '$(kitchen) /tmp/kitchen/testing/tests/runtests.py --run-destructive --output-columns 80 <%= ENV["TESTOPTS"] %>'
<% end %>

View File

@ -1,5 +1,17 @@
{
"alwaysNotifyForPaths": [
{
"name": "ryan-lane",
"files": ["salt/**/*boto*.py"],
"skipTeamPrs": false
},
{
"name": "tkwilliams",
"files": ["salt/**/*boto*.py"],
"skipTeamPrs": false
}
],
"skipTitle": "Merge forward",
"userBlacklist": ["cvrebert", "markusgattol", "olliewalsh"]
"userBlacklist": ["cvrebert", "markusgattol", "olliewalsh", "basepi"]
}

View File

@ -258,8 +258,8 @@ ignore-imports=no
[BASIC]
# Required attributes for module, separated by a comma
required-attributes=
# Required attributes for module, separated by a comma (will be removed in Pylint 2.0)
#required-attributes=
# List of builtins function names that should not be used, separated by a comma
bad-functions=map,filter,apply,input
@ -365,7 +365,8 @@ spelling-store-unknown-words=no
[CLASSES]
# List of interface methods to ignore, separated by a comma. This is used for
# instance to not check methods defines in Zope's Interface base class.
ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by
# Will be removed in Pylint 2.0
#ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by
# List of method names used to declare (i.e. assign) instance attributes.
defining-attr-methods=__init__,__new__,setUp

24
Gemfile Normal file
View File

@ -0,0 +1,24 @@
# This file is only used for running the test suite with kitchen-salt.
source 'https://rubygems.org'
gem 'test-kitchen'
gem 'kitchen-salt', :git => 'https://github.com/saltstack/kitchen-salt.git'
gem 'kitchen-sync'
gem 'git'
group :docker do
gem 'kitchen-docker', :git => 'https://github.com/test-kitchen/kitchen-docker.git'
end
group :opennebula do
gem 'kitchen-opennebula', :git => 'https://github.com/gtmanfred/kitchen-opennebula.git'
gem 'xmlrpc'
end
group :windows do
gem 'vagrant-wrapper'
gem 'kitchen-vagrant'
gem 'winrm', '~>2.0'
gem 'winrm-fs', '~>1.0'
end

View File

@ -373,7 +373,7 @@
# interface: eth0
# cidr: '10.0.0.0/8'
# The number of seconds a mine update runs.
# The number of minutes between mine updates.
#mine_interval: 60
# Windows platforms lack posix IPC and must rely on slower TCP based inter-

Binary file not shown.

Before

Width:  |  Height:  |  Size: 790 KiB

After

Width:  |  Height:  |  Size: 438 KiB

View File

@ -245,8 +245,8 @@ on_saltstack = 'SALT_ON_SALTSTACK' in os.environ
project = 'Salt'
version = salt.version.__version__
latest_release = '2017.7.1' # latest release
previous_release = '2016.11.7' # latest release from previous branch
latest_release = '2017.7.2' # latest release
previous_release = '2016.11.8' # latest release from previous branch
previous_release_dir = '2016.11' # path on web server for previous branch
next_release = '' # next release
next_release_dir = '' # path on web server for next release branch

View File

@ -10795,6 +10795,7 @@ cmd_whitelist_glob:
.UNINDENT
.UNINDENT
.SS Thread Settings
.SS \fBmultiprocessing\fP
.sp
Default: \fBTrue\fP
.sp

View File

@ -19,14 +19,18 @@ Salt SSH allows for salt routines to be executed using only SSH for transport
Options
=======
.. program:: salt-ssh
.. include:: _includes/common-options.rst
.. option:: --hard-crash
Raise any original exception rather than exiting gracefully. Default: False.
.. option:: -r, --raw, --raw-shell
Execute a raw shell command.
.. option:: --priv
Specify the SSH private key file to be used for authentication.
.. option:: --roster
Define which roster system to use, this defines if a database backend,
@ -53,38 +57,117 @@ Options
the more running process the faster communication should be, default
is 25.
.. option:: --extra-filerefs=EXTRA_FILEREFS
Pass in extra files to include in the state tarball.
.. option:: --min-extra-modules=MIN_EXTRA_MODS
One or comma-separated list of extra Python modulesto be included
into Minimal Salt.
.. option:: --thin-extra-modules=THIN_EXTRA_MODS
One or comma-separated list of extra Python modulesto be included
into Thin Salt.
.. option:: -v, --verbose
Turn on command verbosity, display jid.
.. option:: -s, --static
Return the data from minions as a group after they all return.
.. option:: -w, --wipe
Remove the deployment of the salt files when done executing.
.. option:: -W, --rand-thin-dir
Select a random temp dir to deploy on the remote system. The dir
will be cleaned after the execution.
.. option:: -t, --regen-thin, --thin
Trigger a thin tarball regeneration. This is needed if custom
grains/modules/states have been added or updated.
.. option:: --python2-bin=PYTHON2_BIN
Path to a python2 binary which has salt installed.
.. option:: --python3-bin=PYTHON3_BIN
Path to a python3 binary which has salt installed.
.. option:: --jid=JID
Pass a JID to be used instead of generating one.
Authentication Options
----------------------
.. option:: --priv=SSH_PRIV
Specify the SSH private key file to be used for authentication.
.. option:: -i, --ignore-host-keys
Disables StrictHostKeyChecking to relax acceptance of new and unknown
host keys.
By default ssh host keys are honored and connections will ask for
approval. Use this option to disable StrictHostKeyChecking.
.. option:: --no-host-keys
Fully ignores ssh host keys which by default are honored and connections
would ask for approval. Useful if the host key of a remote server has
would ask for approval. Useful if the host key of a remote server has
changed and would still error with --ignore-host-keys.
.. option:: --user=SSH_USER
Set the default user to attempt to use when authenticating.
.. option:: --passwd
Set the default password to attempt to use when authenticating.
.. option:: --askpass
Interactively ask for the SSH password with no echo - avoids password
in process args and stored in history.
.. option:: --key-deploy
Set this flag to attempt to deploy the authorized ssh key with all
minions. This combined with --passwd can make initial deployment of keys
very fast and easy.
.. program:: salt
.. option:: --identities-only
.. include:: _includes/common-options.rst
Use the only authentication identity files configured in the ssh_config
files. See IdentitiesOnly flag in man ssh_config.
.. include:: _includes/target-selection-ssh.rst
.. option:: --sudo
Run command via sudo.
Scan Roster Options
-------------------
.. option:: --scan-ports=SSH_SCAN_PORTS
Comma-separated list of ports to scan in the scan roster.
.. option:: --scan-timeout=SSH_SCAN_TIMEOUT
Scanning socket timeout for the scan roster.
.. include:: _includes/logging-options.rst
.. |logfile| replace:: /var/log/salt/ssh
.. |loglevel| replace:: ``warning``
.. include:: _includes/target-selection-ssh.rst
.. include:: _includes/output-options.rst

View File

@ -674,7 +674,7 @@ Note these can be defined in the pillar for a minion as well.
Default: ``60``
The number of seconds a mine update runs.
The number of minutes between mine updates.
.. code-block:: yaml
@ -1164,7 +1164,7 @@ be able to execute a certain module. The ``sys`` module is built into the minion
and cannot be disabled.
This setting can also tune the minion. Because all modules are loaded into system
memory, disabling modules will lover the minion's memory footprint.
memory, disabling modules will lower the minion's memory footprint.
Modules should be specified according to their file name on the system and not by
their virtual name. For example, to disable ``cmd``, use the string ``cmdmod`` which
@ -2337,11 +2337,14 @@ Thread Settings
.. conf_minion:: multiprocessing
``multiprocessing``
-------
Default: ``True``
If `multiprocessing` is enabled when a minion receives a
If ``multiprocessing`` is enabled when a minion receives a
publication a new process is spawned and the command is executed therein.
Conversely, if `multiprocessing` is disabled the new publication will be run
Conversely, if ``multiprocessing`` is disabled the new publication will be run
executed in a thread.

View File

@ -118,3 +118,53 @@ has to be closed after every command.
.. code-block:: yaml
proxy_always_alive: False
``proxy_merge_pillar_in_opts``
------------------------------
.. versionadded:: 2017.7.3
Default: ``False``.
Wheter the pillar data to be merged into the proxy configuration options.
As multiple proxies can run on the same server, we may need different
configuration options for each, while there's one single configuration file.
The solution is merging the pillar data of each proxy minion into the opts.
.. code-block:: yaml
proxy_merge_pillar_in_opts: True
``proxy_deep_merge_pillar_in_opts``
-----------------------------------
.. versionadded:: 2017.7.3
Default: ``False``.
Deep merge of pillar data into configuration opts.
This option is evaluated only when :conf_proxy:`proxy_merge_pillar_in_opts` is
enabled.
``proxy_merge_pillar_in_opts_strategy``
---------------------------------------
.. versionadded:: 2017.7.3
Default: ``smart``.
The strategy used when merging pillar configuration into opts.
This option is evaluated only when :conf_proxy:`proxy_merge_pillar_in_opts` is
enabled.
``proxy_mines_pillar``
----------------------
.. versionadded:: 2017.7.3
Default: ``True``.
Allow enabling mine details using pillar data. This evaluates the mine
configuration under the pillar, for the following regular minion options that
are also equally available on the proxy minion: :conf_minion:`mine_interval`,
and :conf_minion:`mine_functions`.

View File

@ -25,6 +25,9 @@ configuration:
- web*:
- test.*
- pkg.*
# Allow managers to use saltutil module functions
manager_.*:
- saltutil.*
Permission Issues
-----------------

View File

@ -1,5 +1,5 @@
salt.runners.auth module
========================
salt.runners.auth
=================
.. automodule:: salt.runners.auth
:members:

View File

@ -1,5 +1,5 @@
salt.runners.digicertapi module
===============================
salt.runners.digicertapi
========================
.. automodule:: salt.runners.digicertapi
:members:

View File

@ -1,5 +1,5 @@
salt.runners.event module
=========================
salt.runners.event
==================
.. automodule:: salt.runners.event
:members:

View File

@ -1,5 +1,11 @@
salt.runners.mattermost module
==============================
salt.runners.mattermost
=======================
**Note for 2017.7 releases!**
Due to the `salt.runners.config <https://github.com/saltstack/salt/blob/develop/salt/runners/config.py>`_ module not being available in this release series, importing the `salt.runners.config <https://github.com/saltstack/salt/blob/develop/salt/runners/config.py>`_ module from the develop branch is required to make this module work.
Ref: `Mattermost runner failing to retrieve config values due to unavailable config runner #43479 <https://github.com/saltstack/salt/issues/43479>`_
.. automodule:: salt.runners.mattermost
:members:

View File

@ -1,5 +1,5 @@
salt.runners.smartos_vmadm module
=================================
salt.runners.smartos_vmadm
==========================
.. automodule:: salt.runners.smartos_vmadm
:members:

View File

@ -1,5 +1,5 @@
salt.runners.vault module
=========================
salt.runners.vault
==================
.. automodule:: salt.runners.vault
:members:

View File

@ -1,5 +1,5 @@
salt.runners.venafiapi module
=============================
salt.runners.venafiapi
======================
.. automodule:: salt.runners.venafiapi
:members:

View File

@ -1,5 +1,5 @@
salt.runners.vistara module
===========================
salt.runners.vistara
====================
.. automodule:: salt.runners.vistara
:members:

View File

@ -6,7 +6,7 @@ Introduced in Salt version ``2017.7.0`` it is now possible to run select states
in parallel. This is accomplished very easily by adding the ``parallel: True``
option to your state declaration:
.. code_block:: yaml
.. code-block:: yaml
nginx:
service.running:
@ -24,7 +24,7 @@ state to finish.
Given this example:
.. code_block:: yaml
.. code-block:: yaml
sleep 10:
cmd.run:
@ -74,16 +74,16 @@ also complete.
Things to be Careful of
=======================
Parallel States does not prevent you from creating parallel conflicts on your
Parallel States do not prevent you from creating parallel conflicts on your
system. This means that if you start multiple package installs using Salt then
the package manager will block or fail. If you attempt to manage the same file
with multiple states in parallel then the result can produce an unexpected
file.
Make sure that the states you choose to run in parallel do not conflict, or
else, like in and parallel programming environment, the outcome may not be
else, like in any parallel programming environment, the outcome may not be
what you expect. Doing things like just making all states run in parallel
will almost certinly result in unexpected behavior.
will almost certainly result in unexpected behavior.
With that said, running states in parallel should be safe the vast majority
of the time and the most likely culprit for unexpected behavior is running

View File

@ -40,7 +40,7 @@ Set up an initial profile at /etc/salt/cloud.profiles or in the /etc/salt/cloud.
.. code-block:: yaml
scalewa-ubuntu:
scaleway-ubuntu:
provider: my-scaleway-config
image: Ubuntu Trusty (14.04 LTS)

View File

@ -31,7 +31,7 @@ documentation for more information.
.. _github-pull-request:
Sending a GitHub pull request
=============================
-----------------------------
Sending pull requests on GitHub is the preferred method for receiving
contributions. The workflow advice below mirrors `GitHub's own guide <GitHub
@ -66,7 +66,7 @@ Fork a Repo Guide_>`_ and is well worth reading.
.. code-block:: bash
git fetch upstream
git checkout -b fix-broken-thing upstream/2016.3
git checkout -b fix-broken-thing upstream/2016.11
If you're working on a feature, create your branch from the develop branch.
@ -130,7 +130,7 @@ Fork a Repo Guide_>`_ and is well worth reading.
.. code-block:: bash
git fetch upstream
git rebase upstream/2016.3 fix-broken-thing
git rebase upstream/2016.11 fix-broken-thing
git push -u origin fix-broken-thing
or
@ -170,9 +170,9 @@ Fork a Repo Guide_>`_ and is well worth reading.
https://github.com/my-account/salt/pull/new/fix-broken-thing
#. If your branch is a fix for a release branch, choose that as the base
branch (e.g. ``2016.3``),
branch (e.g. ``2016.11``),
https://github.com/my-account/salt/compare/saltstack:2016.3...fix-broken-thing
https://github.com/my-account/salt/compare/saltstack:2016.11...fix-broken-thing
If your branch is a feature, choose ``develop`` as the base branch,
@ -205,72 +205,206 @@ Fork a Repo Guide_>`_ and is well worth reading.
.. _which-salt-branch:
Which Salt branch?
==================
GitHub will open pull requests against Salt's main branch, ``develop``, by
default. Ideally, features should go into ``develop`` and bug fixes and
documentation changes should go into the oldest supported release branch
affected by the bug or documentation update. See
:ref:`Sending a GitHub pull request <github-pull-request>`.
If you have a bug fix or doc change and have already forked your working
branch from ``develop`` and do not know how to rebase your commits against
another branch, then submit it to ``develop`` anyway and we'll be sure to
back-port it to the correct place.
The current release branch
--------------------------
The current release branch is the most recent stable release. Pull requests
containing bug fixes should be made against the release branch.
The branch name will be a date-based name such as ``2016.3``.
Bug fixes are made on this branch so that minor releases can be cut from this
branch without introducing surprises and new features. This approach maximizes
stability.
The Salt development team will "merge-forward" any fixes made on the release
branch to the ``develop`` branch once the pull request has been accepted. This
keeps the fix in isolation on the release branch and also keeps the ``develop``
branch up-to-date.
.. note:: Closing GitHub issues from commits
This "merge-forward" strategy requires that `the magic keywords to close a
GitHub issue <Closing issues via commit message_>`_ appear in the commit
message text directly. Only including the text in a pull request will not
close the issue.
GitHub will close the referenced issue once the *commit* containing the
magic text is merged into the default branch (``develop``). Any magic text
input only into the pull request description will not be seen at the
Git-level when those commits are merged-forward. In other words, only the
commits are merged-forward and not the pull request.
The ``develop`` branch
Salt's Branch Topology
----------------------
There are three different kinds of branches in use: develop, main release
branches, and dot release branches.
- All feature work should go into the ``develop`` branch.
- Bug fixes and documentation changes should go into the oldest supported
**main** release branch affected by the the bug or documentation change.
Main release branches are named after a year and month, such as
``2016.11`` and ``2017.7``.
- Hot fixes, as determined by SaltStack's release team, should be submitted
against **dot** release branches. Dot release branches are named after a
year, month, and version. Examples include ``2016.11.8`` and ``2017.7.2``.
.. note::
GitHub will open pull requests against Salt's main branch, ``develop``,
byndefault. Be sure to check which branch is selected when creating the
pull request.
The Develop Branch
==================
The ``develop`` branch is unstable and bleeding-edge. Pull requests containing
feature additions or non-bug-fix changes should be made against the ``develop``
branch.
The Salt development team will back-port bug fixes made to ``develop`` to the
current release branch if the contributor cannot create the pull request
against that branch.
.. note::
Release Branches
----------------
If you have a bug fix or documentation change and have already forked your
working branch from ``develop`` and do not know how to rebase your commits
against another branch, then submit it to ``develop`` anyway. SaltStack's
development team will be happy to back-port it to the correct branch.
For each release a branch will be created when we are ready to tag. The branch will be the same name as the tag minus the v. For example, the v2017.7.1 release was created from the 2017.7.1 branch. This branching strategy will allow for more stability when there is a need for a re-tag during the testing phase of our releases.
**Please make sure you let the maintainers know that the pull request needs
to be back-ported.**
Once the branch is created, the fixes required for a given release, as determined by the SaltStack release team, will be added to this branch. All commits in this branch will be merged forward into the parent branch as well.
Main Release Branches
=====================
The current release branch is the most recent stable release. Pull requests
containing bug fixes or documentation changes should be made against the main
release branch that is affected.
The branch name will be a date-based name such as ``2016.11``.
Bug fixes are made on this branch so that dot release branches can be cut from
the main release branch without introducing surprises and new features. This
approach maximizes stability.
Dot Release Branches
====================
Prior to tagging an official release, a branch will be created when the SaltStack
release team is ready to tag. The dot release branch is created from a main release
branch. The dot release branch will be the same name as the tag minus the ``v``.
For example, the ``2017.7.1`` dot release branch was created from the ``2017.7``
main release branch. The ``v2017.7.1`` release was tagged at the ``HEAD`` of the
``2017.7.1`` branch.
This branching strategy will allow for more stability when there is a need for
a re-tag during the testing phase of the release process and further increases
stability.
Once the dot release branch is created, the fixes required for a given release,
as determined by the SaltStack release team, will be added to this branch. All
commits in this branch will be merged forward into the main release branch as
well.
Merge Forward Process
=====================
The Salt repository follows a "Merge Forward" policy. The merge-forward
behavior means that changes submitted to older main release branches will
automatically be "merged-forward" into the newer branches.
For example, a pull request is merged into ``2016.11``. Then, the entire
``2016.11`` branch is merged-forward into the ``2017.7`` branch, and the
``2017.7`` branch is merged-forward into the ``develop`` branch.
This process makes is easy for contributors to make only one pull-request
against an older branch, but allows the change to propagate to all **main**
release branches.
The merge-forward work-flow applies to all main release branches and the
operation runs continuously.
Merge-Forwards for Dot Release Branches
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The merge-forward policy applies to dot release branches as well, but has a
slightly different behavior. If a change is submitted to a **dot** release
branch, the dot release branch will be merged into its parent **main**
release branch.
For example, a pull request is merged into the ``2017.7.2`` release branch.
Then, the entire ``2017.7.2`` branch is merged-forward into the ``2017.7``
branch. From there, the merge forward process continues as normal.
The only way in which dot release branches differ from main release branches
in regard to merge-forwards, is that once a dot release branch is created
from the main release branch, the dot release branch does not receive merge
forwards.
.. note::
The merge forward process for dot release branches is one-way:
dot release branch --> main release branch.
Closing GitHub issues from commits
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This "merge-forward" strategy requires that `the magic keywords to close a
GitHub issue <Closing issues via commit message_>`_ appear in the commit
message text directly. Only including the text in a pull request will not
close the issue.
GitHub will close the referenced issue once the *commit* containing the
magic text is merged into the default branch (``develop``). Any magic text
input only into the pull request description will not be seen at the
Git-level when those commits are merged-forward. In other words, only the
commits are merged-forward and not the pull request text.
.. _backporting-pull-requests:
Backporting Pull Requests
=========================
If a bug is fixed on ``develop`` and the bug is also present on a
currently-supported release branch, it will need to be back-ported to an
applicable branch.
.. note:: Most Salt contributors can skip these instructions
These instructions do not need to be read in order to contribute to the
Salt project! The SaltStack team will back-port fixes on behalf of
contributors in order to keep the contribution process easy.
These instructions are intended for frequent Salt contributors, advanced
Git users, SaltStack employees, or independent souls who wish to back-port
changes themselves.
It is often easiest to fix a bug on the oldest supported release branch and
then merge that branch forward into ``develop`` (as described earlier in this
document). When that is not possible the fix must be back-ported, or copied,
into any other affected branches.
These steps assume a pull request ``#1234`` has been merged into ``develop``.
And ``upstream`` is the name of the remote pointing to the main Salt repo.
#. Identify the oldest supported release branch that is affected by the bug.
#. Create a new branch for the back-port by reusing the same branch from the
original pull request.
Name the branch ``bp-<NNNN>`` and use the number of the original pull
request.
.. code-block:: bash
git fetch upstream refs/pull/1234/head:bp-1234
git checkout bp-1234
#. Find the parent commit of the original pull request.
The parent commit of the original pull request must be known in order to
rebase onto a release branch. The easiest way to find this is on GitHub.
Open the original pull request on GitHub and find the first commit in the
list of commits. Select and copy the SHA for that commit. The parent of
that commit can be specified by appending ``~1`` to the end.
#. Rebase the new branch on top of the release branch.
* ``<release-branch>`` is the branch identified in step #1.
* ``<orig-base>`` is the SHA identified in step #3 -- don't forget to add
``~1`` to the end!
.. code-block:: bash
git rebase --onto <release-branch> <orig-base> bp-1234
Note, release branches prior to ``2016.11`` will not be able to make use of
rebase and must use cherry-picking instead.
#. Push the back-port branch to GitHub and open a new pull request.
Opening a pull request for the back-port allows for the test suite and
normal code-review process.
.. code-block:: bash
git push -u origin bp-1234
Keeping Salt Forks in Sync
==========================
--------------------------
Salt is advancing quickly. It is therefore critical to pull upstream changes
Salt advances quickly. It is therefore critical to pull upstream changes
from upstream into your fork on a regular basis. Nothing is worse than putting
hard work into a pull request only to see bunches of merge conflicts because it
has diverged too far from upstream.
@ -332,92 +466,53 @@ the name of the main `saltstack/salt`_ repository.
the current release branch.
Posting patches to the mailing list
===================================
-----------------------------------
Patches will also be accepted by email. Format patches using `git
format-patch`_ and send them to the `salt-users`_ mailing list. The contributor
will then get credit for the patch, and the Salt community will have an archive
of the patch and a place for discussion.
.. _backporting-pull-requests:
Backporting Pull Requests
=========================
If a bug is fixed on ``develop`` and the bug is also present on a
currently-supported release branch it will need to be back-ported to all
applicable branches.
.. note:: Most Salt contributors can skip these instructions
These instructions do not need to be read in order to contribute to the
Salt project! The SaltStack team will back-port fixes on behalf of
contributors in order to keep the contribution process easy.
These instructions are intended for frequent Salt contributors, advanced
Git users, SaltStack employees, or independent souls who wish to back-port
changes themselves.
It is often easiest to fix a bug on the oldest supported release branch and
then merge that branch forward into ``develop`` (as described earlier in this
document). When that is not possible the fix must be back-ported, or copied,
into any other affected branches.
These steps assume a pull request ``#1234`` has been merged into ``develop``.
And ``upstream`` is the name of the remote pointing to the main Salt repo.
1. Identify the oldest supported release branch that is affected by the bug.
2. Create a new branch for the back-port by reusing the same branch from the
original pull request.
Name the branch ``bp-<NNNN>`` and use the number of the original pull
request.
.. code-block:: bash
git fetch upstream refs/pull/1234/head:bp-1234
git checkout bp-1234
3. Find the parent commit of the original pull request.
The parent commit of the original pull request must be known in order to
rebase onto a release branch. The easiest way to find this is on GitHub.
Open the original pull request on GitHub and find the first commit in the
list of commits. Select and copy the SHA for that commit. The parent of
that commit can be specified by appending ``~1`` to the end.
4. Rebase the new branch on top of the release branch.
* ``<release-branch>`` is the branch identified in step #1.
* ``<orig-base>`` is the SHA identified in step #3 -- don't forget to add
``~1`` to the end!
.. code-block:: bash
git rebase --onto <release-branch> <orig-base> bp-1234
Note, release branches prior to ``2016.3`` will not be able to make use of
rebase and must use cherry-picking instead.
5. Push the back-port branch to GitHub and open a new pull request.
Opening a pull request for the back-port allows for the test suite and
normal code-review process.
.. code-block:: bash
git push -u origin bp-1234
Issue and Pull Request Labeling System
======================================
--------------------------------------
SaltStack uses several labeling schemes to help facilitate code contributions
and bug resolution. See the :ref:`Labels and Milestones
<labels-and-milestones>` documentation for more information.
Mentionbot
----------
SaltStack runs a mention-bot which notifies contributors who might be able
to help review incoming pull-requests based on their past contribution to
files which are being changed.
If you do not wish to receive these notifications, please add your GitHub
handle to the blacklist line in the ``.mention-bot`` file located in the
root of the Salt repository.
.. _probot-gpg-verification:
GPG Verification
----------------
SaltStack has enabled `GPG Probot`_ to enforce GPG signatures for all
commits included in a Pull Request.
In order for the GPG verification status check to pass, *every* contributor in
the pull request must:
- Set up a GPG key on local machine
- Sign all commits in the pull request with key
- Link key with GitHub account
This applies to all commits in the pull request.
GitHub hosts a number of `help articles`_ for creating a GPG key, using the
GPG key with ``git`` locally, and linking the GPG key to your GitHub account.
Once these steps are completed, the commit signing verification will look like
the example in GitHub's `GPG Signature Verification feature announcement`_.
.. _`saltstack/salt`: https://github.com/saltstack/salt
.. _`GitHub Fork a Repo Guide`: https://help.github.com/articles/fork-a-repo
.. _`GitHub issue tracker`: https://github.com/saltstack/salt/issues
@ -426,14 +521,6 @@ and bug resolution. See the :ref:`Labels and Milestones
.. _`Closing issues via commit message`: https://help.github.com/articles/closing-issues-via-commit-messages
.. _`git format-patch`: https://www.kernel.org/pub/software/scm/git/docs/git-format-patch.html
.. _salt-users: https://groups.google.com/forum/#!forum/salt-users
Mentionbot
==========
SaltStack runs a mention-bot which notifies contributors who might be able
to help review incoming pull-requests based on their past contribution to
files which are being changed.
If you do not wish to receive these notifications, please add your GitHub
handle to the blacklist line in the `.mention-bot` file located in the
root of the Salt repository.
.. _GPG Probot: https://probot.github.io/apps/gpg/
.. _help articles: https://help.github.com/articles/signing-commits-with-gpg/
.. _GPG Signature Verification feature announcement: https://github.com/blog/2144-gpg-signature-verification

View File

@ -95,19 +95,19 @@ globally available or passed in through function arguments, file data, etc.
Mocking Loader Modules
----------------------
Salt loader modules use a series of globally available dunder variables,
``__salt__``, ``__opts__``, ``__pillar__``, etc. To facilitate testing these
modules a mixin class was created, ``LoaderModuleMockMixin`` which can be found
in ``tests/support/mixins.py``. The reason for the exitance of this class is
because, historycally, and because it was easier, one would add these dunder
variables directly on the imported module. This however, introduces unexpected
behavior when running the full test suite since those attributes would not be
removed once we were done testing the module and would therefor leak to other
modules being tested with unpredictable results. This is the kind of work that
should be defered to mock, and that's exactly what this mixin class does.
Salt loader modules use a series of globally available dunder variables,
``__salt__``, ``__opts__``, ``__pillar__``, etc. To facilitate testing these
modules a mixin class was created, ``LoaderModuleMockMixin`` which can be found
in ``tests/support/mixins.py``. The reason for the existance of this class is
because historiclly and because it was easier, one would add these dunder
variables directly on the imported module. This however, introduces unexpected
behavior when running the full test suite since those attributes would not be
removed once we were done testing the module and would therefore leak to other
modules being tested with unpredictable results. This is the kind of work that
should be deferred to mock, and that's exactly what this mixin class does.
As an example, if one needs to specify some options which should be available
to the module being tests one should do:
As an example, if one needs to specify some options which should be available
to the module being tested one should do:
.. code-block:: python
@ -122,8 +122,8 @@ to the module being tests one should do:
}
}
Consider this more extensive example from
``tests/unit/modules/test_libcloud_dns.py``::
Consider this more extensive example from
``tests/unit/modules/test_libcloud_dns.py``:
.. code-block:: python
@ -173,10 +173,10 @@ Consider this more extensive example from
return {libcloud_dns: module_globals}
What happens on the above example is that, we mock a call to
`__salt__['config.option']` to return the configuration needed for the
execution of the tests. Additionally, if the ``libcloud`` library is not
available, since that's not actually part of whats being tested, we mocked that
What happens in the above example is we mock a call to
`__salt__['config.option']` to return the configuration needed for the
execution of the tests. Additionally, if the ``libcloud`` library is not
available, since that's not actually part of what's being tested, we mocked that
import by patching ``sys.modules`` when tests are running.
@ -245,7 +245,7 @@ To understand how one might integrate Mock into writing a unit test for Salt,
let's imagine a scenario in which we're testing an execution module that's
designed to operate on a database. Furthermore, let's imagine two separate
methods, here presented in pseduo-code in an imaginary execution module called
'db.py.
'db.py'.
.. code-block:: python
@ -319,7 +319,7 @@ function into ``__salt__`` that's actually a MagicMock instance.
def show_patch(self):
with patch.dict(my_module.__salt__,
{'function.to_replace': MagicMock()}:
{'function.to_replace': MagicMock()}):
# From this scope, carry on with testing, with a modified __salt__!

View File

@ -218,6 +218,7 @@ Server configuration values and their defaults:
# Bind to LDAP anonymously to determine group membership
# Active Directory does not allow anonymous binds without special configuration
# In addition, if auth.ldap.anonymous is True, empty bind passwords are not permitted.
auth.ldap.anonymous: False
# FOR TESTING ONLY, this is a VERY insecure setting.
@ -257,7 +258,11 @@ and groups, it re-authenticates as the user running the Salt commands.
If you are already aware of the structure of your DNs and permissions in your LDAP store are set such that
users can look up their own group memberships, then the first and second users can be the same. To tell Salt this is
the case, omit the ``auth.ldap.bindpw`` parameter. You can template the ``binddn`` like this:
the case, omit the ``auth.ldap.bindpw`` parameter. Note this is not the same thing as using an anonymous bind.
Most LDAP servers will not permit anonymous bind, and as mentioned above, if `auth.ldap.anonymous` is False you
cannot use an empty password.
You can template the ``binddn`` like this:
.. code-block:: yaml

View File

@ -27,7 +27,12 @@ Salt engines are configured under an ``engines`` top-level section in your Salt
port: 5959
proto: tcp
Salt engines must be in the Salt path, or you can add the ``engines_dirs`` option in your Salt master configuration with a list of directories under which Salt attempts to find Salt engines.
Salt engines must be in the Salt path, or you can add the ``engines_dirs`` option in your Salt master configuration with a list of directories under which Salt attempts to find Salt engines. This option should be formatted as a list of directories to search, such as:
.. code-block:: yaml
engines_dirs:
- /home/bob/engines
Writing an Engine
=================

View File

@ -18,7 +18,7 @@ Installation from official Debian and Raspbian repositories is described
Installation from the Official SaltStack Repository
===================================================
Packages for Debian 8 (Jessie) and Debian 7 (Wheezy) are available in the
Packages for Debian 9 (Stretch) and Debian 8 (Jessie) are available in the
Official SaltStack repository.
Instructions are at https://repo.saltstack.com/#debian.

View File

@ -202,7 +202,7 @@ this.
# /srv/salt/orch/deploy.sls
{% set servers = salt['pillar.get']('servers', 'test') %}
{% set master = salt['pillat.get']('master', 'salt') %}
{% set master = salt['pillar.get']('master', 'salt') %}
create_instance:
salt.runner:
- name: cloud.profile

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,6 @@
============================
Salt 2016.11.9 Release Notes
============================
Version 2016.11.9 is a bugfix release for :ref:`2016.11.0 <release-2016-11-0>`.]

View File

@ -7,23 +7,9 @@ Version 2016.3.8 is a bugfix release for :ref:`2016.3.0 <release-2016-3-0>`.
Changes for v2016.3.7..v2016.3.8
--------------------------------
New master configuration option `allow_minion_key_revoke`, defaults to True. This option
controls whether a minion can request that the master revoke its key. When True, a minion
can request a key revocation and the master will comply. If it is False, the key will not
be revoked by the msater.
Security Fix
============
New master configuration option `require_minion_sign_messages`
This requires that minions cryptographically sign the messages they
publish to the master. If minions are not signing, then log this information
at loglevel 'INFO' and drop the message without acting on it.
CVE-2017-14695 Directory traversal vulnerability in minion id validation in SaltStack. Allows remote minions with incorrect credentials to authenticate to a master via a crafted minion ID. Credit for discovering the security flaw goes to: Julian Brost (julian@0x4a42.net)
New master configuration option `drop_messages_signature_fail`
Drop messages from minions when their signatures do not validate.
Note that when this option is False but `require_minion_sign_messages` is True
minions MUST sign their messages but the validity of their signatures
is ignored.
New minion configuration option `minion_sign_messages`
Causes the minion to cryptographically sign the payload of messages it places
on the event bus for the master. The payloads are signed with the minion's
private key so the master can verify the signature with its public key.
CVE-2017-14696 Remote Denial of Service with a specially crafted authentication request. Credit for discovering the security flaw goes to: Julian Brost (julian@0x4a42.net)

View File

@ -0,0 +1,29 @@
===========================
Salt 2016.3.9 Release Notes
===========================
Version 2016.3.9 is a bugfix release for :ref:`2016.3.0 <release-2016-3-0>`.
Changes for v2016.3.7..v2016.3.9
--------------------------------
New master configuration option `allow_minion_key_revoke`, defaults to True. This option
controls whether a minion can request that the master revoke its key. When True, a minion
can request a key revocation and the master will comply. If it is False, the key will not
be revoked by the msater.
New master configuration option `require_minion_sign_messages`
This requires that minions cryptographically sign the messages they
publish to the master. If minions are not signing, then log this information
at loglevel 'INFO' and drop the message without acting on it.
New master configuration option `drop_messages_signature_fail`
Drop messages from minions when their signatures do not validate.
Note that when this option is False but `require_minion_sign_messages` is True
minions MUST sign their messages but the validity of their signatures
is ignored.
New minion configuration option `minion_sign_messages`
Causes the minion to cryptographically sign the payload of messages it places
on the event bus for the master. The payloads are signed with the minion's
private key so the master can verify the signature with its public key.

View File

@ -21,6 +21,9 @@ Salt will no longer support Python 2.6. We will provide python2.7 packages on ou
.. _repo: https://repo.saltstack.com/
As this will impact the installation of additional dependencies for salt modules please use pip packages if there is not a package available in a repository. You will need to install the python27-pip package to get access to the correct pip27 executable: ``yum install python27-pip``
============
Known Issues
============

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,6 @@
============================
Salt 2017.7.3 Release Notes
============================
Version 2017.7.3 is a bugfix release for :ref:`2017.7.0 <release-2017-7-0>`.

View File

@ -27,7 +27,7 @@ Installing Dependencies
=======================
Both pygit2_ and GitPython_ are supported Python interfaces to git. If
compatible versions of both are installed, pygit2_ will preferred. In these
compatible versions of both are installed, pygit2_ will be preferred. In these
cases, GitPython_ can be forced using the :conf_master:`gitfs_provider`
parameter in the master config file.

View File

@ -33,3 +33,5 @@ Tutorials Index
* :ref:`The macOS (Maverick) Developer Step By Step Guide To Salt Installation <tutorial-macos-walk-through>`
* :ref:`SaltStack Walk-through <tutorial-salt-walk-through>`
* :ref:`Writing Salt Tests <tutorial-salt-testing>`
* :ref:`Running Salt States and Commands in Docker Containers <docker-sls>`
* :ref:`Preseed Minion with Accepted Key <tutorial-preseed-key>`

View File

@ -23,7 +23,7 @@ Supported Operating Systems
.. note::
In the event you do not see your distribution or version available please
review the develop branch on GitHub as it main contain updates that are
review the develop branch on GitHub as it may contain updates that are
not present in the stable release:
https://github.com/saltstack/salt-bootstrap/tree/develop

View File

@ -88,7 +88,8 @@ sudo $PKGRESOURCES/build_env.sh $PYVER
echo -n -e "\033]0;Build: Install Salt\007"
sudo rm -rf $SRCDIR/build
sudo rm -rf $SRCDIR/dist
sudo $PYTHON $SRCDIR/setup.py build -e "$PYTHON -E -s" install
sudo $PYTHON $SRCDIR/setup.py build -e "$PYTHON -E -s"
sudo $PYTHON $SRCDIR/setup.py install
############################################################################
# Build Package

View File

@ -67,7 +67,7 @@ _su_cmd() {
_get_pid() {
netstat $NS_NOTRIM -ap --protocol=unix 2>$ERROR_TO_DEVNULL \
netstat -n $NS_NOTRIM -ap --protocol=unix 2>$ERROR_TO_DEVNULL \
| sed -r -e "\|\s${SOCK_DIR}/minion_event_${MINION_ID_HASH}_pub\.ipc$|"'!d; s|/.*||; s/.*\s//;' \
| uniq
}
@ -155,7 +155,7 @@ start() {
printf "\nPROCESSES:\n" >&2
ps wwwaxu | grep '[s]alt-minion' >&2
printf "\nSOCKETS:\n" >&2
netstat $NS_NOTRIM -ap --protocol=unix | grep 'salt.*minion' >&2
netstat -n $NS_NOTRIM -ap --protocol=unix | grep 'salt.*minion' >&2
printf "\nLOG_FILE:\n" >&2
tail -n 20 "$LOG_FILE" >&2
printf "\nENVIRONMENT:\n" >&2

View File

@ -35,7 +35,8 @@ _salt_get_keys(){
}
_salt(){
local _salt_cache_functions=${SALT_COMP_CACHE_FUNCTIONS:='~/.cache/salt-comp-cache_functions'}
CACHE_DIR="$HOME/.cache/salt-comp-cache_functions"
local _salt_cache_functions=${SALT_COMP_CACHE_FUNCTIONS:=$CACHE_DIR}
local _salt_cache_timeout=${SALT_COMP_CACHE_TIMEOUT:='last hour'}
if [ ! -d "$(dirname ${_salt_cache_functions})" ]; then

View File

@ -89,7 +89,7 @@ if Defined x (
if %Python%==2 (
Set "PyDir=C:\Python27"
) else (
Set "PyDir=C:\Program Files\Python35"
Set "PyDir=C:\Python35"
)
Set "PATH=%PATH%;%PyDir%;%PyDir%\Scripts"

View File

@ -175,7 +175,7 @@ If (Test-Path "$($ini['Settings']['Python2Dir'])\python.exe") {
DownloadFileWithProgress $url $file
Write-Output " - $script_name :: Installing $($ini[$bitPrograms]['Python2']) . . ."
$p = Start-Process msiexec -ArgumentList "/i $file /qb ADDLOCAL=DefaultFeature,SharedCRT,Extensions,pip_feature,PrependPath TARGETDIR=$($ini['Settings']['Python2Dir'])" -Wait -NoNewWindow -PassThru
$p = Start-Process msiexec -ArgumentList "/i $file /qb ADDLOCAL=DefaultFeature,SharedCRT,Extensions,pip_feature,PrependPath TARGETDIR=`"$($ini['Settings']['Python2Dir'])`"" -Wait -NoNewWindow -PassThru
}
#------------------------------------------------------------------------------
@ -191,7 +191,7 @@ If (!($Path.ToLower().Contains("$($ini['Settings']['Scripts2Dir'])".ToLower())))
#==============================================================================
# Update PIP and SetupTools
# caching depends on environmant variable SALT_PIP_LOCAL_CACHE
# caching depends on environment variable SALT_PIP_LOCAL_CACHE
#==============================================================================
Write-Output " ----------------------------------------------------------------"
Write-Output " - $script_name :: Updating PIP and SetupTools . . ."
@ -212,7 +212,7 @@ if ( ! [bool]$Env:SALT_PIP_LOCAL_CACHE) {
#==============================================================================
# Install pypi resources using pip
# caching depends on environmant variable SALT_REQ_LOCAL_CACHE
# caching depends on environment variable SALT_REQ_LOCAL_CACHE
#==============================================================================
Write-Output " ----------------------------------------------------------------"
Write-Output " - $script_name :: Installing pypi resources using pip . . ."
@ -230,6 +230,24 @@ if ( ! [bool]$Env:SALT_REQ_LOCAL_CACHE) {
Start_Process_and_test_exitcode "$($ini['Settings']['Python2Dir'])\python.exe" "-m pip install --no-index --find-links=$Env:SALT_REQ_LOCAL_CACHE -r $($script_path)\req_2.txt" "pip install"
}
#==============================================================================
# Move PyWin32 DLL's to site-packages\win32
#==============================================================================
Write-Output " - $script_name :: Moving PyWin32 DLLs . . ."
Move-Item "$($ini['Settings']['SitePkgs2Dir'])\pywin32_system32\*.dll" "$($ini['Settings']['SitePkgs2Dir'])\win32" -Force
# Remove pywin32_system32 directory
Write-Output " - $script_name :: Removing pywin32_system32 Directory . . ."
Remove-Item "$($ini['Settings']['SitePkgs2Dir'])\pywin32_system32"
# Remove pythonwin directory
Write-Output " - $script_name :: Removing pythonwin Directory . . ."
Remove-Item "$($ini['Settings']['SitePkgs2Dir'])\pythonwin" -Force -Recurse
# Remove PyWin32 PostInstall and testall Scripts
Write-Output " - $script_name :: Removing PyWin32 scripts . . ."
Remove-Item "$($ini['Settings']['Scripts2Dir'])\pywin32_*" -Force -Recurse
#==============================================================================
# Install PyYAML with CLoader
# This has to be a compiled binary to get the CLoader

View File

@ -175,7 +175,7 @@ If (Test-Path "$($ini['Settings']['Python3Dir'])\python.exe") {
DownloadFileWithProgress $url $file
Write-Output " - $script_name :: Installing $($ini[$bitPrograms]['Python3']) . . ."
$p = Start-Process $file -ArgumentList '/passive InstallAllUsers=1 TargetDir="C:\Program Files\Python35" Include_doc=0 Include_tcltk=0 Include_test=0 Include_launcher=0 PrependPath=1 Shortcuts=0' -Wait -NoNewWindow -PassThru
$p = Start-Process $file -ArgumentList "/passive InstallAllUsers=1 TargetDir=`"$($ini['Settings']['Python3Dir'])`" Include_doc=0 Include_tcltk=0 Include_test=0 Include_launcher=0 PrependPath=1 Shortcuts=0" -Wait -NoNewWindow -PassThru
}
#------------------------------------------------------------------------------
@ -247,7 +247,7 @@ Start_Process_and_test_exitcode "$($ini['Settings']['Scripts3Dir'])\pip.exe" "i
# Move DLL's to Python Root
Write-Output " - $script_name :: Moving PyWin32 DLLs . . ."
Move-Item "$($ini['Settings']['SitePkgs3Dir'])\pywin32_system32\*.dll" "$($ini['Settings']['Python3Dir'])" -Force
Move-Item "$($ini['Settings']['SitePkgs3Dir'])\pywin32_system32\*.dll" "$($ini['Settings']['SitePkgs3Dir'])\win32" -Force
# Remove pywin32_system32 directory
Write-Output " - $script_name :: Removing pywin32_system32 Directory . . ."
@ -257,6 +257,10 @@ Remove-Item "$($ini['Settings']['SitePkgs3Dir'])\pywin32_system32"
Write-Output " - $script_name :: Removing pythonwin Directory . . ."
Remove-Item "$($ini['Settings']['SitePkgs3Dir'])\pythonwin" -Force -Recurse
# Remove PyWin32 PostInstall and testall Scripts
Write-Output " - $script_name :: Removing PyWin32 scripts . . ."
Remove-Item "$($ini['Settings']['Scripts3Dir'])\pywin32_*" -Force -Recurse
#==============================================================================
# Fix PyCrypto
#==============================================================================

View File

@ -56,7 +56,7 @@ if %Python%==2 (
Set "PyVerMajor=2"
Set "PyVerMinor=7"
) else (
Set "PyDir=C:\Program Files\Python35"
Set "PyDir=C:\Python35"
Set "PyVerMajor=3"
Set "PyVerMinor=5"
)

View File

@ -16,9 +16,10 @@ if %errorLevel%==0 (
)
echo.
:CheckPython2
if exist "\Python27" goto RemovePython2
if exist "\Program Files\Python35" goto RemovePython3
goto eof
goto CheckPython3
:RemovePython2
rem Uninstall Python 2.7
@ -47,25 +48,30 @@ goto eof
goto eof
:CheckPython3
if exist "\Python35" goto RemovePython3
goto eof
:RemovePython3
echo %0 :: Uninstalling Python 3 ...
echo ---------------------------------------------------------------------
:: 64 bit
if exist "%LOCALAPPDATA%\Package Cache\{b94f45d6-8461-440c-aa4d-bf197b2c2499}" (
echo %0 :: - 3.5.3 64bit
"%LOCALAPPDATA%\Package Cache\{b94f45d6-8461-440c-aa4d-bf197b2c2499}\python-3.5.3-amd64.exe" /uninstall
"%LOCALAPPDATA%\Package Cache\{b94f45d6-8461-440c-aa4d-bf197b2c2499}\python-3.5.3-amd64.exe" /uninstall /passive
)
:: 32 bit
if exist "%LOCALAPPDATA%\Package Cache\{a10037e1-4247-47c9-935b-c5ca049d0299}" (
echo %0 :: - 3.5.3 32bit
"%LOCALAPPDATA%\Package Cache\{a10037e1-4247-47c9-935b-c5ca049d0299}\python-3.5.3" /uninstall
"%LOCALAPPDATA%\Package Cache\{a10037e1-4247-47c9-935b-c5ca049d0299}\python-3.5.3" /uninstall /passive
)
rem wipe the Python directory
echo %0 :: Removing the C:\Program Files\Python35 Directory ...
echo %0 :: Removing the C:\Python35 Directory ...
echo ---------------------------------------------------------------------
rd /s /q "C:\Program Files\Python35"
rd /s /q "C:\Python35"
if %errorLevel%==0 (
echo Successful
) else (

View File

@ -44,7 +44,7 @@ ${StrStrAdv}
!define CPUARCH "x86"
!endif
; Part of the Trim function for Strings
# Part of the Trim function for Strings
!define Trim "!insertmacro Trim"
!macro Trim ResultVar String
Push "${String}"
@ -61,27 +61,27 @@ ${StrStrAdv}
!define MUI_UNICON "salt.ico"
!define MUI_WELCOMEFINISHPAGE_BITMAP "panel.bmp"
; Welcome page
# Welcome page
!insertmacro MUI_PAGE_WELCOME
; License page
# License page
!insertmacro MUI_PAGE_LICENSE "LICENSE.txt"
; Configure Minion page
# Configure Minion page
Page custom pageMinionConfig pageMinionConfig_Leave
; Instfiles page
# Instfiles page
!insertmacro MUI_PAGE_INSTFILES
; Finish page (Customized)
# Finish page (Customized)
!define MUI_PAGE_CUSTOMFUNCTION_SHOW pageFinish_Show
!define MUI_PAGE_CUSTOMFUNCTION_LEAVE pageFinish_Leave
!insertmacro MUI_PAGE_FINISH
; Uninstaller pages
# Uninstaller pages
!insertmacro MUI_UNPAGE_INSTFILES
; Language files
# Language files
!insertmacro MUI_LANGUAGE "English"
@ -201,8 +201,8 @@ ShowInstDetails show
ShowUnInstDetails show
; Check and install Visual C++ redist packages
; See http://blogs.msdn.com/b/astebner/archive/2009/01/29/9384143.aspx for more info
# Check and install Visual C++ redist packages
# See http://blogs.msdn.com/b/astebner/archive/2009/01/29/9384143.aspx for more info
Section -Prerequisites
Var /GLOBAL VcRedistName
@ -211,12 +211,12 @@ Section -Prerequisites
Var /Global CheckVcRedist
StrCpy $CheckVcRedist "False"
; Visual C++ 2015 redist packages
# Visual C++ 2015 redist packages
!define PY3_VC_REDIST_NAME "VC_Redist_2015"
!define PY3_VC_REDIST_X64_GUID "{50A2BC33-C9CD-3BF1-A8FF-53C10A0B183C}"
!define PY3_VC_REDIST_X86_GUID "{BBF2AC74-720C-3CB3-8291-5E34039232FA}"
; Visual C++ 2008 SP1 MFC Security Update redist packages
# Visual C++ 2008 SP1 MFC Security Update redist packages
!define PY2_VC_REDIST_NAME "VC_Redist_2008_SP1_MFC"
!define PY2_VC_REDIST_X64_GUID "{5FCE6D76-F5DC-37AB-B2B8-22AB8CEDB1D4}"
!define PY2_VC_REDIST_X86_GUID "{9BE518E6-ECC6-35A9-88E4-87755C07200F}"
@ -239,7 +239,7 @@ Section -Prerequisites
StrCpy $VcRedistGuid ${PY2_VC_REDIST_X86_GUID}
${EndIf}
; VCRedist 2008 only needed on Windows Server 2008R2/Windows 7 and below
# VCRedist 2008 only needed on Windows Server 2008R2/Windows 7 and below
${If} ${AtMostWin2008R2}
StrCpy $CheckVcRedist "True"
${EndIf}
@ -255,20 +255,41 @@ Section -Prerequisites
"$VcRedistName is currently not installed. Would you like to install?" \
/SD IDYES IDNO endVcRedist
ClearErrors
; The Correct version of VCRedist is copied over by "build_pkg.bat"
# The Correct version of VCRedist is copied over by "build_pkg.bat"
SetOutPath "$INSTDIR\"
File "..\prereqs\vcredist.exe"
; /passive used by 2015 installer
; /qb! used by 2008 installer
; It just ignores the unrecognized switches...
ExecWait "$INSTDIR\vcredist.exe /qb! /passive"
IfErrors 0 endVcRedist
# If an output variable is specified ($0 in the case below),
# ExecWait sets the variable with the exit code (and only sets the
# error flag if an error occurs; if an error occurs, the contents
# of the user variable are undefined).
# http://nsis.sourceforge.net/Reference/ExecWait
# /passive used by 2015 installer
# /qb! used by 2008 installer
# It just ignores the unrecognized switches...
ClearErrors
ExecWait '"$INSTDIR\vcredist.exe" /qb! /passive /norestart' $0
IfErrors 0 CheckVcRedistErrorCode
MessageBox MB_OK \
"$VcRedistName failed to install. Try installing the package manually." \
/SD IDOK
Goto endVcRedist
CheckVcRedistErrorCode:
# Check for Reboot Error Code (3010)
${If} $0 == 3010
MessageBox MB_OK \
"$VcRedistName installed but requires a restart to complete." \
/SD IDOK
# Check for any other errors
${ElseIfNot} $0 == 0
MessageBox MB_OK \
"$VcRedistName failed with ErrorCode: $0. Try installing the package manually." \
/SD IDOK
${EndIf}
endVcRedist:
${EndIf}
${EndIf}
@ -294,12 +315,12 @@ Function .onInit
Call parseCommandLineSwitches
; Check for existing installation
# Check for existing installation
ReadRegStr $R0 HKLM \
"Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \
"UninstallString"
StrCmp $R0 "" checkOther
; Found existing installation, prompt to uninstall
# Found existing installation, prompt to uninstall
MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION \
"${PRODUCT_NAME} is already installed.$\n$\n\
Click `OK` to remove the existing installation." \
@ -307,12 +328,12 @@ Function .onInit
Abort
checkOther:
; Check for existing installation of full salt
# Check for existing installation of full salt
ReadRegStr $R0 HKLM \
"Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME_OTHER}" \
"UninstallString"
StrCmp $R0 "" skipUninstall
; Found existing installation, prompt to uninstall
# Found existing installation, prompt to uninstall
MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION \
"${PRODUCT_NAME_OTHER} is already installed.$\n$\n\
Click `OK` to remove the existing installation." \
@ -321,22 +342,22 @@ Function .onInit
uninst:
; Get current Silent status
# Get current Silent status
StrCpy $R0 0
${If} ${Silent}
StrCpy $R0 1
${EndIf}
; Turn on Silent mode
# Turn on Silent mode
SetSilent silent
; Don't remove all directories
# Don't remove all directories
StrCpy $DeleteInstallDir 0
; Uninstall silently
# Uninstall silently
Call uninstallSalt
; Set it back to Normal mode, if that's what it was before
# Set it back to Normal mode, if that's what it was before
${If} $R0 == 0
SetSilent normal
${EndIf}
@ -350,7 +371,7 @@ Section -Post
WriteUninstaller "$INSTDIR\uninst.exe"
; Uninstall Registry Entries
# Uninstall Registry Entries
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" \
"DisplayName" "$(^Name)"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" \
@ -366,19 +387,19 @@ Section -Post
WriteRegStr HKLM "SYSTEM\CurrentControlSet\services\salt-minion" \
"DependOnService" "nsi"
; Set the estimated size
# Set the estimated size
${GetSize} "$INSTDIR\bin" "/S=OK" $0 $1 $2
IntFmt $0 "0x%08X" $0
WriteRegDWORD ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" \
"EstimatedSize" "$0"
; Commandline Registry Entries
# Commandline Registry Entries
WriteRegStr HKLM "${PRODUCT_CALL_REGKEY}" "" "$INSTDIR\salt-call.bat"
WriteRegStr HKLM "${PRODUCT_CALL_REGKEY}" "Path" "$INSTDIR\bin\"
WriteRegStr HKLM "${PRODUCT_MINION_REGKEY}" "" "$INSTDIR\salt-minion.bat"
WriteRegStr HKLM "${PRODUCT_MINION_REGKEY}" "Path" "$INSTDIR\bin\"
; Register the Salt-Minion Service
# Register the Salt-Minion Service
nsExec::Exec "nssm.exe install salt-minion $INSTDIR\bin\python.exe -E -s $INSTDIR\bin\Scripts\salt-minion -c $INSTDIR\conf -l quiet"
nsExec::Exec "nssm.exe set salt-minion Description Salt Minion from saltstack.com"
nsExec::Exec "nssm.exe set salt-minion Start SERVICE_AUTO_START"
@ -398,12 +419,12 @@ SectionEnd
Function .onInstSuccess
; If StartMinionDelayed is 1, then set the service to start delayed
# If StartMinionDelayed is 1, then set the service to start delayed
${If} $StartMinionDelayed == 1
nsExec::Exec "nssm.exe set salt-minion Start SERVICE_DELAYED_AUTO_START"
${EndIf}
; If start-minion is 1, then start the service
# If start-minion is 1, then start the service
${If} $StartMinion == 1
nsExec::Exec 'net start salt-minion'
${EndIf}
@ -413,10 +434,11 @@ FunctionEnd
Function un.onInit
; Load the parameters
# Load the parameters
${GetParameters} $R0
# Uninstaller: Remove Installation Directory
ClearErrors
${GetOptions} $R0 "/delete-install-dir" $R1
IfErrors delete_install_dir_not_found
StrCpy $DeleteInstallDir 1
@ -434,7 +456,7 @@ Section Uninstall
Call un.uninstallSalt
; Remove C:\salt from the Path
# Remove C:\salt from the Path
Push "C:\salt"
Call un.RemoveFromPath
@ -444,27 +466,27 @@ SectionEnd
!macro uninstallSalt un
Function ${un}uninstallSalt
; Make sure we're in the right directory
# Make sure we're in the right directory
${If} $INSTDIR == "c:\salt\bin\Scripts"
StrCpy $INSTDIR "C:\salt"
${EndIf}
; Stop and Remove salt-minion service
# Stop and Remove salt-minion service
nsExec::Exec 'net stop salt-minion'
nsExec::Exec 'sc delete salt-minion'
; Stop and remove the salt-master service
# Stop and remove the salt-master service
nsExec::Exec 'net stop salt-master'
nsExec::Exec 'sc delete salt-master'
; Remove files
# Remove files
Delete "$INSTDIR\uninst.exe"
Delete "$INSTDIR\nssm.exe"
Delete "$INSTDIR\salt*"
Delete "$INSTDIR\vcredist.exe"
RMDir /r "$INSTDIR\bin"
; Remove Registry entries
# Remove Registry entries
DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}"
DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY_OTHER}"
DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_CALL_REGKEY}"
@ -474,17 +496,17 @@ Function ${un}uninstallSalt
DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_MINION_REGKEY}"
DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_RUN_REGKEY}"
; Automatically close when finished
# Automatically close when finished
SetAutoClose true
; Prompt to remove the Installation directory
# Prompt to remove the Installation directory
${IfNot} $DeleteInstallDir == 1
MessageBox MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2 \
"Would you like to completely remove $INSTDIR and all of its contents?" \
/SD IDNO IDNO finished
${EndIf}
; Make sure you're not removing Program Files
# Make sure you're not removing Program Files
${If} $INSTDIR != 'Program Files'
${AndIf} $INSTDIR != 'Program Files (x86)'
RMDir /r "$INSTDIR"
@ -526,7 +548,7 @@ FunctionEnd
Function Trim
Exch $R1 ; Original string
Exch $R1 # Original string
Push $R2
Loop:
@ -558,36 +580,36 @@ Function Trim
FunctionEnd
;------------------------------------------------------------------------------
; StrStr Function
; - find substring in a string
;
; Usage:
; Push "this is some string"
; Push "some"
; Call StrStr
; Pop $0 ; "some string"
;------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# StrStr Function
# - find substring in a string
#
# Usage:
# Push "this is some string"
# Push "some"
# Call StrStr
# Pop $0 ; "some string"
#------------------------------------------------------------------------------
!macro StrStr un
Function ${un}StrStr
Exch $R1 ; $R1=substring, stack=[old$R1,string,...]
Exch ; stack=[string,old$R1,...]
Exch $R2 ; $R2=string, stack=[old$R2,old$R1,...]
Push $R3 ; $R3=strlen(substring)
Push $R4 ; $R4=count
Push $R5 ; $R5=tmp
StrLen $R3 $R1 ; Get the length of the Search String
StrCpy $R4 0 ; Set the counter to 0
Exch $R1 # $R1=substring, stack=[old$R1,string,...]
Exch # stack=[string,old$R1,...]
Exch $R2 # $R2=string, stack=[old$R2,old$R1,...]
Push $R3 # $R3=strlen(substring)
Push $R4 # $R4=count
Push $R5 # $R5=tmp
StrLen $R3 $R1 # Get the length of the Search String
StrCpy $R4 0 # Set the counter to 0
loop:
StrCpy $R5 $R2 $R3 $R4 ; Create a moving window of the string that is
; the size of the length of the search string
StrCmp $R5 $R1 done ; Is the contents of the window the same as
; search string, then done
StrCmp $R5 "" done ; Is the window empty, then done
IntOp $R4 $R4 + 1 ; Shift the windows one character
Goto loop ; Repeat
StrCpy $R5 $R2 $R3 $R4 # Create a moving window of the string that is
# the size of the length of the search string
StrCmp $R5 $R1 done # Is the contents of the window the same as
# search string, then done
StrCmp $R5 "" done # Is the window empty, then done
IntOp $R4 $R4 + 1 # Shift the windows one character
Goto loop # Repeat
done:
StrCpy $R1 $R2 "" $R4
@ -595,7 +617,7 @@ Function ${un}StrStr
Pop $R4
Pop $R3
Pop $R2
Exch $R1 ; $R1=old$R1, stack=[result,...]
Exch $R1 # $R1=old$R1, stack=[result,...]
FunctionEnd
!macroend
@ -603,74 +625,74 @@ FunctionEnd
!insertmacro StrStr "un."
;------------------------------------------------------------------------------
; AddToPath Function
; - Adds item to Path for All Users
; - Overcomes NSIS ReadRegStr limitation of 1024 characters by using Native
; Windows Commands
;
; Usage:
; Push "C:\path\to\add"
; Call AddToPath
;------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# AddToPath Function
# - Adds item to Path for All Users
# - Overcomes NSIS ReadRegStr limitation of 1024 characters by using Native
# Windows Commands
#
# Usage:
# Push "C:\path\to\add"
# Call AddToPath
#------------------------------------------------------------------------------
!define Environ 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"'
Function AddToPath
Exch $0 ; Path to add
Push $1 ; Current Path
Push $2 ; Results of StrStr / Length of Path + Path to Add
Push $3 ; Handle to Reg / Length of Path
Push $4 ; Result of Registry Call
Exch $0 # Path to add
Push $1 # Current Path
Push $2 # Results of StrStr / Length of Path + Path to Add
Push $3 # Handle to Reg / Length of Path
Push $4 # Result of Registry Call
; Open a handle to the key in the registry, handle in $3, Error in $4
# Open a handle to the key in the registry, handle in $3, Error in $4
System::Call "advapi32::RegOpenKey(i 0x80000002, t'SYSTEM\CurrentControlSet\Control\Session Manager\Environment', *i.r3) i.r4"
; Make sure registry handle opened successfully (returned 0)
# Make sure registry handle opened successfully (returned 0)
IntCmp $4 0 0 done done
; Load the contents of path into $1, Error Code into $4, Path length into $2
# Load the contents of path into $1, Error Code into $4, Path length into $2
System::Call "advapi32::RegQueryValueEx(i $3, t'PATH', i 0, i 0, t.r1, *i ${NSIS_MAX_STRLEN} r2) i.r4"
; Close the handle to the registry ($3)
# Close the handle to the registry ($3)
System::Call "advapi32::RegCloseKey(i $3)"
; Check for Error Code 234, Path too long for the variable
IntCmp $4 234 0 +4 +4 ; $4 == ERROR_MORE_DATA
# Check for Error Code 234, Path too long for the variable
IntCmp $4 234 0 +4 +4 # $4 == ERROR_MORE_DATA
DetailPrint "AddToPath Failed: original length $2 > ${NSIS_MAX_STRLEN}"
MessageBox MB_OK \
"You may add C:\salt to the %PATH% for convenience when issuing local salt commands from the command line." \
/SD IDOK
Goto done
; If no error, continue
IntCmp $4 0 +5 ; $4 != NO_ERROR
; Error 2 means the Key was not found
IntCmp $4 2 +3 ; $4 != ERROR_FILE_NOT_FOUND
# If no error, continue
IntCmp $4 0 +5 # $4 != NO_ERROR
# Error 2 means the Key was not found
IntCmp $4 2 +3 # $4 != ERROR_FILE_NOT_FOUND
DetailPrint "AddToPath: unexpected error code $4"
Goto done
StrCpy $1 ""
; Check if already in PATH
Push "$1;" ; The string to search
Push "$0;" ; The string to find
# Check if already in PATH
Push "$1;" # The string to search
Push "$0;" # The string to find
Call StrStr
Pop $2 ; The result of the search
StrCmp $2 "" 0 done ; String not found, try again with ';' at the end
; Otherwise, it's already in the path
Push "$1;" ; The string to search
Push "$0\;" ; The string to find
Pop $2 # The result of the search
StrCmp $2 "" 0 done # String not found, try again with ';' at the end
# Otherwise, it's already in the path
Push "$1;" # The string to search
Push "$0\;" # The string to find
Call StrStr
Pop $2 ; The result
StrCmp $2 "" 0 done ; String not found, continue (add)
; Otherwise, it's already in the path
Pop $2 # The result
StrCmp $2 "" 0 done # String not found, continue (add)
# Otherwise, it's already in the path
; Prevent NSIS string overflow
StrLen $2 $0 ; Length of path to add ($2)
StrLen $3 $1 ; Length of current path ($3)
IntOp $2 $2 + $3 ; Length of current path + path to add ($2)
IntOp $2 $2 + 2 ; Account for the additional ';'
; $2 = strlen(dir) + strlen(PATH) + sizeof(";")
# Prevent NSIS string overflow
StrLen $2 $0 # Length of path to add ($2)
StrLen $3 $1 # Length of current path ($3)
IntOp $2 $2 + $3 # Length of current path + path to add ($2)
IntOp $2 $2 + 2 # Account for the additional ';'
# $2 = strlen(dir) + strlen(PATH) + sizeof(";")
; Make sure the new length isn't over the NSIS_MAX_STRLEN
# Make sure the new length isn't over the NSIS_MAX_STRLEN
IntCmp $2 ${NSIS_MAX_STRLEN} +4 +4 0
DetailPrint "AddToPath: new length $2 > ${NSIS_MAX_STRLEN}"
MessageBox MB_OK \
@ -678,18 +700,18 @@ Function AddToPath
/SD IDOK
Goto done
; Append dir to PATH
# Append dir to PATH
DetailPrint "Add to PATH: $0"
StrCpy $2 $1 1 -1 ; Copy the last character of the existing path
StrCmp $2 ";" 0 +2 ; Check for trailing ';'
StrCpy $1 $1 -1 ; remove trailing ';'
StrCmp $1 "" +2 ; Make sure Path is not empty
StrCpy $0 "$1;$0" ; Append new path at the end ($0)
StrCpy $2 $1 1 -1 # Copy the last character of the existing path
StrCmp $2 ";" 0 +2 # Check for trailing ';'
StrCpy $1 $1 -1 # remove trailing ';'
StrCmp $1 "" +2 # Make sure Path is not empty
StrCpy $0 "$1;$0" # Append new path at the end ($0)
; We can use the NSIS command here. Only 'ReadRegStr' is affected
# We can use the NSIS command here. Only 'ReadRegStr' is affected
WriteRegExpandStr ${Environ} "PATH" $0
; Broadcast registry change to open programs
# Broadcast registry change to open programs
SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
done:
@ -702,16 +724,16 @@ Function AddToPath
FunctionEnd
;------------------------------------------------------------------------------
; RemoveFromPath Function
; - Removes item from Path for All Users
; - Overcomes NSIS ReadRegStr limitation of 1024 characters by using Native
; Windows Commands
;
; Usage:
; Push "C:\path\to\add"
; Call un.RemoveFromPath
;------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# RemoveFromPath Function
# - Removes item from Path for All Users
# - Overcomes NSIS ReadRegStr limitation of 1024 characters by using Native
# Windows Commands
#
# Usage:
# Push "C:\path\to\add"
# Call un.RemoveFromPath
#------------------------------------------------------------------------------
Function un.RemoveFromPath
Exch $0
@ -722,59 +744,59 @@ Function un.RemoveFromPath
Push $5
Push $6
; Open a handle to the key in the registry, handle in $3, Error in $4
# Open a handle to the key in the registry, handle in $3, Error in $4
System::Call "advapi32::RegOpenKey(i 0x80000002, t'SYSTEM\CurrentControlSet\Control\Session Manager\Environment', *i.r3) i.r4"
; Make sure registry handle opened successfully (returned 0)
# Make sure registry handle opened successfully (returned 0)
IntCmp $4 0 0 done done
; Load the contents of path into $1, Error Code into $4, Path length into $2
# Load the contents of path into $1, Error Code into $4, Path length into $2
System::Call "advapi32::RegQueryValueEx(i $3, t'PATH', i 0, i 0, t.r1, *i ${NSIS_MAX_STRLEN} r2) i.r4"
; Close the handle to the registry ($3)
# Close the handle to the registry ($3)
System::Call "advapi32::RegCloseKey(i $3)"
; Check for Error Code 234, Path too long for the variable
IntCmp $4 234 0 +4 +4 ; $4 == ERROR_MORE_DATA
# Check for Error Code 234, Path too long for the variable
IntCmp $4 234 0 +4 +4 # $4 == ERROR_MORE_DATA
DetailPrint "AddToPath: original length $2 > ${NSIS_MAX_STRLEN}"
Goto done
; If no error, continue
IntCmp $4 0 +5 ; $4 != NO_ERROR
; Error 2 means the Key was not found
IntCmp $4 2 +3 ; $4 != ERROR_FILE_NOT_FOUND
# If no error, continue
IntCmp $4 0 +5 # $4 != NO_ERROR
# Error 2 means the Key was not found
IntCmp $4 2 +3 # $4 != ERROR_FILE_NOT_FOUND
DetailPrint "AddToPath: unexpected error code $4"
Goto done
StrCpy $1 ""
; Ensure there's a trailing ';'
StrCpy $5 $1 1 -1 ; Copy the last character of the path
StrCmp $5 ";" +2 ; Check for trailing ';', if found continue
StrCpy $1 "$1;" ; ensure trailing ';'
# Ensure there's a trailing ';'
StrCpy $5 $1 1 -1 # Copy the last character of the path
StrCmp $5 ";" +2 # Check for trailing ';', if found continue
StrCpy $1 "$1;" # ensure trailing ';'
; Check for our directory inside the path
Push $1 ; String to Search
Push "$0;" ; Dir to Find
# Check for our directory inside the path
Push $1 # String to Search
Push "$0;" # Dir to Find
Call un.StrStr
Pop $2 ; The results of the search
StrCmp $2 "" done ; If results are empty, we're done, otherwise continue
Pop $2 # The results of the search
StrCmp $2 "" done # If results are empty, we're done, otherwise continue
; Remove our Directory from the Path
# Remove our Directory from the Path
DetailPrint "Remove from PATH: $0"
StrLen $3 "$0;" ; Get the length of our dir ($3)
StrLen $4 $2 ; Get the length of the return from StrStr ($4)
StrCpy $5 $1 -$4 ; $5 is now the part before the path to remove
StrCpy $6 $2 "" $3 ; $6 is now the part after the path to remove
StrCpy $3 "$5$6" ; Combine $5 and $6
StrLen $3 "$0;" # Get the length of our dir ($3)
StrLen $4 $2 # Get the length of the return from StrStr ($4)
StrCpy $5 $1 -$4 # $5 is now the part before the path to remove
StrCpy $6 $2 "" $3 # $6 is now the part after the path to remove
StrCpy $3 "$5$6" # Combine $5 and $6
; Check for Trailing ';'
StrCpy $5 $3 1 -1 ; Load the last character of the string
StrCmp $5 ";" 0 +2 ; Check for ';'
StrCpy $3 $3 -1 ; remove trailing ';'
# Check for Trailing ';'
StrCpy $5 $3 1 -1 # Load the last character of the string
StrCmp $5 ";" 0 +2 # Check for ';'
StrCpy $3 $3 -1 # remove trailing ';'
; Write the new path to the registry
# Write the new path to the registry
WriteRegExpandStr ${Environ} "PATH" $3
; Broadcast the change to all open applications
# Broadcast the change to all open applications
SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
done:
@ -808,6 +830,7 @@ Function getMinionConfig
confFound:
FileOpen $0 "$INSTDIR\conf\minion" r
ClearErrors
confLoop:
FileRead $0 $1
IfErrors EndOfFile
@ -838,68 +861,69 @@ FunctionEnd
Function updateMinionConfig
ClearErrors
FileOpen $0 "$INSTDIR\conf\minion" "r" ; open target file for reading
GetTempFileName $R0 ; get new temp file name
FileOpen $1 $R0 "w" ; open temp file for writing
FileOpen $0 "$INSTDIR\conf\minion" "r" # open target file for reading
GetTempFileName $R0 # get new temp file name
FileOpen $1 $R0 "w" # open temp file for writing
loop: ; loop through each line
FileRead $0 $2 ; read line from target file
IfErrors done ; end if errors are encountered (end of line)
loop: # loop through each line
FileRead $0 $2 # read line from target file
IfErrors done # end if errors are encountered (end of line)
${If} $MasterHost_State != "" ; if master is empty
${AndIf} $MasterHost_State != "salt" ; and if master is not 'salt'
${StrLoc} $3 $2 "master:" ">" ; where is 'master:' in this line
${If} $3 == 0 ; is it in the first...
${OrIf} $3 == 1 ; or second position (account for comments)
StrCpy $2 "master: $MasterHost_State$\r$\n" ; write the master
${EndIf} ; close if statement
${EndIf} ; close if statement
${If} $MasterHost_State != "" # if master is empty
${AndIf} $MasterHost_State != "salt" # and if master is not 'salt'
${StrLoc} $3 $2 "master:" ">" # where is 'master:' in this line
${If} $3 == 0 # is it in the first...
${OrIf} $3 == 1 # or second position (account for comments)
StrCpy $2 "master: $MasterHost_State$\r$\n" # write the master
${EndIf} # close if statement
${EndIf} # close if statement
${If} $MinionName_State != "" ; if minion is empty
${AndIf} $MinionName_State != "hostname" ; and if minion is not 'hostname'
${StrLoc} $3 $2 "id:" ">" ; where is 'id:' in this line
${If} $3 == 0 ; is it in the first...
${OrIf} $3 == 1 ; or the second position (account for comments)
StrCpy $2 "id: $MinionName_State$\r$\n" ; change line
${EndIf} ; close if statement
${EndIf} ; close if statement
${If} $MinionName_State != "" # if minion is empty
${AndIf} $MinionName_State != "hostname" # and if minion is not 'hostname'
${StrLoc} $3 $2 "id:" ">" # where is 'id:' in this line
${If} $3 == 0 # is it in the first...
${OrIf} $3 == 1 # or the second position (account for comments)
StrCpy $2 "id: $MinionName_State$\r$\n" # change line
${EndIf} # close if statement
${EndIf} # close if statement
FileWrite $1 $2 ; write changed or unchanged line to temp file
FileWrite $1 $2 # write changed or unchanged line to temp file
Goto loop
done:
FileClose $0 ; close target file
FileClose $1 ; close temp file
Delete "$INSTDIR\conf\minion" ; delete target file
CopyFiles /SILENT $R0 "$INSTDIR\conf\minion" ; copy temp file to target file
Delete $R0 ; delete temp file
FileClose $0 # close target file
FileClose $1 # close temp file
Delete "$INSTDIR\conf\minion" # delete target file
CopyFiles /SILENT $R0 "$INSTDIR\conf\minion" # copy temp file to target file
Delete $R0 # delete temp file
FunctionEnd
Function parseCommandLineSwitches
; Load the parameters
# Load the parameters
${GetParameters} $R0
; Check for start-minion switches
; /start-service is to be deprecated, so we must check for both
# Check for start-minion switches
# /start-service is to be deprecated, so we must check for both
${GetOptions} $R0 "/start-service=" $R1
${GetOptions} $R0 "/start-minion=" $R2
# Service: Start Salt Minion
${IfNot} $R2 == ""
; If start-minion was passed something, then set it
# If start-minion was passed something, then set it
StrCpy $StartMinion $R2
${ElseIfNot} $R1 == ""
; If start-service was passed something, then set StartMinion to that
# If start-service was passed something, then set StartMinion to that
StrCpy $StartMinion $R1
${Else}
; Otherwise default to 1
# Otherwise default to 1
StrCpy $StartMinion 1
${EndIf}
# Service: Minion Startup Type Delayed
ClearErrors
${GetOptions} $R0 "/start-minion-delayed" $R1
IfErrors start_minion_delayed_not_found
StrCpy $StartMinionDelayed 1

View File

@ -19,9 +19,9 @@ Function Get-Settings {
"Python2Dir" = "C:\Python27"
"Scripts2Dir" = "C:\Python27\Scripts"
"SitePkgs2Dir" = "C:\Python27\Lib\site-packages"
"Python3Dir" = "C:\Program Files\Python35"
"Scripts3Dir" = "C:\Program Files\Python35\Scripts"
"SitePkgs3Dir" = "C:\Program Files\Python35\Lib\site-packages"
"Python3Dir" = "C:\Python35"
"Scripts3Dir" = "C:\Python35\Scripts"
"SitePkgs3Dir" = "C:\Python35\Lib\site-packages"
"DownloadDir" = "$env:Temp\DevSalt"
}
# The script deletes the DownLoadDir (above) for each install.

View File

@ -377,46 +377,13 @@ class LoadAuth(object):
eauth_config = self.opts['external_auth'][eauth]
if not groups:
groups = []
group_perm_keys = [item for item in eauth_config if item.endswith('%')] # The configured auth groups
# First we need to know if the user is allowed to proceed via any of their group memberships.
group_auth_match = False
for group_config in group_perm_keys:
if group_config.rstrip('%') in groups:
group_auth_match = True
break
# If a group_auth_match is set it means only that we have a
# user which matches at least one or more of the groups defined
# in the configuration file.
external_auth_in_db = False
for entry in eauth_config:
if entry.startswith('^'):
external_auth_in_db = True
break
# If neither a catchall, a named membership or a group
# membership is found, there is no need to continue. Simply
# deny the user access.
if not ((name in eauth_config) |
('*' in eauth_config) |
group_auth_match | external_auth_in_db):
# Auth successful, but no matching user found in config
log.warning('Authorization failure occurred.')
return None
# We now have an authenticated session and it is time to determine
# what the user has access to.
auth_list = []
if name in eauth_config:
auth_list = eauth_config[name]
elif '*' in eauth_config:
auth_list = eauth_config['*']
if group_auth_match:
auth_list = self.ckminions.fill_auth_list_from_groups(
eauth_config,
groups,
auth_list)
auth_list = self.ckminions.fill_auth_list(
eauth_config,
name,
groups)
auth_list = self.__process_acl(load, auth_list)

View File

@ -110,6 +110,10 @@ class _LDAPConnection(object):
self.ldap.set_option(ldap.OPT_REFERRALS, 0) # Needed for AD
if not anonymous:
if self.bindpw is None or len(self.bindpw) < 1:
raise CommandExecutionError(
'LDAP bind password is not set: password cannot be empty if auth.ldap.anonymous is False'
)
self.ldap.simple_bind_s(self.binddn, self.bindpw)
except Exception as ldap_error:
raise CommandExecutionError(

View File

@ -3,6 +3,8 @@
Beacon to monitor temperature, humidity and pressure using the SenseHat
of a Raspberry Pi.
.. versionadded:: 2017.7.0
:maintainer: Benedikt Werner <1benediktwerner@gmail.com>
:maturity: new
:depends: sense_hat Python module

View File

@ -73,7 +73,7 @@ class Cache(object):
self.cachedir = opts.get('cachedir', salt.syspaths.CACHE_DIR)
else:
self.cachedir = cachedir
self.driver = opts.get('cache', salt.config.DEFAULT_MASTER_OPTS)
self.driver = opts.get('cache', salt.config.DEFAULT_MASTER_OPTS['cache'])
self.serial = Serial(opts)
self._modules = None
self._kwargs = kwargs

View File

@ -4,6 +4,8 @@ Minion data cache plugin for Consul key/value data store.
.. versionadded:: 2016.11.2
:depends: python-consul >= 0.2.0
It is up to the system administrator to set up and configure the Consul
infrastructure. All is needed for this plugin is a working Consul agent
with a read-write access to the key-value store.
@ -81,8 +83,11 @@ def __virtual__():
'verify': __opts__.get('consul.verify', True),
}
global api
api = consul.Consul(**consul_kwargs)
try:
global api
api = consul.Consul(**consul_kwargs)
except AttributeError:
return (False, "Failed to invoke consul.Consul, please make sure you have python-consul >= 0.2.0 installed")
return __virtualname__

View File

@ -421,18 +421,17 @@ def list_(bank):
Lists entries stored in the specified bank.
'''
redis_server = _get_redis_server()
bank_keys_redis_key = _get_bank_keys_redis_key(bank)
bank_keys = None
bank_redis_key = _get_bank_redis_key(bank)
try:
bank_keys = redis_server.smembers(bank_keys_redis_key)
banks = redis_server.smembers(bank_redis_key)
except (RedisConnectionError, RedisResponseError) as rerr:
mesg = 'Cannot list the Redis cache key {rkey}: {rerr}'.format(rkey=bank_keys_redis_key,
mesg = 'Cannot list the Redis cache key {rkey}: {rerr}'.format(rkey=bank_redis_key,
rerr=rerr)
log.error(mesg)
raise SaltCacheError(mesg)
if not bank_keys:
if not banks:
return []
return list(bank_keys)
return list(banks)
def contains(bank, key):
@ -440,15 +439,11 @@ def contains(bank, key):
Checks if the specified bank contains the specified key.
'''
redis_server = _get_redis_server()
bank_keys_redis_key = _get_bank_keys_redis_key(bank)
bank_keys = None
bank_redis_key = _get_bank_redis_key(bank)
try:
bank_keys = redis_server.smembers(bank_keys_redis_key)
return redis_server.sismember(bank_redis_key, key)
except (RedisConnectionError, RedisResponseError) as rerr:
mesg = 'Cannot retrieve the Redis cache key {rkey}: {rerr}'.format(rkey=bank_keys_redis_key,
mesg = 'Cannot retrieve the Redis cache key {rkey}: {rerr}'.format(rkey=bank_redis_key,
rerr=rerr)
log.error(mesg)
raise SaltCacheError(mesg)
if not bank_keys:
return False
return key in bank_keys

View File

@ -140,10 +140,11 @@ class Batch(object):
# sure that the main while loop finishes even with unresp minions
minion_tracker = {}
# We already know some minions didn't respond to the ping, so inform
# the user we won't be attempting to run a job on them
for down_minion in self.down_minions:
print_cli('Minion {0} did not respond. No job will be sent.'.format(down_minion))
if not self.quiet:
# We already know some minions didn't respond to the ping, so inform
# the user we won't be attempting to run a job on them
for down_minion in self.down_minions:
print_cli('Minion {0} did not respond. No job will be sent.'.format(down_minion))
# Iterate while we still have things to execute
while len(ret) < len(self.minions):

View File

@ -14,7 +14,7 @@ from __future__ import absolute_import
# Import Salt libs
import salt.spm
import salt.utils.parsers as parsers
from salt.utils.verify import verify_log
from salt.utils.verify import verify_log, verify_env
class SPM(parsers.SPMParser):
@ -29,6 +29,10 @@ class SPM(parsers.SPMParser):
ui = salt.spm.SPMCmdlineInterface()
self.parse_args()
self.setup_logfile_logger()
v_dirs = [
self.config['cachedir'],
]
verify_env(v_dirs, self.config['user'],)
verify_log(self.config)
client = salt.spm.SPMClient(ui, self.config)
client.run(self.args)

View File

@ -1582,7 +1582,10 @@ class LocalClient(object):
timeout=timeout,
tgt=tgt,
tgt_type=tgt_type,
expect_minions=(verbose or show_timeout),
# (gtmanfred) expect_minions is popped here incase it is passed from a client
# call. If this is not popped, then it would be passed twice to
# get_iter_returns.
expect_minions=(kwargs.pop('expect_minions', False) or verbose or show_timeout),
**kwargs
):
log.debug('return event: %s', ret)

View File

@ -289,6 +289,143 @@ def apply_(mods=None,
return highstate(**kwargs)
def request(mods=None,
**kwargs):
'''
.. versionadded:: 2017.7.3
Request that the local admin execute a state run via
`salt-call state.run_request`
All arguments match state.apply
CLI Example:
.. code-block:: bash
salt '*' state.request
salt '*' state.request test
salt '*' state.request test,pkgs
'''
kwargs['test'] = True
ret = apply_(mods, **kwargs)
notify_path = os.path.join(__opts__['cachedir'], 'req_state.p')
serial = salt.payload.Serial(__opts__)
req = check_request()
req.update({kwargs.get('name', 'default'): {
'test_run': ret,
'mods': mods,
'kwargs': kwargs
}
})
cumask = os.umask(0o77)
try:
if salt.utils.is_windows():
# Make sure cache file isn't read-only
__salt__['cmd.run']('attrib -R "{0}"'.format(notify_path))
with salt.utils.fopen(notify_path, 'w+b') as fp_:
serial.dump(req, fp_)
except (IOError, OSError):
msg = 'Unable to write state request file {0}. Check permission.'
log.error(msg.format(notify_path))
os.umask(cumask)
return ret
def check_request(name=None):
'''
.. versionadded:: 2017.7.3
Return the state request information, if any
CLI Example:
.. code-block:: bash
salt '*' state.check_request
'''
notify_path = os.path.join(__opts__['cachedir'], 'req_state.p')
serial = salt.payload.Serial(__opts__)
if os.path.isfile(notify_path):
with salt.utils.fopen(notify_path, 'rb') as fp_:
req = serial.load(fp_)
if name:
return req[name]
return req
return {}
def clear_request(name=None):
'''
.. versionadded:: 2017.7.3
Clear out the state execution request without executing it
CLI Example:
.. code-block:: bash
salt '*' state.clear_request
'''
notify_path = os.path.join(__opts__['cachedir'], 'req_state.p')
serial = salt.payload.Serial(__opts__)
if not os.path.isfile(notify_path):
return True
if not name:
try:
os.remove(notify_path)
except (IOError, OSError):
pass
else:
req = check_request()
if name in req:
req.pop(name)
else:
return False
cumask = os.umask(0o77)
try:
if salt.utils.is_windows():
# Make sure cache file isn't read-only
__salt__['cmd.run']('attrib -R "{0}"'.format(notify_path))
with salt.utils.fopen(notify_path, 'w+b') as fp_:
serial.dump(req, fp_)
except (IOError, OSError):
msg = 'Unable to write state request file {0}. Check permission.'
log.error(msg.format(notify_path))
os.umask(cumask)
return True
def run_request(name='default', **kwargs):
'''
.. versionadded:: 2017.7.3
Execute the pending state request
CLI Example:
.. code-block:: bash
salt '*' state.run_request
'''
req = check_request()
if name not in req:
return {}
n_req = req[name]
if 'mods' not in n_req or 'kwargs' not in n_req:
return {}
req[name]['kwargs'].update(kwargs)
if 'test' in n_req['kwargs']:
n_req['kwargs'].pop('test')
if req:
ret = apply_(n_req['mods'], **n_req['kwargs'])
try:
os.remove(os.path.join(__opts__['cachedir'], 'req_state.p'))
except (IOError, OSError):
pass
return ret
return {}
def highstate(test=None, **kwargs):
'''
Retrieve the state data from the salt master for this minion and execute it

View File

@ -234,7 +234,7 @@ class CloudClient(object):
if a.get('provider', '')]
if providers:
_providers = opts.get('providers', {})
for provider in list(_providers):
for provider in list(_providers).copy():
if provider not in providers:
_providers.pop(provider)
return opts

View File

@ -1990,7 +1990,7 @@ def request_instance(vm_=None, call=None):
params[termination_key] = str(set_del_root_vol_on_destroy).lower()
# Use default volume type if not specified
if ex_blockdevicemappings and 'Ebs.VolumeType' not in ex_blockdevicemappings[dev_index]:
if ex_blockdevicemappings and dev_index < len(ex_blockdevicemappings) and 'Ebs.VolumeType' not in ex_blockdevicemappings[dev_index]:
type_key = '{0}BlockDeviceMapping.{1}.Ebs.VolumeType'.format(spot_prefix, dev_index)
params[type_key] = rd_type
@ -3539,16 +3539,15 @@ def list_nodes_min(location=None, call=None):
for instance in instances:
if isinstance(instance['instancesSet']['item'], list):
for item in instance['instancesSet']['item']:
state = item['instanceState']['name']
name = _extract_name_tag(item)
id = item['instanceId']
items = instance['instancesSet']['item']
else:
item = instance['instancesSet']['item']
items = [instance['instancesSet']['item']]
for item in items:
state = item['instanceState']['name']
name = _extract_name_tag(item)
id = item['instanceId']
ret[name] = {'state': state, 'id': id}
ret[name] = {'state': state, 'id': id}
return ret

View File

@ -2400,9 +2400,10 @@ def create_attach_volumes(name, kwargs, call=None):
'-a or --action.'
)
volumes = kwargs['volumes']
volumes = literal_eval(kwargs['volumes'])
node = kwargs['node']
node_data = _expand_node(node)
conn = get_conn()
node_data = _expand_node(conn.ex_get_node(node))
letter = ord('a') - 1
for idx, volume in enumerate(volumes):
@ -2412,9 +2413,9 @@ def create_attach_volumes(name, kwargs, call=None):
'disk_name': volume_name,
'location': node_data['extra']['zone']['name'],
'size': volume['size'],
'type': volume['type'],
'image': volume['image'],
'snapshot': volume['snapshot']
'type': volume.get('type', 'pd-standard'),
'image': volume.get('image', None),
'snapshot': volume.get('snapshot', None)
}
create_disk(volume_dict, 'function')
@ -2580,7 +2581,10 @@ def create(vm_=None, call=None):
ssh_user, ssh_key = __get_ssh_credentials(vm_)
vm_['ssh_host'] = __get_host(node_data, vm_)
vm_['key_filename'] = ssh_key
__utils__['cloud.bootstrap'](vm_, __opts__)
ret = __utils__['cloud.bootstrap'](vm_, __opts__)
ret.update(node_dict)
log.info('Created Cloud VM \'{0[name]}\''.format(vm_))
log.trace(
@ -2598,7 +2602,7 @@ def create(vm_=None, call=None):
transport=__opts__['transport']
)
return node_dict
return ret
def update_pricing(kwargs=None, call=None):

View File

@ -41,6 +41,7 @@ Example profile:
master_port: 5506
Tested on:
- Fedora 26 (libvirt 3.2.1, qemu 2.9.1)
- Fedora 25 (libvirt 1.3.3.2, qemu 2.6.1)
- Fedora 23 (libvirt 1.2.18, qemu 2.4.1)
- Centos 7 (libvirt 1.2.17, qemu 1.5.3)
@ -82,9 +83,6 @@ from salt.exceptions import (
SaltCloudSystemExit
)
# Get logging started
log = logging.getLogger(__name__)
VIRT_STATE_NAME_MAP = {0: 'running',
1: 'running',
2: 'running',
@ -99,6 +97,20 @@ IP_LEARNING_XML = """<filterref filter='clean-traffic'>
__virtualname__ = 'libvirt'
# Set up logging
log = logging.getLogger(__name__)
def libvirt_error_handler(ctx, error): # pylint: disable=unused-argument
'''
Redirect stderr prints from libvirt to salt logging.
'''
log.debug("libvirt error {0}".format(error))
if HAS_LIBVIRT:
libvirt.registerErrorHandler(f=libvirt_error_handler, ctx=None)
def __virtual__():
'''
@ -450,18 +462,54 @@ def create(vm_):
return ret
except Exception as e: # pylint: disable=broad-except
# Try to clean up in as much cases as possible
log.info('Cleaning up after exception clean up items: {0}'.format(cleanup))
for leftover in cleanup:
what = leftover['what']
item = leftover['item']
if what == 'domain':
destroy_domain(conn, item)
if what == 'volume':
item.delete()
do_cleanup(cleanup)
# throw the root cause after cleanup
raise e
def do_cleanup(cleanup):
'''
Clean up clone domain leftovers as much as possible.
Extra robust clean up in order to deal with some small changes in libvirt
behavior over time. Passed in volumes and domains are deleted, any errors
are ignored. Used when cloning/provisioning a domain fails.
:param cleanup: list containing dictonaries with two keys: 'what' and 'item'.
If 'what' is domain the 'item' is a libvirt domain object.
If 'what' is volume then the item is a libvirt volume object.
Returns:
none
.. versionadded: 2017.7.3
'''
log.info('Cleaning up after exception')
for leftover in cleanup:
what = leftover['what']
item = leftover['item']
if what == 'domain':
log.info('Cleaning up {0} {1}'.format(what, item.name()))
try:
item.destroy()
log.debug('{0} {1} forced off'.format(what, item.name()))
except libvirtError:
pass
try:
item.undefineFlags(libvirt.VIR_DOMAIN_UNDEFINE_MANAGED_SAVE+
libvirt.VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA+
libvirt.VIR_DOMAIN_UNDEFINE_NVRAM)
log.debug('{0} {1} undefined'.format(what, item.name()))
except libvirtError:
pass
if what == 'volume':
try:
item.delete()
log.debug('{0} {1} cleaned up'.format(what, item.name()))
except libvirtError:
pass
def destroy(name, call=None):
"""
This function irreversibly destroys a virtual machine on the cloud provider.

View File

@ -4571,7 +4571,8 @@ def _list_nodes(full=False):
pass
vms[name]['id'] = vm.find('ID').text
vms[name]['image'] = vm.find('TEMPLATE').find('TEMPLATE_ID').text
if vm.find('TEMPLATE').find('TEMPLATE_ID'):
vms[name]['image'] = vm.find('TEMPLATE').find('TEMPLATE_ID').text
vms[name]['name'] = name
vms[name]['size'] = {'cpu': cpu_size, 'memory': memory_size}
vms[name]['state'] = vm.find('STATE').text

View File

@ -55,7 +55,7 @@ _DFLT_LOG_DATEFMT = '%H:%M:%S'
_DFLT_LOG_DATEFMT_LOGFILE = '%Y-%m-%d %H:%M:%S'
_DFLT_LOG_FMT_CONSOLE = '[%(levelname)-8s] %(message)s'
_DFLT_LOG_FMT_LOGFILE = (
'%(asctime)s,%(msecs)03d [%(name)-17s][%(levelname)-8s][%(process)d] %(message)s'
'%(asctime)s,%(msecs)03d [%(name)-17s:%(lineno)-4d][%(levelname)-8s][%(process)d] %(message)s'
)
_DFLT_REFSPECS = ['+refs/heads/*:refs/remotes/origin/*', '+refs/tags/*:refs/tags/*']
@ -334,7 +334,7 @@ VALID_OPTS = {
# Whether or not scheduled mine updates should be accompanied by a job return for the job cache
'mine_return_job': bool,
# Schedule a mine update every n number of seconds
# The number of minutes between mine updates.
'mine_interval': int,
# The ipc strategy. (i.e., sockets versus tcp, etc)
@ -569,6 +569,23 @@ VALID_OPTS = {
# False in 2016.3.0
'add_proxymodule_to_opts': bool,
# Merge pillar data into configuration opts.
# As multiple proxies can run on the same server, we may need different
# configuration options for each, while there's one single configuration file.
# The solution is merging the pillar data of each proxy minion into the opts.
'proxy_merge_pillar_in_opts': bool,
# Deep merge of pillar data into configuration opts.
# Evaluated only when `proxy_merge_pillar_in_opts` is True.
'proxy_deep_merge_pillar_in_opts': bool,
# The strategy used when merging pillar into opts.
# Considered only when `proxy_merge_pillar_in_opts` is True.
'proxy_merge_pillar_in_opts_strategy': str,
# Allow enabling mine details using pillar data.
'proxy_mines_pillar': bool,
# In some particular cases, always alive proxies are not beneficial.
# This option can be used in those less dynamic environments:
# the user can request the connection
@ -700,6 +717,10 @@ VALID_OPTS = {
'fileserver_limit_traversal': bool,
'fileserver_verify_config': bool,
# Optionally apply '*' permissioins to any user. By default '*' is a fallback case that is
# applied only if the user didn't matched by other matchers.
'permissive_acl': bool,
# Optionally enables keeping the calculated user's auth list in the token file.
'keep_acl_in_token': bool,
@ -1449,6 +1470,7 @@ DEFAULT_MASTER_OPTS = {
'external_auth': {},
'token_expire': 43200,
'token_expire_user_override': False,
'permissive_acl': False,
'keep_acl_in_token': False,
'eauth_acl_module': '',
'extension_modules': os.path.join(salt.syspaths.CACHE_DIR, 'master', 'extmods'),
@ -1637,6 +1659,12 @@ DEFAULT_PROXY_MINION_OPTS = {
'append_minionid_config_dirs': ['cachedir', 'pidfile', 'default_include', 'extension_modules'],
'default_include': 'proxy.d/*.conf',
'proxy_merge_pillar_in_opts': False,
'proxy_deep_merge_pillar_in_opts': False,
'proxy_merge_pillar_in_opts_strategy': 'smart',
'proxy_mines_pillar': True,
# By default, proxies will preserve the connection.
# If this option is set to False,
# the connection with the remote dumb device

View File

@ -607,6 +607,9 @@ class AsyncAuth(object):
raise tornado.gen.Return('retry')
else:
raise SaltClientError('Attempt to authenticate with the salt master failed with timeout error')
if not isinstance(payload, dict):
log.error('Sign-in attempt failed: %s', payload)
raise tornado.gen.Return(False)
if 'load' in payload:
if 'ret' in payload['load']:
if not payload['load']['ret']:

View File

@ -204,6 +204,14 @@ def clean_old_jobs(opts):
def mk_key(opts, user):
if HAS_PWD:
uid = None
try:
uid = pwd.getpwnam(user).pw_uid
except KeyError:
# User doesn't exist in the system
if opts['client_acl_verify']:
return None
if salt.utils.is_windows():
# The username may contain '\' if it is in Windows
# 'DOMAIN\username' format. Fix this for the keyfile path.
@ -231,9 +239,9 @@ def mk_key(opts, user):
# Write access is necessary since on subsequent runs, if the file
# exists, it needs to be written to again. Windows enforces this.
os.chmod(keyfile, 0o600)
if HAS_PWD:
if HAS_PWD and uid is not None:
try:
os.chown(keyfile, pwd.getpwnam(user).pw_uid, -1)
os.chown(keyfile, uid, -1)
except OSError:
# The master is not being run as root and can therefore not
# chown the key file
@ -248,27 +256,26 @@ def access_keys(opts):
'''
# TODO: Need a way to get all available users for systems not supported by pwd module.
# For now users pattern matching will not work for publisher_acl.
users = []
keys = {}
publisher_acl = opts['publisher_acl']
acl_users = set(publisher_acl.keys())
if opts.get('user'):
acl_users.add(opts['user'])
acl_users.add(salt.utils.get_user())
if opts['client_acl_verify'] and HAS_PWD:
log.profile('Beginning pwd.getpwall() call in masterarpi access_keys function')
for user in pwd.getpwall():
users.append(user.pw_name)
log.profile('End pwd.getpwall() call in masterarpi access_keys function')
for user in acl_users:
log.info('Preparing the %s key for local communication', user)
keys[user] = mk_key(opts, user)
key = mk_key(opts, user)
if key is not None:
keys[user] = key
# Check other users matching ACL patterns
if HAS_PWD:
for user in users:
if opts['client_acl_verify'] and HAS_PWD:
log.profile('Beginning pwd.getpwall() call in masterapi access_keys function')
for user in pwd.getpwall():
user = user.pw_name
if user not in keys and salt.utils.check_whitelist_blacklist(user, whitelist=acl_users):
keys[user] = mk_key(opts, user)
log.profile('End pwd.getpwall() call in masterapi access_keys function')
return keys

View File

@ -74,8 +74,12 @@ def start(docker_url='unix://var/run/docker.sock',
else:
__salt__['event.send'](tag, msg)
client = docker.Client(base_url=docker_url,
timeout=timeout)
try:
# docker-py 2.0 renamed this client attribute
client = docker.APIClient(base_url=docker_url, timeout=timeout)
except AttributeError:
client = docker.Client(base_url=docker_url, timeout=timeout)
try:
events = client.events()
for event in events:

View File

@ -265,6 +265,12 @@ class SaltCacheError(SaltException):
'''
class TimeoutError(SaltException):
'''
Thrown when an opration cannot be completet within a given time limit.
'''
class SaltReqTimeoutError(SaltException):
'''
Thrown when a salt master request call fails to return within the timeout

View File

@ -622,10 +622,14 @@ class Client(object):
def on_header(hdr):
if write_body[1] is not False and write_body[2] is None:
if not hdr.strip() and 'Content-Type' not in write_body[1]:
# We've reached the end of the headers and not yet
# found the Content-Type. Reset the values we're
# tracking so that we properly follow the redirect.
write_body[0] = None
# If write_body[0] is True, then we are not following a
# redirect (initial response was a 200 OK). So there is
# no need to reset write_body[0].
if write_body[0] is not True:
# We are following a redirect, so we need to reset
# write_body[0] so that we properly follow it.
write_body[0] = None
# We don't need the HTTPHeaders object anymore
write_body[1] = False
return
# Try to find out what content type encoding is used if
@ -648,9 +652,12 @@ class Client(object):
# If write_body[0] is False, this means that this
# header is a 30x redirect, so we need to reset
# write_body[0] to None so that we parse the HTTP
# status code from the redirect target.
# status code from the redirect target. Additionally,
# we need to reset write_body[2] so that we inspect the
# headers for the Content-Type of the URL we're
# following.
if write_body[0] is write_body[1] is False:
write_body[0] = None
write_body[0] = write_body[2] = None
# Check the status line of the HTTP request
if write_body[0] is None:

View File

@ -367,6 +367,16 @@ def _file_lists(load, form):
'roots: %s symlink destination is %s',
abs_path, link_dest
)
if salt.utils.is_windows() \
and link_dest.startswith('\\\\'):
# Symlink points to a network path. Since you can't
# join UNC and non-UNC paths, just assume the original
# path.
log.trace(
'roots: %s is a UNC path, using %s instead',
link_dest, abs_path
)
link_dest = abs_path
if link_dest.startswith('..'):
joined = os.path.join(abs_path, link_dest)
else:

View File

@ -1175,6 +1175,10 @@ _OS_FAMILY_MAP = {
'Raspbian': 'Debian',
'Devuan': 'Debian',
'antiX': 'Debian',
'Kali': 'Debian',
'neon': 'Debian',
'Cumulus': 'Debian',
'Deepin': 'Debian',
'NILinuxRT': 'NILinuxRT',
'NILinuxRT-XFCE': 'NILinuxRT',
'Void': 'Void',
@ -1363,7 +1367,10 @@ def os_data():
.format(' '.join(init_cmdline))
)
# Add lsb grains on any distro with lsb-release
# Add lsb grains on any distro with lsb-release. Note that this import
# can fail on systems with lsb-release installed if the system package
# does not install the python package for the python interpreter used by
# Salt (i.e. python2 or python3)
try:
import lsb_release # pylint: disable=import-error
release = lsb_release.get_distro_information()
@ -1412,7 +1419,13 @@ def os_data():
if 'VERSION_ID' in os_release:
grains['lsb_distrib_release'] = os_release['VERSION_ID']
if 'PRETTY_NAME' in os_release:
grains['lsb_distrib_codename'] = os_release['PRETTY_NAME']
codename = os_release['PRETTY_NAME']
# https://github.com/saltstack/salt/issues/44108
if os_release['ID'] == 'debian':
codename_match = re.search(r'\((\w+)\)$', codename)
if codename_match:
codename = codename_match.group(1)
grains['lsb_distrib_codename'] = codename
if 'CPE_NAME' in os_release:
if ":suse:" in os_release['CPE_NAME'] or ":opensuse:" in os_release['CPE_NAME']:
grains['os'] = "SUSE"

View File

@ -17,6 +17,7 @@ metadata server set `metadata_server_grains: True`.
from __future__ import absolute_import
# Import python libs
import json
import os
import socket
@ -47,14 +48,28 @@ def _search(prefix="latest/"):
Recursively look up all grains in the metadata server
'''
ret = {}
for line in http.query(os.path.join(HOST, prefix))['body'].split('\n'):
linedata = http.query(os.path.join(HOST, prefix))
if 'body' not in linedata:
return ret
for line in linedata['body'].split('\n'):
if line.endswith('/'):
ret[line[:-1]] = _search(prefix=os.path.join(prefix, line))
elif prefix == 'latest/':
# (gtmanfred) The first level should have a forward slash since
# they have stuff underneath. This will not be doubled up though,
# because lines ending with a slash are checked first.
ret[line] = _search(prefix=os.path.join(prefix, line + '/'))
elif '=' in line:
key, value = line.split('=')
ret[value] = _search(prefix=os.path.join(prefix, key))
else:
ret[line] = http.query(os.path.join(HOST, prefix, line))['body']
retdata = http.query(os.path.join(HOST, prefix, line)).get('body', None)
# (gtmanfred) This try except block is slightly faster than
# checking if the string starts with a curly brace
try:
ret[line] = json.loads(retdata)
except ValueError:
ret[line] = retdata
return ret

View File

@ -489,7 +489,7 @@ class Key(object):
minions = []
for key, val in six.iteritems(keys):
minions.extend(val)
if not self.opts.get('preserve_minion_cache', False) or not preserve_minions:
if not self.opts.get('preserve_minion_cache', False):
m_cache = os.path.join(self.opts['cachedir'], self.ACC)
if os.path.isdir(m_cache):
for minion in os.listdir(m_cache):
@ -736,7 +736,7 @@ class Key(object):
def delete_key(self,
match=None,
match_dict=None,
preserve_minions=False,
preserve_minions=None,
revoke_auth=False):
'''
Delete public keys. If "match" is passed, it is evaluated as a glob.
@ -774,11 +774,10 @@ class Key(object):
salt.utils.event.tagify(prefix='key'))
except (OSError, IOError):
pass
if preserve_minions:
preserve_minions_list = matches.get('minions', [])
if self.opts.get('preserve_minions') is True:
self.check_minion_cache(preserve_minions=matches.get('minions', []))
else:
preserve_minions_list = []
self.check_minion_cache(preserve_minions=preserve_minions_list)
self.check_minion_cache()
if self.opts.get('rotate_aes_key'):
salt.crypt.dropfile(self.opts['cachedir'], self.opts['user'])
return (
@ -969,16 +968,17 @@ class RaetKey(Key):
minions.extend(val)
m_cache = os.path.join(self.opts['cachedir'], 'minions')
if os.path.isdir(m_cache):
for minion in os.listdir(m_cache):
if minion not in minions:
shutil.rmtree(os.path.join(m_cache, minion))
cache = salt.cache.factory(self.opts)
clist = cache.list(self.ACC)
if clist:
for minion in clist:
if not self.opts.get('preserve_minion_cache', False):
if os.path.isdir(m_cache):
for minion in os.listdir(m_cache):
if minion not in minions and minion not in preserve_minions:
cache.flush('{0}/{1}'.format(self.ACC, minion))
shutil.rmtree(os.path.join(m_cache, minion))
cache = salt.cache.factory(self.opts)
clist = cache.list(self.ACC)
if clist:
for minion in clist:
if minion not in minions and minion not in preserve_minions:
cache.flush('{0}/{1}'.format(self.ACC, minion))
kind = self.opts.get('__role', '') # application kind
if kind not in salt.utils.kinds.APPL_KINDS:
@ -1220,7 +1220,7 @@ class RaetKey(Key):
def delete_key(self,
match=None,
match_dict=None,
preserve_minions=False,
preserve_minions=None,
revoke_auth=False):
'''
Delete public keys. If "match" is passed, it is evaluated as a glob.
@ -1251,7 +1251,10 @@ class RaetKey(Key):
os.remove(os.path.join(self.opts['pki_dir'], status, key))
except (OSError, IOError):
pass
self.check_minion_cache(preserve_minions=matches.get('minions', []))
if self.opts.get('preserve_minions') is True:
self.check_minion_cache(preserve_minions=matches.get('minions', []))
else:
self.check_minion_cache()
return (
self.name_match(match) if match is not None
else self.dict_match(matches)

View File

@ -270,7 +270,7 @@ def raw_mod(opts, name, functions, mod='modules'):
testmod['test.ping']()
'''
loader = LazyLoader(
_module_dirs(opts, mod, 'rawmodule'),
_module_dirs(opts, mod, 'module'),
opts,
tag='rawmodule',
virtual_enable=False,

View File

@ -128,12 +128,12 @@ def setup_handlers():
callable(transport_registry.compute_scope)):
conf_extras = transport_registry.compute_scope(url, dsn_config)
dsn_config.update(conf_extras)
options.update({
'project': dsn_config['SENTRY_PROJECT'],
'servers': dsn_config['SENTRY_SERVERS'],
'public_key': dsn_config['SENTRY_PUBLIC_KEY'],
'secret_key': dsn_config['SENTRY_SECRET_KEY']
})
options.update({
'project': dsn_config['SENTRY_PROJECT'],
'servers': dsn_config['SENTRY_SERVERS'],
'public_key': dsn_config['SENTRY_PUBLIC_KEY'],
'secret_key': dsn_config['SENTRY_SECRET_KEY']
})
except ValueError as exc:
log.info(
'Raven failed to parse the configuration provided '

View File

@ -60,7 +60,6 @@ import salt.search
import salt.key
import salt.acl
import salt.engines
import salt.fileserver
import salt.daemons.masterapi
import salt.defaults.exitcodes
import salt.transport.server
@ -181,7 +180,8 @@ class Maintenance(SignalHandlingMultiprocessingProcess):
in the parent process, then once the fork happens you'll start getting
errors like "WARNING: Mixing fork() and threads detected; memory leaked."
'''
# Init fileserver manager
# Avoid circular import
import salt.fileserver
self.fileserver = salt.fileserver.Fileserver(self.opts)
# Load Runners
ropts = dict(self.opts)
@ -459,6 +459,8 @@ class Master(SMaster):
)
if self.opts.get('fileserver_verify_config', True):
# Avoid circular import
import salt.fileserver
fileserver = salt.fileserver.Fileserver(self.opts)
if not fileserver.servers:
errors.append(
@ -494,16 +496,15 @@ class Master(SMaster):
if non_legacy_git_pillars:
try:
new_opts = copy.deepcopy(self.opts)
from salt.pillar.git_pillar \
import PER_REMOTE_OVERRIDES as per_remote_overrides, \
PER_REMOTE_ONLY as per_remote_only
import salt.pillar.git_pillar
for repo in non_legacy_git_pillars:
new_opts['ext_pillar'] = [repo]
try:
git_pillar = salt.utils.gitfs.GitPillar(new_opts)
git_pillar.init_remotes(repo['git'],
per_remote_overrides,
per_remote_only)
git_pillar.init_remotes(
repo['git'],
salt.pillar.git_pillar.PER_REMOTE_OVERRIDES,
salt.pillar.git_pillar.PER_REMOTE_ONLY)
except FileserverConfigError as exc:
critical_errors.append(exc.strerror)
finally:
@ -973,6 +974,8 @@ class AESFuncs(object):
'''
Set the local file objects from the file server interface
'''
# Avoid circular import
import salt.fileserver
self.fs_ = salt.fileserver.Fileserver(self.opts)
self._serve_file = self.fs_.serve_file
self._file_find = self.fs_._find_file

View File

@ -100,6 +100,7 @@ import salt.defaults.exitcodes
import salt.cli.daemons
import salt.log.setup
import salt.utils.dictupdate
from salt.config import DEFAULT_MINION_OPTS
from salt.defaults import DEFAULT_TARGET_DELIM
from salt.executors import FUNCTION_EXECUTORS
@ -934,7 +935,7 @@ class Minion(MinionBase):
# Flag meaning minion has finished initialization including first connect to the master.
# True means the Minion is fully functional and ready to handle events.
self.ready = False
self.jid_queue = jid_queue
self.jid_queue = jid_queue or []
if io_loop is None:
if HAS_ZMQ:
@ -1599,13 +1600,24 @@ class Minion(MinionBase):
minion side execution.
'''
salt.utils.appendproctitle('{0}._thread_multi_return {1}'.format(cls.__name__, data['jid']))
ret = {
'return': {},
'retcode': {},
'success': {}
}
for ind in range(0, len(data['fun'])):
ret['success'][data['fun'][ind]] = False
multifunc_ordered = opts.get('multifunc_ordered', False)
num_funcs = len(data['fun'])
if multifunc_ordered:
ret = {
'return': [None] * num_funcs,
'retcode': [None] * num_funcs,
'success': [False] * num_funcs
}
else:
ret = {
'return': {},
'retcode': {},
'success': {}
}
for ind in range(0, num_funcs):
if not multifunc_ordered:
ret['success'][data['fun'][ind]] = False
try:
if minion_instance.connected and minion_instance.opts['pillar'].get('minion_blackout', False):
# this minion is blacked out. Only allow saltutil.refresh_pillar
@ -1620,12 +1632,20 @@ class Minion(MinionBase):
data['arg'][ind],
data)
minion_instance.functions.pack['__context__']['retcode'] = 0
ret['return'][data['fun'][ind]] = func(*args, **kwargs)
ret['retcode'][data['fun'][ind]] = minion_instance.functions.pack['__context__'].get(
'retcode',
0
)
ret['success'][data['fun'][ind]] = True
if multifunc_ordered:
ret['return'][ind] = func(*args, **kwargs)
ret['retcode'][ind] = minion_instance.functions.pack['__context__'].get(
'retcode',
0
)
ret['success'][ind] = True
else:
ret['return'][data['fun'][ind]] = func(*args, **kwargs)
ret['retcode'][data['fun'][ind]] = minion_instance.functions.pack['__context__'].get(
'retcode',
0
)
ret['success'][data['fun'][ind]] = True
except Exception as exc:
trb = traceback.format_exc()
log.warning(
@ -1633,7 +1653,10 @@ class Minion(MinionBase):
exc
)
)
ret['return'][data['fun'][ind]] = trb
if multifunc_ordered:
ret['return'][ind] = trb
else:
ret['return'][data['fun'][ind]] = trb
ret['jid'] = data['jid']
ret['fun'] = data['fun']
ret['fun_args'] = data['arg']
@ -3120,6 +3143,26 @@ class ProxyMinion(Minion):
if 'proxy' not in self.opts:
self.opts['proxy'] = self.opts['pillar']['proxy']
if self.opts.get('proxy_merge_pillar_in_opts'):
# Override proxy opts with pillar data when the user required.
self.opts = salt.utils.dictupdate.merge(self.opts,
self.opts['pillar'],
strategy=self.opts.get('proxy_merge_pillar_in_opts_strategy'),
merge_lists=self.opts.get('proxy_deep_merge_pillar_in_opts', False))
elif self.opts.get('proxy_mines_pillar'):
# Even when not required, some details such as mine configuration
# should be merged anyway whenever possible.
if 'mine_interval' in self.opts['pillar']:
self.opts['mine_interval'] = self.opts['pillar']['mine_interval']
if 'mine_functions' in self.opts['pillar']:
general_proxy_mines = self.opts.get('mine_functions', [])
specific_proxy_mines = self.opts['pillar']['mine_functions']
try:
self.opts['mine_functions'] = general_proxy_mines + specific_proxy_mines
except TypeError as terr:
log.error('Unable to merge mine functions from the pillar in the opts, for proxy {}'.format(
self.opts['id']))
fq_proxyname = self.opts['proxy']['proxytype']
# Need to load the modules so they get all the dunder variables

View File

@ -12,6 +12,7 @@ import logging
# Import Salt libs
import salt.utils
import salt.utils.path
# Import 3rd-party libs
import salt.ext.six as six
@ -241,4 +242,4 @@ def _read_link(name):
Throws an OSError if the link does not exist
'''
alt_link_path = '/etc/alternatives/{0}'.format(name)
return os.readlink(alt_link_path)
return salt.utils.path.readlink(alt_link_path)

View File

@ -446,11 +446,15 @@ def config(name, config, edit=True):
salt '*' apache.config /etc/httpd/conf.d/ports.conf config="[{'Listen': '22'}]"
'''
configs = []
for entry in config:
key = next(six.iterkeys(entry))
configs = _parse_config(entry[key], key)
if edit:
with salt.utils.fopen(name, 'w') as configfile:
configfile.write('# This file is managed by Salt.\n')
configfile.write(configs)
return configs
configs.append(_parse_config(entry[key], key))
# Python auto-correct line endings
configstext = "\n".join(configs)
if edit:
with salt.utils.fopen(name, 'w') as configfile:
configfile.write('# This file is managed by Salt.\n')
configfile.write(configstext)
return configstext

View File

@ -29,7 +29,6 @@ import json
import yaml
# pylint: disable=no-name-in-module,import-error,redefined-builtin
import salt.ext.six as six
from salt.ext.six.moves import range
from salt.ext.six.moves.urllib.error import HTTPError
from salt.ext.six.moves.urllib.request import Request as _Request, urlopen as _urlopen
# pylint: enable=no-name-in-module,import-error,redefined-builtin
@ -93,11 +92,15 @@ __virtualname__ = 'pkg'
def __virtual__():
'''
Confirm this module is on a Debian based system
Confirm this module is on a Debian-based system
'''
if __grains__.get('os_family') in ('Kali', 'Debian', 'neon'):
return __virtualname__
elif __grains__.get('os_family', False) == 'Cumulus':
# If your minion is running an OS which is Debian-based but does not have
# an "os_family" grain of Debian, then the proper fix is NOT to check for
# the minion's "os_family" grain here in the __virtual__. The correct fix
# is to add the value from the minion's "os" grain to the _OS_FAMILY_MAP
# dict in salt/grains/core.py, so that we assign the correct "os_family"
# grain to the minion.
if __grains__.get('os_family') == 'Debian':
return __virtualname__
return (False, 'The pkg module could not be loaded: unsupported OS family')
@ -1554,7 +1557,7 @@ def _consolidate_repo_sources(sources):
combined_comps = set(repo.comps).union(set(combined.comps))
consolidated[key].comps = list(combined_comps)
else:
consolidated[key] = sourceslist.SourceEntry(_strip_uri(repo.line))
consolidated[key] = sourceslist.SourceEntry(salt.utils.pkg.deb.strip_uri(repo.line))
if repo.file != base_file:
delete_files.add(repo.file)
@ -1662,7 +1665,7 @@ def list_repos():
repo['dist'] = source.dist
repo['type'] = source.type
repo['uri'] = source.uri.rstrip('/')
repo['line'] = _strip_uri(source.line.strip())
repo['line'] = salt.utils.pkg.deb.strip_uri(source.line.strip())
repo['architectures'] = getattr(source, 'architectures', [])
repos.setdefault(source.uri, []).append(repo)
return repos
@ -2408,18 +2411,6 @@ def file_dict(*packages):
return __salt__['lowpkg.file_dict'](*packages)
def _strip_uri(repo):
'''
Remove the trailing slash from the URI in a repo definition
'''
splits = repo.split()
for idx in range(len(splits)):
if any(splits[idx].startswith(x)
for x in ('http://', 'https://', 'ftp://')):
splits[idx] = splits[idx].rstrip('/')
return ' '.join(splits)
def expand_repo_def(**kwargs):
'''
Take a repository definition and expand it to the full pkg repository dict
@ -2435,7 +2426,7 @@ def expand_repo_def(**kwargs):
_check_apt()
sanitized = {}
repo = _strip_uri(kwargs['repo'])
repo = salt.utils.pkg.deb.strip_uri(kwargs['repo'])
if repo.startswith('ppa:') and __grains__['os'] in ('Ubuntu', 'Mint', 'neon'):
dist = __grains__['lsb_distrib_codename']
owner_name, ppa_name = repo[4:].split('/', 1)

View File

@ -498,16 +498,16 @@ def tar(options, tarfile, sources=None, dest=None,
.. code-block:: bash
salt '*' archive.tar -cjvf /tmp/salt.tar.bz2 {{grains.saltpath}} template=jinja
salt '*' archive.tar cjvf /tmp/salt.tar.bz2 {{grains.saltpath}} template=jinja
CLI Examples:
.. code-block:: bash
# Create a tarfile
salt '*' archive.tar -cjvf /tmp/tarfile.tar.bz2 /tmp/file_1,/tmp/file_2
salt '*' archive.tar cjvf /tmp/tarfile.tar.bz2 /tmp/file_1,/tmp/file_2
# Create a tarfile using globbing (2017.7.0 and later)
salt '*' archive.tar -cjvf /tmp/tarfile.tar.bz2 '/tmp/file_*'
salt '*' archive.tar cjvf /tmp/tarfile.tar.bz2 '/tmp/file_*'
# Unpack a tarfile
salt '*' archive.tar xf foo.tar dest=/target/directory
'''

View File

@ -51,6 +51,7 @@ import datetime
import logging
import json
import sys
import time
import email.mime.multipart
log = logging.getLogger(__name__)
@ -675,11 +676,23 @@ def get_scaling_policy_arn(as_group, scaling_policy_name, region=None,
salt '*' boto_asg.get_scaling_policy_arn mygroup mypolicy
'''
conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile)
policies = conn.get_all_policies(as_group=as_group)
for policy in policies:
if policy.name == scaling_policy_name:
return policy.policy_arn
log.error('Could not convert: {0}'.format(as_group))
retries = 30
while retries > 0:
retries -= 1
try:
policies = conn.get_all_policies(as_group=as_group)
for policy in policies:
if policy.name == scaling_policy_name:
return policy.policy_arn
log.error('Could not convert: {0}'.format(as_group))
return None
except boto.exception.BotoServerError as e:
if e.error_code != 'Throttling':
raise
log.debug('Throttled by API, will retry in 5 seconds')
time.sleep(5)
log.error('Maximum number of retries exceeded')
return None
@ -761,11 +774,18 @@ def get_instances(name, lifecycle_state="InService", health_status="Healthy",
# get full instance info, so that we can return the attribute
instances = ec2_conn.get_only_instances(instance_ids=instance_ids)
if attributes:
return [[getattr(instance, attr).encode("ascii") for attr in attributes] for instance in instances]
return [[_convert_attribute(instance, attr) for attr in attributes] for instance in instances]
else:
# properly handle case when not all instances have the requested attribute
return [getattr(instance, attribute).encode("ascii") for instance in instances if getattr(instance, attribute)]
return [getattr(instance, attribute).encode("ascii") for instance in instances]
return [_convert_attribute(instance, attribute) for instance in instances if getattr(instance, attribute)]
def _convert_attribute(instance, attribute):
if attribute == "tags":
tags = dict(getattr(instance, attribute))
return {key.encode("utf-8"): value.encode("utf-8") for key, value in six.iteritems(tags)}
return getattr(instance, attribute).encode("ascii")
def enter_standby(name, instance_ids, should_decrement_desired_capacity=False,

View File

@ -66,15 +66,17 @@ except ImportError:
log = logging.getLogger(__name__)
__virtualname__ = 'boto_kinesis'
def __virtual__():
'''
Only load if boto3 libraries exist.
'''
if not HAS_BOTO:
return False
return False, 'The boto_kinesis module could not be loaded: boto libraries not found.'
__utils__['boto3.assign_funcs'](__name__, 'kinesis')
return True
return __virtualname__
def _get_basic_stream(stream_name, conn):

View File

@ -493,10 +493,17 @@ def update_parameter_group(name, parameters, apply_method="pending-reboot",
param_list = []
for key, value in six.iteritems(parameters):
item = (key, value, apply_method)
item = odict.OrderedDict()
item.update({'ParameterName': key})
item.update({'ApplyMethod': apply_method})
if type(value) is bool:
item.update({'ParameterValue': 'on' if value else 'off'})
else:
item.update({'ParameterValue': str(value)})
param_list.append(item)
if not len(param_list):
return {'results': False}
if not len(param_list):
return {'results': False}
try:
conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile)
@ -779,6 +786,7 @@ def describe_parameters(name, Source=None, MaxRecords=None, Marker=None,
'message': 'Could not establish a connection to RDS'}
kwargs = {}
kwargs.update({'DBParameterGroupName': name})
for key in ('Marker', 'Source'):
if locals()[key] is not None:
kwargs[key] = str(locals()[key])
@ -786,26 +794,23 @@ def describe_parameters(name, Source=None, MaxRecords=None, Marker=None,
if locals()['MaxRecords'] is not None:
kwargs['MaxRecords'] = int(locals()['MaxRecords'])
r = conn.describe_db_parameters(DBParameterGroupName=name, **kwargs)
pag = conn.get_paginator('describe_db_parameters')
pit = pag.paginate(**kwargs)
if not r:
return {'result': False,
'message': 'Failed to get RDS parameters for group {0}.'
.format(name)}
results = r['Parameters']
keys = ['ParameterName', 'ParameterValue', 'Description',
'Source', 'ApplyType', 'DataType', 'AllowedValues',
'IsModifieable', 'MinimumEngineVersion', 'ApplyMethod']
parameters = odict.OrderedDict()
ret = {'result': True}
for result in results:
data = odict.OrderedDict()
for k in keys:
data[k] = result.get(k)
parameters[result.get('ParameterName')] = data
for p in pit:
for result in p['Parameters']:
data = odict.OrderedDict()
for k in keys:
data[k] = result.get(k)
parameters[result.get('ParameterName')] = data
ret['parameters'] = parameters
return ret

View File

@ -598,9 +598,14 @@ def exists(vpc_id=None, name=None, cidr=None, tags=None, region=None, key=None,
try:
vpc_ids = _find_vpcs(vpc_id=vpc_id, vpc_name=name, cidr=cidr, tags=tags,
region=region, key=key, keyid=keyid, profile=profile)
return {'exists': bool(vpc_ids)}
except BotoServerError as e:
return {'error': salt.utils.boto.get_error(e)}
except BotoServerError as err:
boto_err = salt.utils.boto.get_error(err)
if boto_err.get('aws', {}).get('code') == 'InvalidVpcID.NotFound':
# VPC was not found: handle the error and return False.
return {'exists': False}
return {'error': boto_err}
return {'exists': bool(vpc_ids)}
def create(cidr_block, instance_tenancy=None, vpc_name=None,
@ -722,27 +727,34 @@ def describe(vpc_id=None, vpc_name=None, region=None, key=None,
try:
conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile)
vpc_id = check_vpc(vpc_id, vpc_name, region, key, keyid, profile)
if not vpc_id:
except BotoServerError as err:
boto_err = salt.utils.boto.get_error(err)
if boto_err.get('aws', {}).get('code') == 'InvalidVpcID.NotFound':
# VPC was not found: handle the error and return None.
return {'vpc': None}
return {'error': boto_err}
filter_parameters = {'vpc_ids': vpc_id}
if not vpc_id:
return {'vpc': None}
filter_parameters = {'vpc_ids': vpc_id}
try:
vpcs = conn.get_all_vpcs(**filter_parameters)
except BotoServerError as err:
return {'error': salt.utils.boto.get_error(err)}
if vpcs:
vpc = vpcs[0] # Found!
log.debug('Found VPC: {0}'.format(vpc.id))
if vpcs:
vpc = vpcs[0] # Found!
log.debug('Found VPC: {0}'.format(vpc.id))
keys = ('id', 'cidr_block', 'is_default', 'state', 'tags',
'dhcp_options_id', 'instance_tenancy')
_r = dict([(k, getattr(vpc, k)) for k in keys])
_r.update({'region': getattr(vpc, 'region').name})
return {'vpc': _r}
else:
return {'vpc': None}
except BotoServerError as e:
return {'error': salt.utils.boto.get_error(e)}
keys = ('id', 'cidr_block', 'is_default', 'state', 'tags',
'dhcp_options_id', 'instance_tenancy')
_r = dict([(k, getattr(vpc, k)) for k in keys])
_r.update({'region': getattr(vpc, 'region').name})
return {'vpc': _r}
else:
return {'vpc': None}
def describe_vpcs(vpc_id=None, name=None, cidr=None, tags=None,
@ -808,7 +820,7 @@ def _find_subnets(subnet_name=None, vpc_id=None, cidr=None, tags=None, conn=None
Given subnet properties, find and return matching subnet ids
'''
if not any(subnet_name, tags, cidr):
if not any([subnet_name, tags, cidr]):
raise SaltInvocationError('At least one of the following must be '
'specified: subnet_name, cidr or tags.')
@ -926,34 +938,38 @@ def subnet_exists(subnet_id=None, name=None, subnet_name=None, cidr=None,
try:
conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile)
filter_parameters = {'filters': {}}
except BotoServerError as err:
return {'error': salt.utils.boto.get_error(err)}
if subnet_id:
filter_parameters['subnet_ids'] = [subnet_id]
if subnet_name:
filter_parameters['filters']['tag:Name'] = subnet_name
if cidr:
filter_parameters['filters']['cidr'] = cidr
if tags:
for tag_name, tag_value in six.iteritems(tags):
filter_parameters['filters']['tag:{0}'.format(tag_name)] = tag_value
if zones:
filter_parameters['filters']['availability_zone'] = zones
filter_parameters = {'filters': {}}
if subnet_id:
filter_parameters['subnet_ids'] = [subnet_id]
if subnet_name:
filter_parameters['filters']['tag:Name'] = subnet_name
if cidr:
filter_parameters['filters']['cidr'] = cidr
if tags:
for tag_name, tag_value in six.iteritems(tags):
filter_parameters['filters']['tag:{0}'.format(tag_name)] = tag_value
if zones:
filter_parameters['filters']['availability_zone'] = zones
try:
subnets = conn.get_all_subnets(**filter_parameters)
log.debug('The filters criteria {0} matched the following subnets:{1}'.format(filter_parameters, subnets))
if subnets:
log.info('Subnet {0} exists.'.format(subnet_name or subnet_id))
return {'exists': True}
else:
log.info('Subnet {0} does not exist.'.format(subnet_name or subnet_id))
except BotoServerError as err:
boto_err = salt.utils.boto.get_error(err)
if boto_err.get('aws', {}).get('code') == 'InvalidSubnetID.NotFound':
# Subnet was not found: handle the error and return False.
return {'exists': False}
except BotoServerError as e:
return {'error': salt.utils.boto.get_error(e)}
return {'error': boto_err}
log.debug('The filters criteria {0} matched the following subnets:{1}'.format(filter_parameters, subnets))
if subnets:
log.info('Subnet {0} exists.'.format(subnet_name or subnet_id))
return {'exists': True}
else:
log.info('Subnet {0} does not exist.'.format(subnet_name or subnet_id))
return {'exists': False}
def get_subnet_association(subnets, region=None, key=None, keyid=None,
@ -2456,7 +2472,8 @@ def describe_route_table(route_table_id=None, route_table_name=None,
'''
salt.utils.warn_until('Oxygen',
salt.utils.warn_until(
'Neon',
'The \'describe_route_table\' method has been deprecated and '
'replaced by \'describe_route_tables\'.'
)

View File

@ -396,10 +396,8 @@ def _run(cmd,
msg = 'missing salt/utils/win_runas.py'
raise CommandExecutionError(msg)
if not isinstance(cmd, list):
cmd = salt.utils.shlex_split(cmd, posix=False)
cmd = ' '.join(cmd)
if isinstance(cmd, (list, tuple)):
cmd = ' '.join(cmd)
return win_runas(cmd, runas, password, cwd)
@ -536,11 +534,11 @@ def _run(cmd,
.format(cwd)
)
if python_shell is not True and not isinstance(cmd, list):
posix = True
if salt.utils.is_windows():
posix = False
cmd = salt.utils.shlex_split(cmd, posix=posix)
if python_shell is not True \
and not salt.utils.is_windows() \
and not isinstance(cmd, list):
cmd = salt.utils.shlex_split(cmd)
if not use_vt:
# This is where the magic happens
try:

View File

@ -1388,7 +1388,7 @@ def _parse_settings_eth(opts, iface_type, enabled, iface):
for opt in ['up_cmds', 'pre_up_cmds', 'post_up_cmds',
'down_cmds', 'pre_down_cmds', 'post_down_cmds']:
if opt in opts:
iface_data['inet'][opt] = opts[opt]
iface_data[def_addrfam][opt] = opts[opt]
for addrfam in ['inet', 'inet6']:
if 'addrfam' in iface_data[addrfam] and iface_data[addrfam]['addrfam'] == addrfam:
@ -2027,19 +2027,12 @@ def build_network_settings(**settings):
# Write settings
_write_file_network(network, _DEB_NETWORKING_FILE, True)
# Write hostname to /etc/hostname
# Get hostname and domain from opts
sline = opts['hostname'].split('.', 1)
opts['hostname'] = sline[0]
hostname = '{0}\n' . format(opts['hostname'])
current_domainname = current_network_settings['domainname']
current_searchdomain = current_network_settings['searchdomain']
# Only write the hostname if it has changed
if not opts['hostname'] == current_network_settings['hostname']:
if not ('test' in settings and settings['test']):
# TODO replace wiht a call to network.mod_hostname instead
_write_file_network(hostname, _DEB_HOSTNAME_FILE)
new_domain = False
if len(sline) > 1:
new_domainname = sline[1]

View File

@ -232,6 +232,7 @@ except ImportError:
# pylint: enable=import-error
HAS_NSENTER = bool(salt.utils.which('nsenter'))
HUB_PREFIX = 'docker.io/'
# Set up logging
log = logging.getLogger(__name__)
@ -909,8 +910,8 @@ def compare_container(first, second, ignore=None):
ret.setdefault(conf_dict, {})[item] = {'old': image1, 'new': image2}
else:
if item == 'Links':
val1 = _scrub_links(val1, first)
val2 = _scrub_links(val2, second)
val1 = sorted(_scrub_links(val1, first))
val2 = sorted(_scrub_links(val2, second))
if val1 != val2:
ret.setdefault(conf_dict, {})[item] = {'old': val1, 'new': val2}
# Check for optionally-present items that were in the second container
@ -932,8 +933,8 @@ def compare_container(first, second, ignore=None):
ret.setdefault(conf_dict, {})[item] = {'old': image1, 'new': image2}
else:
if item == 'Links':
val1 = _scrub_links(val1, first)
val2 = _scrub_links(val2, second)
val1 = sorted(_scrub_links(val1, first))
val2 = sorted(_scrub_links(val2, second))
if val1 != val2:
ret.setdefault(conf_dict, {})[item] = {'old': val1, 'new': val2}
return ret
@ -1486,6 +1487,43 @@ def list_tags():
return sorted(ret)
def resolve_tag(name, tags=None):
'''
.. versionadded:: 2017.7.2,Oxygen
Given an image tag, check the locally-pulled tags (using
:py:func:`docker.list_tags <salt.modules.dockermod.list_tags>`) and return
the matching tag. This helps disambiguate differences on some platforms
where images from the Docker Hub are prefixed with ``docker.io/``. If an
image name with no tag is passed, a tag of ``latest`` is assumed.
If the specified image is not pulled locally, this function will return
``False``.
tags
An optional Python list of tags to check against. If passed, then
:py:func:`docker.list_tags <salt.modules.dockermod.list_tags>` will not
be run to get a list of tags. This is useful when resolving a number of
tags at the same time.
CLI Examples:
.. code-block:: bash
salt myminion docker.resolve_tag busybox
salt myminion docker.resolve_tag busybox:latest
'''
tag_name = ':'.join(salt.utils.docker.get_repo_tag(name))
if tags is None:
tags = list_tags()
if tag_name in tags:
return tag_name
full_name = HUB_PREFIX + tag_name
if not name.startswith(HUB_PREFIX) and full_name in tags:
return full_name
return False
def logs(name):
'''
Returns the logs for the container. Equivalent to running the ``docker

View File

@ -54,7 +54,8 @@ import salt.utils.files
import salt.utils.locales
import salt.utils.templates
import salt.utils.url
from salt.exceptions import CommandExecutionError, MinionError, SaltInvocationError, get_error_message as _get_error_message
from salt.exceptions import CommandExecutionError, SaltInvocationError, get_error_message as _get_error_message
from salt.utils.files import HASHES, HASHES_REVMAP
log = logging.getLogger(__name__)
@ -62,16 +63,6 @@ __func_alias__ = {
'makedirs_': 'makedirs'
}
HASHES = {
'sha512': 128,
'sha384': 96,
'sha256': 64,
'sha224': 56,
'sha1': 40,
'md5': 32,
}
HASHES_REVMAP = dict([(y, x) for x, y in six.iteritems(HASHES)])
def __virtual__():
'''
@ -2188,14 +2179,14 @@ def replace(path,
if not_found_content is None:
not_found_content = repl
if prepend_if_not_found:
new_file.insert(0, not_found_content + b'\n')
new_file.insert(0, not_found_content + salt.utils.to_bytes(os.linesep))
else:
# append_if_not_found
# Make sure we have a newline at the end of the file
if 0 != len(new_file):
if not new_file[-1].endswith(b'\n'):
new_file[-1] += b'\n'
new_file.append(not_found_content + b'\n')
if not new_file[-1].endswith(salt.utils.to_bytes(os.linesep)):
new_file[-1] += salt.utils.to_bytes(os.linesep)
new_file.append(not_found_content + salt.utils.to_bytes(os.linesep))
has_changes = True
if not dry_run:
try:
@ -2206,9 +2197,9 @@ def replace(path,
raise CommandExecutionError("Exception: {0}".format(exc))
# write new content in the file while avoiding partial reads
try:
fh_ = salt.utils.atomicfile.atomic_open(path, 'w')
fh_ = salt.utils.atomicfile.atomic_open(path, 'wb')
for line in new_file:
fh_.write(salt.utils.to_str(line))
fh_.write(salt.utils.to_bytes(line))
finally:
fh_.close()
@ -2378,9 +2369,10 @@ def blockreplace(path,
try:
fi_file = fileinput.input(path,
inplace=False, backup=False,
bufsize=1, mode='r')
bufsize=1, mode='rb')
for line in fi_file:
line = salt.utils.to_str(line)
result = line
if marker_start in line:
@ -2393,14 +2385,24 @@ def blockreplace(path,
# end of block detected
in_block = False
# Check for multi-line '\n' terminated content as split will
# introduce an unwanted additional new line.
if content and content[-1] == '\n':
content = content[:-1]
# Handle situations where there may be multiple types
# of line endings in the same file. Separate the content
# into lines. Account for Windows-style line endings
# using os.linesep, then by linux-style line endings
# using '\n'
split_content = []
for linesep_line in content.split(os.linesep):
for content_line in linesep_line.split('\n'):
split_content.append(content_line)
# Trim any trailing new lines to avoid unwanted
# additional new lines
while not split_content[-1]:
split_content.pop()
# push new block content in file
for cline in content.split('\n'):
new_file.append(cline + '\n')
for content_line in split_content:
new_file.append(content_line + os.linesep)
done = True
@ -2428,25 +2430,25 @@ def blockreplace(path,
if not done:
if prepend_if_not_found:
# add the markers and content at the beginning of file
new_file.insert(0, marker_end + '\n')
new_file.insert(0, marker_end + os.linesep)
if append_newline is True:
new_file.insert(0, content + '\n')
new_file.insert(0, content + os.linesep)
else:
new_file.insert(0, content)
new_file.insert(0, marker_start + '\n')
new_file.insert(0, marker_start + os.linesep)
done = True
elif append_if_not_found:
# Make sure we have a newline at the end of the file
if 0 != len(new_file):
if not new_file[-1].endswith('\n'):
new_file[-1] += '\n'
if not new_file[-1].endswith(os.linesep):
new_file[-1] += os.linesep
# add the markers and content at the end of file
new_file.append(marker_start + '\n')
new_file.append(marker_start + os.linesep)
if append_newline is True:
new_file.append(content + '\n')
new_file.append(content + os.linesep)
else:
new_file.append(content)
new_file.append(marker_end + '\n')
new_file.append(marker_end + os.linesep)
done = True
else:
raise CommandExecutionError(
@ -2477,9 +2479,9 @@ def blockreplace(path,
# write new content in the file while avoiding partial reads
try:
fh_ = salt.utils.atomicfile.atomic_open(path, 'w')
fh_ = salt.utils.atomicfile.atomic_open(path, 'wb')
for line in new_file:
fh_.write(line)
fh_.write(salt.utils.to_bytes(line))
finally:
fh_.close()
@ -3618,6 +3620,14 @@ def source_list(source, source_hash, saltenv):
single_src = next(iter(single))
single_hash = single[single_src] if single[single_src] else source_hash
urlparsed_single_src = _urlparse(single_src)
# Fix this for Windows
if salt.utils.is_windows():
# urlparse doesn't handle a local Windows path without the
# protocol indicator (file://). The scheme will be the
# drive letter instead of the protocol. So, we'll add the
# protocol and re-parse
if urlparsed_single_src.scheme.lower() in string.ascii_lowercase:
urlparsed_single_src = _urlparse('file://' + single_src)
proto = urlparsed_single_src.scheme
if proto == 'salt':
path, senv = salt.utils.url.parse(single_src)
@ -3627,18 +3637,17 @@ def source_list(source, source_hash, saltenv):
ret = (single_src, single_hash)
break
elif proto.startswith('http') or proto == 'ftp':
try:
if __salt__['cp.cache_file'](single_src):
ret = (single_src, single_hash)
break
except MinionError as exc:
# Error downloading file. Log the caught exception and
# continue on to the next source.
log.exception(exc)
elif proto == 'file' and os.path.exists(urlparsed_single_src.path):
ret = (single_src, single_hash)
break
elif single_src.startswith('/') and os.path.exists(single_src):
elif proto == 'file' and (
os.path.exists(urlparsed_single_src.netloc) or
os.path.exists(urlparsed_single_src.path) or
os.path.exists(os.path.join(
urlparsed_single_src.netloc,
urlparsed_single_src.path))):
ret = (single_src, single_hash)
break
elif single_src.startswith(os.sep) and os.path.exists(single_src):
ret = (single_src, single_hash)
break
elif isinstance(single, six.string_types):
@ -3649,15 +3658,26 @@ def source_list(source, source_hash, saltenv):
ret = (single, source_hash)
break
urlparsed_src = _urlparse(single)
if salt.utils.is_windows():
# urlparse doesn't handle a local Windows path without the
# protocol indicator (file://). The scheme will be the
# drive letter instead of the protocol. So, we'll add the
# protocol and re-parse
if urlparsed_src.scheme.lower() in string.ascii_lowercase:
urlparsed_src = _urlparse('file://' + single)
proto = urlparsed_src.scheme
if proto == 'file' and os.path.exists(urlparsed_src.path):
if proto == 'file' and (
os.path.exists(urlparsed_src.netloc) or
os.path.exists(urlparsed_src.path) or
os.path.exists(os.path.join(
urlparsed_src.netloc,
urlparsed_src.path))):
ret = (single, source_hash)
break
elif proto.startswith('http') or proto == 'ftp':
if __salt__['cp.cache_file'](single):
ret = (single, source_hash)
break
elif single.startswith('/') and os.path.exists(single):
ret = (single, source_hash)
break
elif single.startswith(os.sep) and os.path.exists(single):
ret = (single, source_hash)
break
if ret is None:
@ -4478,7 +4498,7 @@ def check_file_meta(
'''
changes = {}
if not source_sum:
source_sum = dict()
source_sum = {}
lstats = stats(name, hash_type=source_sum.get('hash_type', None), follow_symlinks=False)
if not lstats:
changes['newfile'] = name

View File

@ -17,10 +17,10 @@ except ImportError:
from pipes import quote as _cmd_quote
# Import salt libs
import salt.utils
import salt.utils.yast
import salt.utils.preseed
import salt.utils.kickstart
import salt.utils.validate.path
import salt.syspaths
from salt.exceptions import SaltInvocationError
@ -403,6 +403,11 @@ def _bootstrap_deb(
log.error('Required tool debootstrap is not installed.')
return False
if static_qemu and not salt.utils.validate.path.is_executable(static_qemu):
log.error('Required tool qemu not '
'present/readable at: {0}'.format(static_qemu))
return False
if isinstance(pkgs, (list, tuple)):
pkgs = ','.join(pkgs)
if isinstance(exclude_pkgs, (list, tuple)):
@ -427,11 +432,13 @@ def _bootstrap_deb(
__salt__['cmd.run'](deb_args, python_shell=False)
__salt__['cmd.run'](
'cp {qemu} {root}/usr/bin/'.format(
qemu=_cmd_quote(static_qemu), root=_cmd_quote(root)
if static_qemu:
__salt__['cmd.run'](
'cp {qemu} {root}/usr/bin/'.format(
qemu=_cmd_quote(static_qemu), root=_cmd_quote(root)
)
)
)
env = {'DEBIAN_FRONTEND': 'noninteractive',
'DEBCONF_NONINTERACTIVE_SEEN': 'true',
'LC_ALL': 'C',

View File

@ -9,6 +9,7 @@ import copy
import logging
import os
import re
import stat
# Import salt libs
import salt.utils
@ -115,6 +116,22 @@ def _expand_path(cwd, user):
return os.path.join(os.path.expanduser(to_expand), str(cwd))
def _path_is_executable_others(path):
'''
Check every part of path for executable permission
'''
prevpath = None
while path and path != prevpath:
try:
if not os.stat(path).st_mode & stat.S_IXOTH:
return False
except OSError:
return False
prevpath = path
path, _ = os.path.split(path)
return True
def _format_opts(opts):
'''
Common code to inspect opts and split them if necessary
@ -214,11 +231,12 @@ def _git_run(command, cwd=None, user=None, password=None, identity=None,
}
# copy wrapper to area accessible by ``runas`` user
# currently no suppport in windows for wrapping git ssh
# currently no support in windows for wrapping git ssh
ssh_id_wrapper = os.path.join(
salt.utils.templates.TEMPLATE_DIRNAME,
'git/ssh-id-wrapper'
)
tmp_ssh_wrapper = None
if salt.utils.is_windows():
for suffix in ('', ' (x86)'):
ssh_exe = (
@ -235,12 +253,14 @@ def _git_run(command, cwd=None, user=None, password=None, identity=None,
# Use the windows batch file instead of the bourne shell script
ssh_id_wrapper += '.bat'
env['GIT_SSH'] = ssh_id_wrapper
elif not user or _path_is_executable_others(ssh_id_wrapper):
env['GIT_SSH'] = ssh_id_wrapper
else:
tmp_file = salt.utils.files.mkstemp()
salt.utils.files.copyfile(ssh_id_wrapper, tmp_file)
os.chmod(tmp_file, 0o500)
os.chown(tmp_file, __salt__['file.user_to_uid'](user), -1)
env['GIT_SSH'] = tmp_file
tmp_ssh_wrapper = salt.utils.files.mkstemp()
salt.utils.files.copyfile(ssh_id_wrapper, tmp_ssh_wrapper)
os.chmod(tmp_ssh_wrapper, 0o500)
os.chown(tmp_ssh_wrapper, __salt__['file.user_to_uid'](user), -1)
env['GIT_SSH'] = tmp_ssh_wrapper
if 'salt-call' not in _salt_cli \
and __salt__['ssh.key_is_encrypted'](id_file):
@ -270,13 +290,25 @@ def _git_run(command, cwd=None, user=None, password=None, identity=None,
redirect_stderr=redirect_stderr,
**kwargs)
finally:
if not salt.utils.is_windows() and 'GIT_SSH' in env:
os.remove(env['GIT_SSH'])
# Cleanup the temporary ssh wrapper file
try:
__salt__['file.remove'](tmp_ssh_wrapper)
log.debug('Removed ssh wrapper file %s', tmp_ssh_wrapper)
except AttributeError:
# No wrapper was used
pass
except (SaltInvocationError, CommandExecutionError) as exc:
log.warning('Failed to remove ssh wrapper file %s: %s', tmp_ssh_wrapper, exc)
# Cleanup the temporary identity file
if tmp_identity_file and os.path.exists(tmp_identity_file):
log.debug('Removing identity file {0}'.format(tmp_identity_file))
try:
__salt__['file.remove'](tmp_identity_file)
log.debug('Removed identity file %s', tmp_identity_file)
except AttributeError:
# No identify file was used
pass
except (SaltInvocationError, CommandExecutionError) as exc:
log.warning('Failed to remove identity file %s: %s', tmp_identity_file, exc)
# If the command was successful, no need to try additional IDs
if result['retcode'] == 0:

View File

@ -118,7 +118,7 @@ def get(key, default='', delimiter=DEFAULT_TARGET_DELIM, ordered=True):
def has_value(key):
'''
Determine whether a named value exists in the grains dictionary.
Determine whether a key exists in the grains dictionary.
Given a grains dictionary that contains the following structure::
@ -134,7 +134,10 @@ def has_value(key):
salt '*' grains.has_value pkg:apache
'''
return True if salt.utils.traverse_dict_and_list(__grains__, key, False) else False
return salt.utils.traverse_dict_and_list(
__grains__,
key,
KeyError) is not KeyError
def items(sanitize=False):

View File

@ -31,7 +31,7 @@ def __virtual__():
if __grains__['kernel'] in ('Linux', 'OpenBSD', 'NetBSD'):
return __virtualname__
return (False, 'The groupadd execution module cannot be loaded: '
' only available on Linux, OpenBSD and NetBSD')
' only available on Linux, OpenBSD and NetBSD')
def add(name, gid=None, system=False, root=None):
@ -44,12 +44,12 @@ def add(name, gid=None, system=False, root=None):
salt '*' group.add foo 3456
'''
cmd = 'groupadd '
cmd = ['groupadd']
if gid:
cmd += '-g {0} '.format(gid)
cmd.append('-g {0}'.format(gid))
if system and __grains__['kernel'] != 'OpenBSD':
cmd += '-r '
cmd += name
cmd.append('-r')
cmd.append(name)
if root is not None:
cmd.extend(('-R', root))
@ -69,7 +69,7 @@ def delete(name, root=None):
salt '*' group.delete foo
'''
cmd = ('groupdel', name)
cmd = ['groupdel', name]
if root is not None:
cmd.extend(('-R', root))
@ -140,7 +140,7 @@ def chgid(name, gid, root=None):
pre_gid = __salt__['file.group_to_gid'](name)
if gid == pre_gid:
return True
cmd = ('groupmod', '-g', gid, name)
cmd = ['groupmod', '-g', gid, name]
if root is not None:
cmd.extend(('-R', root))
@ -170,15 +170,15 @@ def adduser(name, username, root=None):
if __grains__['kernel'] == 'Linux':
if on_redhat_5:
cmd = ('gpasswd', '-a', username, name)
cmd = ['gpasswd', '-a', username, name]
elif on_suse_11:
cmd = ('usermod', '-A', name, username)
cmd = ['usermod', '-A', name, username]
else:
cmd = ('gpasswd', '--add', username, name)
cmd = ['gpasswd', '--add', username, name]
if root is not None:
cmd.extend(('-Q', root))
else:
cmd = ('usermod', '-G', name, username)
cmd = ['usermod', '-G', name, username]
if root is not None:
cmd.extend(('-R', root))
@ -208,20 +208,20 @@ def deluser(name, username, root=None):
if username in grp_info['members']:
if __grains__['kernel'] == 'Linux':
if on_redhat_5:
cmd = ('gpasswd', '-d', username, name)
cmd = ['gpasswd', '-d', username, name]
elif on_suse_11:
cmd = ('usermod', '-R', name, username)
cmd = ['usermod', '-R', name, username]
else:
cmd = ('gpasswd', '--del', username, name)
cmd = ['gpasswd', '--del', username, name]
if root is not None:
cmd.extend(('-R', root))
retcode = __salt__['cmd.retcode'](cmd, python_shell=False)
elif __grains__['kernel'] == 'OpenBSD':
out = __salt__['cmd.run_stdout']('id -Gn {0}'.format(username),
python_shell=False)
cmd = 'usermod -S '
cmd += ','.join([g for g in out.split() if g != str(name)])
cmd += ' {0}'.format(username)
cmd = ['usermod', '-S']
cmd.append(','.join([g for g in out.split() if g != str(name)]))
cmd.append('{0}'.format(username))
retcode = __salt__['cmd.retcode'](cmd, python_shell=False)
else:
log.error('group.deluser is not yet supported on this platform')
@ -249,13 +249,13 @@ def members(name, members_list, root=None):
if __grains__['kernel'] == 'Linux':
if on_redhat_5:
cmd = ('gpasswd', '-M', members_list, name)
cmd = ['gpasswd', '-M', members_list, name]
elif on_suse_11:
for old_member in __salt__['group.info'](name).get('members'):
__salt__['cmd.run']('groupmod -R {0} {1}'.format(old_member, name), python_shell=False)
cmd = ('groupmod', '-A', members_list, name)
cmd = ['groupmod', '-A', members_list, name]
else:
cmd = ('gpasswd', '--members', members_list, name)
cmd = ['gpasswd', '--members', members_list, name]
if root is not None:
cmd.extend(('-R', root))
retcode = __salt__['cmd.retcode'](cmd, python_shell=False)
@ -270,7 +270,7 @@ def members(name, members_list, root=None):
for user in members_list.split(","):
if user:
retcode = __salt__['cmd.retcode'](
'usermod -G {0} {1}'.format(name, user),
['usermod', '-G', name, user],
python_shell=False)
if not retcode == 0:
break

View File

@ -102,8 +102,6 @@ def _construct_yaml_str(self, node):
Construct for yaml
'''
return self.construct_scalar(node)
YamlLoader.add_constructor(u'tag:yaml.org,2002:str',
_construct_yaml_str)
YamlLoader.add_constructor(u'tag:yaml.org,2002:timestamp',
_construct_yaml_str)

View File

@ -318,17 +318,18 @@ class _Section(OrderedDict):
yield '{0}[{1}]{0}'.format(os.linesep, self.name)
sections_dict = OrderedDict()
for name, value in six.iteritems(self):
# Handle Comment Lines
if com_regx.match(name):
yield '{0}{1}'.format(value, os.linesep)
# Handle Sections
elif isinstance(value, _Section):
sections_dict.update({name: value})
# Key / Value pairs
# Adds spaces between the separator
else:
yield '{0}{1}{2}{3}'.format(
name,
(
' {0} '.format(self.sep) if self.sep != ' '
else self.sep
),
' {0} '.format(self.sep) if self.sep != ' ' else self.sep,
value,
os.linesep
)
@ -372,10 +373,11 @@ class _Ini(_Section):
with salt.utils.fopen(self.name) as rfh:
inicontents = rfh.read()
except (OSError, IOError) as exc:
raise CommandExecutionError(
"Unable to open file '{0}'. "
"Exception: {1}".format(self.name, exc)
)
if __opts__['test'] is False:
raise CommandExecutionError(
"Unable to open file '{0}'. "
"Exception: {1}".format(self.name, exc)
)
if not inicontents:
return
# Remove anything left behind from a previous run.

View File

@ -1455,6 +1455,8 @@ def _parser():
add_arg('--or-mark', dest='or-mark', action='append')
add_arg('--xor-mark', dest='xor-mark', action='append')
add_arg('--set-mark', dest='set-mark', action='append')
add_arg('--nfmask', dest='nfmask', action='append')
add_arg('--ctmask', dest='ctmask', action='append')
## CONNSECMARK
add_arg('--save', dest='save', action='append')
add_arg('--restore', dest='restore', action='append')

View File

@ -123,7 +123,16 @@ def available():
salt '*' kmod.available
'''
ret = []
mod_dir = os.path.join('/lib/modules/', os.uname()[2])
built_in_file = os.path.join(mod_dir, 'modules.builtin')
if os.path.exists(built_in_file):
with salt.utils.fopen(built_in_file, 'r') as f:
for line in f:
# Strip .ko from the basename
ret.append(os.path.basename(line)[:-4])
for root, dirs, files in os.walk(mod_dir):
for fn_ in files:
if '.ko' in fn_:

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