mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
Merge remote-tracking branch 'upstream/2015.2' into merge-forward-develop
Conflicts: doc/ref/index.rst doc/topics/eauth/index.rst salt/beacons/__init__.py salt/beacons/service.py salt/loader.py salt/minion.py salt/output/nested.py
This commit is contained in:
commit
124ad51c40
46 changed files with 2957 additions and 845 deletions
37
conf/master
37
conf/master
|
@ -1,9 +1,10 @@
|
|||
##### Primary configuration settings #####
|
||||
##########################################
|
||||
# This configuration file is used to manage the behavior of the Salt Master.
|
||||
# Values that are commented out but have no space after the comment are
|
||||
# defaults that need not be set in the config. If there is a space after the
|
||||
# comment that the value is presented as an example and is not the default.
|
||||
# Values that are commented out but have an empty line after the comment are
|
||||
# defaults that do not need to be set in the config. If there is no blank line
|
||||
# after the comment then the value is presented as an example and is not the
|
||||
# default.
|
||||
|
||||
# Per default, the master will automatically include all config files
|
||||
# from master.d/*.conf (master.d is a directory in the same directory
|
||||
|
@ -237,7 +238,7 @@
|
|||
# larry:
|
||||
# - test.ping
|
||||
# - network.*
|
||||
|
||||
#
|
||||
# Blacklist any of the following users or modules
|
||||
#
|
||||
# This example would blacklist all non sudo users, including root from
|
||||
|
@ -262,7 +263,7 @@
|
|||
# pam:
|
||||
# fred:
|
||||
# - test.*
|
||||
|
||||
#
|
||||
# Time (in seconds) for a newly generated token to live. Default: 12 hours
|
||||
#token_expire: 43200
|
||||
|
||||
|
@ -387,7 +388,7 @@
|
|||
# prod:
|
||||
# - /srv/salt/prod/services
|
||||
# - /srv/salt/prod/states
|
||||
|
||||
#
|
||||
#file_roots:
|
||||
# base:
|
||||
# - /srv/salt
|
||||
|
@ -492,8 +493,8 @@
|
|||
# within the repository. The path is defined relative to the root of the
|
||||
# repository and defaults to the repository root.
|
||||
#gitfs_root: somefolder/otherfolder
|
||||
|
||||
|
||||
#
|
||||
#
|
||||
##### Pillar settings #####
|
||||
##########################################
|
||||
# Salt Pillars allow for the building of global data that can be made selectively
|
||||
|
@ -526,13 +527,23 @@
|
|||
# master config file that can then be used on minions.
|
||||
#pillar_opts: False
|
||||
|
||||
# The pillar_safe_render_error option prevents the master from passing piller
|
||||
# The pillar_safe_render_error option prevents the master from passing piller
|
||||
# render errors to the minion. This is set on by default because the error could
|
||||
# contain templating data which would give that minion information it shouldn't
|
||||
# have, like a password! When set true the error message will only show:
|
||||
# Rendering SLS 'my.sls' failed. Please see master log for details.
|
||||
#pillar_safe_render_error: True
|
||||
|
||||
# The pillar_source_merging_strategy option allows you to configure merging strategy
|
||||
# between different sources. It accepts four values: recurse, aggregate, overwrite,
|
||||
# or smart. Recurse will merge recursively mapping of data. Aggregate instructs
|
||||
# aggregation of elements between sources that use the #!yamlex renderer. Overwrite
|
||||
# will verwrite elements according the order in which they are processed. This is
|
||||
# behavior of the 2014.1 branch and earlier. Smart guesses the best strategy based
|
||||
# on the "renderer" setting and is the default value.
|
||||
#pillar_source_merging_strategy: smart
|
||||
|
||||
|
||||
##### Syndic settings #####
|
||||
##########################################
|
||||
# The Salt syndic is used to pass commands through a master from a higher
|
||||
|
@ -599,8 +610,8 @@
|
|||
#peer_run:
|
||||
# foo.example.com:
|
||||
# - manage.up
|
||||
|
||||
|
||||
#
|
||||
#
|
||||
##### Mine settings #####
|
||||
##########################################
|
||||
# Restrict mine.get access from minions. By default any minion has a full access
|
||||
|
@ -688,10 +699,10 @@
|
|||
##############################################
|
||||
# Location of the repo on the master:
|
||||
#win_repo: '/srv/salt/win/repo'
|
||||
|
||||
#
|
||||
# Location of the master's repo cache file:
|
||||
#win_repo_mastercachefile: '/srv/salt/win/repo/winrepo.p'
|
||||
|
||||
#
|
||||
# List of git repositories to include with the local repo:
|
||||
#win_gitrepos:
|
||||
# - 'https://github.com/saltstack/salt-winrepo.git'
|
||||
|
|
28
conf/minion
28
conf/minion
|
@ -1,10 +1,10 @@
|
|||
##### Primary configuration settings #####
|
||||
##########################################
|
||||
##########################################
|
||||
# This configuration file is used to manage the behavior of the Salt Minion.
|
||||
# With the exception of the location of the Salt Master Server, values that
|
||||
# are commented out but have no space after the comment are defaults that need
|
||||
# not be set in the config. If there is a space after the comment that the value
|
||||
# is presented as an example and is not the default.
|
||||
# With the exception of the location of the Salt Master Server, values that are
|
||||
# commented out but have an empty line after the comment are defaults that need
|
||||
# not be set in the config. If there is no blank line after the comment, the
|
||||
# value is presented as an example and is not the default.
|
||||
|
||||
# Per default the minion will automatically include all config files
|
||||
# from minion.d/*.conf (minion.d is a directory in the same directory
|
||||
|
@ -68,7 +68,7 @@
|
|||
# deployment: datacenter4
|
||||
# cabinet: 13
|
||||
# cab_u: 14-15
|
||||
|
||||
#
|
||||
# Where cache data goes.
|
||||
#cachedir: /var/cache/salt/minion
|
||||
|
||||
|
@ -215,7 +215,8 @@
|
|||
# recon_default: 100
|
||||
# recon_max: 5000
|
||||
# recon_randomize: False
|
||||
|
||||
#
|
||||
#
|
||||
# The loop_interval sets how long in seconds the minion will wait between
|
||||
# evaluating the scheduler and running cleanup tasks. This defaults to a
|
||||
# sane 60 seconds, but if the minion scheduler needs to be evaluated more
|
||||
|
@ -276,8 +277,9 @@
|
|||
#include:
|
||||
# - /etc/salt/extra_config
|
||||
# - /etc/roles/webserver
|
||||
|
||||
|
||||
#
|
||||
#
|
||||
#
|
||||
##### Minion module management #####
|
||||
##########################################
|
||||
# Disable specific modules. This allows the admin to limit the level of
|
||||
|
@ -427,8 +429,8 @@
|
|||
#pillar_roots:
|
||||
# base:
|
||||
# - /srv/pillar
|
||||
|
||||
|
||||
#
|
||||
#
|
||||
###### Security settings #####
|
||||
###########################################
|
||||
# Enable "open mode", this mode still maintains encryption, but turns off
|
||||
|
@ -561,8 +563,8 @@
|
|||
#
|
||||
# A dict for the test module:
|
||||
#test.baz: {spam: sausage, cheese: bread}
|
||||
|
||||
|
||||
#
|
||||
#
|
||||
###### Update settings ######
|
||||
###########################################
|
||||
# Using the features in Esky, a salt minion can both run as a frozen app and
|
||||
|
|
2385
doc/man/salt.7
2385
doc/man/salt.7
File diff suppressed because it is too large
Load diff
|
@ -1856,7 +1856,7 @@ Default: ``False``
|
|||
Default: ``smart``
|
||||
|
||||
The pillar_source_merging_strategy option allows you to configure merging
|
||||
strategy between different sources. It accepts 3 values:
|
||||
strategy between different sources. It accepts 4 values:
|
||||
|
||||
* recurse:
|
||||
|
||||
|
@ -1922,37 +1922,37 @@ strategy between different sources. It accepts 3 values:
|
|||
|
||||
* overwrite:
|
||||
|
||||
Will use the behaviour of the 2014.1 branch and earlier.
|
||||
Will use the behaviour of the 2014.1 branch and earlier.
|
||||
|
||||
Overwrites elements according the order in which they are processed.
|
||||
Overwrites elements according the order in which they are processed.
|
||||
|
||||
First pillar processed:
|
||||
First pillar processed:
|
||||
|
||||
.. code-block:: yaml
|
||||
.. code-block:: yaml
|
||||
|
||||
A:
|
||||
first_key: blah
|
||||
second_key: blah
|
||||
A:
|
||||
first_key: blah
|
||||
second_key: blah
|
||||
|
||||
Second pillar processed:
|
||||
Second pillar processed:
|
||||
|
||||
.. code-block:: yaml
|
||||
.. code-block:: yaml
|
||||
|
||||
A:
|
||||
third_key: blah
|
||||
fourth_key: blah
|
||||
A:
|
||||
third_key: blah
|
||||
fourth_key: blah
|
||||
|
||||
will be merged as:
|
||||
will be merged as:
|
||||
|
||||
.. code-block:: yaml
|
||||
.. code-block:: yaml
|
||||
|
||||
A:
|
||||
third_key: blah
|
||||
fourth_key: blah
|
||||
A:
|
||||
third_key: blah
|
||||
fourth_key: blah
|
||||
|
||||
* smart (default):
|
||||
|
||||
Guesses the best strategy based on the "renderer" setting.
|
||||
Guesses the best strategy based on the "renderer" setting.
|
||||
|
||||
|
||||
Syndic Server Settings
|
||||
|
|
|
@ -32,3 +32,4 @@ Reference
|
|||
wheel/all/index
|
||||
beacons/all/index
|
||||
engines/all/index
|
||||
sdb/all/index
|
||||
|
|
|
@ -28,6 +28,7 @@ Full list of runner modules
|
|||
pagerduty
|
||||
pillar
|
||||
queue
|
||||
sdb
|
||||
search
|
||||
state
|
||||
survey
|
||||
|
|
6
doc/ref/runners/all/salt.runners.sdb.rst
Normal file
6
doc/ref/runners/all/salt.runners.sdb.rst
Normal file
|
@ -0,0 +1,6 @@
|
|||
================
|
||||
salt.runners.sdb
|
||||
================
|
||||
|
||||
.. automodule:: salt.runners.sdb
|
||||
:members:
|
16
doc/ref/sdb/all/index.rst
Normal file
16
doc/ref/sdb/all/index.rst
Normal file
|
@ -0,0 +1,16 @@
|
|||
.. _all-salt.sdb:
|
||||
|
||||
================================
|
||||
Full list of builtin sdb modules
|
||||
================================
|
||||
|
||||
.. currentmodule:: salt.sdb
|
||||
|
||||
.. autosummary::
|
||||
:toctree:
|
||||
:template: autosummary.rst.tmpl
|
||||
|
||||
etcd_db
|
||||
keyring_db
|
||||
memcached
|
||||
sqlite3
|
6
doc/ref/sdb/all/salt.sdb.etcd_db.rst
Normal file
6
doc/ref/sdb/all/salt.sdb.etcd_db.rst
Normal file
|
@ -0,0 +1,6 @@
|
|||
================
|
||||
salt.sdb.etcd_db
|
||||
================
|
||||
|
||||
.. automodule:: salt.sdb.etcd_db
|
||||
:members:
|
6
doc/ref/sdb/all/salt.sdb.keyring_db.rst
Normal file
6
doc/ref/sdb/all/salt.sdb.keyring_db.rst
Normal file
|
@ -0,0 +1,6 @@
|
|||
===================
|
||||
salt.sdb.keyring_db
|
||||
===================
|
||||
|
||||
.. automodule:: salt.sdb.keyring_db
|
||||
:members:
|
6
doc/ref/sdb/all/salt.sdb.memcached.rst
Normal file
6
doc/ref/sdb/all/salt.sdb.memcached.rst
Normal file
|
@ -0,0 +1,6 @@
|
|||
==================
|
||||
salt.sdb.memcached
|
||||
==================
|
||||
|
||||
.. automodule:: salt.sdb.memcached
|
||||
:members:
|
6
doc/ref/sdb/all/salt.sdb.sqlite3.rst
Normal file
6
doc/ref/sdb/all/salt.sdb.sqlite3.rst
Normal file
|
@ -0,0 +1,6 @@
|
|||
================
|
||||
salt.sdb.sqlite3
|
||||
================
|
||||
|
||||
.. automodule:: salt.sdb.sqlite3
|
||||
:members:
|
|
@ -103,17 +103,19 @@ User authentication does not need to be entered again until the token expires.
|
|||
Token expiration time can be set in the Salt master config file.
|
||||
|
||||
|
||||
LDAP
|
||||
----
|
||||
LDAP and Active Directory
|
||||
-------------------------
|
||||
|
||||
.. note::
|
||||
|
||||
LDAP usage requires that you have installed python-ldap.
|
||||
|
||||
Salt supports both user and group authentication for LDAP.
|
||||
Salt supports both user and group authentication for LDAP (and Active Directory
|
||||
accessed via its LDAP interface)
|
||||
|
||||
LDAP configuration happens in the Salt master configuration file.
|
||||
|
||||
Server configuration values:
|
||||
Server configuration values and their defaults:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
@ -121,6 +123,17 @@ Server configuration values:
|
|||
auth.ldap.port: 389
|
||||
auth.ldap.tls: False
|
||||
auth.ldap.scope: 2
|
||||
auth.ldap.uri: ''
|
||||
auth.ldap.tls: False
|
||||
auth.ldap.no_verify: False
|
||||
auth.ldap.anonymous: False
|
||||
auth.ldap.groupou: 'Groups'
|
||||
auth.ldap.groupclass: 'posixGroup'
|
||||
auth.ldap.accountattributename: 'memberUid'
|
||||
|
||||
# These are only for Active Directory
|
||||
auth.ldap.activedirectory: False
|
||||
auth.ldap.persontype: 'person'
|
||||
|
||||
Salt also needs to know which Base DN to search for users and groups and
|
||||
the DN to bind to:
|
||||
|
@ -136,21 +149,55 @@ To bind to a DN, a password is required
|
|||
|
||||
auth.ldap.bindpw: mypassword
|
||||
|
||||
Salt uses a filter to find the DN associated with a user. Salt substitutes
|
||||
the ``{{ username }}`` value for the username when querying LDAP.
|
||||
Salt uses a filter to find the DN associated with a user. Salt
|
||||
substitutes the ``{{ username }}`` value for the username when querying LDAP
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
auth.ldap.filter: uid={{ username }}
|
||||
|
||||
If group support for LDAP is desired, one can specify an OU that contains group
|
||||
data. This is prepended to the basedn to create a search path
|
||||
For OpenLDAP, to determine group membership, one can specify an OU that contains
|
||||
group data. This is prepended to the basedn to create a search path. Then
|
||||
the results are filtered against ``auth.ldap.groupclass``, default
|
||||
``posixGroup``, and the account's 'name' attribute, ``memberUid`` by default.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
auth.ldap.groupou: Groups
|
||||
|
||||
Once configured, LDAP permissions can be assigned to users and groups.
|
||||
Active Directory handles group membership differently, and does not utilize the
|
||||
``groupou`` configuration variable. AD needs the following options in
|
||||
the master config:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
auth.ldap.activedirectory: True
|
||||
auth.ldap.filter: sAMAccountName={{username}}
|
||||
auth.ldap.accountattributename: sAMAccountName
|
||||
auth.ldap.groupclass: group
|
||||
auth.ldap.persontype: person
|
||||
|
||||
To determine group membership in AD, the username and password that is entered
|
||||
when LDAP is requested as the eAuth mechanism on the command line is used to
|
||||
bind to AD's LDAP interface. If this fails, then it doesn't matter what groups
|
||||
the user belongs to, he or she is denied access. Next, the distinguishedName
|
||||
of the user is looked up with the following LDAP search:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
(&(<value of auth.ldap.accountattributename>={{username}})
|
||||
(objectClass=<value of auth.ldap.persontype>)
|
||||
)
|
||||
|
||||
This should return a distinguishedName that we can use to filter for group
|
||||
membership. Then the following LDAP quey is executed:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
(&(member=<distinguishedName from search above>)
|
||||
(objectClass=<value of auth.ldap.groupclass>)
|
||||
)
|
||||
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
|
140
doc/topics/releases/2014.7.3.rst
Normal file
140
doc/topics/releases/2014.7.3.rst
Normal file
|
@ -0,0 +1,140 @@
|
|||
===========================
|
||||
Salt 2014.7.3 Release Notes
|
||||
===========================
|
||||
|
||||
:release: TBA
|
||||
|
||||
Version 2014.7.3 is a bugfix release for :doc:`2014.7.0
|
||||
</topics/releases/2014.7.0>`.
|
||||
|
||||
Changes:
|
||||
|
||||
- Multi-master minions mode no longer route fileclient operations asymetrically.
|
||||
This fixes the source of many multi-master bugs where the minion would
|
||||
become unrepsonsive from one or more masters.
|
||||
|
||||
- Fix bug wherein network.iface could produce stack traces.
|
||||
|
||||
- net.arp will no longer be made available unless arp is installed on the
|
||||
system.
|
||||
|
||||
- Major performance improvements to Saltnado
|
||||
|
||||
- Allow KVM module to operate under KVM itself or VMWare Fusion
|
||||
|
||||
- Various fixes to the Windows installation scripts
|
||||
|
||||
- Fix issue where the syndic would not correctly propogate loads to the master
|
||||
job cache.
|
||||
|
||||
- Improve error handling on invalid /etc/network/interfaces file in salt
|
||||
networking modules
|
||||
|
||||
- Fix bug where a reponse status was not checked for in fileclient.get_url
|
||||
|
||||
- Enable eauth when running salt in batch mode
|
||||
|
||||
- Increase timeout in Boto Route53 module
|
||||
|
||||
- Fix bugs with Salt's 'tar' module option parsing
|
||||
|
||||
- Fix parsing of NTP servers on Windows
|
||||
|
||||
- Fix issue with blockdev tuning not reporting changes correctly
|
||||
|
||||
- Update to the latest Salt bootstrap script
|
||||
|
||||
- Update Linode salt-cloud driver to use either linode-python or
|
||||
apache-libcloud
|
||||
|
||||
- Fix for s3.query function to return correct headers
|
||||
|
||||
- Fix for s3.head returning None for files that exist
|
||||
|
||||
- Fix the disable function in win_service module so that the service is
|
||||
disabled correctly
|
||||
|
||||
- Fix race condition between master and minion when making a directory when
|
||||
both daemons are on the same host
|
||||
|
||||
- Fix an issue where file.recurse would fail at the root of an svn repo
|
||||
when the repo has a mountpoint
|
||||
|
||||
- Fix an issue where file.recurse would fail at the root of an hgfs repo
|
||||
when the repo has a mountpoint
|
||||
|
||||
- Fix an issue where file.recurse would fail at the root of an gitfs repo
|
||||
when the repo has a mountpoint
|
||||
|
||||
- Add status.master capability for Windows.
|
||||
|
||||
- Various fixes to ssh_known_hosts
|
||||
|
||||
- Various fixes to states.network bonding for Debian
|
||||
|
||||
- The debian_ip.get_interfaces module no longer removes nameservers.
|
||||
|
||||
- Better integration between grains.virtual and systemd-detect-virt and
|
||||
virt-what
|
||||
|
||||
- Fix traceback in sysctl.present state output
|
||||
|
||||
- Fix for issue where mount.mounted would fail when superopts were not a part
|
||||
of mount.active (extended=True). Also mount.mounted various fixes for Solaris
|
||||
and FreeBSD.
|
||||
|
||||
- Fix error where datetimes were not correctly safeguarded before being passed
|
||||
into msgpack.
|
||||
|
||||
- Fix file.replace regressions. If the pattern is not found, and if dry run is False,
|
||||
and if `backup` is False, and if a pre-existing file exists with extension `.bak`,
|
||||
then that backup file will be overwritten. This backup behavior is a result of how `fileinput`
|
||||
works. Fixing it requires either passing through the file twice (the
|
||||
first time only to search for content and set a flag), or rewriting
|
||||
`file.replace` so it doesn't use `fileinput`
|
||||
|
||||
- VCS filreserver fixes/optimizations
|
||||
|
||||
- Catch fileserver configuration errors on master start
|
||||
|
||||
- Raise errors on invalid gitfs configurations
|
||||
|
||||
- set_locale when locale file does not exist (Redhat family)
|
||||
|
||||
- Fix to correctly count active devices when created mdadm array with spares
|
||||
|
||||
- Fix to correctly target minions in batch mode
|
||||
|
||||
- Support ssh:// urls using the gitfs dulwhich backend
|
||||
|
||||
- New fileserver runner
|
||||
|
||||
- Fix various bugs with argument parsing to the publish module.
|
||||
|
||||
- Fix disk.usage for Synology OS
|
||||
|
||||
- Fix issue with tags occurring twice with docker.pulled
|
||||
|
||||
- Fix incorrect key error in SMTP returner
|
||||
|
||||
- Fix condition which would remount loopback filesystems on every state run
|
||||
|
||||
- Remove requsites from listens after they are called in the state system
|
||||
|
||||
- Make system implementation of service.running aware of legacy service calls
|
||||
|
||||
- Fix issue where publish.publish would not handle duplicate responses gracefully.
|
||||
|
||||
- Accept Kali Linux for aptpkg salt execution module
|
||||
|
||||
- Fix bug where cmd.which could not handle a dirname as an argument
|
||||
|
||||
- Fix issue in ps.pgrep where exceptions were thrown on Windows.
|
||||
|
||||
|
||||
Known issues:
|
||||
|
||||
- In multimaster mode, a minion may become temporarily unresponsive
|
||||
if modules or pillars are refreshed at the same time that one
|
||||
or more masters are down. This can be worked around by setting
|
||||
'auth_timeout' and 'auth_tries' down to shorter periods.
|
140
doc/topics/releases/2014.7.4.rst
Normal file
140
doc/topics/releases/2014.7.4.rst
Normal file
|
@ -0,0 +1,140 @@
|
|||
===========================
|
||||
Salt 2014.7.4 Release Notes
|
||||
===========================
|
||||
|
||||
:release: TBA
|
||||
|
||||
Version 2014.7.4 is a bugfix release for :doc:`2014.7.0
|
||||
</topics/releases/2014.7.0>`.
|
||||
|
||||
Changes:
|
||||
|
||||
- Multi-master minions mode no longer route fileclient operations asymetrically.
|
||||
This fixes the source of many multi-master bugs where the minion would
|
||||
become unrepsonsive from one or more masters.
|
||||
|
||||
- Fix bug wherein network.iface could produce stack traces.
|
||||
|
||||
- net.arp will no longer be made available unless arp is installed on the
|
||||
system.
|
||||
|
||||
- Major performance improvements to Saltnado
|
||||
|
||||
- Allow KVM module to operate under KVM itself or VMWare Fusion
|
||||
|
||||
- Various fixes to the Windows installation scripts
|
||||
|
||||
- Fix issue where the syndic would not correctly propogate loads to the master
|
||||
job cache.
|
||||
|
||||
- Improve error handling on invalid /etc/network/interfaces file in salt
|
||||
networking modules
|
||||
|
||||
- Fix bug where a reponse status was not checked for in fileclient.get_url
|
||||
|
||||
- Enable eauth when running salt in batch mode
|
||||
|
||||
- Increase timeout in Boto Route53 module
|
||||
|
||||
- Fix bugs with Salt's 'tar' module option parsing
|
||||
|
||||
- Fix parsing of NTP servers on Windows
|
||||
|
||||
- Fix issue with blockdev tuning not reporting changes correctly
|
||||
|
||||
- Update to the latest Salt bootstrap script
|
||||
|
||||
- Update Linode salt-cloud driver to use either linode-python or
|
||||
apache-libcloud
|
||||
|
||||
- Fix for s3.query function to return correct headers
|
||||
|
||||
- Fix for s3.head returning None for files that exist
|
||||
|
||||
- Fix the disable function in win_service module so that the service is
|
||||
disabled correctly
|
||||
|
||||
- Fix race condition between master and minion when making a directory when
|
||||
both daemons are on the same host
|
||||
|
||||
- Fix an issue where file.recurse would fail at the root of an svn repo
|
||||
when the repo has a mountpoint
|
||||
|
||||
- Fix an issue where file.recurse would fail at the root of an hgfs repo
|
||||
when the repo has a mountpoint
|
||||
|
||||
- Fix an issue where file.recurse would fail at the root of an gitfs repo
|
||||
when the repo has a mountpoint
|
||||
|
||||
- Add status.master capability for Windows.
|
||||
|
||||
- Various fixes to ssh_known_hosts
|
||||
|
||||
- Various fixes to states.network bonding for Debian
|
||||
|
||||
- The debian_ip.get_interfaces module no longer removes nameservers.
|
||||
|
||||
- Better integration between grains.virtual and systemd-detect-virt and
|
||||
virt-what
|
||||
|
||||
- Fix traceback in sysctl.present state output
|
||||
|
||||
- Fix for issue where mount.mounted would fail when superopts were not a part
|
||||
of mount.active (extended=True). Also mount.mounted various fixes for Solaris
|
||||
and FreeBSD.
|
||||
|
||||
- Fix error where datetimes were not correctly safeguarded before being passed
|
||||
into msgpack.
|
||||
|
||||
- Fix file.replace regressions. If the pattern is not found, and if dry run is False,
|
||||
and if `backup` is False, and if a pre-existing file exists with extension `.bak`,
|
||||
then that backup file will be overwritten. This backup behavior is a result of how `fileinput`
|
||||
works. Fixing it requires either passing through the file twice (the
|
||||
first time only to search for content and set a flag), or rewriting
|
||||
`file.replace` so it doesn't use `fileinput`
|
||||
|
||||
- VCS filreserver fixes/optimizations
|
||||
|
||||
- Catch fileserver configuration errors on master start
|
||||
|
||||
- Raise errors on invalid gitfs configurations
|
||||
|
||||
- set_locale when locale file does not exist (Redhat family)
|
||||
|
||||
- Fix to correctly count active devices when created mdadm array with spares
|
||||
|
||||
- Fix to correctly target minions in batch mode
|
||||
|
||||
- Support ssh:// urls using the gitfs dulwhich backend
|
||||
|
||||
- New fileserver runner
|
||||
|
||||
- Fix various bugs with argument parsing to the publish module.
|
||||
|
||||
- Fix disk.usage for Synology OS
|
||||
|
||||
- Fix issue with tags occurring twice with docker.pulled
|
||||
|
||||
- Fix incorrect key error in SMTP returner
|
||||
|
||||
- Fix condition which would remount loopback filesystems on every state run
|
||||
|
||||
- Remove requsites from listens after they are called in the state system
|
||||
|
||||
- Make system implementation of service.running aware of legacy service calls
|
||||
|
||||
- Fix issue where publish.publish would not handle duplicate responses gracefully.
|
||||
|
||||
- Accept Kali Linux for aptpkg salt execution module
|
||||
|
||||
- Fix bug where cmd.which could not handle a dirname as an argument
|
||||
|
||||
- Fix issue in ps.pgrep where exceptions were thrown on Windows.
|
||||
|
||||
|
||||
Known issues:
|
||||
|
||||
- In multimaster mode, a minion may become temporarily unresponsive
|
||||
if modules or pillars are refreshed at the same time that one
|
||||
or more masters are down. This can be worked around by setting
|
||||
'auth_timeout' and 'auth_tries' down to shorter periods.
|
|
@ -2,67 +2,167 @@
|
|||
Salt 2015.2.0 Release Notes - Codename Lithium
|
||||
==============================================
|
||||
|
||||
The 2015.2.0 feature release of Salt was focused on hardening Salt and mostly
|
||||
on improving existing systems. A few major additions were made, primarily the
|
||||
Beacon system. But most enhancements have been focused around improving
|
||||
existing features and interfaces.
|
||||
|
||||
As usual the release notes are not exhaustive and primarily include the most
|
||||
notable additions and improvements. Hundreds of bugs have been fixed and many
|
||||
modules have been substantially updated and added.
|
||||
|
||||
Beacons
|
||||
=======
|
||||
|
||||
The beacon system allows the minion to hook into system processes and
|
||||
continually translate external events into the salt event bus. The
|
||||
primary example of this is the :py:mod:`~salt.beacons.inotify` beacon. This
|
||||
beacon uses inotify to watch configured files or directories on the minion for
|
||||
changes, creation, deletion etc.
|
||||
continually translate external events into the salt event bus. The primary
|
||||
example of this is the :py:mod:`~salt.beacons.inotify` beacon. This beacon uses
|
||||
inotify to watch configured files or directories on the minion for changes,
|
||||
creation, deletion etc.
|
||||
|
||||
This allows for the changes to be sent up to the master where the
|
||||
reactor can respond to changes.
|
||||
This allows for the changes to be sent up to the master where the reactor can
|
||||
respond to changes.
|
||||
|
||||
Sudo Minion Settings
|
||||
====================
|
||||
|
||||
The new ability to run the minion as a non-root user but add the ability for
|
||||
the minion to execute commands via sudo has been added, simply add `sudo_user:
|
||||
root` to the minion config, run the minion as a non-root user and grant that
|
||||
user sudo rights to execute salt-call.
|
||||
|
||||
Lazy Loader
|
||||
========
|
||||
===========
|
||||
|
||||
The Lazy Loader is a significant overhaul of Salt's module loader system. The
|
||||
Lazy Loader will lazily load modules on access, instead of all on start. In
|
||||
addition to major performance improvement this "sandboxes" modules-- meaning a
|
||||
bad/broken import of a single module will only effect jobs that require accessing
|
||||
the broken module. (:pull: `20274`)
|
||||
bad/broken import of a single module will only effect jobs that require
|
||||
accessing the broken module. (:pull: `20274`)
|
||||
|
||||
Enhanced Active Directory Support
|
||||
=================================
|
||||
|
||||
The eauth system for LDAP has been extended to support Microsoft Active
|
||||
Directory out of the box. This includes Active Directory and LDAP group support
|
||||
for eauth.
|
||||
|
||||
Salt LXC Enhancements
|
||||
=====================
|
||||
|
||||
The LXC systems have been overhauled to be more consistent and to fix many
|
||||
bugs.
|
||||
|
||||
This overhaul makes using LXC with Salt much easier and substantially improves
|
||||
the underlying capabilities of Salt's LXC integration.
|
||||
|
||||
Salt SSH
|
||||
========
|
||||
|
||||
- Additional configuration options and command line flags have been added to
|
||||
configure the scan roster on the fly
|
||||
|
||||
- Added support for ``state.single`` in ``salt-ssh``
|
||||
|
||||
- Added support for ``publish.publish``, ``publish.full_data``, and
|
||||
``publish.runner`` in ``salt-ssh``
|
||||
|
||||
- Added support for ``mine.get`` in ``salt-ssh``
|
||||
|
||||
New Windows Installer
|
||||
=====================
|
||||
|
||||
The new Windows installer for Salt changes how salt is installed on Windows.
|
||||
The old installer used bbfreeze to create an isolated python environment to
|
||||
execute in, this made adding modules and python libraries difficult. The new
|
||||
installer sets up a more flexible python environment making it easy to manage
|
||||
the python install and add python modules.
|
||||
|
||||
Removed Requests Dependency
|
||||
===========================
|
||||
|
||||
The hard dependency on the requests library has been removed. Requests is still
|
||||
required by a number of cloud modules but is no longer required for normal Salt
|
||||
operations.
|
||||
|
||||
This removal fixes issues that were introduced with requests and salt-ssh, as
|
||||
well as issues users experienced from the many different packaging methods used
|
||||
by requests package maintainers
|
||||
|
||||
Python 3 Updates
|
||||
================
|
||||
|
||||
While Salt does not YET run on python 3 it has been updated to INSTALL on
|
||||
python 3, making us one step closer. What remains is getting the test suite to
|
||||
the point where it can run on python 3 so that we can verify compatibility.
|
||||
|
||||
RAET Additions
|
||||
==============
|
||||
|
||||
The RAET support continues to improve, RAET now supports multi master and many
|
||||
bugs and performance issues have been fixed. RAET is much closer to being a
|
||||
first class citizen.
|
||||
|
||||
Modified File Detection
|
||||
=======================
|
||||
|
||||
A number of functions have been added to the RPM-based package managers to
|
||||
detect and diff files that are modified from the original package installs.
|
||||
This can be found in the new pkg.modified functions.
|
||||
|
||||
Reactor Update
|
||||
==============
|
||||
|
||||
Fix the infinite recursion problem for runner/wheel reactor jobs by passing a
|
||||
"user" (Reactor) to all jobs that the reactor starts. Then the reactor skips
|
||||
all events created by that username-- thereby only reacting to events not
|
||||
caused by itself. Because of this, runner and wheel executions from the runner
|
||||
will have user "Reactor" in the job cache.
|
||||
|
||||
Misc Fixes/Additions
|
||||
====================
|
||||
|
||||
- SDB driver for etcd. (:issue: `22043`)
|
||||
|
||||
- Add ``only_upgrade`` argument to apt-based ``pkg.install`` to only install a
|
||||
package version if the package is already installed. (Great for security
|
||||
updates!)
|
||||
|
||||
- Joyent now requires a ``keyname`` to be specified in the provider
|
||||
configuration. This change was necessitated upstream by the 7.0+ API.
|
||||
|
||||
- Add ``args`` argument to ``cmd.script_retcode`` to match ``cmd.script`` in
|
||||
the :py:mod:`cmd module <salt.cmd.cmdmod>`. (:issue:`21122`)
|
||||
the :py:mod:`cmd module <salt.cmd.cmdmod>`. (:issue: `21122`)
|
||||
|
||||
- Fixed bug where TCP keepalive was not being sent on the defined interval on
|
||||
the return port (4506) from minion to master. (:issue: `21465`)
|
||||
|
||||
- LocalClient may now optionally raise SaltClientError exceptions. If using
|
||||
this class directly, checking for and handling this exception is recommended.
|
||||
(:issue: `21501`)
|
||||
- The SAuth object is now a singleton, meaning authentication state is
|
||||
global (per master) on each minion. This reduces sign-ins of minions from 3->1
|
||||
per startup.
|
||||
|
||||
- The SAuth object is now a singleton, meaning authentication state is global
|
||||
(per master) on each minion. This reduces sign-ins of minions from 3->1 per
|
||||
startup.
|
||||
|
||||
- Nested outputter has been optimized, it is now much faster.
|
||||
|
||||
- Extensive fileserver backend updates.
|
||||
|
||||
Deprecations
|
||||
============
|
||||
|
||||
- Removed ``parameter`` keyword argument from ``eselect.exec_action`` execution
|
||||
module.
|
||||
|
||||
- Removed ``runas`` parameter from the following ``pip``` execution module
|
||||
functions: ``install``, ``uninstall``, ``freeze``, ``list_``, ``list_upgrades``,
|
||||
``upgrade_available``, ``upgrade``. Please migrate to ``user``.
|
||||
functions: ``install``, ``uninstall``, ``freeze``, ``list_``,
|
||||
``list_upgrades``, ``upgrade_available``, ``upgrade``. Please migrate to
|
||||
``user``.
|
||||
|
||||
- Removed ``runas`` parameter from the following ``pip`` state module
|
||||
functions: ``installed``, ``removed``, ``uptodate`` . Please migrate to ``user``.
|
||||
functions: ``installed``, ``removed``, ``uptodate`` . Please migrate to
|
||||
``user``.
|
||||
|
||||
- Removed ``quiet`` option from all functions in ``cmdmod`` execution module.
|
||||
Please use ``output_loglevel=quiet`` instead.
|
||||
|
@ -79,9 +179,9 @@ Deprecations
|
|||
``ALTER TABLE salt_events ADD master_id VARCHAR(255) NOT NULL;``
|
||||
|
||||
Known Issues
|
||||
===========
|
||||
============
|
||||
|
||||
- In multimaster mode, a minion may become temporarily unresponsive
|
||||
if modules or pillars are refreshed at the same time that one
|
||||
or more masters are down. This can be worked around by setting
|
||||
'auth_timeout' and 'auth_tries' down to shorter periods.
|
||||
- In multimaster mode, a minion may become temporarily unresponsive if modules
|
||||
or pillars are refreshed at the same time that one or more masters are down.
|
||||
This can be worked around by setting 'auth_timeout' and 'auth_tries' down to
|
||||
shorter periods.
|
||||
|
|
|
@ -32,6 +32,8 @@ xcopy /S /E "%PyDir%" "%BinDir%\"
|
|||
@ echo -------------------------------------------
|
||||
:: Remove all Compiled Python files (.pyc)
|
||||
del /S /Q "%BinDir%\*.pyc"
|
||||
:: Remove all Compiled HTML Help (.chm)
|
||||
del /S /Q "%BinDir%\*.chm"
|
||||
|
||||
:: Delete Unused Docs and Modules
|
||||
If Exist "%BinDir%\Doc" rd /S /Q "%BinDir%\Doc"
|
||||
|
|
|
@ -12,7 +12,10 @@
|
|||
!include "nsDialogs.nsh"
|
||||
!include "LogicLib.nsh"
|
||||
!include "FileFunc.nsh"
|
||||
!include "StrFunc.nsh"
|
||||
!include "x64.nsh"
|
||||
${StrLoc}
|
||||
${StrStrAdv}
|
||||
|
||||
!if "$%PROCESSOR_ARCHITECTURE%" == "AMD64"
|
||||
!define CPUARCH "AMD64"
|
||||
|
@ -54,6 +57,14 @@ Page custom nsDialogsPage nsDialogsPageLeave
|
|||
; Language files
|
||||
!insertmacro MUI_LANGUAGE "English"
|
||||
|
||||
; Part of the Trim function for Strings
|
||||
!define Trim "!insertmacro Trim"
|
||||
!macro Trim ResultVar String
|
||||
Push "${String}"
|
||||
Call Trim
|
||||
Pop "${ResultVar}"
|
||||
!macroend
|
||||
|
||||
; MUI end ------
|
||||
|
||||
Function nsDialogsPage
|
||||
|
@ -217,25 +228,118 @@ Function un.onInit
|
|||
FunctionEnd
|
||||
|
||||
Function .onInit
|
||||
Push $R0
|
||||
Push $R1
|
||||
Push $R2
|
||||
${GetParameters} $R0
|
||||
${GetOptions} $R0 "/master=" $R1
|
||||
${GetOptions} $R0 "/minion-name=" $R2
|
||||
${If} $R1 == ""
|
||||
StrCpy $MasterHost_State "salt"
|
||||
${Else}
|
||||
StrCpy $MasterHost_State $R1
|
||||
${EndIf}
|
||||
${If} $R2 == ""
|
||||
StrCpy $MinionName_State "hostname"
|
||||
${Else}
|
||||
StrCpy $MinionName_State $R2
|
||||
${EndIf}
|
||||
Pop $R2
|
||||
Pop $R1
|
||||
Pop $R0
|
||||
|
||||
IfFileExists "$INSTDIR\conf\minion" confFound confNotFound
|
||||
|
||||
confFound:
|
||||
FileOpen $0 "$INSTDIR\conf\minion" r
|
||||
|
||||
confLoop:
|
||||
FileRead $0 $1
|
||||
IfErrors EndOfFile
|
||||
${StrLoc} $2 $1 "master:" ">"
|
||||
${If} $2 == 0
|
||||
${StrStrAdv} $2 $1 "master: " ">" ">" "0" "0" "0"
|
||||
${Trim} $2 $2
|
||||
StrCpy $MasterHost_State $2
|
||||
${EndIf}
|
||||
|
||||
${StrLoc} $2 $1 "id:" ">"
|
||||
${If} $2 == 0
|
||||
${StrStrAdv} $2 $1 "id: " ">" ">" "0" "0" "0"
|
||||
${Trim} $2 $2
|
||||
StrCpy $MinionName_State $2
|
||||
${EndIf}
|
||||
|
||||
Goto confLoop
|
||||
|
||||
EndOfFile:
|
||||
FileClose $0
|
||||
|
||||
confNotFound:
|
||||
Push $R0
|
||||
Push $R1
|
||||
Push $R2
|
||||
${GetParameters} $R0
|
||||
${GetOptions} $R0 "/master=" $R1
|
||||
${GetOptions} $R0 "/minion-name=" $R2
|
||||
${IfNot} $R1 == ""
|
||||
StrCpy $MasterHost_State $R1
|
||||
${ElseIf} $MasterHost_State == ""
|
||||
StrCpy $MasterHost_State "salt"
|
||||
${EndIf}
|
||||
${IfNot} $R2 == ""
|
||||
StrCpy $MinionName_State $R2
|
||||
${ElseIf} $MinionName_State == ""
|
||||
StrCpy $MinionName_State "hostname"
|
||||
${EndIf}
|
||||
Pop $R2
|
||||
Pop $R1
|
||||
Pop $R0
|
||||
|
||||
; Remove previous version of salt, but don't remove conf and key
|
||||
ExecWait "net stop salt-minion"
|
||||
ExecWait "sc delete salt-minion"
|
||||
|
||||
; Delete everything except conf and var
|
||||
ClearErrors
|
||||
FindFirst $0 $1 $INSTDIR\*
|
||||
|
||||
loop:
|
||||
IfFileExists "$INSTDIR\$1\*.*" IsDir IsFile
|
||||
|
||||
IsDir:
|
||||
${IfNot} $1 == "."
|
||||
${AndIfNot} $1 == ".."
|
||||
${AndIfNot} $1 == "conf"
|
||||
${AndIfNot} $1 == "var"
|
||||
RMDir /r "$INSTDIR\$1"
|
||||
${EndIf}
|
||||
|
||||
IsFile:
|
||||
DELETE "$INSTDIR\$1"
|
||||
|
||||
FindNext $0 $1
|
||||
IfErrors done
|
||||
|
||||
Goto loop
|
||||
|
||||
done:
|
||||
FindClose $0
|
||||
|
||||
FunctionEnd
|
||||
|
||||
Function Trim
|
||||
|
||||
Exch $R1 ; Original string
|
||||
Push $R2
|
||||
|
||||
Loop:
|
||||
StrCpy $R2 "$R1" 1
|
||||
StrCmp "$R2" " " TrimLeft
|
||||
StrCmp "$R2" "$\r" TrimLeft
|
||||
StrCmp "$R2" "$\n" TrimLeft
|
||||
StrCmp "$R2" "$\t" TrimLeft
|
||||
GoTo Loop2
|
||||
TrimLeft:
|
||||
StrCpy $R1 "$R1" "" 1
|
||||
Goto Loop
|
||||
|
||||
Loop2:
|
||||
StrCpy $R2 "$R1" 1 -1
|
||||
StrCmp "$R2" " " TrimRight
|
||||
StrCmp "$R2" "$\r" TrimRight
|
||||
StrCmp "$R2" "$\n" TrimRight
|
||||
StrCmp "$R2" "$\t" TrimRight
|
||||
GoTo Done
|
||||
TrimRight:
|
||||
StrCpy $R1 "$R1" -1
|
||||
Goto Loop2
|
||||
|
||||
Done:
|
||||
Pop $R2
|
||||
Exch $R1
|
||||
|
||||
FunctionEnd
|
||||
|
||||
Section Uninstall
|
||||
|
|
|
@ -92,8 +92,8 @@ class LoadAuth(object):
|
|||
return self.auth[fstr](*fcall['args'], **fcall['kwargs'])
|
||||
else:
|
||||
return self.auth[fstr](*fcall['args'])
|
||||
except Exception:
|
||||
err = 'Authentication module threw an exception. Exception not logged.'
|
||||
except Exception as e:
|
||||
log.debug('Authentication module threw {0}'.format(e))
|
||||
return False
|
||||
|
||||
def time_auth(self, load):
|
||||
|
|
|
@ -32,7 +32,11 @@ __defopts__ = {'auth.ldap.uri': '',
|
|||
'auth.ldap.no_verify': False,
|
||||
'auth.ldap.anonymous': False,
|
||||
'auth.ldap.scope': 2,
|
||||
'auth.ldap.groupou': 'Groups'
|
||||
'auth.ldap.groupou': 'Groups',
|
||||
'auth.ldap.accountattributename': 'memberUid',
|
||||
'auth.ldap.persontype': 'person',
|
||||
'auth.ldap.groupclass': 'posixGroup',
|
||||
'auth.ldap.activedirectory': False,
|
||||
}
|
||||
|
||||
|
||||
|
@ -69,7 +73,7 @@ class _LDAPConnection(object):
|
|||
'''
|
||||
|
||||
def __init__(self, uri, server, port, tls, no_verify, binddn, bindpw,
|
||||
anonymous):
|
||||
anonymous, accountattributename, activedirectory=False):
|
||||
'''
|
||||
Bind to an LDAP directory using passed credentials.
|
||||
'''
|
||||
|
@ -117,8 +121,8 @@ def _bind(username, password):
|
|||
connargs = {}
|
||||
# config params (auth.ldap.*)
|
||||
params = {
|
||||
'mandatory': ['uri', 'server', 'port', 'tls', 'no_verify', 'anonymous'],
|
||||
'additional': ['binddn', 'bindpw', 'filter'],
|
||||
'mandatory': ['uri', 'server', 'port', 'tls', 'no_verify', 'anonymous', 'accountattributename', 'activedirectory'],
|
||||
'additional': ['binddn', 'bindpw', 'filter', 'groupclass'],
|
||||
}
|
||||
|
||||
paramvalues = {}
|
||||
|
@ -172,8 +176,25 @@ def _bind(username, password):
|
|||
log.warn('Unable to find user {0}'.format(username))
|
||||
return False
|
||||
elif len(result) > 1:
|
||||
log.warn('Found multiple results for user {0}'.format(username))
|
||||
return False
|
||||
# Active Directory returns something odd. Though we do not
|
||||
# chase referrals (ldap.set_option(ldap.OPT_REFERRALS, 0) above)
|
||||
# it still appears to return several entries for other potential
|
||||
# sources for a match. All these sources have None for the
|
||||
# CN (ldap array return items are tuples: (cn, ldap entry))
|
||||
# But the actual CNs are at the front of the list.
|
||||
# So with some list comprehension magic, extract the first tuple
|
||||
# entry from all the results, create a list from those,
|
||||
# and count the ones that are not None. If that total is more than one
|
||||
# we need to error out because the ldap filter isn't narrow enough.
|
||||
cns = [tup[0] for tup in result]
|
||||
total_not_none = sum(1 for c in cns if c is not None)
|
||||
if total_not_none > 1:
|
||||
log.error('LDAP lookup found multiple results for user {0}'.format(username))
|
||||
return False
|
||||
elif total_not_none == 0:
|
||||
log.error('LDAP lookup--unable to find CN matching user {0}'.format(username))
|
||||
return False
|
||||
|
||||
connargs['binddn'] = result[0][0]
|
||||
if paramvalues['binddn'] and not paramvalues['bindpw']:
|
||||
connargs['binddn'] = paramvalues['binddn']
|
||||
|
@ -188,7 +209,7 @@ def _bind(username, password):
|
|||
ldap_conn = _LDAPConnection(**connargs).ldap
|
||||
except Exception:
|
||||
connargs.pop('bindpw', None) # Don't log the password
|
||||
log.warn('Failed to authenticate user dn via LDAP: {0}'.format(connargs))
|
||||
log.error('Failed to authenticate user dn via LDAP: {0}'.format(connargs))
|
||||
log.debug('Error authenticating user dn via LDAP:', exc_info=True)
|
||||
return False
|
||||
log.debug(
|
||||
|
@ -203,10 +224,12 @@ def auth(username, password):
|
|||
'''
|
||||
Simple LDAP auth
|
||||
'''
|
||||
|
||||
if _bind(username, password):
|
||||
log.debug('LDAP authentication successful')
|
||||
return True
|
||||
else:
|
||||
log.error('LDAP _bind authentication FAILED')
|
||||
return False
|
||||
|
||||
|
||||
|
@ -214,20 +237,64 @@ def groups(username, **kwargs):
|
|||
'''
|
||||
Authenticate against an LDAP group
|
||||
|
||||
Uses groupou and basedn specified in group to filter
|
||||
group search
|
||||
Behavior is highly dependent on if Active Directory is in use.
|
||||
|
||||
AD handles group membership very differently than OpenLDAP.
|
||||
See the :ref:`External Authentication <acl-eauth>` documentation for a thorough
|
||||
discussion of available parameters for customizing the search.
|
||||
|
||||
OpenLDAP allows you to search for all groups in the directory
|
||||
and returns members of those groups. Then we check against
|
||||
the username entered.
|
||||
|
||||
'''
|
||||
group_list = []
|
||||
|
||||
bind = _bind(username, kwargs['password'])
|
||||
if bind:
|
||||
search_results = bind.search_s('ou={0},{1}'.format(_config('groupou'), _config('basedn')),
|
||||
ldap.SCOPE_SUBTREE,
|
||||
'(&(memberUid={0})(objectClass=posixGroup))'.format(username),
|
||||
['memberUid', 'cn'])
|
||||
log.debug('ldap bind to determine group membership succeeded!')
|
||||
|
||||
if _config('activedirectory'):
|
||||
try:
|
||||
get_user_dn_search = '(&({0}={1})(objectClass={2}))'.format(_config('accountattributename'),
|
||||
username,
|
||||
_config('persontype'))
|
||||
user_dn_results = bind.search_s(_config('basedn'),
|
||||
ldap.SCOPE_SUBTREE,
|
||||
get_user_dn_search, ['distinguishedName'])
|
||||
except Exception as e:
|
||||
log.error('Exception thrown while looking up user DN in AD: {0}'.format(e))
|
||||
return group_list
|
||||
if not user_dn_results:
|
||||
log.error('Could not get distinguished name for user {0}'.format(username))
|
||||
return group_list
|
||||
# LDAP results are always tuples. First entry in the tuple is the DN
|
||||
dn = user_dn_results[0][0]
|
||||
ldap_search_string = '(&(member={0})(objectClass={1}))'.format(dn, _config('groupclass'))
|
||||
try:
|
||||
search_results = bind.search_s(_config('basedn'),
|
||||
ldap.SCOPE_SUBTREE,
|
||||
ldap_search_string,
|
||||
[_config('accountattributename'), 'cn'])
|
||||
except Exception as e:
|
||||
log.error('Exception thrown while retrieving group membership in AD: {0}'.format(e))
|
||||
return group_list
|
||||
for _, entry in search_results:
|
||||
if 'cn' in entry:
|
||||
group_list.append(entry['cn'][0])
|
||||
log.debug('User {0} is a member of groups: {1}'.format(username, group_list))
|
||||
else:
|
||||
search_results = bind.search_s('ou={0},{1}'.format(_config('groupou'), _config('basedn')),
|
||||
ldap.SCOPE_SUBTREE,
|
||||
'(&({0}={1})(objectClass={2}))'.format(_config('accountattributename'),
|
||||
username, _config('groupclass')),
|
||||
[_config('accountattributename'), 'cn'])
|
||||
for _, entry in search_results:
|
||||
if username in entry[_config('accountattributename')]:
|
||||
group_list.append(entry['cn'][0])
|
||||
log.debug('User {0} is a member of groups: {1}'.format(username, group_list))
|
||||
else:
|
||||
return False
|
||||
for _, entry in search_results:
|
||||
if username in entry['memberUid']:
|
||||
group_list.append(entry['cn'][0])
|
||||
log.debug('User {0} is a member of groups: {1}'.format(username, group_list))
|
||||
log.error('ldap bind to determine group membership FAILED!')
|
||||
return group_list
|
||||
|
||||
return group_list
|
||||
|
|
|
@ -139,8 +139,8 @@ class LocalClient(object):
|
|||
self.opts['transport'],
|
||||
opts=self.opts,
|
||||
listen=not self.opts.get('__worker', False))
|
||||
|
||||
self.returners = salt.loader.returners(self.opts, {})
|
||||
self.functions = salt.loader.minion_mods(self.opts)
|
||||
self.returners = salt.loader.returners(self.opts, self.functions)
|
||||
|
||||
def __read_master_key(self):
|
||||
'''
|
||||
|
|
|
@ -300,9 +300,13 @@ def _file_lists(load, form):
|
|||
rel_fn = rel_fn.replace('\\', '/')
|
||||
ret['files'].append(rel_fn)
|
||||
if save_cache:
|
||||
salt.fileserver.write_file_list_cache(
|
||||
__opts__, ret, list_cache, w_lock
|
||||
)
|
||||
try:
|
||||
salt.fileserver.write_file_list_cache(
|
||||
__opts__, ret, list_cache, w_lock
|
||||
)
|
||||
except NameError:
|
||||
# Catch msgpack error in salt-ssh
|
||||
pass
|
||||
return ret.get(form, [])
|
||||
# Shouldn't get here, but if we do, this prevents a TypeError
|
||||
return []
|
||||
|
|
|
@ -19,6 +19,7 @@ import re
|
|||
import platform
|
||||
import logging
|
||||
import locale
|
||||
import salt.exceptions
|
||||
|
||||
# Extend the default list of supported distros. This will be used for the
|
||||
# /etc/DISTRO-release checking that is part of platform.linux_distribution()
|
||||
|
@ -999,8 +1000,10 @@ def os_data():
|
|||
# pylint: enable=unpacking-non-sequence
|
||||
|
||||
if salt.utils.is_windows():
|
||||
grains['osrelease'] = grains['kernelrelease']
|
||||
grains['osversion'] = grains['kernelrelease'] = version
|
||||
with salt.utils.winapi.Com():
|
||||
wmi_c = wmi.WMI()
|
||||
grains['osrelease'] = grains['kernelrelease']
|
||||
grains['osversion'] = grains['kernelrelease'] = wmi_c.Win32_OperatingSystem()[0].Version
|
||||
grains['os'] = 'Windows'
|
||||
grains['os_family'] = 'Windows'
|
||||
grains.update(_memdata(grains))
|
||||
|
@ -1631,11 +1634,17 @@ def _dmidecode_data(regex_dict):
|
|||
return {}
|
||||
|
||||
# No use running if dmidecode/smbios isn't in the path
|
||||
if salt.utils.which('dmidecode'):
|
||||
out = __salt__['cmd.run']('dmidecode')
|
||||
elif salt.utils.which('smbios'):
|
||||
out = __salt__['cmd.run']('smbios')
|
||||
else:
|
||||
no_dmidecode = False
|
||||
try:
|
||||
if salt.utils.which('dmidecode'):
|
||||
out = __salt__['cmd.run']('dmidecode')
|
||||
elif salt.utils.which('smbios'):
|
||||
out = __salt__['cmd.run']('smbios')
|
||||
else:
|
||||
no_dmidecode = True
|
||||
except (salt.exceptions.CommandExecutionError,) as exc:
|
||||
no_dmidecode = True
|
||||
if no_dmidecode:
|
||||
log.debug(
|
||||
'The `dmidecode` binary is not available on the system. GPU '
|
||||
'grains will not be available.'
|
||||
|
|
|
@ -90,7 +90,14 @@ def _module_dirs(
|
|||
return cli_module_dirs + ext_type_types + [ext_types, sys_types]
|
||||
|
||||
|
||||
def minion_mods(opts, context=None, whitelist=None, include_errors=False, initial_load=False, notify=False):
|
||||
def minion_mods(
|
||||
opts,
|
||||
context=None,
|
||||
whitelist=None,
|
||||
include_errors=False,
|
||||
initial_load=False,
|
||||
loaded_base_name=None,
|
||||
notify=False):
|
||||
'''
|
||||
Load execution modules
|
||||
|
||||
|
@ -116,7 +123,8 @@ def minion_mods(opts, context=None, whitelist=None, include_errors=False, initia
|
|||
opts,
|
||||
tag='module',
|
||||
pack={'__context__': context},
|
||||
whitelist=whitelist)
|
||||
whitelist=whitelist,
|
||||
loaded_base_name=loaded_base_name)
|
||||
ret.pack['__salt__'] = ret
|
||||
if notify:
|
||||
evt = salt.utils.event.get_event('minion', opts=opts)
|
||||
|
@ -699,11 +707,11 @@ class LazyLoader(salt.utils.lazy.LazyDict):
|
|||
return '{0!r} is not available.'.format(function_name)
|
||||
else:
|
||||
if self.missing_modules.get(mod_name) is not None:
|
||||
return '{0!r}\' __virtual__ returned False: {1}'.format(mod_name, self.missing_modules[mod_name])
|
||||
return '\'{0}\' __virtual__ returned False: {1}'.format(mod_name, self.missing_modules[mod_name])
|
||||
elif self.missing_modules.get(mod_name) is None:
|
||||
return '{0!r}\' __virtual__ returned False'.format(mod_name)
|
||||
return '\'{0}\' __virtual__ returned False'.format(mod_name)
|
||||
else:
|
||||
return '{0!r} is not available.'.format(function_name)
|
||||
return '\'{0}\' is not available.'.format(function_name)
|
||||
|
||||
def refresh_file_mapping(self):
|
||||
'''
|
||||
|
|
|
@ -557,7 +557,11 @@ class MultiMinion(MinionBase):
|
|||
'last': time.time(),
|
||||
'auth_wait': s_opts['acceptance_wait_time']}
|
||||
try:
|
||||
minion = Minion(s_opts, self.MINION_CONNECT_TIMEOUT, False)
|
||||
minion = Minion(
|
||||
s_opts,
|
||||
self.MINION_CONNECT_TIMEOUT,
|
||||
False,
|
||||
'salt.loader.{0}'.format(master))
|
||||
ret[master]['minion'] = minion
|
||||
ret[master]['generator'] = minion.tune_in_no_block()
|
||||
except SaltClientError as exc:
|
||||
|
@ -648,12 +652,13 @@ class Minion(MinionBase):
|
|||
and loads all of the functions into the minion
|
||||
'''
|
||||
|
||||
def __init__(self, opts, timeout=60, safe=True): # pylint: disable=W0231
|
||||
def __init__(self, opts, timeout=60, safe=True, loaded_base_name=None): # pylint: disable=W0231
|
||||
'''
|
||||
Pass in the options dict
|
||||
'''
|
||||
self._running = None
|
||||
self.win_proc = []
|
||||
self.loaded_base_name = loaded_base_name
|
||||
|
||||
# Warn if ZMQ < 3.2
|
||||
if HAS_ZMQ:
|
||||
|
@ -932,7 +937,7 @@ class Minion(MinionBase):
|
|||
self.opts['grains'] = salt.loader.grains(self.opts, force_refresh)
|
||||
if self.opts.get('multimaster', False):
|
||||
s_opts = copy.deepcopy(self.opts)
|
||||
functions = salt.loader.minion_mods(s_opts, notify=notify)
|
||||
functions = salt.loader.minion_mods(s_opts, loaded_base_name=self.loaded_base_name, notify=notify)
|
||||
else:
|
||||
functions = salt.loader.minion_mods(self.opts, notify=notify)
|
||||
returners = salt.loader.returners(self.opts, functions)
|
||||
|
@ -1552,12 +1557,17 @@ class Minion(MinionBase):
|
|||
Refresh the pillar
|
||||
'''
|
||||
log.debug('Refreshing pillar')
|
||||
self.opts['pillar'] = salt.pillar.get_pillar(
|
||||
self.opts,
|
||||
self.opts['grains'],
|
||||
self.opts['id'],
|
||||
self.opts['environment'],
|
||||
).compile_pillar()
|
||||
try:
|
||||
self.opts['pillar'] = salt.pillar.get_pillar(
|
||||
self.opts,
|
||||
self.opts['grains'],
|
||||
self.opts['id'],
|
||||
self.opts['environment'],
|
||||
).compile_pillar()
|
||||
except SaltClientError:
|
||||
# Do not exit if a pillar refresh fails.
|
||||
log.error('Pillar data could not be refreshed. '
|
||||
'One or more masters may be down!')
|
||||
self.module_refresh(force_refresh)
|
||||
|
||||
def manage_schedule(self, package):
|
||||
|
|
|
@ -7,6 +7,7 @@ Execute chef in server or solo mode
|
|||
from __future__ import absolute_import
|
||||
import logging
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
# Import Salt libs
|
||||
import salt.utils
|
||||
|
@ -28,12 +29,19 @@ def __virtual__():
|
|||
|
||||
|
||||
def _default_logfile(exe_name):
|
||||
|
||||
'''
|
||||
Retrieve the logfile name
|
||||
'''
|
||||
if salt.utils.is_windows():
|
||||
logfile = salt.utils.path_join(
|
||||
os.environ['TMP'],
|
||||
'{0}.log'.format(exe_name)
|
||||
)
|
||||
tmp_dir = os.path.join(__opts__['cachedir'], 'tmp')
|
||||
if not os.path.isdir(tmp_dir):
|
||||
os.mkdir(tmp_dir)
|
||||
logfile_tmp = tempfile.NamedTemporaryFile(dir=tmp_dir,
|
||||
prefix=exe_name,
|
||||
suffix='.log',
|
||||
delete=False)
|
||||
logfile = logfile_tmp.name
|
||||
logfile_tmp.close()
|
||||
else:
|
||||
logfile = salt.utils.path_join(
|
||||
'/var/log',
|
||||
|
@ -46,7 +54,7 @@ def _default_logfile(exe_name):
|
|||
@decorators.which('chef-client')
|
||||
def client(whyrun=False,
|
||||
localmode=False,
|
||||
logfile=_default_logfile('chef-client'),
|
||||
logfile=None,
|
||||
**kwargs):
|
||||
'''
|
||||
Execute a chef client run and return a dict with the stderr, stdout,
|
||||
|
@ -115,6 +123,8 @@ def client(whyrun=False,
|
|||
Enable whyrun mode when set to True
|
||||
|
||||
'''
|
||||
if logfile is None:
|
||||
logfile = _default_logfile('chef-client'),
|
||||
args = ['chef-client',
|
||||
'--no-color',
|
||||
'--once',
|
||||
|
@ -132,7 +142,7 @@ def client(whyrun=False,
|
|||
|
||||
@decorators.which('chef-solo')
|
||||
def solo(whyrun=False,
|
||||
logfile=_default_logfile('chef-solo'),
|
||||
logfile=None,
|
||||
**kwargs):
|
||||
'''
|
||||
Execute a chef solo run and return a dict with the stderr, stdout,
|
||||
|
@ -182,6 +192,8 @@ def solo(whyrun=False,
|
|||
whyrun
|
||||
Enable whyrun mode when set to True
|
||||
'''
|
||||
if logfile is None:
|
||||
logfile = _default_logfile('chef-client'),
|
||||
args = ['chef-solo',
|
||||
'--no-color',
|
||||
'--logfile "{0}"'.format(logfile),
|
||||
|
|
|
@ -54,6 +54,23 @@ def __virtual__():
|
|||
return __virtualname__
|
||||
|
||||
|
||||
def _python_shell_default(python_shell, __pub_jid):
|
||||
'''
|
||||
Set python_shell default based on remote execution and __opts__['cmd_safe']
|
||||
'''
|
||||
try:
|
||||
# Default to python_shell=True when run directly from remote execution
|
||||
# system. Cross-module calls won't have a jid.
|
||||
if __pub_jid and python_shell is None:
|
||||
return True
|
||||
elif __opts__.get('cmd_safe', True) is False and python_shell is None:
|
||||
# Override-switch for python_shell
|
||||
return True
|
||||
except NameError:
|
||||
pass
|
||||
return python_shell
|
||||
|
||||
|
||||
def _chroot_pids(chroot):
|
||||
pids = []
|
||||
for root in glob.glob('/proc/[0-9]*/root'):
|
||||
|
@ -614,12 +631,8 @@ def run(cmd,
|
|||
|
||||
salt '*' cmd.run cmd='sed -e s/=/:/g'
|
||||
'''
|
||||
try:
|
||||
if __opts__.get('cmd_safe', True) is False and python_shell is None:
|
||||
# Override-switch for python_shell
|
||||
python_shell = True
|
||||
except NameError:
|
||||
pass
|
||||
python_shell = _python_shell_default(python_shell,
|
||||
kwargs.get('__pub_jid', ''))
|
||||
ret = _run(cmd,
|
||||
runas=runas,
|
||||
shell=shell,
|
||||
|
@ -808,12 +821,8 @@ def run_stdout(cmd,
|
|||
|
||||
salt '*' cmd.run_stdout "grep f" stdin='one\\ntwo\\nthree\\nfour\\nfive\\n'
|
||||
'''
|
||||
try:
|
||||
if __opts__.get('cmd_safe', True) is False and python_shell is None:
|
||||
# Override-switch for python_shell
|
||||
python_shell = True
|
||||
except NameError:
|
||||
pass
|
||||
python_shell = _python_shell_default(python_shell,
|
||||
kwargs.get('__pub_jid', ''))
|
||||
ret = _run(cmd,
|
||||
runas=runas,
|
||||
cwd=cwd,
|
||||
|
@ -896,12 +905,8 @@ def run_stderr(cmd,
|
|||
|
||||
salt '*' cmd.run_stderr "grep f" stdin='one\\ntwo\\nthree\\nfour\\nfive\\n'
|
||||
'''
|
||||
try:
|
||||
if __opts__.get('cmd_safe', True) is False and python_shell is None:
|
||||
# Override-switch for python_shell
|
||||
python_shell = True
|
||||
except NameError:
|
||||
pass
|
||||
python_shell = _python_shell_default(python_shell,
|
||||
kwargs.get('__pub_jid', ''))
|
||||
ret = _run(cmd,
|
||||
runas=runas,
|
||||
cwd=cwd,
|
||||
|
@ -984,12 +989,8 @@ def run_all(cmd,
|
|||
|
||||
salt '*' cmd.run_all "grep f" stdin='one\\ntwo\\nthree\\nfour\\nfive\\n'
|
||||
'''
|
||||
try:
|
||||
if __opts__.get('cmd_safe', True) is False and python_shell is None:
|
||||
# Override-switch for python_shell
|
||||
python_shell = True
|
||||
except NameError:
|
||||
pass
|
||||
python_shell = _python_shell_default(python_shell,
|
||||
kwargs.get('__pub_jid', ''))
|
||||
ret = _run(cmd,
|
||||
runas=runas,
|
||||
cwd=cwd,
|
||||
|
@ -1191,12 +1192,8 @@ def script(source,
|
|||
|
||||
salt '*' cmd.script salt://scripts/runme.sh stdin='one\\ntwo\\nthree\\nfour\\nfive\\n'
|
||||
'''
|
||||
try:
|
||||
if __opts__.get('cmd_safe', True) is False and python_shell is None:
|
||||
# Override-switch for python_shell
|
||||
python_shell = True
|
||||
except NameError:
|
||||
pass
|
||||
python_shell = _python_shell_default(python_shell,
|
||||
kwargs.get('__pub_jid', ''))
|
||||
|
||||
def _cleanup_tempfile(path):
|
||||
try:
|
||||
|
@ -1304,12 +1301,8 @@ def script_retcode(source,
|
|||
|
||||
salt '*' cmd.script_retcode salt://scripts/runme.sh stdin='one\\ntwo\\nthree\\nfour\\nfive\\n'
|
||||
'''
|
||||
try:
|
||||
if __opts__.get('cmd_safe', True) is False and python_shell is None:
|
||||
# Override-switch for python_shell
|
||||
python_shell = True
|
||||
except NameError:
|
||||
pass
|
||||
python_shell = _python_shell_default(python_shell,
|
||||
kwargs.get('__pub_jid', ''))
|
||||
if isinstance(__env__, string_types):
|
||||
salt.utils.warn_until(
|
||||
'Boron',
|
||||
|
|
|
@ -1042,7 +1042,7 @@ def remove_container(container, force=False, v=False):
|
|||
remove a running container, Default is ``False``
|
||||
|
||||
v
|
||||
verbose mode, Default is ``False``
|
||||
remove the volumes associated to the container, Default is ``False``
|
||||
|
||||
CLI Example:
|
||||
|
||||
|
@ -1858,6 +1858,8 @@ def load(imagepath):
|
|||
|
||||
def save(image, filename):
|
||||
'''
|
||||
.. versionadded:: 2015.2.0
|
||||
|
||||
Save the specified image to filename from docker
|
||||
e.g. `docker save image > filename`
|
||||
|
||||
|
@ -1885,7 +1887,7 @@ def save(image, filename):
|
|||
|
||||
if ok:
|
||||
try:
|
||||
dockercmd = ['docker', '-o', filename, 'save', image]
|
||||
dockercmd = ['docker', 'save', '-o', filename, image]
|
||||
ret = __salt__['cmd.run'](dockercmd)
|
||||
if ((isinstance(ret, dict) and
|
||||
('retcode' in ret) and
|
||||
|
@ -2072,7 +2074,7 @@ def get_container_root(container):
|
|||
'containers',
|
||||
_get_container_infos(container)['Id'],
|
||||
)
|
||||
default_rootfs = os.path.join(default_path, 'roofs')
|
||||
default_rootfs = os.path.join(default_path, 'rootfs')
|
||||
rootfs_re = re.compile(r'^lxc.rootfs\s*=\s*(.*)\s*$', re.U)
|
||||
try:
|
||||
lxcconfig = os.path.join(default_path, 'config.lxc')
|
||||
|
|
|
@ -9,6 +9,7 @@ from __future__ import absolute_import
|
|||
import xml.etree.cElementTree as ET
|
||||
import salt.utils
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
import logging
|
||||
|
||||
|
@ -32,15 +33,20 @@ def __execute_cmd(name, xml):
|
|||
ret = {name.replace('_', ' '): {}}
|
||||
id_num = 0
|
||||
|
||||
with salt.utils.fopen('/tmp/{0}.{1}'.format(name, os.getpid()), 'w') as fh:
|
||||
tmp_dir = os.path.join(__opts__['cachedir'], 'tmp')
|
||||
if not os.path.isdir(tmp_dir):
|
||||
os.mkdir(tmp_dir)
|
||||
with tempfile.NamedTemporaryFile(dir=tmp_dir,
|
||||
prefix=name,
|
||||
suffix=os.getpid(),
|
||||
delete=False) as fh:
|
||||
tmpfilename = fh.name
|
||||
fh.write(xml)
|
||||
|
||||
cmd = __salt__['cmd.run_all']('hponcfg -f /tmp/{0}.{1}'.format(
|
||||
name, os.getpid())
|
||||
)
|
||||
cmd = __salt__['cmd.run_all']('hponcfg -f {0}'.format(tmpfilename))
|
||||
|
||||
# Clean up the temp file
|
||||
__salt__['file.remove']('/tmp/{0}.{1}'.format(name, os.getpid()))
|
||||
__salt__['file.remove'](tmpfilename)
|
||||
|
||||
if cmd['retcode'] != 0:
|
||||
for i in cmd['stderr'].splitlines():
|
||||
|
|
|
@ -830,7 +830,8 @@ def user_verify_password(user_id=None, name=None, password=None,
|
|||
'auth_url': auth_url}
|
||||
try:
|
||||
userauth = client.Client(**kwargs)
|
||||
except keystoneclient.exceptions.Unauthorized:
|
||||
except (keystoneclient.exceptions.Unauthorized,
|
||||
keystoneclient.exceptions.AuthorizationFailure):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ import time
|
|||
# Import salt libs
|
||||
import salt.crypt
|
||||
import salt.payload
|
||||
import salt.utils
|
||||
import salt.utils.network
|
||||
import salt.utils.event
|
||||
from salt.exceptions import SaltClientError
|
||||
|
@ -153,6 +154,7 @@ def send(func, *args, **kwargs):
|
|||
salt '*' mine.send network.ip_addrs eth0
|
||||
salt '*' mine.send eth0_ip_addrs mine_function=network.ip_addrs eth0
|
||||
'''
|
||||
kwargs = salt.utils.clean_kwargs(**kwargs)
|
||||
mine_func = kwargs.pop('mine_function', func)
|
||||
if mine_func not in __salt__:
|
||||
return False
|
||||
|
|
|
@ -14,6 +14,7 @@ import socket
|
|||
|
||||
# Import salt libs
|
||||
import salt.utils
|
||||
import salt.utils.decorators as decorators
|
||||
import salt.utils.network
|
||||
import salt.utils.validate.net
|
||||
from salt.exceptions import CommandExecutionError
|
||||
|
@ -589,6 +590,7 @@ def dig(host):
|
|||
return __salt__['cmd.run'](cmd)
|
||||
|
||||
|
||||
@decorators.which('arp')
|
||||
def arp():
|
||||
'''
|
||||
Return the arp table from the minion
|
||||
|
|
|
@ -83,6 +83,7 @@ def list_(show_all=False, return_yaml=True):
|
|||
for item in schedule[job]:
|
||||
if item not in SCHEDULE_CONF:
|
||||
del schedule[job][item]
|
||||
continue
|
||||
if schedule[job][item] == 'true':
|
||||
schedule[job][item] = True
|
||||
if schedule[job][item] == 'false':
|
||||
|
|
|
@ -10,6 +10,8 @@ Wrapper around Server Density API
|
|||
from __future__ import absolute_import
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
# Import 3rd-party libs
|
||||
import salt.ext.six as six
|
||||
|
@ -239,17 +241,24 @@ def install_agent(agent_key):
|
|||
|
||||
salt '*' serverdensity_device.install_agent c2bbdd6689ff46282bdaa07555641498
|
||||
'''
|
||||
work_dir = '/tmp/'
|
||||
work_dir = os.path.join(__opts__['cachedir'], 'tmp')
|
||||
if not os.path.isdir(work_dir):
|
||||
os.mkdir(work_dir)
|
||||
install_file = tempfile.NamedTemporaryFile(dir=work_dir,
|
||||
suffix='.sh',
|
||||
delete=False)
|
||||
install_filename = install_file.name
|
||||
install_file.close()
|
||||
account_url = get_sd_auth('account_url')
|
||||
|
||||
__salt__['cmd.run'](
|
||||
cmd='curl https://www.serverdensity.com/downloads/agent-install.sh -o install.sh',
|
||||
cmd='curl https://www.serverdensity.com/downloads/agent-install.sh -o {0}'.format(install_filename),
|
||||
cwd=work_dir
|
||||
)
|
||||
__salt__['cmd.run'](cmd='chmod +x install.sh', cwd=work_dir)
|
||||
__salt__['cmd.run'](cmd='chmod +x {0}'.format(install_filename), cwd=work_dir)
|
||||
|
||||
return __salt__['cmd.run'](
|
||||
cmd='./install.sh -a {account_url} -k {agent_key}'.format(
|
||||
account_url=account_url, agent_key=agent_key),
|
||||
cmd='./{filename} -a {account_url} -k {agent_key}'.format(
|
||||
filename=install_filename, account_url=account_url, agent_key=agent_key),
|
||||
cwd=work_dir
|
||||
)
|
||||
|
|
|
@ -258,7 +258,7 @@ def host_keys(keydir=None, private=True):
|
|||
continue
|
||||
|
||||
top = fn_.split('.')
|
||||
comps = fn_.split('_')
|
||||
comps = top[0].split('_')
|
||||
kname = comps[2]
|
||||
if len(top) > 1:
|
||||
kname += '.{0}'.format(top[1])
|
||||
|
@ -267,7 +267,11 @@ def host_keys(keydir=None, private=True):
|
|||
# As of RFC 4716 "a key file is a text file, containing a sequence of lines",
|
||||
# although some SSH implementations (e.g. OpenSSH) manage their own format(s).
|
||||
# Please see #20708 for a discussion about how to handle SSH key files in the future
|
||||
keys[kname] = _fh.read.strip()
|
||||
keys[kname] = _fh.readline()
|
||||
# only read the whole file if it is not in the legacy 1.1 binary format
|
||||
if keys[kname] != "SSH PRIVATE KEY FILE FORMAT 1.1\n":
|
||||
keys[kname] += _fh.read()
|
||||
keys[kname] = keys[kname].strip()
|
||||
except (IOError, OSError):
|
||||
keys[kname] = ''
|
||||
return keys
|
||||
|
|
|
@ -231,11 +231,44 @@ def restart(name):
|
|||
salt '*' service.restart <service name>
|
||||
'''
|
||||
if has_powershell():
|
||||
if 'salt-minion' in name:
|
||||
create_win_salt_restart_task()
|
||||
return execute_salt_restart_task()
|
||||
cmd = 'Restart-Service {0}'.format(_cmd_quote(name))
|
||||
return not __salt__['cmd.retcode'](cmd, shell='powershell', python_shell=True)
|
||||
return stop(name) and start(name)
|
||||
|
||||
|
||||
def create_win_salt_restart_task():
|
||||
'''
|
||||
|
||||
Create a task in Windows task scheduler to enable restarting the salt-minion
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' service.create_win_salt_restart_task()
|
||||
'''
|
||||
cmd = 'schtasks /RU "System" /Create /TN restart-salt-minion /TR "powershell Restart-Service salt-minion" /sc ONCE /sd 01/15/1975 /st 01:00 /F'
|
||||
|
||||
return __salt__['cmd.run'](cmd)
|
||||
|
||||
|
||||
def execute_salt_restart_task():
|
||||
'''
|
||||
Run the Windows Salt restart task
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' service.execute_salt_restart_task()
|
||||
'''
|
||||
cmd = 'schtasks /Run /TN restart-salt-minion'
|
||||
return __salt__['cmd.run'](cmd)
|
||||
|
||||
|
||||
def status(name, sig=None):
|
||||
'''
|
||||
Return the status for a service, returns the PID or an empty string if the
|
||||
|
|
|
@ -28,9 +28,9 @@ from __future__ import absolute_import
|
|||
from numbers import Number
|
||||
|
||||
# Import salt libs
|
||||
from salt.utils import get_colors, sdecode
|
||||
import salt.output
|
||||
from salt.ext.six import string_types
|
||||
from salt.utils import get_colors, sdecode
|
||||
|
||||
|
||||
class NestDisplay(object):
|
||||
|
@ -68,7 +68,6 @@ class NestDisplay(object):
|
|||
'''
|
||||
Recursively iterate down through data structures to determine output
|
||||
'''
|
||||
|
||||
if ret is None or ret is True or ret is False:
|
||||
out.append(
|
||||
self.ustring(
|
||||
|
|
|
@ -287,15 +287,16 @@ def ext_pillar(minion_id,
|
|||
|
||||
# environment is "different" from the branch
|
||||
branch, _, environment = branch_env.partition(':')
|
||||
|
||||
gitpil = GitPillar(branch, repo_location, __opts__)
|
||||
branch = gitpil.branch
|
||||
|
||||
if environment == '':
|
||||
if branch == 'master':
|
||||
environment = 'base'
|
||||
else:
|
||||
environment = branch
|
||||
|
||||
gitpil = GitPillar(branch, repo_location, __opts__)
|
||||
branch = gitpil.branch
|
||||
|
||||
# normpath is needed to remove appended '/' if root is empty string.
|
||||
pillar_dir = os.path.normpath(os.path.join(gitpil.working_dir, root))
|
||||
|
||||
|
|
|
@ -138,6 +138,7 @@ class Runner(RunnerClient):
|
|||
args, kwargs = salt.minion.load_args_and_kwargs(
|
||||
self.functions[low['fun']],
|
||||
salt.utils.args.parse_input(self.opts['arg']),
|
||||
self.opts,
|
||||
)
|
||||
low['args'] = args
|
||||
low['kwargs'] = kwargs
|
||||
|
|
42
salt/runners/sdb.py
Normal file
42
salt/runners/sdb.py
Normal file
|
@ -0,0 +1,42 @@
|
|||
# coding: utf-8
|
||||
'''
|
||||
Runner for setting and querying data via the sdb API on the master
|
||||
'''
|
||||
from __future__ import absolute_import
|
||||
|
||||
# Import salt libs
|
||||
import salt.utils.sdb
|
||||
|
||||
|
||||
__func_alias__ = {
|
||||
'set_': 'set',
|
||||
}
|
||||
|
||||
|
||||
def get(uri):
|
||||
'''
|
||||
Get a value from a db, using a uri in the form of sdb://<profile>/<key>. If
|
||||
the uri provided does not start with sdb://, then it will be returned as-is.
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' sdb.get sdb://mymemcached/foo
|
||||
'''
|
||||
return salt.utils.sdb.sdb_get(uri, __opts__)
|
||||
|
||||
|
||||
def set_(uri, value):
|
||||
'''
|
||||
Set a value in a db, using a uri in the form of ``sdb://<profile>/<key>``.
|
||||
If the uri provided does not start with ``sdb://`` or the value is not
|
||||
successfully set, return ``False``.
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' sdb.set sdb://mymemcached/foo bar
|
||||
'''
|
||||
return salt.utils.sdb.sdb_set(uri, value, __opts__)
|
84
salt/sdb/etcd_db.py
Normal file
84
salt/sdb/etcd_db.py
Normal file
|
@ -0,0 +1,84 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
etcd Database Module
|
||||
|
||||
:maintainer: SaltStack
|
||||
:maturity: New
|
||||
:depends: python-etcd
|
||||
:platform: all
|
||||
|
||||
.. versionadded:: 2015.2.0
|
||||
|
||||
This module allows access to the etcd database using an ``sdb://`` URI. This
|
||||
package is located at ``https://pypi.python.org/pypi/python-etcd``.
|
||||
|
||||
Like all sdb modules, the etcd module requires a configuration profile to
|
||||
be configured in either the minion or master configuration file. This profile
|
||||
requires very little. In the example:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
myetcd:
|
||||
driver: etcd
|
||||
etcd.host: 127.0.0.1
|
||||
etcd.port: 4001
|
||||
|
||||
The ``driver`` refers to the etcd module, ``etcd.host`` refers to the host that
|
||||
is hosting the etcd database and ``etcd.port`` refers to the port on that host.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
password: sdb://myetcd/mypassword
|
||||
|
||||
'''
|
||||
|
||||
# import python libs
|
||||
import logging
|
||||
|
||||
try:
|
||||
import salt.utils.etcd_util
|
||||
HAS_LIBS = True
|
||||
except ImportError:
|
||||
HAS_LIBS = False
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
__func_alias__ = {
|
||||
'set_': 'set'
|
||||
}
|
||||
|
||||
__virtualname__ = 'etcd'
|
||||
|
||||
|
||||
def __virtual__():
|
||||
'''
|
||||
Only load the module if keyring is installed
|
||||
'''
|
||||
if HAS_LIBS:
|
||||
return __virtualname__
|
||||
return False
|
||||
|
||||
|
||||
def set_(key, value, service=None, profile=None): # pylint: disable=W0613
|
||||
'''
|
||||
Set a key/value pair in the etcd service
|
||||
'''
|
||||
client = _get_conn(profile)
|
||||
client.set(key, value)
|
||||
return get(key, service, profile)
|
||||
|
||||
|
||||
def get(key, service=None, profile=None): # pylint: disable=W0613
|
||||
'''
|
||||
Get a value from the etcd service
|
||||
'''
|
||||
client = _get_conn(profile)
|
||||
result = client.get(key)
|
||||
return result.value
|
||||
|
||||
|
||||
def _get_conn(profile):
|
||||
'''
|
||||
Get a connection
|
||||
'''
|
||||
return salt.utils.etcd_util.get_conn(profile)
|
|
@ -134,13 +134,24 @@ def mounted(name,
|
|||
real_device = _real_device
|
||||
else:
|
||||
# Remote file systems act differently.
|
||||
opts = list(set(opts + active[_device]['opts'] + active[_device]['superopts']))
|
||||
active[real_name]['opts'].append('bind')
|
||||
if _device in active:
|
||||
opts = list(set(opts + active[_device]['opts'] + active[_device]['superopts']))
|
||||
active[real_name]['opts'].append('bind')
|
||||
real_device = active[real_name]['device']
|
||||
else:
|
||||
real_device = os.path.realpath(device)
|
||||
elif device.upper().startswith('UUID='):
|
||||
real_device = device.split('=')[1].strip('"').lower()
|
||||
elif device.upper().startswith('LABEL='):
|
||||
_label = device.split('=')[1]
|
||||
cmd = 'blkid -L {0}'.format(_label)
|
||||
res = __salt__['cmd.run_all']('{0}'.format(cmd))
|
||||
if res['retcode'] > 0:
|
||||
ret['comment'] = 'Unable to find device with label {0}.'.format(_label)
|
||||
ret['result'] = False
|
||||
return ret
|
||||
else:
|
||||
real_device = res['stdout']
|
||||
else:
|
||||
real_device = device
|
||||
|
||||
|
@ -205,6 +216,7 @@ def mounted(name,
|
|||
'soft',
|
||||
'auto',
|
||||
'users',
|
||||
'bind',
|
||||
]
|
||||
# options which are provided as key=value (e.g. password=Zohp5ohb)
|
||||
mount_invisible_keys = [
|
||||
|
|
|
@ -722,28 +722,56 @@ def _ipv4_to_bits(ipaddr):
|
|||
return ''.join([bin(int(x))[2:].rjust(8, '0') for x in ipaddr.split('.')])
|
||||
|
||||
|
||||
def _get_iface_info(iface):
|
||||
'''
|
||||
If `iface` is available, return interface info and no error, otherwise
|
||||
return no info and log and return an error
|
||||
'''
|
||||
iface_info = interfaces()
|
||||
|
||||
if iface in iface_info.keys():
|
||||
return iface_info, False
|
||||
else:
|
||||
error_msg = ('Interface "{0}" not in available interfaces: "{1}"'
|
||||
''.format(iface, '", "'.join(iface_info.keys())))
|
||||
log.error(error_msg)
|
||||
return None, error_msg
|
||||
|
||||
|
||||
def hw_addr(iface):
|
||||
'''
|
||||
Return the hardware address (a.k.a. MAC address) for a given interface
|
||||
'''
|
||||
return interfaces().get(iface, {}).get('hwaddr', '')
|
||||
iface_info, error = _get_iface_info(iface)
|
||||
|
||||
if error is False:
|
||||
return iface_info.get(iface, {}).get('hwaddr', '')
|
||||
else:
|
||||
return error
|
||||
|
||||
|
||||
def interface(iface):
|
||||
'''
|
||||
Return the interface details
|
||||
Return the details of `iface` or an error if it does not exist
|
||||
'''
|
||||
return interfaces().get(iface, {}).get('inet', '')
|
||||
iface_info, error = _get_iface_info(iface)
|
||||
|
||||
if error is False:
|
||||
return iface_info.get(iface, {}).get('inet', '')
|
||||
else:
|
||||
return error
|
||||
|
||||
|
||||
def interface_ip(iface):
|
||||
'''
|
||||
Return the interface details
|
||||
Return `iface` IPv4 addr or an error if `iface` does not exist
|
||||
'''
|
||||
try:
|
||||
return interfaces().get(iface, {}).get('inet', {})[0].get('address', {})
|
||||
except KeyError:
|
||||
return {} # iface has no IP
|
||||
iface_info, error = _get_iface_info(iface)
|
||||
|
||||
if error is False:
|
||||
return iface_info.get(iface, {}).get('inet', {})[0].get('address', '')
|
||||
else:
|
||||
return error
|
||||
|
||||
|
||||
def subnets():
|
||||
|
|
|
@ -206,6 +206,16 @@ class State(object):
|
|||
self.id_ = id_
|
||||
self.module = module
|
||||
self.func = func
|
||||
|
||||
# our requisites should all be lists, but when you only have a
|
||||
# single item it's more convenient to provide it without
|
||||
# wrapping it in a list. transform them into a list
|
||||
for attr in REQUISITES:
|
||||
if attr in kwargs:
|
||||
try:
|
||||
iter(kwargs[attr])
|
||||
except TypeError:
|
||||
kwargs[attr] = [kwargs[attr]]
|
||||
self.kwargs = kwargs
|
||||
|
||||
if isinstance(self.id_, StateExtend):
|
||||
|
@ -223,12 +233,6 @@ class State(object):
|
|||
# handle our requisites
|
||||
for attr in REQUISITES:
|
||||
if attr in kwargs:
|
||||
# our requisites should all be lists, but when you only have a
|
||||
# single item it's more convenient to provide it without
|
||||
# wrapping it in a list. transform them into a list
|
||||
if not isinstance(kwargs[attr], list):
|
||||
kwargs[attr] = [kwargs[attr]]
|
||||
|
||||
# rebuild the requisite list transforming any of the actual
|
||||
# StateRequisite objects into their representative dict
|
||||
kwargs[attr] = [
|
||||
|
|
|
@ -172,9 +172,11 @@ class ReactWrap(object):
|
|||
f_call = salt.utils.format_call(l_fun, low)
|
||||
kwargs = f_call.get('kwargs', {})
|
||||
|
||||
# TODO: pick one...
|
||||
kwargs['__user__'] = self.event_user
|
||||
kwargs['user'] = self.event_user
|
||||
# TODO: Setting the user doesn't seem to work for actual remote publishes
|
||||
if low['state'] in ('runner', 'wheel'):
|
||||
# TODO: pick one...
|
||||
kwargs['__user__'] = self.event_user
|
||||
kwargs['user'] = self.event_user
|
||||
|
||||
l_fun(*f_call.get('args', ()), **kwargs)
|
||||
except Exception:
|
||||
|
|
|
@ -109,6 +109,11 @@ random_password_import_template = '''#!pyobjecs
|
|||
from salt://password.sls import password
|
||||
'''
|
||||
|
||||
requisite_implicit_list_template = '''#!pyobjects
|
||||
with Pkg.installed("pkg"):
|
||||
Service.running("service", watch=File("file"), require=Cmd("cmd"))
|
||||
'''
|
||||
|
||||
|
||||
class StateTests(TestCase):
|
||||
def setUp(self):
|
||||
|
@ -259,7 +264,7 @@ class RendererMixin(object):
|
|||
state.opts['renderer'])
|
||||
|
||||
|
||||
class RendererTests(RendererMixin, TestCase):
|
||||
class RendererTests(RendererMixin, StateTests):
|
||||
def test_basic(self):
|
||||
ret = self.render(basic_template)
|
||||
self.assertEqual(ret, OrderedDict([
|
||||
|
@ -318,6 +323,31 @@ class RendererTests(RendererMixin, TestCase):
|
|||
render_and_assert(from_import_template)
|
||||
render_and_assert(import_as_template)
|
||||
|
||||
def test_random_password(self):
|
||||
'''Test for https://github.com/saltstack/salt/issues/21796'''
|
||||
ret = self.render(random_password_template)
|
||||
|
||||
def test_import_random_password(self):
|
||||
'''Import test for https://github.com/saltstack/salt/issues/21796'''
|
||||
self.write_template_file("password.sls", random_password_template)
|
||||
ret = self.render(random_password_import_template)
|
||||
|
||||
def test_requisite_implicit_list(self):
|
||||
'''Ensure that the implicit list characteristic works as expected'''
|
||||
ret = self.render(requisite_implicit_list_template)
|
||||
|
||||
self.assertEqual(ret, OrderedDict([
|
||||
('pkg', OrderedDict([
|
||||
('pkg.installed', [])
|
||||
])),
|
||||
('service', OrderedDict([
|
||||
('service.running', [
|
||||
{'require': [{'cmd': 'cmd'}, {'pkg': 'pkg'}]},
|
||||
{'watch': [{'file': 'file'}]},
|
||||
])
|
||||
]))
|
||||
]))
|
||||
|
||||
|
||||
class MapTests(RendererMixin, TestCase):
|
||||
def test_map(self):
|
||||
|
@ -346,15 +376,6 @@ class MapTests(RendererMixin, TestCase):
|
|||
ret = samba_with_grains({'os_family': 'RedHat', 'os': 'CentOS'})
|
||||
assert_ret(ret, 'samba', 'samba', 'smb')
|
||||
|
||||
def test_random_password(self):
|
||||
'''Test for https://github.com/saltstack/salt/issues/21796'''
|
||||
ret = self.render(random_password_template)
|
||||
|
||||
def test_import_random_password(self):
|
||||
'''Import test for https://github.com/saltstack/salt/issues/21796'''
|
||||
self.write_template_file("password.sls", random_password_template)
|
||||
ret = self.render(random_password_import_template)
|
||||
|
||||
|
||||
class SaltObjectTests(TestCase):
|
||||
def test_salt_object(self):
|
||||
|
|
Loading…
Add table
Reference in a new issue