mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
Merge branch '2017.7' into Issue47689-pip-state-performance
This commit is contained in:
commit
d6a49ae41c
101 changed files with 4450 additions and 641 deletions
50
.ci/docs
Normal file
50
.ci/docs
Normal file
|
@ -0,0 +1,50 @@
|
|||
pipeline {
|
||||
agent { label 'docs' }
|
||||
options {
|
||||
timestamps()
|
||||
ansiColor('xterm')
|
||||
}
|
||||
environment {
|
||||
PYENV_ROOT = "/usr/local/pyenv"
|
||||
PATH = "$PYENV_ROOT/bin:$PATH"
|
||||
PY_COLORS = 1
|
||||
}
|
||||
stages {
|
||||
stage('github-pending') {
|
||||
steps {
|
||||
githubNotify credentialsId: 'test-jenkins-credentials',
|
||||
description: 'Testing docs...',
|
||||
status: 'PENDING',
|
||||
context: "jenkins/pr/docs"
|
||||
}
|
||||
}
|
||||
stage('setup') {
|
||||
steps {
|
||||
sh 'eval "$(pyenv init -)"; pyenv install 2.7.14 || echo "We already have this python."; pyenv local 2.7.14; pyenv shell 2.7.14'
|
||||
sh 'eval "$(pyenv init -)"; pip install sphinx -e .'
|
||||
}
|
||||
}
|
||||
stage('build') {
|
||||
steps {
|
||||
sh 'eval "$(pyenv init -)"; make -C doc clean html'
|
||||
}
|
||||
}
|
||||
}
|
||||
post {
|
||||
always {
|
||||
cleanWs()
|
||||
}
|
||||
success {
|
||||
githubNotify credentialsId: 'test-jenkins-credentials',
|
||||
description: 'The docs job has passed',
|
||||
status: 'SUCCESS',
|
||||
context: "jenkins/pr/docs"
|
||||
}
|
||||
failure {
|
||||
githubNotify credentialsId: 'test-jenkins-credentials',
|
||||
description: 'The docs job has failed',
|
||||
status: 'FAILURE',
|
||||
context: "jenkins/pr/docs"
|
||||
}
|
||||
}
|
||||
}
|
71
.ci/kitchen-centos7-py2
Normal file
71
.ci/kitchen-centos7-py2
Normal file
|
@ -0,0 +1,71 @@
|
|||
pipeline {
|
||||
agent { label 'kitchen-slave' }
|
||||
options {
|
||||
timestamps()
|
||||
ansiColor('xterm')
|
||||
}
|
||||
environment {
|
||||
SALT_KITCHEN_PLATFORMS = "/var/jenkins/workspace/platforms.yml"
|
||||
SALT_KITCHEN_DRIVER = "/var/jenkins/workspace/driver.yml"
|
||||
PATH = "/usr/local/rbenv/shims/:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/root/bin"
|
||||
RBENV_VERSION = "2.4.2"
|
||||
TEST_SUITE = "py2"
|
||||
TEST_PLATFORM = "centos-7"
|
||||
PY_COLORS = 1
|
||||
}
|
||||
stages {
|
||||
stage('github-pending') {
|
||||
steps {
|
||||
githubNotify credentialsId: 'test-jenkins-credentials',
|
||||
description: "running ${TEST_SUITE}-${TEST_PLATFORM}...",
|
||||
status: 'PENDING',
|
||||
context: "jenkins/pr/${TEST_SUITE}-${TEST_PLATFORM}"
|
||||
}
|
||||
}
|
||||
stage('setup') {
|
||||
steps {
|
||||
sh 'bundle install --with ec2 windows --without opennebula docker'
|
||||
}
|
||||
}
|
||||
stage('run kitchen') {
|
||||
steps {
|
||||
script { withCredentials([[$class: 'AmazonWebServicesCredentialsBinding', accessKeyVariable: 'AWS_ACCESS_KEY_ID', credentialsId: 'AWS_ACCESS_KEY_ID', secretKeyVariable: 'AWS_SECRET_ACCESS_KEY']]) {
|
||||
sshagent(credentials: ['jenkins-testing-ssh-key']) {
|
||||
sh 'ssh-add ~/.ssh/jenkins-testing.pem'
|
||||
sh 'bundle exec kitchen converge $TEST_SUITE-$TEST_PLATFORM || bundle exec kitchen converge $TEST_SUITE-$TEST_PLATFORM'
|
||||
sh 'bundle exec kitchen verify $TEST_SUITE-$TEST_PLATFORM'
|
||||
}
|
||||
}}
|
||||
}
|
||||
post {
|
||||
always {
|
||||
script { withCredentials([[$class: 'AmazonWebServicesCredentialsBinding', accessKeyVariable: 'AWS_ACCESS_KEY_ID', credentialsId: 'AWS_ACCESS_KEY_ID', secretKeyVariable: 'AWS_SECRET_ACCESS_KEY']]) {
|
||||
sshagent(credentials: ['jenkins-testing-ssh-key']) {
|
||||
sh 'ssh-add ~/.ssh/jenkins-testing.pem'
|
||||
sh 'bundle exec kitchen destroy $TEST_SUITE-$TEST_PLATFORM'
|
||||
}
|
||||
}}
|
||||
archiveArtifacts artifacts: 'artifacts/xml-unittests-output/*.xml'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
post {
|
||||
always {
|
||||
junit 'artifacts/xml-unittests-output/*.xml'
|
||||
cleanWs()
|
||||
}
|
||||
success {
|
||||
githubNotify credentialsId: 'test-jenkins-credentials',
|
||||
description: "The ${TEST_SUITE}-${TEST_PLATFORM} job has passed",
|
||||
status: 'SUCCESS',
|
||||
context: "jenkins/pr/${TEST_SUITE}-${TEST_PLATFORM}"
|
||||
}
|
||||
failure {
|
||||
githubNotify credentialsId: 'test-jenkins-credentials',
|
||||
description: "The ${TEST_SUITE}-${TEST_PLATFORM} job has failed",
|
||||
status: 'FAILURE',
|
||||
context: "jenkins/pr/${TEST_SUITE}-${TEST_PLATFORM}"
|
||||
}
|
||||
}
|
||||
}
|
71
.ci/kitchen-centos7-py3
Normal file
71
.ci/kitchen-centos7-py3
Normal file
|
@ -0,0 +1,71 @@
|
|||
pipeline {
|
||||
agent { label 'kitchen-slave' }
|
||||
options {
|
||||
timestamps()
|
||||
ansiColor('xterm')
|
||||
}
|
||||
environment {
|
||||
SALT_KITCHEN_PLATFORMS = "/var/jenkins/workspace/platforms.yml"
|
||||
SALT_KITCHEN_DRIVER = "/var/jenkins/workspace/driver.yml"
|
||||
PATH = "/usr/local/rbenv/shims/:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/root/bin"
|
||||
RBENV_VERSION = "2.4.2"
|
||||
TEST_SUITE = "py3"
|
||||
TEST_PLATFORM = "centos-7"
|
||||
PY_COLORS = 1
|
||||
}
|
||||
stages {
|
||||
stage('github-pending') {
|
||||
steps {
|
||||
githubNotify credentialsId: 'test-jenkins-credentials',
|
||||
description: "running ${TEST_SUITE}-${TEST_PLATFORM}...",
|
||||
status: 'PENDING',
|
||||
context: "jenkins/pr/${TEST_SUITE}-${TEST_PLATFORM}"
|
||||
}
|
||||
}
|
||||
stage('setup') {
|
||||
steps {
|
||||
sh 'bundle install --with ec2 windows --without opennebula docker'
|
||||
}
|
||||
}
|
||||
stage('run kitchen') {
|
||||
steps {
|
||||
script { withCredentials([[$class: 'AmazonWebServicesCredentialsBinding', accessKeyVariable: 'AWS_ACCESS_KEY_ID', credentialsId: 'AWS_ACCESS_KEY_ID', secretKeyVariable: 'AWS_SECRET_ACCESS_KEY']]) {
|
||||
sshagent(credentials: ['jenkins-testing-ssh-key']) {
|
||||
sh 'ssh-add ~/.ssh/jenkins-testing.pem'
|
||||
sh 'bundle exec kitchen converge $TEST_SUITE-$TEST_PLATFORM || bundle exec kitchen converge $TEST_SUITE-$TEST_PLATFORM'
|
||||
sh 'bundle exec kitchen verify $TEST_SUITE-$TEST_PLATFORM'
|
||||
}
|
||||
}}
|
||||
}
|
||||
post {
|
||||
always {
|
||||
script { withCredentials([[$class: 'AmazonWebServicesCredentialsBinding', accessKeyVariable: 'AWS_ACCESS_KEY_ID', credentialsId: 'AWS_ACCESS_KEY_ID', secretKeyVariable: 'AWS_SECRET_ACCESS_KEY']]) {
|
||||
sshagent(credentials: ['jenkins-testing-ssh-key']) {
|
||||
sh 'ssh-add ~/.ssh/jenkins-testing.pem'
|
||||
sh 'bundle exec kitchen destroy $TEST_SUITE-$TEST_PLATFORM'
|
||||
}
|
||||
}}
|
||||
archiveArtifacts artifacts: 'artifacts/xml-unittests-output/*.xml'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
post {
|
||||
always {
|
||||
junit 'artifacts/xml-unittests-output/*.xml'
|
||||
cleanWs()
|
||||
}
|
||||
success {
|
||||
githubNotify credentialsId: 'test-jenkins-credentials',
|
||||
description: "The ${TEST_SUITE}-${TEST_PLATFORM} job has passed",
|
||||
status: 'SUCCESS',
|
||||
context: "jenkins/pr/${TEST_SUITE}-${TEST_PLATFORM}"
|
||||
}
|
||||
failure {
|
||||
githubNotify credentialsId: 'test-jenkins-credentials',
|
||||
description: "The ${TEST_SUITE}-${TEST_PLATFORM} job has failed",
|
||||
status: 'FAILURE',
|
||||
context: "jenkins/pr/${TEST_SUITE}-${TEST_PLATFORM}"
|
||||
}
|
||||
}
|
||||
}
|
71
.ci/kitchen-ubuntu1604-py2
Normal file
71
.ci/kitchen-ubuntu1604-py2
Normal file
|
@ -0,0 +1,71 @@
|
|||
pipeline {
|
||||
agent { label 'kitchen-slave' }
|
||||
options {
|
||||
timestamps()
|
||||
ansiColor('xterm')
|
||||
}
|
||||
environment {
|
||||
SALT_KITCHEN_PLATFORMS = "/var/jenkins/workspace/platforms.yml"
|
||||
SALT_KITCHEN_DRIVER = "/var/jenkins/workspace/driver.yml"
|
||||
PATH = "/usr/local/rbenv/shims/:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/root/bin"
|
||||
RBENV_VERSION = "2.4.2"
|
||||
TEST_SUITE = "py2"
|
||||
TEST_PLATFORM = "ubuntu-1604"
|
||||
PY_COLORS = 1
|
||||
}
|
||||
stages {
|
||||
stage('github-pending') {
|
||||
steps {
|
||||
githubNotify credentialsId: 'test-jenkins-credentials',
|
||||
description: "running ${TEST_SUITE}-${TEST_PLATFORM}...",
|
||||
status: 'PENDING',
|
||||
context: "jenkins/pr/${TEST_SUITE}-${TEST_PLATFORM}"
|
||||
}
|
||||
}
|
||||
stage('setup') {
|
||||
steps {
|
||||
sh 'bundle install --with ec2 windows --without opennebula docker'
|
||||
}
|
||||
}
|
||||
stage('run kitchen') {
|
||||
steps {
|
||||
script { withCredentials([[$class: 'AmazonWebServicesCredentialsBinding', accessKeyVariable: 'AWS_ACCESS_KEY_ID', credentialsId: 'AWS_ACCESS_KEY_ID', secretKeyVariable: 'AWS_SECRET_ACCESS_KEY']]) {
|
||||
sshagent(credentials: ['jenkins-testing-ssh-key']) {
|
||||
sh 'ssh-add ~/.ssh/jenkins-testing.pem'
|
||||
sh 'bundle exec kitchen converge $TEST_SUITE-$TEST_PLATFORM || bundle exec kitchen converge $TEST_SUITE-$TEST_PLATFORM'
|
||||
sh 'bundle exec kitchen verify $TEST_SUITE-$TEST_PLATFORM'
|
||||
}
|
||||
}}
|
||||
}
|
||||
post {
|
||||
always {
|
||||
script { withCredentials([[$class: 'AmazonWebServicesCredentialsBinding', accessKeyVariable: 'AWS_ACCESS_KEY_ID', credentialsId: 'AWS_ACCESS_KEY_ID', secretKeyVariable: 'AWS_SECRET_ACCESS_KEY']]) {
|
||||
sshagent(credentials: ['jenkins-testing-ssh-key']) {
|
||||
sh 'ssh-add ~/.ssh/jenkins-testing.pem'
|
||||
sh 'bundle exec kitchen destroy $TEST_SUITE-$TEST_PLATFORM'
|
||||
}
|
||||
}}
|
||||
archiveArtifacts artifacts: 'artifacts/xml-unittests-output/*.xml'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
post {
|
||||
always {
|
||||
junit 'artifacts/xml-unittests-output/*.xml'
|
||||
cleanWs()
|
||||
}
|
||||
success {
|
||||
githubNotify credentialsId: 'test-jenkins-credentials',
|
||||
description: "The ${TEST_SUITE}-${TEST_PLATFORM} job has passed",
|
||||
status: 'SUCCESS',
|
||||
context: "jenkins/pr/${TEST_SUITE}-${TEST_PLATFORM}"
|
||||
}
|
||||
failure {
|
||||
githubNotify credentialsId: 'test-jenkins-credentials',
|
||||
description: "The ${TEST_SUITE}-${TEST_PLATFORM} job has failed",
|
||||
status: 'FAILURE',
|
||||
context: "jenkins/pr/${TEST_SUITE}-${TEST_PLATFORM}"
|
||||
}
|
||||
}
|
||||
}
|
71
.ci/kitchen-ubuntu1604-py3
Normal file
71
.ci/kitchen-ubuntu1604-py3
Normal file
|
@ -0,0 +1,71 @@
|
|||
pipeline {
|
||||
agent { label 'kitchen-slave' }
|
||||
options {
|
||||
timestamps()
|
||||
ansiColor('xterm')
|
||||
}
|
||||
environment {
|
||||
SALT_KITCHEN_PLATFORMS = "/var/jenkins/workspace/platforms.yml"
|
||||
SALT_KITCHEN_DRIVER = "/var/jenkins/workspace/driver.yml"
|
||||
PATH = "/usr/local/rbenv/shims/:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/root/bin"
|
||||
RBENV_VERSION = "2.4.2"
|
||||
TEST_SUITE = "py3"
|
||||
TEST_PLATFORM = "ubuntu-1604"
|
||||
PY_COLORS = 1
|
||||
}
|
||||
stages {
|
||||
stage('github-pending') {
|
||||
steps {
|
||||
githubNotify credentialsId: 'test-jenkins-credentials',
|
||||
description: "running ${TEST_SUITE}-${TEST_PLATFORM}...",
|
||||
status: 'PENDING',
|
||||
context: "jenkins/pr/${TEST_SUITE}-${TEST_PLATFORM}"
|
||||
}
|
||||
}
|
||||
stage('setup') {
|
||||
steps {
|
||||
sh 'bundle install --with ec2 windows --without opennebula docker'
|
||||
}
|
||||
}
|
||||
stage('run kitchen') {
|
||||
steps {
|
||||
script { withCredentials([[$class: 'AmazonWebServicesCredentialsBinding', accessKeyVariable: 'AWS_ACCESS_KEY_ID', credentialsId: 'AWS_ACCESS_KEY_ID', secretKeyVariable: 'AWS_SECRET_ACCESS_KEY']]) {
|
||||
sshagent(credentials: ['jenkins-testing-ssh-key']) {
|
||||
sh 'ssh-add ~/.ssh/jenkins-testing.pem'
|
||||
sh 'bundle exec kitchen converge $TEST_SUITE-$TEST_PLATFORM || bundle exec kitchen converge $TEST_SUITE-$TEST_PLATFORM'
|
||||
sh 'bundle exec kitchen verify $TEST_SUITE-$TEST_PLATFORM'
|
||||
}
|
||||
}}
|
||||
}
|
||||
post {
|
||||
always {
|
||||
script { withCredentials([[$class: 'AmazonWebServicesCredentialsBinding', accessKeyVariable: 'AWS_ACCESS_KEY_ID', credentialsId: 'AWS_ACCESS_KEY_ID', secretKeyVariable: 'AWS_SECRET_ACCESS_KEY']]) {
|
||||
sshagent(credentials: ['jenkins-testing-ssh-key']) {
|
||||
sh 'ssh-add ~/.ssh/jenkins-testing.pem'
|
||||
sh 'bundle exec kitchen destroy $TEST_SUITE-$TEST_PLATFORM'
|
||||
}
|
||||
}}
|
||||
archiveArtifacts artifacts: 'artifacts/xml-unittests-output/*.xml'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
post {
|
||||
always {
|
||||
junit 'artifacts/xml-unittests-output/*.xml'
|
||||
cleanWs()
|
||||
}
|
||||
success {
|
||||
githubNotify credentialsId: 'test-jenkins-credentials',
|
||||
description: "The ${TEST_SUITE}-${TEST_PLATFORM} job has passed",
|
||||
status: 'SUCCESS',
|
||||
context: "jenkins/pr/${TEST_SUITE}-${TEST_PLATFORM}"
|
||||
}
|
||||
failure {
|
||||
githubNotify credentialsId: 'test-jenkins-credentials',
|
||||
description: "The ${TEST_SUITE}-${TEST_PLATFORM} job has failed",
|
||||
status: 'FAILURE',
|
||||
context: "jenkins/pr/${TEST_SUITE}-${TEST_PLATFORM}"
|
||||
}
|
||||
}
|
||||
}
|
70
.ci/lint
Normal file
70
.ci/lint
Normal file
|
@ -0,0 +1,70 @@
|
|||
pipeline {
|
||||
agent { label 'pr-lint-slave' }
|
||||
options {
|
||||
timestamps()
|
||||
ansiColor('xterm')
|
||||
}
|
||||
environment {
|
||||
PYENV_ROOT = "/usr/local/pyenv"
|
||||
PATH = "$PYENV_ROOT/bin:$PATH"
|
||||
PY_COLORS = 1
|
||||
}
|
||||
stages {
|
||||
stage('github-pending') {
|
||||
steps {
|
||||
githubNotify credentialsId: 'test-jenkins-credentials',
|
||||
description: 'Testing lint...',
|
||||
status: 'PENDING',
|
||||
context: "jenkins/pr/lint"
|
||||
}
|
||||
}
|
||||
stage('setup') {
|
||||
steps {
|
||||
sh 'eval "$(pyenv init -)"; pyenv install 2.7.14 || echo "We already have this python."; pyenv local 2.7.14; pyenv shell 2.7.14'
|
||||
sh 'eval "$(pyenv init -)"; pip install tox'
|
||||
}
|
||||
}
|
||||
stage('linting') {
|
||||
failFast false
|
||||
parallel {
|
||||
stage('salt linting') {
|
||||
steps {
|
||||
sh 'eval "$(pyenv init -)"; tox -e pylint-salt | tee pylint-report.xml'
|
||||
archiveArtifacts artifacts: 'pylint-report.xml'
|
||||
}
|
||||
}
|
||||
stage('test linting') {
|
||||
steps {
|
||||
sh 'eval "$(pyenv init -)"; tox -e pylint-tests | tee pylint-report-tests.xml'
|
||||
archiveArtifacts artifacts: 'pylint-report-tests.xml'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
post {
|
||||
always {
|
||||
step([$class: 'WarningsPublisher',
|
||||
parserConfigurations: [[
|
||||
parserName: 'PyLint',
|
||||
pattern: 'pylint-report*.xml'
|
||||
]],
|
||||
failedTotalAll: '1',
|
||||
usePreviousBuildAsReference: true
|
||||
])
|
||||
cleanWs()
|
||||
}
|
||||
success {
|
||||
githubNotify credentialsId: 'test-jenkins-credentials',
|
||||
description: 'The lint job has passed',
|
||||
status: 'SUCCESS',
|
||||
context: "jenkins/pr/lint"
|
||||
}
|
||||
failure {
|
||||
githubNotify credentialsId: 'test-jenkins-credentials',
|
||||
description: 'The lint job has failed',
|
||||
status: 'FAILURE',
|
||||
context: "jenkins/pr/lint"
|
||||
}
|
||||
}
|
||||
}
|
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
|
@ -48,6 +48,7 @@ salt/spm/* @saltstack/team-spm
|
|||
# Team SSH
|
||||
salt/cli/ssh.py @saltstack/team-ssh
|
||||
salt/client/ssh/* @saltstack/team-ssh
|
||||
salt/roster/* @saltstack/team-ssh
|
||||
salt/runners/ssh.py @saltstack/team-ssh
|
||||
salt/**/thin.py @saltstack/team-ssh
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
<% vagrant = system('gem list -i kitchen-vagrant 2>/dev/null >/dev/null') %>
|
||||
<% version = '2017.7.4' %>
|
||||
<% version = '2017.7.6' %>
|
||||
<% platformsfile = ENV['SALT_KITCHEN_PLATFORMS'] || '.kitchen/platforms.yml' %>
|
||||
<% driverfile = ENV['SALT_KITCHEN_DRIVER'] || '.kitchen/driver.yml' %>
|
||||
<% verifierfile = ENV['SALT_KITCHEN_VERIFIER'] || '.kitchen/verifier.yml' %>
|
||||
|
@ -31,7 +31,7 @@ provisioner:
|
|||
salt_version: latest
|
||||
salt_bootstrap_url: https://bootstrap.saltstack.com
|
||||
salt_bootstrap_options: -X -p rsync stable <%= version %>
|
||||
log_level: debug
|
||||
log_level: info
|
||||
sudo: true
|
||||
require_chef: false
|
||||
retry_on_exit_code:
|
||||
|
|
|
@ -250,8 +250,8 @@ on_saltstack = 'SALT_ON_SALTSTACK' in os.environ
|
|||
project = 'Salt'
|
||||
|
||||
version = salt.version.__version__
|
||||
latest_release = '2018.3.1' # latest release
|
||||
previous_release = '2017.7.6' # latest release from previous branch
|
||||
latest_release = '2018.3.2' # latest release
|
||||
previous_release = '2017.7.7' # latest release from previous branch
|
||||
previous_release_dir = '2017.7' # path on web server for previous branch
|
||||
next_release = '' # next release
|
||||
next_release_dir = '' # path on web server for next release branch
|
||||
|
|
23
doc/faq.rst
23
doc/faq.rst
|
@ -148,22 +148,23 @@ Why aren't my custom modules/states/etc. available on my Minions?
|
|||
-----------------------------------------------------------------
|
||||
|
||||
Custom modules are synced to Minions when
|
||||
:mod:`saltutil.sync_modules <salt.modules.saltutil.sync_modules>`,
|
||||
or :mod:`saltutil.sync_all <salt.modules.saltutil.sync_all>` is run.
|
||||
Custom modules are also synced by :mod:`state.apply` when run without
|
||||
any arguments.
|
||||
:py:func:`saltutil.sync_modules <salt.modules.saltutil.sync_modules>`,
|
||||
or :py:func:`saltutil.sync_all <salt.modules.saltutil.sync_all>` is run.
|
||||
|
||||
Similarly, custom states are synced to Minions when :py:func:`saltutil.sync_states
|
||||
<salt.modules.saltutil.sync_states>`, or :py:func:`saltutil.sync_all
|
||||
<salt.modules.saltutil.sync_all>` is run.
|
||||
|
||||
Similarly, custom states are synced to Minions
|
||||
when :mod:`state.apply <salt.modules.state.apply_>`,
|
||||
:mod:`saltutil.sync_states <salt.modules.saltutil.sync_states>`, or
|
||||
:mod:`saltutil.sync_all <salt.modules.saltutil.sync_all>` is run.
|
||||
They are both also synced when a :ref:`highstate <running-highstate>` is
|
||||
triggered.
|
||||
|
||||
Custom states are also synced by :mod:`state.apply<salt.modules.state.apply_>`
|
||||
when run without any arguments.
|
||||
As of the Fluorine release, as well as 2017.7.7 and 2018.3.2 in their
|
||||
respective release cycles, the ``sync`` argument to :py:func:`state.apply
|
||||
<salt.modules.state.apply_>`/:py:func:`state.sls <salt.modules.state.sls>` can
|
||||
be used to sync custom types when running individual SLS files.
|
||||
|
||||
Other custom types (renderers, outputters, etc.) have similar behavior, see the
|
||||
documentation for the :mod:`saltutil <salt.modules.saltutil>` module for more
|
||||
documentation for the :py:func:`saltutil <salt.modules.saltutil>` module for more
|
||||
information.
|
||||
|
||||
:ref:`This reactor example <minion-start-reactor>` can be used to automatically
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.\" Man page generated from reStructuredText.
|
||||
.
|
||||
.TH "SALT-API" "1" "May 07, 2018" "2017.7.6" "Salt"
|
||||
.TH "SALT-API" "1" "Jun 14, 2018" "2017.7.7" "Salt"
|
||||
.SH NAME
|
||||
salt-api \- salt-api Command
|
||||
.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.\" Man page generated from reStructuredText.
|
||||
.
|
||||
.TH "SALT-CALL" "1" "May 07, 2018" "2017.7.6" "Salt"
|
||||
.TH "SALT-CALL" "1" "Jun 14, 2018" "2017.7.7" "Salt"
|
||||
.SH NAME
|
||||
salt-call \- salt-call Documentation
|
||||
.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.\" Man page generated from reStructuredText.
|
||||
.
|
||||
.TH "SALT-CLOUD" "1" "May 07, 2018" "2017.7.6" "Salt"
|
||||
.TH "SALT-CLOUD" "1" "Jun 14, 2018" "2017.7.7" "Salt"
|
||||
.SH NAME
|
||||
salt-cloud \- Salt Cloud Command
|
||||
.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.\" Man page generated from reStructuredText.
|
||||
.
|
||||
.TH "SALT-CP" "1" "May 07, 2018" "2017.7.6" "Salt"
|
||||
.TH "SALT-CP" "1" "Jun 14, 2018" "2017.7.7" "Salt"
|
||||
.SH NAME
|
||||
salt-cp \- salt-cp Documentation
|
||||
.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.\" Man page generated from reStructuredText.
|
||||
.
|
||||
.TH "SALT-KEY" "1" "May 07, 2018" "2017.7.6" "Salt"
|
||||
.TH "SALT-KEY" "1" "Jun 14, 2018" "2017.7.7" "Salt"
|
||||
.SH NAME
|
||||
salt-key \- salt-key Documentation
|
||||
.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.\" Man page generated from reStructuredText.
|
||||
.
|
||||
.TH "SALT-MASTER" "1" "May 07, 2018" "2017.7.6" "Salt"
|
||||
.TH "SALT-MASTER" "1" "Jun 14, 2018" "2017.7.7" "Salt"
|
||||
.SH NAME
|
||||
salt-master \- salt-master Documentation
|
||||
.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.\" Man page generated from reStructuredText.
|
||||
.
|
||||
.TH "SALT-MINION" "1" "May 07, 2018" "2017.7.6" "Salt"
|
||||
.TH "SALT-MINION" "1" "Jun 14, 2018" "2017.7.7" "Salt"
|
||||
.SH NAME
|
||||
salt-minion \- salt-minion Documentation
|
||||
.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.\" Man page generated from reStructuredText.
|
||||
.
|
||||
.TH "SALT-PROXY" "1" "May 07, 2018" "2017.7.6" "Salt"
|
||||
.TH "SALT-PROXY" "1" "Jun 14, 2018" "2017.7.7" "Salt"
|
||||
.SH NAME
|
||||
salt-proxy \- salt-proxy Documentation
|
||||
.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.\" Man page generated from reStructuredText.
|
||||
.
|
||||
.TH "SALT-RUN" "1" "May 07, 2018" "2017.7.6" "Salt"
|
||||
.TH "SALT-RUN" "1" "Jun 14, 2018" "2017.7.7" "Salt"
|
||||
.SH NAME
|
||||
salt-run \- salt-run Documentation
|
||||
.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.\" Man page generated from reStructuredText.
|
||||
.
|
||||
.TH "SALT-SSH" "1" "May 07, 2018" "2017.7.6" "Salt"
|
||||
.TH "SALT-SSH" "1" "Jun 14, 2018" "2017.7.7" "Salt"
|
||||
.SH NAME
|
||||
salt-ssh \- salt-ssh Documentation
|
||||
.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.\" Man page generated from reStructuredText.
|
||||
.
|
||||
.TH "SALT-SYNDIC" "1" "May 07, 2018" "2017.7.6" "Salt"
|
||||
.TH "SALT-SYNDIC" "1" "Jun 14, 2018" "2017.7.7" "Salt"
|
||||
.SH NAME
|
||||
salt-syndic \- salt-syndic Documentation
|
||||
.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.\" Man page generated from reStructuredText.
|
||||
.
|
||||
.TH "SALT-UNITY" "1" "May 07, 2018" "2017.7.6" "Salt"
|
||||
.TH "SALT-UNITY" "1" "Jun 14, 2018" "2017.7.7" "Salt"
|
||||
.SH NAME
|
||||
salt-unity \- salt-unity Command
|
||||
.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.\" Man page generated from reStructuredText.
|
||||
.
|
||||
.TH "SALT" "1" "May 07, 2018" "2017.7.6" "Salt"
|
||||
.TH "SALT" "1" "Jun 14, 2018" "2017.7.7" "Salt"
|
||||
.SH NAME
|
||||
salt \- salt
|
||||
.
|
||||
|
|
2559
doc/man/salt.7
2559
doc/man/salt.7
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,6 @@
|
|||
.\" Man page generated from reStructuredText.
|
||||
.
|
||||
.TH "SPM" "1" "May 07, 2018" "2017.7.6" "Salt"
|
||||
.TH "SPM" "1" "Jun 14, 2018" "2017.7.7" "Salt"
|
||||
.SH NAME
|
||||
spm \- Salt Package Manager Command
|
||||
.
|
||||
|
|
|
@ -1162,6 +1162,40 @@ The password used for HTTP proxy access.
|
|||
|
||||
proxy_password: obolus
|
||||
|
||||
Docker Configuration
|
||||
====================
|
||||
|
||||
.. conf_minion:: docker.update_mine
|
||||
|
||||
``docker.update_mine``
|
||||
----------------------
|
||||
|
||||
.. versionadded:: 2017.7.8,2018.3.3
|
||||
.. versionchanged:: Fluorine
|
||||
The default value is now ``False``
|
||||
|
||||
Default: ``True``
|
||||
|
||||
If enabled, when containers are added, removed, stopped, started, etc., the
|
||||
:ref:`mine <salt-mine>` will be updated with the results of :py:func:`docker.ps
|
||||
verbose=True all=True host=True <salt.modules.dockermod.ps>`. This mine data is
|
||||
used by :py:func:`mine.get_docker <salt.modules.mine.get_docker>`. Set this
|
||||
option to ``False`` to keep Salt from updating the mine with this information.
|
||||
|
||||
.. note::
|
||||
This option can also be set in Grains or Pillar data, with Grains
|
||||
overriding Pillar and the minion config file overriding Grains.
|
||||
|
||||
.. note::
|
||||
Disabling this will of course keep :py:func:`mine.get_docker
|
||||
<salt.modules.mine.get_docker>` from returning any information for a given
|
||||
minion.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
docker.update_mine: False
|
||||
|
||||
|
||||
Minion Module Management
|
||||
========================
|
||||
|
||||
|
|
|
@ -1,27 +1,67 @@
|
|||
========================================
|
||||
In Progress: Salt 2017.7.7 Release Notes
|
||||
========================================
|
||||
===========================
|
||||
Salt 2017.7.7 Release Notes
|
||||
===========================
|
||||
|
||||
Version 2017.7.7 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.
|
||||
Version 2017.7.7 is a bugfix release for :ref:`2017.7.0 <release-2017-7-0>`.
|
||||
|
||||
The ``2017.7.7`` release contains only a single fix for Issue `#48038`_, which
|
||||
is a critical bug that occurs in a multi-syndic setup where the same job is run
|
||||
multiple times on a minion.
|
||||
The ``2017.7.7`` release contains only a small number of fixes, which are detailed
|
||||
below.
|
||||
|
||||
This release fixes two critical issues.
|
||||
|
||||
The first is Issue `#48038`_, which is a critical bug that occurs in a multi-syndic
|
||||
setup where the same job is run multiple times on a minion.
|
||||
|
||||
The second issue is `#48130`_. This bug appears in certain setups where the Master
|
||||
reports a Minion time-out, even though the job is still running on the Minion.
|
||||
|
||||
Both of these issues have been fixed with this release.
|
||||
|
||||
Statistics
|
||||
==========
|
||||
|
||||
- Total Merges: **1**
|
||||
- Total Issue References: **1**
|
||||
- Total PR References: **2**
|
||||
- Total Merges: **5**
|
||||
- Total Issue References: **2**
|
||||
- Total PR References: **6**
|
||||
|
||||
- Contributors: **2** (`garethgreenaway`_, `rallytime`_)
|
||||
- Contributors: **3** (`garethgreenaway`_, `gtmanfred`_, `rallytime`_)
|
||||
|
||||
Changelog for v2017.7.6..v2017.7.7
|
||||
==================================
|
||||
|
||||
*Generated at: 2018-06-14 15:43:34 UTC*
|
||||
*Generated at: 2018-06-17 19:26:52 UTC*
|
||||
|
||||
* **ISSUE** `#48130`_: (`rmarchei`_) Minion timeouts with 2018.3.1 (refs: `#48157`_)
|
||||
|
||||
* **PR** `#48157`_: (`gtmanfred`_) always listen when gathering job info
|
||||
@ *2018-06-17 19:04:09 UTC*
|
||||
|
||||
* 8af4452134 Merge pull request `#48157`_ from gtmanfred/2017.7.7
|
||||
|
||||
* d8209e8a40 always listen when gathering job info
|
||||
|
||||
* **PR** `#48140`_: (`rallytime`_) Update man pages for 2017.7.7
|
||||
@ *2018-06-14 21:22:43 UTC*
|
||||
|
||||
* b98c52ee51 Merge pull request `#48140`_ from rallytime/man-pages-2017.7.7
|
||||
|
||||
* 8893bf0d4c Update man pages for 2017.7.7
|
||||
|
||||
* **PR** `#48136`_: (`gtmanfred`_) [2017.7.7] bootstrap kitchen branch tests with 2017.7.6
|
||||
@ *2018-06-14 21:20:16 UTC*
|
||||
|
||||
* baa0363336 Merge pull request `#48136`_ from gtmanfred/2017.7.7
|
||||
|
||||
* fce1c31146 bootstrap kitchen branch tests with 2017.7.6
|
||||
|
||||
* **PR** `#48134`_: (`rallytime`_) Add release notes file for 2017.7.7
|
||||
@ *2018-06-14 16:31:34 UTC*
|
||||
|
||||
* b0ba08f4d9 Merge pull request `#48134`_ from rallytime/release-notes-2017.7.7
|
||||
|
||||
* 217005b8f1 Add missing `v` for tag reference
|
||||
|
||||
* d53569d1e3 Add release notes file for 2017.7.7
|
||||
|
||||
* **ISSUE** `#48038`_: (`austinpapp`_) jobs are not dedup'ing minion side (refs: `#48075`_)
|
||||
|
||||
|
@ -37,6 +77,13 @@ Changelog for v2017.7.6..v2017.7.7
|
|||
.. _`#48038`: https://github.com/saltstack/salt/issues/48038
|
||||
.. _`#48075`: https://github.com/saltstack/salt/pull/48075
|
||||
.. _`#48098`: https://github.com/saltstack/salt/pull/48098
|
||||
.. _`#48130`: https://github.com/saltstack/salt/issues/48130
|
||||
.. _`#48134`: https://github.com/saltstack/salt/pull/48134
|
||||
.. _`#48136`: https://github.com/saltstack/salt/pull/48136
|
||||
.. _`#48140`: https://github.com/saltstack/salt/pull/48140
|
||||
.. _`#48157`: https://github.com/saltstack/salt/pull/48157
|
||||
.. _`austinpapp`: https://github.com/austinpapp
|
||||
.. _`garethgreenaway`: https://github.com/garethgreenaway
|
||||
.. _`gtmanfred`: https://github.com/gtmanfred
|
||||
.. _`rallytime`: https://github.com/rallytime
|
||||
.. _`rmarchei`: https://github.com/rmarchei
|
||||
|
|
|
@ -16,3 +16,16 @@ New win_snmp behavior
|
|||
- :py:func:`win_snmp.set_community_names
|
||||
<salt.modules.win_snmp.set_community_names>` now raises an error when SNMP
|
||||
settings are being managed by GroupPolicy.
|
||||
|
||||
Option Added to Disable Docker Mine Updates
|
||||
===========================================
|
||||
|
||||
When a docker container is added, removed, started, stopped, etc., the results
|
||||
of a :py:func:`docker.ps verbose=True all=True host=True
|
||||
<salt.modules.dockermod.ps>` are sent to the :ref:`mine <salt-mine>`, to be
|
||||
used by :py:func:`mine.get_docker <salt.modules.mine.get_docker>`.
|
||||
|
||||
A new config option (:conf_minion:`docker.update_mine`) has been added. When
|
||||
set to ``False``, Salt will not send this information to the mine. This is
|
||||
useful in cases where sensitive information is stored in the container's
|
||||
environment.
|
||||
|
|
|
@ -330,7 +330,13 @@ Nested pillar values can also be set via the command line:
|
|||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' state.sls my_sls_file pillar='{"foo": {"bar": "baz"}}'
|
||||
salt '*' state.sls my_sls_file pillar='{"foo": {"bar": "baz"}}'
|
||||
|
||||
Lists can be passed via command line pillar data as follows:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' state.sls my_sls_file pillar='{"some_list": ["foo", "bar", "baz"]}'
|
||||
|
||||
.. note::
|
||||
|
||||
|
|
|
@ -135,13 +135,18 @@ where it is necessary to invoke the same function from a custom :ref:`outputter
|
|||
<all-salt.output>`/returner, as well as an execution module.
|
||||
|
||||
Utility modules placed in ``salt://_utils/`` will be synced to the minions when
|
||||
any of the following Salt functions are called:
|
||||
a :ref:`highstate <running-highstate>` is run, as well as when any of the
|
||||
following Salt functions are called:
|
||||
|
||||
* :mod:`state.apply <salt.modules.state.apply_>`
|
||||
* :mod:`saltutil.sync_utils <salt.modules.saltutil.sync_utils>`
|
||||
* :mod:`saltutil.sync_all <salt.modules.saltutil.sync_all>`
|
||||
* :py:func:`saltutil.sync_utils <salt.modules.saltutil.sync_utils>`
|
||||
* :py:func:`saltutil.sync_all <salt.modules.saltutil.sync_all>`
|
||||
|
||||
As of the Fluorine release, as well as 2017.7.7 and 2018.3.2 in their
|
||||
respective release cycles, the ``sync`` argument to :py:func:`state.apply
|
||||
<salt.modules.state.apply_>`/:py:func:`state.sls <salt.modules.state.sls>` can
|
||||
be used to sync custom types when running individual SLS files.
|
||||
|
||||
To sync to the Master, use either of the following:
|
||||
|
||||
* :mod:`saltutil.sync_utils <salt.runners.saltutil.sync_utils>`
|
||||
* :mod:`saltutil.sync_all <salt.runners.saltutil.sync_all>`
|
||||
* :py:func:`saltutil.sync_utils <salt.runners.saltutil.sync_utils>`
|
||||
* :py:func:`saltutil.sync_all <salt.runners.saltutil.sync_all>`
|
||||
|
|
|
@ -197,17 +197,17 @@ Write-Output " ----------------------------------------------------------------"
|
|||
Write-Output " - $script_name :: Updating PIP and SetupTools . . ."
|
||||
Write-Output " ----------------------------------------------------------------"
|
||||
if ( ! [bool]$Env:SALT_PIP_LOCAL_CACHE) {
|
||||
Start_Process_and_test_exitcode "cmd" "/c $($ini['Settings']['Python2Dir'])\python.exe -m pip --no-cache-dir install -r $($script_path)\req_pip.txt" "python pip"
|
||||
Start_Process_and_test_exitcode "cmd" "/c $($ini['Settings']['Python2Dir'])\python.exe -m pip --disable-pip-version-check --no-cache-dir install -r $($script_path)\req_pip.txt" "python pip"
|
||||
} else {
|
||||
$p = New-Item $Env:SALT_PIP_LOCAL_CACHE -ItemType Directory -Force # Ensure directory exists
|
||||
if ( (Get-ChildItem $Env:SALT_PIP_LOCAL_CACHE | Measure-Object).Count -eq 0 ) {
|
||||
# folder empty
|
||||
Write-Output " pip download from req_pip.txt into empty local cache SALT_REQ_PIP $Env:SALT_PIP_LOCAL_CACHE"
|
||||
Start_Process_and_test_exitcode "cmd" "/c $($ini['Settings']['Python2Dir'])\python.exe -m pip download --dest $Env:SALT_PIP_LOCAL_CACHE -r $($script_path)\req_pip.txt" "pip download"
|
||||
Start_Process_and_test_exitcode "cmd" "/c $($ini['Settings']['Python2Dir'])\python.exe -m pip --disable-pip-version-check download --dest $Env:SALT_PIP_LOCAL_CACHE -r $($script_path)\req_pip.txt" "pip download"
|
||||
}
|
||||
Write-Output " reading from local pip cache $Env:SALT_PIP_LOCAL_CACHE"
|
||||
Write-Output " If a (new) resource is missing, please delete all files in this cache, go online and repeat"
|
||||
Start_Process_and_test_exitcode "cmd" "/c $($ini['Settings']['Python2Dir'])\python.exe -m pip install --no-index --find-links=$Env:SALT_PIP_LOCAL_CACHE -r $($script_path)\req_pip.txt" "pip install"
|
||||
Start_Process_and_test_exitcode "cmd" "/c $($ini['Settings']['Python2Dir'])\python.exe -m pip --disable-pip-version-check install --no-index --find-links=$Env:SALT_PIP_LOCAL_CACHE -r $($script_path)\req_pip.txt" "pip install"
|
||||
}
|
||||
|
||||
#==============================================================================
|
||||
|
@ -218,16 +218,16 @@ Write-Output " ----------------------------------------------------------------"
|
|||
Write-Output " - $script_name :: Installing pypi resources using pip . . ."
|
||||
Write-Output " ----------------------------------------------------------------"
|
||||
if ( ! [bool]$Env:SALT_REQ_LOCAL_CACHE) {
|
||||
Start_Process_and_test_exitcode "cmd" "/c $($ini['Settings']['Python2Dir'])\python.exe -m pip --no-cache-dir install -r $($script_path)\req.txt" "pip install"
|
||||
Start_Process_and_test_exitcode "cmd" "/c $($ini['Settings']['Python2Dir'])\python.exe -m pip --disable-pip-version-check --no-cache-dir install -r $($script_path)\req.txt" "pip install"
|
||||
} else {
|
||||
if ( (Get-ChildItem $Env:SALT_REQ_LOCAL_CACHE | Measure-Object).Count -eq 0 ) {
|
||||
# folder empty
|
||||
Write-Output " pip download from req.txt into empty local cache SALT_REQ $Env:SALT_REQ_LOCAL_CACHE"
|
||||
Start_Process_and_test_exitcode "cmd" "/c $($ini['Settings']['Python2Dir'])\python.exe -m pip download --dest $Env:SALT_REQ_LOCAL_CACHE -r $($script_path)\req.txt" "pip download"
|
||||
Start_Process_and_test_exitcode "cmd" "/c $($ini['Settings']['Python2Dir'])\python.exe -m pip --disable-pip-version-check download --dest $Env:SALT_REQ_LOCAL_CACHE -r $($script_path)\req.txt" "pip download"
|
||||
}
|
||||
Write-Output " reading from local pip cache $Env:SALT_REQ_LOCAL_CACHE"
|
||||
Write-Output " If a (new) resource is missing, please delete all files in this cache, go online and repeat"
|
||||
Start_Process_and_test_exitcode "cmd" "/c $($ini['Settings']['Python2Dir'])\python.exe -m pip install --no-index --find-links=$Env:SALT_REQ_LOCAL_CACHE -r $($script_path)\req.txt" "pip install"
|
||||
Start_Process_and_test_exitcode "cmd" "/c $($ini['Settings']['Python2Dir'])\python.exe -m pip --disable-pip-version-check install --no-index --find-links=$Env:SALT_REQ_LOCAL_CACHE -r $($script_path)\req.txt" "pip install"
|
||||
}
|
||||
|
||||
#==============================================================================
|
||||
|
|
|
@ -197,17 +197,17 @@ Write-Output " ----------------------------------------------------------------"
|
|||
Write-Output " - $script_name :: Updating PIP and SetupTools . . ."
|
||||
Write-Output " ----------------------------------------------------------------"
|
||||
if ( ! [bool]$Env:SALT_PIP_LOCAL_CACHE) {
|
||||
Start_Process_and_test_exitcode "cmd" "/c $($ini['Settings']['Python3Dir'])\python.exe -m pip --no-cache-dir install -r $($script_path)\req_pip.txt" "python pip"
|
||||
Start_Process_and_test_exitcode "cmd" "/c $($ini['Settings']['Python3Dir'])\python.exe -m pip --disable-pip-version-check --no-cache-dir install -r $($script_path)\req_pip.txt" "python pip"
|
||||
} else {
|
||||
$p = New-Item $Env:SALT_PIP_LOCAL_CACHE -ItemType Directory -Force # Ensure directory exists
|
||||
if ( (Get-ChildItem $Env:SALT_PIP_LOCAL_CACHE | Measure-Object).Count -eq 0 ) {
|
||||
# folder empty
|
||||
Write-Output " pip download from req_pip.txt into empty local cache SALT_REQ_PIP $Env:SALT_PIP_LOCAL_CACHE"
|
||||
Start_Process_and_test_exitcode "cmd" "/c $($ini['Settings']['Python3Dir'])\python.exe -m pip download --dest $Env:SALT_PIP_LOCAL_CACHE -r $($script_path)\req_pip.txt" "pip download"
|
||||
Start_Process_and_test_exitcode "cmd" "/c $($ini['Settings']['Python3Dir'])\python.exe -m pip --disable-pip-version-check download --dest $Env:SALT_PIP_LOCAL_CACHE -r $($script_path)\req_pip.txt" "pip download"
|
||||
}
|
||||
Write-Output " reading from local pip cache $Env:SALT_PIP_LOCAL_CACHE"
|
||||
Write-Output " If a (new) resource is missing, please delete all files in this cache, go online and repeat"
|
||||
Start_Process_and_test_exitcode "cmd" "/c $($ini['Settings']['Python3Dir'])\python.exe -m pip install --no-index --find-links=$Env:SALT_PIP_LOCAL_CACHE -r $($script_path)\req_pip.txt" "pip install"
|
||||
Start_Process_and_test_exitcode "cmd" "/c $($ini['Settings']['Python3Dir'])\python.exe -m pip --disable-pip-version-check install --no-index --find-links=$Env:SALT_PIP_LOCAL_CACHE -r $($script_path)\req_pip.txt" "pip install"
|
||||
}
|
||||
|
||||
#==============================================================================
|
||||
|
@ -218,16 +218,16 @@ Write-Output " ----------------------------------------------------------------"
|
|||
Write-Output " - $script_name :: Installing pypi resources using pip . . ."
|
||||
Write-Output " ----------------------------------------------------------------"
|
||||
if ( ! [bool]$Env:SALT_REQ_LOCAL_CACHE) {
|
||||
Start_Process_and_test_exitcode "cmd" "/c $($ini['Settings']['Python3Dir'])\python.exe -m pip --no-cache-dir install -r $($script_path)\req.txt" "pip install"
|
||||
Start_Process_and_test_exitcode "cmd" "/c $($ini['Settings']['Python3Dir'])\python.exe -m pip --disable-pip-version-check --no-cache-dir install -r $($script_path)\req.txt" "pip install"
|
||||
} else {
|
||||
if ( (Get-ChildItem $Env:SALT_REQ_LOCAL_CACHE | Measure-Object).Count -eq 0 ) {
|
||||
# folder empty
|
||||
Write-Output " pip download from req.txt into empty local cache SALT_REQ $Env:SALT_REQ_LOCAL_CACHE"
|
||||
Start_Process_and_test_exitcode "cmd" "/c $($ini['Settings']['Python3Dir'])\python.exe -m pip download --dest $Env:SALT_REQ_LOCAL_CACHE -r $($script_path)\req.txt" "pip download"
|
||||
Start_Process_and_test_exitcode "cmd" "/c $($ini['Settings']['Python3Dir'])\python.exe -m pip --disable-pip-version-check download --dest $Env:SALT_REQ_LOCAL_CACHE -r $($script_path)\req.txt" "pip download"
|
||||
}
|
||||
Write-Output " reading from local pip cache $Env:SALT_REQ_LOCAL_CACHE"
|
||||
Write-Output " If a (new) resource is missing, please delete all files in this cache, go online and repeat"
|
||||
Start_Process_and_test_exitcode "cmd" "/c $($ini['Settings']['Python3Dir'])\python.exe -m pip install --no-index --find-links=$Env:SALT_REQ_LOCAL_CACHE -r $($script_path)\req.txt" "pip install"
|
||||
Start_Process_and_test_exitcode "cmd" "/c $($ini['Settings']['Python3Dir'])\python.exe -m pip --disable-pip-version-check install --no-index --find-links=$Env:SALT_REQ_LOCAL_CACHE -r $($script_path)\req.txt" "pip install"
|
||||
}
|
||||
|
||||
#==============================================================================
|
||||
|
|
|
@ -77,6 +77,7 @@ Function Get-Settings {
|
|||
"SSLeay" = "ssleay32.dll"
|
||||
"OpenSSLLic" = "OpenSSL_License.txt"
|
||||
"msvcr" = "msvcr120.dll"
|
||||
"Libsodium" = "libsodium.dll"
|
||||
}
|
||||
$ini.Add("64bitDLLs", $64bitDLLs)
|
||||
|
||||
|
@ -86,6 +87,7 @@ Function Get-Settings {
|
|||
"SSLeay" = "ssleay32.dll"
|
||||
"OpenSSLLic" = "OpenSSL_License.txt"
|
||||
"msvcr" = "msvcr120.dll"
|
||||
"Libsodium" = "libsodium.dll"
|
||||
}
|
||||
$ini.Add("32bitDLLs", $32bitDLLs)
|
||||
|
||||
|
|
|
@ -9,34 +9,36 @@ salt for Windows with their corresponding licenses:
|
|||
| certifi | ISC |
|
||||
| cffi | MIT |
|
||||
| CherryPy | BSD |
|
||||
| cryptography | BSD |
|
||||
| enum34 | BSD |
|
||||
| futures | BSD |
|
||||
| gitdb | BSD |
|
||||
| GitPython | BSD |
|
||||
| idna | BSD-like |
|
||||
| ioflo | Apache 2.0 |
|
||||
| ioloop | MIT |
|
||||
| ipaddress | PSF |
|
||||
| Jinja2 | BSD |
|
||||
| libnacl | --- |
|
||||
| libnacl | Apache |
|
||||
| lxml | BSD |
|
||||
| Mako | MIT |
|
||||
| MarkupSafe | BSD |
|
||||
| msgpack-python | --- |
|
||||
| msgpack-python | Apache 2.0 |
|
||||
| pip | MIT |
|
||||
| psutil | BSD |
|
||||
| pyasn1 | BSD |
|
||||
| pycparser | BSD |
|
||||
| pycurl | LGPL + MIT |
|
||||
| PyMySQL | MIT |
|
||||
| pypiwin32 | PSF |
|
||||
| PyOpenSSL | Apache 2.0 |
|
||||
| python-certifi-win32 | BSD |
|
||||
| python-dateutil | Simplified BSD |
|
||||
| python-gnupg | BSD |
|
||||
| pywin32 | PSF |
|
||||
| PyYAML | MIT |
|
||||
| pyzmq | LGPL + BSD |
|
||||
| requests | Apache 2.0 |
|
||||
| setuptools | MIT |
|
||||
| singledispatch | MIT |
|
||||
| six | MIT |
|
||||
| smmap | BSD |
|
||||
| timelib | ZLIB/PHP |
|
||||
| tornado | Apache 2.0 |
|
||||
|
|
|
@ -12,6 +12,7 @@ idna==2.5
|
|||
ioloop==0.1a0
|
||||
ipaddress==1.0.18
|
||||
Jinja2==2.9.6
|
||||
libnacl==1.6.1 # required by the nacl module
|
||||
lxml==3.7.3
|
||||
Mako==1.0.6
|
||||
MarkupSafe==1.0
|
||||
|
@ -23,6 +24,7 @@ pycrypto==2.6.1
|
|||
pycurl==7.43.0
|
||||
PyMySQL==0.7.11
|
||||
pyOpenSSL==17.0.0
|
||||
#python-certifi-win32==1.2
|
||||
python-dateutil==2.6.0
|
||||
python-gnupg==0.4.0
|
||||
pywin32==223
|
||||
|
|
|
@ -10,3 +10,4 @@ git+https://github.com/saltstack/pytest-salt.git@master#egg=pytest-salt
|
|||
# satisfy other requirements, and httpretty 0.8.10 has bugs in setup.py that
|
||||
# prevent it from being successfully installed (at least on Python 3.4).
|
||||
httpretty; python_version >= '3.4'
|
||||
pylint==1.6.5
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
-r base.txt
|
||||
|
||||
pycrypto>=2.6.1
|
||||
pyzmq>=2.2.0
|
||||
pyzmq>=2.2.0,<17.1.0; python_version == '3.4' # pyzmq 17.1.0 stopped building wheels for python3.4
|
||||
pyzmq>=2.2.0; python_version != '3.4'
|
||||
|
|
|
@ -221,7 +221,7 @@ class LocalClient(object):
|
|||
# Looks like the timeout is invalid, use config
|
||||
return self.opts['timeout']
|
||||
|
||||
def gather_job_info(self, jid, tgt, tgt_type, **kwargs):
|
||||
def gather_job_info(self, jid, tgt, tgt_type, listen=True, **kwargs):
|
||||
'''
|
||||
Return the information about a given job
|
||||
'''
|
||||
|
@ -233,6 +233,7 @@ class LocalClient(object):
|
|||
arg=[jid],
|
||||
tgt_type=tgt_type,
|
||||
timeout=timeout,
|
||||
listen=listen,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
|
|
|
@ -1106,7 +1106,10 @@ ARGS = {10}\n'''.format(self.minion_config,
|
|||
shim_tmp_file.write(salt.utils.to_bytes(cmd_str))
|
||||
|
||||
# Copy shim to target system, under $HOME/.<randomized name>
|
||||
target_shim_file = '.{0}.{1}'.format(binascii.hexlify(os.urandom(6)), extension)
|
||||
target_shim_file = '.{0}.{1}'.format(
|
||||
binascii.hexlify(os.urandom(6)).decode('ascii'),
|
||||
extension
|
||||
)
|
||||
if self.winrm:
|
||||
target_shim_file = saltwinshell.get_target_shim_file(self, target_shim_file)
|
||||
self.shell.send(shim_tmp_file.name, target_shim_file, makedirs=True)
|
||||
|
|
|
@ -32,6 +32,60 @@ __func_alias__ = {
|
|||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _ssh_state(chunks, __opts__, __context__, __pillar__, __salt__, st_kwargs,
|
||||
kwargs, test=False):
|
||||
'''
|
||||
funciton to run a state with the given chunk via salt-ssh
|
||||
'''
|
||||
file_refs = salt.client.ssh.state.lowstate_file_refs(
|
||||
chunks,
|
||||
_merge_extra_filerefs(
|
||||
kwargs.get('extra_filerefs', ''),
|
||||
__opts__.get('extra_filerefs', '')
|
||||
)
|
||||
)
|
||||
# Create the tar containing the state pkg and relevant files.
|
||||
trans_tar = salt.client.ssh.state.prep_trans_tar(
|
||||
__opts__,
|
||||
__context__['fileclient'],
|
||||
chunks,
|
||||
file_refs,
|
||||
__pillar__,
|
||||
st_kwargs['id_'])
|
||||
trans_tar_sum = salt.utils.get_hash(trans_tar, __opts__['hash_type'])
|
||||
cmd = 'state.pkg {0}/salt_state.tgz test={1} pkg_sum={2} hash_type={3}'.format(
|
||||
__opts__['thin_dir'],
|
||||
test,
|
||||
trans_tar_sum,
|
||||
__opts__['hash_type'])
|
||||
single = salt.client.ssh.Single(
|
||||
__opts__,
|
||||
cmd,
|
||||
fsclient=__context__['fileclient'],
|
||||
minion_opts=__salt__.minion_opts,
|
||||
**st_kwargs)
|
||||
single.shell.send(
|
||||
trans_tar,
|
||||
'{0}/salt_state.tgz'.format(__opts__['thin_dir']))
|
||||
stdout, stderr, _ = single.cmd_block()
|
||||
|
||||
# Clean up our tar
|
||||
try:
|
||||
os.remove(trans_tar)
|
||||
except (OSError, IOError):
|
||||
pass
|
||||
|
||||
# Read in the JSON data and return the data structure
|
||||
try:
|
||||
return json.loads(stdout, object_hook=salt.utils.decode_dict)
|
||||
except Exception as e:
|
||||
log.error("JSON Render failed for: %s\n%s", stdout, stderr)
|
||||
log.error(str(e))
|
||||
|
||||
# If for some reason the json load fails, return the stdout
|
||||
return stdout
|
||||
|
||||
|
||||
def _set_retcode(ret, highstate=None):
|
||||
'''
|
||||
Set the return code based on the data back from the state system
|
||||
|
@ -835,6 +889,7 @@ def sls_id(id_, mods, test=None, queue=False, **kwargs):
|
|||
|
||||
salt '*' state.sls_id my_state my_module,a_common_module
|
||||
'''
|
||||
st_kwargs = __salt__.kwargs
|
||||
conflict = _check_queue(queue, kwargs)
|
||||
if conflict is not None:
|
||||
return conflict
|
||||
|
@ -847,13 +902,11 @@ def sls_id(id_, mods, test=None, queue=False, **kwargs):
|
|||
if opts['environment'] is None:
|
||||
opts['environment'] = 'base'
|
||||
|
||||
try:
|
||||
st_ = salt.state.HighState(opts,
|
||||
proxy=__proxy__,
|
||||
initial_pillar=_get_initial_pillar(opts))
|
||||
except NameError:
|
||||
st_ = salt.state.HighState(opts,
|
||||
initial_pillar=_get_initial_pillar(opts))
|
||||
st_ = salt.client.ssh.state.SSHHighState(
|
||||
__opts__,
|
||||
__pillar__,
|
||||
__salt__,
|
||||
__context__['fileclient'])
|
||||
|
||||
if not _check_pillar(kwargs, st_.opts['pillar']):
|
||||
__context__['retcode'] = 5
|
||||
|
@ -864,10 +917,7 @@ def sls_id(id_, mods, test=None, queue=False, **kwargs):
|
|||
if isinstance(mods, six.string_types):
|
||||
split_mods = mods.split(',')
|
||||
st_.push_active()
|
||||
try:
|
||||
high_, errors = st_.render_highstate({opts['environment']: split_mods})
|
||||
finally:
|
||||
st_.pop_active()
|
||||
high_, errors = st_.render_highstate({opts['environment']: split_mods})
|
||||
errors += st_.state.verify_high(high_)
|
||||
# Apply requisites to high data
|
||||
high_, req_in_errors = st_.state.requisite_in(high_)
|
||||
|
@ -879,20 +929,26 @@ def sls_id(id_, mods, test=None, queue=False, **kwargs):
|
|||
__context__['retcode'] = 1
|
||||
return errors
|
||||
chunks = st_.state.compile_high_data(high_)
|
||||
ret = {}
|
||||
for chunk in chunks:
|
||||
if chunk.get('__id__', '') == id_:
|
||||
ret.update(st_.state.call_chunk(chunk, {}, chunks))
|
||||
chunk = [x for x in chunks if x.get('__id__', '') == id_]
|
||||
|
||||
_set_retcode(ret, highstate=highstate)
|
||||
# Work around Windows multiprocessing bug, set __opts__['test'] back to
|
||||
# value from before this function was run.
|
||||
__opts__['test'] = orig_test
|
||||
if not ret:
|
||||
if not chunk:
|
||||
raise SaltInvocationError(
|
||||
'No matches for ID \'{0}\' found in SLS \'{1}\' within saltenv '
|
||||
'\'{2}\''.format(id_, mods, opts['environment'])
|
||||
)
|
||||
|
||||
ret = _ssh_state(chunk,
|
||||
__opts__,
|
||||
__context__,
|
||||
__pillar__,
|
||||
__salt__,
|
||||
st_kwargs,
|
||||
kwargs,
|
||||
test=test)
|
||||
_set_retcode(ret, highstate=highstate)
|
||||
# Work around Windows multiprocessing bug, set __opts__['test'] back to
|
||||
# value from before this function was run.
|
||||
__opts__['test'] = orig_test
|
||||
return ret
|
||||
|
||||
|
||||
|
|
|
@ -520,9 +520,17 @@ class AsyncAuth(object):
|
|||
error = SaltClientError('Detect mode is on')
|
||||
break
|
||||
if self.opts.get('caller'):
|
||||
print('Minion failed to authenticate with the master, '
|
||||
'has the minion key been accepted?')
|
||||
sys.exit(2)
|
||||
# We have a list of masters, so we should break
|
||||
# and try the next one in the list.
|
||||
if self.opts.get('local_masters', None):
|
||||
error = SaltClientError('Minion failed to authenticate'
|
||||
' with the master, has the '
|
||||
'minion key been accepted?')
|
||||
break
|
||||
else:
|
||||
print('Minion failed to authenticate with the master, '
|
||||
'has the minion key been accepted?')
|
||||
sys.exit(2)
|
||||
if acceptance_wait_time:
|
||||
log.info('Waiting {0} seconds before retry.'.format(acceptance_wait_time))
|
||||
yield tornado.gen.sleep(acceptance_wait_time)
|
||||
|
|
|
@ -64,10 +64,10 @@ if USE_IMPORTLIB:
|
|||
SUFFIXES = []
|
||||
for suffix in importlib.machinery.EXTENSION_SUFFIXES:
|
||||
SUFFIXES.append((suffix, 'rb', MODULE_KIND_EXTENSION))
|
||||
for suffix in importlib.machinery.BYTECODE_SUFFIXES:
|
||||
SUFFIXES.append((suffix, 'rb', MODULE_KIND_COMPILED))
|
||||
for suffix in importlib.machinery.SOURCE_SUFFIXES:
|
||||
SUFFIXES.append((suffix, 'rb', MODULE_KIND_SOURCE))
|
||||
for suffix in importlib.machinery.BYTECODE_SUFFIXES:
|
||||
SUFFIXES.append((suffix, 'rb', MODULE_KIND_COMPILED))
|
||||
MODULE_KIND_MAP = {
|
||||
MODULE_KIND_SOURCE: importlib.machinery.SourceFileLoader,
|
||||
MODULE_KIND_COMPILED: importlib.machinery.SourcelessFileLoader,
|
||||
|
|
|
@ -1032,10 +1032,11 @@ class Minion(MinionBase):
|
|||
# I made the following 3 line oddity to preserve traceback.
|
||||
# Please read PR #23978 before changing, hopefully avoiding regressions.
|
||||
# Good luck, we're all counting on you. Thanks.
|
||||
future_exception = self._connect_master_future.exception()
|
||||
if future_exception:
|
||||
# This needs to be re-raised to preserve restart_on_error behavior.
|
||||
raise six.reraise(*future_exception)
|
||||
if self._connect_master_future.done():
|
||||
future_exception = self._connect_master_future.exception()
|
||||
if future_exception:
|
||||
# This needs to be re-raised to preserve restart_on_error behavior.
|
||||
raise six.reraise(*future_exception)
|
||||
if timeout and self._sync_connect_master_success is False:
|
||||
raise SaltDaemonNotRunning('Failed to connect to the salt-master')
|
||||
|
||||
|
@ -1527,7 +1528,9 @@ class Minion(MinionBase):
|
|||
)
|
||||
ret['out'] = 'nested'
|
||||
except TypeError as exc:
|
||||
msg = 'Passed invalid arguments to {0}: {1}\n{2}'.format(function_name, exc, func.__doc__, )
|
||||
msg = 'Passed invalid arguments to {0}: {1}\n{2}'.format(
|
||||
function_name, exc, func.__doc__ or ''
|
||||
)
|
||||
log.warning(msg, exc_info_on_loglevel=logging.DEBUG)
|
||||
ret['return'] = msg
|
||||
ret['out'] = 'nested'
|
||||
|
|
|
@ -304,7 +304,7 @@ def install(name=None,
|
|||
# We don't support installing specific version for now
|
||||
# so transform the dict in list ignoring version provided
|
||||
pkgs = [
|
||||
p.keys()[0] for p in pkgs
|
||||
next(iter(p)) for p in pkgs
|
||||
if isinstance(p, dict)
|
||||
]
|
||||
pkg_to_install.extend(pkgs)
|
||||
|
|
|
@ -282,12 +282,14 @@ def raw_cron(user):
|
|||
# Preserve line endings
|
||||
lines = sdecode(__salt__['cmd.run_stdout'](cmd,
|
||||
runas=user,
|
||||
ignore_retcode=True,
|
||||
rstrip=False,
|
||||
python_shell=False)).splitlines(True)
|
||||
else:
|
||||
cmd = 'crontab -u {0} -l'.format(user)
|
||||
# Preserve line endings
|
||||
lines = sdecode(__salt__['cmd.run_stdout'](cmd,
|
||||
ignore_retcode=True,
|
||||
rstrip=False,
|
||||
python_shell=False)).splitlines(True)
|
||||
|
||||
|
|
|
@ -436,11 +436,20 @@ def _refresh_mine_cache(wrapped):
|
|||
refresh salt mine on exit.
|
||||
'''
|
||||
returned = wrapped(*args, **salt.utils.clean_kwargs(**kwargs))
|
||||
__salt__['mine.send']('docker.ps', verbose=True, all=True, host=True)
|
||||
if _check_update_mine():
|
||||
__salt__['mine.send']('docker.ps', verbose=True, all=True, host=True)
|
||||
return returned
|
||||
return wrapper
|
||||
|
||||
|
||||
def _check_update_mine():
|
||||
try:
|
||||
ret = __context__['docker.update_mine']
|
||||
except KeyError:
|
||||
ret = __context__['docker.update_mine'] = __salt__['config.get']('docker.update_mine', default=True)
|
||||
return ret
|
||||
|
||||
|
||||
# Helper functions
|
||||
def _change_state(name, action, expected, *args, **kwargs):
|
||||
'''
|
||||
|
|
|
@ -84,6 +84,9 @@ def fire_master(data, tag, preload=None):
|
|||
channel = salt.transport.Channel.factory(__opts__, master_uri=master)
|
||||
try:
|
||||
channel.send(load)
|
||||
# channel.send was successful.
|
||||
# Ensure ret is True.
|
||||
ret = True
|
||||
except Exception:
|
||||
ret = False
|
||||
return ret
|
||||
|
|
|
@ -4262,26 +4262,6 @@ def check_perms(name, ret, user, group, mode, follow_symlinks=False):
|
|||
perms['lgroup'] = cur['group']
|
||||
perms['lmode'] = salt.utils.normalize_mode(cur['mode'])
|
||||
|
||||
# Mode changes if needed
|
||||
if mode is not None:
|
||||
# File is a symlink, ignore the mode setting
|
||||
# if follow_symlinks is False
|
||||
if os.path.islink(name) and not follow_symlinks:
|
||||
pass
|
||||
else:
|
||||
mode = salt.utils.normalize_mode(mode)
|
||||
if mode != perms['lmode']:
|
||||
if __opts__['test'] is True:
|
||||
ret['changes']['mode'] = mode
|
||||
else:
|
||||
set_mode(name, mode)
|
||||
if mode != salt.utils.normalize_mode(get_mode(name)):
|
||||
ret['result'] = False
|
||||
ret['comment'].append(
|
||||
'Failed to change mode to {0}'.format(mode)
|
||||
)
|
||||
else:
|
||||
ret['changes']['mode'] = mode
|
||||
# user/group changes if needed, then check if it worked
|
||||
if user:
|
||||
if isinstance(user, int):
|
||||
|
@ -4358,6 +4338,27 @@ def check_perms(name, ret, user, group, mode, follow_symlinks=False):
|
|||
elif 'cgroup' in perms and user != '':
|
||||
ret['changes']['group'] = group
|
||||
|
||||
# Mode changes if needed
|
||||
if mode is not None:
|
||||
# File is a symlink, ignore the mode setting
|
||||
# if follow_symlinks is False
|
||||
if os.path.islink(name) and not follow_symlinks:
|
||||
pass
|
||||
else:
|
||||
mode = salt.utils.normalize_mode(mode)
|
||||
if mode != perms['lmode']:
|
||||
if __opts__['test'] is True:
|
||||
ret['changes']['mode'] = mode
|
||||
else:
|
||||
set_mode(name, mode)
|
||||
if mode != salt.utils.normalize_mode(get_mode(name)):
|
||||
ret['result'] = False
|
||||
ret['comment'].append(
|
||||
'Failed to change mode to {0}'.format(mode)
|
||||
)
|
||||
else:
|
||||
ret['changes']['mode'] = mode
|
||||
|
||||
if isinstance(orig_comment, six.string_types):
|
||||
if orig_comment:
|
||||
ret['comment'].insert(0, orig_comment)
|
||||
|
@ -4484,6 +4485,11 @@ def check_managed_changes(
|
|||
defaults,
|
||||
skip_verify,
|
||||
**kwargs)
|
||||
|
||||
# Ensure that user-provided hash string is lowercase
|
||||
if source_sum and ('hsum' in source_sum):
|
||||
source_sum['hsum'] = source_sum['hsum'].lower()
|
||||
|
||||
if comments:
|
||||
__clean_tmp(sfn)
|
||||
return False, comments
|
||||
|
@ -4725,7 +4731,7 @@ def manage_file(name,
|
|||
source
|
||||
file reference on the master
|
||||
|
||||
source_hash
|
||||
source_sum
|
||||
sum hash for source
|
||||
|
||||
user
|
||||
|
|
|
@ -26,15 +26,16 @@ def __virtual__():
|
|||
return (False, 'glusterfs server is not installed')
|
||||
|
||||
|
||||
def _get_minor_version():
|
||||
# Set default version to 6 for tests
|
||||
version = 6
|
||||
def _get_version():
|
||||
# Set the default minor version to 6 for tests
|
||||
version = [3, 6]
|
||||
cmd = 'gluster --version'
|
||||
result = __salt__['cmd.run'](cmd).splitlines()
|
||||
for line in result:
|
||||
if line.startswith('glusterfs'):
|
||||
version = int(line.split()[1].split('.')[1])
|
||||
return version
|
||||
version = line.split()[-1].split('.')
|
||||
version = [int(i) for i in version]
|
||||
return tuple(version)
|
||||
|
||||
|
||||
def _gluster_ok(xml_data):
|
||||
|
@ -67,7 +68,7 @@ def _gluster_xml(cmd):
|
|||
# We will pass the command string as stdin to allow for much longer
|
||||
# command strings. This is especially useful for creating large volumes
|
||||
# where the list of bricks exceeds 128 characters.
|
||||
if _get_minor_version() < 6:
|
||||
if _get_version() < (3, 6,):
|
||||
result = __salt__['cmd.run'](
|
||||
'script -q -c "gluster --xml --mode=script"', stdin="{0}\n\004".format(cmd)
|
||||
)
|
||||
|
|
|
@ -870,7 +870,7 @@ def _network_conf(conf_tuples=None, **kwargs):
|
|||
# on old versions of lxc, still support the gateway auto mode
|
||||
# if we didn't explicitly say no to
|
||||
# (lxc.network.ipv4.gateway: auto)
|
||||
if _LooseVersion(version()) <= '1.0.7' and \
|
||||
if _LooseVersion(version()) <= _LooseVersion('1.0.7') and \
|
||||
True not in ['lxc.network.ipv4.gateway' in a for a in ret] and \
|
||||
True in ['lxc.network.ipv4' in a for a in ret]:
|
||||
ret.append({'lxc.network.ipv4.gateway': 'auto'})
|
||||
|
@ -2079,7 +2079,7 @@ def clone(name,
|
|||
if backing in ('dir', 'overlayfs', 'btrfs'):
|
||||
size = None
|
||||
# LXC commands and options changed in 2.0 - CF issue #34086 for details
|
||||
if version() >= _LooseVersion('2.0'):
|
||||
if _LooseVersion(version()) >= _LooseVersion('2.0'):
|
||||
# https://linuxcontainers.org/lxc/manpages//man1/lxc-copy.1.html
|
||||
cmd = 'lxc-copy'
|
||||
cmd += ' {0} -n {1} -N {2}'.format(snapshot, orig, name)
|
||||
|
@ -2270,22 +2270,22 @@ def _change_state(cmd,
|
|||
# as te command itself mess with double forks; we must not
|
||||
# communicate with it, but just wait for the exit status
|
||||
pkwargs = {'python_shell': False,
|
||||
'redirect_stderr': True,
|
||||
'with_communicate': with_communicate,
|
||||
'use_vt': use_vt,
|
||||
'stdin': stdin,
|
||||
'stdout': stdout,
|
||||
'stderr': stderr}
|
||||
'stdout': stdout}
|
||||
for i in [a for a in pkwargs]:
|
||||
val = pkwargs[i]
|
||||
if val is _marker:
|
||||
pkwargs.pop(i, None)
|
||||
|
||||
error = __salt__['cmd.run_stderr'](cmd, **pkwargs)
|
||||
_cmdout = __salt__['cmd.run_all'](cmd, **pkwargs)
|
||||
|
||||
if error:
|
||||
if _cmdout['retcode'] != 0:
|
||||
raise CommandExecutionError(
|
||||
'Error changing state for container \'{0}\' using command '
|
||||
'\'{1}\': {2}'.format(name, cmd, error)
|
||||
'\'{1}\': {2}'.format(name, cmd, _cmdout['stdout'])
|
||||
)
|
||||
if expected is not None:
|
||||
# some commands do not wait, so we will
|
||||
|
@ -3507,7 +3507,9 @@ def bootstrap(name,
|
|||
configdir = '/var/tmp/.c_{0}'.format(rstr)
|
||||
|
||||
cmd = 'install -m 0700 -d {0}'.format(configdir)
|
||||
if run(name, cmd, python_shell=False):
|
||||
if run_all(
|
||||
name, cmd, path=path, python_shell=False
|
||||
)['retcode'] != 0:
|
||||
log.error('tmpdir {0} creation failed ({1}'
|
||||
.format(configdir, cmd))
|
||||
return False
|
||||
|
@ -3518,6 +3520,7 @@ def bootstrap(name,
|
|||
copy_to(name, bs_, script, path=path)
|
||||
result = run_all(name,
|
||||
'sh -c "chmod +x {0}"'.format(script),
|
||||
path=path,
|
||||
python_shell=True)
|
||||
|
||||
copy_to(name, cfg_files['config'],
|
||||
|
@ -3544,6 +3547,7 @@ def bootstrap(name,
|
|||
run_all(name,
|
||||
'sh -c \'if [ -f "{0}" ];then rm -f "{0}";fi\''
|
||||
''.format(script),
|
||||
path=path,
|
||||
ignore_retcode=True,
|
||||
python_shell=True)
|
||||
else:
|
||||
|
|
|
@ -374,10 +374,18 @@ def flush():
|
|||
|
||||
def get_docker(interfaces=None, cidrs=None, with_container_id=False):
|
||||
'''
|
||||
Get all mine data for 'docker.get_containers' and run an aggregation
|
||||
routine. The "interfaces" parameter allows for specifying which network
|
||||
interfaces to select ip addresses from. The "cidrs" parameter allows for
|
||||
specifying a list of cidrs which the ip address must match.
|
||||
.. versionchanged:: 2017.7.8,2018.3.3
|
||||
When :conf_minion:`docker.update_mine` is set to ``False`` for a given
|
||||
minion, no mine data will be populated for that minion, and thus none
|
||||
will be returned for it.
|
||||
.. versionchanged:: Fluorine
|
||||
:conf_minion:`docker.update_mine` now defaults to ``False``
|
||||
|
||||
Get all mine data for :py:func:`docker.ps <salt.modules.dockermod.ps_>` and
|
||||
run an aggregation routine. The ``interfaces`` parameter allows for
|
||||
specifying the network interfaces from which to select IP addresses. The
|
||||
``cidrs`` parameter allows for specifying a list of subnets which the IP
|
||||
address must match.
|
||||
|
||||
with_container_id
|
||||
Boolean, to expose container_id in the list of results
|
||||
|
|
|
@ -168,20 +168,7 @@ def _get_pip_bin(bin_env):
|
|||
# If the python binary was passed, return it
|
||||
if 'python' in os.path.basename(bin_env):
|
||||
return [os.path.normpath(bin_env), '-m', 'pip']
|
||||
# Try to find the python binary based on the location of pip in a
|
||||
# virtual environment, should be relative
|
||||
if 'pip' in os.path.basename(bin_env):
|
||||
# Look in the same directory as the pip binary, and also its
|
||||
# parent directories.
|
||||
pip_dirname = os.path.dirname(bin_env)
|
||||
pip_parent_dir = os.path.dirname(pip_dirname)
|
||||
for bin_path in _search_paths(pip_dirname, pip_parent_dir):
|
||||
if os.path.isfile(bin_path):
|
||||
logger.debug('pip: Found python binary: %s', bin_path)
|
||||
return [os.path.normpath(bin_path), '-m', 'pip']
|
||||
|
||||
# Couldn't find python, use the passed pip binary
|
||||
# This has the limitation of being unable to update pip itself
|
||||
# We have been passed a pip binary, use the pip binary.
|
||||
return [os.path.normpath(bin_env)]
|
||||
|
||||
raise CommandExecutionError(
|
||||
|
@ -457,6 +444,13 @@ def install(pkgs=None, # pylint: disable=R0912,R0913,R0914
|
|||
``/usr/bin/pip-2.7`` or ``/usr/bin/pip-2.6``. If a directory path is
|
||||
specified, it is assumed to be a virtualenv.
|
||||
|
||||
.. note::
|
||||
|
||||
For Windows, if the pip module is being used to upgrade the pip
|
||||
package, bin_env should be the path to the virtualenv or to the
|
||||
python binary that should be used. The pip command is unable to
|
||||
upgrade itself in Windows.
|
||||
|
||||
use_wheel
|
||||
Prefer wheel archives (requires pip>=1.4)
|
||||
|
||||
|
|
|
@ -25,13 +25,13 @@ def __virtual__():
|
|||
'''
|
||||
if salt.utils.is_darwin() or salt.utils.is_windows():
|
||||
return True
|
||||
return (False, 'Module proxy: module only works on Windows or MacOS systems')
|
||||
return False, 'Module proxy: module only works on Windows or MacOS systems'
|
||||
|
||||
|
||||
def _get_proxy_osx(function, network_service):
|
||||
def _get_proxy_osx(cmd_function, network_service):
|
||||
ret = {}
|
||||
|
||||
out = __salt__['cmd.run']('networksetup -{0} {1}'.format(function, network_service))
|
||||
out = __salt__['cmd.run']('networksetup -{0} {1}'.format(cmd_function, network_service))
|
||||
match = re.match('Enabled: (.*)\nServer: (.*)\nPort: (.*)\n', out)
|
||||
if match is not None:
|
||||
g = match.groups()
|
||||
|
@ -41,8 +41,8 @@ def _get_proxy_osx(function, network_service):
|
|||
return ret
|
||||
|
||||
|
||||
def _set_proxy_osx(function, server, port, user, password, network_service):
|
||||
cmd = 'networksetup -{0} {1} {2} {3}'.format(function, network_service, server, port)
|
||||
def _set_proxy_osx(cmd_function, server, port, user, password, network_service):
|
||||
cmd = 'networksetup -{0} {1} {2} {3}'.format(cmd_function, network_service, server, port)
|
||||
|
||||
if user is not None and password is not None:
|
||||
cmd = cmd + ' On {0} {1}'.format(user, password)
|
||||
|
@ -58,12 +58,12 @@ def _get_proxy_windows(types=None):
|
|||
if types is None:
|
||||
types = ['http', 'https', 'ftp']
|
||||
|
||||
reg_val = __salt__['reg.read_value']('HKEY_CURRENT_USER',
|
||||
r'SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings',
|
||||
'ProxyServer')
|
||||
servers = reg_val['vdata']
|
||||
servers = __salt__['reg.read_value'](
|
||||
hive='HKEY_CURRENT_USER',
|
||||
key=r'SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings',
|
||||
vname='ProxyServer')['vdata']
|
||||
|
||||
if "=" in servers:
|
||||
if servers and "=" in servers:
|
||||
split = servers.split(";")
|
||||
for s in split:
|
||||
if len(s) == 0:
|
||||
|
@ -87,16 +87,19 @@ def _get_proxy_windows(types=None):
|
|||
del ret[key]
|
||||
|
||||
# Return enabled info
|
||||
reg_val = __salt__['reg.read_value']('HKEY_CURRENT_USER',
|
||||
r'SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings',
|
||||
'ProxyEnable')
|
||||
enabled = reg_val.get('vdata', 0)
|
||||
ret['enabled'] = True if enabled == 1 else False
|
||||
ret['enabled'] = __salt__['reg.read_value'](
|
||||
hive='HKEY_CURRENT_USER',
|
||||
key=r'SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings',
|
||||
vname='ProxyEnable')['vdata'] == 1
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def _set_proxy_windows(server, port, types=None, bypass_hosts=None, import_winhttp=True):
|
||||
def _set_proxy_windows(server,
|
||||
port,
|
||||
types=None,
|
||||
bypass_hosts=None,
|
||||
import_winhttp=True):
|
||||
if types is None:
|
||||
types = ['http', 'https', 'ftp']
|
||||
|
||||
|
@ -104,17 +107,27 @@ def _set_proxy_windows(server, port, types=None, bypass_hosts=None, import_winht
|
|||
for t in types:
|
||||
server_str += '{0}={1}:{2};'.format(t, server, port)
|
||||
|
||||
__salt__['reg.set_value']('HKEY_CURRENT_USER', r'SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings',
|
||||
'ProxyServer', server_str)
|
||||
__salt__['reg.set_value'](
|
||||
hive='HKEY_CURRENT_USER',
|
||||
key=r'SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings',
|
||||
vname='ProxyServer',
|
||||
vdata=server_str)
|
||||
|
||||
__salt__['reg.set_value']('HKEY_CURRENT_USER', r'SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings',
|
||||
'ProxyEnable', 1, vtype='REG_DWORD')
|
||||
__salt__['reg.set_value'](
|
||||
hive='HKEY_CURRENT_USER',
|
||||
key=r'SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings',
|
||||
vname='ProxyEnable',
|
||||
vdata=1,
|
||||
vtype='REG_DWORD')
|
||||
|
||||
if bypass_hosts is not None:
|
||||
bypass_hosts_str = '<local>;{0}'.format(';'.join(bypass_hosts))
|
||||
|
||||
__salt__['reg.set_value']('HKEY_CURRENT_USER', r'SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings',
|
||||
'ProxyOverride', bypass_hosts_str)
|
||||
__salt__['reg.set_value'](
|
||||
hive='HKEY_CURRENT_USER',
|
||||
key=r'SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings',
|
||||
vname='ProxyOverride',
|
||||
vdata=bypass_hosts_str)
|
||||
|
||||
if import_winhttp:
|
||||
cmd = 'netsh winhttp import proxy source=ie'
|
||||
|
@ -138,15 +151,22 @@ def get_http_proxy(network_service="Ethernet"):
|
|||
salt '*' proxy.get_http_proxy Ethernet
|
||||
'''
|
||||
if __grains__['os'] == 'Windows':
|
||||
return _get_proxy_windows(['http'])
|
||||
return _get_proxy_windows(types=['http'])
|
||||
|
||||
return _get_proxy_osx("getwebproxy", network_service)
|
||||
return _get_proxy_osx(cmd_function="getwebproxy",
|
||||
network_service=network_service)
|
||||
|
||||
|
||||
def set_http_proxy(server, port, user=None, password=None, network_service="Ethernet", bypass_hosts=None):
|
||||
def set_http_proxy(server,
|
||||
port,
|
||||
user=None,
|
||||
password=None,
|
||||
network_service="Ethernet",
|
||||
bypass_hosts=None):
|
||||
'''
|
||||
Sets the http proxy settings. Note: On Windows this will override any other proxy settings you have,
|
||||
the preferred method of updating proxies on windows is using set_proxy.
|
||||
Sets the http proxy settings. Note: On Windows this will override any other
|
||||
proxy settings you have, the preferred method of updating proxies on windows
|
||||
is using set_proxy.
|
||||
|
||||
server
|
||||
The proxy server to use
|
||||
|
@ -165,8 +185,8 @@ def set_http_proxy(server, port, user=None, password=None, network_service="Ethe
|
|||
macOS
|
||||
|
||||
bypass_hosts
|
||||
The hosts that are allowed to by pass the proxy. Only used on Windows for other OS's use
|
||||
set_proxy_bypass to edit the bypass hosts.
|
||||
The hosts that are allowed to by pass the proxy. Only used on Windows
|
||||
for other OS's use set_proxy_bypass to edit the bypass hosts.
|
||||
|
||||
CLI Example:
|
||||
|
||||
|
@ -175,9 +195,17 @@ def set_http_proxy(server, port, user=None, password=None, network_service="Ethe
|
|||
salt '*' proxy.set_http_proxy example.com 1080 user=proxy_user password=proxy_pass network_service=Ethernet
|
||||
'''
|
||||
if __grains__['os'] == 'Windows':
|
||||
return _set_proxy_windows(server, port, ['http'], bypass_hosts)
|
||||
return _set_proxy_windows(server=server,
|
||||
port=port,
|
||||
types=['http'],
|
||||
bypass_hosts=bypass_hosts)
|
||||
|
||||
return _set_proxy_osx("setwebproxy", server, port, user, password, network_service)
|
||||
return _set_proxy_osx(cmd_function="setwebproxy",
|
||||
server=server,
|
||||
port=port,
|
||||
user=user,
|
||||
password=password,
|
||||
network_service=network_service)
|
||||
|
||||
|
||||
def get_https_proxy(network_service="Ethernet"):
|
||||
|
@ -195,15 +223,22 @@ def get_https_proxy(network_service="Ethernet"):
|
|||
salt '*' proxy.get_https_proxy Ethernet
|
||||
'''
|
||||
if __grains__['os'] == 'Windows':
|
||||
return _get_proxy_windows(['https'])
|
||||
return _get_proxy_windows(types=['https'])
|
||||
|
||||
return _get_proxy_osx("getsecurewebproxy", network_service)
|
||||
return _get_proxy_osx(cmd_function="getsecurewebproxy",
|
||||
network_service=network_service)
|
||||
|
||||
|
||||
def set_https_proxy(server, port, user=None, password=None, network_service="Ethernet", bypass_hosts=None):
|
||||
def set_https_proxy(server,
|
||||
port,
|
||||
user=None,
|
||||
password=None,
|
||||
network_service="Ethernet",
|
||||
bypass_hosts=None):
|
||||
'''
|
||||
Sets the https proxy settings. Note: On Windows this will override any other proxy settings you have,
|
||||
the preferred method of updating proxies on windows is using set_proxy.
|
||||
Sets the https proxy settings. Note: On Windows this will override any other
|
||||
proxy settings you have, the preferred method of updating proxies on windows
|
||||
is using set_proxy.
|
||||
|
||||
server
|
||||
The proxy server to use
|
||||
|
@ -222,8 +257,8 @@ def set_https_proxy(server, port, user=None, password=None, network_service="Eth
|
|||
macOS
|
||||
|
||||
bypass_hosts
|
||||
The hosts that are allowed to by pass the proxy. Only used on Windows for other OS's use
|
||||
set_proxy_bypass to edit the bypass hosts.
|
||||
The hosts that are allowed to by pass the proxy. Only used on Windows
|
||||
for other OS's use set_proxy_bypass to edit the bypass hosts.
|
||||
|
||||
CLI Example:
|
||||
|
||||
|
@ -232,9 +267,17 @@ def set_https_proxy(server, port, user=None, password=None, network_service="Eth
|
|||
salt '*' proxy.set_https_proxy example.com 1080 user=proxy_user password=proxy_pass network_service=Ethernet
|
||||
'''
|
||||
if __grains__['os'] == 'Windows':
|
||||
return _set_proxy_windows(server, port, ['https'], bypass_hosts)
|
||||
return _set_proxy_windows(server=server,
|
||||
port=port,
|
||||
types=['https'],
|
||||
bypass_hosts=bypass_hosts)
|
||||
|
||||
return _set_proxy_osx("setsecurewebproxy", server, port, user, password, network_service)
|
||||
return _set_proxy_osx(cmd_function="setsecurewebproxy",
|
||||
server=server,
|
||||
port=port,
|
||||
user=user,
|
||||
password=password,
|
||||
network_service=network_service)
|
||||
|
||||
|
||||
def get_ftp_proxy(network_service="Ethernet"):
|
||||
|
@ -252,12 +295,18 @@ def get_ftp_proxy(network_service="Ethernet"):
|
|||
salt '*' proxy.get_ftp_proxy Ethernet
|
||||
'''
|
||||
if __grains__['os'] == 'Windows':
|
||||
return _get_proxy_windows(['ftp'])
|
||||
return _get_proxy_windows(types=['ftp'])
|
||||
|
||||
return _get_proxy_osx("getftpproxy", network_service)
|
||||
return _get_proxy_osx(cmd_function="getftpproxy",
|
||||
network_service=network_service)
|
||||
|
||||
|
||||
def set_ftp_proxy(server, port, user=None, password=None, network_service="Ethernet", bypass_hosts=None):
|
||||
def set_ftp_proxy(server,
|
||||
port,
|
||||
user=None,
|
||||
password=None,
|
||||
network_service="Ethernet",
|
||||
bypass_hosts=None):
|
||||
'''
|
||||
Sets the ftp proxy settings
|
||||
|
||||
|
@ -278,8 +327,8 @@ def set_ftp_proxy(server, port, user=None, password=None, network_service="Ether
|
|||
macOS
|
||||
|
||||
bypass_hosts
|
||||
The hosts that are allowed to by pass the proxy. Only used on Windows for other OS's use
|
||||
set_proxy_bypass to edit the bypass hosts.
|
||||
The hosts that are allowed to by pass the proxy. Only used on Windows
|
||||
for other OS's use set_proxy_bypass to edit the bypass hosts.
|
||||
|
||||
CLI Example:
|
||||
|
||||
|
@ -288,9 +337,17 @@ def set_ftp_proxy(server, port, user=None, password=None, network_service="Ether
|
|||
salt '*' proxy.set_ftp_proxy example.com 1080 user=proxy_user password=proxy_pass network_service=Ethernet
|
||||
'''
|
||||
if __grains__['os'] == 'Windows':
|
||||
return _set_proxy_windows(server, port, ['ftp'], bypass_hosts)
|
||||
return _set_proxy_windows(server=server,
|
||||
port=port,
|
||||
types=['ftp'],
|
||||
bypass_hosts=bypass_hosts)
|
||||
|
||||
return _set_proxy_osx("setftpproxy", server, port, user, password, network_service)
|
||||
return _set_proxy_osx(cmd_function="setftpproxy",
|
||||
server=server,
|
||||
port=port,
|
||||
user=user,
|
||||
password=password,
|
||||
network_service=network_service)
|
||||
|
||||
|
||||
def get_proxy_bypass(network_service="Ethernet"):
|
||||
|
@ -309,12 +366,16 @@ def get_proxy_bypass(network_service="Ethernet"):
|
|||
|
||||
'''
|
||||
if __grains__['os'] == 'Windows':
|
||||
reg_val = __salt__['reg.read_value']('HKEY_CURRENT_USER',
|
||||
r'SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings',
|
||||
'ProxyOverride')
|
||||
bypass_servers = reg_val['vdata'].replace("<local>", "").split(";")
|
||||
reg_val = __salt__['reg.read_value'](
|
||||
hive='HKEY_CURRENT_USER',
|
||||
key=r'SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings',
|
||||
vname='ProxyOverride')['vdata']
|
||||
|
||||
return bypass_servers
|
||||
# `reg.read_value` returns None if the key doesn't exist
|
||||
if reg_val is None:
|
||||
return []
|
||||
|
||||
return reg_val.replace('<local>', '').split(';')
|
||||
|
||||
out = __salt__['cmd.run']('networksetup -getproxybypassdomains {0}'.format(network_service))
|
||||
|
||||
|
@ -357,7 +418,12 @@ def set_proxy_win(server, port, types=None, bypass_hosts=None):
|
|||
The password to use if required by the server
|
||||
|
||||
types
|
||||
The types of proxy connections should be setup with this server. Valid types are http and https.
|
||||
The types of proxy connections should be setup with this server. Valid
|
||||
types are:
|
||||
|
||||
- ``http``
|
||||
- ``https``
|
||||
- ``ftp``
|
||||
|
||||
bypass_hosts
|
||||
The hosts that are allowed to by pass the proxy.
|
||||
|
@ -369,7 +435,10 @@ def set_proxy_win(server, port, types=None, bypass_hosts=None):
|
|||
salt '*' proxy.set_http_proxy example.com 1080 types="['http', 'https']"
|
||||
'''
|
||||
if __grains__['os'] == 'Windows':
|
||||
return _set_proxy_windows(server, port, types, bypass_hosts)
|
||||
return _set_proxy_windows(server=server,
|
||||
port=port,
|
||||
types=types,
|
||||
bypass_hosts=bypass_hosts)
|
||||
|
||||
|
||||
def get_proxy_win():
|
||||
|
|
|
@ -223,6 +223,7 @@ def list_users(runas=None):
|
|||
runas = salt.utils.get_user()
|
||||
res = __salt__['cmd.run_all'](
|
||||
[RABBITMQCTL, 'list_users', '-q'],
|
||||
reset_system_locale=False,
|
||||
runas=runas,
|
||||
python_shell=False)
|
||||
|
||||
|
@ -246,6 +247,7 @@ def list_vhosts(runas=None):
|
|||
runas = salt.utils.get_user()
|
||||
res = __salt__['cmd.run_all'](
|
||||
[RABBITMQCTL, 'list_vhosts', '-q'],
|
||||
reset_system_locale=False,
|
||||
runas=runas,
|
||||
python_shell=False)
|
||||
_check_response(res)
|
||||
|
@ -320,6 +322,7 @@ def add_user(name, password=None, runas=None):
|
|||
|
||||
res = __salt__['cmd.run_all'](
|
||||
cmd,
|
||||
reset_system_locale=False,
|
||||
output_loglevel='quiet',
|
||||
runas=runas,
|
||||
python_shell=python_shell)
|
||||
|
@ -352,6 +355,7 @@ def delete_user(name, runas=None):
|
|||
runas = salt.utils.get_user()
|
||||
res = __salt__['cmd.run_all'](
|
||||
[RABBITMQCTL, 'delete_user', name],
|
||||
reset_system_locale=False,
|
||||
python_shell=False,
|
||||
runas=runas)
|
||||
msg = 'Deleted'
|
||||
|
@ -387,6 +391,7 @@ def change_password(name, password, runas=None):
|
|||
cmd = [RABBITMQCTL, 'change_password', name, password]
|
||||
res = __salt__['cmd.run_all'](
|
||||
cmd,
|
||||
reset_system_locale=False,
|
||||
runas=runas,
|
||||
output_loglevel='quiet',
|
||||
python_shell=python_shell)
|
||||
|
@ -409,6 +414,7 @@ def clear_password(name, runas=None):
|
|||
runas = salt.utils.get_user()
|
||||
res = __salt__['cmd.run_all'](
|
||||
[RABBITMQCTL, 'clear_password', name],
|
||||
reset_system_locale=False,
|
||||
runas=runas,
|
||||
python_shell=False)
|
||||
msg = 'Password Cleared'
|
||||
|
@ -434,7 +440,7 @@ def check_password(name, password, runas=None):
|
|||
runas = salt.utils.get_user()
|
||||
|
||||
try:
|
||||
res = __salt__['cmd.run']([RABBITMQCTL, 'status'], runas=runas, python_shell=False)
|
||||
res = __salt__['cmd.run']([RABBITMQCTL, 'status'], reset_system_locale=False, runas=runas, python_shell=False)
|
||||
server_version = re.search(r'\{rabbit,"RabbitMQ","(.+)"\}', res)
|
||||
|
||||
if server_version is None:
|
||||
|
@ -466,6 +472,7 @@ def check_password(name, password, runas=None):
|
|||
|
||||
res = __salt__['cmd.run_all'](
|
||||
cmd,
|
||||
reset_system_locale=False,
|
||||
runas=runas,
|
||||
output_loglevel='quiet',
|
||||
python_shell=python_shell)
|
||||
|
@ -481,6 +488,7 @@ def check_password(name, password, runas=None):
|
|||
|
||||
res = __salt__['cmd.run_all'](
|
||||
[RABBITMQCTL, 'eval', cmd],
|
||||
reset_system_locale=False,
|
||||
runas=runas,
|
||||
output_loglevel='quiet',
|
||||
python_shell=False)
|
||||
|
@ -509,6 +517,7 @@ def add_vhost(vhost, runas=None):
|
|||
runas = salt.utils.get_user()
|
||||
res = __salt__['cmd.run_all'](
|
||||
[RABBITMQCTL, 'add_vhost', vhost],
|
||||
reset_system_locale=False,
|
||||
runas=runas,
|
||||
python_shell=False)
|
||||
|
||||
|
@ -530,6 +539,7 @@ def delete_vhost(vhost, runas=None):
|
|||
runas = salt.utils.get_user()
|
||||
res = __salt__['cmd.run_all'](
|
||||
[RABBITMQCTL, 'delete_vhost', vhost],
|
||||
reset_system_locale=False,
|
||||
runas=runas,
|
||||
python_shell=False)
|
||||
msg = 'Deleted'
|
||||
|
@ -551,6 +561,7 @@ def set_permissions(vhost, user, conf='.*', write='.*', read='.*', runas=None):
|
|||
res = __salt__['cmd.run_all'](
|
||||
[RABBITMQCTL, 'set_permissions', '-p',
|
||||
vhost, user, conf, write, read],
|
||||
reset_system_locale=False,
|
||||
runas=runas,
|
||||
python_shell=False)
|
||||
msg = 'Permissions Set'
|
||||
|
@ -571,6 +582,7 @@ def list_permissions(vhost, runas=None):
|
|||
runas = salt.utils.get_user()
|
||||
res = __salt__['cmd.run_all'](
|
||||
[RABBITMQCTL, 'list_permissions', '-q', '-p', vhost],
|
||||
reset_system_locale=False,
|
||||
runas=runas,
|
||||
python_shell=False)
|
||||
|
||||
|
@ -591,6 +603,7 @@ def list_user_permissions(name, runas=None):
|
|||
runas = salt.utils.get_user()
|
||||
res = __salt__['cmd.run_all'](
|
||||
[RABBITMQCTL, 'list_user_permissions', name, '-q'],
|
||||
reset_system_locale=False,
|
||||
runas=runas,
|
||||
python_shell=False)
|
||||
|
||||
|
@ -614,6 +627,7 @@ def set_user_tags(name, tags, runas=None):
|
|||
|
||||
res = __salt__['cmd.run_all'](
|
||||
[RABBITMQCTL, 'set_user_tags', name] + list(tags),
|
||||
reset_system_locale=False,
|
||||
runas=runas,
|
||||
python_shell=False)
|
||||
msg = "Tag(s) set"
|
||||
|
@ -634,6 +648,7 @@ def status(runas=None):
|
|||
runas = salt.utils.get_user()
|
||||
res = __salt__['cmd.run_all'](
|
||||
[RABBITMQCTL, 'status'],
|
||||
reset_system_locale=False,
|
||||
runas=runas,
|
||||
python_shell=False)
|
||||
_check_response(res)
|
||||
|
@ -654,6 +669,7 @@ def cluster_status(runas=None):
|
|||
runas = salt.utils.get_user()
|
||||
res = __salt__['cmd.run_all'](
|
||||
[RABBITMQCTL, 'cluster_status'],
|
||||
reset_system_locale=False,
|
||||
runas=runas,
|
||||
python_shell=False)
|
||||
_check_response(res)
|
||||
|
@ -678,7 +694,7 @@ def join_cluster(host, user='rabbit', ram_node=None, runas=None):
|
|||
if runas is None and not salt.utils.is_windows():
|
||||
runas = salt.utils.get_user()
|
||||
stop_app(runas)
|
||||
res = __salt__['cmd.run_all'](cmd, runas=runas, python_shell=False)
|
||||
res = __salt__['cmd.run_all'](cmd, reset_system_locale=False, runas=runas, python_shell=False)
|
||||
start_app(runas)
|
||||
|
||||
return _format_response(res, 'Join')
|
||||
|
@ -698,6 +714,7 @@ def stop_app(runas=None):
|
|||
runas = salt.utils.get_user()
|
||||
res = __salt__['cmd.run_all'](
|
||||
[RABBITMQCTL, 'stop_app'],
|
||||
reset_system_locale=False,
|
||||
runas=runas,
|
||||
python_shell=False)
|
||||
_check_response(res)
|
||||
|
@ -718,6 +735,7 @@ def start_app(runas=None):
|
|||
runas = salt.utils.get_user()
|
||||
res = __salt__['cmd.run_all'](
|
||||
[RABBITMQCTL, 'start_app'],
|
||||
reset_system_locale=False,
|
||||
runas=runas,
|
||||
python_shell=False)
|
||||
_check_response(res)
|
||||
|
@ -738,6 +756,7 @@ def reset(runas=None):
|
|||
runas = salt.utils.get_user()
|
||||
res = __salt__['cmd.run_all'](
|
||||
[RABBITMQCTL, 'reset'],
|
||||
reset_system_locale=False,
|
||||
runas=runas,
|
||||
python_shell=False)
|
||||
_check_response(res)
|
||||
|
@ -758,6 +777,7 @@ def force_reset(runas=None):
|
|||
runas = salt.utils.get_user()
|
||||
res = __salt__['cmd.run_all'](
|
||||
[RABBITMQCTL, 'force_reset'],
|
||||
reset_system_locale=False,
|
||||
runas=runas,
|
||||
python_shell=False)
|
||||
_check_response(res)
|
||||
|
@ -778,7 +798,7 @@ def list_queues(runas=None, *args):
|
|||
runas = salt.utils.get_user()
|
||||
cmd = [RABBITMQCTL, 'list_queues', '-q']
|
||||
cmd.extend(args)
|
||||
res = __salt__['cmd.run_all'](cmd, runas=runas, python_shell=False)
|
||||
res = __salt__['cmd.run_all'](cmd, reset_system_locale=False, runas=runas, python_shell=False)
|
||||
_check_response(res)
|
||||
return _output_to_dict(res['stdout'])
|
||||
|
||||
|
@ -800,7 +820,7 @@ def list_queues_vhost(vhost, runas=None, *args):
|
|||
runas = salt.utils.get_user()
|
||||
cmd = [RABBITMQCTL, 'list_queues', '-q', '-p', vhost]
|
||||
cmd.extend(args)
|
||||
res = __salt__['cmd.run_all'](cmd, runas=runas, python_shell=False)
|
||||
res = __salt__['cmd.run_all'](cmd, reset_system_locale=False, runas=runas, python_shell=False)
|
||||
_check_response(res)
|
||||
return _output_to_dict(res['stdout'])
|
||||
|
||||
|
@ -823,6 +843,7 @@ def list_policies(vhost="/", runas=None):
|
|||
runas = salt.utils.get_user()
|
||||
res = __salt__['cmd.run_all'](
|
||||
[RABBITMQCTL, 'list_policies', '-q', '-p', vhost],
|
||||
reset_system_locale=False,
|
||||
runas=runas,
|
||||
python_shell=False)
|
||||
_check_response(res)
|
||||
|
@ -873,8 +894,8 @@ def set_policy(vhost, name, pattern, definition, priority=None, runas=None):
|
|||
if priority:
|
||||
cmd.extend(['--priority', priority])
|
||||
cmd.extend([name, pattern, definition])
|
||||
res = __salt__['cmd.run_all'](cmd, runas=runas, python_shell=False)
|
||||
log.debug('Set policy: {0}'.format(res['stdout']))
|
||||
res = __salt__['cmd.run_all'](cmd, reset_system_locale=False, runas=runas, python_shell=False)
|
||||
log.debug('Set policy: %s', res['stdout'])
|
||||
return _format_response(res, 'Set')
|
||||
|
||||
|
||||
|
@ -894,6 +915,7 @@ def delete_policy(vhost, name, runas=None):
|
|||
runas = salt.utils.get_user()
|
||||
res = __salt__['cmd.run_all'](
|
||||
[RABBITMQCTL, 'clear_policy', '-p', vhost, name],
|
||||
reset_system_locale=False,
|
||||
runas=runas,
|
||||
python_shell=False)
|
||||
log.debug('Delete policy: {0}'.format(res['stdout']))
|
||||
|
@ -931,7 +953,7 @@ def list_available_plugins(runas=None):
|
|||
if runas is None and not salt.utils.is_windows():
|
||||
runas = salt.utils.get_user()
|
||||
cmd = [_get_rabbitmq_plugin(), 'list', '-m']
|
||||
ret = __salt__['cmd.run_all'](cmd, python_shell=False, runas=runas)
|
||||
ret = __salt__['cmd.run_all'](cmd, reset_system_locale=False, python_shell=False, runas=runas)
|
||||
_check_response(ret)
|
||||
return _output_to_list(ret['stdout'])
|
||||
|
||||
|
@ -949,7 +971,7 @@ def list_enabled_plugins(runas=None):
|
|||
if runas is None and not salt.utils.is_windows():
|
||||
runas = salt.utils.get_user()
|
||||
cmd = [_get_rabbitmq_plugin(), 'list', '-m', '-e']
|
||||
ret = __salt__['cmd.run_all'](cmd, python_shell=False, runas=runas)
|
||||
ret = __salt__['cmd.run_all'](cmd, reset_system_locale=False, python_shell=False, runas=runas)
|
||||
_check_response(ret)
|
||||
return _output_to_list(ret['stdout'])
|
||||
|
||||
|
@ -982,7 +1004,7 @@ def enable_plugin(name, runas=None):
|
|||
if runas is None and not salt.utils.is_windows():
|
||||
runas = salt.utils.get_user()
|
||||
cmd = [_get_rabbitmq_plugin(), 'enable', name]
|
||||
ret = __salt__['cmd.run_all'](cmd, runas=runas, python_shell=False)
|
||||
ret = __salt__['cmd.run_all'](cmd, reset_system_locale=False, runas=runas, python_shell=False)
|
||||
return _format_response(ret, 'Enabled')
|
||||
|
||||
|
||||
|
@ -999,5 +1021,5 @@ def disable_plugin(name, runas=None):
|
|||
if runas is None and not salt.utils.is_windows():
|
||||
runas = salt.utils.get_user()
|
||||
cmd = [_get_rabbitmq_plugin(), 'disable', name]
|
||||
ret = __salt__['cmd.run_all'](cmd, runas=runas, python_shell=False)
|
||||
ret = __salt__['cmd.run_all'](cmd, reset_system_locale=False, runas=runas, python_shell=False)
|
||||
return _format_response(ret, 'Disabled')
|
||||
|
|
|
@ -19,6 +19,7 @@ Module to provide redis functionality to Salt
|
|||
from __future__ import absolute_import
|
||||
from salt.ext.six.moves import zip
|
||||
from salt.ext import six
|
||||
from salt.utils import clean_kwargs
|
||||
from datetime import datetime
|
||||
|
||||
# Import third party libs
|
||||
|
@ -395,7 +396,7 @@ def hmset(key, **fieldsvals):
|
|||
database = fieldsvals.pop('db', None)
|
||||
password = fieldsvals.pop('password', None)
|
||||
server = _connect(host, port, database, password)
|
||||
return server.hmset(key, **fieldsvals)
|
||||
return server.hmset(key, clean_kwargs(**fieldsvals))
|
||||
|
||||
|
||||
def hset(key, field, value, host=None, port=None, db=None, password=None):
|
||||
|
|
|
@ -35,6 +35,7 @@ def __virtual__():
|
|||
'Devuan',
|
||||
'Arch',
|
||||
'Arch ARM',
|
||||
'Manjaro',
|
||||
'ALT',
|
||||
'SUSE Enterprise Server',
|
||||
'SUSE',
|
||||
|
|
|
@ -458,8 +458,7 @@ def template_str(tem, queue=False, **kwargs):
|
|||
return ret
|
||||
|
||||
|
||||
def apply_(mods=None,
|
||||
**kwargs):
|
||||
def apply_(mods=None, **kwargs):
|
||||
'''
|
||||
.. versionadded:: 2015.5.0
|
||||
|
||||
|
@ -599,6 +598,22 @@ def apply_(mods=None,
|
|||
.. code-block:: bash
|
||||
|
||||
salt '*' state.apply test localconfig=/path/to/minion.yml
|
||||
|
||||
sync_mods
|
||||
If specified, the desired custom module types will be synced prior to
|
||||
running the SLS files:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' state.apply test sync_mods=states,modules
|
||||
salt '*' state.apply test sync_mods=all
|
||||
|
||||
.. note::
|
||||
This option is ignored when no SLS files are specified, as a
|
||||
:ref:`highstate <running-highstate>` automatically syncs all custom
|
||||
module types.
|
||||
|
||||
.. versionadded:: 2017.7.8,2018.3.3,Fluorine
|
||||
'''
|
||||
if mods:
|
||||
return sls(mods, **kwargs)
|
||||
|
@ -928,7 +943,7 @@ def highstate(test=None, queue=False, **kwargs):
|
|||
return ret
|
||||
|
||||
|
||||
def sls(mods, test=None, exclude=None, queue=False, **kwargs):
|
||||
def sls(mods, test=None, exclude=None, queue=False, sync_mods=None, **kwargs):
|
||||
'''
|
||||
Execute the states in one or more SLS files
|
||||
|
||||
|
@ -1019,6 +1034,17 @@ def sls(mods, test=None, exclude=None, queue=False, **kwargs):
|
|||
|
||||
.. versionadded:: 2015.8.4
|
||||
|
||||
sync_mods
|
||||
If specified, the desired custom module types will be synced prior to
|
||||
running the SLS files:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' state.sls test sync_mods=states,modules
|
||||
salt '*' state.sls test sync_mods=all
|
||||
|
||||
.. versionadded:: 2017.7.8,2018.3.3,Fluorine
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
@ -1087,6 +1113,28 @@ def sls(mods, test=None, exclude=None, queue=False, **kwargs):
|
|||
'{0}.cache.p'.format(kwargs.get('cache_name', 'highstate'))
|
||||
)
|
||||
|
||||
if sync_mods is True:
|
||||
sync_mods = ['all']
|
||||
if sync_mods is not None:
|
||||
sync_mods = salt.utils.split_input(sync_mods)
|
||||
else:
|
||||
sync_mods = []
|
||||
|
||||
if 'all' in sync_mods and sync_mods != ['all']:
|
||||
# Prevent unnecessary extra syncing
|
||||
sync_mods = ['all']
|
||||
|
||||
for module_type in sync_mods:
|
||||
try:
|
||||
__salt__['saltutil.sync_{0}'.format(module_type)](
|
||||
saltenv=opts['environment']
|
||||
)
|
||||
except KeyError:
|
||||
log.warning(
|
||||
'Invalid custom module type \'%s\', ignoring',
|
||||
module_type
|
||||
)
|
||||
|
||||
try:
|
||||
st_ = salt.state.HighState(opts,
|
||||
pillar_override,
|
||||
|
|
|
@ -296,7 +296,7 @@ def _register_functions():
|
|||
modules_ = [module_ for module_ in modules.modules]
|
||||
|
||||
for mod_name in modules_:
|
||||
mod_name = _to_snake_case(module_)
|
||||
mod_name = _to_snake_case(mod_name)
|
||||
mod_func = _copy_function(mod_name, str(mod_name))
|
||||
mod_func.__doc__ = _build_doc(mod_name)
|
||||
__all__.append(mod_name)
|
||||
|
|
|
@ -683,7 +683,7 @@ def modify(name,
|
|||
win32service.SERVICE_QUERY_CONFIG)
|
||||
except pywintypes.error as exc:
|
||||
raise CommandExecutionError(
|
||||
'Failed To Open {0}: {1}'.format(name, exc[2]))
|
||||
'Failed To Open {0}: {1}'.format(name, exc))
|
||||
|
||||
config_info = win32service.QueryServiceConfig(handle_svc)
|
||||
|
||||
|
|
|
@ -942,7 +942,6 @@ def create_crl( # pylint: disable=too-many-arguments,too-many-locals
|
|||
rev_item['not_after'] = rev_cert['Not After']
|
||||
|
||||
serial_number = rev_item['serial_number'].replace(':', '')
|
||||
serial_number = str(int(serial_number, 16))
|
||||
|
||||
if 'not_after' in rev_item and not include_expired:
|
||||
not_after = datetime.datetime.strptime(
|
||||
|
|
|
@ -581,6 +581,8 @@ def latest_version(*names, **kwargs):
|
|||
status = pkg_info.get('status', '').lower()
|
||||
if status.find('not installed') > -1 or status.find('out-of-date') > -1:
|
||||
ret[name] = pkg_info.get('version')
|
||||
else:
|
||||
ret[name] = ''
|
||||
|
||||
# Return a string if only one package name passed
|
||||
if len(names) == 1 and len(ret):
|
||||
|
|
|
@ -210,7 +210,7 @@ import tornado
|
|||
TORNADO_50 = tornado.version_info >= (5,)
|
||||
|
||||
if not TORNADO_50:
|
||||
import zmq.eventloop.ioloop
|
||||
import zmq.eventloop.ioloop # pylint: disable=import-error
|
||||
# instantiate the zmq IOLoop (specialized poller)
|
||||
zmq.eventloop.ioloop.install()
|
||||
|
||||
|
@ -923,9 +923,11 @@ class SaltAPIHandler(BaseSaltAPIHandler): # pylint: disable=W0223
|
|||
# Generate jid before triggering a job to subscribe all returns from minions
|
||||
chunk['jid'] = salt.utils.jid.gen_jid()
|
||||
|
||||
# Subscribe returns from minions before firing a job
|
||||
minions = set(self.ckminions.check_minions(chunk['tgt'], chunk.get('tgt_type', 'glob')))
|
||||
future_minion_map = self.subscribe_minion_returns(chunk['jid'], minions)
|
||||
# start listening for the event before we fire the job to avoid races
|
||||
events = [
|
||||
self.application.event_listener.get_event(self, tag='salt/job/'+chunk['jid']),
|
||||
self.application.event_listener.get_event(self, tag='syndic/job/'+chunk['jid']),
|
||||
]
|
||||
|
||||
f_call = self._format_call_run_job_async(chunk)
|
||||
# fire a job off
|
||||
|
@ -937,88 +939,92 @@ class SaltAPIHandler(BaseSaltAPIHandler): # pylint: disable=W0223
|
|||
# if the job didn't publish, lets not wait around for nothing
|
||||
# TODO: set header??
|
||||
if 'jid' not in pub_data:
|
||||
for future in future_minion_map:
|
||||
for future in events:
|
||||
try:
|
||||
future.set_result(None)
|
||||
except Exception:
|
||||
pass
|
||||
raise tornado.gen.Return('No minions matched the target. No command was sent, no jid was assigned.')
|
||||
|
||||
# Map of minion_id -> returned for all minions we think we need to wait on
|
||||
minions = {m: False for m in pub_data['minions']}
|
||||
|
||||
# minimum time required for return to complete. By default no waiting, if
|
||||
# we are a syndic then we must wait syndic_wait at a minimum
|
||||
min_wait_time = Future()
|
||||
min_wait_time.set_result(True)
|
||||
|
||||
# wait syndic a while to avoid missing published events
|
||||
if self.application.opts['order_masters']:
|
||||
yield tornado.gen.sleep(self.application.opts['syndic_wait'])
|
||||
min_wait_time = tornado.gen.sleep(self.application.opts['syndic_wait'])
|
||||
|
||||
# To ensure job_not_running and all_return are terminated by each other, communicate using a future
|
||||
is_finished = Future()
|
||||
is_finished = tornado.gen.sleep(self.application.opts['gather_job_timeout'])
|
||||
|
||||
job_not_running_future = self.job_not_running(pub_data['jid'],
|
||||
# ping until the job is not running, while doing so, if we see new minions returning
|
||||
# that they are running the job, add them to the list
|
||||
tornado.ioloop.IOLoop.current().spawn_callback(self.job_not_running, pub_data['jid'],
|
||||
chunk['tgt'],
|
||||
f_call['kwargs']['tgt_type'],
|
||||
minions,
|
||||
is_finished)
|
||||
|
||||
minion_returns_future = self.sanitize_minion_returns(future_minion_map, pub_data['minions'], is_finished)
|
||||
|
||||
yield job_not_running_future
|
||||
raise tornado.gen.Return((yield minion_returns_future))
|
||||
|
||||
def subscribe_minion_returns(self, jid, minions):
|
||||
# Subscribe each minion event
|
||||
future_minion_map = {}
|
||||
for minion in minions:
|
||||
tag = tagify([jid, 'ret', minion], 'job')
|
||||
minion_future = self.application.event_listener.get_event(self,
|
||||
tag=tag,
|
||||
matcher=EventListener.exact_matcher)
|
||||
future_minion_map[minion_future] = minion
|
||||
return future_minion_map
|
||||
|
||||
@tornado.gen.coroutine
|
||||
def sanitize_minion_returns(self, future_minion_map, minions, is_finished):
|
||||
'''
|
||||
Return a future which will complete once all returns are completed
|
||||
(according to minions), or one of the passed in "finish_chunk_ret_future" completes
|
||||
'''
|
||||
if minions is None:
|
||||
minions = []
|
||||
|
||||
# Remove redundant minions
|
||||
redundant_minion_futures = [future for future in future_minion_map.keys() if future_minion_map[future] not in minions]
|
||||
for redundant_minion_future in redundant_minion_futures:
|
||||
try:
|
||||
redundant_minion_future.set_result(None)
|
||||
except Exception:
|
||||
pass
|
||||
del future_minion_map[redundant_minion_future]
|
||||
def more_todo():
|
||||
'''Check if there are any more minions we are waiting on returns from
|
||||
'''
|
||||
return any(x is False for x in six.itervalues(minions))
|
||||
|
||||
# here we want to follow the behavior of LocalClient.get_iter_returns
|
||||
# namely we want to wait at least syndic_wait (assuming we are a syndic)
|
||||
# and that there are no more jobs running on minions. We are allowed to exit
|
||||
# early if gather_job_timeout has been exceeded
|
||||
chunk_ret = {}
|
||||
while True:
|
||||
f = yield Any(list(future_minion_map.keys()) + [is_finished])
|
||||
to_wait = events+[is_finished]
|
||||
if not min_wait_time.done():
|
||||
to_wait += [min_wait_time]
|
||||
|
||||
def cancel_inflight_futures():
|
||||
for event in to_wait:
|
||||
if not event.done():
|
||||
event.set_result(None)
|
||||
f = yield Any(to_wait)
|
||||
try:
|
||||
# When finished entire routine, cleanup other futures and return result
|
||||
if f is is_finished:
|
||||
for event in future_minion_map.keys():
|
||||
if not event.done():
|
||||
event.set_result(None)
|
||||
cancel_inflight_futures()
|
||||
raise tornado.gen.Return(chunk_ret)
|
||||
elif f is min_wait_time:
|
||||
if not more_todo():
|
||||
cancel_inflight_futures()
|
||||
raise tornado.gen.Return(chunk_ret)
|
||||
continue
|
||||
f_result = f.result()
|
||||
chunk_ret[f_result['data']['id']] = f_result['data']['return']
|
||||
# if this is a start, then we need to add it to the pile
|
||||
if f_result['tag'].endswith('/new'):
|
||||
for minion_id in f_result['data']['minions']:
|
||||
if minion_id not in minions:
|
||||
minions[minion_id] = False
|
||||
else:
|
||||
chunk_ret[f_result['data']['id']] = f_result['data']['return']
|
||||
# clear finished event future
|
||||
minions[f_result['data']['id']] = True
|
||||
|
||||
# if there are no more minions to wait for, then we are done
|
||||
if not more_todo() and min_wait_time.done():
|
||||
cancel_inflight_futures()
|
||||
raise tornado.gen.Return(chunk_ret)
|
||||
|
||||
except TimeoutException:
|
||||
pass
|
||||
|
||||
# clear finished event future
|
||||
try:
|
||||
minions.remove(future_minion_map[f])
|
||||
del future_minion_map[f]
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
if not minions:
|
||||
if not is_finished.done():
|
||||
is_finished.set_result(True)
|
||||
raise tornado.gen.Return(chunk_ret)
|
||||
if f == events[0]:
|
||||
events[0] = self.application.event_listener.get_event(self, tag='salt/job/'+chunk['jid'])
|
||||
else:
|
||||
events[1] = self.application.event_listener.get_event(self, tag='syndic/job/'+chunk['jid'])
|
||||
|
||||
@tornado.gen.coroutine
|
||||
def job_not_running(self, jid, tgt, tgt_type, is_finished):
|
||||
def job_not_running(self, jid, tgt, tgt_type, minions, is_finished):
|
||||
'''
|
||||
Return a future which will complete once jid (passed in) is no longer
|
||||
running on tgt
|
||||
|
@ -1044,8 +1050,6 @@ class SaltAPIHandler(BaseSaltAPIHandler): # pylint: disable=W0223
|
|||
event = f.result()
|
||||
except TimeoutException:
|
||||
if not minion_running:
|
||||
if not is_finished.done():
|
||||
is_finished.set_result(True)
|
||||
raise tornado.gen.Return(True)
|
||||
else:
|
||||
ping_pub_data = yield self.saltclients['local'](tgt,
|
||||
|
@ -1059,6 +1063,8 @@ class SaltAPIHandler(BaseSaltAPIHandler): # pylint: disable=W0223
|
|||
# Minions can return, we want to see if the job is running...
|
||||
if event['data'].get('return', {}) == {}:
|
||||
continue
|
||||
if event['data']['id'] not in minions:
|
||||
minions[event['data']['id']] = False
|
||||
minion_running = True
|
||||
|
||||
@tornado.gen.coroutine
|
||||
|
|
|
@ -923,6 +923,11 @@ class Pillar(object):
|
|||
decrypt_errors = self.decrypt_pillar(pillar)
|
||||
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):
|
||||
|
|
|
@ -154,7 +154,7 @@ def action(func=None,
|
|||
info = {}
|
||||
client = _get_client()
|
||||
try:
|
||||
info = client.action(func, cloudmap, instances, provider, instance, **_filter_kwargs(kwargs))
|
||||
info = client.action(func, cloudmap, instances, provider, instance, _filter_kwargs(kwargs))
|
||||
except SaltCloudConfigError as err:
|
||||
log.error(err)
|
||||
return info
|
||||
|
|
|
@ -150,7 +150,7 @@ def lookup_jid(jid,
|
|||
try:
|
||||
# Check if the return data has an 'out' key. We'll use that as the
|
||||
# outputter in the absence of one being passed on the CLI.
|
||||
outputter = data[next(iter(data))].get('out')
|
||||
outputter = returns[next(iter(returns))].get('out')
|
||||
except (StopIteration, AttributeError):
|
||||
outputter = None
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@ def set_(key, value, service=None, profile=None): # pylint: disable=W0613
|
|||
'''
|
||||
key, profile = _parse_key(key, profile)
|
||||
cache = salt.cache.Cache(__opts__)
|
||||
cache.set(profile['bank'], key=key, value=value)
|
||||
cache.store(profile['bank'], key, value)
|
||||
return get(key, service, profile)
|
||||
|
||||
|
||||
|
|
|
@ -80,6 +80,8 @@ def _checksum_file_path(path):
|
|||
drive.rstrip(':'),
|
||||
path.lstrip('/\\'),
|
||||
)
|
||||
elif str(exc).startswith('Cannot mix UNC'):
|
||||
relpath = salt.utils.path_join('unc', path)
|
||||
else:
|
||||
raise
|
||||
ret = salt.utils.path_join(__opts__['cachedir'], 'archive_hash', relpath)
|
||||
|
|
|
@ -1396,19 +1396,25 @@ def symlink(
|
|||
preflight_errors = []
|
||||
if salt.utils.is_windows():
|
||||
# Make sure the passed owner exists
|
||||
if not salt.utils.win_functions.get_sid_from_name(win_owner):
|
||||
try:
|
||||
salt.utils.win_functions.get_sid_from_name(win_owner)
|
||||
except CommandExecutionError as exc:
|
||||
preflight_errors.append('User {0} does not exist'.format(win_owner))
|
||||
|
||||
# Make sure users passed in win_perms exist
|
||||
if win_perms:
|
||||
for name_check in win_perms:
|
||||
if not salt.utils.win_functions.get_sid_from_name(name_check):
|
||||
try:
|
||||
salt.utils.win_functions.get_sid_from_name(name_check)
|
||||
except CommandExecutionError as exc:
|
||||
preflight_errors.append('User {0} does not exist'.format(name_check))
|
||||
|
||||
# Make sure users passed in win_deny_perms exist
|
||||
if win_deny_perms:
|
||||
for name_check in win_deny_perms:
|
||||
if not salt.utils.win_functions.get_sid_from_name(name_check):
|
||||
try:
|
||||
salt.utils.win_functions.get_sid_from_name(name_check)
|
||||
except CommandExecutionError as exc:
|
||||
preflight_errors.append('User {0} does not exist'.format(name_check))
|
||||
else:
|
||||
uid = __salt__['file.user_to_uid'](user)
|
||||
|
@ -5663,7 +5669,7 @@ def copy(
|
|||
if not os.path.isdir(dname):
|
||||
if makedirs:
|
||||
try:
|
||||
_makedirs(name=name)
|
||||
_makedirs(name=name, user=user, group=group, dir_mode=mode)
|
||||
except CommandExecutionError as exc:
|
||||
return _error(ret, 'Drive {0} is not mapped'.format(exc.message))
|
||||
else:
|
||||
|
|
|
@ -72,9 +72,16 @@ def _changes(name,
|
|||
delusers = [salt.utils.win_functions.get_sam_name(user).lower() for user in delusers]
|
||||
|
||||
change = {}
|
||||
ret = {}
|
||||
if gid:
|
||||
if lgrp['gid'] != gid:
|
||||
change['gid'] = gid
|
||||
try:
|
||||
gid = int(gid)
|
||||
if lgrp['gid'] != gid:
|
||||
change['gid'] = gid
|
||||
except (TypeError, ValueError):
|
||||
ret['result'] = False
|
||||
ret['comment'] = 'Invalid gid'
|
||||
return ret
|
||||
|
||||
if members:
|
||||
# -- if new member list if different than the current
|
||||
|
|
|
@ -255,7 +255,12 @@ def _disable(name, started, result=True, **kwargs):
|
|||
return ret
|
||||
|
||||
# Service can be disabled
|
||||
before_toggle_disable_status = __salt__['service.disabled'](name)
|
||||
if salt.utils.is_windows():
|
||||
# service.disabled in Windows returns True for services that are set to
|
||||
# Manual start, so we need to check specifically for Disabled
|
||||
before_toggle_disable_status = __salt__['service.info'](name)['StartType'] in ['Disabled']
|
||||
else:
|
||||
before_toggle_disable_status = __salt__['service.disabled'](name)
|
||||
if before_toggle_disable_status:
|
||||
# Service is disabled
|
||||
if started is True:
|
||||
|
@ -549,7 +554,12 @@ def dead(name,
|
|||
# command, so it is just an indicator but can not be fully trusted
|
||||
before_toggle_status = __salt__['service.status'](name, sig)
|
||||
if 'service.enabled' in __salt__:
|
||||
before_toggle_enable_status = __salt__['service.enabled'](name)
|
||||
if salt.utils.is_windows():
|
||||
# service.enabled in Windows returns True for services that are set
|
||||
# to Auto start, but services set to Manual can also be disabled
|
||||
before_toggle_enable_status = __salt__['service.info'](name)['StartType'] in ['Auto', 'Manual']
|
||||
else:
|
||||
before_toggle_enable_status = __salt__['service.enabled'](name)
|
||||
else:
|
||||
before_toggle_enable_status = True
|
||||
|
||||
|
|
|
@ -752,9 +752,9 @@ class IPCMessageSubscriber(IPCClient):
|
|||
# This will prevent this message from showing up:
|
||||
# '[ERROR ] Future exception was never retrieved:
|
||||
# StreamClosedError'
|
||||
if self._read_sync_future is not None:
|
||||
if self._read_sync_future is not None and self._read_sync_future.done():
|
||||
self._read_sync_future.exception()
|
||||
if self._read_stream_future is not None:
|
||||
if self._read_stream_future is not None and self._read_stream_future.done():
|
||||
self._read_stream_future.exception()
|
||||
|
||||
def __del__(self):
|
||||
|
|
|
@ -896,10 +896,9 @@ class SaltMessageClient(object):
|
|||
# This happens because the logic is always waiting to read
|
||||
# the next message and the associated read future is marked
|
||||
# 'StreamClosedError' when the stream is closed.
|
||||
self._read_until_future.exception()
|
||||
if (not self._stream_return_future.done() and
|
||||
self.io_loop != tornado.ioloop.IOLoop.current(
|
||||
instance=False)):
|
||||
if self._read_until_future.done():
|
||||
self._read_until_future.exception()
|
||||
elif self.io_loop != tornado.ioloop.IOLoop.current(instance=False):
|
||||
self.io_loop.add_future(
|
||||
self._stream_return_future,
|
||||
lambda future: self.io_loop.stop()
|
||||
|
@ -1134,7 +1133,7 @@ class Subscriber(object):
|
|||
self._closing = True
|
||||
if not self.stream.closed():
|
||||
self.stream.close()
|
||||
if self._read_until_future is not None:
|
||||
if self._read_until_future is not None and self._read_until_future.done():
|
||||
# This will prevent this message from showing up:
|
||||
# '[ERROR ] Future exception was never retrieved:
|
||||
# StreamClosedError'
|
||||
|
|
|
@ -2360,7 +2360,7 @@ def alias_function(fun, name, doc=None):
|
|||
orig_name = fun.__name__
|
||||
alias_msg = ('\nThis function is an alias of '
|
||||
'``{0}``.\n'.format(orig_name))
|
||||
alias_fun.__doc__ = alias_msg + fun.__doc__
|
||||
alias_fun.__doc__ = alias_msg + (fun.__doc__ or '')
|
||||
|
||||
return alias_fun
|
||||
|
||||
|
|
|
@ -70,10 +70,9 @@ def _init_libcrypto():
|
|||
libcrypto.RSA_public_decrypt.argtypes = (c_int, c_char_p, c_char_p, c_void_p, c_int)
|
||||
|
||||
try:
|
||||
if libcrypto.OPENSSL_init_crypto(OPENSSL_INIT_NO_LOAD_CONFIG |
|
||||
OPENSSL_INIT_ADD_ALL_CIPHERS |
|
||||
OPENSSL_INIT_ADD_ALL_DIGESTS, None) != 1:
|
||||
raise OSError("Failed to initialize OpenSSL library (OPENSSL_init_crypto failed)")
|
||||
libcrypto.OPENSSL_init_crypto(OPENSSL_INIT_NO_LOAD_CONFIG |
|
||||
OPENSSL_INIT_ADD_ALL_CIPHERS |
|
||||
OPENSSL_INIT_ADD_ALL_DIGESTS, None)
|
||||
except AttributeError:
|
||||
# Support for OpenSSL < 1.1 (OPENSSL_API_COMPAT < 0x10100000L)
|
||||
libcrypto.OPENSSL_no_config()
|
||||
|
|
|
@ -156,20 +156,23 @@ def query(key, keyid, method='GET', params=None, headers=None,
|
|||
headers=headers,
|
||||
data=data,
|
||||
verify=verify_ssl,
|
||||
stream=True)
|
||||
stream=True,
|
||||
timeout=300)
|
||||
elif method == 'GET' and local_file and not return_bin:
|
||||
result = requests.request(method,
|
||||
requesturl,
|
||||
headers=headers,
|
||||
data=data,
|
||||
verify=verify_ssl,
|
||||
stream=True)
|
||||
stream=True,
|
||||
timeout=300)
|
||||
else:
|
||||
result = requests.request(method,
|
||||
requesturl,
|
||||
headers=headers,
|
||||
data=data,
|
||||
verify=verify_ssl)
|
||||
verify=verify_ssl,
|
||||
timeout=300)
|
||||
finally:
|
||||
if data is not None:
|
||||
data.close()
|
||||
|
|
|
@ -14,6 +14,7 @@ import tarfile
|
|||
import zipfile
|
||||
import tempfile
|
||||
import subprocess
|
||||
import concurrent
|
||||
|
||||
# Import third party libs
|
||||
import jinja2
|
||||
|
@ -106,6 +107,8 @@ def get_tops(extra_mods='', so_mods=''):
|
|||
os.path.dirname(msgpack.__file__),
|
||||
]
|
||||
|
||||
if _six.PY2:
|
||||
tops.append(os.path.dirname(concurrent.__file__))
|
||||
tops.append(_six.__file__.replace('.pyc', '.py'))
|
||||
tops.append(backports_abc.__file__.replace('.pyc', '.py'))
|
||||
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
# Import python libs
|
||||
from __future__ import absolute_import
|
||||
# pylint: disable=blacklisted-module
|
||||
from distutils.version import StrictVersion as _StrictVersion
|
||||
from distutils.version import LooseVersion as _LooseVersion
|
||||
from distutils.version import StrictVersion as _StrictVersion # pylint: disable=no-name-in-module
|
||||
from distutils.version import LooseVersion as _LooseVersion # pylint: disable=no-name-in-module
|
||||
# pylint: enable=blacklisted-module
|
||||
|
||||
# Import 3rd-party libs
|
||||
|
|
|
@ -140,7 +140,7 @@ def accept_dict(match, include_rejected=False, include_denied=False):
|
|||
|
||||
.. code-block:: python
|
||||
|
||||
>>> wheel.cmd('accept_dict',
|
||||
>>> wheel.cmd('key.accept_dict',
|
||||
{
|
||||
'minions_pre': [
|
||||
'jerry',
|
||||
|
|
4
setup.py
4
setup.py
|
@ -366,14 +366,14 @@ class DownloadWindowsDlls(Command):
|
|||
import pip
|
||||
# pip has moved many things to `_internal` starting with pip 10
|
||||
if LooseVersion(pip.__version__) < LooseVersion('10.0'):
|
||||
from pip.utils.logging import indent_log
|
||||
from pip.utils.logging import indent_log # pylint: disable=no-name-in-module
|
||||
else:
|
||||
from pip._internal.utils.logging import indent_log # pylint: disable=no-name-in-module
|
||||
platform_bits, _ = platform.architecture()
|
||||
url = 'https://repo.saltstack.com/windows/dependencies/{bits}/{fname}.dll'
|
||||
dest = os.path.join(os.path.dirname(sys.executable), '{fname}.dll')
|
||||
with indent_log():
|
||||
for fname in ('libeay32', 'ssleay32', 'msvcr120'):
|
||||
for fname in ('libeay32', 'libsodium', 'ssleay32', 'msvcr120'):
|
||||
# See if the library is already on the system
|
||||
if find_library(fname):
|
||||
continue
|
||||
|
|
1
tests/integration/files/file/base/hello_world.txt
Normal file
1
tests/integration/files/file/base/hello_world.txt
Normal file
|
@ -0,0 +1 @@
|
|||
Hello, World!
|
|
@ -3,3 +3,7 @@ ssh-file-test:
|
|||
file.managed:
|
||||
- name: /tmp/{{ jinja }}
|
||||
- contents: 'test'
|
||||
|
||||
second_id:
|
||||
cmd.run:
|
||||
- name: echo test
|
||||
|
|
|
@ -11,7 +11,7 @@ import string
|
|||
# Import Salt Testing libs
|
||||
from tests.support.case import ModuleCase
|
||||
from tests.support.unit import skipIf
|
||||
from tests.support.helpers import destructiveTest, skip_if_not_root
|
||||
from tests.support.helpers import destructiveTest, skip_if_not_root, flaky
|
||||
|
||||
# Import salt libs
|
||||
import salt.utils
|
||||
|
@ -33,6 +33,7 @@ SET_SUBNET_NAME = __random_string()
|
|||
|
||||
|
||||
@skip_if_not_root
|
||||
@flaky
|
||||
@skipIf(not salt.utils.is_darwin(), 'Test only available on macOS')
|
||||
@skipIf(not salt.utils.which('systemsetup'), '\'systemsetup\' binary not found in $PATH')
|
||||
class MacSystemModuleTest(ModuleCase):
|
||||
|
|
|
@ -17,13 +17,14 @@ import datetime
|
|||
# Import Salt Testing libs
|
||||
from tests.support.case import ModuleCase
|
||||
from tests.support.unit import skipIf
|
||||
from tests.support.helpers import destructiveTest, skip_if_not_root
|
||||
from tests.support.helpers import destructiveTest, skip_if_not_root, flaky
|
||||
|
||||
# Import salt libs
|
||||
import salt.utils
|
||||
|
||||
|
||||
@skip_if_not_root
|
||||
@flaky
|
||||
@skipIf(not salt.utils.is_darwin(), 'Test only available on macOS')
|
||||
@skipIf(not salt.utils.which('systemsetup'), '\'systemsetup\' binary not found in $PATH')
|
||||
class MacTimezoneModuleTest(ModuleCase):
|
||||
|
|
|
@ -429,6 +429,16 @@ class PipModuleTest(ModuleCase):
|
|||
pprint.pprint(ret)
|
||||
raise
|
||||
|
||||
@skipIf(not os.path.isfile('pip3'), 'test where pip3 is installed')
|
||||
@skipIf(salt.utils.is_windows(), 'test specific for linux usage of /bin/python')
|
||||
def test_system_pip3(self):
|
||||
self.run_function('pip.install', pkgs=['lazyimport==0.0.1'], bin_env='/bin/pip3')
|
||||
ret1 = self.run_function('cmd.run', '/bin/pip3 freeze | grep lazyimport')
|
||||
self.run_function('pip.uninstall', pkgs=['lazyimport'], bin_env='/bin/pip3')
|
||||
ret2 = self.run_function('cmd.run', '/bin/pip3 freeze | grep lazyimport')
|
||||
assert 'lazyimport==0.0.1' in ret1
|
||||
assert ret2 == ''
|
||||
|
||||
def tearDown(self):
|
||||
super(PipModuleTest, self).tearDown()
|
||||
if os.path.isdir(self.venv_test_dir):
|
||||
|
|
|
@ -266,6 +266,10 @@ class TestSaltAPIHandler(_SaltnadoIntegrationTestCase):
|
|||
'tgt': '*',
|
||||
'fun': 'test.ping',
|
||||
}
|
||||
|
||||
self.application.opts['order_masters'] = True
|
||||
self.application.opts['syndic_wait'] = 5
|
||||
|
||||
response = self.fetch('/',
|
||||
method='POST',
|
||||
body=salt.utils.json.dumps(low),
|
||||
|
|
|
@ -382,3 +382,88 @@ class OrchEventTest(ShellCase):
|
|||
self.assertTrue(received)
|
||||
del listener
|
||||
signal.alarm(0)
|
||||
|
||||
def test_orchestration_with_pillar_dot_items(self):
|
||||
'''
|
||||
Test to confirm when using a state file that includes other state file, if
|
||||
one of those state files includes pillar related functions that will not
|
||||
be pulling from the pillar cache that all the state files are available and
|
||||
the file_roots has been preserved. See issues #48277 and #46986.
|
||||
'''
|
||||
self.write_conf({
|
||||
'fileserver_backend': ['roots'],
|
||||
'file_roots': {
|
||||
'base': [self.base_env],
|
||||
},
|
||||
})
|
||||
|
||||
orch_sls = os.path.join(self.base_env, 'main.sls')
|
||||
with salt.utils.fopen(orch_sls, 'w') as fp_:
|
||||
fp_.write(textwrap.dedent('''
|
||||
include:
|
||||
- one
|
||||
- two
|
||||
- three
|
||||
'''))
|
||||
|
||||
orch_sls = os.path.join(self.base_env, 'one.sls')
|
||||
with salt.utils.fopen(orch_sls, 'w') as fp_:
|
||||
fp_.write(textwrap.dedent('''
|
||||
{%- set foo = salt['saltutil.runner']('pillar.show_pillar') %}
|
||||
placeholder_one:
|
||||
test.succeed_without_changes
|
||||
'''))
|
||||
|
||||
orch_sls = os.path.join(self.base_env, 'two.sls')
|
||||
with salt.utils.fopen(orch_sls, 'w') as fp_:
|
||||
fp_.write(textwrap.dedent('''
|
||||
placeholder_two:
|
||||
test.succeed_without_changes
|
||||
'''))
|
||||
|
||||
orch_sls = os.path.join(self.base_env, 'three.sls')
|
||||
with salt.utils.fopen(orch_sls, 'w') as fp_:
|
||||
fp_.write(textwrap.dedent('''
|
||||
placeholder_three:
|
||||
test.succeed_without_changes
|
||||
'''))
|
||||
|
||||
orch_sls = os.path.join(self.base_env, 'main.sls')
|
||||
|
||||
listener = salt.utils.event.get_event(
|
||||
'master',
|
||||
sock_dir=self.master_opts['sock_dir'],
|
||||
transport=self.master_opts['transport'],
|
||||
opts=self.master_opts)
|
||||
|
||||
start_time = time.time()
|
||||
jid = self.run_run_plus(
|
||||
'state.orchestrate',
|
||||
'main',
|
||||
__reload_config=True).get('jid')
|
||||
|
||||
if jid is None:
|
||||
raise salt.exceptions.SaltInvocationError('jid missing from run_run_plus output')
|
||||
|
||||
signal.signal(signal.SIGALRM, self.alarm_handler)
|
||||
signal.alarm(self.timeout)
|
||||
received = False
|
||||
try:
|
||||
while True:
|
||||
event = listener.get_event(full=True)
|
||||
if event is None:
|
||||
continue
|
||||
if event.get('tag', '') == 'salt/run/{0}/ret'.format(jid):
|
||||
received = True
|
||||
# Don't wrap this in a try/except. We want to know if the
|
||||
# data structure is different from what we expect!
|
||||
ret = event['data']['return']['data']['master']
|
||||
for state in ret:
|
||||
data = ret[state]
|
||||
# Each state should be successful
|
||||
self.assertEqual(data['comment'], 'Success!')
|
||||
break
|
||||
finally:
|
||||
self.assertTrue(received)
|
||||
del listener
|
||||
signal.alarm(0)
|
||||
|
|
|
@ -24,9 +24,12 @@ class SSHStateTest(SSHCase):
|
|||
'''
|
||||
testing the state system with salt-ssh
|
||||
'''
|
||||
def _check_dict_ret(self, ret, val, exp_ret):
|
||||
def _check_dict_ret(self, ret, val, exp_ret, equal=True):
|
||||
for key, value in ret.items():
|
||||
self.assertEqual(value[val], exp_ret)
|
||||
if equal:
|
||||
self.assertEqual(value[val], exp_ret)
|
||||
else:
|
||||
self.assertNotEqual(value[val], exp_ret)
|
||||
|
||||
def _check_request(self, empty=False):
|
||||
check = self.run_function('state.check_request', wipe=False)
|
||||
|
@ -50,12 +53,31 @@ class SSHStateTest(SSHCase):
|
|||
'''
|
||||
test state.sls_id with salt-ssh
|
||||
'''
|
||||
# check state.sls_id with test=True
|
||||
ret = self.run_function('state.sls_id', ['ssh-file-test', SSH_SLS,
|
||||
'test=True'])
|
||||
self._check_dict_ret(ret=ret, val='comment',
|
||||
exp_ret='The file /tmp/test is set to be changed')
|
||||
|
||||
# check state.sls_id without test=True
|
||||
ret = self.run_function('state.sls_id', ['ssh-file-test', SSH_SLS])
|
||||
self._check_dict_ret(ret=ret, val='__sls__', exp_ret=SSH_SLS)
|
||||
|
||||
# make sure the other id in the state was not run
|
||||
self._check_dict_ret(ret=ret, val='__id__',
|
||||
exp_ret='second_id', equal=False)
|
||||
|
||||
check_file = self.run_function('file.file_exists', ['/tmp/test'])
|
||||
self.assertTrue(check_file)
|
||||
|
||||
def test_state_sls_wrong_id(self):
|
||||
'''
|
||||
test state.sls_id when id does not exist
|
||||
'''
|
||||
# check state.sls_id with test=True
|
||||
ret = self.run_function('state.sls_id', ['doesnotexist', SSH_SLS])
|
||||
assert 'No matches for ID' in ret
|
||||
|
||||
def test_state_show_sls(self):
|
||||
'''
|
||||
test state.show_sls with salt-ssh
|
||||
|
|
|
@ -25,6 +25,7 @@ from tests.support.case import ModuleCase
|
|||
from tests.support.unit import skipIf
|
||||
from tests.support.paths import FILES, TMP, TMP_STATE_TREE
|
||||
from tests.support.helpers import (
|
||||
destructiveTest,
|
||||
skip_if_not_root,
|
||||
with_system_user_and_group,
|
||||
with_tempfile,
|
||||
|
@ -137,6 +138,10 @@ class FileTest(ModuleCase, SaltReturnAssertsMixin):
|
|||
'''
|
||||
remove files created in previous tests
|
||||
'''
|
||||
user = 'salt'
|
||||
if user in str(self.run_function('user.list_users', [user])):
|
||||
self.run_function('user.delete', [user])
|
||||
|
||||
for path in (FILEPILLAR, FILEPILLARDEF, FILEPILLARGIT):
|
||||
try:
|
||||
os.remove(path)
|
||||
|
@ -656,6 +661,57 @@ class FileTest(ModuleCase, SaltReturnAssertsMixin):
|
|||
self.assertIn(
|
||||
'does not exist', ret['comment'])
|
||||
|
||||
def test_managed_source_hash_indifferent_case(self):
|
||||
'''
|
||||
Test passing a source_hash as an uppercase hash.
|
||||
|
||||
This is a regression test for Issue #38914 and Issue #48230 (test=true use).
|
||||
'''
|
||||
name = os.path.join(TMP, 'source_hash_indifferent_case')
|
||||
state_name = 'file_|-/tmp/salt-tests-tmpdir/source_hash_indifferent_case_|' \
|
||||
'-/tmp/salt-tests-tmpdir/source_hash_indifferent_case_|-managed'
|
||||
local_path = os.path.join(FILES, 'file', 'base', 'hello_world.txt')
|
||||
actual_hash = 'c98c24b677eff44860afea6f493bbaec5bb1c4cbb209c6fc2bbb47f66ff2ad31'
|
||||
uppercase_hash = actual_hash.upper()
|
||||
|
||||
try:
|
||||
# Lay down tmp file to test against
|
||||
self.run_state(
|
||||
'file.managed',
|
||||
name=name,
|
||||
source=local_path,
|
||||
source_hash=actual_hash
|
||||
)
|
||||
|
||||
# Test uppercase source_hash: should return True with no changes
|
||||
ret = self.run_state(
|
||||
'file.managed',
|
||||
name=name,
|
||||
source=local_path,
|
||||
source_hash=uppercase_hash
|
||||
)
|
||||
assert ret[state_name]['result'] is True
|
||||
assert ret[state_name]['pchanges'] == {}
|
||||
assert ret[state_name]['changes'] == {}
|
||||
|
||||
# Test uppercase source_hash using test=true
|
||||
# Should return True with no changes
|
||||
ret = self.run_state(
|
||||
'file.managed',
|
||||
name=name,
|
||||
source=local_path,
|
||||
source_hash=uppercase_hash,
|
||||
test=True
|
||||
)
|
||||
assert ret[state_name]['result'] is True
|
||||
assert ret[state_name]['pchanges'] == {}
|
||||
assert ret[state_name]['changes'] == {}
|
||||
|
||||
finally:
|
||||
# Clean Up File
|
||||
if os.path.exists(name):
|
||||
os.remove(name)
|
||||
|
||||
def test_directory(self):
|
||||
'''
|
||||
file.directory
|
||||
|
@ -2478,6 +2534,27 @@ class FileTest(ModuleCase, SaltReturnAssertsMixin):
|
|||
os.remove(source)
|
||||
os.remove(dest)
|
||||
|
||||
@destructiveTest
|
||||
@with_tempfile
|
||||
def test_file_copy_make_dirs(self, source):
|
||||
'''
|
||||
ensure make_dirs creates correct user perms
|
||||
'''
|
||||
shutil.copyfile(os.path.join(FILES, 'hosts'), source)
|
||||
dest = os.path.join(TMP, 'dir1', 'dir2', 'copied_file.txt')
|
||||
|
||||
user = 'salt'
|
||||
mode = '0644'
|
||||
self.run_function('user.add', [user])
|
||||
ret = self.run_state('file.copy', name=dest, source=source, user=user,
|
||||
makedirs=True, mode=mode)
|
||||
file_checks = [dest, os.path.join(TMP, 'dir1'), os.path.join(TMP, 'dir1', 'dir2')]
|
||||
for check in file_checks:
|
||||
user_check = self.run_function('file.get_user', [check])
|
||||
mode_check = self.run_function('file.get_mode', [check])
|
||||
assert user_check == user
|
||||
assert salt.utils.normalize_mode(mode_check) == mode
|
||||
|
||||
def test_contents_pillar_with_pillar_list(self):
|
||||
'''
|
||||
This tests for any regressions for this issue:
|
||||
|
@ -2488,6 +2565,37 @@ class FileTest(ModuleCase, SaltReturnAssertsMixin):
|
|||
ret = self.run_function('state.sls', mods=state_file)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
|
||||
@skip_if_not_root
|
||||
@skipIf(not HAS_PWD, "pwd not available. Skipping test")
|
||||
@skipIf(not HAS_GRP, "grp not available. Skipping test")
|
||||
@with_system_user_and_group('user12209', 'group12209',
|
||||
on_existing='delete', delete=True)
|
||||
def test_issue_48336_file_managed_mode_setuid(self, user, group):
|
||||
'''
|
||||
Ensure that mode is correct with changing of ownership and group
|
||||
symlinks)
|
||||
'''
|
||||
tempfile = os.path.join(TMP, 'temp_file_issue_48336')
|
||||
|
||||
# Run the state
|
||||
ret = self.run_state(
|
||||
'file.managed', name=tempfile,
|
||||
user=user, group=group, mode='4750',
|
||||
)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
|
||||
# Check that the owner and group are correct, and
|
||||
# the mode is what we expect
|
||||
temp_file_stats = os.stat(tempfile)
|
||||
|
||||
# Normalize the mode
|
||||
temp_file_mode = six.text_type(oct(stat.S_IMODE(temp_file_stats.st_mode)))
|
||||
temp_file_mode = salt.utils.normalize_mode(temp_file_mode)
|
||||
|
||||
self.assertEqual(temp_file_mode, '4750')
|
||||
self.assertEqual(pwd.getpwuid(temp_file_stats.st_uid).pw_name, user)
|
||||
self.assertEqual(grp.getgrgid(temp_file_stats.st_gid).gr_name, group)
|
||||
|
||||
|
||||
class BlockreplaceTest(ModuleCase, SaltReturnAssertsMixin):
|
||||
marker_start = '# start'
|
||||
|
|
|
@ -33,7 +33,7 @@ class NpmStateTest(ModuleCase, SaltReturnAssertsMixin):
|
|||
Basic test to determine if NPM module was successfully installed and
|
||||
removed.
|
||||
'''
|
||||
ret = self.run_state('npm.installed', name='pm2', registry="http://registry.npmjs.org/")
|
||||
ret = self.run_state('npm.installed', name='pm2@2.10.4', registry="http://registry.npmjs.org/")
|
||||
self.assertSaltTrueReturn(ret)
|
||||
ret = self.run_state('npm.removed', name='pm2')
|
||||
self.assertSaltTrueReturn(ret)
|
||||
|
@ -69,7 +69,7 @@ class NpmStateTest(ModuleCase, SaltReturnAssertsMixin):
|
|||
Basic test to determine if NPM module successfully installs multiple
|
||||
packages.
|
||||
'''
|
||||
ret = self.run_state('npm.installed', name=None, pkgs=['pm2', 'grunt'], registry="http://registry.npmjs.org/")
|
||||
ret = self.run_state('npm.installed', name=None, pkgs=['pm2@2.10.4', 'grunt@1.0.2'], registry="http://registry.npmjs.org/")
|
||||
self.assertSaltTrueReturn(ret)
|
||||
|
||||
@skipIf(salt.utils.which('npm') and LooseVersion(cmd.run('npm -v')) >= LooseVersion(MAX_NPM_VERSION),
|
||||
|
|
|
@ -22,6 +22,11 @@ from tests.support.mixins import SaltReturnAssertsMixin
|
|||
# Import salt libs
|
||||
import salt.utils
|
||||
|
||||
try:
|
||||
import grp
|
||||
except ImportError:
|
||||
grp = None
|
||||
|
||||
if salt.utils.is_darwin():
|
||||
USER = 'macuser'
|
||||
GROUP = 'macuser'
|
||||
|
@ -32,13 +37,11 @@ elif salt.utils.is_windows():
|
|||
GROUP = 'winuser'
|
||||
GID = randint(400, 500)
|
||||
NOGROUPGID = randint(400, 500)
|
||||
grp = None
|
||||
else:
|
||||
USER = 'nobody'
|
||||
GROUP = 'nobody'
|
||||
GID = 'nobody'
|
||||
NOGROUPGID = 'nogroup'
|
||||
import grp
|
||||
|
||||
|
||||
@destructiveTest
|
||||
|
|
54
tests/integration/utils/test_thin.py
Normal file
54
tests/integration/utils/test_thin.py
Normal file
|
@ -0,0 +1,54 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import
|
||||
import tarfile
|
||||
import tempfile
|
||||
import subprocess
|
||||
import sys
|
||||
import os
|
||||
|
||||
from tests.support.unit import TestCase
|
||||
|
||||
import salt.utils
|
||||
import salt.utils.thin
|
||||
try:
|
||||
import virtualenv
|
||||
HAS_VENV = True
|
||||
except ImportError:
|
||||
HAS_VENV = False
|
||||
|
||||
|
||||
class TestThinDir(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.tmpdir = tempfile.mkdtemp()
|
||||
|
||||
def tearDown(self):
|
||||
salt.utils.rm_rf(self.tmpdir)
|
||||
|
||||
def test_thin_dir(self):
|
||||
'''
|
||||
Test the thin dir to make sure salt-call can run
|
||||
|
||||
Run salt call via a python in a new virtual environment to ensure
|
||||
salt-call has all dependencies needed.
|
||||
'''
|
||||
venv_dir = os.path.join(self.tmpdir, 'venv')
|
||||
virtualenv.create_environment(venv_dir)
|
||||
salt.utils.thin.gen_thin(self.tmpdir)
|
||||
thin_dir = os.path.join(self.tmpdir, 'thin')
|
||||
thin_archive = os.path.join(thin_dir, 'thin.tgz')
|
||||
tar = tarfile.open(thin_archive)
|
||||
tar.extractall(thin_dir)
|
||||
tar.close()
|
||||
bins = 'bin'
|
||||
if sys.platform == 'win32':
|
||||
bins = 'Scripts'
|
||||
cmd = [
|
||||
os.path.join(venv_dir, bins, 'python'),
|
||||
os.path.join(thin_dir, 'salt-call'),
|
||||
'--version',
|
||||
]
|
||||
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
stdout, stderr = proc.communicate()
|
||||
proc.wait()
|
||||
assert proc.returncode == 0, (stdout, stderr, proc.returncode)
|
|
@ -29,7 +29,7 @@ def iter_installers(content):
|
|||
x = m.groups()[0]
|
||||
if not x.startswith(PREFIX):
|
||||
continue
|
||||
if x.endswith('zip'):
|
||||
if x.endswith(('zip', 'sha256')):
|
||||
continue
|
||||
if installer:
|
||||
if x != installer + '.md5':
|
||||
|
|
|
@ -789,6 +789,7 @@ class CronTestCase(TestCase, LoaderModuleMockMixin):
|
|||
cron.raw_cron(STUB_USER)
|
||||
cron.__salt__['cmd.run_stdout'].assert_called_with("crontab -l",
|
||||
runas=STUB_USER,
|
||||
ignore_retcode=True,
|
||||
rstrip=False,
|
||||
python_shell=False)
|
||||
|
||||
|
@ -803,6 +804,7 @@ class CronTestCase(TestCase, LoaderModuleMockMixin):
|
|||
MagicMock(return_value=False)):
|
||||
cron.raw_cron(STUB_USER)
|
||||
cron.__salt__['cmd.run_stdout'].assert_called_with("crontab -u root -l",
|
||||
ignore_retcode=True,
|
||||
rstrip=False,
|
||||
python_shell=False)
|
||||
|
||||
|
@ -818,6 +820,7 @@ class CronTestCase(TestCase, LoaderModuleMockMixin):
|
|||
cron.raw_cron(STUB_USER)
|
||||
cron.__salt__['cmd.run_stdout'].assert_called_with("crontab -l",
|
||||
runas=STUB_USER,
|
||||
ignore_retcode=True,
|
||||
rstrip=False,
|
||||
python_shell=False)
|
||||
|
||||
|
@ -833,6 +836,7 @@ class CronTestCase(TestCase, LoaderModuleMockMixin):
|
|||
cron.raw_cron(STUB_USER)
|
||||
cron.__salt__['cmd.run_stdout'].assert_called_with("crontab -l",
|
||||
runas=STUB_USER,
|
||||
ignore_retcode=True,
|
||||
rstrip=False,
|
||||
python_shell=False)
|
||||
|
||||
|
@ -848,6 +852,7 @@ class CronTestCase(TestCase, LoaderModuleMockMixin):
|
|||
cron.raw_cron(STUB_USER)
|
||||
cron.__salt__['cmd.run_stdout'].assert_called_with("crontab -l",
|
||||
runas=STUB_USER,
|
||||
ignore_retcode=True,
|
||||
rstrip=False,
|
||||
python_shell=False)
|
||||
|
||||
|
@ -863,6 +868,7 @@ class CronTestCase(TestCase, LoaderModuleMockMixin):
|
|||
cron.raw_cron(STUB_USER)
|
||||
cron.__salt__['cmd.run_stdout'].assert_called_with("crontab -l",
|
||||
runas=STUB_USER,
|
||||
ignore_retcode=True,
|
||||
rstrip=False,
|
||||
python_shell=False)
|
||||
|
||||
|
|
|
@ -136,6 +136,7 @@ class DockerTestCase(TestCase, LoaderModuleMockMixin):
|
|||
with patch.dict(docker_mod.__salt__,
|
||||
{'mine.send': mine_send,
|
||||
'container_resource.run': MagicMock(),
|
||||
'config.get': MagicMock(return_value=True),
|
||||
'cp.cache_file': MagicMock(return_value=False)}):
|
||||
with patch.dict(docker_mod.__utils__,
|
||||
{'docker.get_client_args': client_args_mock}):
|
||||
|
@ -144,6 +145,44 @@ class DockerTestCase(TestCase, LoaderModuleMockMixin):
|
|||
mine_send.assert_called_with('docker.ps', verbose=True, all=True,
|
||||
host=True)
|
||||
|
||||
def test_update_mine(self):
|
||||
'''
|
||||
Test the docker.update_mine config option
|
||||
'''
|
||||
def config_get_disabled(val, default):
|
||||
return {'base_url': docker_mod.NOTSET,
|
||||
'version': docker_mod.NOTSET,
|
||||
'docker.url': docker_mod.NOTSET,
|
||||
'docker.version': docker_mod.NOTSET,
|
||||
'docker.machine': docker_mod.NOTSET,
|
||||
'docker.update_mine': False}[val]
|
||||
|
||||
def config_get_enabled(val, default):
|
||||
return {'base_url': docker_mod.NOTSET,
|
||||
'version': docker_mod.NOTSET,
|
||||
'docker.url': docker_mod.NOTSET,
|
||||
'docker.version': docker_mod.NOTSET,
|
||||
'docker.machine': docker_mod.NOTSET,
|
||||
'docker.update_mine': True}[val]
|
||||
|
||||
mine_mock = Mock()
|
||||
dunder_salt = {
|
||||
'config.get': MagicMock(side_effect=config_get_disabled),
|
||||
'mine.send': mine_mock,
|
||||
}
|
||||
with patch.dict(docker_mod.__salt__, dunder_salt), \
|
||||
patch.dict(docker_mod.__context__, {'docker.client': Mock()}), \
|
||||
patch.object(docker_mod, 'state', MagicMock(return_value='stopped')):
|
||||
docker_mod.stop('foo', timeout=1)
|
||||
mine_mock.assert_not_called()
|
||||
|
||||
with patch.dict(docker_mod.__salt__, dunder_salt), \
|
||||
patch.dict(docker_mod.__context__, {'docker.client': Mock()}), \
|
||||
patch.object(docker_mod, 'state', MagicMock(return_value='stopped')):
|
||||
dunder_salt['config.get'].side_effect = config_get_enabled
|
||||
docker_mod.stop('foo', timeout=1)
|
||||
self.assert_called_once(mine_mock)
|
||||
|
||||
@skipIf(_docker_py_version() < (1, 5, 0),
|
||||
'docker module must be installed to run this test or is too old. >=1.5.0')
|
||||
def test_list_networks(self, *args):
|
||||
|
|
|
@ -117,12 +117,12 @@ class MountTestCase(TestCase, LoaderModuleMockMixin):
|
|||
mock_open(read_data=file_data),
|
||||
create=True) as m:
|
||||
m.return_value.__iter__.return_value = file_data.splitlines()
|
||||
self.assertEqual(mount.fstab(), {'/tmp': {'device': 'swap',
|
||||
'device_fsck': '-',
|
||||
'fstype': 'tmpfs',
|
||||
'mount_at_boot': 'yes',
|
||||
'opts': ['size=2048m'],
|
||||
'pass_fsck': '-'}})
|
||||
self.assertEqual(mount.vfstab(), {'/tmp': {'device': 'swap',
|
||||
'device_fsck': '-',
|
||||
'fstype': 'tmpfs',
|
||||
'mount_at_boot': 'yes',
|
||||
'opts': ['size=2048m'],
|
||||
'pass_fsck': '-'}})
|
||||
|
||||
def test_rm_fstab(self):
|
||||
'''
|
||||
|
|
|
@ -126,65 +126,56 @@ class ProxyTestCase(TestCase, LoaderModuleMockMixin):
|
|||
|
||||
def test_get_http_proxy_windows(self):
|
||||
'''
|
||||
Test to make sure that we correctly get the current proxy info
|
||||
on Windows
|
||||
Test to make sure that we correctly get the current proxy info on
|
||||
Windows
|
||||
'''
|
||||
result = {'vdata': 'http=192.168.0.1:3128;https=192.168.0.2:3128;ftp=192.168.0.3:3128'}
|
||||
mock = MagicMock(return_value=result)
|
||||
expected = {'server': '192.168.0.1',
|
||||
'port': '3128'}
|
||||
with patch.dict(proxy.__grains__, {'os': 'Windows'}):
|
||||
result = {
|
||||
'vdata': 'http=192.168.0.1:3128;https=192.168.0.2:3128;ftp=192.168.0.3:3128'
|
||||
}
|
||||
mock = MagicMock(return_value=result)
|
||||
expected = {
|
||||
'server': '192.168.0.1',
|
||||
'port': '3128'
|
||||
}
|
||||
with patch.dict(proxy.__salt__, {'reg.read_value': mock}):
|
||||
out = proxy.get_http_proxy()
|
||||
mock.assert_called_once_with('HKEY_CURRENT_USER',
|
||||
'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings',
|
||||
'ProxyServer')
|
||||
mock.assert_called_once_with(
|
||||
hive='HKEY_CURRENT_USER',
|
||||
key='SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings',
|
||||
vname='ProxyServer')
|
||||
self.assertEqual(expected, out)
|
||||
|
||||
def test_get_https_proxy_windows(self):
|
||||
'''
|
||||
Test to make sure that we correctly get the current proxy info
|
||||
on Windows
|
||||
Test to make sure that we correctly get the current proxy info on
|
||||
Windows
|
||||
'''
|
||||
result = {'vdata': 'http=192.168.0.1:3128;https=192.168.0.2:3128;ftp=192.168.0.3:3128'}
|
||||
mock = MagicMock(return_value=result)
|
||||
expected = {'server': '192.168.0.2',
|
||||
'port': '3128'}
|
||||
with patch.dict(proxy.__grains__, {'os': 'Windows'}):
|
||||
result = {
|
||||
'vdata': 'http=192.168.0.1:3128;https=192.168.0.2:3128;ftp=192.168.0.3:3128'
|
||||
}
|
||||
mock = MagicMock(return_value=result)
|
||||
expected = {
|
||||
'server': '192.168.0.2',
|
||||
'port': '3128'
|
||||
}
|
||||
with patch.dict(proxy.__salt__, {'reg.read_value': mock}):
|
||||
out = proxy.get_https_proxy()
|
||||
mock.assert_called_once_with('HKEY_CURRENT_USER',
|
||||
'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings',
|
||||
'ProxyServer')
|
||||
mock.assert_called_once_with(
|
||||
hive='HKEY_CURRENT_USER',
|
||||
key='SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings',
|
||||
vname='ProxyServer')
|
||||
self.assertEqual(expected, out)
|
||||
|
||||
def test_get_ftp_proxy_windows(self):
|
||||
'''
|
||||
Test to make sure that we correctly get the current proxy info
|
||||
on Windows
|
||||
Test to make sure that we correctly get the current proxy info on
|
||||
Windows
|
||||
'''
|
||||
result = {'vdata': 'http=192.168.0.1:3128;https=192.168.0.2:3128;ftp=192.168.0.3:3128'}
|
||||
mock = MagicMock(return_value=result)
|
||||
expected = {'server': '192.168.0.3',
|
||||
'port': '3128'}
|
||||
with patch.dict(proxy.__grains__, {'os': 'Windows'}):
|
||||
result = {
|
||||
'vdata': 'http=192.168.0.1:3128;https=192.168.0.2:3128;ftp=192.168.0.3:3128'
|
||||
}
|
||||
mock = MagicMock(return_value=result)
|
||||
expected = {
|
||||
'server': '192.168.0.3',
|
||||
'port': '3128'
|
||||
}
|
||||
with patch.dict(proxy.__salt__, {'reg.read_value': mock}):
|
||||
out = proxy.get_ftp_proxy()
|
||||
mock.assert_called_once_with('HKEY_CURRENT_USER',
|
||||
'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings',
|
||||
'ProxyServer')
|
||||
mock.assert_called_once_with(
|
||||
hive='HKEY_CURRENT_USER',
|
||||
key='SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings',
|
||||
vname='ProxyServer')
|
||||
self.assertEqual(expected, out)
|
||||
|
||||
def test_get_all_proxies_macos_fails(self):
|
||||
|
@ -196,201 +187,179 @@ class ProxyTestCase(TestCase, LoaderModuleMockMixin):
|
|||
|
||||
def test_get_all_proxies_windows(self):
|
||||
'''
|
||||
Test to make sure that we correctly get the current proxy info
|
||||
on Windows
|
||||
Test to make sure that we correctly get the current proxy info on
|
||||
Windows
|
||||
'''
|
||||
results = [{'vdata': 'http=192.168.0.1:3128;https=192.168.0.2:3128;ftp=192.168.0.3:3128'},
|
||||
{'vdata': 1}]
|
||||
mock = MagicMock(side_effect=results)
|
||||
expected = {'enabled': True,
|
||||
'http': {'server': '192.168.0.1',
|
||||
'port': '3128'},
|
||||
'https': {'server': '192.168.0.2',
|
||||
'port': '3128'},
|
||||
'ftp': {'server': '192.168.0.3',
|
||||
'port': '3128'}}
|
||||
calls = [
|
||||
call(hive='HKEY_CURRENT_USER',
|
||||
key='SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings',
|
||||
vname='ProxyServer'),
|
||||
call(hive='HKEY_CURRENT_USER',
|
||||
key='SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings',
|
||||
vname='ProxyEnable')]
|
||||
with patch.dict(proxy.__grains__, {'os': 'Windows'}):
|
||||
results = [
|
||||
{
|
||||
'vdata': 'http=192.168.0.1:3128;https=192.168.0.2:3128;ftp=192.168.0.3:3128'
|
||||
},
|
||||
{
|
||||
'vdata': 1
|
||||
}
|
||||
]
|
||||
mock = MagicMock(side_effect=results)
|
||||
|
||||
expected = {
|
||||
'enabled': True,
|
||||
'http': {
|
||||
'server': '192.168.0.1',
|
||||
'port': '3128'
|
||||
},
|
||||
'https': {
|
||||
'server': '192.168.0.2',
|
||||
'port': '3128'
|
||||
},
|
||||
'ftp': {
|
||||
'server': '192.168.0.3',
|
||||
'port': '3128'
|
||||
}
|
||||
}
|
||||
with patch.dict(proxy.__salt__, {'reg.read_value': mock}):
|
||||
out = proxy.get_proxy_win()
|
||||
calls = [
|
||||
call('HKEY_CURRENT_USER',
|
||||
'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings',
|
||||
'ProxyServer'),
|
||||
call('HKEY_CURRENT_USER',
|
||||
'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings',
|
||||
'ProxyEnable'),
|
||||
]
|
||||
|
||||
mock.assert_has_calls(calls)
|
||||
self.assertEqual(expected, out)
|
||||
|
||||
def test_set_http_proxy_windows(self):
|
||||
'''
|
||||
Test to make sure that we correctly set the proxy info
|
||||
on Windows
|
||||
Test to make sure that we correctly set the proxy info on Windows
|
||||
'''
|
||||
calls = [
|
||||
call(hive='HKEY_CURRENT_USER',
|
||||
key='SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings',
|
||||
vname='ProxyServer',
|
||||
vdata='http=192.168.0.1:3128;'),
|
||||
call(hive='HKEY_CURRENT_USER',
|
||||
key='SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings',
|
||||
vname='ProxyEnable',
|
||||
vdata=1,
|
||||
vtype='REG_DWORD'),
|
||||
call(hive='HKEY_CURRENT_USER',
|
||||
key='SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings',
|
||||
vname='ProxyOverride',
|
||||
vdata='<local>;.moo.com;.salt.com')]
|
||||
mock_reg = MagicMock()
|
||||
mock_cmd = MagicMock()
|
||||
with patch.dict(proxy.__grains__, {'os': 'Windows'}):
|
||||
mock_reg = MagicMock()
|
||||
mock_cmd = MagicMock()
|
||||
|
||||
with patch.dict(proxy.__salt__, {'reg.set_value': mock_reg, 'cmd.run': mock_cmd}):
|
||||
out = proxy.set_http_proxy('192.168.0.1', 3128, bypass_hosts=['.moo.com', '.salt.com'])
|
||||
|
||||
calls = [
|
||||
call('HKEY_CURRENT_USER',
|
||||
'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings',
|
||||
'ProxyServer',
|
||||
'http=192.168.0.1:3128;'),
|
||||
call('HKEY_CURRENT_USER',
|
||||
'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings',
|
||||
'ProxyEnable',
|
||||
1,
|
||||
vtype='REG_DWORD'),
|
||||
call('HKEY_CURRENT_USER',
|
||||
'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings',
|
||||
'ProxyOverride',
|
||||
'<local>;.moo.com;.salt.com')
|
||||
]
|
||||
with patch.dict(proxy.__salt__, {'reg.set_value': mock_reg,
|
||||
'cmd.run': mock_cmd}):
|
||||
out = proxy.set_http_proxy(server='192.168.0.1',
|
||||
port=3128,
|
||||
bypass_hosts=['.moo.com', '.salt.com'])
|
||||
mock_reg.assert_has_calls(calls)
|
||||
mock_cmd.assert_called_once_with('netsh winhttp import proxy source=ie')
|
||||
self.assertTrue(out)
|
||||
|
||||
def test_set_https_proxy_windows(self):
|
||||
'''
|
||||
Test to make sure that we correctly set the proxy info
|
||||
on Windows
|
||||
Test to make sure that we correctly set the proxy info on Windows
|
||||
'''
|
||||
calls = [
|
||||
call(hive='HKEY_CURRENT_USER',
|
||||
key='SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings',
|
||||
vname='ProxyServer',
|
||||
vdata='https=192.168.0.1:3128;'),
|
||||
call(hive='HKEY_CURRENT_USER',
|
||||
key='SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings',
|
||||
vname='ProxyEnable',
|
||||
vdata=1,
|
||||
vtype='REG_DWORD'),
|
||||
call(hive='HKEY_CURRENT_USER',
|
||||
key='SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings',
|
||||
vname='ProxyOverride',
|
||||
vdata='<local>;.moo.com;.salt.com')]
|
||||
mock_reg = MagicMock()
|
||||
mock_cmd = MagicMock()
|
||||
with patch.dict(proxy.__grains__, {'os': 'Windows'}):
|
||||
mock_reg = MagicMock()
|
||||
mock_cmd = MagicMock()
|
||||
|
||||
with patch.dict(proxy.__salt__, {'reg.set_value': mock_reg, 'cmd.run': mock_cmd}):
|
||||
out = proxy.set_https_proxy('192.168.0.1', 3128, bypass_hosts=['.moo.com', '.salt.com'])
|
||||
|
||||
calls = [
|
||||
call('HKEY_CURRENT_USER',
|
||||
'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings',
|
||||
'ProxyServer',
|
||||
'https=192.168.0.1:3128;'),
|
||||
call('HKEY_CURRENT_USER',
|
||||
'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings',
|
||||
'ProxyEnable',
|
||||
1,
|
||||
vtype='REG_DWORD'),
|
||||
call('HKEY_CURRENT_USER',
|
||||
'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings',
|
||||
'ProxyOverride',
|
||||
'<local>;.moo.com;.salt.com')
|
||||
]
|
||||
with patch.dict(proxy.__salt__, {'reg.set_value': mock_reg,
|
||||
'cmd.run': mock_cmd}):
|
||||
out = proxy.set_https_proxy(server='192.168.0.1',
|
||||
port=3128,
|
||||
bypass_hosts=['.moo.com', '.salt.com'])
|
||||
mock_reg.assert_has_calls(calls)
|
||||
mock_cmd.assert_called_once_with('netsh winhttp import proxy source=ie')
|
||||
self.assertTrue(out)
|
||||
|
||||
def test_set_ftp_proxy_windows(self):
|
||||
'''
|
||||
Test to make sure that we correctly set the proxy info
|
||||
on Windows
|
||||
Test to make sure that we correctly set the proxy info on Windows
|
||||
'''
|
||||
calls = [
|
||||
call(hive='HKEY_CURRENT_USER',
|
||||
key='SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings',
|
||||
vname='ProxyServer',
|
||||
vdata='ftp=192.168.0.1:3128;'),
|
||||
call(hive='HKEY_CURRENT_USER',
|
||||
key='SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings',
|
||||
vname='ProxyEnable',
|
||||
vdata=1,
|
||||
vtype='REG_DWORD'),
|
||||
call(hive='HKEY_CURRENT_USER',
|
||||
key='SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings',
|
||||
vname='ProxyOverride',
|
||||
vdata='<local>;.moo.com;.salt.com')]
|
||||
mock_reg = MagicMock()
|
||||
mock_cmd = MagicMock()
|
||||
with patch.dict(proxy.__grains__, {'os': 'Windows'}):
|
||||
mock_reg = MagicMock()
|
||||
mock_cmd = MagicMock()
|
||||
|
||||
with patch.dict(proxy.__salt__, {'reg.set_value': mock_reg, 'cmd.run': mock_cmd}):
|
||||
out = proxy.set_ftp_proxy('192.168.0.1', 3128, bypass_hosts=['.moo.com', '.salt.com'])
|
||||
|
||||
calls = [
|
||||
call('HKEY_CURRENT_USER',
|
||||
'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings',
|
||||
'ProxyServer',
|
||||
'ftp=192.168.0.1:3128;'),
|
||||
call('HKEY_CURRENT_USER',
|
||||
'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings',
|
||||
'ProxyEnable',
|
||||
1,
|
||||
vtype='REG_DWORD'),
|
||||
call('HKEY_CURRENT_USER',
|
||||
'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings',
|
||||
'ProxyOverride',
|
||||
'<local>;.moo.com;.salt.com')
|
||||
]
|
||||
with patch.dict(proxy.__salt__, {'reg.set_value': mock_reg,
|
||||
'cmd.run': mock_cmd}):
|
||||
out = proxy.set_ftp_proxy(server='192.168.0.1',
|
||||
port=3128,
|
||||
bypass_hosts=['.moo.com', '.salt.com'])
|
||||
mock_reg.assert_has_calls(calls)
|
||||
mock_cmd.assert_called_once_with('netsh winhttp import proxy source=ie')
|
||||
self.assertTrue(out)
|
||||
|
||||
def test_set_proxy_windows(self):
|
||||
'''
|
||||
Test to make sure that we correctly set the proxy info
|
||||
on Windows
|
||||
Test to make sure that we correctly set the proxy info on Windows
|
||||
'''
|
||||
calls = [
|
||||
call(hive='HKEY_CURRENT_USER',
|
||||
key='SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings',
|
||||
vname='ProxyServer',
|
||||
vdata='http=192.168.0.1:3128;https=192.168.0.1:3128;ftp=192.168.0.1:3128;'),
|
||||
call(hive='HKEY_CURRENT_USER',
|
||||
key='SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings',
|
||||
vname='ProxyEnable',
|
||||
vdata=1,
|
||||
vtype='REG_DWORD'),
|
||||
call(hive='HKEY_CURRENT_USER',
|
||||
key='SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings',
|
||||
vname='ProxyOverride',
|
||||
vdata='<local>;.moo.com;.salt.com')]
|
||||
mock_reg = MagicMock()
|
||||
mock_cmd = MagicMock()
|
||||
with patch.dict(proxy.__grains__, {'os': 'Windows'}):
|
||||
mock_reg = MagicMock()
|
||||
mock_cmd = MagicMock()
|
||||
|
||||
with patch.dict(proxy.__salt__, {'reg.set_value': mock_reg, 'cmd.run': mock_cmd}):
|
||||
out = proxy.set_proxy_win('192.168.0.1', 3128, bypass_hosts=['.moo.com', '.salt.com'])
|
||||
|
||||
calls = [
|
||||
call('HKEY_CURRENT_USER',
|
||||
'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings',
|
||||
'ProxyServer',
|
||||
'http=192.168.0.1:3128;https=192.168.0.1:3128;ftp=192.168.0.1:3128;'),
|
||||
call('HKEY_CURRENT_USER',
|
||||
'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings',
|
||||
'ProxyEnable',
|
||||
1,
|
||||
vtype='REG_DWORD'),
|
||||
call('HKEY_CURRENT_USER',
|
||||
'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings',
|
||||
'ProxyOverride',
|
||||
'<local>;.moo.com;.salt.com')
|
||||
]
|
||||
with patch.dict(proxy.__salt__, {'reg.set_value': mock_reg,
|
||||
'cmd.run': mock_cmd}):
|
||||
out = proxy.set_proxy_win(server='192.168.0.1',
|
||||
port=3128,
|
||||
bypass_hosts=['.moo.com', '.salt.com'])
|
||||
mock_reg.assert_has_calls(calls)
|
||||
mock_cmd.assert_called_once_with('netsh winhttp import proxy source=ie')
|
||||
self.assertTrue(out)
|
||||
|
||||
def test_set_proxy_windows_no_ftp(self):
|
||||
'''
|
||||
Test to make sure that we correctly set the proxy info
|
||||
on Windows
|
||||
Test to make sure that we correctly set the proxy info on Windows
|
||||
'''
|
||||
calls = [
|
||||
call(hive='HKEY_CURRENT_USER',
|
||||
key='SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings',
|
||||
vname='ProxyServer',
|
||||
vdata='http=192.168.0.1:3128;https=192.168.0.1:3128;'),
|
||||
call(hive='HKEY_CURRENT_USER',
|
||||
key='SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings',
|
||||
vname='ProxyEnable',
|
||||
vdata=1,
|
||||
vtype='REG_DWORD'),
|
||||
call(hive='HKEY_CURRENT_USER',
|
||||
key='SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings',
|
||||
vname='ProxyOverride',
|
||||
vdata='<local>;.moo.com;.salt.com')]
|
||||
mock_reg = MagicMock()
|
||||
mock_cmd = MagicMock()
|
||||
with patch.dict(proxy.__grains__, {'os': 'Windows'}):
|
||||
mock_reg = MagicMock()
|
||||
mock_cmd = MagicMock()
|
||||
|
||||
with patch.dict(proxy.__salt__, {'reg.set_value': mock_reg, 'cmd.run': mock_cmd}):
|
||||
out = proxy.set_proxy_win('192.168.0.1', 3128, types=['http', 'https'],
|
||||
with patch.dict(proxy.__salt__, {'reg.set_value': mock_reg,
|
||||
'cmd.run': mock_cmd}):
|
||||
out = proxy.set_proxy_win(server='192.168.0.1',
|
||||
port=3128,
|
||||
types=['http', 'https'],
|
||||
bypass_hosts=['.moo.com', '.salt.com'])
|
||||
|
||||
calls = [
|
||||
call('HKEY_CURRENT_USER',
|
||||
'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings',
|
||||
'ProxyServer',
|
||||
'http=192.168.0.1:3128;https=192.168.0.1:3128;'),
|
||||
call('HKEY_CURRENT_USER',
|
||||
'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings',
|
||||
'ProxyEnable',
|
||||
1,
|
||||
vtype='REG_DWORD'),
|
||||
call('HKEY_CURRENT_USER',
|
||||
'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings',
|
||||
'ProxyOverride',
|
||||
'<local>;.moo.com;.salt.com')
|
||||
]
|
||||
mock_reg.assert_has_calls(calls)
|
||||
mock_cmd.assert_called_once_with('netsh winhttp import proxy source=ie')
|
||||
self.assertTrue(out)
|
||||
|
|
|
@ -11,6 +11,7 @@ import os
|
|||
from tests.support.mixins import LoaderModuleMockMixin
|
||||
from tests.support.unit import TestCase, skipIf
|
||||
from tests.support.mock import (
|
||||
Mock,
|
||||
MagicMock,
|
||||
patch,
|
||||
mock_open,
|
||||
|
@ -357,6 +358,9 @@ class StateTestCase(TestCase, LoaderModuleMockMixin):
|
|||
'environment': None,
|
||||
'__cli': 'salt',
|
||||
},
|
||||
'__salt__': {
|
||||
'config.option': MagicMock(return_value=''),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -752,28 +756,25 @@ class StateTestCase(TestCase, LoaderModuleMockMixin):
|
|||
"whitelist=sls1.sls",
|
||||
pillar="A")
|
||||
|
||||
mock = MagicMock(return_value=True)
|
||||
with patch.dict(state.__salt__,
|
||||
{'config.option': mock}):
|
||||
mock = MagicMock(return_value="A")
|
||||
mock = MagicMock(return_value="A")
|
||||
with patch.object(state, '_filter_running',
|
||||
mock):
|
||||
mock = MagicMock(return_value=True)
|
||||
with patch.object(state, '_filter_running',
|
||||
mock):
|
||||
mock = MagicMock(return_value=True)
|
||||
with patch.object(state, '_filter_running',
|
||||
with patch.object(salt.payload, 'Serial',
|
||||
mock):
|
||||
mock = MagicMock(return_value=True)
|
||||
with patch.object(salt.payload, 'Serial',
|
||||
mock):
|
||||
with patch.object(os.path,
|
||||
'join', mock):
|
||||
with patch.object(
|
||||
state,
|
||||
'_set'
|
||||
'_retcode',
|
||||
mock):
|
||||
self.assertTrue(state.
|
||||
highstate
|
||||
(arg))
|
||||
with patch.object(os.path,
|
||||
'join', mock):
|
||||
with patch.object(
|
||||
state,
|
||||
'_set'
|
||||
'_retcode',
|
||||
mock):
|
||||
self.assertTrue(state.
|
||||
highstate
|
||||
(arg))
|
||||
|
||||
def test_clear_request(self):
|
||||
'''
|
||||
|
@ -914,17 +915,11 @@ class StateTestCase(TestCase, LoaderModuleMockMixin):
|
|||
|
||||
MockState.HighState.flag = False
|
||||
mock = MagicMock(return_value=True)
|
||||
with patch.dict(state.__salt__,
|
||||
{'config.option':
|
||||
mock}):
|
||||
mock = MagicMock(return_value=
|
||||
True)
|
||||
with patch.object(
|
||||
state,
|
||||
'_filter_'
|
||||
'running',
|
||||
mock):
|
||||
self.sub_test_sls()
|
||||
with patch.object(state,
|
||||
'_filter_'
|
||||
'running',
|
||||
mock):
|
||||
self.sub_test_sls()
|
||||
|
||||
def sub_test_sls(self):
|
||||
'''
|
||||
|
@ -947,6 +942,75 @@ class StateTestCase(TestCase, LoaderModuleMockMixin):
|
|||
None,
|
||||
True))
|
||||
|
||||
def test_sls_sync(self):
|
||||
'''
|
||||
Test test.sls with the sync argument
|
||||
|
||||
We're only mocking the sync functions we expect to sync. If any other
|
||||
sync functions are run then they will raise a KeyError, which we want
|
||||
as it will tell us that we are syncing things we shouldn't.
|
||||
'''
|
||||
mock_empty_list = MagicMock(return_value=[])
|
||||
with patch.object(state, 'running', mock_empty_list), \
|
||||
patch.object(state, '_disabled', mock_empty_list), \
|
||||
patch.object(state, '_get_pillar_errors', mock_empty_list):
|
||||
|
||||
sync_mocks = {
|
||||
'saltutil.sync_modules': Mock(),
|
||||
'saltutil.sync_states': Mock(),
|
||||
}
|
||||
with patch.dict(state.__salt__, sync_mocks):
|
||||
state.sls('foo', sync_mods='modules,states')
|
||||
|
||||
for key in sync_mocks:
|
||||
call_count = sync_mocks[key].call_count
|
||||
expected = 1
|
||||
assert call_count == expected, \
|
||||
'{0} called {1} time(s) (expected: {2})'.format(
|
||||
key, call_count, expected
|
||||
)
|
||||
|
||||
# Test syncing all
|
||||
sync_mocks = {'saltutil.sync_all': Mock()}
|
||||
with patch.dict(state.__salt__, sync_mocks):
|
||||
state.sls('foo', sync_mods='all')
|
||||
|
||||
for key in sync_mocks:
|
||||
call_count = sync_mocks[key].call_count
|
||||
expected = 1
|
||||
assert call_count == expected, \
|
||||
'{0} called {1} time(s) (expected: {2})'.format(
|
||||
key, call_count, expected
|
||||
)
|
||||
|
||||
# sync_mods=True should be interpreted as sync_mods=all
|
||||
sync_mocks = {'saltutil.sync_all': Mock()}
|
||||
with patch.dict(state.__salt__, sync_mocks):
|
||||
state.sls('foo', sync_mods=True)
|
||||
|
||||
for key in sync_mocks:
|
||||
call_count = sync_mocks[key].call_count
|
||||
expected = 1
|
||||
assert call_count == expected, \
|
||||
'{0} called {1} time(s) (expected: {2})'.format(
|
||||
key, call_count, expected
|
||||
)
|
||||
|
||||
# Test syncing all when "all" is passed along with module types.
|
||||
# This tests that we *only* run a sync_all and avoid unnecessary
|
||||
# extra syncing.
|
||||
sync_mocks = {'saltutil.sync_all': Mock()}
|
||||
with patch.dict(state.__salt__, sync_mocks):
|
||||
state.sls('foo', sync_mods='modules,all')
|
||||
|
||||
for key in sync_mocks:
|
||||
call_count = sync_mocks[key].call_count
|
||||
expected = 1
|
||||
assert call_count == expected, \
|
||||
'{0} called {1} time(s) (expected: {2})'.format(
|
||||
key, call_count, expected
|
||||
)
|
||||
|
||||
def test_pkg(self):
|
||||
'''
|
||||
Test to execute a packaged state run
|
||||
|
|
|
@ -361,6 +361,7 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
|
|||
ZyppCallMock(return_value=get_test_data('zypper-available.txt'))), \
|
||||
patch('salt.modules.zypper.refresh_db', MagicMock(return_value=True)):
|
||||
self.assertEqual(zypper.latest_version('vim'), '7.4.326-2.62')
|
||||
self.assertDictEqual(zypper.latest_version('vim', 'fakepkg'), {'vim': '7.4.326-2.62', 'fakepkg': ''})
|
||||
|
||||
def test_upgrade_success(self):
|
||||
'''
|
||||
|
|
|
@ -39,6 +39,7 @@ import salt.serializers.yaml as yamlserializer
|
|||
import salt.serializers.json as jsonserializer
|
||||
import salt.serializers.python as pythonserializer
|
||||
from salt.exceptions import CommandExecutionError
|
||||
import salt.utils.win_functions
|
||||
|
||||
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
|
@ -60,6 +61,15 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
|
|||
}
|
||||
}
|
||||
|
||||
def tearDown(self):
|
||||
remove_dir = '/tmp/etc'
|
||||
if salt.utils.is_windows():
|
||||
remove_dir = 'c:\\tmp\\etc'
|
||||
try:
|
||||
salt.utils.rm_rf(remove_dir)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
def test_serialize(self):
|
||||
def returner(contents, *args, **kwargs):
|
||||
returner.returned = contents
|
||||
|
@ -145,10 +155,15 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
|
|||
else:
|
||||
group = 'saltstack'
|
||||
|
||||
ret = {'name': name,
|
||||
'result': False,
|
||||
'comment': '',
|
||||
'changes': {}}
|
||||
def return_val(kwargs):
|
||||
val = {
|
||||
'name': name,
|
||||
'result': False,
|
||||
'comment': '',
|
||||
'changes': {},
|
||||
}
|
||||
val.update(kwargs)
|
||||
return val
|
||||
|
||||
mock_t = MagicMock(return_value=True)
|
||||
mock_f = MagicMock(return_value=False)
|
||||
|
@ -162,7 +177,7 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
|
|||
|
||||
with patch.dict(filestate.__salt__, {'config.manage_mode': mock_t}):
|
||||
comt = ('Must provide name to file.symlink')
|
||||
ret.update({'comment': comt, 'name': ''})
|
||||
ret = return_val({'comment': comt, 'name': ''})
|
||||
self.assertDictEqual(filestate.symlink('', target), ret)
|
||||
|
||||
with patch.dict(filestate.__salt__, {'config.manage_mode': mock_t,
|
||||
|
@ -170,8 +185,12 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
|
|||
'file.group_to_gid': mock_empty,
|
||||
'user.info': mock_empty,
|
||||
'user.current': mock_user}):
|
||||
comt = ('User {0} does not exist. Group {1} does not exist.'.format(user, group))
|
||||
ret.update({'comment': comt, 'name': name})
|
||||
if salt.utils.is_windows():
|
||||
comt = ('User {0} does not exist'.format(user))
|
||||
ret = return_val({'comment': comt, 'name': name})
|
||||
else:
|
||||
comt = ('User {0} does not exist. Group {1} does not exist.'.format(user, group))
|
||||
ret = return_val({'comment': comt, 'name': name})
|
||||
self.assertDictEqual(filestate.symlink(name, target, user=user,
|
||||
group=group), ret)
|
||||
|
||||
|
@ -183,11 +202,22 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
|
|||
'user.current': mock_user}):
|
||||
with patch.dict(filestate.__opts__, {'test': True}):
|
||||
with patch.object(os.path, 'exists', mock_f):
|
||||
comt = ('Symlink {0} to {1}'
|
||||
' is set for creation').format(name, target)
|
||||
ret.update({'comment': comt,
|
||||
'result': None,
|
||||
'pchanges': {'new': name}})
|
||||
if salt.utils.is_windows():
|
||||
comt = ('User {0} does not exist'.format(user))
|
||||
ret = return_val(
|
||||
{
|
||||
'comment': comt,
|
||||
'result': False,
|
||||
'name': name,
|
||||
'changes': {}
|
||||
}
|
||||
)
|
||||
else:
|
||||
comt = ('Symlink {0} to {1}'
|
||||
' is set for creation').format(name, target)
|
||||
ret = return_val({'comment': comt,
|
||||
'result': None,
|
||||
'pchanges': {'new': name}})
|
||||
self.assertDictEqual(filestate.symlink(name, target,
|
||||
user=user,
|
||||
group=group), ret)
|
||||
|
@ -201,10 +231,21 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
|
|||
with patch.dict(filestate.__opts__, {'test': False}):
|
||||
with patch.object(os.path, 'isdir', mock_f):
|
||||
with patch.object(os.path, 'exists', mock_f):
|
||||
comt = ('Directory {0} for symlink is not present').format(test_dir)
|
||||
ret.update({'comment': comt,
|
||||
if salt.utils.is_windows():
|
||||
comt = 'User {0} does not exist'.format(user)
|
||||
ret = return_val(
|
||||
{
|
||||
'comment': comt,
|
||||
'result': False,
|
||||
'pchanges': {'new': name}})
|
||||
'name': name,
|
||||
'changes': {},
|
||||
}
|
||||
)
|
||||
else:
|
||||
comt = ('Directory {0} for symlink is not present').format(test_dir)
|
||||
ret = return_val({'comment': comt,
|
||||
'result': False,
|
||||
'pchanges': {'new': name}})
|
||||
self.assertDictEqual(filestate.symlink(name, target,
|
||||
user=user,
|
||||
group=group), ret)
|
||||
|
@ -219,15 +260,19 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
|
|||
with patch.dict(filestate.__opts__, {'test': False}):
|
||||
with patch.object(os.path, 'isdir', mock_t):
|
||||
with patch.object(salt.states.file, '_check_symlink_ownership', mock_t):
|
||||
comt = ('Symlink {0} is present and owned by '
|
||||
'{1}:{2}'.format(name, user, group))
|
||||
ret.update({'comment': comt,
|
||||
'result': True,
|
||||
'pchanges': {}})
|
||||
self.assertDictEqual(filestate.symlink(name, target,
|
||||
user=user,
|
||||
group=group), ret)
|
||||
|
||||
with patch('salt.utils.win_functions.get_sid_from_name', return_value='test-sid'):
|
||||
if salt.utils.is_windows():
|
||||
comt = ('Symlink {0} is present and owned by '
|
||||
'{1}'.format(name, user))
|
||||
else:
|
||||
comt = ('Symlink {0} is present and owned by '
|
||||
'{1}:{2}'.format(name, user, group))
|
||||
ret = return_val({'comment': comt,
|
||||
'result': True,
|
||||
'pchanges': {}})
|
||||
self.assertDictEqual(filestate.symlink(name, target,
|
||||
user=user,
|
||||
group=group), ret)
|
||||
with patch.dict(filestate.__salt__, {'config.manage_mode': mock_t,
|
||||
'file.user_to_uid': mock_uid,
|
||||
'file.group_to_gid': mock_gid,
|
||||
|
@ -239,15 +284,16 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
|
|||
with patch.object(os.path, 'isdir', mock_t):
|
||||
with patch.object(os.path, 'exists', mock_f):
|
||||
with patch.object(os.path, 'lexists', mock_t):
|
||||
comt = ('File exists where the backup target SALT'
|
||||
' should go')
|
||||
ret.update({'comment': comt,
|
||||
'result': False,
|
||||
'pchanges': {'new': name}})
|
||||
self.assertDictEqual(filestate.symlink
|
||||
(name, target, user=user,
|
||||
group=group, backupname='SALT'),
|
||||
ret)
|
||||
with patch('salt.utils.win_functions.get_sid_from_name', return_value='test-sid'):
|
||||
comt = ('File exists where the backup target SALT'
|
||||
' should go')
|
||||
ret = return_val({'comment': comt,
|
||||
'result': False,
|
||||
'pchanges': {'new': name}})
|
||||
self.assertDictEqual(filestate.symlink
|
||||
(name, target, user=user,
|
||||
group=group, backupname='SALT'),
|
||||
ret)
|
||||
|
||||
with patch.dict(filestate.__salt__, {'config.manage_mode': mock_t,
|
||||
'file.user_to_uid': mock_uid,
|
||||
|
@ -260,14 +306,15 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
|
|||
with patch.object(os.path, 'isdir', mock_t):
|
||||
with patch.object(os.path, 'exists', mock_f):
|
||||
with patch.object(os.path, 'isfile', mock_t):
|
||||
comt = ('File exists where the symlink {0} should be'
|
||||
.format(name))
|
||||
ret.update({'comment': comt,
|
||||
'pchanges': {'new': name},
|
||||
'result': False})
|
||||
self.assertDictEqual(filestate.symlink
|
||||
(name, target, user=user,
|
||||
group=group), ret)
|
||||
with patch('salt.utils.win_functions.get_sid_from_name', return_value='test-sid'):
|
||||
comt = ('File exists where the symlink {0} should be'
|
||||
.format(name))
|
||||
ret = return_val({'comment': comt,
|
||||
'pchanges': {'new': name},
|
||||
'result': False})
|
||||
self.assertDictEqual(filestate.symlink
|
||||
(name, target, user=user,
|
||||
group=group), ret)
|
||||
|
||||
with patch.dict(filestate.__salt__, {'config.manage_mode': mock_t,
|
||||
'file.user_to_uid': mock_uid,
|
||||
|
@ -281,11 +328,12 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
|
|||
with patch.object(os.path, 'isdir', MagicMock(side_effect=[True, False])):
|
||||
with patch.object(os.path, 'isfile', mock_t):
|
||||
with patch.object(os.path, 'exists', mock_f):
|
||||
comt = ('File exists where the symlink {0} should be'.format(name))
|
||||
ret.update({'comment': comt, 'result': False})
|
||||
self.assertDictEqual(filestate.symlink
|
||||
(name, target, user=user,
|
||||
group=group), ret)
|
||||
with patch('salt.utils.win_functions.get_sid_from_name', return_value='test-sid'):
|
||||
comt = ('File exists where the symlink {0} should be'.format(name))
|
||||
ret = return_val({'comment': comt, 'result': False, 'pchanges': {'new': '/tmp/testfile.txt'}})
|
||||
self.assertDictEqual(filestate.symlink
|
||||
(name, target, user=user,
|
||||
group=group), ret)
|
||||
|
||||
with patch.dict(filestate.__salt__, {'config.manage_mode': mock_t,
|
||||
'file.user_to_uid': mock_uid,
|
||||
|
@ -299,11 +347,12 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
|
|||
with patch.object(os.path, 'isdir', MagicMock(side_effect=[True, False])):
|
||||
with patch.object(os.path, 'isdir', mock_t):
|
||||
with patch.object(os.path, 'exists', mock_f):
|
||||
comt = ('Directory exists where the symlink {0} should be'.format(name))
|
||||
ret.update({'comment': comt, 'result': False})
|
||||
self.assertDictEqual(filestate.symlink
|
||||
(name, target, user=user,
|
||||
group=group), ret)
|
||||
with patch('salt.utils.win_functions.get_sid_from_name', return_value='test-sid'):
|
||||
comt = ('Directory exists where the symlink {0} should be'.format(name))
|
||||
ret = return_val({'comment': comt, 'result': False, 'pchanges': {'new': '/tmp/testfile.txt'}})
|
||||
self.assertDictEqual(filestate.symlink
|
||||
(name, target, user=user,
|
||||
group=group), ret)
|
||||
|
||||
with patch.dict(filestate.__salt__, {'config.manage_mode': mock_t,
|
||||
'file.user_to_uid': mock_uid,
|
||||
|
@ -316,12 +365,13 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
|
|||
with patch.dict(filestate.__opts__, {'test': False}):
|
||||
with patch.object(os.path, 'isdir', MagicMock(side_effect=[True, False])):
|
||||
with patch.object(os.path, 'isfile', mock_f):
|
||||
comt = ('Unable to create new symlink {0} -> '
|
||||
'{1}: '.format(name, target))
|
||||
ret.update({'comment': comt, 'result': False})
|
||||
self.assertDictEqual(filestate.symlink
|
||||
(name, target, user=user,
|
||||
group=group), ret)
|
||||
with patch('salt.utils.win_functions.get_sid_from_name', return_value='test-sid'):
|
||||
comt = ('Unable to create new symlink {0} -> '
|
||||
'{1}: '.format(name, target))
|
||||
ret = return_val({'comment': comt, 'result': False, 'pchanges': {'new': '/tmp/testfile.txt'}})
|
||||
self.assertDictEqual(filestate.symlink
|
||||
(name, target, user=user,
|
||||
group=group), ret)
|
||||
|
||||
with patch.dict(filestate.__salt__, {'config.manage_mode': mock_t,
|
||||
'file.user_to_uid': mock_uid,
|
||||
|
@ -336,13 +386,15 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
|
|||
with patch.dict(filestate.__opts__, {'test': False}):
|
||||
with patch.object(os.path, 'isdir', MagicMock(side_effect=[True, False])):
|
||||
with patch.object(os.path, 'isfile', mock_f):
|
||||
comt = 'Created new symlink {0} -> {1}'.format(name, target)
|
||||
ret.update({'comment': comt,
|
||||
'result': True,
|
||||
'changes': {'new': name}})
|
||||
self.assertDictEqual(filestate.symlink
|
||||
(name, target, user=user,
|
||||
group=group), ret)
|
||||
with patch('salt.states.file._check_symlink_ownership', return_value=True):
|
||||
with patch('salt.utils.win_functions.get_sid_from_name', return_value='test-sid'):
|
||||
comt = 'Created new symlink {0} -> {1}'.format(name, target)
|
||||
ret = return_val({'comment': comt,
|
||||
'result': True, 'pchanges': {'new': '/tmp/testfile.txt'},
|
||||
'changes': {'new': name}})
|
||||
self.assertDictEqual(filestate.symlink
|
||||
(name, target, user=user,
|
||||
group=group), ret)
|
||||
|
||||
with patch.dict(filestate.__salt__, {'config.manage_mode': mock_t,
|
||||
'file.user_to_uid': mock_uid,
|
||||
|
@ -357,15 +409,19 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
|
|||
with patch.dict(filestate.__opts__, {'test': False}):
|
||||
with patch.object(os.path, 'isdir', MagicMock(side_effect=[True, False])):
|
||||
with patch.object(os.path, 'isfile', mock_f):
|
||||
comt = ('Created new symlink {0} -> {1}, '
|
||||
'but was unable to set ownership to '
|
||||
'{2}:{3}'.format(name, target, user, group))
|
||||
ret.update({'comment': comt,
|
||||
'result': False,
|
||||
'changes': {'new': name}})
|
||||
self.assertDictEqual(filestate.symlink
|
||||
(name, target, user=user,
|
||||
group=group), ret)
|
||||
with patch('salt.utils.win_functions.get_sid_from_name', return_value='test-sid'):
|
||||
with patch('salt.states.file._set_symlink_ownership', return_value=False):
|
||||
with patch('salt.states.file._check_symlink_ownership', return_value=False):
|
||||
comt = ('Created new symlink {0} -> {1}, '
|
||||
'but was unable to set ownership to '
|
||||
'{2}:{3}'.format(name, target, user, group))
|
||||
ret = return_val({'comment': comt,
|
||||
'result': False,
|
||||
'pchanges': {'new': '/tmp/testfile.txt'},
|
||||
'changes': {'new': name}})
|
||||
self.assertDictEqual(filestate.symlink
|
||||
(name, target, user=user,
|
||||
group=group), ret)
|
||||
|
||||
# 'absent' function tests: 1
|
||||
def test_absent(self):
|
||||
|
@ -1127,7 +1183,10 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
|
|||
'''
|
||||
Test to ensure that some text appears at the beginning of a file.
|
||||
'''
|
||||
name = '/etc/motd'
|
||||
name = '/tmp/etc/motd'
|
||||
if salt.utils.is_windows():
|
||||
name = 'c:\\tmp\\etc\\motd'
|
||||
assert not os.path.exists(os.path.split(name)[0])
|
||||
source = ['salt://motd/hr-messages.tmpl']
|
||||
sources = ['salt://motd/devops-messages.tmpl']
|
||||
text = ['Trust no one unless you have eaten much salt with him.']
|
||||
|
@ -1156,12 +1215,15 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
|
|||
'cp.get_template': mock_f,
|
||||
'file.search': mock_f,
|
||||
'file.prepend': mock_t}):
|
||||
with patch.object(os.path, 'isdir', mock_t):
|
||||
comt = ('The following files will be changed:\n/etc:'
|
||||
' directory - new\n')
|
||||
ret.update({'comment': comt, 'name': name, 'pchanges': {'/etc': {'directory': 'new'}}})
|
||||
self.assertDictEqual(filestate.prepend(name, makedirs=True),
|
||||
ret)
|
||||
comt = ('The following files will be changed:\n/tmp/etc:'
|
||||
' directory - new\n')
|
||||
pchanges = {'/tmp/etc': {'directory': 'new'}}
|
||||
if salt.utils.is_windows():
|
||||
comt = 'The directory "c:\\tmp\\etc" will be changed'
|
||||
pchanges = {'c:\\tmp\\etc': {'directory': 'new'}}
|
||||
ret.update({'comment': comt, 'name': name, 'pchanges': pchanges})
|
||||
self.assertDictEqual(filestate.prepend(name, makedirs=True),
|
||||
ret)
|
||||
|
||||
with patch.object(os.path, 'isabs', mock_f):
|
||||
comt = ('Specified file {0} is not an absolute path'
|
||||
|
|
|
@ -125,6 +125,7 @@ class ServiceTestCase(TestCase, LoaderModuleMockMixin):
|
|||
{'changes': 'saltstack',
|
||||
'comment': 'The service salt is already dead', 'name': 'salt',
|
||||
'result': True}]
|
||||
info_mock = MagicMock(return_value={'StartType': ''})
|
||||
|
||||
mock = MagicMock(return_value="salt")
|
||||
with patch.object(service, '_enabled_used_error', mock):
|
||||
|
@ -140,31 +141,36 @@ class ServiceTestCase(TestCase, LoaderModuleMockMixin):
|
|||
with patch.dict(service.__opts__, {'test': True}):
|
||||
with patch.dict(service.__salt__, {'service.enabled': fmock,
|
||||
'service.stop': tmock,
|
||||
'service.status': fmock}):
|
||||
'service.status': fmock,
|
||||
'service.info': info_mock}):
|
||||
with patch.object(service, '_enable', mock):
|
||||
self.assertDictEqual(service.dead("salt", True), ret[5])
|
||||
|
||||
with patch.dict(service.__salt__, {'service.enabled': tmock,
|
||||
'service.status': tmock}):
|
||||
'service.status': tmock,
|
||||
'service.info': info_mock}):
|
||||
self.assertDictEqual(service.dead("salt"), ret[2])
|
||||
|
||||
with patch.dict(service.__opts__, {'test': False}):
|
||||
with patch.dict(service.__salt__, {'service.enabled': fmock,
|
||||
'service.stop': tmock,
|
||||
'service.status': fmock}):
|
||||
'service.status': fmock,
|
||||
'service.info': info_mock}):
|
||||
with patch.object(service, '_enable', mock):
|
||||
self.assertDictEqual(service.dead("salt", True), ret[1])
|
||||
|
||||
with patch.dict(service.__salt__, {'service.enabled': MagicMock(side_effect=[True, True, False]),
|
||||
'service.status': MagicMock(side_effect=[True, False, False]),
|
||||
'service.stop': MagicMock(return_value="stack")}):
|
||||
'service.stop': MagicMock(return_value="stack"),
|
||||
'service.info': info_mock}):
|
||||
with patch.object(service, '_enable', MagicMock(return_value={'changes': 'saltstack'})):
|
||||
self.assertDictEqual(service.dead("salt", True), ret[3])
|
||||
|
||||
# test an initd which a wrong status (True even if dead)
|
||||
with patch.dict(service.__salt__, {'service.enabled': MagicMock(side_effect=[False, False, False]),
|
||||
'service.status': MagicMock(side_effect=[True, True, True]),
|
||||
'service.stop': MagicMock(return_value="stack")}):
|
||||
'service.stop': MagicMock(return_value="stack"),
|
||||
'service.info': info_mock}):
|
||||
with patch.object(service, '_disable', MagicMock(return_value={})):
|
||||
self.assertDictEqual(service.dead("salt", False), ret[4])
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue