mirror of
https://github.com/saltstack/salt.git
synced 2025-04-16 17:50:20 +00:00
Merge branch '2018.3' into 'fluorine'
Conflicts: - doc/ref/tops/all/index.rst - salt/fileclient.py - salt/grains/core.py - salt/modules/win_file.py - salt/pillar/__init__.py - salt/utils/http.py
This commit is contained in:
commit
82e73fe49d
105 changed files with 1432 additions and 783 deletions
3
.ci/docs
3
.ci/docs
|
@ -48,6 +48,9 @@ pipeline {
|
|||
description: 'The docs job has failed',
|
||||
status: 'FAILURE',
|
||||
context: "jenkins/pr/docs"
|
||||
slackSend channel: "#jenkins-prod-pr",
|
||||
color: '#FF0000',
|
||||
message: "FAILED: PR-Job: '${env.JOB_NAME} [${env.BUILD_NUMBER}]' (${env.BUILD_URL})"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,6 +72,9 @@ timeout(time: 6, unit: 'HOURS') {
|
|||
description: "The ${TEST_SUITE}-${TEST_PLATFORM} job has failed",
|
||||
status: 'FAILURE',
|
||||
context: "jenkins/pr/${TEST_SUITE}-${TEST_PLATFORM}"
|
||||
slackSend channel: "#jenkins-prod-pr",
|
||||
color: '#FF0000',
|
||||
message: "FAILED: PR-Job: '${env.JOB_NAME} [${env.BUILD_NUMBER}]' (${env.BUILD_URL})"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,6 +72,9 @@ timeout(time: 6, unit: 'HOURS') {
|
|||
description: "The ${TEST_SUITE}-${TEST_PLATFORM} job has failed",
|
||||
status: 'FAILURE',
|
||||
context: "jenkins/pr/${TEST_SUITE}-${TEST_PLATFORM}"
|
||||
slackSend channel: "#jenkins-prod-pr",
|
||||
color: '#FF0000',
|
||||
message: "FAILED: PR-Job: '${env.JOB_NAME} [${env.BUILD_NUMBER}]' (${env.BUILD_URL})"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,7 +62,7 @@ timeout(time: 6, unit: 'HOURS') {
|
|||
} finally {
|
||||
cleanWs notFailBuild: true
|
||||
def currentResult = currentBuild.result ?: 'SUCCESS'
|
||||
if ( currentResult == 'SUCCESS') {
|
||||
if (currentResult == 'SUCCESS') {
|
||||
githubNotify credentialsId: 'test-jenkins-credentials',
|
||||
description: "The ${TEST_SUITE}-${TEST_PLATFORM} job has passed",
|
||||
status: 'SUCCESS',
|
||||
|
@ -72,6 +72,9 @@ timeout(time: 6, unit: 'HOURS') {
|
|||
description: "The ${TEST_SUITE}-${TEST_PLATFORM} job has failed",
|
||||
status: 'FAILURE',
|
||||
context: "jenkins/pr/${TEST_SUITE}-${TEST_PLATFORM}"
|
||||
slackSend channel: "#jenkins-prod-pr",
|
||||
color: '#FF0000',
|
||||
message: "FAILED: PR-Job: '${env.JOB_NAME} [${env.BUILD_NUMBER}]' (${env.BUILD_URL})"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,6 +72,9 @@ timeout(time: 6, unit: 'HOURS') {
|
|||
description: "The ${TEST_SUITE}-${TEST_PLATFORM} job has failed",
|
||||
status: 'FAILURE',
|
||||
context: "jenkins/pr/${TEST_SUITE}-${TEST_PLATFORM}"
|
||||
slackSend channel: "#jenkins-prod-pr",
|
||||
color: '#FF0000',
|
||||
message: "FAILED: PR-Job: '${env.JOB_NAME} [${env.BUILD_NUMBER}]' (${env.BUILD_URL})"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,6 +72,9 @@ timeout(time: 6, unit: 'HOURS') {
|
|||
description: "The ${TEST_SUITE}-${TEST_PLATFORM} job has failed",
|
||||
status: 'FAILURE',
|
||||
context: "jenkins/pr/${TEST_SUITE}-${TEST_PLATFORM}"
|
||||
slackSend channel: "#jenkins-prod-pr",
|
||||
color: '#FF0000',
|
||||
message: "FAILED: PR-Job: '${env.JOB_NAME} [${env.BUILD_NUMBER}]' (${env.BUILD_URL})"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,6 +72,9 @@ timeout(time: 6, unit: 'HOURS') {
|
|||
description: "The ${TEST_SUITE}-${TEST_PLATFORM} job has failed",
|
||||
status: 'FAILURE',
|
||||
context: "jenkins/pr/${TEST_SUITE}-${TEST_PLATFORM}"
|
||||
slackSend channel: "#jenkins-prod-pr",
|
||||
color: '#FF0000',
|
||||
message: "FAILED: PR-Job: '${env.JOB_NAME} [${env.BUILD_NUMBER}]' (${env.BUILD_URL})"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
3
.ci/lint
3
.ci/lint
|
@ -94,6 +94,9 @@ pipeline {
|
|||
description: 'The lint job has failed',
|
||||
status: 'FAILURE',
|
||||
context: "jenkins/pr/lint"
|
||||
slackSend channel: "#jenkins-prod-pr",
|
||||
color: '#FF0000',
|
||||
message: "FAILED: PR-Job: '${env.JOB_NAME} [${env.BUILD_NUMBER}]' (${env.BUILD_URL})"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
13
CONTRIBUTING.rst
Normal file
13
CONTRIBUTING.rst
Normal file
|
@ -0,0 +1,13 @@
|
|||
Developing Salt
|
||||
===============
|
||||
|
||||
The Salt development team is welcoming, positive, and dedicated to
|
||||
helping people get new code and fixes into SaltStack projects. Log into
|
||||
GitHub and get started with one of the largest developer communities in
|
||||
the world. The following links should get you started:
|
||||
|
||||
`<https://github.com/saltstack>`_
|
||||
|
||||
`<https://docs.saltstack.com/en/latest/topics/development/index.html>`_
|
||||
|
||||
`<https://docs.saltstack.com/en/develop/topics/development/pull_requests.html>`_
|
9
Gemfile
9
Gemfile
|
@ -12,12 +12,15 @@ group :docker do
|
|||
end
|
||||
|
||||
group :windows do
|
||||
gem 'vagrant-wrapper'
|
||||
gem 'kitchen-vagrant'
|
||||
gem 'winrm', '~>2.0'
|
||||
gem 'winrm-fs', '~>1.2.1'
|
||||
gem 'winrm-fs', :git => 'https://github.com/dwoz/winrm-fs.git', :branch => 'chunked_downloads'
|
||||
end
|
||||
|
||||
group :ec2 do
|
||||
gem 'kitchen-ec2'
|
||||
end
|
||||
|
||||
group :vagrant do
|
||||
gem 'vagrant-wrapper'
|
||||
gem 'kitchen-vagrant'
|
||||
end
|
||||
|
|
2
LICENSE
2
LICENSE
|
@ -1,6 +1,6 @@
|
|||
Salt - Remote execution system
|
||||
|
||||
Copyright 2014-2016 SaltStack Team
|
||||
Copyright 2014-2019 SaltStack Team
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
|
5
NOTICE
Normal file
5
NOTICE
Normal file
|
@ -0,0 +1,5 @@
|
|||
Apache SaltStack
|
||||
Copyright 2014-2019 The Apache Software Foundation
|
||||
|
||||
This product includes software developed at
|
||||
The Apache Software Foundation (http://www.apache.org/).
|
47
README.rst
47
README.rst
|
@ -34,39 +34,6 @@ documentation.
|
|||
|
||||
`<https://docs.saltstack.com/en/latest/>`_
|
||||
|
||||
Get SaltStack Support and Help
|
||||
==============================
|
||||
|
||||
**IRC Chat** - Join the vibrant, helpful and positive SaltStack chat room in
|
||||
Freenode at #salt. There is no need to introduce yourself, or ask permission to
|
||||
join in, just help and be helped! Make sure to wait for an answer, sometimes it
|
||||
may take a few moments for someone to reply.
|
||||
|
||||
`<http://webchat.freenode.net/?channels=salt&uio=Mj10cnVlJjk9dHJ1ZSYxMD10cnVl83>`_
|
||||
|
||||
**SaltStack Slack** - Alongside IRC is our SaltStack Community Slack for the
|
||||
SaltStack Working groups. Use the following link to request an invitation.
|
||||
|
||||
`<https://saltstackcommunity.herokuapp.com/>`_
|
||||
|
||||
**Mailing List** - The SaltStack community users mailing list is hosted by
|
||||
Google groups. Anyone can post to ask questions about SaltStack products and
|
||||
anyone can help answer. Join the conversation!
|
||||
|
||||
`<https://groups.google.com/forum/#!forum/salt-users>`_
|
||||
|
||||
You may subscribe to the list without a Google account by emailing
|
||||
salt-users+subscribe@googlegroups.com and you may post to the list by emailing
|
||||
salt-users@googlegroups.com
|
||||
|
||||
**Reporting Issues** - To report an issue with Salt, please follow the
|
||||
guidelines for filing bug reports:
|
||||
`<https://docs.saltstack.com/en/develop/topics/development/reporting_bugs.html>`_
|
||||
|
||||
**SaltStack Support** - If you need dedicated, prioritized support, please
|
||||
consider a SaltStack Support package that fits your needs:
|
||||
`<http://www.saltstack.com/support>`_
|
||||
|
||||
Engage SaltStack
|
||||
================
|
||||
|
||||
|
@ -100,17 +67,3 @@ services`_ offerings.
|
|||
.. _SaltStack education offerings: http://saltstack.com/training/
|
||||
.. _SaltStack Certified Engineer (SSCE): http://saltstack.com/certification/
|
||||
.. _SaltStack professional services: http://saltstack.com/services/
|
||||
|
||||
Developing Salt
|
||||
===============
|
||||
|
||||
The Salt development team is welcoming, positive, and dedicated to
|
||||
helping people get new code and fixes into SaltStack projects. Log into
|
||||
GitHub and get started with one of the largest developer communities in
|
||||
the world. The following links should get you started:
|
||||
|
||||
`<https://github.com/saltstack>`_
|
||||
|
||||
`<https://docs.saltstack.com/en/latest/topics/development/index.html>`_
|
||||
|
||||
`<https://docs.saltstack.com/en/develop/topics/development/pull_requests.html>`_
|
||||
|
|
33
SUPPORT.rst
Normal file
33
SUPPORT.rst
Normal file
|
@ -0,0 +1,33 @@
|
|||
Get SaltStack Support and Help
|
||||
==============================
|
||||
|
||||
**IRC Chat** - Join the vibrant, helpful and positive SaltStack chat room in
|
||||
Freenode at #salt. There is no need to introduce yourself, or ask permission to
|
||||
join in, just help and be helped! Make sure to wait for an answer, sometimes it
|
||||
may take a few moments for someone to reply.
|
||||
|
||||
`<http://webchat.freenode.net/?channels=salt&uio=Mj10cnVlJjk9dHJ1ZSYxMD10cnVl83>`_
|
||||
|
||||
**SaltStack Slack** - Alongside IRC is our SaltStack Community Slack for the
|
||||
SaltStack Working groups. Use the following link to request an invitation.
|
||||
|
||||
`<https://saltstackcommunity.herokuapp.com/>`_
|
||||
|
||||
**Mailing List** - The SaltStack community users mailing list is hosted by
|
||||
Google groups. Anyone can post to ask questions about SaltStack products and
|
||||
anyone can help answer. Join the conversation!
|
||||
|
||||
`<https://groups.google.com/forum/#!forum/salt-users>`_
|
||||
|
||||
You may subscribe to the list without a Google account by emailing
|
||||
salt-users+subscribe@googlegroups.com and you may post to the list by emailing
|
||||
salt-users@googlegroups.com
|
||||
|
||||
**Reporting Issues** - To report an issue with Salt, please follow the
|
||||
guidelines for filing bug reports:
|
||||
`<https://docs.saltstack.com/en/develop/topics/development/reporting_bugs.html>`_
|
||||
|
||||
**SaltStack Support** - If you need dedicated, prioritized support, please
|
||||
consider a SaltStack Support package that fits your needs:
|
||||
`<http://www.saltstack.com/support>`_
|
||||
|
18
conf/master
18
conf/master
|
@ -269,24 +269,6 @@
|
|||
# The publisher interface ZeroMQPubServerChannel
|
||||
#pub_hwm: 1000
|
||||
|
||||
# These two ZMQ HWM settings, salt_event_pub_hwm and event_publisher_pub_hwm
|
||||
# are significant for masters with thousands of minions. When these are
|
||||
# insufficiently high it will manifest in random responses missing in the CLI
|
||||
# and even missing from the job cache. Masters that have fast CPUs and many
|
||||
# cores with appropriate worker_threads will not need these set as high.
|
||||
|
||||
# On deployment with 8,000 minions, 2.4GHz CPUs, 24 cores, 32GiB memory has
|
||||
# these settings:
|
||||
#
|
||||
# salt_event_pub_hwm: 128000
|
||||
# event_publisher_pub_hwm: 64000
|
||||
|
||||
# ZMQ high-water-mark for SaltEvent pub socket
|
||||
#salt_event_pub_hwm: 20000
|
||||
|
||||
# ZMQ high-water-mark for EventPublisher pub socket
|
||||
#event_publisher_pub_hwm: 10000
|
||||
|
||||
# The master may allocate memory per-event and not
|
||||
# reclaim it.
|
||||
# To set a high-water mark for memory allocation, use
|
||||
|
|
|
@ -263,24 +263,6 @@ syndic_user: salt
|
|||
# The publisher interface ZeroMQPubServerChannel
|
||||
#pub_hwm: 1000
|
||||
|
||||
# These two ZMQ HWM settings, salt_event_pub_hwm and event_publisher_pub_hwm
|
||||
# are significant for masters with thousands of minions. When these are
|
||||
# insufficiently high it will manifest in random responses missing in the CLI
|
||||
# and even missing from the job cache. Masters that have fast CPUs and many
|
||||
# cores with appropriate worker_threads will not need these set as high.
|
||||
|
||||
# On deployment with 8,000 minions, 2.4GHz CPUs, 24 cores, 32GiB memory has
|
||||
# these settings:
|
||||
#
|
||||
# salt_event_pub_hwm: 128000
|
||||
# event_publisher_pub_hwm: 64000
|
||||
|
||||
# ZMQ high-water-mark for SaltEvent pub socket
|
||||
#salt_event_pub_hwm: 20000
|
||||
|
||||
# ZMQ high-water-mark for EventPublisher pub socket
|
||||
#event_publisher_pub_hwm: 10000
|
||||
|
||||
# The master may allocate memory per-event and not
|
||||
# reclaim it.
|
||||
# To set a high-water mark for memory allocation, use
|
||||
|
|
|
@ -1893,40 +1893,6 @@ The listen queue size of the ZeroMQ backlog.
|
|||
|
||||
zmq_backlog: 1000
|
||||
|
||||
.. conf_master:: salt_event_pub_hwm
|
||||
.. conf_master:: event_publisher_pub_hwm
|
||||
|
||||
``salt_event_pub_hwm`` and ``event_publisher_pub_hwm``
|
||||
------------------------------------------------------
|
||||
|
||||
These two ZeroMQ High Water Mark settings, ``salt_event_pub_hwm`` and
|
||||
``event_publisher_pub_hwm`` are significant for masters with thousands of
|
||||
minions. When these are insufficiently high it will manifest in random
|
||||
responses missing in the CLI and even missing from the job cache. Masters
|
||||
that have fast CPUs and many cores with appropriate ``worker_threads``
|
||||
will not need these set as high.
|
||||
|
||||
The ZeroMQ high-water-mark for the ``SaltEvent`` pub socket default is:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
salt_event_pub_hwm: 20000
|
||||
|
||||
The ZeroMQ high-water-mark for the ``EventPublisher`` pub socket default is:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
event_publisher_pub_hwm: 10000
|
||||
|
||||
As an example, on single master deployment with 8,000 minions, 2.4GHz CPUs,
|
||||
24 cores, and 32GiB memory has these settings:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
salt_event_pub_hwm: 128000
|
||||
event_publisher_pub_hwm: 64000
|
||||
|
||||
|
||||
.. _master-module-management:
|
||||
|
||||
Master Module Management
|
||||
|
@ -2482,6 +2448,12 @@ Master will not be returned to the Minion.
|
|||
------------------------------
|
||||
|
||||
.. versionadded:: 2014.1.0
|
||||
.. deprecated:: 2018.3.4
|
||||
This option is now ignored. Firstly, it only traversed
|
||||
:conf_master:`file_roots`, which means it did not work for the other
|
||||
fileserver backends. Secondly, since this option was added we have added
|
||||
caching to the code that traverses the file_roots (and gitfs, etc.), which
|
||||
greatly reduces the amount of traversal that is done.
|
||||
|
||||
Default: ``False``
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ execution modules
|
|||
aix_group
|
||||
aliases
|
||||
alternatives
|
||||
ansiblegate
|
||||
apache
|
||||
apcups
|
||||
apf
|
||||
|
|
6
doc/ref/modules/all/salt.modules.ansiblegate.rst
Normal file
6
doc/ref/modules/all/salt.modules.ansiblegate.rst
Normal file
|
@ -0,0 +1,6 @@
|
|||
========================
|
||||
salt.modules.ansiblegate
|
||||
========================
|
||||
|
||||
.. automodule:: salt.modules.ansiblegate
|
||||
:members:
|
|
@ -43,6 +43,7 @@ pillar modules
|
|||
reclass_adapter
|
||||
redismod
|
||||
s3
|
||||
saltclass
|
||||
sql_base
|
||||
sqlcipher
|
||||
sqlite3
|
||||
|
@ -53,4 +54,3 @@ pillar modules
|
|||
venafi
|
||||
virtkey
|
||||
vmware_pillar
|
||||
|
||||
|
|
6
doc/ref/pillar/all/salt.pillar.saltclass.rst
Normal file
6
doc/ref/pillar/all/salt.pillar.saltclass.rst
Normal file
|
@ -0,0 +1,6 @@
|
|||
=====================
|
||||
salt.pillar.saltclass
|
||||
=====================
|
||||
|
||||
.. automodule:: salt.pillar.saltclass
|
||||
:members:
|
|
@ -13,6 +13,7 @@ state modules
|
|||
acme
|
||||
alias
|
||||
alternatives
|
||||
ansiblegate
|
||||
apache
|
||||
apache_conf
|
||||
apache_module
|
||||
|
|
6
doc/ref/states/all/salt.states.ansiblegate.rst
Normal file
6
doc/ref/states/all/salt.states.ansiblegate.rst
Normal file
|
@ -0,0 +1,6 @@
|
|||
=======================
|
||||
salt.states.ansiblegate
|
||||
=======================
|
||||
|
||||
.. automodule:: salt.states.ansiblegate
|
||||
:members:
|
|
@ -14,4 +14,5 @@ master tops modules
|
|||
ext_nodes
|
||||
mongo
|
||||
reclass_adapter
|
||||
saltclass
|
||||
varstack_top
|
||||
|
|
6
doc/ref/tops/all/salt.tops.saltclass.rst
Normal file
6
doc/ref/tops/all/salt.tops.saltclass.rst
Normal file
|
@ -0,0 +1,6 @@
|
|||
===================
|
||||
salt.tops.saltclass
|
||||
===================
|
||||
|
||||
.. automodule:: salt.tops.saltclass
|
||||
:members:
|
|
@ -114,6 +114,12 @@ Set up the provider cloud config at ``/etc/salt/cloud.providers`` or
|
|||
|
||||
driver: gce
|
||||
|
||||
.. note::
|
||||
|
||||
Empty strings as values for ``service_account_private_key`` and ``service_account_email_address``
|
||||
can be used on GCE instances. This will result in the service account assigned to the GCE instance
|
||||
being used.
|
||||
|
||||
.. note::
|
||||
|
||||
The value provided for ``project`` must not contain underscores or spaces and
|
||||
|
|
|
@ -35,8 +35,8 @@ NAPALM
|
|||
NAPALM (Network Automation and Programmability Abstraction Layer with
|
||||
Multivendor support) is an opensourced Python library that implements a set of
|
||||
functions to interact with different router vendor devices using a unified API.
|
||||
Begin vendor-agnostic simplifies the operations, as the configuration
|
||||
and the interaction with the network device does not rely on a particular vendor.
|
||||
Being vendor-agnostic simplifies operations, as the configuration and
|
||||
interaction with the network device does not rely on a particular vendor.
|
||||
|
||||
.. image:: /_static/napalm_logo.png
|
||||
|
||||
|
|
16
doc/topics/releases/2017.7.9.rst
Normal file
16
doc/topics/releases/2017.7.9.rst
Normal file
|
@ -0,0 +1,16 @@
|
|||
========================================
|
||||
In Progress: Salt 2017.7.9 Release Notes
|
||||
========================================
|
||||
|
||||
Version 2017.7.9 is an **unreleased** bugfix release for :ref:`2017.7.0 <release-2017-7-0>`.
|
||||
This release is still in progress and has not been released yet.
|
||||
|
||||
Salt Cloud Features
|
||||
===================
|
||||
|
||||
GCE Driver
|
||||
----------
|
||||
The GCE salt cloud driver can now be used with GCE instance credentials by
|
||||
setting the configuration paramaters ``service_account_private_key`` and
|
||||
``service_account_private_email`` to an empty string.
|
||||
|
6
doc/topics/releases/2018.3.4.rst
Normal file
6
doc/topics/releases/2018.3.4.rst
Normal file
|
@ -0,0 +1,6 @@
|
|||
========================================
|
||||
In Progress: Salt 2018.3.4 Release Notes
|
||||
========================================
|
||||
|
||||
Version 2018.3.4 is an **unreleased** bugfix release for :ref:`2018.3.0 <release-2018-3-0>`.
|
||||
This release is still in progress and has not been released yet.
|
|
@ -244,14 +244,12 @@ Write-Output " - $script_name :: Copying DLLs . . ."
|
|||
Write-Output " ----------------------------------------------------------------"
|
||||
# Architecture Specific DLL's
|
||||
ForEach($key in $ini[$bitDLLs].Keys) {
|
||||
If ($arrInstalled -notcontains $key) {
|
||||
Write-Output " - $key . . ."
|
||||
$file = "$($ini[$bitDLLs][$key])"
|
||||
$url = "$($ini['Settings']['SaltRepo'])/$bitFolder/$file"
|
||||
$file = "$($ini['Settings']['DownloadDir'])\$bitFolder\$file"
|
||||
DownloadFileWithProgress $url $file
|
||||
Copy-Item $file -destination $($ini['Settings']['Python2Dir'])
|
||||
}
|
||||
Write-Output " - $key . . ."
|
||||
$file = "$($ini[$bitDLLs][$key])"
|
||||
$url = "$($ini['Settings']['SaltRepo'])/$bitFolder/$file"
|
||||
$file = "$($ini['Settings']['DownloadDir'])\$bitFolder\$file"
|
||||
DownloadFileWithProgress $url $file
|
||||
Copy-Item $file -destination $($ini['Settings']['Python2Dir'])
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
|
|
@ -251,14 +251,12 @@ Write-Output " - $script_name :: Copying DLLs . . ."
|
|||
Write-Output " ----------------------------------------------------------------"
|
||||
# Architecture Specific DLL's
|
||||
ForEach($key in $ini[$bitDLLs].Keys) {
|
||||
If ($arrInstalled -notcontains $key) {
|
||||
Write-Output " - $key . . ."
|
||||
$file = "$($ini[$bitDLLs][$key])"
|
||||
$url = "$($ini['Settings']['SaltRepo'])/$bitFolder/$file"
|
||||
$file = "$($ini['Settings']['DownloadDir'])\$bitFolder\$file"
|
||||
DownloadFileWithProgress $url $file
|
||||
Copy-Item $file -destination $($ini['Settings']['Python3Dir'])
|
||||
}
|
||||
Write-Output " - $key . . ."
|
||||
$file = "$($ini[$bitDLLs][$key])"
|
||||
$url = "$($ini['Settings']['SaltRepo'])/$bitFolder/$file"
|
||||
$file = "$($ini['Settings']['DownloadDir'])\$bitFolder\$file"
|
||||
DownloadFileWithProgress $url $file
|
||||
Copy-Item $file -destination $($ini['Settings']['Python3Dir'])
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
|
|
@ -11,7 +11,7 @@ Watch files and translate the changes into salt events
|
|||
the beacon configuration.
|
||||
|
||||
:note: The `inotify` beacon only works on OSes that have `inotify`
|
||||
kernel support. Currently this excludes FreeBSD, macOS, and Windows.
|
||||
kernel support.
|
||||
|
||||
'''
|
||||
# Import Python libs
|
||||
|
|
|
@ -1077,7 +1077,7 @@ class LocalClient(object):
|
|||
# stop the iteration, since the jid is invalid
|
||||
raise StopIteration()
|
||||
except Exception as exc:
|
||||
log.warning('Returner unavailable: %s', exc)
|
||||
log.warning('Returner unavailable: %s', exc, exc_info_on_loglevel=logging.DEBUG)
|
||||
# Wait for the hosts to check in
|
||||
last_time = False
|
||||
# iterator for this job's return
|
||||
|
|
|
@ -841,7 +841,7 @@ def create_network_interface(call=None, kwargs=None):
|
|||
)
|
||||
if pub_ip_data.ip_address: # pylint: disable=no-member
|
||||
ip_kwargs['public_ip_address'] = PublicIPAddress(
|
||||
six.text_type(pub_ip_data.id), # pylint: disable=no-member
|
||||
id=six.text_type(pub_ip_data.id), # pylint: disable=no-member
|
||||
)
|
||||
ip_configurations = [
|
||||
NetworkInterfaceIPConfiguration(
|
||||
|
|
|
@ -134,7 +134,8 @@ def __virtual__():
|
|||
|
||||
parameters = details['gce']
|
||||
pathname = os.path.expanduser(parameters['service_account_private_key'])
|
||||
if salt.utils.cloud.check_key_path_and_mode(
|
||||
# empty pathname will tell libcloud to use instance credentials
|
||||
if pathname and salt.utils.cloud.check_key_path_and_mode(
|
||||
provider, pathname
|
||||
) is False:
|
||||
return False
|
||||
|
|
|
@ -596,7 +596,7 @@ class SlackClient(object):
|
|||
Run each of them through ``get_configured_target(('foo', f), 'pillar.get')`` and confirm a valid target
|
||||
|
||||
'''
|
||||
# Default to targetting all minions with a type of glob
|
||||
# Default to targeting all minions with a type of glob
|
||||
null_target = {'target': '*', 'tgt_type': 'glob'}
|
||||
|
||||
def check_cmd_against_group(cmd):
|
||||
|
@ -634,6 +634,8 @@ class SlackClient(object):
|
|||
'''
|
||||
Print out YAML using the block mode
|
||||
'''
|
||||
# emulate the yaml_out output formatter. It relies on a global __opts__ object which
|
||||
# we can't obviously pass in
|
||||
try:
|
||||
try:
|
||||
outputter = data[next(iter(data))].get('out')
|
||||
|
|
|
@ -60,7 +60,7 @@ def get_file_client(opts, pillar=False):
|
|||
return {
|
||||
'remote': RemoteClient,
|
||||
'local': FSClient,
|
||||
'pillar': LocalClient,
|
||||
'pillar': PillarClient,
|
||||
}.get(client, RemoteClient)(opts)
|
||||
|
||||
|
||||
|
@ -346,58 +346,17 @@ class Client(object):
|
|||
Return a list of all available sls modules on the master for a given
|
||||
environment
|
||||
'''
|
||||
|
||||
limit_traversal = self.opts.get('fileserver_limit_traversal', False)
|
||||
states = []
|
||||
|
||||
if limit_traversal:
|
||||
if saltenv not in self.opts['file_roots']:
|
||||
log.warning(
|
||||
'During an attempt to list states for saltenv \'%s\', '
|
||||
'the environment could not be found in the configured '
|
||||
'file roots', saltenv
|
||||
)
|
||||
return states
|
||||
for path in self.opts['file_roots'][saltenv]:
|
||||
for root, dirs, files in os.walk(path, topdown=True): # future lint: disable=blacklisted-function
|
||||
root = salt.utils.data.decode(root)
|
||||
files = salt.utils.data.decode(files)
|
||||
log.debug(
|
||||
'Searching for states in dirs %s and files %s',
|
||||
salt.utils.data.decode(dirs), files
|
||||
)
|
||||
if not [filename.endswith('.sls') for filename in files]:
|
||||
# Use shallow copy so we don't disturb the memory used
|
||||
# by os.walk. Otherwise this breaks!
|
||||
del dirs[:]
|
||||
else:
|
||||
for found_file in files:
|
||||
stripped_root = os.path.relpath(root, path)
|
||||
if salt.utils.platform.is_windows():
|
||||
stripped_root = stripped_root.replace('\\', '/')
|
||||
stripped_root = stripped_root.replace('/', '.')
|
||||
if found_file.endswith(('.sls')):
|
||||
if found_file.endswith('init.sls'):
|
||||
if stripped_root.endswith('.'):
|
||||
stripped_root = stripped_root.rstrip('.')
|
||||
states.append(stripped_root)
|
||||
else:
|
||||
if not stripped_root.endswith('.'):
|
||||
stripped_root += '.'
|
||||
if stripped_root.startswith('.'):
|
||||
stripped_root = stripped_root.lstrip('.')
|
||||
states.append(stripped_root + found_file[:-4])
|
||||
else:
|
||||
for path in self.file_list(saltenv):
|
||||
if salt.utils.platform.is_windows():
|
||||
path = path.replace('\\', '/')
|
||||
if path.endswith('.sls'):
|
||||
# is an sls module!
|
||||
if path.endswith('/init.sls'):
|
||||
states.append(path.replace('/', '.')[:-9])
|
||||
else:
|
||||
states.append(path.replace('/', '.')[:-4])
|
||||
return states
|
||||
states = set()
|
||||
for path in self.file_list(saltenv):
|
||||
if salt.utils.platform.is_windows():
|
||||
path = path.replace('\\', '/')
|
||||
if path.endswith('.sls'):
|
||||
# is an sls module!
|
||||
if path.endswith('/init.sls'):
|
||||
states.add(path.replace('/', '.')[:-9])
|
||||
else:
|
||||
states.add(path.replace('/', '.')[:-4])
|
||||
return sorted(states)
|
||||
|
||||
def get_state(self, sls, saltenv, cachedir=None):
|
||||
'''
|
||||
|
@ -844,13 +803,10 @@ class Client(object):
|
|||
)
|
||||
|
||||
|
||||
class LocalClient(Client):
|
||||
class PillarClient(Client):
|
||||
'''
|
||||
Use the local_roots option to parse a local file root
|
||||
Used by pillar to handle fileclient requests
|
||||
'''
|
||||
def __init__(self, opts):
|
||||
Client.__init__(self, opts)
|
||||
|
||||
def _find_file(self, path, saltenv='base'):
|
||||
'''
|
||||
Locate the file path
|
||||
|
@ -861,7 +817,7 @@ class LocalClient(Client):
|
|||
if salt.utils.url.is_escaped(path):
|
||||
# The path arguments are escaped
|
||||
path = salt.utils.url.unescape(path)
|
||||
for root in self.opts['file_roots'].get(saltenv, []):
|
||||
for root in self.opts['pillar_roots'].get(saltenv, []):
|
||||
full = os.path.join(root, path)
|
||||
if os.path.isfile(full):
|
||||
fnd['path'] = full
|
||||
|
@ -895,7 +851,7 @@ class LocalClient(Client):
|
|||
'''
|
||||
ret = []
|
||||
prefix = prefix.strip('/')
|
||||
for path in self.opts['file_roots'].get(saltenv, []):
|
||||
for path in self.opts['pillar_roots'].get(saltenv, []):
|
||||
for root, dirs, files in salt.utils.path.os_walk(
|
||||
os.path.join(path, prefix), followlinks=True
|
||||
):
|
||||
|
@ -908,12 +864,12 @@ class LocalClient(Client):
|
|||
|
||||
def file_list_emptydirs(self, saltenv='base', prefix=''):
|
||||
'''
|
||||
List the empty dirs in the file_roots
|
||||
List the empty dirs in the pillar_roots
|
||||
with optional relative prefix path to limit directory traversal
|
||||
'''
|
||||
ret = []
|
||||
prefix = prefix.strip('/')
|
||||
for path in self.opts['file_roots'].get(saltenv, []):
|
||||
for path in self.opts['pillar_roots'].get(saltenv, []):
|
||||
for root, dirs, files in salt.utils.path.os_walk(
|
||||
os.path.join(path, prefix), followlinks=True
|
||||
):
|
||||
|
@ -925,12 +881,12 @@ class LocalClient(Client):
|
|||
|
||||
def dir_list(self, saltenv='base', prefix=''):
|
||||
'''
|
||||
List the dirs in the file_roots
|
||||
List the dirs in the pillar_roots
|
||||
with optional relative prefix path to limit directory traversal
|
||||
'''
|
||||
ret = []
|
||||
prefix = prefix.strip('/')
|
||||
for path in self.opts['file_roots'].get(saltenv, []):
|
||||
for path in self.opts['pillar_roots'].get(saltenv, []):
|
||||
for root, dirs, files in salt.utils.path.os_walk(
|
||||
os.path.join(path, prefix), followlinks=True
|
||||
):
|
||||
|
@ -957,7 +913,7 @@ class LocalClient(Client):
|
|||
|
||||
def hash_file(self, path, saltenv='base'):
|
||||
'''
|
||||
Return the hash of a file, to get the hash of a file in the file_roots
|
||||
Return the hash of a file, to get the hash of a file in the pillar_roots
|
||||
prepend the path with salt://<file on server> otherwise, prepend the
|
||||
file with / for a local file.
|
||||
'''
|
||||
|
@ -980,7 +936,7 @@ class LocalClient(Client):
|
|||
|
||||
def hash_and_stat_file(self, path, saltenv='base'):
|
||||
'''
|
||||
Return the hash of a file, to get the hash of a file in the file_roots
|
||||
Return the hash of a file, to get the hash of a file in the pillar_roots
|
||||
prepend the path with salt://<file on server> otherwise, prepend the
|
||||
file with / for a local file.
|
||||
|
||||
|
@ -1025,7 +981,10 @@ class LocalClient(Client):
|
|||
'''
|
||||
Return the available environments
|
||||
'''
|
||||
return list(self.opts['file_roots'])
|
||||
ret = []
|
||||
for saltenv in self.opts['pillar_roots']:
|
||||
ret.append(saltenv)
|
||||
return ret
|
||||
|
||||
def master_tops(self):
|
||||
'''
|
||||
|
@ -1417,6 +1376,11 @@ class FSClient(RemoteClient):
|
|||
self.auth = DumbAuth()
|
||||
|
||||
|
||||
# Provide backward compatibility for anyone directly using LocalClient (but no
|
||||
# one should be doing this).
|
||||
LocalClient = FSClient
|
||||
|
||||
|
||||
class DumbAuth(object):
|
||||
'''
|
||||
The dumbauth class is used to stub out auth calls fired from the FSClient
|
||||
|
|
|
@ -131,7 +131,10 @@ def check_file_list_cache(opts, form, list_cache, w_lock):
|
|||
if os.path.exists(list_cache):
|
||||
# calculate filelist age is possible
|
||||
cache_stat = os.stat(list_cache)
|
||||
age = time.time() - cache_stat.st_mtime
|
||||
# st_time can have a greater precision than time, removing
|
||||
# float precision makes sure age will never be a negative
|
||||
# number.
|
||||
age = int(time.time()) - int(cache_stat.st_mtime)
|
||||
else:
|
||||
# if filelist does not exists yet, mark it as expired
|
||||
age = opts.get('fileserver_list_cache_time', 20) + 1
|
||||
|
|
|
@ -52,6 +52,7 @@ import salt.utils.dns
|
|||
import salt.utils.files
|
||||
import salt.utils.network
|
||||
import salt.utils.path
|
||||
import salt.utils.pkg.rpm
|
||||
import salt.utils.platform
|
||||
import salt.utils.stringutils
|
||||
from salt.ext import six
|
||||
|
@ -617,6 +618,8 @@ def _windows_virtual(osdata):
|
|||
if osdata['kernel'] != 'Windows':
|
||||
return grains
|
||||
|
||||
grains['virtual'] = 'physical'
|
||||
|
||||
# It is possible that the 'manufacturer' and/or 'productname' grains
|
||||
# exist but have a value of None.
|
||||
manufacturer = osdata.get('manufacturer', '')
|
||||
|
@ -1523,6 +1526,34 @@ def _parse_os_release(*os_release_files):
|
|||
return ret
|
||||
|
||||
|
||||
def _parse_cpe_name(cpe):
|
||||
'''
|
||||
Parse CPE_NAME data from the os-release
|
||||
|
||||
Info: https://csrc.nist.gov/projects/security-content-automation-protocol/scap-specifications/cpe
|
||||
|
||||
:param cpe:
|
||||
:return:
|
||||
'''
|
||||
part = {
|
||||
'o': 'operating system',
|
||||
'h': 'hardware',
|
||||
'a': 'application',
|
||||
}
|
||||
ret = {}
|
||||
cpe = (cpe or '').split(':')
|
||||
if len(cpe) > 4 and cpe[0] == 'cpe':
|
||||
if cpe[1].startswith('/'): # WFN to URI
|
||||
ret['vendor'], ret['product'], ret['version'] = cpe[2:5]
|
||||
ret['phase'] = cpe[5] if len(cpe) > 5 else None
|
||||
ret['part'] = part.get(cpe[1][1:])
|
||||
elif len(cpe) == 13 and cpe[1] == '2.3': # WFN to a string
|
||||
ret['vendor'], ret['product'], ret['version'], ret['phase'] = [x if x != '*' else None for x in cpe[3:7]]
|
||||
ret['part'] = part.get(cpe[2])
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def os_data():
|
||||
'''
|
||||
Return grains pertaining to the operating system
|
||||
|
@ -1719,13 +1750,20 @@ def os_data():
|
|||
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']:
|
||||
cpe = _parse_cpe_name(os_release['CPE_NAME'])
|
||||
if not cpe:
|
||||
log.error('Broken CPE_NAME format in /etc/os-release!')
|
||||
elif cpe.get('vendor', '').lower() in ['suse', 'opensuse']:
|
||||
grains['os'] = "SUSE"
|
||||
# openSUSE `osfullname` grain normalization
|
||||
if os_release.get("NAME") == "openSUSE Leap":
|
||||
grains['osfullname'] = "Leap"
|
||||
elif os_release.get("VERSION") == "Tumbleweed":
|
||||
grains['osfullname'] = os_release["VERSION"]
|
||||
# Override VERSION_ID, if CPE_NAME around
|
||||
if cpe.get('version') and cpe.get('vendor') == 'opensuse': # Keep VERSION_ID for SLES
|
||||
grains['lsb_distrib_release'] = cpe['version']
|
||||
|
||||
elif os.path.isfile('/etc/SuSE-release'):
|
||||
log.trace('Parsing distrib info from /etc/SuSE-release')
|
||||
grains['lsb_distrib_id'] = 'SUSE'
|
||||
|
@ -1835,8 +1873,7 @@ def os_data():
|
|||
# Commit introducing this comment should be reverted after the upstream bug is released.
|
||||
if 'CentOS Linux 7' in grains.get('lsb_distrib_codename', ''):
|
||||
grains.pop('lsb_distrib_release', None)
|
||||
grains['osrelease'] = \
|
||||
grains.get('lsb_distrib_release', osrelease).strip()
|
||||
grains['osrelease'] = grains.get('lsb_distrib_release', osrelease).strip()
|
||||
grains['oscodename'] = grains.get('lsb_distrib_codename', '').strip() or oscodename
|
||||
if 'Red Hat' in grains['oscodename']:
|
||||
grains['oscodename'] = oscodename
|
||||
|
@ -1874,8 +1911,7 @@ def os_data():
|
|||
r'((?:Open|Oracle )?Solaris|OpenIndiana|OmniOS) (Development)?'
|
||||
r'\s*(\d+\.?\d*|v\d+)\s?[A-Z]*\s?(r\d+|\d+\/\d+|oi_\S+|snv_\S+)?'
|
||||
)
|
||||
osname, development, osmajorrelease, osminorrelease = \
|
||||
release_re.search(rel_data).groups()
|
||||
osname, development, osmajorrelease, osminorrelease = release_re.search(rel_data).groups()
|
||||
except AttributeError:
|
||||
# Set a blank osrelease grain and fallback to 'Solaris'
|
||||
# as the 'os' grain.
|
||||
|
@ -1962,8 +1998,8 @@ def os_data():
|
|||
# architecture.
|
||||
if grains.get('os_family') == 'Debian':
|
||||
osarch = __salt__['cmd.run']('dpkg --print-architecture').strip()
|
||||
elif grains.get('os_family') == 'RedHat':
|
||||
osarch = __salt__['cmd.run']('rpm --eval %{_host_cpu}').strip()
|
||||
elif grains.get('os_family') in ['RedHat', 'Suse']:
|
||||
osarch = salt.utils.pkg.rpm.get_osarch()
|
||||
elif grains.get('os_family') in ('NILinuxRT', 'Poky'):
|
||||
archinfo = {}
|
||||
for line in __salt__['cmd.run']('opkg print-architecture').splitlines():
|
||||
|
@ -2617,7 +2653,7 @@ def _hw_data(osdata):
|
|||
break
|
||||
elif osdata['kernel'] == 'AIX':
|
||||
cmd = salt.utils.path.which('prtconf')
|
||||
if data:
|
||||
if cmd:
|
||||
data = __salt__['cmd.run']('{0}'.format(cmd)) + os.linesep
|
||||
for dest, regstring in (('serialnumber', r'(?im)^\s*Machine\s+Serial\s+Number:\s+(\S+)'),
|
||||
('systemfirmware', r'(?im)^\s*Firmware\s+Version:\s+(.*)')):
|
||||
|
|
|
@ -332,7 +332,9 @@ class Maintenance(salt.utils.process.SignalHandlingMultiprocessingProcess):
|
|||
'''
|
||||
Fire presence events if enabled
|
||||
'''
|
||||
if self.presence_events:
|
||||
# On the first run it may need more time for the EventPublisher
|
||||
# to come up and be ready. Set the timeout to account for this.
|
||||
if self.presence_events and self.event.connect_pull(timeout=3):
|
||||
present = self.ckminions.connected_ids()
|
||||
new = present.difference(old_present)
|
||||
lost = old_present.difference(present)
|
||||
|
@ -342,9 +344,7 @@ class Maintenance(salt.utils.process.SignalHandlingMultiprocessingProcess):
|
|||
'lost': list(lost)}
|
||||
self.event.fire_event(data, tagify('change', 'presence'))
|
||||
data = {'present': list(present)}
|
||||
# On the first run it may need more time for the EventPublisher
|
||||
# to come up and be ready. Set the timeout to account for this.
|
||||
self.event.fire_event(data, tagify('present', 'presence'), timeout=3)
|
||||
self.event.fire_event(data, tagify('present', 'presence'))
|
||||
old_present.clear()
|
||||
old_present.update(present)
|
||||
|
||||
|
|
|
@ -1596,7 +1596,7 @@ class Minion(MinionBase):
|
|||
|
||||
sdata = {'pid': os.getpid()}
|
||||
sdata.update(data)
|
||||
log.info('Starting a new job with PID %s', sdata['pid'])
|
||||
log.info('Starting a new job %s with PID %s', data['jid'], sdata['pid'])
|
||||
with salt.utils.files.fopen(fn_, 'w+b') as fp_:
|
||||
fp_.write(minion_instance.serial.dumps(sdata))
|
||||
ret = {'success': False}
|
||||
|
|
|
@ -400,9 +400,9 @@ def update_distribution(
|
|||
keyid=keyid,
|
||||
profile=profile
|
||||
)
|
||||
if 'error' in distribution_result:
|
||||
return distribution_result
|
||||
dist_with_tags = distribution_result['result']
|
||||
if 'error' in distribution_ret:
|
||||
return distribution_ret
|
||||
dist_with_tags = distribution_ret['result']
|
||||
|
||||
current_distribution = dist_with_tags['distribution']
|
||||
current_config = current_distribution['DistributionConfig']
|
||||
|
|
|
@ -217,7 +217,7 @@ def get(consul_url=None, key=None, token=None, recurse=False, decode=False, raw=
|
|||
if ret['res']:
|
||||
if decode:
|
||||
for item in ret['data']:
|
||||
if item['Value'] != None:
|
||||
if item['Value'] is not None:
|
||||
item['Value'] = base64.b64decode(item['Value'])
|
||||
else:
|
||||
item['Value'] = ""
|
||||
|
|
|
@ -420,7 +420,9 @@ def get_url(path, dest='', saltenv='base', makedirs=False, source_hash=None):
|
|||
result = _client().get_url(
|
||||
path, None, makedirs, saltenv, no_cache=True, source_hash=source_hash)
|
||||
if not result:
|
||||
log.error('Unable to fetch file %s from saltenv %s.', path, saltenv)
|
||||
log.error('Unable to fetch file %s from saltenv %s.',
|
||||
salt.utils.url.redact_http_basic_auth(path),
|
||||
saltenv)
|
||||
return result
|
||||
|
||||
|
||||
|
|
|
@ -4119,7 +4119,7 @@ def get_managed(
|
|||
msg = (
|
||||
'Unable to verify upstream hash of source file {0}, '
|
||||
'please set source_hash or set skip_verify to True'
|
||||
.format(source)
|
||||
.format(salt.utils.url.redact_http_basic_auth(source))
|
||||
)
|
||||
return '', {}, msg
|
||||
|
||||
|
@ -4151,12 +4151,14 @@ def get_managed(
|
|||
except Exception as exc:
|
||||
# A 404 or other error code may raise an exception, catch it
|
||||
# and return a comment that will fail the calling state.
|
||||
return '', {}, 'Failed to cache {0}: {1}'.format(source, exc)
|
||||
_source = salt.utils.url.redact_http_basic_auth(source)
|
||||
return '', {}, 'Failed to cache {0}: {1}'.format(_source, exc)
|
||||
|
||||
# If cache failed, sfn will be False, so do a truth check on sfn first
|
||||
# as invoking os.path.exists() on a bool raises a TypeError.
|
||||
if not sfn or not os.path.exists(sfn):
|
||||
return sfn, {}, 'Source file \'{0}\' not found'.format(source)
|
||||
_source = salt.utils.url.redact_http_basic_auth(source)
|
||||
return sfn, {}, 'Source file \'{0}\' not found'.format(_source)
|
||||
if sfn == name:
|
||||
raise SaltInvocationError(
|
||||
'Source file cannot be the same as destination'
|
||||
|
|
|
@ -1035,11 +1035,8 @@ def _parse_conf(conf_file=None, in_mem=False, family='ipv4'):
|
|||
if args[-1].startswith('-'):
|
||||
args.append('')
|
||||
parsed_args = []
|
||||
if sys.version.startswith('2.6'):
|
||||
(opts, leftover_args) = parser.parse_args(args)
|
||||
parsed_args = vars(opts)
|
||||
else:
|
||||
parsed_args = vars(parser.parse_args(args))
|
||||
opts, _ = parser.parse_known_args(args)
|
||||
parsed_args = vars(opts)
|
||||
ret_args = {}
|
||||
chain = parsed_args['append']
|
||||
for arg in parsed_args:
|
||||
|
|
|
@ -402,18 +402,14 @@ def add(connect_spec, dn, attributes):
|
|||
# convert the "iterable of values" to lists in case that's what
|
||||
# addModlist() expects (also to ensure that the caller's objects
|
||||
# are not modified)
|
||||
attributes = dict(((attr, list(vals))
|
||||
attributes = dict(((attr, salt.utils.data.encode(list(vals)))
|
||||
for attr, vals in six.iteritems(attributes)))
|
||||
log.info('adding entry: dn: %s attributes: %s', repr(dn), repr(attributes))
|
||||
|
||||
if 'unicodePwd' in attributes:
|
||||
attributes['unicodePwd'] = [_format_unicode_password(x) for x in attributes['unicodePwd']]
|
||||
|
||||
modlist = salt.utils.data.decode(
|
||||
ldap.modlist.addModlist(attributes),
|
||||
to_str=True,
|
||||
preserve_tuples=True
|
||||
)
|
||||
modlist = ldap.modlist.addModlist(attributes),
|
||||
try:
|
||||
l.c.add_s(dn, modlist)
|
||||
except ldap.LDAPError as e:
|
||||
|
@ -572,19 +568,16 @@ def change(connect_spec, dn, before, after):
|
|||
# convert the "iterable of values" to lists in case that's what
|
||||
# modifyModlist() expects (also to ensure that the caller's dicts
|
||||
# are not modified)
|
||||
before = dict(((attr, list(vals))
|
||||
before = dict(((attr, salt.utils.data.encode(list(vals)))
|
||||
for attr, vals in six.iteritems(before)))
|
||||
after = dict(((attr, list(vals))
|
||||
after = dict(((attr, salt.utils.data.encode(list(vals)))
|
||||
for attr, vals in six.iteritems(after)))
|
||||
|
||||
if 'unicodePwd' in after:
|
||||
after['unicodePwd'] = [_format_unicode_password(x) for x in after['unicodePwd']]
|
||||
|
||||
modlist = salt.utils.data.decode(
|
||||
ldap.modlist.modifyModlist(before, after),
|
||||
to_str=True,
|
||||
preserve_tuples=True
|
||||
)
|
||||
modlist = ldap.modlist.modifyModlist(before, after)
|
||||
|
||||
try:
|
||||
l.c.modify_s(dn, modlist)
|
||||
except ldap.LDAPError as e:
|
||||
|
|
|
@ -4689,7 +4689,7 @@ def get_pid(name, path=None):
|
|||
if name not in list_(limit='running', path=path):
|
||||
raise CommandExecutionError('Container {0} is not running, can\'t determine PID'.format(name))
|
||||
info = __salt__['cmd.run']('lxc-info -n {0}'.format(name)).split("\n")
|
||||
pid = [line.split(':')[1].strip() for line in info if re.match(r'\s*PID', line) != None][0]
|
||||
pid = [line.split(':')[1].strip() for line in info if re.match(r'\s*PID', line) is not None][0]
|
||||
return pid
|
||||
|
||||
|
||||
|
|
|
@ -175,7 +175,7 @@ def db_remove(database_name, **kwargs):
|
|||
salt minion mssql.db_remove database_name='DBNAME'
|
||||
'''
|
||||
try:
|
||||
if db_exists(database_name) and database_name not in ['master', 'model', 'msdb', 'tempdb']:
|
||||
if db_exists(database_name, **kwargs) and database_name not in ['master', 'model', 'msdb', 'tempdb']:
|
||||
conn = _get_connection(**kwargs)
|
||||
conn.autocommit(True)
|
||||
cur = conn.cursor()
|
||||
|
|
|
@ -35,7 +35,6 @@ Module to provide MySQL compatibility to salt.
|
|||
|
||||
# Import python libs
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
import hashlib
|
||||
import time
|
||||
import logging
|
||||
import re
|
||||
|
@ -201,12 +200,6 @@ def __virtual__():
|
|||
return bool(MySQLdb), 'No python mysql client installed.' if MySQLdb is None else ''
|
||||
|
||||
|
||||
def __mysql_hash_password(password):
|
||||
_password = hashlib.sha1(password).digest()
|
||||
_password = '*{0}'.format(hashlib.sha1(_password).hexdigest().upper())
|
||||
return _password
|
||||
|
||||
|
||||
def __check_table(name, table, **connection_args):
|
||||
dbc = _connect(**connection_args)
|
||||
if dbc is None:
|
||||
|
@ -1208,6 +1201,7 @@ def user_exists(user,
|
|||
salt '*' mysql.user_exists 'username' passwordless=True
|
||||
salt '*' mysql.user_exists 'username' password_column='authentication_string'
|
||||
'''
|
||||
run_verify = False
|
||||
server_version = version(**connection_args)
|
||||
dbc = _connect(**connection_args)
|
||||
# Did we fail to connect with the user we are checking
|
||||
|
@ -1240,18 +1234,19 @@ def user_exists(user,
|
|||
else:
|
||||
qry += ' AND ' + password_column + ' = \'\''
|
||||
elif password:
|
||||
if salt.utils.versions.version_cmp(server_version, '8.0.11') <= 0:
|
||||
# Hash the password before comparing
|
||||
_password = __mysql_hash_password(password)
|
||||
qry += ' AND ' + password_column + ' = %(password)s'
|
||||
if salt.utils.versions.version_cmp(server_version, '8.0.11') >= 0:
|
||||
run_verify = True
|
||||
else:
|
||||
_password = password
|
||||
qry += ' AND ' + password_column + ' = PASSWORD(%(password)s)'
|
||||
args['password'] = six.text_type(_password)
|
||||
args['password'] = six.text_type(_password)
|
||||
elif password_hash:
|
||||
qry += ' AND ' + password_column + ' = %(password)s'
|
||||
args['password'] = password_hash
|
||||
|
||||
if run_verify:
|
||||
if not verify_login(user, host, password):
|
||||
return False
|
||||
try:
|
||||
_execute(cur, qry, args)
|
||||
except MySQLdb.OperationalError as exc:
|
||||
|
@ -1366,7 +1361,7 @@ def user_create(user,
|
|||
qry += ' IDENTIFIED BY %(password)s'
|
||||
args['password'] = six.text_type(password)
|
||||
elif password_hash is not None:
|
||||
if salt.utils.versions.version_cmp(server_version, '8.0.11') <= 0:
|
||||
if salt.utils.versions.version_cmp(server_version, '8.0.11') >= 0:
|
||||
qry += ' IDENTIFIED BY %(password)s'
|
||||
else:
|
||||
qry += ' IDENTIFIED BY PASSWORD %(password)s'
|
||||
|
@ -1452,7 +1447,7 @@ def user_chpass(user,
|
|||
server_version = version(**connection_args)
|
||||
args = {}
|
||||
if password is not None:
|
||||
if salt.utils.versions.version_cmp(server_version, '8.0.11') <= 0:
|
||||
if salt.utils.versions.version_cmp(server_version, '8.0.11') >= 0:
|
||||
password_sql = '%(password)s'
|
||||
else:
|
||||
password_sql = 'PASSWORD(%(password)s)'
|
||||
|
@ -1475,18 +1470,28 @@ def user_chpass(user,
|
|||
password_column = __password_column(**connection_args)
|
||||
|
||||
cur = dbc.cursor()
|
||||
qry = ('UPDATE mysql.user SET ' + password_column + '='
|
||||
+ password_sql +
|
||||
' WHERE User=%(user)s AND Host = %(host)s;')
|
||||
args['user'] = user
|
||||
args['host'] = host
|
||||
if salt.utils.versions.version_cmp(server_version, '8.0.11') >= 0:
|
||||
qry = ("ALTER USER '" + user + "'@'" + host + "'"
|
||||
" IDENTIFIED BY '" + password + "';")
|
||||
args = {}
|
||||
else:
|
||||
qry = ('UPDATE mysql.user SET ' + password_column + '='
|
||||
+ password_sql +
|
||||
' WHERE User=%(user)s AND Host = %(host)s;')
|
||||
args['user'] = user
|
||||
args['host'] = host
|
||||
if salt.utils.data.is_true(allow_passwordless) and \
|
||||
salt.utils.data.is_true(unix_socket):
|
||||
if host == 'localhost':
|
||||
qry = ('UPDATE mysql.user SET ' + password_column + '='
|
||||
+ password_sql + ', plugin=%(unix_socket)s' +
|
||||
' WHERE User=%(user)s AND Host = %(host)s;')
|
||||
args['unix_socket'] = 'unix_socket'
|
||||
if salt.utils.versions.version_cmp(server_version, '8.0.11') >= 0:
|
||||
qry = ("ALTER USER '" + user + "'@'" + host + "'"
|
||||
" IDENTIFIED BY '" + password + "';")
|
||||
args = {}
|
||||
else:
|
||||
qry = ('UPDATE mysql.user SET ' + password_column + '='
|
||||
+ password_sql + ', plugin=%(unix_socket)s' +
|
||||
' WHERE User=%(user)s AND Host = %(host)s;')
|
||||
args['unix_socket'] = 'unix_socket'
|
||||
else:
|
||||
log.error('Auth via unix_socket can be set only for host=localhost')
|
||||
try:
|
||||
|
@ -1497,7 +1502,7 @@ def user_chpass(user,
|
|||
log.error(err)
|
||||
return False
|
||||
|
||||
if result:
|
||||
if salt.utils.versions.version_cmp(server_version, '8.0.11') >= 0:
|
||||
_execute(cur, 'FLUSH PRIVILEGES;')
|
||||
log.info(
|
||||
'Password for user \'%s\'@\'%s\' has been %s',
|
||||
|
@ -1505,6 +1510,15 @@ def user_chpass(user,
|
|||
'changed' if any((password, password_hash)) else 'cleared'
|
||||
)
|
||||
return True
|
||||
else:
|
||||
if result:
|
||||
_execute(cur, 'FLUSH PRIVILEGES;')
|
||||
log.info(
|
||||
'Password for user \'%s\'@\'%s\' has been %s',
|
||||
user, host,
|
||||
'changed' if any((password, password_hash)) else 'cleared'
|
||||
)
|
||||
return True
|
||||
|
||||
log.info(
|
||||
'Password for user \'%s\'@\'%s\' was not %s',
|
||||
|
@ -1973,17 +1987,20 @@ def processlist(**connection_args):
|
|||
"SHOW FULL PROCESSLIST".
|
||||
|
||||
Returns: a list of dicts, with each dict representing a process:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
{'Command': 'Query',
|
||||
'Host': 'localhost',
|
||||
'Id': 39,
|
||||
'Info': 'SHOW FULL PROCESSLIST',
|
||||
'Rows_examined': 0,
|
||||
'Rows_read': 1,
|
||||
'Rows_sent': 0,
|
||||
'State': None,
|
||||
'Time': 0,
|
||||
'User': 'root',
|
||||
'db': 'mysql'}
|
||||
'Host': 'localhost',
|
||||
'Id': 39,
|
||||
'Info': 'SHOW FULL PROCESSLIST',
|
||||
'Rows_examined': 0,
|
||||
'Rows_read': 1,
|
||||
'Rows_sent': 0,
|
||||
'State': None,
|
||||
'Time': 0,
|
||||
'User': 'root',
|
||||
'db': 'mysql'}
|
||||
|
||||
CLI Example:
|
||||
|
||||
|
@ -2214,3 +2231,29 @@ def showglobal(**connection_args):
|
|||
|
||||
log.debug('%s-->%s', mod, len(rtnv[0]))
|
||||
return rtnv
|
||||
|
||||
|
||||
def verify_login(user, host='localhost', password=None, **connection_args):
|
||||
'''
|
||||
Attempt to login using the provided credentials.
|
||||
If successful, return true. Otherwise, return False.
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' mysql.verify_login root localhost password
|
||||
'''
|
||||
# Override the connection args
|
||||
connection_args['connection_user'] = user
|
||||
connection_args['connection_host'] = host
|
||||
connection_args['connection_pass'] = password
|
||||
|
||||
dbc = _connect(**connection_args)
|
||||
if dbc is None:
|
||||
# Clear the mysql.error if unable to connect
|
||||
# if the connection fails, we simply return False
|
||||
if 'mysql.error' in __context__:
|
||||
del __context__['mysql.error']
|
||||
return False
|
||||
return True
|
||||
|
|
|
@ -35,7 +35,7 @@ import fnmatch # do not remove, used in imported file.py functions
|
|||
import mmap # do not remove, used in imported file.py functions
|
||||
import glob # do not remove, used in imported file.py functions
|
||||
# do not remove, used in imported file.py functions
|
||||
import salt.ext.six as six # pylint: disable=import-error,no-name-in-module
|
||||
from salt.ext import six
|
||||
from salt.ext.six.moves.urllib.parse import urlparse as _urlparse # pylint: disable=import-error,no-name-in-module
|
||||
import salt.utils.atomicfile # do not remove, used in imported file.py functions
|
||||
from salt.exceptions import CommandExecutionError, SaltInvocationError
|
||||
|
|
|
@ -5010,7 +5010,7 @@ def _writeAdminTemplateRegPolFile(admtemplate_data,
|
|||
adml_policy_resources=None,
|
||||
display_language='en-US',
|
||||
registry_class='Machine'):
|
||||
u'''
|
||||
r'''
|
||||
helper function to prep/write adm template data to the Registry.pol file
|
||||
|
||||
each file begins with REGFILE_SIGNATURE (u'\u5250\u6765') and
|
||||
|
|
|
@ -699,7 +699,6 @@ def refresh_db(**kwargs):
|
|||
include_pat='*.sls',
|
||||
exclude_pat=r'E@\/\..*?\/' # Exclude all hidden directories (.git)
|
||||
)
|
||||
|
||||
return genrepo(saltenv=saltenv, verbose=verbose, failhard=failhard)
|
||||
|
||||
|
||||
|
|
|
@ -345,8 +345,6 @@ class Pillar(object):
|
|||
if pillarenv is None:
|
||||
if opts.get('pillarenv_from_saltenv', False):
|
||||
opts['pillarenv'] = saltenv
|
||||
# Store the file_roots path so we can restore later. Issue 5449
|
||||
self.actual_file_roots = opts['file_roots']
|
||||
# use the local file client
|
||||
self.opts = self.__gen_opts(opts, grains, saltenv=saltenv, pillarenv=pillarenv)
|
||||
self.saltenv = saltenv
|
||||
|
@ -369,9 +367,6 @@ class Pillar(object):
|
|||
self.matchers = salt.loader.matchers(self.opts)
|
||||
self.rend = salt.loader.render(self.opts, self.functions)
|
||||
ext_pillar_opts = copy.deepcopy(self.opts)
|
||||
# Fix self.opts['file_roots'] so that ext_pillars know the real
|
||||
# location of file_roots. Issue 5951
|
||||
ext_pillar_opts['file_roots'] = self.actual_file_roots
|
||||
# Keep the incoming opts ID intact, ie, the master id
|
||||
if 'id' in opts:
|
||||
ext_pillar_opts['id'] = opts['id']
|
||||
|
@ -438,7 +433,6 @@ class Pillar(object):
|
|||
The options need to be altered to conform to the file client
|
||||
'''
|
||||
opts = copy.deepcopy(opts_in)
|
||||
opts['file_roots'] = opts['pillar_roots']
|
||||
opts['file_client'] = 'local'
|
||||
if not grains:
|
||||
opts['grains'] = {}
|
||||
|
@ -463,22 +457,25 @@ class Pillar(object):
|
|||
opts['ext_pillar'].append(self.ext)
|
||||
else:
|
||||
opts['ext_pillar'] = [self.ext]
|
||||
if '__env__' in opts['file_roots']:
|
||||
if '__env__' in opts['pillar_roots']:
|
||||
env = opts.get('pillarenv') or opts.get('saltenv') or 'base'
|
||||
if env not in opts['file_roots']:
|
||||
if env not in opts['pillar_roots']:
|
||||
log.debug("pillar environment '%s' maps to __env__ pillar_roots directory", env)
|
||||
opts['file_roots'][env] = opts['file_roots'].pop('__env__')
|
||||
opts['pillar_roots'][env] = opts['pillar_roots'].pop('__env__')
|
||||
else:
|
||||
log.debug("pillar_roots __env__ ignored (environment '%s' found in pillar_roots)",
|
||||
env)
|
||||
opts['file_roots'].pop('__env__')
|
||||
opts['pillar_roots'].pop('__env__')
|
||||
return opts
|
||||
|
||||
def _get_envs(self):
|
||||
'''
|
||||
Pull the file server environments out of the master options
|
||||
'''
|
||||
return set(['base']) | set(self.opts.get('file_roots', []))
|
||||
envs = set(['base'])
|
||||
if 'pillar_roots' in self.opts:
|
||||
envs.update(list(self.opts['pillar_roots']))
|
||||
return envs
|
||||
|
||||
def get_tops(self):
|
||||
'''
|
||||
|
@ -494,11 +491,11 @@ class Pillar(object):
|
|||
if self.opts['pillarenv']:
|
||||
# If the specified pillarenv is not present in the available
|
||||
# pillar environments, do not cache the pillar top file.
|
||||
if self.opts['pillarenv'] not in self.opts['file_roots']:
|
||||
if self.opts['pillarenv'] not in self.opts['pillar_roots']:
|
||||
log.debug(
|
||||
'pillarenv \'%s\' not found in the configured pillar '
|
||||
'environments (%s)',
|
||||
self.opts['pillarenv'], ', '.join(self.opts['file_roots'])
|
||||
self.opts['pillarenv'], ', '.join(self.opts['pillar_roots'])
|
||||
)
|
||||
else:
|
||||
saltenvs.add(self.opts['pillarenv'])
|
||||
|
@ -1002,8 +999,6 @@ class Pillar(object):
|
|||
mopts = dict(self.opts)
|
||||
if 'grains' in mopts:
|
||||
mopts.pop('grains')
|
||||
# Restore the actual file_roots path. Issue 5449
|
||||
mopts['file_roots'] = self.actual_file_roots
|
||||
mopts['saltversion'] = __version__
|
||||
pillar['master'] = mopts
|
||||
if 'pillar' in self.opts and self.opts.get('ssh_merge_pillar', False):
|
||||
|
@ -1030,10 +1025,6 @@ class Pillar(object):
|
|||
if decrypt_errors:
|
||||
pillar.setdefault('_errors', []).extend(decrypt_errors)
|
||||
|
||||
# Reset the file_roots for the renderers
|
||||
for mod_name in sys.modules:
|
||||
if mod_name.startswith('salt.loaded.int.render.'):
|
||||
sys.modules[mod_name].__opts__['file_roots'] = self.actual_file_roots
|
||||
return pillar
|
||||
|
||||
def decrypt_pillar(self, pillar):
|
||||
|
|
|
@ -156,6 +156,7 @@ import salt.utils.files
|
|||
import salt.utils.minions
|
||||
import salt.utils.path
|
||||
import salt.utils.stringio
|
||||
import salt.utils.stringutils
|
||||
import salt.template
|
||||
from salt.ext import six
|
||||
|
||||
|
@ -251,7 +252,7 @@ def _construct_pillar(top_dir,
|
|||
else:
|
||||
data = contents
|
||||
if template is True:
|
||||
data = salt.template.compile_template_str(template=contents,
|
||||
data = salt.template.compile_template_str(template=salt.utils.stringutils.to_unicode(contents),
|
||||
renderers=renderers,
|
||||
default=render_default,
|
||||
blacklist=renderer_blacklist,
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
SaltClass Pillar Module
|
||||
=======================
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
ext_pillar:
|
||||
- saltclass:
|
||||
- path: /srv/saltclass
|
||||
ext_pillar:
|
||||
- saltclass:
|
||||
- path: /srv/saltclass
|
||||
|
||||
For additional configuration instructions, see the :mod:`saltclass <salt.tops.saltclass>` module
|
||||
'''
|
||||
|
||||
# import python libs
|
||||
|
|
|
@ -95,6 +95,8 @@ class SPMClient(object):
|
|||
self.files_prov = self.opts.get('spm_files_provider', 'local')
|
||||
self._prep_pkgdb()
|
||||
self._prep_pkgfiles()
|
||||
self.db_conn = None
|
||||
self.files_conn = None
|
||||
self._init()
|
||||
|
||||
def _prep_pkgdb(self):
|
||||
|
@ -104,8 +106,14 @@ class SPMClient(object):
|
|||
self.pkgfiles = salt.loader.pkgfiles(self.opts)
|
||||
|
||||
def _init(self):
|
||||
self.db_conn = self._pkgdb_fun('init')
|
||||
self.files_conn = self._pkgfiles_fun('init')
|
||||
if not self.db_conn:
|
||||
self.db_conn = self._pkgdb_fun('init')
|
||||
if not self.files_conn:
|
||||
self.files_conn = self._pkgfiles_fun('init')
|
||||
|
||||
def _close(self):
|
||||
if self.db_conn:
|
||||
self.db_conn.close()
|
||||
|
||||
def run(self, args):
|
||||
'''
|
||||
|
@ -133,6 +141,8 @@ class SPMClient(object):
|
|||
self._info(args)
|
||||
elif command == 'list':
|
||||
self._list(args)
|
||||
elif command == 'close':
|
||||
self._close()
|
||||
else:
|
||||
raise SPMInvocationError('Invalid command \'{0}\''.format(command))
|
||||
except SPMException as exc:
|
||||
|
@ -249,7 +259,7 @@ class SPMClient(object):
|
|||
if pkg.endswith('.spm'):
|
||||
if self._pkgfiles_fun('path_exists', pkg):
|
||||
comps = pkg.split('-')
|
||||
comps = '-'.join(comps[:-2]).split('/')
|
||||
comps = os.path.split('-'.join(comps[:-2]))
|
||||
pkg_name = comps[-1]
|
||||
|
||||
formula_tar = tarfile.open(pkg, 'r:bz2')
|
||||
|
@ -265,6 +275,7 @@ class SPMClient(object):
|
|||
to_install.extend(to_)
|
||||
optional.extend(op_)
|
||||
recommended.extend(re_)
|
||||
formula_tar.close()
|
||||
else:
|
||||
raise SPMInvocationError('Package file {0} not found'.format(pkg))
|
||||
else:
|
||||
|
@ -901,6 +912,7 @@ class SPMClient(object):
|
|||
formula_def = salt.utils.yaml.safe_load(formula_ref)
|
||||
|
||||
self.ui.status(self._get_info(formula_def))
|
||||
formula_tar.close()
|
||||
|
||||
def _info(self, args):
|
||||
'''
|
||||
|
|
|
@ -73,7 +73,9 @@ def info(package, conn=None):
|
|||
'''
|
||||
List info for a package
|
||||
'''
|
||||
close = False
|
||||
if conn is None:
|
||||
close = True
|
||||
conn = init()
|
||||
|
||||
fields = (
|
||||
|
@ -94,6 +96,8 @@ def info(package, conn=None):
|
|||
(package, )
|
||||
)
|
||||
row = data.fetchone()
|
||||
if close:
|
||||
conn.close()
|
||||
if not row:
|
||||
return None
|
||||
|
||||
|
@ -107,7 +111,9 @@ def list_packages(conn=None):
|
|||
'''
|
||||
List files for an installed package
|
||||
'''
|
||||
close = False
|
||||
if conn is None:
|
||||
close = True
|
||||
conn = init()
|
||||
|
||||
ret = []
|
||||
|
@ -115,6 +121,8 @@ def list_packages(conn=None):
|
|||
for pkg in data.fetchall():
|
||||
ret.append(pkg)
|
||||
|
||||
if close:
|
||||
conn.close()
|
||||
return ret
|
||||
|
||||
|
||||
|
@ -122,17 +130,23 @@ def list_files(package, conn=None):
|
|||
'''
|
||||
List files for an installed package
|
||||
'''
|
||||
close = False
|
||||
if conn is None:
|
||||
close = True
|
||||
conn = init()
|
||||
|
||||
data = conn.execute('SELECT package FROM packages WHERE package=?', (package, ))
|
||||
if not data.fetchone():
|
||||
if close:
|
||||
conn.close()
|
||||
return None
|
||||
|
||||
ret = []
|
||||
data = conn.execute('SELECT path, sum FROM files WHERE package=?', (package, ))
|
||||
for file_ in data.fetchall():
|
||||
ret.append(file_)
|
||||
if close:
|
||||
conn.close()
|
||||
|
||||
return ret
|
||||
|
||||
|
@ -141,7 +155,9 @@ def register_pkg(name, formula_def, conn=None):
|
|||
'''
|
||||
Register a package in the package database
|
||||
'''
|
||||
close = False
|
||||
if conn is None:
|
||||
close = True
|
||||
conn = init()
|
||||
|
||||
conn.execute('INSERT INTO packages VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)', (
|
||||
|
@ -157,13 +173,17 @@ def register_pkg(name, formula_def, conn=None):
|
|||
formula_def['summary'],
|
||||
formula_def['description'],
|
||||
))
|
||||
if close:
|
||||
conn.close()
|
||||
|
||||
|
||||
def register_file(name, member, path, digest='', conn=None):
|
||||
'''
|
||||
Register a file in the package database
|
||||
'''
|
||||
close = False
|
||||
if conn is None:
|
||||
close = True
|
||||
conn = init()
|
||||
|
||||
conn.execute('INSERT INTO files VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)', (
|
||||
|
@ -180,6 +200,8 @@ def register_file(name, member, path, digest='', conn=None):
|
|||
member.gname,
|
||||
member.mtime
|
||||
))
|
||||
if close:
|
||||
conn.close()
|
||||
|
||||
|
||||
def unregister_pkg(name, conn=None):
|
||||
|
@ -196,10 +218,14 @@ def unregister_file(path, pkg=None, conn=None): # pylint: disable=W0612
|
|||
'''
|
||||
Unregister a file from the package database
|
||||
'''
|
||||
close = False
|
||||
if conn is None:
|
||||
close = True
|
||||
conn = init()
|
||||
|
||||
conn.execute('DELETE FROM files WHERE path=?', (path, ))
|
||||
if close:
|
||||
conn.close()
|
||||
|
||||
|
||||
def db_exists(db_):
|
||||
|
|
|
@ -292,6 +292,12 @@ def mod_watch(name, **kwargs):
|
|||
'''
|
||||
The at watcher, called to invoke the watch command.
|
||||
|
||||
.. note::
|
||||
This state exists to support special handling of the ``watch``
|
||||
:ref:`requisite <requisites>`. It should not be called directly.
|
||||
|
||||
Parameters for this function should be set by the state being triggered.
|
||||
|
||||
name
|
||||
The name of the atjob
|
||||
|
||||
|
|
|
@ -1304,6 +1304,12 @@ def wait_call(name,
|
|||
def mod_watch(name, **kwargs):
|
||||
'''
|
||||
Execute a cmd function based on a watch call
|
||||
|
||||
.. note::
|
||||
This state exists to support special handling of the ``watch``
|
||||
:ref:`requisite <requisites>`. It should not be called directly.
|
||||
|
||||
Parameters for this function should be set by the state being triggered.
|
||||
'''
|
||||
if kwargs['sfun'] in ('wait', 'run', 'watch'):
|
||||
if kwargs.get('stateful'):
|
||||
|
|
|
@ -2614,6 +2614,15 @@ def mod_run_check(onlyif, unless, creates):
|
|||
|
||||
|
||||
def mod_watch(name, sfun=None, **kwargs):
|
||||
'''
|
||||
The docker_container watcher, called to invoke the watch command.
|
||||
|
||||
.. note::
|
||||
This state exists to support special handling of the ``watch``
|
||||
:ref:`requisite <requisites>`. It should not be called directly.
|
||||
|
||||
Parameters for this function should be set by the state being triggered.
|
||||
'''
|
||||
if sfun == 'running':
|
||||
watch_kwargs = copy.deepcopy(kwargs)
|
||||
if watch_kwargs.get('watch_action', 'force') == 'force':
|
||||
|
|
|
@ -503,6 +503,15 @@ def absent(name=None, images=None, force=False):
|
|||
|
||||
|
||||
def mod_watch(name, sfun=None, **kwargs):
|
||||
'''
|
||||
The docker_image watcher, called to invoke the watch command.
|
||||
|
||||
.. note::
|
||||
This state exists to support special handling of the ``watch``
|
||||
:ref:`requisite <requisites>`. It should not be called directly.
|
||||
|
||||
Parameters for this function should be set by the state being triggered.
|
||||
'''
|
||||
if sfun == 'present':
|
||||
# Force image to be updated
|
||||
kwargs['force'] = True
|
||||
|
|
|
@ -334,7 +334,14 @@ def wait_rm(name, recurse=False, profile=None, **kwargs):
|
|||
|
||||
def mod_watch(name, **kwargs):
|
||||
'''
|
||||
Execute a etcd function based on a watch call requisite.
|
||||
The etcd watcher, called to invoke the watch command.
|
||||
When called, execute a etcd function based on a watch call requisite.
|
||||
|
||||
.. note::
|
||||
This state exists to support special handling of the ``watch``
|
||||
:ref:`requisite <requisites>`. It should not be called directly.
|
||||
|
||||
Parameters for this function should be set by the state being triggered.
|
||||
'''
|
||||
|
||||
# Watch to set etcd key
|
||||
|
|
|
@ -392,55 +392,63 @@ def _present(name,
|
|||
{'old': zones,
|
||||
'new': name}})
|
||||
|
||||
block_icmp = block_icmp or []
|
||||
new_icmp_types = []
|
||||
old_icmp_types = []
|
||||
try:
|
||||
_valid_icmp_types = __salt__['firewalld.get_icmp_types'](
|
||||
permanent=True)
|
||||
_current_icmp_blocks = __salt__['firewalld.list_icmp_block'](name,
|
||||
permanent=True)
|
||||
except CommandExecutionError as err:
|
||||
ret['comment'] = 'Error: {0}'.format(err)
|
||||
return ret
|
||||
if block_icmp or prune_block_icmp:
|
||||
block_icmp = block_icmp or []
|
||||
new_icmp_types = []
|
||||
old_icmp_types = []
|
||||
|
||||
new_icmp_types = set(block_icmp) - set(_current_icmp_blocks)
|
||||
old_icmp_types = []
|
||||
try:
|
||||
_current_icmp_blocks = __salt__['firewalld.list_icmp_block'](name,
|
||||
permanent=True)
|
||||
except CommandExecutionError as err:
|
||||
ret['comment'] = 'Error: {0}'.format(err)
|
||||
return ret
|
||||
|
||||
for icmp_type in new_icmp_types:
|
||||
if icmp_type in _valid_icmp_types:
|
||||
if not __opts__['test']:
|
||||
try:
|
||||
__salt__['firewalld.block_icmp'](name, icmp_type,
|
||||
permanent=True)
|
||||
except CommandExecutionError as err:
|
||||
ret['comment'] = 'Error: {0}'.format(err)
|
||||
return ret
|
||||
else:
|
||||
log.error('%s is an invalid ICMP type', icmp_type)
|
||||
if block_icmp:
|
||||
try:
|
||||
_valid_icmp_types = __salt__['firewalld.get_icmp_types'](
|
||||
permanent=True)
|
||||
except CommandExecutionError as err:
|
||||
ret['comment'] = 'Error: {0}'.format(err)
|
||||
return ret
|
||||
|
||||
if prune_block_icmp:
|
||||
old_icmp_types = set(_current_icmp_blocks) - set(block_icmp)
|
||||
for icmp_type in old_icmp_types:
|
||||
# no need to check against _valid_icmp_types here, because all
|
||||
# elements in old_icmp_types are guaranteed to be in
|
||||
# _current_icmp_blocks, whose elements are inherently valid
|
||||
if not __opts__['test']:
|
||||
try:
|
||||
__salt__['firewalld.allow_icmp'](name, icmp_type,
|
||||
permanent=True)
|
||||
except CommandExecutionError as err:
|
||||
ret['comment'] = 'Error: {0}'.format(err)
|
||||
return ret
|
||||
# log errors for invalid ICMP types in block_icmp input
|
||||
for icmp_type in set(block_icmp) - set(_valid_icmp_types):
|
||||
log.error('%s is an invalid ICMP type', icmp_type)
|
||||
block_icmp.remove(icmp_type)
|
||||
|
||||
if new_icmp_types or old_icmp_types:
|
||||
# If we're not pruning, include current items in new output so it's clear
|
||||
# that they're still present
|
||||
if not prune_block_icmp:
|
||||
block_icmp = list(new_icmp_types | set(_current_icmp_blocks))
|
||||
ret['changes'].update({'icmp_types':
|
||||
{'old': _current_icmp_blocks,
|
||||
'new': block_icmp}})
|
||||
new_icmp_types = set(block_icmp) - set(_current_icmp_blocks)
|
||||
for icmp_type in new_icmp_types:
|
||||
if not __opts__['test']:
|
||||
try:
|
||||
__salt__['firewalld.block_icmp'](name, icmp_type,
|
||||
permanent=True)
|
||||
except CommandExecutionError as err:
|
||||
ret['comment'] = 'Error: {0}'.format(err)
|
||||
return ret
|
||||
|
||||
if prune_block_icmp:
|
||||
old_icmp_types = set(_current_icmp_blocks) - set(block_icmp)
|
||||
for icmp_type in old_icmp_types:
|
||||
# no need to check against _valid_icmp_types here, because all
|
||||
# elements in old_icmp_types are guaranteed to be in
|
||||
# _current_icmp_blocks, whose elements are inherently valid
|
||||
if not __opts__['test']:
|
||||
try:
|
||||
__salt__['firewalld.allow_icmp'](name, icmp_type,
|
||||
permanent=True)
|
||||
except CommandExecutionError as err:
|
||||
ret['comment'] = 'Error: {0}'.format(err)
|
||||
return ret
|
||||
|
||||
if new_icmp_types or old_icmp_types:
|
||||
# If we're not pruning, include current items in new output so it's clear
|
||||
# that they're still present
|
||||
if not prune_block_icmp:
|
||||
block_icmp = list(new_icmp_types | set(_current_icmp_blocks))
|
||||
ret['changes'].update({'icmp_types':
|
||||
{'old': _current_icmp_blocks,
|
||||
'new': block_icmp}})
|
||||
|
||||
# that's the only parameter that can't be permanent or runtime, it's
|
||||
# directly both
|
||||
|
@ -461,292 +469,290 @@ def _present(name,
|
|||
{'old': default_zone,
|
||||
'new': name}})
|
||||
|
||||
if masquerade:
|
||||
try:
|
||||
masquerade_ret = __salt__['firewalld.get_masquerade'](name,
|
||||
permanent=True)
|
||||
except CommandExecutionError as err:
|
||||
ret['comment'] = 'Error: {0}'.format(err)
|
||||
return ret
|
||||
if not masquerade_ret:
|
||||
if not __opts__['test']:
|
||||
try:
|
||||
__salt__['firewalld.add_masquerade'](name, permanent=True)
|
||||
except CommandExecutionError as err:
|
||||
ret['comment'] = 'Error: {0}'.format(err)
|
||||
return ret
|
||||
ret['changes'].update({'masquerade':
|
||||
{'old': '',
|
||||
'new': 'Masquerading successfully set.'}})
|
||||
|
||||
if not masquerade:
|
||||
try:
|
||||
masquerade_ret = __salt__['firewalld.get_masquerade'](name,
|
||||
permanent=True)
|
||||
except CommandExecutionError as err:
|
||||
ret['comment'] = 'Error: {0}'.format(err)
|
||||
return ret
|
||||
if masquerade_ret:
|
||||
if not __opts__['test']:
|
||||
try:
|
||||
__salt__['firewalld.remove_masquerade'](name,
|
||||
permanent=True)
|
||||
except CommandExecutionError as err:
|
||||
ret['comment'] = 'Error: {0}'.format(err)
|
||||
return ret
|
||||
ret['changes'].update({'masquerade':
|
||||
{'old': '',
|
||||
'new': 'Masquerading successfully '
|
||||
'disabled.'}})
|
||||
|
||||
ports = ports or []
|
||||
try:
|
||||
_current_ports = __salt__['firewalld.list_ports'](name, permanent=True)
|
||||
except CommandExecutionError as err:
|
||||
ret['comment'] = 'Error: {0}'.format(err)
|
||||
return ret
|
||||
|
||||
new_ports = set(ports) - set(_current_ports)
|
||||
old_ports = []
|
||||
|
||||
for port in new_ports:
|
||||
if not __opts__['test']:
|
||||
try:
|
||||
# TODO: force_masquerade to be removed in future release
|
||||
__salt__['firewalld.add_port'](name, port, permanent=True, force_masquerade=False)
|
||||
except CommandExecutionError as err:
|
||||
ret['comment'] = 'Error: {0}'.format(err)
|
||||
return ret
|
||||
|
||||
if prune_ports:
|
||||
old_ports = set(_current_ports) - set(ports)
|
||||
for port in old_ports:
|
||||
if not __opts__['test']:
|
||||
try:
|
||||
__salt__['firewalld.remove_port'](name, port, permanent=True)
|
||||
except CommandExecutionError as err:
|
||||
ret['comment'] = 'Error: {0}'.format(err)
|
||||
return ret
|
||||
|
||||
if new_ports or old_ports:
|
||||
# If we're not pruning, include current items in new output so it's clear
|
||||
# that they're still present
|
||||
if not prune_ports:
|
||||
ports = list(new_ports | set(_current_ports))
|
||||
ret['changes'].update({'ports':
|
||||
{'old': _current_ports,
|
||||
'new': ports}})
|
||||
|
||||
port_fwd = port_fwd or []
|
||||
try:
|
||||
_current_port_fwd = __salt__['firewalld.list_port_fwd'](name,
|
||||
permanent=True)
|
||||
except CommandExecutionError as err:
|
||||
ret['comment'] = 'Error: {0}'.format(err)
|
||||
return ret
|
||||
|
||||
port_fwd = [_parse_forward(fwd) for fwd in port_fwd]
|
||||
_current_port_fwd = [
|
||||
ForwardingMapping(
|
||||
srcport=fwd['Source port'],
|
||||
destport=fwd['Destination port'],
|
||||
protocol=fwd['Protocol'],
|
||||
destaddr=fwd['Destination address']
|
||||
) for fwd in _current_port_fwd]
|
||||
|
||||
new_port_fwd = set(port_fwd) - set(_current_port_fwd)
|
||||
old_port_fwd = []
|
||||
|
||||
for fwd in new_port_fwd:
|
||||
if not __opts__['test']:
|
||||
try:
|
||||
# TODO: force_masquerade to be removed in future release
|
||||
__salt__['firewalld.add_port_fwd'](name, fwd.srcport,
|
||||
fwd.destport, fwd.protocol, fwd.destaddr, permanent=True,
|
||||
force_masquerade=False)
|
||||
except CommandExecutionError as err:
|
||||
ret['comment'] = 'Error: {0}'.format(err)
|
||||
return ret
|
||||
|
||||
if prune_port_fwd:
|
||||
old_port_fwd = set(_current_port_fwd) - set(port_fwd)
|
||||
for fwd in old_port_fwd:
|
||||
if not __opts__['test']:
|
||||
try:
|
||||
__salt__['firewalld.remove_port_fwd'](name, fwd.srcport,
|
||||
fwd.destport, fwd.protocol, fwd.destaddr, permanent=True)
|
||||
except CommandExecutionError as err:
|
||||
ret['comment'] = 'Error: {0}'.format(err)
|
||||
return ret
|
||||
|
||||
if new_port_fwd or old_port_fwd:
|
||||
# If we're not pruning, include current items in new output so it's clear
|
||||
# that they're still present
|
||||
if not prune_port_fwd:
|
||||
port_fwd = list(new_port_fwd | set(_current_port_fwd))
|
||||
ret['changes'].update({'port_fwd':
|
||||
{'old': [fwd.todict() for fwd in
|
||||
_current_port_fwd],
|
||||
'new': [fwd.todict() for fwd in port_fwd]}})
|
||||
|
||||
services = services or []
|
||||
try:
|
||||
_current_services = __salt__['firewalld.list_services'](name,
|
||||
masquerade_ret = __salt__['firewalld.get_masquerade'](name,
|
||||
permanent=True)
|
||||
except CommandExecutionError as err:
|
||||
ret['comment'] = 'Error: {0}'.format(err)
|
||||
return ret
|
||||
|
||||
new_services = set(services) - set(_current_services)
|
||||
old_services = []
|
||||
|
||||
for new_service in new_services:
|
||||
if masquerade and not masquerade_ret:
|
||||
if not __opts__['test']:
|
||||
try:
|
||||
__salt__['firewalld.add_service'](new_service, name,
|
||||
permanent=True)
|
||||
__salt__['firewalld.add_masquerade'](name, permanent=True)
|
||||
except CommandExecutionError as err:
|
||||
ret['comment'] = 'Error: {0}'.format(err)
|
||||
return ret
|
||||
ret['changes'].update({'masquerade':
|
||||
{'old': '',
|
||||
'new': 'Masquerading successfully set.'}})
|
||||
elif not masquerade and masquerade_ret:
|
||||
if not __opts__['test']:
|
||||
try:
|
||||
__salt__['firewalld.remove_masquerade'](name,
|
||||
permanent=True)
|
||||
except CommandExecutionError as err:
|
||||
ret['comment'] = 'Error: {0}'.format(err)
|
||||
return ret
|
||||
ret['changes'].update({'masquerade':
|
||||
{'old': '',
|
||||
'new': 'Masquerading successfully '
|
||||
'disabled.'}})
|
||||
|
||||
if prune_services:
|
||||
old_services = set(_current_services) - set(services)
|
||||
for old_service in old_services:
|
||||
if ports or prune_ports:
|
||||
ports = ports or []
|
||||
try:
|
||||
_current_ports = __salt__['firewalld.list_ports'](name, permanent=True)
|
||||
except CommandExecutionError as err:
|
||||
ret['comment'] = 'Error: {0}'.format(err)
|
||||
return ret
|
||||
|
||||
new_ports = set(ports) - set(_current_ports)
|
||||
old_ports = []
|
||||
|
||||
for port in new_ports:
|
||||
if not __opts__['test']:
|
||||
try:
|
||||
__salt__['firewalld.remove_service'](old_service, name,
|
||||
permanent=True)
|
||||
# TODO: force_masquerade to be removed in future release
|
||||
__salt__['firewalld.add_port'](name, port, permanent=True, force_masquerade=False)
|
||||
except CommandExecutionError as err:
|
||||
ret['comment'] = 'Error: {0}'.format(err)
|
||||
return ret
|
||||
|
||||
if new_services or old_services:
|
||||
# If we're not pruning, include current items in new output so it's clear
|
||||
# that they're still present
|
||||
if not prune_services:
|
||||
services = list(new_services | set(_current_services))
|
||||
ret['changes'].update({'services':
|
||||
{'old': _current_services,
|
||||
'new': services}})
|
||||
if prune_ports:
|
||||
old_ports = set(_current_ports) - set(ports)
|
||||
for port in old_ports:
|
||||
if not __opts__['test']:
|
||||
try:
|
||||
__salt__['firewalld.remove_port'](name, port, permanent=True)
|
||||
except CommandExecutionError as err:
|
||||
ret['comment'] = 'Error: {0}'.format(err)
|
||||
return ret
|
||||
|
||||
interfaces = interfaces or []
|
||||
try:
|
||||
_current_interfaces = __salt__['firewalld.get_interfaces'](name,
|
||||
permanent=True)
|
||||
except CommandExecutionError as err:
|
||||
ret['comment'] = 'Error: {0}'.format(err)
|
||||
return ret
|
||||
if new_ports or old_ports:
|
||||
# If we're not pruning, include current items in new output so it's clear
|
||||
# that they're still present
|
||||
if not prune_ports:
|
||||
ports = list(new_ports | set(_current_ports))
|
||||
ret['changes'].update({'ports':
|
||||
{'old': _current_ports,
|
||||
'new': ports}})
|
||||
|
||||
new_interfaces = set(interfaces) - set(_current_interfaces)
|
||||
old_interfaces = []
|
||||
if port_fwd or prune_port_fwd:
|
||||
port_fwd = port_fwd or []
|
||||
try:
|
||||
_current_port_fwd = __salt__['firewalld.list_port_fwd'](name,
|
||||
permanent=True)
|
||||
except CommandExecutionError as err:
|
||||
ret['comment'] = 'Error: {0}'.format(err)
|
||||
return ret
|
||||
|
||||
for interface in new_interfaces:
|
||||
if not __opts__['test']:
|
||||
try:
|
||||
__salt__['firewalld.add_interface'](name, interface,
|
||||
permanent=True)
|
||||
except CommandExecutionError as err:
|
||||
ret['comment'] = 'Error: {0}'.format(err)
|
||||
return ret
|
||||
port_fwd = [_parse_forward(fwd) for fwd in port_fwd]
|
||||
_current_port_fwd = [
|
||||
ForwardingMapping(
|
||||
srcport=fwd['Source port'],
|
||||
destport=fwd['Destination port'],
|
||||
protocol=fwd['Protocol'],
|
||||
destaddr=fwd['Destination address']
|
||||
) for fwd in _current_port_fwd]
|
||||
|
||||
if prune_interfaces:
|
||||
old_interfaces = set(_current_interfaces) - set(interfaces)
|
||||
for interface in old_interfaces:
|
||||
new_port_fwd = set(port_fwd) - set(_current_port_fwd)
|
||||
old_port_fwd = []
|
||||
|
||||
for fwd in new_port_fwd:
|
||||
if not __opts__['test']:
|
||||
try:
|
||||
__salt__['firewalld.remove_interface'](name, interface,
|
||||
permanent=True)
|
||||
# TODO: force_masquerade to be removed in future release
|
||||
__salt__['firewalld.add_port_fwd'](name, fwd.srcport,
|
||||
fwd.destport, fwd.protocol, fwd.destaddr, permanent=True,
|
||||
force_masquerade=False)
|
||||
except CommandExecutionError as err:
|
||||
ret['comment'] = 'Error: {0}'.format(err)
|
||||
return ret
|
||||
|
||||
if new_interfaces or old_interfaces:
|
||||
# If we're not pruning, include current items in new output so it's clear
|
||||
# that they're still present
|
||||
if not prune_interfaces:
|
||||
interfaces = list(new_interfaces | set(_current_interfaces))
|
||||
ret['changes'].update({'interfaces':
|
||||
{'old': _current_interfaces,
|
||||
'new': interfaces}})
|
||||
if prune_port_fwd:
|
||||
old_port_fwd = set(_current_port_fwd) - set(port_fwd)
|
||||
for fwd in old_port_fwd:
|
||||
if not __opts__['test']:
|
||||
try:
|
||||
__salt__['firewalld.remove_port_fwd'](name, fwd.srcport,
|
||||
fwd.destport, fwd.protocol, fwd.destaddr, permanent=True)
|
||||
except CommandExecutionError as err:
|
||||
ret['comment'] = 'Error: {0}'.format(err)
|
||||
return ret
|
||||
|
||||
sources = sources or []
|
||||
try:
|
||||
_current_sources = __salt__['firewalld.get_sources'](name,
|
||||
if new_port_fwd or old_port_fwd:
|
||||
# If we're not pruning, include current items in new output so it's clear
|
||||
# that they're still present
|
||||
if not prune_port_fwd:
|
||||
port_fwd = list(new_port_fwd | set(_current_port_fwd))
|
||||
ret['changes'].update({'port_fwd':
|
||||
{'old': [fwd.todict() for fwd in
|
||||
_current_port_fwd],
|
||||
'new': [fwd.todict() for fwd in port_fwd]}})
|
||||
|
||||
if services or prune_services:
|
||||
services = services or []
|
||||
try:
|
||||
_current_services = __salt__['firewalld.list_services'](name,
|
||||
permanent=True)
|
||||
except CommandExecutionError as err:
|
||||
ret['comment'] = 'Error: {0}'.format(err)
|
||||
return ret
|
||||
|
||||
new_services = set(services) - set(_current_services)
|
||||
old_services = []
|
||||
|
||||
for new_service in new_services:
|
||||
if not __opts__['test']:
|
||||
try:
|
||||
__salt__['firewalld.add_service'](new_service, name,
|
||||
permanent=True)
|
||||
except CommandExecutionError as err:
|
||||
ret['comment'] = 'Error: {0}'.format(err)
|
||||
return ret
|
||||
|
||||
if prune_services:
|
||||
old_services = set(_current_services) - set(services)
|
||||
for old_service in old_services:
|
||||
if not __opts__['test']:
|
||||
try:
|
||||
__salt__['firewalld.remove_service'](old_service, name,
|
||||
permanent=True)
|
||||
except CommandExecutionError as err:
|
||||
ret['comment'] = 'Error: {0}'.format(err)
|
||||
return ret
|
||||
except CommandExecutionError as err:
|
||||
ret['comment'] = 'Error: {0}'.format(err)
|
||||
return ret
|
||||
|
||||
new_sources = set(sources) - set(_current_sources)
|
||||
old_sources = []
|
||||
if new_services or old_services:
|
||||
# If we're not pruning, include current items in new output so it's clear
|
||||
# that they're still present
|
||||
if not prune_services:
|
||||
services = list(new_services | set(_current_services))
|
||||
ret['changes'].update({'services':
|
||||
{'old': _current_services,
|
||||
'new': services}})
|
||||
|
||||
for source in new_sources:
|
||||
if not __opts__['test']:
|
||||
try:
|
||||
__salt__['firewalld.add_source'](name, source, permanent=True)
|
||||
except CommandExecutionError as err:
|
||||
ret['comment'] = 'Error: {0}'.format(err)
|
||||
return ret
|
||||
if interfaces or prune_interfaces:
|
||||
interfaces = interfaces or []
|
||||
try:
|
||||
_current_interfaces = __salt__['firewalld.get_interfaces'](name,
|
||||
permanent=True)
|
||||
except CommandExecutionError as err:
|
||||
ret['comment'] = 'Error: {0}'.format(err)
|
||||
return ret
|
||||
|
||||
if prune_sources:
|
||||
old_sources = set(_current_sources) - set(sources)
|
||||
for source in old_sources:
|
||||
new_interfaces = set(interfaces) - set(_current_interfaces)
|
||||
old_interfaces = []
|
||||
|
||||
for interface in new_interfaces:
|
||||
if not __opts__['test']:
|
||||
try:
|
||||
__salt__['firewalld.remove_source'](name, source,
|
||||
__salt__['firewalld.add_interface'](name, interface,
|
||||
permanent=True)
|
||||
except CommandExecutionError as err:
|
||||
ret['comment'] = 'Error: {0}'.format(err)
|
||||
return ret
|
||||
|
||||
if new_sources or old_sources:
|
||||
# If we're not pruning, include current items in new output so it's clear
|
||||
# that they're still present
|
||||
if not prune_sources:
|
||||
sources = list(new_sources | set(_current_sources))
|
||||
ret['changes'].update({'sources':
|
||||
{'old': _current_sources,
|
||||
'new': sources}})
|
||||
if prune_interfaces:
|
||||
old_interfaces = set(_current_interfaces) - set(interfaces)
|
||||
for interface in old_interfaces:
|
||||
if not __opts__['test']:
|
||||
try:
|
||||
__salt__['firewalld.remove_interface'](name, interface,
|
||||
permanent=True)
|
||||
except CommandExecutionError as err:
|
||||
ret['comment'] = 'Error: {0}'.format(err)
|
||||
return ret
|
||||
|
||||
rich_rules = rich_rules or []
|
||||
try:
|
||||
_current_rich_rules = __salt__['firewalld.get_rich_rules'](name,
|
||||
permanent=True)
|
||||
except CommandExecutionError as err:
|
||||
ret['comment'] = 'Error: {0}'.format(err)
|
||||
return ret
|
||||
if new_interfaces or old_interfaces:
|
||||
# If we're not pruning, include current items in new output so it's clear
|
||||
# that they're still present
|
||||
if not prune_interfaces:
|
||||
interfaces = list(new_interfaces | set(_current_interfaces))
|
||||
ret['changes'].update({'interfaces':
|
||||
{'old': _current_interfaces,
|
||||
'new': interfaces}})
|
||||
|
||||
new_rich_rules = set(rich_rules) - set(_current_rich_rules)
|
||||
old_rich_rules = []
|
||||
if sources or prune_sources:
|
||||
sources = sources or []
|
||||
try:
|
||||
_current_sources = __salt__['firewalld.get_sources'](name,
|
||||
permanent=True)
|
||||
except CommandExecutionError as err:
|
||||
ret['comment'] = 'Error: {0}'.format(err)
|
||||
return ret
|
||||
|
||||
for rich_rule in new_rich_rules:
|
||||
if not __opts__['test']:
|
||||
try:
|
||||
__salt__['firewalld.add_rich_rule'](name, rich_rule,
|
||||
permanent=True)
|
||||
except CommandExecutionError as err:
|
||||
ret['comment'] = 'Error: {0}'.format(err)
|
||||
return ret
|
||||
new_sources = set(sources) - set(_current_sources)
|
||||
old_sources = []
|
||||
|
||||
if prune_rich_rules:
|
||||
old_rich_rules = set(_current_rich_rules) - set(rich_rules)
|
||||
for rich_rule in old_rich_rules:
|
||||
for source in new_sources:
|
||||
if not __opts__['test']:
|
||||
try:
|
||||
__salt__['firewalld.remove_rich_rule'](name, rich_rule,
|
||||
permanent=True)
|
||||
__salt__['firewalld.add_source'](name, source, permanent=True)
|
||||
except CommandExecutionError as err:
|
||||
ret['comment'] = 'Error: {0}'.format(err)
|
||||
return ret
|
||||
|
||||
if new_rich_rules or old_rich_rules:
|
||||
# If we're not pruning, include current items in new output so it's clear
|
||||
# that they're still present
|
||||
if not prune_rich_rules:
|
||||
rich_rules = list(new_rich_rules | set(_current_rich_rules))
|
||||
ret['changes'].update({'rich_rules':
|
||||
{'old': _current_rich_rules,
|
||||
'new': rich_rules}})
|
||||
if prune_sources:
|
||||
old_sources = set(_current_sources) - set(sources)
|
||||
for source in old_sources:
|
||||
if not __opts__['test']:
|
||||
try:
|
||||
__salt__['firewalld.remove_source'](name, source,
|
||||
permanent=True)
|
||||
except CommandExecutionError as err:
|
||||
ret['comment'] = 'Error: {0}'.format(err)
|
||||
return ret
|
||||
|
||||
if new_sources or old_sources:
|
||||
# If we're not pruning, include current items in new output so it's clear
|
||||
# that they're still present
|
||||
if not prune_sources:
|
||||
sources = list(new_sources | set(_current_sources))
|
||||
ret['changes'].update({'sources':
|
||||
{'old': _current_sources,
|
||||
'new': sources}})
|
||||
|
||||
if rich_rules or prune_rich_rules:
|
||||
rich_rules = rich_rules or []
|
||||
try:
|
||||
_current_rich_rules = __salt__['firewalld.get_rich_rules'](name,
|
||||
permanent=True)
|
||||
except CommandExecutionError as err:
|
||||
ret['comment'] = 'Error: {0}'.format(err)
|
||||
return ret
|
||||
|
||||
new_rich_rules = set(rich_rules) - set(_current_rich_rules)
|
||||
old_rich_rules = []
|
||||
|
||||
for rich_rule in new_rich_rules:
|
||||
if not __opts__['test']:
|
||||
try:
|
||||
__salt__['firewalld.add_rich_rule'](name, rich_rule,
|
||||
permanent=True)
|
||||
except CommandExecutionError as err:
|
||||
ret['comment'] = 'Error: {0}'.format(err)
|
||||
return ret
|
||||
|
||||
if prune_rich_rules:
|
||||
old_rich_rules = set(_current_rich_rules) - set(rich_rules)
|
||||
for rich_rule in old_rich_rules:
|
||||
if not __opts__['test']:
|
||||
try:
|
||||
__salt__['firewalld.remove_rich_rule'](name, rich_rule,
|
||||
permanent=True)
|
||||
except CommandExecutionError as err:
|
||||
ret['comment'] = 'Error: {0}'.format(err)
|
||||
return ret
|
||||
|
||||
if new_rich_rules or old_rich_rules:
|
||||
# If we're not pruning, include current items in new output so it's clear
|
||||
# that they're still present
|
||||
if not prune_rich_rules:
|
||||
rich_rules = list(new_rich_rules | set(_current_rich_rules))
|
||||
ret['changes'].update({'rich_rules':
|
||||
{'old': _current_rich_rules,
|
||||
'new': rich_rules}})
|
||||
|
||||
# No changes
|
||||
if ret['changes'] == {}:
|
||||
|
|
|
@ -48,7 +48,7 @@ def present(name,
|
|||
The keyId or keyIds to add to the GPG keychain.
|
||||
|
||||
user
|
||||
Add GPG keys to the user's keychain
|
||||
Add GPG keys to the specified user's keychain
|
||||
|
||||
keyserver
|
||||
The keyserver to retrieve the keys from.
|
||||
|
@ -151,7 +151,7 @@ def absent(name,
|
|||
The keyId or keyIds to add to the GPG keychain.
|
||||
|
||||
user
|
||||
Add GPG keys to the user's keychain
|
||||
Remove GPG keys from the specified user's keychain
|
||||
|
||||
gnupghome
|
||||
Override GNUPG Home directory
|
||||
|
|
|
@ -83,8 +83,11 @@ def _changes(name,
|
|||
ret['comment'] = 'Invalid gid'
|
||||
return ret
|
||||
|
||||
if members:
|
||||
# -- if new member list if different than the current
|
||||
if members is not None and not members:
|
||||
if set(lgrp['members']).symmetric_difference(members):
|
||||
change['delusers'] = set(lgrp['members'])
|
||||
elif members:
|
||||
# if new member list if different than the current
|
||||
if set(lgrp['members']).symmetric_difference(members):
|
||||
change['members'] = members
|
||||
|
||||
|
@ -165,7 +168,7 @@ def present(name,
|
|||
'result': True,
|
||||
'comment': 'Group {0} is present and up to date'.format(name)}
|
||||
|
||||
if members and (addusers or delusers):
|
||||
if members is not None and (addusers is not None or delusers is not None):
|
||||
ret['result'] = None
|
||||
ret['comment'] = (
|
||||
'Error: Conflicting options "members" with "addusers" and/or'
|
||||
|
|
|
@ -42,7 +42,7 @@ def __virtual__():
|
|||
|
||||
def pv_present(name, **kwargs):
|
||||
'''
|
||||
Set a physical device to be used as an LVM physical volume
|
||||
Set a Physical Device to be used as an LVM Physical Volume
|
||||
|
||||
name
|
||||
The device name to initialize.
|
||||
|
@ -106,13 +106,13 @@ def pv_absent(name):
|
|||
|
||||
def vg_present(name, devices=None, **kwargs):
|
||||
'''
|
||||
Create an LVM volume group
|
||||
Create an LVM Volume Group
|
||||
|
||||
name
|
||||
The volume group name to create
|
||||
The Volume Group name to create
|
||||
|
||||
devices
|
||||
A list of devices that will be added to the volume group
|
||||
A list of devices that will be added to the Volume Group
|
||||
|
||||
kwargs
|
||||
Any supported options to vgcreate. See
|
||||
|
@ -214,16 +214,16 @@ def lv_present(name,
|
|||
force=False,
|
||||
**kwargs):
|
||||
'''
|
||||
Create a new logical volume
|
||||
Create a new Logical Volume
|
||||
|
||||
name
|
||||
The name of the logical volume
|
||||
The name of the Logical Volume
|
||||
|
||||
vgname
|
||||
The volume group name for this logical volume
|
||||
The name of the Volume Group on which the Logical Volume resides
|
||||
|
||||
size
|
||||
The initial size of the logical volume
|
||||
The initial size of the Logical Volume
|
||||
|
||||
extents
|
||||
The number of logical extents to allocate
|
||||
|
@ -232,7 +232,7 @@ def lv_present(name,
|
|||
The name of the snapshot
|
||||
|
||||
pv
|
||||
The physical volume to use
|
||||
The Physical Volume to use
|
||||
|
||||
kwargs
|
||||
Any supported options to lvcreate. See
|
||||
|
@ -241,10 +241,10 @@ def lv_present(name,
|
|||
.. versionadded:: to_complete
|
||||
|
||||
thinvolume
|
||||
Logical volume is thinly provisioned
|
||||
Logical Volume is thinly provisioned
|
||||
|
||||
thinpool
|
||||
Logical volume is a thin pool
|
||||
Logical Volume is a thin pool
|
||||
|
||||
.. versionadded:: 2018.3.0
|
||||
|
||||
|
@ -297,13 +297,13 @@ def lv_present(name,
|
|||
|
||||
def lv_absent(name, vgname=None):
|
||||
'''
|
||||
Remove a given existing logical volume from a named existing volume group
|
||||
Remove a given existing Logical Volume from a named existing volume group
|
||||
|
||||
name
|
||||
The logical volume to remove
|
||||
The Logical Volume to remove
|
||||
|
||||
vgname
|
||||
The volume group name
|
||||
The name of the Volume Group on which the Logical Volume resides
|
||||
'''
|
||||
ret = {'changes': {},
|
||||
'comment': '',
|
||||
|
|
|
@ -931,6 +931,12 @@ def mod_watch(name, user=None, **kwargs):
|
|||
'''
|
||||
The mounted watcher, called to invoke the watch command.
|
||||
|
||||
.. note::
|
||||
This state exists to support special handling of the ``watch``
|
||||
:ref:`requisite <requisites>`. It should not be called directly.
|
||||
|
||||
Parameters for this function should be set by the state being triggered.
|
||||
|
||||
name
|
||||
The name of the mount point
|
||||
|
||||
|
|
|
@ -23,7 +23,11 @@ requisite to a pkg.installed state for the package which provides pip
|
|||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
import re
|
||||
import logging
|
||||
import pkg_resources
|
||||
try:
|
||||
import pkg_resources
|
||||
HAS_PKG_RESOURCES = True
|
||||
except ImportError:
|
||||
HAS_PKG_RESOURCES = False
|
||||
|
||||
# Import salt libs
|
||||
import salt.utils.versions
|
||||
|
@ -71,6 +75,8 @@ def __virtual__():
|
|||
'''
|
||||
Only load if the pip module is available in __salt__
|
||||
'''
|
||||
if HAS_PKG_RESOURCES is False:
|
||||
return False, 'The pkg_resources python library is not installed'
|
||||
if 'pip.list' in __salt__:
|
||||
return __virtualname__
|
||||
return False
|
||||
|
|
|
@ -3264,6 +3264,12 @@ def mod_aggregate(low, chunks, running):
|
|||
def mod_watch(name, **kwargs):
|
||||
'''
|
||||
Install/reinstall a package based on a watch requisite
|
||||
|
||||
.. note::
|
||||
This state exists to support special handling of the ``watch``
|
||||
:ref:`requisite <requisites>`. It should not be called directly.
|
||||
|
||||
Parameters for this function should be set by the state being triggered.
|
||||
'''
|
||||
sfun = kwargs.pop('sfun', None)
|
||||
mapfun = {'purged': purged,
|
||||
|
|
|
@ -26,7 +26,7 @@ def absent(name, user=None, signal=None):
|
|||
The pattern to match.
|
||||
|
||||
user
|
||||
The user process belongs
|
||||
The user to which the process belongs
|
||||
|
||||
signal
|
||||
Signal to send to the process(es).
|
||||
|
|
|
@ -55,7 +55,7 @@ def managed(name, port, services=None, user=None, password=None, bypass_domains=
|
|||
The username to use for the proxy server if required
|
||||
|
||||
password
|
||||
The password to use if required by the server
|
||||
The password to use for the proxy server if required
|
||||
|
||||
bypass_domains
|
||||
An array of the domains that should bypass the proxy
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
Starting or restarting of services and daemons
|
||||
==============================================
|
||||
|
||||
Services are defined as system daemons typically started with system init or
|
||||
rc scripts. The service state uses whichever service module that is loaded on
|
||||
the minion with the virtualname of ``service``. Services can be defined as
|
||||
running or dead.
|
||||
Services are defined as system daemons and are typically launched using system
|
||||
init or rc scripts. This service state uses whichever service module is loaded
|
||||
on the minion with the virtualname of ``service``. Services can be defined as
|
||||
either running or dead.
|
||||
|
||||
If you need to know if your init system is supported, see the list of supported
|
||||
:mod:`service modules <salt.modules.service.py>` for your desired init system
|
||||
|
@ -30,7 +30,7 @@ section of Salt's module documentation to work around possible errors.
|
|||
httpd:
|
||||
service.running: []
|
||||
|
||||
The service can also be set to be started at runtime via the enable option:
|
||||
The service can also be set to start at runtime via the enable option:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
@ -39,8 +39,8 @@ The service can also be set to be started at runtime via the enable option:
|
|||
- enable: True
|
||||
|
||||
By default if a service is triggered to refresh due to a watch statement the
|
||||
service is by default restarted. If the desired behavior is to reload the
|
||||
service, then set the reload value to True:
|
||||
service is restarted. If the desired behavior is to reload the service, then
|
||||
set the reload value to True:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
@ -832,6 +832,14 @@ def mod_watch(name,
|
|||
**kwargs):
|
||||
'''
|
||||
The service watcher, called to invoke the watch command.
|
||||
When called, it will restart or reload the named service.
|
||||
|
||||
.. note::
|
||||
This state exists to support special handling of the ``watch``
|
||||
:ref:`requisite <requisites>`. It should not be called directly.
|
||||
|
||||
Parameters for this function should be set by the watching service.
|
||||
(i.e. ``service.running``)
|
||||
|
||||
name
|
||||
The name of the init or rc script used to manage the service
|
||||
|
@ -844,11 +852,13 @@ def mod_watch(name,
|
|||
The string to search for when looking for the service process with ps
|
||||
|
||||
reload
|
||||
Use reload instead of the default restart (exclusive option with full_restart,
|
||||
defaults to reload if both are used)
|
||||
When set, reload the service instead of restarting it.
|
||||
(i.e. ``service nginx reload``)
|
||||
|
||||
full_restart
|
||||
Use service.full_restart instead of restart (exclusive option with reload)
|
||||
Perform a full stop/start of a service by passing ``--full-restart``.
|
||||
This option is ignored if ``reload`` is set and is supported by only a few
|
||||
:py:func:`service modules <salt.modules.service>`.
|
||||
|
||||
force
|
||||
Use service.force_reload instead of reload (needs reload to be set to True)
|
||||
|
|
|
@ -361,7 +361,16 @@ def mod_watch(name,
|
|||
conf_file=None,
|
||||
bin_env=None,
|
||||
**kwargs):
|
||||
# Always restart on watch
|
||||
'''
|
||||
The supervisord watcher, called to invoke the watch command.
|
||||
Always restart on watch
|
||||
|
||||
.. note::
|
||||
This state exists to support special handling of the ``watch``
|
||||
:ref:`requisite <requisites>`. It should not be called directly.
|
||||
|
||||
Parameters for this function should be set by the state being triggered.
|
||||
'''
|
||||
return running(
|
||||
name,
|
||||
restart=restart,
|
||||
|
|
|
@ -334,7 +334,7 @@ def _check_key_type(key_str, key_type=None):
|
|||
value = __salt__['pillar.get'](key_str, None)
|
||||
if value is None:
|
||||
return None
|
||||
elif type(value) is not key_type and key_type is not None:
|
||||
elif key_type is not None and not isinstance(value, key_type):
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
@ -415,7 +415,7 @@ def check_pillar(name,
|
|||
checks[int] = integer
|
||||
# those should be str:
|
||||
string = _if_str_then_list(string)
|
||||
checks[str] = string
|
||||
checks[six.string_types] = string
|
||||
# those should be list:
|
||||
listing = _if_str_then_list(listing)
|
||||
checks[list] = listing
|
||||
|
|
|
@ -272,8 +272,14 @@ def wait(name, url='http://localhost:8080/manager', timeout=180):
|
|||
|
||||
def mod_watch(name, url='http://localhost:8080/manager', timeout=180):
|
||||
'''
|
||||
The tomcat watcher function.
|
||||
When called it will reload the webapp in question
|
||||
The tomcat watcher, called to invoke the watch command.
|
||||
When called, it will reload the webapp in question
|
||||
|
||||
.. note::
|
||||
This state exists to support special handling of the ``watch``
|
||||
:ref:`requisite <requisites>`. It should not be called directly.
|
||||
|
||||
Parameters for this function should be set by the state being triggered.
|
||||
'''
|
||||
|
||||
msg = __salt__['tomcat.reload'](name, url, timeout)
|
||||
|
|
|
@ -289,10 +289,13 @@ def set_(name,
|
|||
) == {}
|
||||
|
||||
if not policies_are_equal:
|
||||
additional_policy_comments = []
|
||||
if policy_data['policy_lookup'][policy_name]['rights_assignment'] and cumulative_rights_assignments:
|
||||
for user in policy_data['requested_policy'][policy_name]:
|
||||
if user not in current_policy[policy_data['output_section']][pol_id]:
|
||||
changes = True
|
||||
else:
|
||||
additional_policy_comments.append('"{0}" is already granted the right'.format(user))
|
||||
else:
|
||||
changes = True
|
||||
if changes:
|
||||
|
@ -303,6 +306,11 @@ def set_(name,
|
|||
requested_policy_json, current_policy_json
|
||||
)
|
||||
policy_changes.append(policy_name)
|
||||
else:
|
||||
if additional_policy_comments:
|
||||
ret['comment'] = '"{0}" is already set ({1}).\n'.format(policy_name, ', '.join(additional_policy_comments))
|
||||
else:
|
||||
ret['comment'] = '"{0}" is already set.\n'.format(policy_name) + ret['comment']
|
||||
else:
|
||||
log.debug('%s current setting matches '
|
||||
'the requested setting', policy_name)
|
||||
|
|
|
@ -166,36 +166,46 @@ def hostname(name):
|
|||
return ret
|
||||
|
||||
|
||||
def join_domain(name, username=None, password=None, account_ou=None,
|
||||
account_exists=False, restart=False):
|
||||
|
||||
def join_domain(name,
|
||||
username=None,
|
||||
password=None,
|
||||
account_ou=None,
|
||||
account_exists=False,
|
||||
restart=False):
|
||||
'''
|
||||
Checks if a computer is joined to the Domain.
|
||||
If the computer is not in the Domain, it will be joined.
|
||||
Checks if a computer is joined to the Domain. If the computer is not in the
|
||||
Domain, it will be joined.
|
||||
|
||||
name:
|
||||
The name of the Domain.
|
||||
Args:
|
||||
|
||||
username:
|
||||
Username of an account which is authorized to join computers to the
|
||||
specified domain. Need to be either fully qualified like user@domain.tld
|
||||
or simply user.
|
||||
name (str):
|
||||
The name of the Domain.
|
||||
|
||||
password:
|
||||
Password of the account to add the computer to the Domain.
|
||||
username (str):
|
||||
Username of an account which is authorized to join computers to the
|
||||
specified domain. Need to be either fully qualified like
|
||||
user@domain.tld or simply user.
|
||||
|
||||
account_ou:
|
||||
The DN of the OU below which the account for this computer should be
|
||||
created when joining the domain,
|
||||
e.g. ou=computers,ou=departm_432,dc=my-company,dc=com.
|
||||
password (str):
|
||||
Password of the account to add the computer to the Domain.
|
||||
|
||||
account_exists:
|
||||
Needs to be set to True to allow re-using an existing computer account.
|
||||
account_ou (str):
|
||||
The DN of the OU below which the account for this computer should be
|
||||
created when joining the domain,
|
||||
e.g. ou=computers,ou=departm_432,dc=my-company,dc=com.
|
||||
|
||||
restart:
|
||||
Needs to be set to True to restart the computer after a successful join.
|
||||
account_exists (bool):
|
||||
Needs to be set to ``True`` to allow re-using an existing computer
|
||||
account.
|
||||
|
||||
restart (bool):
|
||||
Needs to be set to ``True`` to restart the computer after a
|
||||
successful join.
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
.. code-block::yaml
|
||||
join_to_domain:
|
||||
system.join_domain:
|
||||
- name: mydomain.local.com
|
||||
|
@ -209,9 +219,6 @@ def join_domain(name, username=None, password=None, account_ou=None,
|
|||
'result': True,
|
||||
'comment': 'Computer already added to \'{0}\''.format(name)}
|
||||
|
||||
# Set name to domain, needed for the add to domain module.
|
||||
domain = name
|
||||
|
||||
current_domain_dic = __salt__['system.get_domain_workgroup']()
|
||||
if 'Domain' in current_domain_dic:
|
||||
current_domain = current_domain_dic['Domain']
|
||||
|
@ -220,7 +227,7 @@ def join_domain(name, username=None, password=None, account_ou=None,
|
|||
else:
|
||||
current_domain = None
|
||||
|
||||
if domain == current_domain:
|
||||
if name.lower() == current_domain.lower():
|
||||
ret['comment'] = 'Computer already added to \'{0}\''.format(name)
|
||||
return ret
|
||||
|
||||
|
@ -229,11 +236,20 @@ def join_domain(name, username=None, password=None, account_ou=None,
|
|||
ret['comment'] = 'Computer will be added to \'{0}\''.format(name)
|
||||
return ret
|
||||
|
||||
result = __salt__['system.join_domain'](domain, username, password,
|
||||
account_ou, account_exists,
|
||||
restart)
|
||||
result = __salt__['system.join_domain'](domain=name,
|
||||
username=username,
|
||||
password=password,
|
||||
account_ou=account_ou,
|
||||
account_exists=account_exists,
|
||||
restart=restart)
|
||||
if result is not False:
|
||||
ret['comment'] = 'Computer added to \'{0}\''.format(name)
|
||||
if restart:
|
||||
ret['comment'] += '\nSystem will restart'
|
||||
else:
|
||||
ret['comment'] += '\nSystem needs to be restarted'
|
||||
ret['changes'] = {'old': current_domain,
|
||||
'new': name}
|
||||
else:
|
||||
ret['comment'] = 'Computer failed to join \'{0}\''.format(name)
|
||||
ret['result'] = False
|
||||
|
|
|
@ -1,11 +1,211 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
SaltClass master_tops Module
|
||||
r'''
|
||||
Saltclass Configuration
|
||||
=======================
|
||||
|
||||
.. code-block:: yaml
|
||||
master_tops:
|
||||
saltclass:
|
||||
path: /srv/saltclass
|
||||
|
||||
master_tops:
|
||||
saltclass:
|
||||
path: /srv/saltclass
|
||||
|
||||
Description
|
||||
===========
|
||||
|
||||
This module clones the behaviour of reclass (http://reclass.pantsfullofunix.net/),
|
||||
without the need of an external app, and add several features to improve flexibility.
|
||||
Saltclass lets you define your nodes from simple ``yaml`` files (``.yml``) through
|
||||
hierarchical class inheritance with the possibility to override pillars down the tree.
|
||||
|
||||
Features
|
||||
========
|
||||
|
||||
- Define your nodes through hierarchical class inheritance
|
||||
- Reuse your reclass datas with minimal modifications
|
||||
- applications => states
|
||||
- parameters => pillars
|
||||
- Use Jinja templating in your yaml definitions
|
||||
- Access to the following Salt objects in Jinja
|
||||
- ``__opts__``
|
||||
- ``__salt__``
|
||||
- ``__grains__``
|
||||
- ``__pillars__``
|
||||
- ``minion_id``
|
||||
- Chose how to merge or override your lists using ^ character (see examples)
|
||||
- Expand variables ${} with possibility to escape them if needed \${} (see examples)
|
||||
- Ignores missing node/class and will simply return empty without breaking the pillar module completely - will be logged
|
||||
|
||||
An example subset of datas is available here: http://git.mauras.ch/salt/saltclass/src/master/examples
|
||||
|
||||
========================== ===========
|
||||
Terms usable in yaml files Description
|
||||
========================== ===========
|
||||
classes A list of classes that will be processed in order
|
||||
states A list of states that will be returned by master_tops function
|
||||
pillars A yaml dictionnary that will be returned by the ext_pillar function
|
||||
environment Node saltenv that will be used by master_tops
|
||||
========================== ===========
|
||||
|
||||
A class consists of:
|
||||
|
||||
- zero or more parent classes
|
||||
- zero or more states
|
||||
- any number of pillars
|
||||
|
||||
A child class can override pillars from a parent class.
|
||||
A node definition is a class in itself with an added ``environment`` parameter for ``saltenv`` definition.
|
||||
|
||||
Class names
|
||||
===========
|
||||
|
||||
Class names mimic salt way of defining states and pillar files.
|
||||
This means that ``default.users`` class name will correspond to one of these:
|
||||
|
||||
- ``<saltclass_path>/classes/default/users.yml``
|
||||
- ``<saltclass_path>/classes/default/users/init.yml``
|
||||
|
||||
Saltclass file hierachy
|
||||
=======================
|
||||
|
||||
A saltclass tree would look like this:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
<saltclass_path>
|
||||
├── classes
|
||||
│ ├── app
|
||||
│ │ ├── borgbackup.yml
|
||||
│ │ └── ssh
|
||||
│ │ └── server.yml
|
||||
│ ├── default
|
||||
│ │ ├── init.yml
|
||||
│ │ ├── motd.yml
|
||||
│ │ └── users.yml
|
||||
│ ├── roles
|
||||
│ │ ├── app.yml
|
||||
│ │ └── nginx
|
||||
│ │ ├── init.yml
|
||||
│ │ └── server.yml
|
||||
│ └── subsidiaries
|
||||
│ ├── gnv.yml
|
||||
│ ├── qls.yml
|
||||
│ └── zrh.yml
|
||||
└── nodes
|
||||
├── geneva
|
||||
│ └── gnv.node1.yml
|
||||
├── lausanne
|
||||
│ ├── qls.node1.yml
|
||||
│ └── qls.node2.yml
|
||||
├── node127.yml
|
||||
└── zurich
|
||||
├── zrh.node1.yml
|
||||
├── zrh.node2.yml
|
||||
└── zrh.node3.yml
|
||||
|
||||
|
||||
Saltclass Examples
|
||||
==================
|
||||
|
||||
``<saltclass_path>/nodes/lausanne/qls.node1.yml``
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
environment: base
|
||||
|
||||
classes:
|
||||
{% for class in ['default'] %}
|
||||
- {{ class }}
|
||||
{% endfor %}
|
||||
- subsidiaries.{{ __grains__['id'].split('.')[0] }}
|
||||
|
||||
``<saltclass_path>/classes/default/init.yml``
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
classes:
|
||||
- default.users
|
||||
- default.motd
|
||||
|
||||
states:
|
||||
- openssh
|
||||
|
||||
pillars:
|
||||
default:
|
||||
network:
|
||||
dns:
|
||||
srv1: 192.168.0.1
|
||||
srv2: 192.168.0.2
|
||||
domain: example.com
|
||||
ntp:
|
||||
srv1: 192.168.10.10
|
||||
srv2: 192.168.10.20
|
||||
|
||||
``<saltclass_path>/classes/subsidiaries/gnv.yml``
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
pillars:
|
||||
default:
|
||||
network:
|
||||
sub: Geneva
|
||||
dns:
|
||||
srv1: 10.20.0.1
|
||||
srv2: 10.20.0.2
|
||||
srv3: 192.168.1.1
|
||||
domain: gnv.example.com
|
||||
users:
|
||||
adm1:
|
||||
uid: 1210
|
||||
gid: 1210
|
||||
gecos: 'Super user admin1'
|
||||
homedir: /srv/app/adm1
|
||||
adm3:
|
||||
uid: 1203
|
||||
gid: 1203
|
||||
gecos: 'Super user adm
|
||||
|
||||
Variable expansions
|
||||
===================
|
||||
|
||||
Escaped variables are rendered as is: ``${test}``
|
||||
|
||||
Missing variables are rendered as is: ``${net:dns:srv2}``
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
pillars:
|
||||
app:
|
||||
config:
|
||||
dns:
|
||||
srv1: ${default:network:dns:srv1}
|
||||
srv2: ${net:dns:srv2}
|
||||
uri: https://application.domain/call?\${test}
|
||||
prod_parameters:
|
||||
- p1
|
||||
- p2
|
||||
- p3
|
||||
pkg:
|
||||
- app-core
|
||||
- app-backend
|
||||
|
||||
List override
|
||||
=============
|
||||
|
||||
Not using ``^`` as the first entry will simply merge the lists
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
pillars:
|
||||
app:
|
||||
pkg:
|
||||
- ^
|
||||
- app-frontend
|
||||
|
||||
|
||||
.. note:: **Known limitation**
|
||||
|
||||
Currently you can't have both a variable and an escaped variable in the same string as the
|
||||
escaped one will not be correctly rendered - '\${xx}' will stay as is instead of being rendered as '${xx}'
|
||||
'''
|
||||
|
||||
# import python libs
|
||||
|
|
|
@ -488,11 +488,7 @@ def query(url,
|
|||
data = _urlencode(data)
|
||||
|
||||
if verify_ssl:
|
||||
# tornado requires a str, cannot be unicode str in py2
|
||||
if ca_bundle is None:
|
||||
req_kwargs['ca_certs'] = ca_bundle
|
||||
else:
|
||||
req_kwargs['ca_certs'] = salt.utils.stringutils.to_str(ca_bundle)
|
||||
req_kwargs['ca_certs'] = ca_bundle
|
||||
|
||||
max_body = opts.get('http_max_body', salt.config.DEFAULT_MINION_OPTS['http_max_body'])
|
||||
connect_timeout = opts.get('http_connect_timeout', salt.config.DEFAULT_MINION_OPTS['http_connect_timeout'])
|
||||
|
@ -538,31 +534,36 @@ def query(url,
|
|||
|
||||
supports_max_body_size = 'max_body_size' in client_argspec.args
|
||||
|
||||
req_kwargs.update({
|
||||
'method': method,
|
||||
'headers': header_dict,
|
||||
'auth_username': username,
|
||||
'auth_password': password,
|
||||
'body': data,
|
||||
'validate_cert': verify_ssl,
|
||||
'allow_nonstandard_methods': True,
|
||||
'streaming_callback': streaming_callback,
|
||||
'header_callback': header_callback,
|
||||
'connect_timeout': connect_timeout,
|
||||
'request_timeout': timeout,
|
||||
'proxy_host': proxy_host,
|
||||
'proxy_port': proxy_port,
|
||||
'proxy_username': proxy_username,
|
||||
'proxy_password': proxy_password,
|
||||
'raise_error': raise_error,
|
||||
'decompress_response': False,
|
||||
})
|
||||
|
||||
# Unicode types will cause a TypeError when Tornado's curl HTTPClient
|
||||
# invokes setopt. Therefore, make sure all arguments we pass which
|
||||
# contain strings are str types.
|
||||
req_kwargs = salt.utils.data.decode(req_kwargs, to_str=True)
|
||||
|
||||
try:
|
||||
download_client = HTTPClient(max_body_size=max_body) \
|
||||
if supports_max_body_size \
|
||||
else HTTPClient()
|
||||
result = download_client.fetch(
|
||||
url_full,
|
||||
method=method,
|
||||
headers=header_dict,
|
||||
auth_username=username,
|
||||
auth_password=password,
|
||||
body=data,
|
||||
validate_cert=verify_ssl,
|
||||
allow_nonstandard_methods=True,
|
||||
streaming_callback=streaming_callback,
|
||||
header_callback=header_callback,
|
||||
connect_timeout=connect_timeout,
|
||||
request_timeout=timeout,
|
||||
proxy_host=proxy_host,
|
||||
proxy_port=proxy_port,
|
||||
proxy_username=proxy_username,
|
||||
proxy_password=proxy_password,
|
||||
raise_error=raise_error,
|
||||
decompress_response=False,
|
||||
**req_kwargs
|
||||
)
|
||||
result = download_client.fetch(url_full, **req_kwargs)
|
||||
except tornado.httpclient.HTTPError as exc:
|
||||
ret['status'] = exc.code
|
||||
ret['error'] = six.text_type(exc)
|
||||
|
|
|
@ -59,16 +59,16 @@ class SaltCacheLoader(BaseLoader):
|
|||
self.opts = opts
|
||||
self.saltenv = saltenv
|
||||
self.encoding = encoding
|
||||
if self.opts['file_roots'] is self.opts['pillar_roots']:
|
||||
if saltenv not in self.opts['file_roots']:
|
||||
self.pillar_rend = pillar_rend
|
||||
if self.pillar_rend:
|
||||
if saltenv not in self.opts['pillar_roots']:
|
||||
self.searchpath = []
|
||||
else:
|
||||
self.searchpath = opts['file_roots'][saltenv]
|
||||
self.searchpath = opts['pillar_roots'][saltenv]
|
||||
else:
|
||||
self.searchpath = [os.path.join(opts['cachedir'], 'files', saltenv)]
|
||||
log.debug('Jinja search path: %s', self.searchpath)
|
||||
self.cached = []
|
||||
self.pillar_rend = pillar_rend
|
||||
self._file_client = None
|
||||
# Instantiate the fileclient
|
||||
self.file_client()
|
||||
|
|
|
@ -213,7 +213,7 @@ class CkMinions(object):
|
|||
return {'minions': fnmatch.filter(self._pki_minions(), expr),
|
||||
'missing': []}
|
||||
|
||||
def _check_list_minions(self, expr, greedy): # pylint: disable=unused-argument
|
||||
def _check_list_minions(self, expr, greedy, ignore_missing=False): # pylint: disable=unused-argument
|
||||
'''
|
||||
Return the minions found by looking via a list
|
||||
'''
|
||||
|
@ -221,7 +221,7 @@ class CkMinions(object):
|
|||
expr = [m for m in expr.split(',') if m]
|
||||
minions = self._pki_minions()
|
||||
return {'minions': [x for x in expr if x in minions],
|
||||
'missing': [x for x in expr if x not in minions]}
|
||||
'missing': [] if ignore_missing else [x for x in expr if x not in minions]}
|
||||
|
||||
def _check_pcre_minions(self, expr, greedy): # pylint: disable=unused-argument
|
||||
'''
|
||||
|
@ -579,6 +579,10 @@ class CkMinions(object):
|
|||
engine_args.append(target_info['delimiter'] or ':')
|
||||
engine_args.append(greedy)
|
||||
|
||||
# ignore missing minions for lists if we exclude them with
|
||||
# a 'not'
|
||||
if 'L' == target_info['engine']:
|
||||
engine_args.append(results and results[-1] == '-')
|
||||
_results = engine(*engine_args)
|
||||
results.append(six.text_type(set(_results['minions'])))
|
||||
missing.extend(_results['missing'])
|
||||
|
|
|
@ -9,6 +9,7 @@ import collections
|
|||
import datetime
|
||||
import logging
|
||||
import subprocess
|
||||
import salt.utils.stringutils
|
||||
|
||||
# Import 3rd-party libs
|
||||
from salt.ext import six
|
||||
|
@ -47,7 +48,7 @@ def get_osarch():
|
|||
close_fds=True,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE).communicate()[0]
|
||||
return ret or 'unknown'
|
||||
return salt.utils.stringutils.to_str(ret).strip() or 'unknown'
|
||||
|
||||
|
||||
def check_32(arch, osarch=None):
|
||||
|
|
|
@ -123,6 +123,12 @@ def get_current_user(with_domain=True):
|
|||
'''
|
||||
Gets the user executing the process
|
||||
|
||||
Args:
|
||||
|
||||
with_domain (bool):
|
||||
``True`` will prepend the user name with the machine name or domain
|
||||
separated by a backslash
|
||||
|
||||
Returns:
|
||||
str: The user name
|
||||
'''
|
||||
|
|
|
@ -41,7 +41,7 @@ class BatchTest(ShellCase):
|
|||
min_ret = "Executing run on [{0}]".format(repr('minion'))
|
||||
|
||||
for item in self.run_salt('minion grains.get os'):
|
||||
if item != 'minion':
|
||||
if item != 'minion:':
|
||||
os_grain = item
|
||||
|
||||
os_grain = os_grain.strip()
|
||||
|
|
|
@ -249,7 +249,11 @@ class GroupModuleTest(ModuleCase):
|
|||
self.run_function('user.add', [self._user])
|
||||
self.run_function('user.add', [self._user1])
|
||||
m = '{0},{1}'.format(self._user, self._user1)
|
||||
self.assertTrue(self.run_function('group.members', [self._group, m]))
|
||||
ret = self.run_function('group.members', [self._group, m])
|
||||
if salt.utils.platform.is_windows():
|
||||
self.assertTrue(ret['result'])
|
||||
else:
|
||||
self.assertTrue(ret)
|
||||
group_info = self.run_function('group.info', [self._group])
|
||||
self.assertIn(self._user, str(group_info['members']))
|
||||
self.assertIn(self._user1, str(group_info['members']))
|
||||
|
|
|
@ -13,6 +13,7 @@ import textwrap
|
|||
from tests.support.case import ModuleCase
|
||||
from tests.support.helpers import flaky
|
||||
from tests.support.paths import TMP_PILLAR_TREE
|
||||
from tests.support.unit import skipIf
|
||||
|
||||
# Import Salt Libs
|
||||
import salt.utils.files
|
||||
|
@ -177,6 +178,7 @@ class SaltUtilSyncModuleTest(ModuleCase):
|
|||
self.assertEqual(ret, expected_return)
|
||||
|
||||
|
||||
@skipIf(True, 'Pillar refresh test is flaky. Skipping for now.')
|
||||
class SaltUtilSyncPillarTest(ModuleCase):
|
||||
'''
|
||||
Testcase for the saltutil sync pillar module
|
||||
|
|
|
@ -15,7 +15,8 @@ from tests.support.runtests import RUNTIME_VARS
|
|||
import salt.utils.files
|
||||
import salt.utils.platform
|
||||
|
||||
CURL = os.path.join(RUNTIME_VARS.FILES, 'file', 'base', 'win', 'repo-ng', 'curl.sls')
|
||||
REPO_DIR = os.path.join(RUNTIME_VARS.FILES, 'file', 'base', 'win', 'repo-ng')
|
||||
CURL = os.path.join(REPO_DIR, 'curl.sls')
|
||||
|
||||
|
||||
@skipIf(not salt.utils.platform.is_windows(), 'windows test only')
|
||||
|
@ -33,8 +34,10 @@ class WinPKGTest(ModuleCase):
|
|||
Test add and removing a new pkg sls
|
||||
in the windows software repository
|
||||
'''
|
||||
def _check_pkg(pkgs, exists=True):
|
||||
self.run_function('pkg.refresh_db')
|
||||
def _check_pkg(pkgs, check_refresh, exists=True):
|
||||
refresh = self.run_function('pkg.refresh_db')
|
||||
self.assertEqual(check_refresh, refresh['total'],
|
||||
msg='total returned {0}. Expected return {1}'.format(refresh['total'], check_refresh))
|
||||
repo_data = self.run_function('pkg.get_repo_data', timeout=300)
|
||||
repo_cache = os.path.join(RUNTIME_VARS.TMP, 'rootdir', 'cache', 'files', 'base', 'win', 'repo-ng')
|
||||
for pkg in pkgs:
|
||||
|
@ -51,7 +54,7 @@ class WinPKGTest(ModuleCase):
|
|||
|
||||
pkgs = ['putty', '7zip']
|
||||
# check putty and 7zip are in cache and repo query
|
||||
_check_pkg(pkgs)
|
||||
_check_pkg(pkgs, 2)
|
||||
|
||||
# now add new sls
|
||||
with salt.utils.files.fopen(CURL, 'w') as fp_:
|
||||
|
@ -74,11 +77,13 @@ class WinPKGTest(ModuleCase):
|
|||
'''))
|
||||
# now check if curl is also in cache and repo query
|
||||
pkgs.append('curl')
|
||||
_check_pkg(pkgs)
|
||||
for pkg in pkgs:
|
||||
self.assertIn(pkg + '.sls', os.listdir(REPO_DIR))
|
||||
_check_pkg(pkgs, 3)
|
||||
|
||||
# remove curl sls and check its not in cache and repo query
|
||||
os.remove(CURL)
|
||||
_check_pkg(['curl'], exists=False)
|
||||
_check_pkg(['curl'], 2, exists=False)
|
||||
|
||||
def tearDown(self):
|
||||
if os.path.isfile(CURL):
|
||||
|
|
|
@ -101,13 +101,13 @@ from salt.utils.gitfs import (
|
|||
# Check for requisite components
|
||||
try:
|
||||
HAS_GITPYTHON = GITPYTHON_VERSION >= GITPYTHON_MINVER
|
||||
except ImportError:
|
||||
except Exception:
|
||||
HAS_GITPYTHON = False
|
||||
|
||||
try:
|
||||
HAS_PYGIT2 = PYGIT2_VERSION >= PYGIT2_MINVER \
|
||||
and LIBGIT2_VERSION >= LIBGIT2_MINVER
|
||||
except AttributeError:
|
||||
except Exception:
|
||||
HAS_PYGIT2 = False
|
||||
|
||||
HAS_SSHD = bool(salt.utils.path.which('sshd'))
|
||||
|
|
|
@ -14,13 +14,16 @@ import os
|
|||
import pipes
|
||||
import shutil
|
||||
import tempfile
|
||||
import logging
|
||||
|
||||
# Import Salt Testing libs
|
||||
from tests.support.case import ShellCase
|
||||
from tests.support.paths import TMP
|
||||
from tests.support.mixins import ShellCaseCommonTestsMixin
|
||||
from tests.support.unit import skipIf
|
||||
|
||||
# Import salt libs
|
||||
import salt.utils.platform
|
||||
import salt.utils.files
|
||||
import salt.utils.yaml
|
||||
|
||||
|
@ -28,6 +31,9 @@ import salt.utils.yaml
|
|||
from salt.ext import six
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CopyTest(ShellCase, ShellCaseCommonTestsMixin):
|
||||
|
||||
_call_binary_ = 'salt-cp'
|
||||
|
@ -54,19 +60,24 @@ class CopyTest(ShellCase, ShellCaseCommonTestsMixin):
|
|||
with salt.utils.files.fopen(testfile, 'r') as fh_:
|
||||
testfile_contents = fh_.read()
|
||||
|
||||
def quote(arg):
|
||||
if salt.utils.platform.is_windows():
|
||||
return arg
|
||||
return pipes.quote(arg)
|
||||
|
||||
for idx, minion in enumerate(minions):
|
||||
if 'localhost' in minion:
|
||||
continue
|
||||
ret = self.run_salt(
|
||||
'--out yaml {0} file.directory_exists {1}'.format(
|
||||
pipes.quote(minion), TMP
|
||||
quote(minion), TMP
|
||||
)
|
||||
)
|
||||
data = salt.utils.yaml.safe_load('\n'.join(ret))
|
||||
if data[minion] is False:
|
||||
ret = self.run_salt(
|
||||
'--out yaml {0} file.makedirs {1}'.format(
|
||||
pipes.quote(minion),
|
||||
quote(minion),
|
||||
TMP
|
||||
)
|
||||
)
|
||||
|
@ -79,19 +90,23 @@ class CopyTest(ShellCase, ShellCaseCommonTestsMixin):
|
|||
)
|
||||
|
||||
ret = self.run_cp('--out pprint {0} {1} {2}'.format(
|
||||
pipes.quote(minion),
|
||||
pipes.quote(testfile),
|
||||
pipes.quote(minion_testfile)
|
||||
quote(minion),
|
||||
quote(testfile),
|
||||
quote(minion_testfile),
|
||||
))
|
||||
|
||||
data = eval('\n'.join(ret), {}, {}) # pylint: disable=eval-used
|
||||
for part in six.itervalues(data):
|
||||
self.assertTrue(part[minion_testfile])
|
||||
if salt.utils.platform.is_windows():
|
||||
key = minion_testfile.replace('\\', '\\\\')
|
||||
else:
|
||||
key = minion_testfile
|
||||
self.assertTrue(part[key])
|
||||
|
||||
ret = self.run_salt(
|
||||
'--out yaml {0} file.file_exists {1}'.format(
|
||||
pipes.quote(minion),
|
||||
pipes.quote(minion_testfile)
|
||||
quote(minion),
|
||||
quote(minion_testfile)
|
||||
)
|
||||
)
|
||||
data = salt.utils.yaml.safe_load('\n'.join(ret))
|
||||
|
@ -99,22 +114,23 @@ class CopyTest(ShellCase, ShellCaseCommonTestsMixin):
|
|||
|
||||
ret = self.run_salt(
|
||||
'--out yaml {0} file.contains {1} {2}'.format(
|
||||
pipes.quote(minion),
|
||||
pipes.quote(minion_testfile),
|
||||
pipes.quote(testfile_contents)
|
||||
quote(minion),
|
||||
quote(minion_testfile),
|
||||
quote(testfile_contents)
|
||||
)
|
||||
)
|
||||
data = salt.utils.yaml.safe_load('\n'.join(ret))
|
||||
self.assertTrue(data[minion])
|
||||
ret = self.run_salt(
|
||||
'--out yaml {0} file.remove {1}'.format(
|
||||
pipes.quote(minion),
|
||||
pipes.quote(minion_testfile)
|
||||
quote(minion),
|
||||
quote(minion_testfile)
|
||||
)
|
||||
)
|
||||
data = salt.utils.yaml.safe_load('\n'.join(ret))
|
||||
self.assertTrue(data[minion])
|
||||
|
||||
@skipIf(salt.utils.platform.is_windows(), 'Skip on Windows OS')
|
||||
def test_issue_7754(self):
|
||||
config_dir = os.path.join(TMP, 'issue-7754')
|
||||
|
||||
|
|
|
@ -8,8 +8,10 @@ import textwrap
|
|||
# Import Salt Testing libs
|
||||
from tests.support.case import ModuleCase
|
||||
from tests.support.paths import FILES
|
||||
from tests.support.unit import skipIf
|
||||
|
||||
# Import Salt Libs
|
||||
import salt.utils.platform
|
||||
import salt.utils.files
|
||||
|
||||
|
||||
|
@ -25,6 +27,7 @@ class EnabledTest(ModuleCase):
|
|||
"export SALTY_VARIABLE='saltines' && echo $SALTY_VARIABLE ; "
|
||||
"echo duh &> /dev/null")
|
||||
|
||||
@skipIf(salt.utils.platform.is_windows(), 'Skip on Windows OS')
|
||||
def test_shell_default_enabled(self):
|
||||
'''
|
||||
ensure that python_shell defaults to True for cmd.run
|
||||
|
@ -33,6 +36,7 @@ class EnabledTest(ModuleCase):
|
|||
ret = self.run_function('cmd.run', [self.cmd])
|
||||
self.assertEqual(ret.strip(), enabled_ret)
|
||||
|
||||
@skipIf(salt.utils.platform.is_windows(), 'Skip on Windows OS')
|
||||
def test_shell_disabled(self):
|
||||
'''
|
||||
test shell disabled output for cmd.run
|
||||
|
@ -42,6 +46,7 @@ class EnabledTest(ModuleCase):
|
|||
ret = self.run_function('cmd.run', [self.cmd], python_shell=False)
|
||||
self.assertEqual(ret, disabled_ret)
|
||||
|
||||
@skipIf(salt.utils.platform.is_windows(), 'Skip on Windows OS')
|
||||
def test_template_shell(self):
|
||||
'''
|
||||
Test cmd.shell works correctly when using a template.
|
||||
|
@ -72,6 +77,7 @@ class EnabledTest(ModuleCase):
|
|||
finally:
|
||||
os.remove(state_file)
|
||||
|
||||
@skipIf(salt.utils.platform.is_windows(), 'Skip on Windows OS')
|
||||
def test_template_default_disabled(self):
|
||||
'''
|
||||
test shell disabled output for templates (python_shell=False is the default
|
||||
|
|
|
@ -256,6 +256,9 @@ class KeyTest(ShellCase, ShellCaseCommonTestsMixin):
|
|||
for fname in key_names:
|
||||
self.assertTrue(os.path.isfile(os.path.join(tempdir, fname)))
|
||||
finally:
|
||||
for dirname, dirs, files in os.walk(tempdir):
|
||||
for filename in files:
|
||||
os.chmod(os.path.join(dirname, filename), 0o700)
|
||||
shutil.rmtree(tempdir)
|
||||
|
||||
def test_keys_generation_keysize_minmax(self):
|
||||
|
|
|
@ -63,7 +63,7 @@ class MatchTest(ShellCase, ShellCaseCommonTestsMixin):
|
|||
|
||||
def test_compound_pcre_grain_and_grain(self):
|
||||
match = 'P@test_grain:^cheese$ and * and G@test_grain:cheese'
|
||||
data = self.run_salt('-t 1 -C \'{0}\' test.ping'.format(match))
|
||||
data = self.run_salt('-t 1 -C "{0}" test.ping'.format(match))
|
||||
assert minion_in_returns('minion', data) is True
|
||||
assert minion_in_returns('sub_minion', data) is False
|
||||
|
||||
|
@ -74,22 +74,22 @@ class MatchTest(ShellCase, ShellCaseCommonTestsMixin):
|
|||
assert minion_in_returns('minion', data) is False
|
||||
|
||||
def test_compound_not_sub_minion(self):
|
||||
data = self.run_salt("-C 'not sub_minion' test.ping")
|
||||
data = self.run_salt('-C "not sub_minion" test.ping')
|
||||
assert minion_in_returns('minion', data) is True
|
||||
assert minion_in_returns('sub_minion', data) is False
|
||||
|
||||
def test_compound_all_and_not_grains(self):
|
||||
data = self.run_salt("-C '* and ( not G@test_grain:cheese )' test.ping")
|
||||
data = self.run_salt('-C "* and ( not G@test_grain:cheese )" test.ping')
|
||||
assert minion_in_returns('minion', data) is False
|
||||
assert minion_in_returns('sub_minion', data) is True
|
||||
|
||||
def test_compound_grain_regex(self):
|
||||
data = self.run_salt("-C 'G%@planets%merc*' test.ping")
|
||||
data = self.run_salt('-C "G%@planets%merc*" test.ping')
|
||||
assert minion_in_returns('minion', data) is True
|
||||
assert minion_in_returns('sub_minion', data) is False
|
||||
|
||||
def test_coumpound_pcre_grain_regex(self):
|
||||
data = self.run_salt("-C 'P%@planets%^(mercury|saturn)$' test.ping")
|
||||
data = self.run_salt('-C "P%@planets%^(mercury|saturn)$" test.ping')
|
||||
assert minion_in_returns('minion', data) is True
|
||||
assert minion_in_returns('sub_minion', data) is True
|
||||
|
||||
|
@ -315,7 +315,7 @@ class MatchTest(ShellCase, ShellCaseCommonTestsMixin):
|
|||
self.assertIn('minion', data.replace('sub_minion', 'stub'))
|
||||
|
||||
def test_ipcidr(self):
|
||||
subnets_data = self.run_salt('--out yaml \'*\' network.subnets')
|
||||
subnets_data = self.run_salt('--out yaml "*" network.subnets')
|
||||
yaml_data = salt.utils.yaml.safe_load('\n'.join(subnets_data))
|
||||
|
||||
# We're just after the first defined subnet from 'minion'
|
||||
|
@ -372,7 +372,11 @@ class MatchTest(ShellCase, ShellCaseCommonTestsMixin):
|
|||
data = self.run_salt('-d minion salt ldap.search "filter=ou=People"', catch_stderr=True)
|
||||
self.assertIn('You can only get documentation for one method at one time', '\n'.join(data[1]))
|
||||
|
||||
@skipIf(salt.utils.platform.is_windows(), 'Skip on Windows OS')
|
||||
def test_issue_7754(self):
|
||||
'''
|
||||
Skip on Windows because Syslog is not installed
|
||||
'''
|
||||
old_cwd = os.getcwd()
|
||||
config_dir = os.path.join(TMP, 'issue-7754')
|
||||
if not os.path.isdir(config_dir):
|
||||
|
|
|
@ -31,6 +31,7 @@ from salt.ext import six
|
|||
# Import salt libs
|
||||
import salt.utils.files
|
||||
import salt.utils.yaml
|
||||
import salt.utils.platform
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
@ -271,9 +272,12 @@ class MinionTest(ShellCase, testprogram.TestProgramCase, ShellCaseCommonTestsMix
|
|||
for minion in minions:
|
||||
minion.shutdown()
|
||||
|
||||
@skipIf(salt.utils.platform.is_windows(), 'Skip on Windows OS')
|
||||
def test_exit_status_unknown_user(self):
|
||||
'''
|
||||
Ensure correct exit status when the minion is configured to run as an unknown user.
|
||||
|
||||
Skipped on windows because daemonization not supported
|
||||
'''
|
||||
|
||||
minion = testprogram.TestDaemonSaltMinion(
|
||||
|
@ -302,6 +306,7 @@ class MinionTest(ShellCase, testprogram.TestProgramCase, ShellCaseCommonTestsMix
|
|||
minion.shutdown()
|
||||
|
||||
# pylint: disable=invalid-name
|
||||
# @skipIf(salt.utils.platform.is_windows(), 'Skip on Windows OS')
|
||||
def test_exit_status_unknown_argument(self):
|
||||
'''
|
||||
Ensure correct exit status when an unknown argument is passed to salt-minion.
|
||||
|
@ -331,9 +336,12 @@ class MinionTest(ShellCase, testprogram.TestProgramCase, ShellCaseCommonTestsMix
|
|||
# cause timeout exceptions and respective traceback
|
||||
minion.shutdown()
|
||||
|
||||
@skipIf(salt.utils.platform.is_windows(), 'Skip on Windows OS')
|
||||
def test_exit_status_correct_usage(self):
|
||||
'''
|
||||
Ensure correct exit status when salt-minion starts correctly.
|
||||
|
||||
Skipped on windows because daemonization not supported
|
||||
'''
|
||||
|
||||
minion = testprogram.TestDaemonSaltMinion(
|
||||
|
|
|
@ -10,13 +10,18 @@
|
|||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
import logging
|
||||
|
||||
from tests.support.unit import skipIf
|
||||
|
||||
# Import salt tests libs
|
||||
import tests.integration.utils
|
||||
from tests.integration.utils import testprogram
|
||||
|
||||
import salt.utils.platform
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@skipIf(salt.utils.platform.is_windows(), 'Skip on Windows OS')
|
||||
class ProxyTest(testprogram.TestProgramCase):
|
||||
'''
|
||||
Various integration tests for the salt-proxy executable.
|
||||
|
@ -25,6 +30,8 @@ class ProxyTest(testprogram.TestProgramCase):
|
|||
def test_exit_status_no_proxyid(self):
|
||||
'''
|
||||
Ensure correct exit status when --proxyid argument is missing.
|
||||
|
||||
Skip on Windows because daemonization not supported
|
||||
'''
|
||||
|
||||
proxy = testprogram.TestDaemonSaltProxy(
|
||||
|
@ -61,6 +68,8 @@ class ProxyTest(testprogram.TestProgramCase):
|
|||
def test_exit_status_unknown_user(self):
|
||||
'''
|
||||
Ensure correct exit status when the proxy is configured to run as an unknown user.
|
||||
|
||||
Skip on Windows because daemonization not supported
|
||||
'''
|
||||
|
||||
proxy = testprogram.TestDaemonSaltProxy(
|
||||
|
@ -92,6 +101,8 @@ class ProxyTest(testprogram.TestProgramCase):
|
|||
def test_exit_status_unknown_argument(self):
|
||||
'''
|
||||
Ensure correct exit status when an unknown argument is passed to salt-proxy.
|
||||
|
||||
Skip on Windows because daemonization not supported
|
||||
'''
|
||||
|
||||
proxy = testprogram.TestDaemonSaltProxy(
|
||||
|
@ -120,6 +131,8 @@ class ProxyTest(testprogram.TestProgramCase):
|
|||
def test_exit_status_correct_usage(self):
|
||||
'''
|
||||
Ensure correct exit status when salt-proxy starts correctly.
|
||||
|
||||
Skip on Windows because daemonization not supported
|
||||
'''
|
||||
|
||||
proxy = testprogram.TestDaemonSaltProxy(
|
||||
|
|
|
@ -15,12 +15,14 @@ from tests.support.case import ShellCase
|
|||
from tests.support.paths import TMP
|
||||
from tests.support.mixins import ShellCaseCommonTestsMixin
|
||||
from tests.support.helpers import skip_if_not_root
|
||||
from tests.support.unit import skipIf
|
||||
|
||||
# Import Salt libs
|
||||
import salt.utils.files
|
||||
import salt.utils.platform
|
||||
import salt.utils.yaml
|
||||
|
||||
|
||||
USERA = 'saltdev'
|
||||
USERA_PWD = 'saltdev'
|
||||
HASHED_USERA_PWD = '$6$SALTsalt$ZZFD90fKFWq8AGmmX0L3uBtS9fXL62SrTk5zcnQ6EkD6zoiM3kB88G1Zvs0xm/gZ7WXJRs5nsTBybUvGSqZkT.'
|
||||
|
@ -90,7 +92,11 @@ class RunTest(ShellCase, testprogram.TestProgramCase, ShellCaseCommonTestsMixin)
|
|||
data = self.run_run('-d virt.list foo', catch_stderr=True)
|
||||
self.assertIn('You can only get documentation for one method at one time', '\n'.join(data[1]))
|
||||
|
||||
@skipIf(salt.utils.platform.is_windows(), 'Skip on Windows OS')
|
||||
def test_issue_7754(self):
|
||||
'''
|
||||
Skip on windows because syslog not available
|
||||
'''
|
||||
old_cwd = os.getcwd()
|
||||
config_dir = os.path.join(TMP, 'issue-7754')
|
||||
if not os.path.isdir(config_dir):
|
||||
|
|
|
@ -18,11 +18,13 @@ import logging
|
|||
from tests.support.case import ShellCase
|
||||
from tests.support.paths import TMP
|
||||
from tests.support.mixins import ShellCaseCommonTestsMixin
|
||||
from tests.support.unit import skipIf
|
||||
from tests.integration.utils import testprogram
|
||||
|
||||
# Import salt libs
|
||||
import salt.utils.files
|
||||
import salt.utils.yaml
|
||||
import salt.utils.platform
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
@ -80,9 +82,12 @@ class SyndicTest(ShellCase, testprogram.TestProgramCase, ShellCaseCommonTestsMix
|
|||
if os.path.isdir(config_dir):
|
||||
shutil.rmtree(config_dir)
|
||||
|
||||
@skipIf(salt.utils.platform.is_windows(), 'Skip on Windows OS')
|
||||
def test_exit_status_unknown_user(self):
|
||||
'''
|
||||
Ensure correct exit status when the syndic is configured to run as an unknown user.
|
||||
|
||||
Skipped on windows because daemonization not supported
|
||||
'''
|
||||
|
||||
syndic = testprogram.TestDaemonSaltSyndic(
|
||||
|
@ -110,9 +115,12 @@ class SyndicTest(ShellCase, testprogram.TestProgramCase, ShellCaseCommonTestsMix
|
|||
syndic.shutdown()
|
||||
|
||||
# pylint: disable=invalid-name
|
||||
@skipIf(salt.utils.platform.is_windows(), 'Skip on Windows OS')
|
||||
def test_exit_status_unknown_argument(self):
|
||||
'''
|
||||
Ensure correct exit status when an unknown argument is passed to salt-syndic.
|
||||
|
||||
Skipped on windows because daemonization not supported
|
||||
'''
|
||||
|
||||
syndic = testprogram.TestDaemonSaltSyndic(
|
||||
|
@ -138,9 +146,12 @@ class SyndicTest(ShellCase, testprogram.TestProgramCase, ShellCaseCommonTestsMix
|
|||
# cause timeout exceptions and respective traceback
|
||||
syndic.shutdown()
|
||||
|
||||
@skipIf(salt.utils.platform.is_windows(), 'Skip on Windows OS')
|
||||
def test_exit_status_correct_usage(self):
|
||||
'''
|
||||
Ensure correct exit status when salt-syndic starts correctly.
|
||||
|
||||
Skipped on windows because daemonization not supported
|
||||
'''
|
||||
|
||||
syndic = testprogram.TestDaemonSaltSyndic(
|
||||
|
|
|
@ -763,6 +763,7 @@ class SPMCase(TestCase, AdaptedConfigurationTestCaseMixin):
|
|||
def run_spm(self, cmd, config, arg=None):
|
||||
client = self._spm_client(config)
|
||||
spm_cmd = client.run([cmd, arg])
|
||||
client._close()
|
||||
return self.ui._status
|
||||
|
||||
|
||||
|
|
|
@ -168,24 +168,3 @@ class RootsTest(TestCase, AdaptedConfigurationTestCaseMixin, LoaderModuleMockMix
|
|||
finally:
|
||||
if self.test_symlink_list_file_roots:
|
||||
self.opts['file_roots'] = orig_file_roots
|
||||
|
||||
|
||||
class RootsLimitTraversalTest(TestCase, AdaptedConfigurationTestCaseMixin):
|
||||
|
||||
def test_limit_traversal(self):
|
||||
'''
|
||||
1) Set up a deep directory structure
|
||||
2) Enable the configuration option 'fileserver_limit_traversal'
|
||||
3) Ensure that we can find SLS files in a directory so long as there is
|
||||
an SLS file in a directory above.
|
||||
4) Ensure that we cannot find an SLS file in a directory that does not
|
||||
have an SLS file in a directory above.
|
||||
|
||||
'''
|
||||
file_client_opts = self.get_temp_config('master')
|
||||
file_client_opts['fileserver_limit_traversal'] = True
|
||||
|
||||
ret = salt.fileclient.Client(file_client_opts).list_states('base')
|
||||
self.assertIn('test_deep.test', ret)
|
||||
self.assertIn('test_deep.a.test', ret)
|
||||
self.assertNotIn('test_deep.b.2.test', ret)
|
||||
|
|
|
@ -87,6 +87,50 @@ class CoreGrainsTestCase(TestCase, LoaderModuleMockMixin):
|
|||
"UBUNTU_CODENAME": "artful",
|
||||
})
|
||||
|
||||
def test_parse_cpe_name_wfn(self):
|
||||
'''
|
||||
Parse correct CPE_NAME data WFN formatted
|
||||
:return:
|
||||
'''
|
||||
for cpe, cpe_ret in [('cpe:/o:opensuse:leap:15.0',
|
||||
{'phase': None, 'version': '15.0', 'product': 'leap',
|
||||
'vendor': 'opensuse', 'part': 'operating system'}),
|
||||
('cpe:/o:vendor:product:42:beta',
|
||||
{'phase': 'beta', 'version': '42', 'product': 'product',
|
||||
'vendor': 'vendor', 'part': 'operating system'})]:
|
||||
ret = core._parse_cpe_name(cpe)
|
||||
for key in cpe_ret:
|
||||
assert key in ret
|
||||
assert cpe_ret[key] == ret[key]
|
||||
|
||||
def test_parse_cpe_name_v23(self):
|
||||
'''
|
||||
Parse correct CPE_NAME data v2.3 formatted
|
||||
:return:
|
||||
'''
|
||||
for cpe, cpe_ret in [('cpe:2.3:o:microsoft:windows_xp:5.1.601:beta:*:*:*:*:*:*',
|
||||
{'phase': 'beta', 'version': '5.1.601', 'product': 'windows_xp',
|
||||
'vendor': 'microsoft', 'part': 'operating system'}),
|
||||
('cpe:2.3:h:corellian:millenium_falcon:1.0:*:*:*:*:*:*:*',
|
||||
{'phase': None, 'version': '1.0', 'product': 'millenium_falcon',
|
||||
'vendor': 'corellian', 'part': 'hardware'}),
|
||||
('cpe:2.3:*:dark_empire:light_saber:3.0:beta:*:*:*:*:*:*',
|
||||
{'phase': 'beta', 'version': '3.0', 'product': 'light_saber',
|
||||
'vendor': 'dark_empire', 'part': None})]:
|
||||
ret = core._parse_cpe_name(cpe)
|
||||
for key in cpe_ret:
|
||||
assert key in ret
|
||||
assert cpe_ret[key] == ret[key]
|
||||
|
||||
def test_parse_cpe_name_broken(self):
|
||||
'''
|
||||
Parse broken CPE_NAME data
|
||||
:return:
|
||||
'''
|
||||
for cpe in ['cpe:broken', 'cpe:broken:in:all:ways:*:*:*:*',
|
||||
'cpe:x:still:broken:123', 'who:/knows:what:is:here']:
|
||||
assert core._parse_cpe_name(cpe) == {}
|
||||
|
||||
def test_missing_os_release(self):
|
||||
with patch('salt.utils.files.fopen', mock_open(read_data={})):
|
||||
os_release = core._parse_os_release('/etc/os-release', '/usr/lib/os-release')
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue