mirror of
https://github.com/valitydev/salt.git
synced 2024-11-06 16:45:27 +00:00
Merge branch '2018.3' into jid
This commit is contained in:
commit
084e7f0ef4
27
.ci/docs
27
.ci/docs
@ -1,10 +1,23 @@
|
|||||||
pipeline {
|
pipeline {
|
||||||
agent { label 'docs' }
|
agent { label 'docs' }
|
||||||
|
options {
|
||||||
|
timestamps()
|
||||||
|
ansiColor('xterm')
|
||||||
|
}
|
||||||
environment {
|
environment {
|
||||||
PYENV_ROOT = "/usr/local/pyenv"
|
PYENV_ROOT = "/usr/local/pyenv"
|
||||||
PATH = "$PYENV_ROOT/bin:$PATH"
|
PATH = "$PYENV_ROOT/bin:$PATH"
|
||||||
|
PY_COLORS = 1
|
||||||
}
|
}
|
||||||
stages {
|
stages {
|
||||||
|
stage('github-pending') {
|
||||||
|
steps {
|
||||||
|
githubNotify credentialsId: 'test-jenkins-credentials',
|
||||||
|
description: 'Testing docs...',
|
||||||
|
status: 'PENDING',
|
||||||
|
context: "jenkins/pr/docs"
|
||||||
|
}
|
||||||
|
}
|
||||||
stage('setup') {
|
stage('setup') {
|
||||||
steps {
|
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 -)"; pyenv install 2.7.14 || echo "We already have this python."; pyenv local 2.7.14; pyenv shell 2.7.14'
|
||||||
@ -14,16 +27,24 @@ pipeline {
|
|||||||
stage('build') {
|
stage('build') {
|
||||||
steps {
|
steps {
|
||||||
sh 'eval "$(pyenv init -)"; make -C doc clean html'
|
sh 'eval "$(pyenv init -)"; make -C doc clean html'
|
||||||
archiveArtifacts artifacts: 'doc/_build/html'
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
post {
|
post {
|
||||||
|
always {
|
||||||
|
cleanWs()
|
||||||
|
}
|
||||||
success {
|
success {
|
||||||
githubNotify description: "The docs job has passed, artifacts have been saved", status: "SUCCESS"
|
githubNotify credentialsId: 'test-jenkins-credentials',
|
||||||
|
description: 'The docs job has passed',
|
||||||
|
status: 'SUCCESS',
|
||||||
|
context: "jenkins/pr/docs"
|
||||||
}
|
}
|
||||||
failure {
|
failure {
|
||||||
githubNotify description: "The docs job has failed", status: "FAILURE"
|
githubNotify credentialsId: 'test-jenkins-credentials',
|
||||||
|
description: 'The docs job has failed',
|
||||||
|
status: 'FAILURE',
|
||||||
|
context: "jenkins/pr/docs"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
pipeline {
|
pipeline {
|
||||||
agent { label 'kitchen-slave' }
|
agent { label 'kitchen-slave' }
|
||||||
|
options {
|
||||||
|
timestamps()
|
||||||
|
ansiColor('xterm')
|
||||||
|
}
|
||||||
environment {
|
environment {
|
||||||
SALT_KITCHEN_PLATFORMS = "/var/jenkins/workspace/platforms.yml"
|
SALT_KITCHEN_PLATFORMS = "/var/jenkins/workspace/platforms.yml"
|
||||||
SALT_KITCHEN_DRIVER = "/var/jenkins/workspace/driver.yml"
|
SALT_KITCHEN_DRIVER = "/var/jenkins/workspace/driver.yml"
|
||||||
@ -7,8 +11,17 @@ pipeline {
|
|||||||
RBENV_VERSION = "2.4.2"
|
RBENV_VERSION = "2.4.2"
|
||||||
TEST_SUITE = "py2"
|
TEST_SUITE = "py2"
|
||||||
TEST_PLATFORM = "centos-7"
|
TEST_PLATFORM = "centos-7"
|
||||||
|
PY_COLORS = 1
|
||||||
}
|
}
|
||||||
stages {
|
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') {
|
stage('setup') {
|
||||||
steps {
|
steps {
|
||||||
sh 'bundle install --with ec2 windows --without opennebula docker'
|
sh 'bundle install --with ec2 windows --without opennebula docker'
|
||||||
@ -23,26 +36,36 @@ pipeline {
|
|||||||
sh 'bundle exec kitchen verify $TEST_SUITE-$TEST_PLATFORM'
|
sh 'bundle exec kitchen verify $TEST_SUITE-$TEST_PLATFORM'
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
archiveArtifacts artifacts: 'artifacts/xml-unittests-output/*.xml'
|
|
||||||
}
|
}
|
||||||
post {
|
post {
|
||||||
always {
|
always {
|
||||||
script { withCredentials([[$class: 'AmazonWebServicesCredentialsBinding', accessKeyVariable: 'AWS_ACCESS_KEY_ID', credentialsId: 'AWS_ACCESS_KEY_ID', secretKeyVariable: 'AWS_SECRET_ACCESS_KEY']]) {
|
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']) {
|
sshagent(credentials: ['jenkins-testing-ssh-key']) {
|
||||||
sh 'ssh-add ~/.ssh/jenkins/jenkins-testing.pem'
|
sh 'ssh-add ~/.ssh/jenkins-testing.pem'
|
||||||
sh 'bundle exec kitchen destroy $TEST_SUITE-$TEST_PLATFORM'
|
sh 'bundle exec kitchen destroy $TEST_SUITE-$TEST_PLATFORM'
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
archiveArtifacts artifacts: 'artifacts/xml-unittests-output/*.xml'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
post {
|
post {
|
||||||
|
always {
|
||||||
|
junit 'artifacts/xml-unittests-output/*.xml'
|
||||||
|
cleanWs()
|
||||||
|
}
|
||||||
success {
|
success {
|
||||||
githubNotify description: "The centos7-py2 job has passed", status: "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 {
|
failure {
|
||||||
githubNotify description: "The centos7-py2 job has failed", status: "FAILURE"
|
githubNotify credentialsId: 'test-jenkins-credentials',
|
||||||
|
description: "The ${TEST_SUITE}-${TEST_PLATFORM} job has failed",
|
||||||
|
status: 'FAILURE',
|
||||||
|
context: "jenkins/pr/${TEST_SUITE}-${TEST_PLATFORM}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
pipeline {
|
pipeline {
|
||||||
agent { label 'kitchen-slave' }
|
agent { label 'kitchen-slave' }
|
||||||
|
options {
|
||||||
|
timestamps()
|
||||||
|
ansiColor('xterm')
|
||||||
|
}
|
||||||
environment {
|
environment {
|
||||||
SALT_KITCHEN_PLATFORMS = "/var/jenkins/workspace/platforms.yml"
|
SALT_KITCHEN_PLATFORMS = "/var/jenkins/workspace/platforms.yml"
|
||||||
SALT_KITCHEN_DRIVER = "/var/jenkins/workspace/driver.yml"
|
SALT_KITCHEN_DRIVER = "/var/jenkins/workspace/driver.yml"
|
||||||
@ -7,8 +11,17 @@ pipeline {
|
|||||||
RBENV_VERSION = "2.4.2"
|
RBENV_VERSION = "2.4.2"
|
||||||
TEST_SUITE = "py3"
|
TEST_SUITE = "py3"
|
||||||
TEST_PLATFORM = "centos-7"
|
TEST_PLATFORM = "centos-7"
|
||||||
|
PY_COLORS = 1
|
||||||
}
|
}
|
||||||
stages {
|
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') {
|
stage('setup') {
|
||||||
steps {
|
steps {
|
||||||
sh 'bundle install --with ec2 windows --without opennebula docker'
|
sh 'bundle install --with ec2 windows --without opennebula docker'
|
||||||
@ -23,26 +36,36 @@ pipeline {
|
|||||||
sh 'bundle exec kitchen verify $TEST_SUITE-$TEST_PLATFORM'
|
sh 'bundle exec kitchen verify $TEST_SUITE-$TEST_PLATFORM'
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
archiveArtifacts artifacts: 'artifacts/xml-unittests-output/*.xml'
|
|
||||||
}
|
}
|
||||||
post {
|
post {
|
||||||
always {
|
always {
|
||||||
script { withCredentials([[$class: 'AmazonWebServicesCredentialsBinding', accessKeyVariable: 'AWS_ACCESS_KEY_ID', credentialsId: 'AWS_ACCESS_KEY_ID', secretKeyVariable: 'AWS_SECRET_ACCESS_KEY']]) {
|
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']) {
|
sshagent(credentials: ['jenkins-testing-ssh-key']) {
|
||||||
sh 'ssh-add ~/.ssh/jenkins/jenkins-testing.pem'
|
sh 'ssh-add ~/.ssh/jenkins-testing.pem'
|
||||||
sh 'bundle exec kitchen destroy $TEST_SUITE-$TEST_PLATFORM'
|
sh 'bundle exec kitchen destroy $TEST_SUITE-$TEST_PLATFORM'
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
archiveArtifacts artifacts: 'artifacts/xml-unittests-output/*.xml'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
post {
|
post {
|
||||||
|
always {
|
||||||
|
junit 'artifacts/xml-unittests-output/*.xml'
|
||||||
|
cleanWs()
|
||||||
|
}
|
||||||
success {
|
success {
|
||||||
githubNotify description: "The centos7-py3 job has passed", status: "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 {
|
failure {
|
||||||
githubNotify description: "The centos7-py3 job has failed", status: "FAILURE"
|
githubNotify credentialsId: 'test-jenkins-credentials',
|
||||||
|
description: "The ${TEST_SUITE}-${TEST_PLATFORM} job has failed",
|
||||||
|
status: 'FAILURE',
|
||||||
|
context: "jenkins/pr/${TEST_SUITE}-${TEST_PLATFORM}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
pipeline {
|
pipeline {
|
||||||
agent { label 'kitchen-slave' }
|
agent { label 'kitchen-slave' }
|
||||||
|
options {
|
||||||
|
timestamps()
|
||||||
|
ansiColor('xterm')
|
||||||
|
}
|
||||||
environment {
|
environment {
|
||||||
SALT_KITCHEN_PLATFORMS = "/var/jenkins/workspace/platforms.yml"
|
SALT_KITCHEN_PLATFORMS = "/var/jenkins/workspace/platforms.yml"
|
||||||
SALT_KITCHEN_DRIVER = "/var/jenkins/workspace/driver.yml"
|
SALT_KITCHEN_DRIVER = "/var/jenkins/workspace/driver.yml"
|
||||||
@ -7,8 +11,17 @@ pipeline {
|
|||||||
RBENV_VERSION = "2.4.2"
|
RBENV_VERSION = "2.4.2"
|
||||||
TEST_SUITE = "py2"
|
TEST_SUITE = "py2"
|
||||||
TEST_PLATFORM = "ubuntu-1604"
|
TEST_PLATFORM = "ubuntu-1604"
|
||||||
|
PY_COLORS = 1
|
||||||
}
|
}
|
||||||
stages {
|
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') {
|
stage('setup') {
|
||||||
steps {
|
steps {
|
||||||
sh 'bundle install --with ec2 windows --without opennebula docker'
|
sh 'bundle install --with ec2 windows --without opennebula docker'
|
||||||
@ -23,26 +36,36 @@ pipeline {
|
|||||||
sh 'bundle exec kitchen verify $TEST_SUITE-$TEST_PLATFORM'
|
sh 'bundle exec kitchen verify $TEST_SUITE-$TEST_PLATFORM'
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
archiveArtifacts artifacts: 'artifacts/xml-unittests-output/*.xml'
|
|
||||||
}
|
}
|
||||||
post {
|
post {
|
||||||
always {
|
always {
|
||||||
script { withCredentials([[$class: 'AmazonWebServicesCredentialsBinding', accessKeyVariable: 'AWS_ACCESS_KEY_ID', credentialsId: 'AWS_ACCESS_KEY_ID', secretKeyVariable: 'AWS_SECRET_ACCESS_KEY']]) {
|
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']) {
|
sshagent(credentials: ['jenkins-testing-ssh-key']) {
|
||||||
sh 'ssh-add ~/.ssh/jenkins/jenkins-testing.pem'
|
sh 'ssh-add ~/.ssh/jenkins-testing.pem'
|
||||||
sh 'bundle exec kitchen destroy $TEST_SUITE-$TEST_PLATFORM'
|
sh 'bundle exec kitchen destroy $TEST_SUITE-$TEST_PLATFORM'
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
archiveArtifacts artifacts: 'artifacts/xml-unittests-output/*.xml'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
post {
|
post {
|
||||||
|
always {
|
||||||
|
junit 'artifacts/xml-unittests-output/*.xml'
|
||||||
|
cleanWs()
|
||||||
|
}
|
||||||
success {
|
success {
|
||||||
githubNotify description: "The ubuntu-1604-py2 job has passed", status: "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 {
|
failure {
|
||||||
githubNotify description: "The ubuntu-1604-py2 job has failed", status: "FAILURE"
|
githubNotify credentialsId: 'test-jenkins-credentials',
|
||||||
|
description: "The ${TEST_SUITE}-${TEST_PLATFORM} job has failed",
|
||||||
|
status: 'FAILURE',
|
||||||
|
context: "jenkins/pr/${TEST_SUITE}-${TEST_PLATFORM}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
pipeline {
|
pipeline {
|
||||||
agent { label 'kitchen-slave' }
|
agent { label 'kitchen-slave' }
|
||||||
|
options {
|
||||||
|
timestamps()
|
||||||
|
ansiColor('xterm')
|
||||||
|
}
|
||||||
environment {
|
environment {
|
||||||
SALT_KITCHEN_PLATFORMS = "/var/jenkins/workspace/platforms.yml"
|
SALT_KITCHEN_PLATFORMS = "/var/jenkins/workspace/platforms.yml"
|
||||||
SALT_KITCHEN_DRIVER = "/var/jenkins/workspace/driver.yml"
|
SALT_KITCHEN_DRIVER = "/var/jenkins/workspace/driver.yml"
|
||||||
@ -7,8 +11,17 @@ pipeline {
|
|||||||
RBENV_VERSION = "2.4.2"
|
RBENV_VERSION = "2.4.2"
|
||||||
TEST_SUITE = "py3"
|
TEST_SUITE = "py3"
|
||||||
TEST_PLATFORM = "ubuntu-1604"
|
TEST_PLATFORM = "ubuntu-1604"
|
||||||
|
PY_COLORS = 1
|
||||||
}
|
}
|
||||||
stages {
|
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') {
|
stage('setup') {
|
||||||
steps {
|
steps {
|
||||||
sh 'bundle install --with ec2 windows --without opennebula docker'
|
sh 'bundle install --with ec2 windows --without opennebula docker'
|
||||||
@ -23,26 +36,36 @@ pipeline {
|
|||||||
sh 'bundle exec kitchen verify $TEST_SUITE-$TEST_PLATFORM'
|
sh 'bundle exec kitchen verify $TEST_SUITE-$TEST_PLATFORM'
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
archiveArtifacts artifacts: 'artifacts/xml-unittests-output/*.xml'
|
|
||||||
}
|
}
|
||||||
post {
|
post {
|
||||||
always {
|
always {
|
||||||
script { withCredentials([[$class: 'AmazonWebServicesCredentialsBinding', accessKeyVariable: 'AWS_ACCESS_KEY_ID', credentialsId: 'AWS_ACCESS_KEY_ID', secretKeyVariable: 'AWS_SECRET_ACCESS_KEY']]) {
|
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']) {
|
sshagent(credentials: ['jenkins-testing-ssh-key']) {
|
||||||
sh 'ssh-add ~/.ssh/jenkins/jenkins-testing.pem'
|
sh 'ssh-add ~/.ssh/jenkins-testing.pem'
|
||||||
sh 'bundle exec kitchen destroy $TEST_SUITE-$TEST_PLATFORM'
|
sh 'bundle exec kitchen destroy $TEST_SUITE-$TEST_PLATFORM'
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
archiveArtifacts artifacts: 'artifacts/xml-unittests-output/*.xml'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
post {
|
post {
|
||||||
|
always {
|
||||||
|
junit 'artifacts/xml-unittests-output/*.xml'
|
||||||
|
cleanWs()
|
||||||
|
}
|
||||||
success {
|
success {
|
||||||
githubNotify description: "The ubuntu-1604-py3 job has passed", status: "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 {
|
failure {
|
||||||
githubNotify description: "The ubuntu-1604-py3 job has failed", status: "FAILURE"
|
githubNotify credentialsId: 'test-jenkins-credentials',
|
||||||
|
description: "The ${TEST_SUITE}-${TEST_PLATFORM} job has failed",
|
||||||
|
status: 'FAILURE',
|
||||||
|
context: "jenkins/pr/${TEST_SUITE}-${TEST_PLATFORM}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
43
.ci/lint
43
.ci/lint
@ -1,15 +1,27 @@
|
|||||||
pipeline {
|
pipeline {
|
||||||
agent { label 'pr-lint-slave' }
|
agent { label 'pr-lint-slave' }
|
||||||
|
options {
|
||||||
|
timestamps()
|
||||||
|
ansiColor('xterm')
|
||||||
|
}
|
||||||
environment {
|
environment {
|
||||||
PYENV_ROOT = "/usr/local/pyenv"
|
PYENV_ROOT = "/usr/local/pyenv"
|
||||||
PATH = "$PYENV_ROOT/bin:$PATH"
|
PATH = "$PYENV_ROOT/bin:$PATH"
|
||||||
|
PY_COLORS = 1
|
||||||
}
|
}
|
||||||
stages {
|
stages {
|
||||||
|
stage('github-pending') {
|
||||||
|
steps {
|
||||||
|
githubNotify credentialsId: 'test-jenkins-credentials',
|
||||||
|
description: 'Testing lint...',
|
||||||
|
status: 'PENDING',
|
||||||
|
context: "jenkins/pr/lint"
|
||||||
|
}
|
||||||
|
}
|
||||||
stage('setup') {
|
stage('setup') {
|
||||||
steps {
|
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 -)"; 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 pylint SaltPyLint'
|
sh 'eval "$(pyenv init -)"; pip install tox'
|
||||||
sh 'eval "$(pyenv init -)"; which pylint; pylint --version'
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stage('linting') {
|
stage('linting') {
|
||||||
@ -17,13 +29,13 @@ pipeline {
|
|||||||
parallel {
|
parallel {
|
||||||
stage('salt linting') {
|
stage('salt linting') {
|
||||||
steps {
|
steps {
|
||||||
sh 'eval "$(pyenv init -)"; pylint --rcfile=.testing.pylintrc --disable=W1307,str-format-in-logging setup.py salt/ | tee pylint-report.xml'
|
sh 'eval "$(pyenv init - --no-rehash)"; tox -e pylint-salt $(find salt/ -name "*.py" -exec git diff --name-only "origin/$CHANGE_TARGET" "origin/$BRANCH_NAME" setup.py {} +) | tee pylint-report.xml'
|
||||||
archiveArtifacts artifacts: 'pylint-report.xml'
|
archiveArtifacts artifacts: 'pylint-report.xml'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stage('test linting') {
|
stage('test linting') {
|
||||||
steps {
|
steps {
|
||||||
sh 'eval "$(pyenv init -)"; pylint --rcfile=.testing.pylintrc --disable=W0232,E1002,W1307,str-format-in-logging tests/ | tee pylint-report-tests.xml'
|
sh 'eval "$(pyenv init - --no-rehash)"; tox -e pylint-tests $(find tests/ -name "*.py" -exec git diff --name-only "origin/$CHANGE_TARGET" "origin/$BRANCH_NAME" {} +) | tee pylint-report-tests.xml'
|
||||||
archiveArtifacts artifacts: 'pylint-report-tests.xml'
|
archiveArtifacts artifacts: 'pylint-report-tests.xml'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -31,11 +43,30 @@ pipeline {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
post {
|
post {
|
||||||
|
always {
|
||||||
|
step([$class: 'WarningsPublisher',
|
||||||
|
parserConfigurations: [[
|
||||||
|
parserName: 'PyLint',
|
||||||
|
pattern: 'pylint-report*.xml'
|
||||||
|
]],
|
||||||
|
failedTotalAll: '0',
|
||||||
|
useDeltaValues: false,
|
||||||
|
canRunOnFailed: true,
|
||||||
|
usePreviousBuildAsReference: true
|
||||||
|
])
|
||||||
|
cleanWs()
|
||||||
|
}
|
||||||
success {
|
success {
|
||||||
githubNotify description: "The lint job has passed", status: "SUCCESS"
|
githubNotify credentialsId: 'test-jenkins-credentials',
|
||||||
|
description: 'The lint job has passed',
|
||||||
|
status: 'SUCCESS',
|
||||||
|
context: "jenkins/pr/lint"
|
||||||
}
|
}
|
||||||
failure {
|
failure {
|
||||||
githubNotify description: "The lint job has failed", status: "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
|
# Team SSH
|
||||||
salt/cli/ssh.py @saltstack/team-ssh
|
salt/cli/ssh.py @saltstack/team-ssh
|
||||||
salt/client/ssh/* @saltstack/team-ssh
|
salt/client/ssh/* @saltstack/team-ssh
|
||||||
|
salt/roster/* @saltstack/team-ssh
|
||||||
salt/runners/ssh.py @saltstack/team-ssh
|
salt/runners/ssh.py @saltstack/team-ssh
|
||||||
salt/**/thin.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') %>
|
<% 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' %>
|
<% platformsfile = ENV['SALT_KITCHEN_PLATFORMS'] || '.kitchen/platforms.yml' %>
|
||||||
<% driverfile = ENV['SALT_KITCHEN_DRIVER'] || '.kitchen/driver.yml' %>
|
<% driverfile = ENV['SALT_KITCHEN_DRIVER'] || '.kitchen/driver.yml' %>
|
||||||
<% verifierfile = ENV['SALT_KITCHEN_VERIFIER'] || '.kitchen/verifier.yml' %>
|
<% verifierfile = ENV['SALT_KITCHEN_VERIFIER'] || '.kitchen/verifier.yml' %>
|
||||||
@ -31,7 +31,7 @@ provisioner:
|
|||||||
salt_version: latest
|
salt_version: latest
|
||||||
salt_bootstrap_url: https://bootstrap.saltstack.com
|
salt_bootstrap_url: https://bootstrap.saltstack.com
|
||||||
salt_bootstrap_options: -X -p rsync stable <%= version %>
|
salt_bootstrap_options: -X -p rsync stable <%= version %>
|
||||||
log_level: debug
|
log_level: info
|
||||||
sudo: true
|
sudo: true
|
||||||
require_chef: false
|
require_chef: false
|
||||||
retry_on_exit_code:
|
retry_on_exit_code:
|
||||||
|
8
doc/_themes/saltstack2/layout.html
vendored
8
doc/_themes/saltstack2/layout.html
vendored
@ -138,7 +138,7 @@
|
|||||||
<span class="icon-bar"></span>
|
<span class="icon-bar"></span>
|
||||||
<span class="icon-bar"></span>
|
<span class="icon-bar"></span>
|
||||||
</button>
|
</button>
|
||||||
<a href="http://saltstack.com/" target="_blank"><img src="{{ pathto('_static/images/saltstack.svg', 1) }}" class="nolightbox" height="40px" width="170px"></a>
|
<a href="http://saltstack.com/" target="_blank"><img src="{{ pathto('_static/images/SaltStack_white.svg', 1) }}" class="nolightbox" height="40px" width="170px"></a>
|
||||||
</div>
|
</div>
|
||||||
<!-- Collect the nav links, forms, and other content for toggling -->
|
<!-- Collect the nav links, forms, and other content for toggling -->
|
||||||
<div class="collapse navbar-collapse" id="navbarCollapse">
|
<div class="collapse navbar-collapse" id="navbarCollapse">
|
||||||
@ -252,13 +252,11 @@
|
|||||||
<p>© {{ copyright }} SaltStack. All Rights Reserved, SaltStack Inc. | <a href="http://saltstack.com/privacy-policy" target="_blank">Privacy Policy</a></p>
|
<p>© {{ copyright }} SaltStack. All Rights Reserved, SaltStack Inc. | <a href="http://saltstack.com/privacy-policy" target="_blank">Privacy Policy</a></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
|
<!--
|
||||||
<a href="https://saltstack.com/saltstack-enterprise/" target="_blank"><img class="nolightbox footer-banner center" src="{{ pathto('_static/images/enterprise_ad.jpg', 1) }}"/></a>
|
<a href="https://saltstack.com/saltstack-enterprise/" target="_blank"><img class="nolightbox footer-banner center" src="{{ pathto('_static/images/enterprise_ad.jpg', 1) }}"/></a>
|
||||||
|
-->
|
||||||
<a href="http://saltconf.com" target="_blank"><img class="nolightbox footer-banner center" src="{{ pathto('_static/images/DOCBANNER.jpg', 1) }}"/></a>
|
<a href="http://saltconf.com" target="_blank"><img class="nolightbox footer-banner center" src="{{ pathto('_static/images/DOCBANNER.jpg', 1) }}"/></a>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
BIN
doc/_themes/saltstack2/static/images/DOCBANNER.jpg
vendored
BIN
doc/_themes/saltstack2/static/images/DOCBANNER.jpg
vendored
Binary file not shown.
Before Width: | Height: | Size: 240 KiB After Width: | Height: | Size: 589 KiB |
1
doc/_themes/saltstack2/static/images/SaltStack_white.svg
vendored
Normal file
1
doc/_themes/saltstack2/static/images/SaltStack_white.svg
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 301.57 44.47"><defs><style>.cls-1{fill:#fff;}</style></defs><title>Asset 2</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><path class="cls-1" d="M50.63,6.05h8.79L72.58,43.24H64.15L61.7,35.6H48l-2.52,7.64H37.35Zm-.51,23.14h9.52l-4.7-14.64Z"/><path class="cls-1" d="M76.12,6.05h7.77V36.56h18.58v6.68H76.12Z"/><path class="cls-1" d="M127.07,6.05v6.58H115.94V43.24h-7.82V12.63H96.94V6.05Z"/><path class="cls-1" d="M190.53,6.05v6.58H179.41V43.24h-7.83V12.63H160.4V6.05Z"/><path class="cls-1" d="M200.41,6.05h8.8l13.16,37.19h-8.43l-2.45-7.64h-13.7l-2.52,7.64h-8.13Zm-.51,23.14h9.53l-4.7-14.64Z"/><path class="cls-1" d="M227.91,10.17a15.34,15.34,0,0,1,11.34-4.83q9.28-.2,13.71,5.87a13.46,13.46,0,0,1,2.69,6.89l-7.77.16a10.78,10.78,0,0,0-2-4A7.68,7.68,0,0,0,239.68,12a7.59,7.59,0,0,0-6.48,3.56Q230.88,19,231,25.25t2.73,9.32a7.91,7.91,0,0,0,6.49,3,7.27,7.27,0,0,0,6-2.8,11.86,11.86,0,0,0,1.84-4.35l7.72-.17a16.79,16.79,0,0,1-4.9,10,14.83,14.83,0,0,1-10.44,4q-7.94.16-12.59-4.88t-4.84-14.09Q222.85,15.56,227.91,10.17Z"/><path class="cls-1" d="M260.39,6.05H268V21.37L282.4,6.05h10.05L277.18,21.34l16.05,21.9h-10L271.78,27,268,30.8V43.24h-7.64Z"/><path class="cls-1" d="M15.65,12.47a9.05,9.05,0,0,1,4.6-1.05,10.15,10.15,0,0,1,4.63.94,5.29,5.29,0,0,1,3,4.77h7.47a11.06,11.06,0,0,0-4.4-9A16.57,16.57,0,0,0,20.79,5a23,23,0,0,0-5.14.54Z"/><path class="cls-1" d="M33.21,24.77a16.6,16.6,0,0,0-6.43-2.7l-6.53-1.54A22.45,22.45,0,0,1,15.31,19a3.18,3.18,0,0,1-1.81-3c0-.12,0-.22,0-.34H6.35c0,.3,0,.59,0,.9q0,5.47,3.76,8.05,2.22,1.54,8.15,2.85l4,.89a17.48,17.48,0,0,1,5.17,1.74A3.17,3.17,0,0,1,29,33c0,2.1-1.1,3.54-3.32,4.31a14.08,14.08,0,0,1-4.56.61c-3.13,0-5.33-.77-6.62-2.3a7.48,7.48,0,0,1-1.42-3.81H5.7a11,11,0,0,0,4.21,9.12q4.22,3.33,11.56,3.32,7.19,0,11.13-3.37a10.64,10.64,0,0,0,3.94-8.46A9.1,9.1,0,0,0,33.21,24.77Z"/><path class="cls-1" d="M137.55,12.73a9,9,0,0,1,4.6-1.05,10.18,10.18,0,0,1,4.63.94,5.33,5.33,0,0,1,3,4.77h7.47a11,11,0,0,0-4.41-9,16.54,16.54,0,0,0-10.15-3.12,23,23,0,0,0-5.14.54Z"/><path class="cls-1" d="M155.11,25a16.83,16.83,0,0,0-6.43-2.7l-6.53-1.54a21.71,21.71,0,0,1-4.94-1.54,3.17,3.17,0,0,1-1.81-3c0-.13,0-.23,0-.35h-7.19c0,.3-.05.6-.05.9,0,3.65,1.26,6.34,3.77,8.05,1.48,1,4.19,2,8.15,2.85l4,.89a17.29,17.29,0,0,1,5.16,1.74,3.16,3.16,0,0,1,1.63,2.85q0,3.15-3.32,4.32a14.39,14.39,0,0,1-4.56.6c-3.13,0-5.34-.76-6.62-2.3A7.48,7.48,0,0,1,135,32H127.6a11,11,0,0,0,4.21,9.13c2.8,2.21,6.66,3.32,11.55,3.32s8.51-1.13,11.14-3.37a10.7,10.7,0,0,0,3.94-8.47A9.1,9.1,0,0,0,155.11,25Z"/><rect class="cls-1" width="9.85" height="9.85"/><path class="cls-1" d="M299.8,40.44a.94.94,0,0,0,.16-.57,1.06,1.06,0,0,0-.08-.45.82.82,0,0,0-.24-.32,1,1,0,0,0-.38-.19,1.72,1.72,0,0,0-.52-.07h-1.2v3.4h.59V40.93h.66l.68,1.31h.63v0l-.76-1.42A1,1,0,0,0,299.8,40.44Zm-.59-.14a.52.52,0,0,1-.19.12,1.18,1.18,0,0,1-.28,0h-.61V39.32h.61a.79.79,0,0,1,.28,0,.55.55,0,0,1,.2.11.76.76,0,0,1,.12.19.85.85,0,0,1,0,.23.56.56,0,0,1,0,.23A.36.36,0,0,1,299.21,40.3Z"/><path class="cls-1" d="M298.7,37.68a2.88,2.88,0,1,0,2.87,2.87A2.88,2.88,0,0,0,298.7,37.68Zm0,5.27a2.4,2.4,0,1,1,2.39-2.4A2.41,2.41,0,0,1,298.7,43Z"/></g></g></svg>
|
After Width: | Height: | Size: 3.1 KiB |
@ -250,8 +250,8 @@ on_saltstack = 'SALT_ON_SALTSTACK' in os.environ
|
|||||||
project = 'Salt'
|
project = 'Salt'
|
||||||
|
|
||||||
version = salt.version.__version__
|
version = salt.version.__version__
|
||||||
latest_release = '2018.3.1' # latest release
|
latest_release = '2018.3.2' # latest release
|
||||||
previous_release = '2017.7.6' # latest release from previous branch
|
previous_release = '2017.7.7' # latest release from previous branch
|
||||||
previous_release_dir = '2017.7' # path on web server for previous branch
|
previous_release_dir = '2017.7' # path on web server for previous branch
|
||||||
next_release = '' # next release
|
next_release = '' # next release
|
||||||
next_release_dir = '' # path on web server for next release branch
|
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
|
Custom modules are synced to Minions when
|
||||||
:mod:`saltutil.sync_modules <salt.modules.saltutil.sync_modules>`,
|
:py:func:`saltutil.sync_modules <salt.modules.saltutil.sync_modules>`,
|
||||||
or :mod:`saltutil.sync_all <salt.modules.saltutil.sync_all>` is run.
|
or :py:func:`saltutil.sync_all <salt.modules.saltutil.sync_all>` is run.
|
||||||
Custom modules are also synced by :mod:`state.apply` when run without
|
|
||||||
any arguments.
|
|
||||||
|
|
||||||
|
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
|
They are both also synced when a :ref:`highstate <running-highstate>` is
|
||||||
when :mod:`state.apply <salt.modules.state.apply_>`,
|
triggered.
|
||||||
:mod:`saltutil.sync_states <salt.modules.saltutil.sync_states>`, or
|
|
||||||
:mod:`saltutil.sync_all <salt.modules.saltutil.sync_all>` is run.
|
|
||||||
|
|
||||||
Custom states are also synced by :mod:`state.apply<salt.modules.state.apply_>`
|
As of the Fluorine release, as well as 2017.7.7 and 2018.3.2 in their
|
||||||
when run without any arguments.
|
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
|
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.
|
information.
|
||||||
|
|
||||||
:ref:`This reactor example <minion-start-reactor>` can be used to automatically
|
:ref:`This reactor example <minion-start-reactor>` can be used to automatically
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
.\" Man page generated from reStructuredText.
|
.\" Man page generated from reStructuredText.
|
||||||
.
|
.
|
||||||
.TH "SALT-API" "1" "May 09, 2018" "2018.3.1" "Salt"
|
.TH "SALT-API" "1" "Jun 14, 2018" "2018.3.2" "Salt"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
salt-api \- salt-api Command
|
salt-api \- salt-api Command
|
||||||
.
|
.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
.\" Man page generated from reStructuredText.
|
.\" Man page generated from reStructuredText.
|
||||||
.
|
.
|
||||||
.TH "SALT-CALL" "1" "May 09, 2018" "2018.3.1" "Salt"
|
.TH "SALT-CALL" "1" "Jun 14, 2018" "2018.3.2" "Salt"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
salt-call \- salt-call Documentation
|
salt-call \- salt-call Documentation
|
||||||
.
|
.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
.\" Man page generated from reStructuredText.
|
.\" Man page generated from reStructuredText.
|
||||||
.
|
.
|
||||||
.TH "SALT-CLOUD" "1" "May 09, 2018" "2018.3.1" "Salt"
|
.TH "SALT-CLOUD" "1" "Jun 14, 2018" "2018.3.2" "Salt"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
salt-cloud \- Salt Cloud Command
|
salt-cloud \- Salt Cloud Command
|
||||||
.
|
.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
.\" Man page generated from reStructuredText.
|
.\" Man page generated from reStructuredText.
|
||||||
.
|
.
|
||||||
.TH "SALT-CP" "1" "May 09, 2018" "2018.3.1" "Salt"
|
.TH "SALT-CP" "1" "Jun 14, 2018" "2018.3.2" "Salt"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
salt-cp \- salt-cp Documentation
|
salt-cp \- salt-cp Documentation
|
||||||
.
|
.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
.\" Man page generated from reStructuredText.
|
.\" Man page generated from reStructuredText.
|
||||||
.
|
.
|
||||||
.TH "SALT-KEY" "1" "May 09, 2018" "2018.3.1" "Salt"
|
.TH "SALT-KEY" "1" "Jun 14, 2018" "2018.3.2" "Salt"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
salt-key \- salt-key Documentation
|
salt-key \- salt-key Documentation
|
||||||
.
|
.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
.\" Man page generated from reStructuredText.
|
.\" Man page generated from reStructuredText.
|
||||||
.
|
.
|
||||||
.TH "SALT-MASTER" "1" "May 09, 2018" "2018.3.1" "Salt"
|
.TH "SALT-MASTER" "1" "Jun 14, 2018" "2018.3.2" "Salt"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
salt-master \- salt-master Documentation
|
salt-master \- salt-master Documentation
|
||||||
.
|
.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
.\" Man page generated from reStructuredText.
|
.\" Man page generated from reStructuredText.
|
||||||
.
|
.
|
||||||
.TH "SALT-MINION" "1" "May 09, 2018" "2018.3.1" "Salt"
|
.TH "SALT-MINION" "1" "Jun 14, 2018" "2018.3.2" "Salt"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
salt-minion \- salt-minion Documentation
|
salt-minion \- salt-minion Documentation
|
||||||
.
|
.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
.\" Man page generated from reStructuredText.
|
.\" Man page generated from reStructuredText.
|
||||||
.
|
.
|
||||||
.TH "SALT-PROXY" "1" "May 09, 2018" "2018.3.1" "Salt"
|
.TH "SALT-PROXY" "1" "Jun 14, 2018" "2018.3.2" "Salt"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
salt-proxy \- salt-proxy Documentation
|
salt-proxy \- salt-proxy Documentation
|
||||||
.
|
.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
.\" Man page generated from reStructuredText.
|
.\" Man page generated from reStructuredText.
|
||||||
.
|
.
|
||||||
.TH "SALT-RUN" "1" "May 09, 2018" "2018.3.1" "Salt"
|
.TH "SALT-RUN" "1" "Jun 14, 2018" "2018.3.2" "Salt"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
salt-run \- salt-run Documentation
|
salt-run \- salt-run Documentation
|
||||||
.
|
.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
.\" Man page generated from reStructuredText.
|
.\" Man page generated from reStructuredText.
|
||||||
.
|
.
|
||||||
.TH "SALT-SSH" "1" "May 09, 2018" "2018.3.1" "Salt"
|
.TH "SALT-SSH" "1" "Jun 14, 2018" "2018.3.2" "Salt"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
salt-ssh \- salt-ssh Documentation
|
salt-ssh \- salt-ssh Documentation
|
||||||
.
|
.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
.\" Man page generated from reStructuredText.
|
.\" Man page generated from reStructuredText.
|
||||||
.
|
.
|
||||||
.TH "SALT-SYNDIC" "1" "May 09, 2018" "2018.3.1" "Salt"
|
.TH "SALT-SYNDIC" "1" "Jun 14, 2018" "2018.3.2" "Salt"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
salt-syndic \- salt-syndic Documentation
|
salt-syndic \- salt-syndic Documentation
|
||||||
.
|
.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
.\" Man page generated from reStructuredText.
|
.\" Man page generated from reStructuredText.
|
||||||
.
|
.
|
||||||
.TH "SALT-UNITY" "1" "May 09, 2018" "2018.3.1" "Salt"
|
.TH "SALT-UNITY" "1" "Jun 14, 2018" "2018.3.2" "Salt"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
salt-unity \- salt-unity Command
|
salt-unity \- salt-unity Command
|
||||||
.
|
.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
.\" Man page generated from reStructuredText.
|
.\" Man page generated from reStructuredText.
|
||||||
.
|
.
|
||||||
.TH "SALT" "1" "May 09, 2018" "2018.3.1" "Salt"
|
.TH "SALT" "1" "Jun 14, 2018" "2018.3.2" "Salt"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
salt \- salt
|
salt \- salt
|
||||||
.
|
.
|
||||||
|
7897
doc/man/salt.7
7897
doc/man/salt.7
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
|||||||
.\" Man page generated from reStructuredText.
|
.\" Man page generated from reStructuredText.
|
||||||
.
|
.
|
||||||
.TH "SPM" "1" "May 09, 2018" "2018.3.1" "Salt"
|
.TH "SPM" "1" "Jun 14, 2018" "2018.3.2" "Salt"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
spm \- Salt Package Manager Command
|
spm \- Salt Package Manager Command
|
||||||
.
|
.
|
||||||
|
@ -5054,6 +5054,21 @@ https://github.com/ytoolshed/range/wiki/%22yamlfile%22-module-file-spec
|
|||||||
Include Configuration
|
Include Configuration
|
||||||
=====================
|
=====================
|
||||||
|
|
||||||
|
Configuration can be loaded from multiple files. The order in which this is
|
||||||
|
done is:
|
||||||
|
|
||||||
|
1. The master config file itself
|
||||||
|
|
||||||
|
2. The files matching the glob in :conf_master:`default_include`
|
||||||
|
|
||||||
|
3. The files matching the glob in :conf_master:`include` (if defined)
|
||||||
|
|
||||||
|
Each successive step overrides any values defined in the previous steps.
|
||||||
|
Therefore, any config options defined in one of the
|
||||||
|
:conf_master:`default_include` files would override the same value in the
|
||||||
|
master config file, and any options defined in :conf_master:`include` would
|
||||||
|
override both.
|
||||||
|
|
||||||
.. conf_master:: default_include
|
.. conf_master:: default_include
|
||||||
|
|
||||||
``default_include``
|
``default_include``
|
||||||
|
@ -2928,7 +2928,22 @@ at the moment a single state fails
|
|||||||
Include Configuration
|
Include Configuration
|
||||||
=====================
|
=====================
|
||||||
|
|
||||||
.. conf_minion:: include
|
Configuration can be loaded from multiple files. The order in which this is
|
||||||
|
done is:
|
||||||
|
|
||||||
|
1. The minion config file itself
|
||||||
|
|
||||||
|
2. The files matching the glob in :conf_minion:`default_include`
|
||||||
|
|
||||||
|
3. The files matching the glob in :conf_minion:`include` (if defined)
|
||||||
|
|
||||||
|
Each successive step overrides any values defined in the previous steps.
|
||||||
|
Therefore, any config options defined in one of the
|
||||||
|
:conf_minion:`default_include` files would override the same value in the
|
||||||
|
minion config file, and any options defined in :conf_minion:`include` would
|
||||||
|
override both.
|
||||||
|
|
||||||
|
.. conf_minion:: default_include
|
||||||
|
|
||||||
``default_include``
|
``default_include``
|
||||||
-------------------
|
-------------------
|
||||||
@ -2946,6 +2961,7 @@ file.
|
|||||||
files are prefixed with an underscore. A common example of this is the
|
files are prefixed with an underscore. A common example of this is the
|
||||||
``_schedule.conf`` file.
|
``_schedule.conf`` file.
|
||||||
|
|
||||||
|
.. conf_minion:: include
|
||||||
|
|
||||||
``include``
|
``include``
|
||||||
-----------
|
-----------
|
||||||
|
@ -21,11 +21,21 @@ SaltStack has its own coding style guide that informs contributors on various co
|
|||||||
approaches. Please review the :ref:`Salt Coding Style <coding-style>` documentation
|
approaches. Please review the :ref:`Salt Coding Style <coding-style>` documentation
|
||||||
for information about Salt's particular coding patterns.
|
for information about Salt's particular coding patterns.
|
||||||
|
|
||||||
Within the :ref:`Salt Coding Style <coding-style>` documentation, there is a section
|
Within the :ref:`Salt Coding Style <coding-style>` documentation, there is a
|
||||||
about running Salt's ``.pylintrc`` file. SaltStack recommends running the ``.pylintrc``
|
section about running Salt's ``.testing.pylintrc`` file. SaltStack recommends
|
||||||
file on any files you are changing with your code contribution before submitting a
|
running the ``.testing.pylintrc`` file on any files you are changing with your
|
||||||
pull request to Salt's repository. Please see the :ref:`Linting<pylint-instructions>`
|
code contribution before submitting a pull request to Salt's repository. Please
|
||||||
documentation for more information.
|
see the :ref:`Linting<pylint-instructions>` documentation for more information.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
There are two pylint files in the ``salt`` directory. One is the
|
||||||
|
``.pylintrc`` file and the other is the ``.testing.pylintrc`` file. The
|
||||||
|
tests that run in Jenkins against GitHub Pull Requests use
|
||||||
|
``.testing.pylintrc``. The ``testing.pylintrc`` file is a little less
|
||||||
|
strict than the ``.pylintrc`` and is used to make it easier for contributors
|
||||||
|
to submit changes. The ``.pylintrc`` file can be used for linting, but the
|
||||||
|
``testing.pylintrc`` is the source of truth when submitting pull requests.
|
||||||
|
|
||||||
|
|
||||||
.. _github-pull-request:
|
.. _github-pull-request:
|
||||||
|
@ -22,21 +22,31 @@ improve Salt)!!
|
|||||||
Linting
|
Linting
|
||||||
=======
|
=======
|
||||||
|
|
||||||
Most Salt style conventions are codified in Salt's ``.pylintrc`` file. Salt's
|
Most Salt style conventions are codified in Salt's ``.testing.pylintrc`` file.
|
||||||
pylint file has two dependencies: pylint_ and saltpylint_. You can install
|
Salt's pylint file has two dependencies: pylint_ and saltpylint_. You can
|
||||||
these dependencies with ``pip``:
|
install these dependencies with ``pip``:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
pip install pylint
|
pip install pylint
|
||||||
pip install saltpylint
|
pip install saltpylint
|
||||||
|
|
||||||
The ``.pylintrc`` file is found in the root of the Salt project and can be passed
|
The ``.testing.pylintrc`` file is found in the root of the Salt project and can
|
||||||
as an argument to the pylint_ program as follows:
|
be passed as an argument to the pylint_ program as follows:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
pylint --rcfile=/path/to/salt/.pylintrc salt/dir/to/lint
|
pylint --rcfile=/path/to/salt/.testing.pylintrc salt/dir/to/lint
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
There are two pylint files in the ``salt`` directory. One is the
|
||||||
|
``.pylintrc`` file and the other is the ``.testing.pylintrc`` file. The
|
||||||
|
tests that run in Jenkins against GitHub Pull Requests use
|
||||||
|
``.testing.pylintrc``. The ``testing.pylintrc`` file is a little less
|
||||||
|
strict than the ``.pylintrc`` and is used to make it easier for contributors
|
||||||
|
to submit changes. The ``.pylintrc`` file can be used for linting, but the
|
||||||
|
``testing.pylintrc`` is the source of truth when submitting pull requests.
|
||||||
|
|
||||||
.. _pylint: http://www.pylint.org
|
.. _pylint: http://www.pylint.org
|
||||||
.. _saltpylint: https://github.com/saltstack/salt-pylint
|
.. _saltpylint: https://github.com/saltstack/salt-pylint
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
.. _event-system:
|
||||||
|
|
||||||
============
|
============
|
||||||
Event System
|
Event System
|
||||||
============
|
============
|
||||||
@ -12,8 +14,8 @@ Event Bus
|
|||||||
The event system is comprised of a two primary components, which make up the
|
The event system is comprised of a two primary components, which make up the
|
||||||
concept of an Event Bus:
|
concept of an Event Bus:
|
||||||
|
|
||||||
* The event sockets which publishes events.
|
- The event sockets, which publish events
|
||||||
* The event library which can listen to events and send events into the salt system.
|
- The event library, which can listen to events and send events into the salt system
|
||||||
|
|
||||||
Events are published onto the event bus and event bus subscribers listen for the
|
Events are published onto the event bus and event bus subscribers listen for the
|
||||||
published events.
|
published events.
|
||||||
@ -237,4 +239,4 @@ done at the CLI:
|
|||||||
'success': True,
|
'success': True,
|
||||||
'message': "It works!",
|
'message': "It works!",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -886,6 +886,10 @@ Example:
|
|||||||
encoding (usually a ``unicode`` type). This filter was incorrectly-named
|
encoding (usually a ``unicode`` type). This filter was incorrectly-named
|
||||||
when it was added. ``json_decode_list`` will be supported until the Neon
|
when it was added. ``json_decode_list`` will be supported until the Neon
|
||||||
release.
|
release.
|
||||||
|
.. deprecated:: 2018.3.3,Fluorine
|
||||||
|
The :jinja_ref:`tojson` filter accomplishes what this filter was designed
|
||||||
|
to do, making this filter redundant.
|
||||||
|
|
||||||
|
|
||||||
Recursively encodes all string elements of the list to bytes.
|
Recursively encodes all string elements of the list to bytes.
|
||||||
|
|
||||||
@ -915,6 +919,9 @@ Returns:
|
|||||||
encoding (usually a ``unicode`` type). This filter was incorrectly-named
|
encoding (usually a ``unicode`` type). This filter was incorrectly-named
|
||||||
when it was added. ``json_decode_dict`` will be supported until the Neon
|
when it was added. ``json_decode_dict`` will be supported until the Neon
|
||||||
release.
|
release.
|
||||||
|
.. deprecated:: 2018.3.3,Fluorine
|
||||||
|
The :jinja_ref:`tojson` filter accomplishes what this filter was designed
|
||||||
|
to do, making this filter redundant.
|
||||||
|
|
||||||
Recursively encodes all string items in the dictionary to bytes.
|
Recursively encodes all string items in the dictionary to bytes.
|
||||||
|
|
||||||
@ -934,6 +941,22 @@ Returns:
|
|||||||
{'a': '\xd0\x94'}
|
{'a': '\xd0\x94'}
|
||||||
|
|
||||||
|
|
||||||
|
.. jinja_ref:: tojson
|
||||||
|
|
||||||
|
``tojson``
|
||||||
|
----------
|
||||||
|
|
||||||
|
.. versionadded:: 2018.3.3,Fluorine
|
||||||
|
|
||||||
|
Dumps a data structure to JSON.
|
||||||
|
|
||||||
|
This filter was added to provide this functionality to hosts which have a
|
||||||
|
Jinja release older than version 2.9 installed. If Jinja 2.9 or newer is
|
||||||
|
installed, then the upstream version of the filter will be used. See the
|
||||||
|
`upstream docs`__ for more information.
|
||||||
|
|
||||||
|
.. __: http://jinja.pocoo.org/docs/2.10/templates/#tojson
|
||||||
|
|
||||||
.. jinja_ref:: random_hash
|
.. jinja_ref:: random_hash
|
||||||
|
|
||||||
``random_hash``
|
``random_hash``
|
||||||
@ -1125,6 +1148,40 @@ Returns:
|
|||||||
}'
|
}'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.. jinja_ref:: traverse
|
||||||
|
|
||||||
|
``traverse``
|
||||||
|
------------
|
||||||
|
|
||||||
|
.. versionadded:: 2018.3.3
|
||||||
|
|
||||||
|
Traverse a dict or list using a colon-delimited target string.
|
||||||
|
The target 'foo:bar:0' will return data['foo']['bar'][0] if this value exists,
|
||||||
|
and will otherwise return the provided default value.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
.. code-block:: jinja
|
||||||
|
|
||||||
|
{{ {'a1': {'b1': {'c1': 'foo'}}, 'a2': 'bar'} | traverse('a1:b1', 'default') }}
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
{'c1': 'foo'}
|
||||||
|
|
||||||
|
.. code-block:: jinja
|
||||||
|
|
||||||
|
{{ {'a1': {'b1': {'c1': 'foo'}}, 'a2': 'bar'} | traverse('a2:b2', 'default') }}
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
'default'
|
||||||
|
|
||||||
.. _`builtin filters`: http://jinja.pocoo.org/docs/templates/#builtin-filters
|
.. _`builtin filters`: http://jinja.pocoo.org/docs/templates/#builtin-filters
|
||||||
.. _`timelib`: https://github.com/pediapress/timelib/
|
.. _`timelib`: https://github.com/pediapress/timelib/
|
||||||
|
|
||||||
|
@ -15,6 +15,23 @@ Statistics
|
|||||||
- Contributors: **52** (`Ch3LL`_, `DmitryKuzmenko`_, `GwiYeong`_, `L4rS6`_, `SteffenKockel`_, `The-Loeki`_, `amendlik`_, `andreaspe`_, `angeloudy`_, `aphor`_, `bdrung`_, `cebe`_, `ciiqr`_, `damon-atkins`_, `danlsgiga`_, `ddoh94`_, `dmurphy18`_, `dwoz`_, `eliasp`_, `frogunder`_, `garethgreenaway`_, `gclinch`_, `gtmanfred`_, `jfindlay`_, `kstreee`_, `marccardinal`_, `mcalmer`_, `mchugh19`_, `meaksh`_, `michelsen`_, `nullify005`_, `oarmstrong`_, `oeuftete`_, `philpep`_, `racker-markh`_, `rallytime`_, `redbaron4`_, `roaldnefs`_, `rongshengfang`_, `rongzeng54`_, `rrroo`_, `samilaine`_, `samodid`_, `skizunov`_, `terminalmage`_, `tintoy`_, `twangboy`_, `viktordaniel`_, `vutny`_, `while0pass`_, `whytewolf`_, `zer0def`_)
|
- Contributors: **52** (`Ch3LL`_, `DmitryKuzmenko`_, `GwiYeong`_, `L4rS6`_, `SteffenKockel`_, `The-Loeki`_, `amendlik`_, `andreaspe`_, `angeloudy`_, `aphor`_, `bdrung`_, `cebe`_, `ciiqr`_, `damon-atkins`_, `danlsgiga`_, `ddoh94`_, `dmurphy18`_, `dwoz`_, `eliasp`_, `frogunder`_, `garethgreenaway`_, `gclinch`_, `gtmanfred`_, `jfindlay`_, `kstreee`_, `marccardinal`_, `mcalmer`_, `mchugh19`_, `meaksh`_, `michelsen`_, `nullify005`_, `oarmstrong`_, `oeuftete`_, `philpep`_, `racker-markh`_, `rallytime`_, `redbaron4`_, `roaldnefs`_, `rongshengfang`_, `rongzeng54`_, `rrroo`_, `samilaine`_, `samodid`_, `skizunov`_, `terminalmage`_, `tintoy`_, `twangboy`_, `viktordaniel`_, `vutny`_, `while0pass`_, `whytewolf`_, `zer0def`_)
|
||||||
|
|
||||||
|
|
||||||
|
Changes to :py:func:`file.blockreplace <salt.states.file.blockreplace>` State
|
||||||
|
=============================================================================
|
||||||
|
|
||||||
|
The ``append_newline`` argument was added to this state. Additionally, to
|
||||||
|
improve idempotence, if the string represented by ``marker_end`` is found in
|
||||||
|
the middle of the line, the content preceding the marker will be removed when
|
||||||
|
the block is replaced. This allows one to remove ``append_newline: False`` from
|
||||||
|
the SLS and have the block properly replaced if the end of the content block is
|
||||||
|
immediately followed by the ``marker_end`` (i.e. no newline before the marker).
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
This will require changes to your SLS if your ``marker_end`` does not
|
||||||
|
include the very beginning of the content you want to keep.
|
||||||
|
|
||||||
|
See the :py:func:`file.blockreplace <salt.states.file.blockreplace>` state
|
||||||
|
documentation for further information.
|
||||||
|
|
||||||
Changelog for v2017.7.4..v2017.7.5
|
Changelog for v2017.7.4..v2017.7.5
|
||||||
==================================
|
==================================
|
||||||
|
|
||||||
|
@ -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>`.
|
Version 2017.7.7 is a bugfix release for :ref:`2017.7.0 <release-2017-7-0>`.
|
||||||
This release is still in progress and has not been released yet.
|
|
||||||
|
|
||||||
The ``2017.7.7`` release contains only a single fix for Issue `#48038`_, which
|
The ``2017.7.7`` release contains only a small number of fixes, which are detailed
|
||||||
is a critical bug that occurs in a multi-syndic setup where the same job is run
|
below.
|
||||||
multiple times on a minion.
|
|
||||||
|
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
|
Statistics
|
||||||
==========
|
==========
|
||||||
|
|
||||||
- Total Merges: **1**
|
- Total Merges: **5**
|
||||||
- Total Issue References: **1**
|
- Total Issue References: **2**
|
||||||
- Total PR References: **2**
|
- Total PR References: **6**
|
||||||
|
|
||||||
- Contributors: **2** (`garethgreenaway`_, `rallytime`_)
|
- Contributors: **3** (`garethgreenaway`_, `gtmanfred`_, `rallytime`_)
|
||||||
|
|
||||||
Changelog for v2017.7.6..v2017.7.7
|
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`_)
|
* **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
|
.. _`#48038`: https://github.com/saltstack/salt/issues/48038
|
||||||
.. _`#48075`: https://github.com/saltstack/salt/pull/48075
|
.. _`#48075`: https://github.com/saltstack/salt/pull/48075
|
||||||
.. _`#48098`: https://github.com/saltstack/salt/pull/48098
|
.. _`#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
|
.. _`austinpapp`: https://github.com/austinpapp
|
||||||
.. _`garethgreenaway`: https://github.com/garethgreenaway
|
.. _`garethgreenaway`: https://github.com/garethgreenaway
|
||||||
|
.. _`gtmanfred`: https://github.com/gtmanfred
|
||||||
.. _`rallytime`: https://github.com/rallytime
|
.. _`rallytime`: https://github.com/rallytime
|
||||||
|
.. _`rmarchei`: https://github.com/rmarchei
|
||||||
|
@ -43,6 +43,23 @@ replaced with ``--update-roster``, which will enable salt-ssh to add minions
|
|||||||
to the flat roster file. This behavior can also be enabled by setting
|
to the flat roster file. This behavior can also be enabled by setting
|
||||||
``ssh_update_roster: True`` in the master config file.
|
``ssh_update_roster: True`` in the master config file.
|
||||||
|
|
||||||
|
Changes to :py:func:`file.blockreplace <salt.states.file.blockreplace>` State
|
||||||
|
=============================================================================
|
||||||
|
|
||||||
|
The ``append_newline`` argument was added to this state. Additionally, to
|
||||||
|
improve idempotence, if the string represented by ``marker_end`` is found in
|
||||||
|
the middle of the line, the content preceding the marker will be removed when
|
||||||
|
the block is replaced. This allows one to remove ``append_newline: False`` from
|
||||||
|
the SLS and have the block properly replaced if the end of the content block is
|
||||||
|
immediately followed by the ``marker_end`` (i.e. no newline before the marker).
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
This will require changes to your SLS if your ``marker_end`` does not
|
||||||
|
include the very beginning of the content you want to keep.
|
||||||
|
|
||||||
|
See the :py:func:`file.blockreplace <salt.states.file.blockreplace>` state
|
||||||
|
documentation for further information.
|
||||||
|
|
||||||
Changelog for v2018.3.0..v2018.3.1
|
Changelog for v2018.3.0..v2018.3.1
|
||||||
==================================
|
==================================
|
||||||
|
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
========================================
|
===========================
|
||||||
In Progress: Salt 2018.3.2 Release Notes
|
Salt 2018.3.2 Release Notes
|
||||||
========================================
|
===========================
|
||||||
|
|
||||||
Version 2018.3.2 is an **unreleased** bugfix release for :ref:`2018.3.0 <release-2018-3-0>`.
|
Version 2018.3.2 is a bugfix release for :ref:`2018.3.0 <release-2018-3-0>`.
|
||||||
This release is still in progress and has not been released yet.
|
|
||||||
|
|
||||||
The ``2018.3.2`` release contains only a small number of fixes, which are detailed
|
The ``2018.3.2`` release contains only a small number of fixes, which are detailed
|
||||||
below.
|
below.
|
||||||
|
@ -14,3 +14,20 @@ Improves timezone detection by using the pytz module.
|
|||||||
|
|
||||||
Adds ``timezone.list`` to list supported timezones in either Windows or Unix
|
Adds ``timezone.list`` to list supported timezones in either Windows or Unix
|
||||||
format.
|
format.
|
||||||
|
|
||||||
|
New Jinja Filter
|
||||||
|
================
|
||||||
|
|
||||||
|
The :jinja_ref:`tojson` filter (from Jinja 2.9 and later) has been ported to
|
||||||
|
Salt, and will be used when this filter is not available. This allows older LTS
|
||||||
|
releases such as CentOS 7 and Ubuntu 14.04 to use this filter.
|
||||||
|
|
||||||
|
You should use this filter any time you wish to dump a list or dictionary into
|
||||||
|
an SLS file, to ensure that the result is able to be loaded by the YAML
|
||||||
|
renderer. For example:
|
||||||
|
|
||||||
|
.. code-block:: jinja
|
||||||
|
|
||||||
|
foo:
|
||||||
|
bar.baz:
|
||||||
|
- some_arg: {{ mydict|tojson }}
|
||||||
|
@ -330,7 +330,13 @@ Nested pillar values can also be set via the command line:
|
|||||||
|
|
||||||
.. code-block:: bash
|
.. 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::
|
.. note::
|
||||||
|
|
||||||
|
@ -139,13 +139,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.
|
<all-salt.output>`/returner, as well as an execution module.
|
||||||
|
|
||||||
Utility modules placed in ``salt://_utils/`` will be synced to the minions when
|
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_>`
|
* :py:func:`saltutil.sync_utils <salt.modules.saltutil.sync_utils>`
|
||||||
* :mod:`saltutil.sync_utils <salt.modules.saltutil.sync_utils>`
|
* :py:func:`saltutil.sync_all <salt.modules.saltutil.sync_all>`
|
||||||
* :mod:`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:
|
To sync to the Master, use either of the following:
|
||||||
|
|
||||||
* :mod:`saltutil.sync_utils <salt.runners.saltutil.sync_utils>`
|
* :py:func:`saltutil.sync_utils <salt.runners.saltutil.sync_utils>`
|
||||||
* :mod:`saltutil.sync_all <salt.runners.saltutil.sync_all>`
|
* :py:func:`saltutil.sync_all <salt.runners.saltutil.sync_all>`
|
||||||
|
@ -130,20 +130,18 @@ If Defined ProgramFiles(x86) (
|
|||||||
)
|
)
|
||||||
@echo.
|
@echo.
|
||||||
|
|
||||||
@echo Copying VCRedist to Prerequisites
|
|
||||||
@echo ----------------------------------------------------------------------
|
|
||||||
:: Make sure the "prereq" directory exists
|
:: Make sure the "prereq" directory exists
|
||||||
If NOT Exist "%PreDir%" mkdir "%PreDir%"
|
If NOT Exist "%PreDir%" mkdir "%PreDir%"
|
||||||
|
|
||||||
:: Set the location of the vcredist to download
|
:: Don't include the vcredist for Py3 installations
|
||||||
If %Python%==3 (
|
If %Python%==3 goto :vcredist_end
|
||||||
Set Url64="http://repo.saltstack.com/windows/dependencies/64/vcredist_x64_2015.exe"
|
|
||||||
Set Url32="http://repo.saltstack.com/windows/dependencies/32/vcredist_x86_2015.exe"
|
|
||||||
|
|
||||||
) Else (
|
@echo Copying VCRedist to Prerequisites
|
||||||
Set Url64="http://repo.saltstack.com/windows/dependencies/64/vcredist_x64_2008_mfc.exe"
|
@echo ----------------------------------------------------------------------
|
||||||
Set Url32="http://repo.saltstack.com/windows/dependencies/32/vcredist_x86_2008_mfc.exe"
|
|
||||||
)
|
:: Set the location of the vcredist to download
|
||||||
|
Set Url64="http://repo.saltstack.com/windows/dependencies/64/vcredist_x64_2008_mfc.exe"
|
||||||
|
Set Url32="http://repo.saltstack.com/windows/dependencies/32/vcredist_x86_2008_mfc.exe"
|
||||||
|
|
||||||
:: Check for 64 bit by finding the Program Files (x86) directory
|
:: Check for 64 bit by finding the Program Files (x86) directory
|
||||||
If Defined ProgramFiles(x86) (
|
If Defined ProgramFiles(x86) (
|
||||||
@ -153,6 +151,8 @@ If Defined ProgramFiles(x86) (
|
|||||||
)
|
)
|
||||||
@echo.
|
@echo.
|
||||||
|
|
||||||
|
:vcredist_end
|
||||||
|
|
||||||
:: Remove the fixed path in .exe files
|
:: Remove the fixed path in .exe files
|
||||||
@echo Removing fixed path from .exe files
|
@echo Removing fixed path from .exe files
|
||||||
@echo ----------------------------------------------------------------------
|
@echo ----------------------------------------------------------------------
|
||||||
|
@ -415,26 +415,13 @@ Section -Prerequisites
|
|||||||
Var /Global CheckVcRedist
|
Var /Global CheckVcRedist
|
||||||
StrCpy $CheckVcRedist "False"
|
StrCpy $CheckVcRedist "False"
|
||||||
|
|
||||||
# Visual C++ 2015 redist packages
|
|
||||||
!define PY3_VC_REDIST_NAME "VC_Redist_2015"
|
|
||||||
!define PY3_VC_REDIST_X64_GUID "{50A2BC33-C9CD-3BF1-A8FF-53C10A0B183C}"
|
|
||||||
!define PY3_VC_REDIST_X86_GUID "{BBF2AC74-720C-3CB3-8291-5E34039232FA}"
|
|
||||||
|
|
||||||
# Visual C++ 2008 SP1 MFC Security Update redist packages
|
# Visual C++ 2008 SP1 MFC Security Update redist packages
|
||||||
!define PY2_VC_REDIST_NAME "VC_Redist_2008_SP1_MFC"
|
!define PY2_VC_REDIST_NAME "VC_Redist_2008_SP1_MFC"
|
||||||
!define PY2_VC_REDIST_X64_GUID "{5FCE6D76-F5DC-37AB-B2B8-22AB8CEDB1D4}"
|
!define PY2_VC_REDIST_X64_GUID "{5FCE6D76-F5DC-37AB-B2B8-22AB8CEDB1D4}"
|
||||||
!define PY2_VC_REDIST_X86_GUID "{9BE518E6-ECC6-35A9-88E4-87755C07200F}"
|
!define PY2_VC_REDIST_X86_GUID "{9BE518E6-ECC6-35A9-88E4-87755C07200F}"
|
||||||
|
|
||||||
${If} ${PYTHON_VERSION} == 3
|
# VCRedist only needs to be installed for Python 2
|
||||||
StrCpy $VcRedistName ${PY3_VC_REDIST_NAME}
|
${If} ${PYTHON_VERSION} == 2
|
||||||
${If} ${CPUARCH} == "AMD64"
|
|
||||||
StrCpy $VcRedistGuid ${PY3_VC_REDIST_X64_GUID}
|
|
||||||
${Else}
|
|
||||||
StrCpy $VcRedistGuid ${PY3_VC_REDIST_X86_GUID}
|
|
||||||
${EndIf}
|
|
||||||
StrCpy $CheckVcRedist "True"
|
|
||||||
|
|
||||||
${Else}
|
|
||||||
|
|
||||||
StrCpy $VcRedistName ${PY2_VC_REDIST_NAME}
|
StrCpy $VcRedistName ${PY2_VC_REDIST_NAME}
|
||||||
${If} ${CPUARCH} == "AMD64"
|
${If} ${CPUARCH} == "AMD64"
|
||||||
|
@ -77,6 +77,7 @@ Function Get-Settings {
|
|||||||
"SSLeay" = "ssleay32.dll"
|
"SSLeay" = "ssleay32.dll"
|
||||||
"OpenSSLLic" = "OpenSSL_License.txt"
|
"OpenSSLLic" = "OpenSSL_License.txt"
|
||||||
"msvcr" = "msvcr120.dll"
|
"msvcr" = "msvcr120.dll"
|
||||||
|
"Libsodium" = "libsodium.dll"
|
||||||
}
|
}
|
||||||
$ini.Add("64bitDLLs", $64bitDLLs)
|
$ini.Add("64bitDLLs", $64bitDLLs)
|
||||||
|
|
||||||
@ -86,6 +87,7 @@ Function Get-Settings {
|
|||||||
"SSLeay" = "ssleay32.dll"
|
"SSLeay" = "ssleay32.dll"
|
||||||
"OpenSSLLic" = "OpenSSL_License.txt"
|
"OpenSSLLic" = "OpenSSL_License.txt"
|
||||||
"msvcr" = "msvcr120.dll"
|
"msvcr" = "msvcr120.dll"
|
||||||
|
"Libsodium" = "libsodium.dll"
|
||||||
}
|
}
|
||||||
$ini.Add("32bitDLLs", $32bitDLLs)
|
$ini.Add("32bitDLLs", $32bitDLLs)
|
||||||
|
|
||||||
|
@ -9,34 +9,36 @@ salt for Windows with their corresponding licenses:
|
|||||||
| certifi | ISC |
|
| certifi | ISC |
|
||||||
| cffi | MIT |
|
| cffi | MIT |
|
||||||
| CherryPy | BSD |
|
| CherryPy | BSD |
|
||||||
|
| cryptography | BSD |
|
||||||
| enum34 | BSD |
|
| enum34 | BSD |
|
||||||
| futures | BSD |
|
| futures | BSD |
|
||||||
| gitdb | BSD |
|
| gitdb | BSD |
|
||||||
| GitPython | BSD |
|
| GitPython | BSD |
|
||||||
| idna | BSD-like |
|
| idna | BSD-like |
|
||||||
| ioflo | Apache 2.0 |
|
|
||||||
| ioloop | MIT |
|
| ioloop | MIT |
|
||||||
| ipaddress | PSF |
|
| ipaddress | PSF |
|
||||||
| Jinja2 | BSD |
|
| Jinja2 | BSD |
|
||||||
| libnacl | --- |
|
| libnacl | Apache |
|
||||||
|
| lxml | BSD |
|
||||||
| Mako | MIT |
|
| Mako | MIT |
|
||||||
| MarkupSafe | BSD |
|
| MarkupSafe | BSD |
|
||||||
| msgpack-python | --- |
|
| msgpack-python | Apache 2.0 |
|
||||||
| pip | MIT |
|
| pip | MIT |
|
||||||
| psutil | BSD |
|
| psutil | BSD |
|
||||||
| pyasn1 | BSD |
|
| pyasn1 | BSD |
|
||||||
| pycparser | BSD |
|
| pycparser | BSD |
|
||||||
| pycurl | LGPL + MIT |
|
| pycurl | LGPL + MIT |
|
||||||
| PyMySQL | MIT |
|
| PyMySQL | MIT |
|
||||||
| pypiwin32 | PSF |
|
| PyOpenSSL | Apache 2.0 |
|
||||||
|
| python-certifi-win32 | BSD |
|
||||||
| python-dateutil | Simplified BSD |
|
| python-dateutil | Simplified BSD |
|
||||||
| python-gnupg | BSD |
|
| python-gnupg | BSD |
|
||||||
|
| pywin32 | PSF |
|
||||||
| PyYAML | MIT |
|
| PyYAML | MIT |
|
||||||
| pyzmq | LGPL + BSD |
|
| pyzmq | LGPL + BSD |
|
||||||
| requests | Apache 2.0 |
|
| requests | Apache 2.0 |
|
||||||
| setuptools | MIT |
|
| setuptools | MIT |
|
||||||
| singledispatch | MIT |
|
| singledispatch | MIT |
|
||||||
| six | MIT |
|
|
||||||
| smmap | BSD |
|
| smmap | BSD |
|
||||||
| timelib | ZLIB/PHP |
|
| timelib | ZLIB/PHP |
|
||||||
| tornado | Apache 2.0 |
|
| tornado | Apache 2.0 |
|
||||||
|
@ -12,6 +12,7 @@ idna==2.5
|
|||||||
ioloop==0.1a0
|
ioloop==0.1a0
|
||||||
ipaddress==1.0.18
|
ipaddress==1.0.18
|
||||||
Jinja2==2.9.6
|
Jinja2==2.9.6
|
||||||
|
libnacl==1.6.1 # required by the nacl module
|
||||||
lxml==3.7.3
|
lxml==3.7.3
|
||||||
Mako==1.0.6
|
Mako==1.0.6
|
||||||
MarkupSafe==1.0
|
MarkupSafe==1.0
|
||||||
@ -23,6 +24,7 @@ pycrypto==2.6.1
|
|||||||
pycurl==7.43.0
|
pycurl==7.43.0
|
||||||
PyMySQL==0.7.11
|
PyMySQL==0.7.11
|
||||||
pyOpenSSL==17.5.0
|
pyOpenSSL==17.5.0
|
||||||
|
#python-certifi-win32==1.2
|
||||||
python-dateutil==2.6.1
|
python-dateutil==2.6.1
|
||||||
python-gnupg==0.4.1
|
python-gnupg==0.4.1
|
||||||
pythonnet==2.3.0
|
pythonnet==2.3.0
|
||||||
|
@ -11,3 +11,4 @@ testinfra>=1.7.0
|
|||||||
# satisfy other requirements, and httpretty 0.8.10 has bugs in setup.py that
|
# 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).
|
# prevent it from being successfully installed (at least on Python 3.4).
|
||||||
httpretty; python_version >= '3.4'
|
httpretty; python_version >= '3.4'
|
||||||
|
pylint==1.6.5
|
||||||
|
@ -22,6 +22,7 @@ psutil
|
|||||||
pyvmomi
|
pyvmomi
|
||||||
setproctitle
|
setproctitle
|
||||||
cherrypy; sys.platform != 'win32' and sys.platform != 'darwin'
|
cherrypy; sys.platform != 'win32' and sys.platform != 'darwin'
|
||||||
|
ldap; sys.platform != 'win32' and sys.platform != 'darwin'
|
||||||
pyinotify; sys.platform != 'win32' and sys.platform != 'darwin'
|
pyinotify; sys.platform != 'win32' and sys.platform != 'darwin'
|
||||||
PyMySQL; sys.platform != 'win32' and sys.platform != 'darwin'
|
PyMySQL; sys.platform != 'win32' and sys.platform != 'darwin'
|
||||||
jsonschema
|
jsonschema
|
||||||
@ -34,3 +35,5 @@ dnspython
|
|||||||
SaltTesting==2017.6.1
|
SaltTesting==2017.6.1
|
||||||
junos-eznc
|
junos-eznc
|
||||||
jxmlease
|
jxmlease
|
||||||
|
croniter
|
||||||
|
kazoo
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
-r base.txt
|
-r base.txt
|
||||||
|
|
||||||
pycrypto>=2.6.1
|
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'
|
||||||
|
@ -83,13 +83,19 @@ def beacon(config):
|
|||||||
it will override the previously defined threshold.
|
it will override the previously defined threshold.
|
||||||
|
|
||||||
'''
|
'''
|
||||||
parts = psutil.disk_partitions(all=False)
|
parts = psutil.disk_partitions(all=True)
|
||||||
ret = []
|
ret = []
|
||||||
for mounts in config:
|
for mounts in config:
|
||||||
mount = next(iter(mounts))
|
mount = next(iter(mounts))
|
||||||
|
|
||||||
|
# Because we're using regular expressions
|
||||||
|
# if our mount doesn't end with a $, insert one.
|
||||||
|
mount_re = mount
|
||||||
|
if not mount.endswith('$'):
|
||||||
|
mount_re = '{0}$'.format(mount)
|
||||||
|
|
||||||
for part in parts:
|
for part in parts:
|
||||||
if re.match(mount, part.mountpoint):
|
if re.match(mount_re, part.mountpoint):
|
||||||
_mount = part.mountpoint
|
_mount = part.mountpoint
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -100,7 +106,7 @@ def beacon(config):
|
|||||||
|
|
||||||
current_usage = _current_usage.percent
|
current_usage = _current_usage.percent
|
||||||
monitor_usage = mounts[mount]
|
monitor_usage = mounts[mount]
|
||||||
log.info('current_usage %s', current_usage)
|
log.debug('current_usage %s', current_usage)
|
||||||
if '%' in monitor_usage:
|
if '%' in monitor_usage:
|
||||||
monitor_usage = re.sub('%', '', monitor_usage)
|
monitor_usage = re.sub('%', '', monitor_usage)
|
||||||
monitor_usage = float(monitor_usage)
|
monitor_usage = float(monitor_usage)
|
||||||
|
@ -11,6 +11,7 @@ import time
|
|||||||
|
|
||||||
# Import salt libs
|
# Import salt libs
|
||||||
import salt.utils.path
|
import salt.utils.path
|
||||||
|
import salt.utils.stringutils
|
||||||
import salt.utils.vt
|
import salt.utils.vt
|
||||||
|
|
||||||
__virtualname__ = 'sh'
|
__virtualname__ = 'sh'
|
||||||
@ -81,14 +82,14 @@ def beacon(config):
|
|||||||
stream_stdout=False,
|
stream_stdout=False,
|
||||||
stream_stderr=False)
|
stream_stderr=False)
|
||||||
__context__[pkey][pid]['user'] = ps_out[pid].get('user')
|
__context__[pkey][pid]['user'] = ps_out[pid].get('user')
|
||||||
for pid in __context__[pkey]:
|
for pid in list(__context__[pkey]):
|
||||||
out = ''
|
out = ''
|
||||||
err = ''
|
err = ''
|
||||||
while __context__[pkey][pid]['vt'].has_unread_data:
|
while __context__[pkey][pid]['vt'].has_unread_data:
|
||||||
tout, terr = __context__[pkey][pid]['vt'].recv()
|
tout, terr = __context__[pkey][pid]['vt'].recv()
|
||||||
if not terr:
|
if not terr:
|
||||||
break
|
break
|
||||||
out += tout
|
out += salt.utils.stringutils.to_unicode(tout or '')
|
||||||
err += terr
|
err += terr
|
||||||
for line in err.split('\n'):
|
for line in err.split('\n'):
|
||||||
event = {'args': [],
|
event = {'args': [],
|
||||||
|
8
salt/cache/mysql_cache.py
vendored
8
salt/cache/mysql_cache.py
vendored
@ -172,8 +172,12 @@ def store(bank, key, data):
|
|||||||
'''
|
'''
|
||||||
_init_client()
|
_init_client()
|
||||||
data = __context__['serial'].dumps(data)
|
data = __context__['serial'].dumps(data)
|
||||||
query = "REPLACE INTO {0} (bank, etcd_key, data) values('{1}', '{2}', " \
|
query = b"REPLACE INTO {0} (bank, etcd_key, data) values('{1}', '{2}', " \
|
||||||
"'{3}')".format(_table_name, bank, key, data)
|
b"'{3}')".format(_table_name,
|
||||||
|
bank,
|
||||||
|
key,
|
||||||
|
data)
|
||||||
|
|
||||||
cur, cnt = run_query(client, query)
|
cur, cnt = run_query(client, query)
|
||||||
cur.close()
|
cur.close()
|
||||||
if cnt not in (1, 2):
|
if cnt not in (1, 2):
|
||||||
|
@ -229,7 +229,7 @@ class LocalClient(object):
|
|||||||
# Looks like the timeout is invalid, use config
|
# Looks like the timeout is invalid, use config
|
||||||
return self.opts['timeout']
|
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
|
Return the information about a given job
|
||||||
'''
|
'''
|
||||||
@ -241,6 +241,7 @@ class LocalClient(object):
|
|||||||
arg=[jid],
|
arg=[jid],
|
||||||
tgt_type=tgt_type,
|
tgt_type=tgt_type,
|
||||||
timeout=timeout,
|
timeout=timeout,
|
||||||
|
listen=listen,
|
||||||
**kwargs
|
**kwargs
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -350,7 +350,9 @@ class SSH(object):
|
|||||||
return
|
return
|
||||||
|
|
||||||
hostname = self.opts['tgt'].split('@')[-1]
|
hostname = self.opts['tgt'].split('@')[-1]
|
||||||
needs_expansion = '*' not in hostname and salt.utils.network.is_reachable_host(hostname)
|
needs_expansion = '*' not in hostname and \
|
||||||
|
salt.utils.network.is_reachable_host(hostname) and \
|
||||||
|
salt.utils.network.is_ip(hostname)
|
||||||
if needs_expansion:
|
if needs_expansion:
|
||||||
hostname = salt.utils.network.ip_to_host(hostname)
|
hostname = salt.utils.network.ip_to_host(hostname)
|
||||||
if hostname is None:
|
if hostname is None:
|
||||||
@ -1245,7 +1247,10 @@ ARGS = {10}\n'''.format(self.minion_config,
|
|||||||
shim_tmp_file.write(salt.utils.stringutils.to_bytes(cmd_str))
|
shim_tmp_file.write(salt.utils.stringutils.to_bytes(cmd_str))
|
||||||
|
|
||||||
# Copy shim to target system, under $HOME/.<randomized name>
|
# 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:
|
if self.winrm:
|
||||||
target_shim_file = saltwinshell.get_target_shim_file(self, target_shim_file)
|
target_shim_file = saltwinshell.get_target_shim_file(self, target_shim_file)
|
||||||
self.shell.send(shim_tmp_file.name, target_shim_file, makedirs=True)
|
self.shell.send(shim_tmp_file.name, target_shim_file, makedirs=True)
|
||||||
|
@ -167,7 +167,7 @@ def salt_refs(data, ret=None):
|
|||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def prep_trans_tar(opts, file_client, chunks, file_refs, pillar=None, id_=None, roster_grains=None):
|
def prep_trans_tar(file_client, chunks, file_refs, pillar=None, id_=None, roster_grains=None):
|
||||||
'''
|
'''
|
||||||
Generate the execution package from the saltenv file refs and a low state
|
Generate the execution package from the saltenv file refs and a low state
|
||||||
data structure
|
data structure
|
||||||
|
@ -36,6 +36,59 @@ __func_alias__ = {
|
|||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def _ssh_state(chunks, st_kwargs,
|
||||||
|
kwargs, test=False):
|
||||||
|
'''
|
||||||
|
Function 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(
|
||||||
|
__context__['fileclient'],
|
||||||
|
chunks,
|
||||||
|
file_refs,
|
||||||
|
__pillar__,
|
||||||
|
st_kwargs['id_'])
|
||||||
|
trans_tar_sum = salt.utils.hashutils.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 salt.utils.data.decode(salt.utils.json.loads(stdout, object_hook=salt.utils.data.encode_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 salt.utils.data.decode(stdout)
|
||||||
|
|
||||||
|
|
||||||
def _set_retcode(ret, highstate=None):
|
def _set_retcode(ret, highstate=None):
|
||||||
'''
|
'''
|
||||||
Set the return code based on the data back from the state system
|
Set the return code based on the data back from the state system
|
||||||
@ -165,7 +218,6 @@ def sls(mods, saltenv='base', test=None, exclude=None, **kwargs):
|
|||||||
# Create the tar containing the state pkg and relevant files.
|
# Create the tar containing the state pkg and relevant files.
|
||||||
_cleanup_slsmod_low_data(chunks)
|
_cleanup_slsmod_low_data(chunks)
|
||||||
trans_tar = salt.client.ssh.state.prep_trans_tar(
|
trans_tar = salt.client.ssh.state.prep_trans_tar(
|
||||||
opts,
|
|
||||||
__context__['fileclient'],
|
__context__['fileclient'],
|
||||||
chunks,
|
chunks,
|
||||||
file_refs,
|
file_refs,
|
||||||
@ -310,7 +362,6 @@ def low(data, **kwargs):
|
|||||||
|
|
||||||
# Create the tar containing the state pkg and relevant files.
|
# Create the tar containing the state pkg and relevant files.
|
||||||
trans_tar = salt.client.ssh.state.prep_trans_tar(
|
trans_tar = salt.client.ssh.state.prep_trans_tar(
|
||||||
__opts__,
|
|
||||||
__context__['fileclient'],
|
__context__['fileclient'],
|
||||||
chunks,
|
chunks,
|
||||||
file_refs,
|
file_refs,
|
||||||
@ -401,7 +452,6 @@ def high(data, **kwargs):
|
|||||||
# Create the tar containing the state pkg and relevant files.
|
# Create the tar containing the state pkg and relevant files.
|
||||||
_cleanup_slsmod_low_data(chunks)
|
_cleanup_slsmod_low_data(chunks)
|
||||||
trans_tar = salt.client.ssh.state.prep_trans_tar(
|
trans_tar = salt.client.ssh.state.prep_trans_tar(
|
||||||
opts,
|
|
||||||
__context__['fileclient'],
|
__context__['fileclient'],
|
||||||
chunks,
|
chunks,
|
||||||
file_refs,
|
file_refs,
|
||||||
@ -647,7 +697,6 @@ def highstate(test=None, **kwargs):
|
|||||||
# Create the tar containing the state pkg and relevant files.
|
# Create the tar containing the state pkg and relevant files.
|
||||||
_cleanup_slsmod_low_data(chunks)
|
_cleanup_slsmod_low_data(chunks)
|
||||||
trans_tar = salt.client.ssh.state.prep_trans_tar(
|
trans_tar = salt.client.ssh.state.prep_trans_tar(
|
||||||
opts,
|
|
||||||
__context__['fileclient'],
|
__context__['fileclient'],
|
||||||
chunks,
|
chunks,
|
||||||
file_refs,
|
file_refs,
|
||||||
@ -730,7 +779,6 @@ def top(topfn, test=None, **kwargs):
|
|||||||
# Create the tar containing the state pkg and relevant files.
|
# Create the tar containing the state pkg and relevant files.
|
||||||
_cleanup_slsmod_low_data(chunks)
|
_cleanup_slsmod_low_data(chunks)
|
||||||
trans_tar = salt.client.ssh.state.prep_trans_tar(
|
trans_tar = salt.client.ssh.state.prep_trans_tar(
|
||||||
opts,
|
|
||||||
__context__['fileclient'],
|
__context__['fileclient'],
|
||||||
chunks,
|
chunks,
|
||||||
file_refs,
|
file_refs,
|
||||||
@ -849,6 +897,7 @@ def sls_id(id_, mods, test=None, queue=False, **kwargs):
|
|||||||
|
|
||||||
salt '*' state.sls_id my_state my_module,a_common_module
|
salt '*' state.sls_id my_state my_module,a_common_module
|
||||||
'''
|
'''
|
||||||
|
st_kwargs = __salt__.kwargs
|
||||||
conflict = _check_queue(queue, kwargs)
|
conflict = _check_queue(queue, kwargs)
|
||||||
if conflict is not None:
|
if conflict is not None:
|
||||||
return conflict
|
return conflict
|
||||||
@ -861,13 +910,11 @@ def sls_id(id_, mods, test=None, queue=False, **kwargs):
|
|||||||
if opts['saltenv'] is None:
|
if opts['saltenv'] is None:
|
||||||
opts['saltenv'] = 'base'
|
opts['saltenv'] = 'base'
|
||||||
|
|
||||||
try:
|
st_ = salt.client.ssh.state.SSHHighState(
|
||||||
st_ = salt.state.HighState(opts,
|
__opts__,
|
||||||
proxy=__proxy__,
|
__pillar__,
|
||||||
initial_pillar=_get_initial_pillar(opts))
|
__salt__,
|
||||||
except NameError:
|
__context__['fileclient'])
|
||||||
st_ = salt.state.HighState(opts,
|
|
||||||
initial_pillar=_get_initial_pillar(opts))
|
|
||||||
|
|
||||||
if not _check_pillar(kwargs, st_.opts['pillar']):
|
if not _check_pillar(kwargs, st_.opts['pillar']):
|
||||||
__context__['retcode'] = 5
|
__context__['retcode'] = 5
|
||||||
@ -878,10 +925,7 @@ def sls_id(id_, mods, test=None, queue=False, **kwargs):
|
|||||||
if isinstance(mods, six.string_types):
|
if isinstance(mods, six.string_types):
|
||||||
split_mods = mods.split(',')
|
split_mods = mods.split(',')
|
||||||
st_.push_active()
|
st_.push_active()
|
||||||
try:
|
high_, errors = st_.render_highstate({opts['saltenv']: split_mods})
|
||||||
high_, errors = st_.render_highstate({opts['saltenv']: split_mods})
|
|
||||||
finally:
|
|
||||||
st_.pop_active()
|
|
||||||
errors += st_.state.verify_high(high_)
|
errors += st_.state.verify_high(high_)
|
||||||
# Apply requisites to high data
|
# Apply requisites to high data
|
||||||
high_, req_in_errors = st_.state.requisite_in(high_)
|
high_, req_in_errors = st_.state.requisite_in(high_)
|
||||||
@ -893,17 +937,22 @@ def sls_id(id_, mods, test=None, queue=False, **kwargs):
|
|||||||
__context__['retcode'] = 1
|
__context__['retcode'] = 1
|
||||||
return errors
|
return errors
|
||||||
chunks = st_.state.compile_high_data(high_)
|
chunks = st_.state.compile_high_data(high_)
|
||||||
ret = {}
|
chunk = [x for x in chunks if x.get('__id__', '') == id_]
|
||||||
for chunk in chunks:
|
|
||||||
if chunk.get('__id__', '') == id_:
|
|
||||||
ret.update(st_.state.call_chunk(chunk, {}, chunks))
|
|
||||||
|
|
||||||
_set_retcode(ret, highstate=highstate)
|
if not chunk:
|
||||||
if not ret:
|
|
||||||
raise SaltInvocationError(
|
raise SaltInvocationError(
|
||||||
'No matches for ID \'{0}\' found in SLS \'{1}\' within saltenv '
|
'No matches for ID \'{0}\' found in SLS \'{1}\' within saltenv '
|
||||||
'\'{2}\''.format(id_, mods, opts['saltenv'])
|
'\'{2}\''.format(id_, mods, opts['saltenv'])
|
||||||
)
|
)
|
||||||
|
|
||||||
|
ret = _ssh_state(chunk,
|
||||||
|
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
|
return ret
|
||||||
|
|
||||||
|
|
||||||
@ -1093,7 +1142,6 @@ def single(fun, name, test=None, **kwargs):
|
|||||||
|
|
||||||
# Create the tar containing the state pkg and relevant files.
|
# Create the tar containing the state pkg and relevant files.
|
||||||
trans_tar = salt.client.ssh.state.prep_trans_tar(
|
trans_tar = salt.client.ssh.state.prep_trans_tar(
|
||||||
opts,
|
|
||||||
__context__['fileclient'],
|
__context__['fileclient'],
|
||||||
chunks,
|
chunks,
|
||||||
file_refs,
|
file_refs,
|
||||||
|
@ -372,7 +372,8 @@ def create(vm_):
|
|||||||
for iface_xml in domain_xml.findall('./devices/interface'):
|
for iface_xml in domain_xml.findall('./devices/interface'):
|
||||||
iface_xml.remove(iface_xml.find('./mac'))
|
iface_xml.remove(iface_xml.find('./mac'))
|
||||||
# enable IP learning, this might be a default behaviour...
|
# enable IP learning, this might be a default behaviour...
|
||||||
if iface_xml.find("./filterref/parameter[@name='CTRL_IP_LEARNING']") is None:
|
# Don't always enable since it can cause problems through libvirt-4.5
|
||||||
|
if ip_source == 'ip-learning' and iface_xml.find("./filterref/parameter[@name='CTRL_IP_LEARNING']") is None:
|
||||||
iface_xml.append(ElementTree.fromstring(IP_LEARNING_XML))
|
iface_xml.append(ElementTree.fromstring(IP_LEARNING_XML))
|
||||||
|
|
||||||
# If a qemu agent is defined we need to fix the path to its socket
|
# If a qemu agent is defined we need to fix the path to its socket
|
||||||
@ -422,7 +423,7 @@ def create(vm_):
|
|||||||
else:
|
else:
|
||||||
raise SaltCloudExecutionFailure("Disk type '{0}' not supported".format(disk_type))
|
raise SaltCloudExecutionFailure("Disk type '{0}' not supported".format(disk_type))
|
||||||
|
|
||||||
clone_xml = ElementTree.tostring(domain_xml)
|
clone_xml = salt.utils.stringutils.to_str(ElementTree.tostring(domain_xml))
|
||||||
log.debug("Clone XML '%s'", clone_xml)
|
log.debug("Clone XML '%s'", clone_xml)
|
||||||
|
|
||||||
validate_flags = libvirt.VIR_DOMAIN_DEFINE_VALIDATE if validate_xml else 0
|
validate_flags = libvirt.VIR_DOMAIN_DEFINE_VALIDATE if validate_xml else 0
|
||||||
@ -615,7 +616,7 @@ def create_volume_xml(volume):
|
|||||||
log.debug("Volume: %s", dir(volume))
|
log.debug("Volume: %s", dir(volume))
|
||||||
volume_xml.find('capacity').text = six.text_type(volume.info()[1])
|
volume_xml.find('capacity').text = six.text_type(volume.info()[1])
|
||||||
volume_xml.find('./target/path').text = volume.path()
|
volume_xml.find('./target/path').text = volume.path()
|
||||||
xml_string = ElementTree.tostring(volume_xml)
|
xml_string = salt.utils.stringutils.to_str(ElementTree.tostring(volume_xml))
|
||||||
log.debug("Creating %s", xml_string)
|
log.debug("Creating %s", xml_string)
|
||||||
return xml_string
|
return xml_string
|
||||||
|
|
||||||
@ -641,7 +642,7 @@ def create_volume_with_backing_store_xml(volume):
|
|||||||
log.debug("volume: %s", dir(volume))
|
log.debug("volume: %s", dir(volume))
|
||||||
volume_xml.find('capacity').text = six.text_type(volume.info()[1])
|
volume_xml.find('capacity').text = six.text_type(volume.info()[1])
|
||||||
volume_xml.find('./backingStore/path').text = volume.path()
|
volume_xml.find('./backingStore/path').text = volume.path()
|
||||||
xml_string = ElementTree.tostring(volume_xml)
|
xml_string = salt.utils.stringutils.to_str(ElementTree.tostring(volume_xml))
|
||||||
log.debug("Creating %s", xml_string)
|
log.debug("Creating %s", xml_string)
|
||||||
return xml_string
|
return xml_string
|
||||||
|
|
||||||
|
@ -206,8 +206,8 @@ def get_rsa_pub_key(path):
|
|||||||
'''
|
'''
|
||||||
log.debug('salt.crypt.get_rsa_pub_key: Loading public key')
|
log.debug('salt.crypt.get_rsa_pub_key: Loading public key')
|
||||||
if HAS_M2:
|
if HAS_M2:
|
||||||
with salt.utils.files.fopen(path) as f:
|
with salt.utils.files.fopen(path, 'rb') as f:
|
||||||
data = f.read().replace(b'RSA ', '')
|
data = f.read().replace(b'RSA ', b'')
|
||||||
bio = BIO.MemoryBuffer(data)
|
bio = BIO.MemoryBuffer(data)
|
||||||
key = RSA.load_pub_key_bio(bio)
|
key = RSA.load_pub_key_bio(bio)
|
||||||
else:
|
else:
|
||||||
@ -608,9 +608,17 @@ class AsyncAuth(object):
|
|||||||
error = SaltClientError('Detect mode is on')
|
error = SaltClientError('Detect mode is on')
|
||||||
break
|
break
|
||||||
if self.opts.get('caller'):
|
if self.opts.get('caller'):
|
||||||
print('Minion failed to authenticate with the master, '
|
# We have a list of masters, so we should break
|
||||||
'has the minion key been accepted?')
|
# and try the next one in the list.
|
||||||
sys.exit(2)
|
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:
|
if acceptance_wait_time:
|
||||||
log.info(
|
log.info(
|
||||||
'Waiting %s seconds before retry.', acceptance_wait_time
|
'Waiting %s seconds before retry.', acceptance_wait_time
|
||||||
|
@ -1,26 +1,84 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
'''
|
'''
|
||||||
An engine that reads messages from Slack and can act on them.
|
An engine that reads messages from Slack and can act on them
|
||||||
|
|
||||||
It has two major uses.
|
|
||||||
|
|
||||||
1. When the ``control`` parameter is set to ``True`` and a message is prefaced
|
|
||||||
with the ``trigger`` (which defaults to ``!``) then the engine will
|
|
||||||
validate that the user has permission, and if so will run the command
|
|
||||||
|
|
||||||
2. In addition, when the parameter ``fire_all`` is set (defaults to False),
|
|
||||||
all other messages (the messages that aren't control messages) will be
|
|
||||||
fired off to the salt event bus with the tag prefixed by the string
|
|
||||||
provided by the ``tag`` config option (defaults to ``salt/engines/slack``).
|
|
||||||
|
|
||||||
This allows for configuration to be gotten from either the engine config, or from
|
|
||||||
the saltmaster's minion pillar.
|
|
||||||
|
|
||||||
.. versionadded: 2016.3.0
|
.. versionadded: 2016.3.0
|
||||||
|
|
||||||
:configuration: Example configuration using only a 'default' group. The default
|
:depends: `slackclient <https://pypi.org/project/slackclient/>`_ Python module
|
||||||
group is not special. In addition, other groups are being loaded from
|
|
||||||
pillars.
|
.. important::
|
||||||
|
This engine requires a bot user. To create a bot user, first go to the
|
||||||
|
**Custom Integrations** page in your Slack Workspace. Copy and paste the
|
||||||
|
following URL, and replace ``myworkspace`` with the proper value for your
|
||||||
|
workspace:
|
||||||
|
|
||||||
|
``https://myworkspace.slack.com/apps/manage/custom-integrations``
|
||||||
|
|
||||||
|
Next, click on the ``Bots`` integration and request installation. Once
|
||||||
|
approved by an admin, you will be able to proceed with adding the bot user.
|
||||||
|
Once the bot user has been added, you can configure it by adding an avatar,
|
||||||
|
setting the display name, etc. You will also at this time have access to
|
||||||
|
your API token, which will be needed to configure this engine.
|
||||||
|
|
||||||
|
Finally, add this bot user to a channel by switching to the channel and
|
||||||
|
using ``/invite @mybotuser``. Keep in mind that this engine will process
|
||||||
|
messages from each channel in which the bot is a member, so it is
|
||||||
|
recommended to narrowly define the commands which can be executed, and the
|
||||||
|
Slack users which are allowed to run commands.
|
||||||
|
|
||||||
|
|
||||||
|
This engine has two boolean configuration parameters that toggle specific
|
||||||
|
features (both default to ``False``):
|
||||||
|
|
||||||
|
1. ``control`` - If set to ``True``, then any message which starts with the
|
||||||
|
trigger string (which defaults to ``!`` and can be overridden by setting the
|
||||||
|
``trigger`` option in the engine configuration) will be interpreted as a
|
||||||
|
Salt CLI command and the engine will attempt to run it. The permissions
|
||||||
|
defined in the various ``groups`` will determine if the Slack user is
|
||||||
|
allowed to run the command. The ``targets`` and ``default_target`` options
|
||||||
|
can be used to set targets for a given command, but the engine can also read
|
||||||
|
the following two keyword arguments:
|
||||||
|
|
||||||
|
- ``target`` - The target expression to use for the command
|
||||||
|
|
||||||
|
- ``tgt_type`` - The match type, can be one of ``glob``, ``list``,
|
||||||
|
``pcre``, ``grain``, ``grain_pcre``, ``pillar``, ``nodegroup``, ``range``,
|
||||||
|
``ipcidr``, or ``compound``. The default value is ``glob``.
|
||||||
|
|
||||||
|
Here are a few examples:
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
!test.ping target=*
|
||||||
|
!state.apply foo target=os:CentOS tgt_type=grain
|
||||||
|
!pkg.version mypkg target=role:database tgt_type=pillar
|
||||||
|
|
||||||
|
2. ``fire_all`` - If set to ``True``, all messages which are not prefixed with
|
||||||
|
the trigger string will fired as events onto Salt's ref:`event bus
|
||||||
|
<event-system>`. The tag for these veents will be prefixed with the string
|
||||||
|
specified by the ``tag`` config option (default: ``salt/engines/slack``).
|
||||||
|
|
||||||
|
|
||||||
|
The ``groups_pillar_name`` config option can be used to pull group
|
||||||
|
configuration from the specified pillar key.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
In order to use ``groups_pillar_name``, the engine must be running as a
|
||||||
|
minion running on the master, so that the ``Caller`` client can be used to
|
||||||
|
retrieve that minions pillar data, because the master process does not have
|
||||||
|
pillar data.
|
||||||
|
|
||||||
|
|
||||||
|
Configuration Examples
|
||||||
|
======================
|
||||||
|
|
||||||
|
.. versionchanged:: 2017.7.0
|
||||||
|
Access control group support added
|
||||||
|
|
||||||
|
This example uses a single group called ``default``. In addition, other groups
|
||||||
|
are being loaded from pillar data. The group names do not have any
|
||||||
|
significance, it is the users and commands defined within them that are used to
|
||||||
|
determine whether the Slack user has permission to run the desired command.
|
||||||
|
|
||||||
.. code-block:: text
|
.. code-block:: text
|
||||||
|
|
||||||
@ -33,7 +91,7 @@ the saltmaster's minion pillar.
|
|||||||
groups:
|
groups:
|
||||||
default:
|
default:
|
||||||
users:
|
users:
|
||||||
- *
|
- '*'
|
||||||
commands:
|
commands:
|
||||||
- test.ping
|
- test.ping
|
||||||
- cmd.run
|
- cmd.run
|
||||||
@ -55,12 +113,9 @@ the saltmaster's minion pillar.
|
|||||||
target: saltmaster
|
target: saltmaster
|
||||||
tgt_type: list
|
tgt_type: list
|
||||||
|
|
||||||
:configuration: Example configuration using the 'default' group and a
|
This example shows multiple groups applying to different users, with all users
|
||||||
non-default group and a pillar that will be merged in If the user is '*'
|
having access to run test.ping. Keep in mind that when using ``*``, the value
|
||||||
(without the quotes) then the group's users or commands will match all
|
must be quoted, or else PyYAML will fail to load the configuration.
|
||||||
users as appropriate
|
|
||||||
|
|
||||||
.. versionadded: 2017.7.0
|
|
||||||
|
|
||||||
.. code-block:: text
|
.. code-block:: text
|
||||||
|
|
||||||
@ -74,9 +129,9 @@ the saltmaster's minion pillar.
|
|||||||
groups_pillar_name: 'slack_engine:groups_pillar'
|
groups_pillar_name: 'slack_engine:groups_pillar'
|
||||||
groups:
|
groups:
|
||||||
default:
|
default:
|
||||||
valid_users:
|
users:
|
||||||
- *
|
- '*'
|
||||||
valid_commands:
|
commands:
|
||||||
- test.ping
|
- test.ping
|
||||||
aliases:
|
aliases:
|
||||||
list_jobs:
|
list_jobs:
|
||||||
@ -87,16 +142,7 @@ the saltmaster's minion pillar.
|
|||||||
users:
|
users:
|
||||||
- garethgreenaway
|
- garethgreenaway
|
||||||
commands:
|
commands:
|
||||||
- *
|
- '*'
|
||||||
|
|
||||||
:depends: slackclient
|
|
||||||
|
|
||||||
|
|
||||||
.. note:: groups_pillar_name
|
|
||||||
|
|
||||||
In order to use this, the engine must be running as a minion running on
|
|
||||||
the master, so that the ``Caller`` client can be used to retrieve that
|
|
||||||
minions pillar data, because the master process does not have pillars.
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
|
|
||||||
@ -330,7 +376,6 @@ class SlackClient(object):
|
|||||||
cmdlist.append(cmditem)
|
cmdlist.append(cmditem)
|
||||||
return cmdlist
|
return cmdlist
|
||||||
|
|
||||||
# m_data -> m_data, _text -> test, all_slack_users -> all_slack_users,
|
|
||||||
def control_message_target(self, slack_user_name, text, loaded_groups, trigger_string):
|
def control_message_target(self, slack_user_name, text, loaded_groups, trigger_string):
|
||||||
'''Returns a tuple of (target, cmdline,) for the response
|
'''Returns a tuple of (target, cmdline,) for the response
|
||||||
|
|
||||||
|
@ -129,8 +129,6 @@ def serve_file(load, fnd):
|
|||||||
with salt.utils.files.fopen(fpath, 'rb') as fp_:
|
with salt.utils.files.fopen(fpath, 'rb') as fp_:
|
||||||
fp_.seek(load['loc'])
|
fp_.seek(load['loc'])
|
||||||
data = fp_.read(__opts__['file_buffer_size'])
|
data = fp_.read(__opts__['file_buffer_size'])
|
||||||
if data and six.PY3 and not salt.utils.files.is_binary(fpath):
|
|
||||||
data = data.decode(__salt_system_encoding__)
|
|
||||||
if gzip and data:
|
if gzip and data:
|
||||||
data = salt.utils.gzip_util.compress(data, gzip)
|
data = salt.utils.gzip_util.compress(data, gzip)
|
||||||
ret['gzip'] = gzip
|
ret['gzip'] = gzip
|
||||||
|
@ -82,6 +82,10 @@ if salt.utils.platform.is_windows():
|
|||||||
'will be missing'
|
'will be missing'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
HAS_UNAME = True
|
||||||
|
if not hasattr(os, 'uname'):
|
||||||
|
HAS_UNAME = False
|
||||||
|
|
||||||
_INTERFACES = {}
|
_INTERFACES = {}
|
||||||
|
|
||||||
|
|
||||||
@ -448,7 +452,7 @@ def _osx_memdata():
|
|||||||
sysctl = salt.utils.path.which('sysctl')
|
sysctl = salt.utils.path.which('sysctl')
|
||||||
if sysctl:
|
if sysctl:
|
||||||
mem = __salt__['cmd.run']('{0} -n hw.memsize'.format(sysctl))
|
mem = __salt__['cmd.run']('{0} -n hw.memsize'.format(sysctl))
|
||||||
swap_total = __salt__['cmd.run']('{0} -n vm.swapusage'.format(sysctl)).split()[2]
|
swap_total = __salt__['cmd.run']('{0} -n vm.swapusage'.format(sysctl)).split()[2].replace(',', '.')
|
||||||
if swap_total.endswith('K'):
|
if swap_total.endswith('K'):
|
||||||
_power = 2**10
|
_power = 2**10
|
||||||
elif swap_total.endswith('M'):
|
elif swap_total.endswith('M'):
|
||||||
@ -689,7 +693,7 @@ def _virtual(osdata):
|
|||||||
|
|
||||||
# Quick backout for BrandZ (Solaris LX Branded zones)
|
# Quick backout for BrandZ (Solaris LX Branded zones)
|
||||||
# Don't waste time trying other commands to detect the virtual grain
|
# Don't waste time trying other commands to detect the virtual grain
|
||||||
if osdata['kernel'] == 'Linux' and 'BrandZ virtual linux' in os.uname():
|
if HAS_UNAME and osdata['kernel'] == 'Linux' and 'BrandZ virtual linux' in os.uname():
|
||||||
grains['virtual'] = 'zone'
|
grains['virtual'] = 'zone'
|
||||||
return grains
|
return grains
|
||||||
|
|
||||||
@ -947,7 +951,7 @@ def _virtual(osdata):
|
|||||||
if os.path.isfile('/sys/devices/virtual/dmi/id/product_name'):
|
if os.path.isfile('/sys/devices/virtual/dmi/id/product_name'):
|
||||||
try:
|
try:
|
||||||
with salt.utils.files.fopen('/sys/devices/virtual/dmi/id/product_name', 'r') as fhr:
|
with salt.utils.files.fopen('/sys/devices/virtual/dmi/id/product_name', 'r') as fhr:
|
||||||
output = salt.utils.stringutils.to_unicode(fhr.read())
|
output = salt.utils.stringutils.to_unicode(fhr.read(), errors='replace')
|
||||||
if 'VirtualBox' in output:
|
if 'VirtualBox' in output:
|
||||||
grains['virtual'] = 'VirtualBox'
|
grains['virtual'] = 'VirtualBox'
|
||||||
elif 'RHEV Hypervisor' in output:
|
elif 'RHEV Hypervisor' in output:
|
||||||
@ -1597,7 +1601,7 @@ def os_data():
|
|||||||
# my_init as pid1
|
# my_init as pid1
|
||||||
grains['init'] = 'runit'
|
grains['init'] = 'runit'
|
||||||
else:
|
else:
|
||||||
log.info(
|
log.debug(
|
||||||
'Could not determine init system from command line: (%s)',
|
'Could not determine init system from command line: (%s)',
|
||||||
' '.join(init_cmdline)
|
' '.join(init_cmdline)
|
||||||
)
|
)
|
||||||
@ -1780,7 +1784,10 @@ def os_data():
|
|||||||
elif grains['kernel'] == 'SunOS':
|
elif grains['kernel'] == 'SunOS':
|
||||||
if salt.utils.platform.is_smartos():
|
if salt.utils.platform.is_smartos():
|
||||||
# See https://github.com/joyent/smartos-live/issues/224
|
# See https://github.com/joyent/smartos-live/issues/224
|
||||||
uname_v = os.uname()[3] # format: joyent_20161101T004406Z
|
if HAS_UNAME:
|
||||||
|
uname_v = os.uname()[3] # format: joyent_20161101T004406Z
|
||||||
|
else:
|
||||||
|
uname_v = os.name
|
||||||
uname_v = uname_v[uname_v.index('_')+1:]
|
uname_v = uname_v[uname_v.index('_')+1:]
|
||||||
grains['os'] = grains['osfullname'] = 'SmartOS'
|
grains['os'] = grains['osfullname'] = 'SmartOS'
|
||||||
# store a parsed version of YYYY.MM.DD as osrelease
|
# store a parsed version of YYYY.MM.DD as osrelease
|
||||||
@ -1809,7 +1816,10 @@ def os_data():
|
|||||||
else:
|
else:
|
||||||
if development is not None:
|
if development is not None:
|
||||||
osname = ' '.join((osname, development))
|
osname = ' '.join((osname, development))
|
||||||
uname_v = os.uname()[3]
|
if HAS_UNAME:
|
||||||
|
uname_v = os.uname()[3]
|
||||||
|
else:
|
||||||
|
uname_v = os.name
|
||||||
grains['os'] = grains['osfullname'] = osname
|
grains['os'] = grains['osfullname'] = osname
|
||||||
if osname in ['Oracle Solaris'] and uname_v.startswith(osmajorrelease):
|
if osname in ['Oracle Solaris'] and uname_v.startswith(osmajorrelease):
|
||||||
# Oracla Solars 11 and up have minor version in uname
|
# Oracla Solars 11 and up have minor version in uname
|
||||||
@ -2288,7 +2298,7 @@ def _hw_data(osdata):
|
|||||||
if os.path.exists(contents_file):
|
if os.path.exists(contents_file):
|
||||||
try:
|
try:
|
||||||
with salt.utils.files.fopen(contents_file, 'r') as ifile:
|
with salt.utils.files.fopen(contents_file, 'r') as ifile:
|
||||||
grains[key] = ifile.read().strip()
|
grains[key] = salt.utils.stringutils.to_unicode(ifile.read().strip(), errors='replace')
|
||||||
if key == 'uuid':
|
if key == 'uuid':
|
||||||
grains['uuid'] = grains['uuid'].lower()
|
grains['uuid'] = grains['uuid'].lower()
|
||||||
except (IOError, OSError) as err:
|
except (IOError, OSError) as err:
|
||||||
|
@ -15,12 +15,14 @@ import inspect
|
|||||||
import tempfile
|
import tempfile
|
||||||
import functools
|
import functools
|
||||||
import threading
|
import threading
|
||||||
|
import traceback
|
||||||
import types
|
import types
|
||||||
from collections import MutableMapping
|
from collections import MutableMapping
|
||||||
from zipimport import zipimporter
|
from zipimport import zipimporter
|
||||||
|
|
||||||
# Import salt libs
|
# Import salt libs
|
||||||
import salt.config
|
import salt.config
|
||||||
|
import salt.defaults.exitcodes
|
||||||
import salt.syspaths
|
import salt.syspaths
|
||||||
import salt.utils.context
|
import salt.utils.context
|
||||||
import salt.utils.data
|
import salt.utils.data
|
||||||
@ -67,10 +69,10 @@ if USE_IMPORTLIB:
|
|||||||
SUFFIXES = []
|
SUFFIXES = []
|
||||||
for suffix in importlib.machinery.EXTENSION_SUFFIXES:
|
for suffix in importlib.machinery.EXTENSION_SUFFIXES:
|
||||||
SUFFIXES.append((suffix, 'rb', MODULE_KIND_EXTENSION))
|
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:
|
for suffix in importlib.machinery.SOURCE_SUFFIXES:
|
||||||
SUFFIXES.append((suffix, 'rb', MODULE_KIND_SOURCE))
|
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_MAP = {
|
||||||
MODULE_KIND_SOURCE: importlib.machinery.SourceFileLoader,
|
MODULE_KIND_SOURCE: importlib.machinery.SourceFileLoader,
|
||||||
MODULE_KIND_COMPILED: importlib.machinery.SourcelessFileLoader,
|
MODULE_KIND_COMPILED: importlib.machinery.SourcelessFileLoader,
|
||||||
@ -1480,6 +1482,17 @@ class LazyLoader(salt.utils.lazy.LazyDict):
|
|||||||
self.missing_modules[name] = error
|
self.missing_modules[name] = error
|
||||||
return False
|
return False
|
||||||
except SystemExit as error:
|
except SystemExit as error:
|
||||||
|
try:
|
||||||
|
fn_, _, caller, _ = traceback.extract_tb(sys.exc_info()[2])[-1]
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
tgt_fn = os.path.join('salt', 'utils', 'process.py')
|
||||||
|
if fn_.endswith(tgt_fn) and '_handle_signals' in caller:
|
||||||
|
# Race conditon, SIGTERM or SIGINT received while loader
|
||||||
|
# was in process of loading a module. Call sys.exit to
|
||||||
|
# ensure that the process is killed.
|
||||||
|
sys.exit(salt.defaults.exitcodes.EX_OK)
|
||||||
log.error(
|
log.error(
|
||||||
'Failed to import %s %s as the module called exit()\n',
|
'Failed to import %s %s as the module called exit()\n',
|
||||||
self.tag, name, exc_info=True
|
self.tag, name, exc_info=True
|
||||||
|
@ -359,13 +359,11 @@ class FileserverUpdate(salt.utils.process.SignalHandlingMultiprocessingProcess):
|
|||||||
self.__init__(
|
self.__init__(
|
||||||
state['opts'],
|
state['opts'],
|
||||||
log_queue=state['log_queue'],
|
log_queue=state['log_queue'],
|
||||||
log_queue_level=state['log_queue_level']
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def __getstate__(self):
|
def __getstate__(self):
|
||||||
return {'opts': self.opts,
|
return {'opts': self.opts,
|
||||||
'log_queue': self.log_queue,
|
'log_queue': self.log_queue,
|
||||||
'log_queue_level': self.log_queue_level
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def fill_buckets(self):
|
def fill_buckets(self):
|
||||||
@ -590,11 +588,19 @@ class Master(SMaster):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
if self.opts.get('git_pillar_verify_config', True):
|
if self.opts.get('git_pillar_verify_config', True):
|
||||||
git_pillars = [
|
try:
|
||||||
x for x in self.opts.get('ext_pillar', [])
|
git_pillars = [
|
||||||
if 'git' in x
|
x for x in self.opts.get('ext_pillar', [])
|
||||||
and not isinstance(x['git'], six.string_types)
|
if 'git' in x
|
||||||
]
|
and not isinstance(x['git'], six.string_types)
|
||||||
|
]
|
||||||
|
except TypeError:
|
||||||
|
git_pillars = []
|
||||||
|
critical_errors.append(
|
||||||
|
'Invalid ext_pillar configuration. It is likely that the '
|
||||||
|
'external pillar type was not specified for one or more '
|
||||||
|
'external pillars.'
|
||||||
|
)
|
||||||
if git_pillars:
|
if git_pillars:
|
||||||
try:
|
try:
|
||||||
new_opts = copy.deepcopy(self.opts)
|
new_opts = copy.deepcopy(self.opts)
|
||||||
|
@ -101,6 +101,7 @@ def cert(name,
|
|||||||
server=None,
|
server=None,
|
||||||
owner='root',
|
owner='root',
|
||||||
group='root',
|
group='root',
|
||||||
|
mode='0640',
|
||||||
certname=None):
|
certname=None):
|
||||||
'''
|
'''
|
||||||
Obtain/renew a certificate from an ACME CA, probably Let's Encrypt.
|
Obtain/renew a certificate from an ACME CA, probably Let's Encrypt.
|
||||||
@ -113,8 +114,9 @@ def cert(name,
|
|||||||
:param renew: True/'force' to force a renewal, or a window of renewal before expiry in days
|
:param renew: True/'force' to force a renewal, or a window of renewal before expiry in days
|
||||||
:param keysize: RSA key bits
|
:param keysize: RSA key bits
|
||||||
:param server: API endpoint to talk to
|
:param server: API endpoint to talk to
|
||||||
:param owner: owner of private key
|
:param owner: owner of the private key file
|
||||||
:param group: group of private key
|
:param group: group of the private key file
|
||||||
|
:param mode: mode of the private key file
|
||||||
:param certname: Name of the certificate to save
|
:param certname: Name of the certificate to save
|
||||||
:return: dict with 'result' True/False/None, 'comment' and certificate's expiry date ('not_after')
|
:return: dict with 'result' True/False/None, 'comment' and certificate's expiry date ('not_after')
|
||||||
|
|
||||||
@ -170,27 +172,17 @@ def cert(name,
|
|||||||
return {'result': False, 'comment': 'Certificate {0} renewal failed with:\n{1}'.format(name, res['stderr'])}
|
return {'result': False, 'comment': 'Certificate {0} renewal failed with:\n{1}'.format(name, res['stderr'])}
|
||||||
|
|
||||||
if 'no action taken' in res['stdout']:
|
if 'no action taken' in res['stdout']:
|
||||||
return {'result': None,
|
comment = 'Certificate {0} unchanged'.format(cert_file)
|
||||||
'comment': 'No action taken on certificate {0}'.format(cert_file),
|
elif renew:
|
||||||
'not_after': expires(name)}
|
|
||||||
|
|
||||||
if renew:
|
|
||||||
comment = 'Certificate {0} renewed'.format(name)
|
comment = 'Certificate {0} renewed'.format(name)
|
||||||
else:
|
else:
|
||||||
comment = 'Certificate {0} obtained'.format(name)
|
comment = 'Certificate {0} obtained'.format(name)
|
||||||
ret = {'comment': comment, 'not_after': expires(name)}
|
|
||||||
|
|
||||||
res = __salt__['file.check_perms'](_cert_file(name, 'privkey'), {}, owner, group, '0600', follow_symlinks=True)
|
ret = {'comment': comment, 'not_after': expires(name), 'changes': {}, 'result': True}
|
||||||
|
ret, _ = __salt__['file.check_perms'](_cert_file(name, 'privkey'),
|
||||||
if res is None:
|
ret,
|
||||||
ret['result'] = False
|
owner, group, mode,
|
||||||
ret['comment'] += ', but setting permissions failed.'
|
follow_symlinks=True)
|
||||||
elif not res[0].get('result', False):
|
|
||||||
ret['result'] = False
|
|
||||||
ret['comment'] += ', but setting permissions failed with \n{0}'.format(res[0]['comment'])
|
|
||||||
else:
|
|
||||||
ret['result'] = True
|
|
||||||
ret['comment'] += '.'
|
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
@ -289,12 +289,14 @@ def raw_cron(user):
|
|||||||
# Preserve line endings
|
# Preserve line endings
|
||||||
lines = sdecode(__salt__['cmd.run_stdout'](cmd,
|
lines = sdecode(__salt__['cmd.run_stdout'](cmd,
|
||||||
runas=user,
|
runas=user,
|
||||||
|
ignore_retcode=True,
|
||||||
rstrip=False,
|
rstrip=False,
|
||||||
python_shell=False)).splitlines(True)
|
python_shell=False)).splitlines(True)
|
||||||
else:
|
else:
|
||||||
cmd = 'crontab -u {0} -l'.format(user)
|
cmd = 'crontab -u {0} -l'.format(user)
|
||||||
# Preserve line endings
|
# Preserve line endings
|
||||||
lines = sdecode(__salt__['cmd.run_stdout'](cmd,
|
lines = sdecode(__salt__['cmd.run_stdout'](cmd,
|
||||||
|
ignore_retcode=True,
|
||||||
rstrip=False,
|
rstrip=False,
|
||||||
python_shell=False)).splitlines(True)
|
python_shell=False)).splitlines(True)
|
||||||
|
|
||||||
|
@ -393,20 +393,14 @@ def __within(within=None, errmsg=None, dtype=None):
|
|||||||
|
|
||||||
def __space_delimited_list(value):
|
def __space_delimited_list(value):
|
||||||
'''validate that a value contains one or more space-delimited values'''
|
'''validate that a value contains one or more space-delimited values'''
|
||||||
valid, _value, errmsg = False, value, 'space-delimited string'
|
if isinstance(value, str):
|
||||||
try:
|
value = value.strip().split()
|
||||||
if hasattr(value, '__iter__'):
|
|
||||||
valid = True # TODO:
|
if hasattr(value, '__iter__') and value != []:
|
||||||
else:
|
return (True, value, 'space-delimited string')
|
||||||
_value = value.split()
|
else:
|
||||||
if _value == []:
|
return (False, value, '{0} is not a valid space-delimited value.\n'.format(value))
|
||||||
raise ValueError
|
|
||||||
valid = True
|
|
||||||
except AttributeError:
|
|
||||||
pass
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
return (valid, _value, errmsg)
|
|
||||||
|
|
||||||
SALT_ATTR_TO_DEBIAN_ATTR_MAP = {
|
SALT_ATTR_TO_DEBIAN_ATTR_MAP = {
|
||||||
'dns': 'dns-nameservers',
|
'dns': 'dns-nameservers',
|
||||||
|
@ -6467,7 +6467,6 @@ def _prepare_trans_tar(name, sls_opts, mods=None, pillar=None):
|
|||||||
refs = salt.client.ssh.state.lowstate_file_refs(chunks)
|
refs = salt.client.ssh.state.lowstate_file_refs(chunks)
|
||||||
_mk_fileclient()
|
_mk_fileclient()
|
||||||
trans_tar = salt.client.ssh.state.prep_trans_tar(
|
trans_tar = salt.client.ssh.state.prep_trans_tar(
|
||||||
sls_opts,
|
|
||||||
__context__['cp.fileclient'],
|
__context__['cp.fileclient'],
|
||||||
chunks, refs, pillar, name)
|
chunks, refs, pillar, name)
|
||||||
return trans_tar
|
return trans_tar
|
||||||
|
@ -86,6 +86,9 @@ def fire_master(data, tag, preload=None):
|
|||||||
channel = salt.transport.Channel.factory(__opts__, master_uri=master)
|
channel = salt.transport.Channel.factory(__opts__, master_uri=master)
|
||||||
try:
|
try:
|
||||||
channel.send(load)
|
channel.send(load)
|
||||||
|
# channel.send was successful.
|
||||||
|
# Ensure ret is True.
|
||||||
|
ret = True
|
||||||
except Exception:
|
except Exception:
|
||||||
ret = False
|
ret = False
|
||||||
return ret
|
return ret
|
||||||
|
@ -61,6 +61,7 @@ import salt.utils.stringutils
|
|||||||
import salt.utils.templates
|
import salt.utils.templates
|
||||||
import salt.utils.url
|
import salt.utils.url
|
||||||
import salt.utils.user
|
import salt.utils.user
|
||||||
|
import salt.utils.data
|
||||||
from salt.exceptions import CommandExecutionError, MinionError, SaltInvocationError, get_error_message as _get_error_message
|
from salt.exceptions import CommandExecutionError, MinionError, SaltInvocationError, get_error_message as _get_error_message
|
||||||
from salt.utils.files import HASHES, HASHES_REVMAP
|
from salt.utils.files import HASHES, HASHES_REVMAP
|
||||||
|
|
||||||
@ -1718,18 +1719,19 @@ def _regex_to_static(src, regex):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
src = re.search(regex, src, re.M)
|
compiled = re.compile(regex, re.DOTALL)
|
||||||
|
src = [line for line in src if compiled.search(line) or line.count(regex)]
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
raise CommandExecutionError("{0}: '{1}'".format(_get_error_message(ex), regex))
|
raise CommandExecutionError("{0}: '{1}'".format(_get_error_message(ex), regex))
|
||||||
|
|
||||||
return src and src.group().rstrip('\r') or regex
|
return src and src or []
|
||||||
|
|
||||||
|
|
||||||
def _assert_occurrence(src, probe, target, amount=1):
|
def _assert_occurrence(probe, target, amount=1):
|
||||||
'''
|
'''
|
||||||
Raise an exception, if there are different amount of specified occurrences in src.
|
Raise an exception, if there are different amount of specified occurrences in src.
|
||||||
'''
|
'''
|
||||||
occ = src.count(probe)
|
occ = len(probe)
|
||||||
if occ > amount:
|
if occ > amount:
|
||||||
msg = 'more than'
|
msg = 'more than'
|
||||||
elif occ < amount:
|
elif occ < amount:
|
||||||
@ -1745,7 +1747,7 @@ def _assert_occurrence(src, probe, target, amount=1):
|
|||||||
return occ
|
return occ
|
||||||
|
|
||||||
|
|
||||||
def _get_line_indent(src, line, indent):
|
def _set_line_indent(src, line, indent):
|
||||||
'''
|
'''
|
||||||
Indent the line with the source line.
|
Indent the line with the source line.
|
||||||
'''
|
'''
|
||||||
@ -1758,7 +1760,36 @@ def _get_line_indent(src, line, indent):
|
|||||||
break
|
break
|
||||||
idt.append(c)
|
idt.append(c)
|
||||||
|
|
||||||
return ''.join(idt) + line.strip()
|
return ''.join(idt) + line.lstrip()
|
||||||
|
|
||||||
|
|
||||||
|
def _get_eol(line):
|
||||||
|
match = re.search('((?<!\r)\n|\r(?!\n)|\r\n)$', line)
|
||||||
|
return match and match.group() or ''
|
||||||
|
|
||||||
|
|
||||||
|
def _set_line_eol(src, line):
|
||||||
|
'''
|
||||||
|
Add line ending
|
||||||
|
'''
|
||||||
|
line_ending = _get_eol(src) or os.linesep
|
||||||
|
return line.rstrip() + line_ending
|
||||||
|
|
||||||
|
|
||||||
|
def _insert_line_before(idx, body, content, indent):
|
||||||
|
if not idx or (idx and _starts_till(body[idx - 1], content) < 0):
|
||||||
|
cnd = _set_line_indent(body[idx], content, indent)
|
||||||
|
body.insert(idx, cnd)
|
||||||
|
return body
|
||||||
|
|
||||||
|
|
||||||
|
def _insert_line_after(idx, body, content, indent):
|
||||||
|
# No duplicates or append, if "after" is the last line
|
||||||
|
next_line = idx + 1 < len(body) and body[idx + 1] or None
|
||||||
|
if next_line is None or _starts_till(next_line, content) < 0:
|
||||||
|
cnd = _set_line_indent(body[idx], content, indent)
|
||||||
|
body.insert(idx + 1, cnd)
|
||||||
|
return body
|
||||||
|
|
||||||
|
|
||||||
def line(path, content=None, match=None, mode=None, location=None,
|
def line(path, content=None, match=None, mode=None, location=None,
|
||||||
@ -1889,132 +1920,110 @@ def line(path, content=None, match=None, mode=None, location=None,
|
|||||||
match = content
|
match = content
|
||||||
|
|
||||||
with salt.utils.files.fopen(path, mode='r') as fp_:
|
with salt.utils.files.fopen(path, mode='r') as fp_:
|
||||||
body = salt.utils.stringutils.to_unicode(fp_.read())
|
body = salt.utils.data.decode_list(fp_.readlines())
|
||||||
body_before = hashlib.sha256(salt.utils.stringutils.to_bytes(body)).hexdigest()
|
body_before = hashlib.sha256(salt.utils.stringutils.to_bytes(''.join(body))).hexdigest()
|
||||||
|
# Add empty line at the end if last line ends with eol.
|
||||||
|
# Allows simpler code
|
||||||
|
if body and _get_eol(body[-1]):
|
||||||
|
body.append('')
|
||||||
|
|
||||||
after = _regex_to_static(body, after)
|
after = _regex_to_static(body, after)
|
||||||
before = _regex_to_static(body, before)
|
before = _regex_to_static(body, before)
|
||||||
match = _regex_to_static(body, match)
|
match = _regex_to_static(body, match)
|
||||||
|
|
||||||
if os.stat(path).st_size == 0 and mode in ('delete', 'replace'):
|
if os.stat(path).st_size == 0 and mode in ('delete', 'replace'):
|
||||||
log.warning('Cannot find text to {0}. File \'{1}\' is empty.'.format(mode, path))
|
log.warning('Cannot find text to {0}. File \'{1}\' is empty.'.format(mode, path))
|
||||||
body = ''
|
body = []
|
||||||
elif mode == 'delete':
|
elif mode == 'delete' and match:
|
||||||
body = os.linesep.join([line for line in body.split(os.linesep) if line.find(match) < 0])
|
body = [line for line in body if line != match[0]]
|
||||||
elif mode == 'replace':
|
elif mode == 'replace' and match:
|
||||||
body = os.linesep.join([(_get_line_indent(file_line, content, indent)
|
idx = body.index(match[0])
|
||||||
if (file_line.find(match) > -1 and not file_line == content) else file_line)
|
file_line = body.pop(idx)
|
||||||
for file_line in body.split(os.linesep)])
|
body.insert(idx, _set_line_indent(file_line, content, indent))
|
||||||
elif mode == 'insert':
|
elif mode == 'insert':
|
||||||
if not location and not before and not after:
|
if not location and not before and not after:
|
||||||
raise CommandExecutionError('On insert must be defined either "location" or "before/after" conditions.')
|
raise CommandExecutionError('On insert must be defined either "location" or "before/after" conditions.')
|
||||||
|
|
||||||
if not location:
|
if not location:
|
||||||
if before and after:
|
if before and after:
|
||||||
_assert_occurrence(body, before, 'before')
|
_assert_occurrence(before, 'before')
|
||||||
_assert_occurrence(body, after, 'after')
|
_assert_occurrence(after, 'after')
|
||||||
|
|
||||||
out = []
|
out = []
|
||||||
lines = body.split(os.linesep)
|
|
||||||
in_range = False
|
in_range = False
|
||||||
for line in lines:
|
for line in body:
|
||||||
if line.find(after) > -1:
|
if line == after[0]:
|
||||||
in_range = True
|
in_range = True
|
||||||
elif line.find(before) > -1 and in_range:
|
elif line == before[0] and in_range:
|
||||||
out.append(_get_line_indent(line, content, indent))
|
cnd = _set_line_indent(line, content, indent)
|
||||||
|
out.append(cnd)
|
||||||
out.append(line)
|
out.append(line)
|
||||||
body = os.linesep.join(out)
|
body = out
|
||||||
|
|
||||||
if before and not after:
|
if before and not after:
|
||||||
_assert_occurrence(body, before, 'before')
|
_assert_occurrence(before, 'before')
|
||||||
out = []
|
|
||||||
lines = body.split(os.linesep)
|
idx = body.index(before[0])
|
||||||
for idx in range(len(lines)):
|
body = _insert_line_before(idx, body, content, indent)
|
||||||
_line = lines[idx]
|
|
||||||
if _line.find(before) > -1:
|
|
||||||
cnd = _get_line_indent(_line, content, indent)
|
|
||||||
if not idx or (idx and _starts_till(lines[idx - 1], cnd) < 0): # Job for replace instead
|
|
||||||
out.append(cnd)
|
|
||||||
out.append(_line)
|
|
||||||
body = os.linesep.join(out)
|
|
||||||
|
|
||||||
elif after and not before:
|
elif after and not before:
|
||||||
_assert_occurrence(body, after, 'after')
|
_assert_occurrence(after, 'after')
|
||||||
out = []
|
|
||||||
lines = body.split(os.linesep)
|
idx = body.index(after[0])
|
||||||
for idx, _line in enumerate(lines):
|
body = _insert_line_after(idx, body, content, indent)
|
||||||
out.append(_line)
|
|
||||||
cnd = _get_line_indent(_line, content, indent)
|
|
||||||
# No duplicates or append, if "after" is the last line
|
|
||||||
if (_line.find(after) > -1 and
|
|
||||||
(lines[((idx + 1) < len(lines)) and idx + 1 or idx].strip() != cnd or
|
|
||||||
idx + 1 == len(lines))):
|
|
||||||
out.append(cnd)
|
|
||||||
body = os.linesep.join(out)
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
if location == 'start':
|
if location == 'start':
|
||||||
body = os.linesep.join((content, body))
|
if body:
|
||||||
|
body.insert(0, _set_line_eol(body[0], content))
|
||||||
|
else:
|
||||||
|
body.append(content + os.linesep)
|
||||||
elif location == 'end':
|
elif location == 'end':
|
||||||
body = os.linesep.join((body, _get_line_indent(body[-1], content, indent) if body else content))
|
body.append(_set_line_indent(body[-1], content, indent) if body else content)
|
||||||
|
|
||||||
elif mode == 'ensure':
|
elif mode == 'ensure':
|
||||||
after = after and after.strip()
|
|
||||||
before = before and before.strip()
|
|
||||||
|
|
||||||
if before and after:
|
if before and after:
|
||||||
_assert_occurrence(body, before, 'before')
|
_assert_occurrence(before, 'before')
|
||||||
_assert_occurrence(body, after, 'after')
|
_assert_occurrence(after, 'after')
|
||||||
|
|
||||||
is_there = bool(body.count(content))
|
is_there = bool([l for l in body if l.count(content)])
|
||||||
if not is_there:
|
if not is_there:
|
||||||
out = []
|
idx = body.index(after[0])
|
||||||
body = body.split(os.linesep)
|
if idx < (len(body) - 1) and body[idx + 1] == before[0]:
|
||||||
for idx, line in enumerate(body):
|
cnd = _set_line_indent(body[idx], content, indent)
|
||||||
out.append(line)
|
body.insert(idx + 1, cnd)
|
||||||
if line.find(content) > -1:
|
else:
|
||||||
is_there = True
|
raise CommandExecutionError('Found more than one line between '
|
||||||
if not is_there:
|
'boundaries "before" and "after".')
|
||||||
if idx < (len(body) - 1) and line.find(after) > -1 and body[idx + 1].find(before) > -1:
|
|
||||||
out.append(content)
|
|
||||||
elif line.find(after) > -1:
|
|
||||||
raise CommandExecutionError('Found more than one line between '
|
|
||||||
'boundaries "before" and "after".')
|
|
||||||
body = os.linesep.join(out)
|
|
||||||
|
|
||||||
elif before and not after:
|
elif before and not after:
|
||||||
_assert_occurrence(body, before, 'before')
|
_assert_occurrence(before, 'before')
|
||||||
body = body.split(os.linesep)
|
|
||||||
out = []
|
idx = body.index(before[0])
|
||||||
for idx in range(len(body)):
|
body = _insert_line_before(idx, body, content, indent)
|
||||||
if body[idx].find(before) > -1:
|
|
||||||
prev = (idx > 0 and idx or 1) - 1
|
|
||||||
out.append(_get_line_indent(body[idx], content, indent))
|
|
||||||
if _starts_till(out[prev], content) > -1:
|
|
||||||
del out[prev]
|
|
||||||
out.append(body[idx])
|
|
||||||
body = os.linesep.join(out)
|
|
||||||
|
|
||||||
elif not before and after:
|
elif not before and after:
|
||||||
_assert_occurrence(body, after, 'after')
|
_assert_occurrence(after, 'after')
|
||||||
body = body.split(os.linesep)
|
|
||||||
skip = None
|
|
||||||
out = []
|
|
||||||
for idx in range(len(body)):
|
|
||||||
if skip != body[idx]:
|
|
||||||
out.append(body[idx])
|
|
||||||
|
|
||||||
if body[idx].find(after) > -1:
|
idx = body.index(after[0])
|
||||||
next_line = idx + 1 < len(body) and body[idx + 1] or None
|
body = _insert_line_after(idx, body, content, indent)
|
||||||
if next_line is not None and _starts_till(next_line, content) > -1:
|
|
||||||
skip = next_line
|
|
||||||
out.append(_get_line_indent(body[idx], content, indent))
|
|
||||||
body = os.linesep.join(out)
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise CommandExecutionError("Wrong conditions? "
|
raise CommandExecutionError("Wrong conditions? "
|
||||||
"Unable to ensure line without knowing "
|
"Unable to ensure line without knowing "
|
||||||
"where to put it before and/or after.")
|
"where to put it before and/or after.")
|
||||||
|
|
||||||
changed = body_before != hashlib.sha256(salt.utils.stringutils.to_bytes(body)).hexdigest()
|
if body:
|
||||||
|
for idx, line in enumerate(body):
|
||||||
|
if not _get_eol(line) and idx+1 < len(body):
|
||||||
|
prev = idx and idx-1 or 1
|
||||||
|
body[idx] = _set_line_eol(body[prev], line)
|
||||||
|
# We do not need empty line at the end anymore
|
||||||
|
if '' == body[-1]:
|
||||||
|
body.pop()
|
||||||
|
|
||||||
|
changed = body_before != hashlib.sha256(salt.utils.stringutils.to_bytes(''.join(body))).hexdigest()
|
||||||
|
|
||||||
if backup and changed and __opts__['test'] is False:
|
if backup and changed and __opts__['test'] is False:
|
||||||
try:
|
try:
|
||||||
@ -2028,12 +2037,9 @@ def line(path, content=None, match=None, mode=None, location=None,
|
|||||||
if changed:
|
if changed:
|
||||||
if show_changes:
|
if show_changes:
|
||||||
with salt.utils.files.fopen(path, 'r') as fp_:
|
with salt.utils.files.fopen(path, 'r') as fp_:
|
||||||
path_content = [salt.utils.stringutils.to_unicode(x)
|
path_content = salt.utils.data.decode_list(fp_.read().splitlines(True))
|
||||||
for x in fp_.read().splitlines(True)]
|
|
||||||
changes_diff = ''.join(difflib.unified_diff(
|
changes_diff = ''.join(difflib.unified_diff(
|
||||||
path_content,
|
path_content, body
|
||||||
[salt.utils.stringutils.to_unicode(x)
|
|
||||||
for x in body.splitlines(True)]
|
|
||||||
))
|
))
|
||||||
if __opts__['test'] is False:
|
if __opts__['test'] is False:
|
||||||
fh_ = None
|
fh_ = None
|
||||||
@ -2041,12 +2047,12 @@ def line(path, content=None, match=None, mode=None, location=None,
|
|||||||
# Make sure we match the file mode from salt.utils.files.fopen
|
# Make sure we match the file mode from salt.utils.files.fopen
|
||||||
if six.PY2 and salt.utils.platform.is_windows():
|
if six.PY2 and salt.utils.platform.is_windows():
|
||||||
mode = 'wb'
|
mode = 'wb'
|
||||||
body = salt.utils.stringutils.to_bytes(body)
|
body = salt.utils.data.encode_list(body)
|
||||||
else:
|
else:
|
||||||
mode = 'w'
|
mode = 'w'
|
||||||
body = salt.utils.stringutils.to_str(body)
|
body = salt.utils.data.decode_list(body, to_str=True)
|
||||||
fh_ = salt.utils.atomicfile.atomic_open(path, mode)
|
fh_ = salt.utils.atomicfile.atomic_open(path, mode)
|
||||||
fh_.write(body)
|
fh_.writelines(body)
|
||||||
finally:
|
finally:
|
||||||
if fh_:
|
if fh_:
|
||||||
fh_.close()
|
fh_.close()
|
||||||
@ -2471,10 +2477,10 @@ def blockreplace(path,
|
|||||||
final output
|
final output
|
||||||
|
|
||||||
marker_end
|
marker_end
|
||||||
The line content identifying a line as the end of the content block.
|
The line content identifying the end of the content block. As of
|
||||||
Note that the whole line containing this marker will be considered, so
|
versions 2017.7.5 and 2018.3.1, everything up to the text matching the
|
||||||
whitespace or extra content before or after the marker is included in
|
marker will be replaced, so it's important to ensure that your marker
|
||||||
final output
|
includes the beginning of the text you wish to replace.
|
||||||
|
|
||||||
content
|
content
|
||||||
The content to be used between the two lines identified by marker_start
|
The content to be used between the two lines identified by marker_start
|
||||||
@ -4463,27 +4469,6 @@ def check_perms(name, ret, user, group, mode, attrs=None, follow_symlinks=False)
|
|||||||
if perms['lattrs']:
|
if perms['lattrs']:
|
||||||
chattr(name, operator='remove', attributes=perms['lattrs'])
|
chattr(name, operator='remove', attributes=perms['lattrs'])
|
||||||
|
|
||||||
# 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.files.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.files.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
|
# user/group changes if needed, then check if it worked
|
||||||
if user:
|
if user:
|
||||||
if isinstance(user, int):
|
if isinstance(user, int):
|
||||||
@ -4540,6 +4525,7 @@ def check_perms(name, ret, user, group, mode, attrs=None, follow_symlinks=False)
|
|||||||
.format(user))
|
.format(user))
|
||||||
elif 'cuser' in perms and user != '':
|
elif 'cuser' in perms and user != '':
|
||||||
ret['changes']['user'] = user
|
ret['changes']['user'] = user
|
||||||
|
|
||||||
if group:
|
if group:
|
||||||
if isinstance(group, int):
|
if isinstance(group, int):
|
||||||
group = gid_to_group(group)
|
group = gid_to_group(group)
|
||||||
@ -4560,18 +4546,32 @@ def check_perms(name, ret, user, group, mode, attrs=None, follow_symlinks=False)
|
|||||||
elif 'cgroup' in perms and user != '':
|
elif 'cgroup' in perms and user != '':
|
||||||
ret['changes']['group'] = group
|
ret['changes']['group'] = group
|
||||||
|
|
||||||
if isinstance(orig_comment, six.string_types):
|
|
||||||
if orig_comment:
|
|
||||||
ret['comment'].insert(0, orig_comment)
|
|
||||||
ret['comment'] = '; '.join(ret['comment'])
|
|
||||||
if __opts__['test'] is True and ret['changes']:
|
|
||||||
ret['result'] = None
|
|
||||||
|
|
||||||
if not salt.utils.platform.is_windows() and not is_dir:
|
if not salt.utils.platform.is_windows() and not is_dir:
|
||||||
# Replace attributes on file if it had been removed
|
# Replace attributes on file if it had been removed
|
||||||
if perms.get('lattrs', ''):
|
if perms.get('lattrs', ''):
|
||||||
chattr(name, operator='add', attributes=perms['lattrs'])
|
chattr(name, operator='add', attributes=perms['lattrs'])
|
||||||
|
|
||||||
|
# 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.files.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.files.normalize_mode(get_mode(name)):
|
||||||
|
ret['result'] = False
|
||||||
|
ret['comment'].append(
|
||||||
|
'Failed to change mode to {0}'.format(mode)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
ret['changes']['mode'] = mode
|
||||||
|
|
||||||
# Modify attributes of file if needed
|
# Modify attributes of file if needed
|
||||||
if attrs is not None and not is_dir:
|
if attrs is not None and not is_dir:
|
||||||
# File is a symlink, ignore the mode setting
|
# File is a symlink, ignore the mode setting
|
||||||
@ -4598,6 +4598,18 @@ def check_perms(name, ret, user, group, mode, attrs=None, follow_symlinks=False)
|
|||||||
else:
|
else:
|
||||||
ret['changes']['attrs'] = attrs
|
ret['changes']['attrs'] = attrs
|
||||||
|
|
||||||
|
# Only combine the comment list into a string
|
||||||
|
# after all comments are added above
|
||||||
|
if isinstance(orig_comment, six.string_types):
|
||||||
|
if orig_comment:
|
||||||
|
ret['comment'].insert(0, orig_comment)
|
||||||
|
ret['comment'] = '; '.join(ret['comment'])
|
||||||
|
|
||||||
|
# Set result to None at the very end of the function,
|
||||||
|
# after all changes have been recorded above
|
||||||
|
if __opts__['test'] is True and ret['changes']:
|
||||||
|
ret['result'] = None
|
||||||
|
|
||||||
return ret, perms
|
return ret, perms
|
||||||
|
|
||||||
|
|
||||||
@ -4722,6 +4734,11 @@ def check_managed_changes(
|
|||||||
defaults,
|
defaults,
|
||||||
skip_verify,
|
skip_verify,
|
||||||
**kwargs)
|
**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:
|
if comments:
|
||||||
__clean_tmp(sfn)
|
__clean_tmp(sfn)
|
||||||
return False, comments
|
return False, comments
|
||||||
@ -5058,7 +5075,7 @@ def manage_file(name,
|
|||||||
source
|
source
|
||||||
file reference on the master
|
file reference on the master
|
||||||
|
|
||||||
source_hash
|
source_sum
|
||||||
sum hash for source
|
sum hash for source
|
||||||
|
|
||||||
user
|
user
|
||||||
@ -6196,6 +6213,16 @@ def grep(path,
|
|||||||
'''
|
'''
|
||||||
path = os.path.expanduser(path)
|
path = os.path.expanduser(path)
|
||||||
|
|
||||||
|
# Backup the path in case the glob returns nothing
|
||||||
|
_path = path
|
||||||
|
path = glob.glob(path)
|
||||||
|
|
||||||
|
# If the list is empty no files exist
|
||||||
|
# so we revert back to the original path
|
||||||
|
# so the result is an error.
|
||||||
|
if not path:
|
||||||
|
path = _path
|
||||||
|
|
||||||
split_opts = []
|
split_opts = []
|
||||||
for opt in opts:
|
for opt in opts:
|
||||||
try:
|
try:
|
||||||
@ -6210,7 +6237,10 @@ def grep(path,
|
|||||||
)
|
)
|
||||||
split_opts.extend(split)
|
split_opts.extend(split)
|
||||||
|
|
||||||
cmd = ['grep'] + split_opts + [pattern, path]
|
if isinstance(path, list):
|
||||||
|
cmd = ['grep'] + split_opts + [pattern] + path
|
||||||
|
else:
|
||||||
|
cmd = ['grep'] + split_opts + [pattern, path]
|
||||||
try:
|
try:
|
||||||
ret = __salt__['cmd.run_all'](cmd, python_shell=False)
|
ret = __salt__['cmd.run_all'](cmd, python_shell=False)
|
||||||
except (IOError, OSError) as exc:
|
except (IOError, OSError) as exc:
|
||||||
|
@ -29,15 +29,16 @@ def __virtual__():
|
|||||||
return (False, 'glusterfs server is not installed')
|
return (False, 'glusterfs server is not installed')
|
||||||
|
|
||||||
|
|
||||||
def _get_minor_version():
|
def _get_version():
|
||||||
# Set default version to 6 for tests
|
# Set the default minor version to 6 for tests
|
||||||
version = 6
|
version = [3, 6]
|
||||||
cmd = 'gluster --version'
|
cmd = 'gluster --version'
|
||||||
result = __salt__['cmd.run'](cmd).splitlines()
|
result = __salt__['cmd.run'](cmd).splitlines()
|
||||||
for line in result:
|
for line in result:
|
||||||
if line.startswith('glusterfs'):
|
if line.startswith('glusterfs'):
|
||||||
version = int(line.split()[1].split('.')[1])
|
version = line.split()[-1].split('.')
|
||||||
return version
|
version = [int(i) for i in version]
|
||||||
|
return tuple(version)
|
||||||
|
|
||||||
|
|
||||||
def _gluster_ok(xml_data):
|
def _gluster_ok(xml_data):
|
||||||
@ -70,7 +71,7 @@ def _gluster_xml(cmd):
|
|||||||
# We will pass the command string as stdin to allow for much longer
|
# We will pass the command string as stdin to allow for much longer
|
||||||
# command strings. This is especially useful for creating large volumes
|
# command strings. This is especially useful for creating large volumes
|
||||||
# where the list of bricks exceeds 128 characters.
|
# where the list of bricks exceeds 128 characters.
|
||||||
if _get_minor_version() < 6:
|
if _get_version() < (3, 6,):
|
||||||
result = __salt__['cmd.run'](
|
result = __salt__['cmd.run'](
|
||||||
'script -q -c "gluster --xml --mode=script"', stdin="{0}\n\004".format(cmd)
|
'script -q -c "gluster --xml --mode=script"', stdin="{0}\n\004".format(cmd)
|
||||||
)
|
)
|
||||||
|
@ -58,22 +58,22 @@ def __virtual__():
|
|||||||
'influxdb library not available.'))
|
'influxdb library not available.'))
|
||||||
|
|
||||||
|
|
||||||
def _client(user=None, password=None, host=None, port=None, **client_args):
|
def _client(influxdb_user=None, influxdb_password=None, influxdb_host=None, influxdb_port=None, **client_args):
|
||||||
if not user:
|
if not influxdb_user:
|
||||||
user = __salt__['config.option']('influxdb.user', 'root')
|
influxdb_user = __salt__['config.option']('influxdb.user', 'root')
|
||||||
if not password:
|
if not influxdb_password:
|
||||||
password = __salt__['config.option']('influxdb.password', 'root')
|
influxdb_password = __salt__['config.option']('influxdb.password', 'root')
|
||||||
if not host:
|
if not influxdb_host:
|
||||||
host = __salt__['config.option']('influxdb.host', 'localhost')
|
influxdb_host = __salt__['config.option']('influxdb.host', 'localhost')
|
||||||
if not port:
|
if not influxdb_port:
|
||||||
port = __salt__['config.option']('influxdb.port', 8086)
|
influxdb_port = __salt__['config.option']('influxdb.port', 8086)
|
||||||
for ignore in _STATE_INTERNAL_KEYWORDS:
|
for ignore in _STATE_INTERNAL_KEYWORDS:
|
||||||
if ignore in client_args:
|
if ignore in client_args:
|
||||||
del client_args[ignore]
|
del client_args[ignore]
|
||||||
return influxdb.InfluxDBClient(host=host,
|
return influxdb.InfluxDBClient(host=influxdb_host,
|
||||||
port=port,
|
port=influxdb_port,
|
||||||
username=user,
|
username=influxdb_user,
|
||||||
password=password,
|
password=influxdb_password,
|
||||||
**client_args)
|
**client_args)
|
||||||
|
|
||||||
|
|
||||||
|
@ -35,9 +35,9 @@ def __virtual__():
|
|||||||
return __virtualname__
|
return __virtualname__
|
||||||
|
|
||||||
|
|
||||||
ini_regx = re.compile(r'^\s*\[(.+?)\]\s*$', flags=re.M)
|
INI_REGX = re.compile(r'^\s*\[(.+?)\]\s*$', flags=re.M)
|
||||||
com_regx = re.compile(r'^\s*(#|;)\s*(.*)')
|
COM_REGX = re.compile(r'^\s*(#|;)\s*(.*)')
|
||||||
indented_regx = re.compile(r'(\s+)(.*)')
|
INDENTED_REGX = re.compile(r'(\s+)(.*)')
|
||||||
|
|
||||||
|
|
||||||
def set_option(file_name, sections=None, separator='='):
|
def set_option(file_name, sections=None, separator='='):
|
||||||
@ -105,7 +105,13 @@ def get_option(file_name, section, option, separator='='):
|
|||||||
salt '*' ini.get_option /path/to/ini section_name option_name
|
salt '*' ini.get_option /path/to/ini section_name option_name
|
||||||
'''
|
'''
|
||||||
inifile = _Ini.get_ini_file(file_name, separator=separator)
|
inifile = _Ini.get_ini_file(file_name, separator=separator)
|
||||||
return inifile.get(section, {}).get(option, None)
|
if section:
|
||||||
|
try:
|
||||||
|
return inifile.get(section, {}).get(option, None)
|
||||||
|
except AttributeError:
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
return inifile.get(option, None)
|
||||||
|
|
||||||
|
|
||||||
def remove_option(file_name, section, option, separator='='):
|
def remove_option(file_name, section, option, separator='='):
|
||||||
@ -129,7 +135,10 @@ def remove_option(file_name, section, option, separator='='):
|
|||||||
salt '*' ini.remove_option /path/to/ini section_name option_name
|
salt '*' ini.remove_option /path/to/ini section_name option_name
|
||||||
'''
|
'''
|
||||||
inifile = _Ini.get_ini_file(file_name, separator=separator)
|
inifile = _Ini.get_ini_file(file_name, separator=separator)
|
||||||
value = inifile.get(section, {}).pop(option, None)
|
if isinstance(inifile.get(section), (dict, OrderedDict)):
|
||||||
|
value = inifile.get(section, {}).pop(option, None)
|
||||||
|
else:
|
||||||
|
value = inifile.pop(option, None)
|
||||||
inifile.flush()
|
inifile.flush()
|
||||||
return value
|
return value
|
||||||
|
|
||||||
@ -182,15 +191,53 @@ def remove_section(file_name, section, separator='='):
|
|||||||
|
|
||||||
salt '*' ini.remove_section /path/to/ini section_name
|
salt '*' ini.remove_section /path/to/ini section_name
|
||||||
'''
|
'''
|
||||||
|
inifile = _Ini.get_ini_file(file_name, separator=separator)
|
||||||
|
if section in inifile:
|
||||||
|
section = inifile.pop(section)
|
||||||
|
inifile.flush()
|
||||||
|
ret = {}
|
||||||
|
for key, value in six.iteritems(section):
|
||||||
|
if key[0] != '#':
|
||||||
|
ret.update({key: value})
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
def get_ini(file_name, separator='='):
|
||||||
|
'''
|
||||||
|
Retrieve whole structure from an ini file and return it as dictionary.
|
||||||
|
|
||||||
|
API Example:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
import salt
|
||||||
|
sc = salt.client.get_local_client()
|
||||||
|
sc.cmd('target', 'ini.get_ini',
|
||||||
|
[path_to_ini_file])
|
||||||
|
|
||||||
|
CLI Example:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
salt '*' ini.get_ini /path/to/ini
|
||||||
|
'''
|
||||||
|
def ini_odict2dict(odict):
|
||||||
|
'''
|
||||||
|
Transform OrderedDict to regular dict recursively
|
||||||
|
:param odict: OrderedDict
|
||||||
|
:return: regular dict
|
||||||
|
'''
|
||||||
|
ret = {}
|
||||||
|
for key, val in six.iteritems(odict):
|
||||||
|
if key[0] != '#':
|
||||||
|
if isinstance(val, (dict, OrderedDict)):
|
||||||
|
ret.update({key: ini_odict2dict(val)})
|
||||||
|
else:
|
||||||
|
ret.update({key: val})
|
||||||
|
return ret
|
||||||
|
|
||||||
inifile = _Ini.get_ini_file(file_name, separator=separator)
|
inifile = _Ini.get_ini_file(file_name, separator=separator)
|
||||||
section = inifile.pop(section, {})
|
return ini_odict2dict(inifile)
|
||||||
inifile.flush()
|
|
||||||
ret = {}
|
|
||||||
for key, value in six.iteritems(section):
|
|
||||||
if key[0] != '#':
|
|
||||||
ret.update({key: value})
|
|
||||||
return ret
|
|
||||||
|
|
||||||
|
|
||||||
class _Section(OrderedDict):
|
class _Section(OrderedDict):
|
||||||
@ -221,7 +268,7 @@ class _Section(OrderedDict):
|
|||||||
self.pop(opt)
|
self.pop(opt)
|
||||||
for opt_str in inicontents.split(os.linesep):
|
for opt_str in inicontents.split(os.linesep):
|
||||||
# Match comments
|
# Match comments
|
||||||
com_match = com_regx.match(opt_str)
|
com_match = COM_REGX.match(opt_str)
|
||||||
if com_match:
|
if com_match:
|
||||||
name = '#comment{0}'.format(comment_count)
|
name = '#comment{0}'.format(comment_count)
|
||||||
self.com = com_match.group(1)
|
self.com = com_match.group(1)
|
||||||
@ -229,7 +276,7 @@ class _Section(OrderedDict):
|
|||||||
self.update({name: opt_str})
|
self.update({name: opt_str})
|
||||||
continue
|
continue
|
||||||
# Add indented lines to the value of the previous entry.
|
# Add indented lines to the value of the previous entry.
|
||||||
indented_match = indented_regx.match(opt_str)
|
indented_match = INDENTED_REGX.match(opt_str)
|
||||||
if indented_match:
|
if indented_match:
|
||||||
indent = indented_match.group(1).replace('\t', ' ')
|
indent = indented_match.group(1).replace('\t', ' ')
|
||||||
if indent > curr_indent:
|
if indent > curr_indent:
|
||||||
@ -318,7 +365,7 @@ class _Section(OrderedDict):
|
|||||||
sections_dict = OrderedDict()
|
sections_dict = OrderedDict()
|
||||||
for name, value in six.iteritems(self):
|
for name, value in six.iteritems(self):
|
||||||
# Handle Comment Lines
|
# Handle Comment Lines
|
||||||
if com_regx.match(name):
|
if COM_REGX.match(name):
|
||||||
yield '{0}{1}'.format(value, os.linesep)
|
yield '{0}{1}'.format(value, os.linesep)
|
||||||
# Handle Sections
|
# Handle Sections
|
||||||
elif isinstance(value, _Section):
|
elif isinstance(value, _Section):
|
||||||
@ -363,9 +410,6 @@ class _Section(OrderedDict):
|
|||||||
|
|
||||||
|
|
||||||
class _Ini(_Section):
|
class _Ini(_Section):
|
||||||
def __init__(self, name, inicontents='', separator='=', commenter='#'):
|
|
||||||
super(_Ini, self).__init__(name, inicontents, separator, commenter)
|
|
||||||
|
|
||||||
def refresh(self, inicontents=None):
|
def refresh(self, inicontents=None):
|
||||||
if inicontents is None:
|
if inicontents is None:
|
||||||
try:
|
try:
|
||||||
@ -382,7 +426,7 @@ class _Ini(_Section):
|
|||||||
# Remove anything left behind from a previous run.
|
# Remove anything left behind from a previous run.
|
||||||
self.clear()
|
self.clear()
|
||||||
|
|
||||||
inicontents = ini_regx.split(inicontents)
|
inicontents = INI_REGX.split(inicontents)
|
||||||
inicontents.reverse()
|
inicontents.reverse()
|
||||||
# Pop anything defined outside of a section (ie. at the top of
|
# Pop anything defined outside of a section (ie. at the top of
|
||||||
# the ini file).
|
# the ini file).
|
||||||
|
@ -2268,22 +2268,22 @@ def _change_state(cmd,
|
|||||||
# as te command itself mess with double forks; we must not
|
# as te command itself mess with double forks; we must not
|
||||||
# communicate with it, but just wait for the exit status
|
# communicate with it, but just wait for the exit status
|
||||||
pkwargs = {'python_shell': False,
|
pkwargs = {'python_shell': False,
|
||||||
|
'redirect_stderr': True,
|
||||||
'with_communicate': with_communicate,
|
'with_communicate': with_communicate,
|
||||||
'use_vt': use_vt,
|
'use_vt': use_vt,
|
||||||
'stdin': stdin,
|
'stdin': stdin,
|
||||||
'stdout': stdout,
|
'stdout': stdout}
|
||||||
'stderr': stderr}
|
|
||||||
for i in [a for a in pkwargs]:
|
for i in [a for a in pkwargs]:
|
||||||
val = pkwargs[i]
|
val = pkwargs[i]
|
||||||
if val is _marker:
|
if val is _marker:
|
||||||
pkwargs.pop(i, None)
|
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(
|
raise CommandExecutionError(
|
||||||
'Error changing state for container \'{0}\' using command '
|
'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:
|
if expected is not None:
|
||||||
# some commands do not wait, so we will
|
# some commands do not wait, so we will
|
||||||
|
@ -48,7 +48,7 @@ def _list_taps():
|
|||||||
'''
|
'''
|
||||||
List currently installed brew taps
|
List currently installed brew taps
|
||||||
'''
|
'''
|
||||||
cmd = 'brew tap'
|
cmd = 'tap'
|
||||||
return _call_brew(cmd)['stdout'].splitlines()
|
return _call_brew(cmd)['stdout'].splitlines()
|
||||||
|
|
||||||
|
|
||||||
@ -60,7 +60,7 @@ def _tap(tap, runas=None):
|
|||||||
if tap in _list_taps():
|
if tap in _list_taps():
|
||||||
return True
|
return True
|
||||||
|
|
||||||
cmd = 'brew tap {0}'.format(tap)
|
cmd = 'tap {0}'.format(tap)
|
||||||
try:
|
try:
|
||||||
_call_brew(cmd)
|
_call_brew(cmd)
|
||||||
except CommandExecutionError:
|
except CommandExecutionError:
|
||||||
@ -85,6 +85,7 @@ def _call_brew(cmd, failhard=True):
|
|||||||
'''
|
'''
|
||||||
user = __salt__['file.get_user'](_homebrew_bin())
|
user = __salt__['file.get_user'](_homebrew_bin())
|
||||||
runas = user if user != __opts__['user'] else None
|
runas = user if user != __opts__['user'] else None
|
||||||
|
cmd = '{} {}'.format(salt.utils.path.which('brew'), cmd)
|
||||||
result = __salt__['cmd.run_all'](cmd,
|
result = __salt__['cmd.run_all'](cmd,
|
||||||
runas=runas,
|
runas=runas,
|
||||||
output_loglevel='trace',
|
output_loglevel='trace',
|
||||||
@ -121,7 +122,7 @@ def list_pkgs(versions_as_list=False, **kwargs):
|
|||||||
__salt__['pkg_resource.stringify'](ret)
|
__salt__['pkg_resource.stringify'](ret)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
cmd = 'brew list --versions'
|
cmd = 'list --versions'
|
||||||
ret = {}
|
ret = {}
|
||||||
out = _call_brew(cmd)['stdout']
|
out = _call_brew(cmd)['stdout']
|
||||||
for line in out.splitlines():
|
for line in out.splitlines():
|
||||||
@ -230,7 +231,7 @@ def remove(name=None, pkgs=None, **kwargs):
|
|||||||
targets = [x for x in pkg_params if x in old]
|
targets = [x for x in pkg_params if x in old]
|
||||||
if not targets:
|
if not targets:
|
||||||
return {}
|
return {}
|
||||||
cmd = 'brew uninstall {0}'.format(' '.join(targets))
|
cmd = 'uninstall {0}'.format(' '.join(targets))
|
||||||
|
|
||||||
out = _call_brew(cmd)
|
out = _call_brew(cmd)
|
||||||
if out['retcode'] != 0 and out['stderr']:
|
if out['retcode'] != 0 and out['stderr']:
|
||||||
@ -263,7 +264,7 @@ def refresh_db():
|
|||||||
'''
|
'''
|
||||||
# Remove rtag file to keep multiple refreshes from happening in pkg states
|
# Remove rtag file to keep multiple refreshes from happening in pkg states
|
||||||
salt.utils.pkg.clear_rtag(__opts__)
|
salt.utils.pkg.clear_rtag(__opts__)
|
||||||
cmd = 'brew update'
|
cmd = 'update'
|
||||||
if _call_brew(cmd)['retcode']:
|
if _call_brew(cmd)['retcode']:
|
||||||
log.error('Failed to update')
|
log.error('Failed to update')
|
||||||
return False
|
return False
|
||||||
@ -286,7 +287,7 @@ def _info(*pkgs):
|
|||||||
Caveat: If one of the packages does not exist, no packages will be
|
Caveat: If one of the packages does not exist, no packages will be
|
||||||
included in the output.
|
included in the output.
|
||||||
'''
|
'''
|
||||||
cmd = 'brew info --json=v1 {0}'.format(' '.join(pkgs))
|
cmd = 'info --json=v1 {0}'.format(' '.join(pkgs))
|
||||||
brew_result = _call_brew(cmd)
|
brew_result = _call_brew(cmd)
|
||||||
if brew_result['retcode']:
|
if brew_result['retcode']:
|
||||||
log.error('Failed to get info about packages: %s',
|
log.error('Failed to get info about packages: %s',
|
||||||
@ -382,9 +383,9 @@ def install(name=None, pkgs=None, taps=None, options=None, **kwargs):
|
|||||||
_tap(tap)
|
_tap(tap)
|
||||||
|
|
||||||
if options:
|
if options:
|
||||||
cmd = 'brew install {0} {1}'.format(formulas, ' '.join(options))
|
cmd = 'install {0} {1}'.format(formulas, ' '.join(options))
|
||||||
else:
|
else:
|
||||||
cmd = 'brew install {0}'.format(formulas)
|
cmd = 'install {0}'.format(formulas)
|
||||||
|
|
||||||
out = _call_brew(cmd)
|
out = _call_brew(cmd)
|
||||||
if out['retcode'] != 0 and out['stderr']:
|
if out['retcode'] != 0 and out['stderr']:
|
||||||
@ -418,7 +419,7 @@ def list_upgrades(refresh=True, **kwargs): # pylint: disable=W0613
|
|||||||
if refresh:
|
if refresh:
|
||||||
refresh_db()
|
refresh_db()
|
||||||
|
|
||||||
res = _call_brew(['brew', 'outdated', '--json=v1'])
|
res = _call_brew('outdated --json=v1')
|
||||||
ret = {}
|
ret = {}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -478,7 +479,7 @@ def upgrade(refresh=True):
|
|||||||
if salt.utils.data.is_true(refresh):
|
if salt.utils.data.is_true(refresh):
|
||||||
refresh_db()
|
refresh_db()
|
||||||
|
|
||||||
result = _call_brew('brew upgrade', failhard=False)
|
result = _call_brew('upgrade', failhard=False)
|
||||||
__context__.pop('pkg.list_pkgs', None)
|
__context__.pop('pkg.list_pkgs', None)
|
||||||
new = list_pkgs()
|
new = list_pkgs()
|
||||||
ret = salt.utils.data.compare_dicts(old, new)
|
ret = salt.utils.data.compare_dicts(old, new)
|
||||||
|
@ -433,7 +433,6 @@ def disabled(name, runas=None, domain='system'):
|
|||||||
disabled = launchctl('print-disabled',
|
disabled = launchctl('print-disabled',
|
||||||
domain,
|
domain,
|
||||||
return_stdout=True,
|
return_stdout=True,
|
||||||
output_loglevel='trace',
|
|
||||||
runas=runas)
|
runas=runas)
|
||||||
for service in disabled.split("\n"):
|
for service in disabled.split("\n"):
|
||||||
if name in service:
|
if name in service:
|
||||||
|
@ -959,7 +959,7 @@ def alter_db(name, character_set=None, collate=None, **connection_args):
|
|||||||
return []
|
return []
|
||||||
cur = dbc.cursor()
|
cur = dbc.cursor()
|
||||||
existing = db_get(name, **connection_args)
|
existing = db_get(name, **connection_args)
|
||||||
qry = 'ALTER DATABASE {0} CHARACTER SET {1} COLLATE {2};'.format(
|
qry = 'ALTER DATABASE `{0}` CHARACTER SET {1} COLLATE {2};'.format(
|
||||||
name.replace('%', r'\%').replace('_', r'\_'),
|
name.replace('%', r'\%').replace('_', r'\_'),
|
||||||
character_set or existing.get('character_set'),
|
character_set or existing.get('character_set'),
|
||||||
collate or existing.get('collate'))
|
collate or existing.get('collate'))
|
||||||
@ -1812,11 +1812,16 @@ def grant_exists(grant,
|
|||||||
if not target_tokens: # Avoid the overhead of re-calc in loop
|
if not target_tokens: # Avoid the overhead of re-calc in loop
|
||||||
target_tokens = _grant_to_tokens(target)
|
target_tokens = _grant_to_tokens(target)
|
||||||
grant_tokens = _grant_to_tokens(grant)
|
grant_tokens = _grant_to_tokens(grant)
|
||||||
grant_tokens_database = grant_tokens['database'].replace('"', '').replace('\\', '').replace('`', '')
|
|
||||||
target_tokens_database = target_tokens['database'].replace('"', '').replace('\\', '').replace('`', '')
|
_grant_tokens = {}
|
||||||
if grant_tokens['user'] == target_tokens['user'] and \
|
_target_tokens = {}
|
||||||
grant_tokens_database == target_tokens_database and \
|
for item in ['user', 'database', 'host']:
|
||||||
grant_tokens['host'] == target_tokens['host'] and \
|
_grant_tokens[item] = grant_tokens[item].replace('"', '').replace('\\', '').replace('`', '')
|
||||||
|
_target_tokens[item] = target_tokens[item].replace('"', '').replace('\\', '').replace('`', '')
|
||||||
|
|
||||||
|
if _grant_tokens['user'] == _target_tokens['user'] and \
|
||||||
|
_grant_tokens['database'] == _target_tokens['database'] and \
|
||||||
|
_grant_tokens['host'] == _target_tokens['host'] and \
|
||||||
set(grant_tokens['grant']) >= set(target_tokens['grant']):
|
set(grant_tokens['grant']) >= set(target_tokens['grant']):
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
|
@ -98,20 +98,16 @@ def _space_delimited_list(value):
|
|||||||
'''
|
'''
|
||||||
validate that a value contains one or more space-delimited values
|
validate that a value contains one or more space-delimited values
|
||||||
'''
|
'''
|
||||||
valid, _value, errmsg = False, value, 'space-delimited string'
|
if isinstance(value, str):
|
||||||
try:
|
items = value.split(' ')
|
||||||
if hasattr(value, '__iter__'):
|
valid = items and all(items)
|
||||||
valid = True
|
else:
|
||||||
else:
|
valid = hasattr(value, '__iter__') and (value != [])
|
||||||
_value = value.split()
|
|
||||||
if _value == []:
|
if valid:
|
||||||
raise ValueError
|
return (True, 'space-delimited string')
|
||||||
valid = True
|
else:
|
||||||
except AttributeError:
|
return (False, '{0} is not a valid list.\n'.format(value))
|
||||||
errmsg = '{0} is not a valid list.\n'.format(value)
|
|
||||||
except ValueError:
|
|
||||||
errmsg = '{0} is not a valid list.\n'.format(value)
|
|
||||||
return (valid, errmsg)
|
|
||||||
|
|
||||||
|
|
||||||
def _validate_ipv4(value):
|
def _validate_ipv4(value):
|
||||||
|
@ -162,7 +162,11 @@ def install(pkg=None,
|
|||||||
env.update({'SUDO_UID': uid, 'SUDO_USER': ''})
|
env.update({'SUDO_UID': uid, 'SUDO_USER': ''})
|
||||||
|
|
||||||
cmd = ' '.join(cmd)
|
cmd = ' '.join(cmd)
|
||||||
result = __salt__['cmd.run_all'](cmd, python_shell=True, cwd=dir, runas=runas, env=env)
|
result = __salt__['cmd.run_all'](cmd,
|
||||||
|
python_shell=True,
|
||||||
|
cwd=dir,
|
||||||
|
runas=runas,
|
||||||
|
env=env)
|
||||||
|
|
||||||
if result['retcode'] != 0:
|
if result['retcode'] != 0:
|
||||||
raise CommandExecutionError(result['stderr'])
|
raise CommandExecutionError(result['stderr'])
|
||||||
@ -170,33 +174,9 @@ def install(pkg=None,
|
|||||||
# npm >1.2.21 is putting the output to stderr even though retcode is 0
|
# npm >1.2.21 is putting the output to stderr even though retcode is 0
|
||||||
npm_output = result['stdout'] or result['stderr']
|
npm_output = result['stdout'] or result['stderr']
|
||||||
try:
|
try:
|
||||||
return salt.utils.json.loads(npm_output)
|
return salt.utils.json.find_json(npm_output)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
return npm_output
|
||||||
|
|
||||||
json_npm_output = _extract_json(npm_output)
|
|
||||||
return json_npm_output or npm_output
|
|
||||||
|
|
||||||
|
|
||||||
def _extract_json(npm_output):
|
|
||||||
lines = npm_output.splitlines()
|
|
||||||
log.error(lines)
|
|
||||||
|
|
||||||
# Strip all lines until JSON output starts
|
|
||||||
while lines and not lines[0].startswith('{') and not lines[0].startswith('['):
|
|
||||||
lines = lines[1:]
|
|
||||||
while lines and not lines[-1].startswith('}') and not lines[-1].startswith(']'):
|
|
||||||
lines = lines[:-1]
|
|
||||||
# macOS with fsevents includes the following line in the return
|
|
||||||
# when a new module is installed which is invalid JSON:
|
|
||||||
# [fsevents] Success: "..."
|
|
||||||
while lines and (lines[0].startswith('[fsevents]') or lines[0].startswith('Pass ')):
|
|
||||||
lines = lines[1:]
|
|
||||||
try:
|
|
||||||
return salt.utils.json.loads(''.join(lines))
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def uninstall(pkg, dir=None, runas=None, env=None):
|
def uninstall(pkg, dir=None, runas=None, env=None):
|
||||||
|
@ -25,13 +25,13 @@ def __virtual__():
|
|||||||
'''
|
'''
|
||||||
if salt.utils.platform.is_darwin() or salt.utils.platform.is_windows():
|
if salt.utils.platform.is_darwin() or salt.utils.platform.is_windows():
|
||||||
return True
|
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 = {}
|
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)
|
match = re.match('Enabled: (.*)\nServer: (.*)\nPort: (.*)\n', out)
|
||||||
if match is not None:
|
if match is not None:
|
||||||
g = match.groups()
|
g = match.groups()
|
||||||
@ -41,8 +41,8 @@ def _get_proxy_osx(function, network_service):
|
|||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def _set_proxy_osx(function, server, port, user, password, network_service):
|
def _set_proxy_osx(cmd_function, server, port, user, password, network_service):
|
||||||
cmd = 'networksetup -{0} {1} {2} {3}'.format(function, network_service, server, port)
|
cmd = 'networksetup -{0} {1} {2} {3}'.format(cmd_function, network_service, server, port)
|
||||||
|
|
||||||
if user is not None and password is not None:
|
if user is not None and password is not None:
|
||||||
cmd = cmd + ' On {0} {1}'.format(user, password)
|
cmd = cmd + ' On {0} {1}'.format(user, password)
|
||||||
@ -58,12 +58,12 @@ def _get_proxy_windows(types=None):
|
|||||||
if types is None:
|
if types is None:
|
||||||
types = ['http', 'https', 'ftp']
|
types = ['http', 'https', 'ftp']
|
||||||
|
|
||||||
reg_val = __salt__['reg.read_value']('HKEY_CURRENT_USER',
|
servers = __salt__['reg.read_value'](
|
||||||
r'SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings',
|
hive='HKEY_CURRENT_USER',
|
||||||
'ProxyServer')
|
key=r'SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings',
|
||||||
servers = reg_val['vdata']
|
vname='ProxyServer')['vdata']
|
||||||
|
|
||||||
if "=" in servers:
|
if servers and "=" in servers:
|
||||||
split = servers.split(";")
|
split = servers.split(";")
|
||||||
for s in split:
|
for s in split:
|
||||||
if len(s) == 0:
|
if len(s) == 0:
|
||||||
@ -87,16 +87,19 @@ def _get_proxy_windows(types=None):
|
|||||||
del ret[key]
|
del ret[key]
|
||||||
|
|
||||||
# Return enabled info
|
# Return enabled info
|
||||||
reg_val = __salt__['reg.read_value']('HKEY_CURRENT_USER',
|
ret['enabled'] = __salt__['reg.read_value'](
|
||||||
r'SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings',
|
hive='HKEY_CURRENT_USER',
|
||||||
'ProxyEnable')
|
key=r'SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings',
|
||||||
enabled = reg_val.get('vdata', 0)
|
vname='ProxyEnable')['vdata'] == 1
|
||||||
ret['enabled'] = True if enabled == 1 else False
|
|
||||||
|
|
||||||
return ret
|
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:
|
if types is None:
|
||||||
types = ['http', 'https', 'ftp']
|
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:
|
for t in types:
|
||||||
server_str += '{0}={1}:{2};'.format(t, server, port)
|
server_str += '{0}={1}:{2};'.format(t, server, port)
|
||||||
|
|
||||||
__salt__['reg.set_value']('HKEY_CURRENT_USER', r'SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings',
|
__salt__['reg.set_value'](
|
||||||
'ProxyServer', server_str)
|
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',
|
__salt__['reg.set_value'](
|
||||||
'ProxyEnable', 1, vtype='REG_DWORD')
|
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:
|
if bypass_hosts is not None:
|
||||||
bypass_hosts_str = '<local>;{0}'.format(';'.join(bypass_hosts))
|
bypass_hosts_str = '<local>;{0}'.format(';'.join(bypass_hosts))
|
||||||
|
|
||||||
__salt__['reg.set_value']('HKEY_CURRENT_USER', r'SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings',
|
__salt__['reg.set_value'](
|
||||||
'ProxyOverride', bypass_hosts_str)
|
hive='HKEY_CURRENT_USER',
|
||||||
|
key=r'SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings',
|
||||||
|
vname='ProxyOverride',
|
||||||
|
vdata=bypass_hosts_str)
|
||||||
|
|
||||||
if import_winhttp:
|
if import_winhttp:
|
||||||
cmd = 'netsh winhttp import proxy source=ie'
|
cmd = 'netsh winhttp import proxy source=ie'
|
||||||
@ -138,15 +151,22 @@ def get_http_proxy(network_service="Ethernet"):
|
|||||||
salt '*' proxy.get_http_proxy Ethernet
|
salt '*' proxy.get_http_proxy Ethernet
|
||||||
'''
|
'''
|
||||||
if __grains__['os'] == 'Windows':
|
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,
|
Sets the http proxy settings. Note: On Windows this will override any other
|
||||||
the preferred method of updating proxies on windows is using set_proxy.
|
proxy settings you have, the preferred method of updating proxies on windows
|
||||||
|
is using set_proxy.
|
||||||
|
|
||||||
server
|
server
|
||||||
The proxy server to use
|
The proxy server to use
|
||||||
@ -165,8 +185,8 @@ def set_http_proxy(server, port, user=None, password=None, network_service="Ethe
|
|||||||
macOS
|
macOS
|
||||||
|
|
||||||
bypass_hosts
|
bypass_hosts
|
||||||
The hosts that are allowed to by pass the proxy. Only used on Windows for other OS's use
|
The hosts that are allowed to by pass the proxy. Only used on Windows
|
||||||
set_proxy_bypass to edit the bypass hosts.
|
for other OS's use set_proxy_bypass to edit the bypass hosts.
|
||||||
|
|
||||||
CLI Example:
|
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
|
salt '*' proxy.set_http_proxy example.com 1080 user=proxy_user password=proxy_pass network_service=Ethernet
|
||||||
'''
|
'''
|
||||||
if __grains__['os'] == 'Windows':
|
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"):
|
def get_https_proxy(network_service="Ethernet"):
|
||||||
@ -195,15 +223,22 @@ def get_https_proxy(network_service="Ethernet"):
|
|||||||
salt '*' proxy.get_https_proxy Ethernet
|
salt '*' proxy.get_https_proxy Ethernet
|
||||||
'''
|
'''
|
||||||
if __grains__['os'] == 'Windows':
|
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,
|
Sets the https proxy settings. Note: On Windows this will override any other
|
||||||
the preferred method of updating proxies on windows is using set_proxy.
|
proxy settings you have, the preferred method of updating proxies on windows
|
||||||
|
is using set_proxy.
|
||||||
|
|
||||||
server
|
server
|
||||||
The proxy server to use
|
The proxy server to use
|
||||||
@ -222,8 +257,8 @@ def set_https_proxy(server, port, user=None, password=None, network_service="Eth
|
|||||||
macOS
|
macOS
|
||||||
|
|
||||||
bypass_hosts
|
bypass_hosts
|
||||||
The hosts that are allowed to by pass the proxy. Only used on Windows for other OS's use
|
The hosts that are allowed to by pass the proxy. Only used on Windows
|
||||||
set_proxy_bypass to edit the bypass hosts.
|
for other OS's use set_proxy_bypass to edit the bypass hosts.
|
||||||
|
|
||||||
CLI Example:
|
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
|
salt '*' proxy.set_https_proxy example.com 1080 user=proxy_user password=proxy_pass network_service=Ethernet
|
||||||
'''
|
'''
|
||||||
if __grains__['os'] == 'Windows':
|
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"):
|
def get_ftp_proxy(network_service="Ethernet"):
|
||||||
@ -252,12 +295,18 @@ def get_ftp_proxy(network_service="Ethernet"):
|
|||||||
salt '*' proxy.get_ftp_proxy Ethernet
|
salt '*' proxy.get_ftp_proxy Ethernet
|
||||||
'''
|
'''
|
||||||
if __grains__['os'] == 'Windows':
|
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
|
Sets the ftp proxy settings
|
||||||
|
|
||||||
@ -278,8 +327,8 @@ def set_ftp_proxy(server, port, user=None, password=None, network_service="Ether
|
|||||||
macOS
|
macOS
|
||||||
|
|
||||||
bypass_hosts
|
bypass_hosts
|
||||||
The hosts that are allowed to by pass the proxy. Only used on Windows for other OS's use
|
The hosts that are allowed to by pass the proxy. Only used on Windows
|
||||||
set_proxy_bypass to edit the bypass hosts.
|
for other OS's use set_proxy_bypass to edit the bypass hosts.
|
||||||
|
|
||||||
CLI Example:
|
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
|
salt '*' proxy.set_ftp_proxy example.com 1080 user=proxy_user password=proxy_pass network_service=Ethernet
|
||||||
'''
|
'''
|
||||||
if __grains__['os'] == 'Windows':
|
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"):
|
def get_proxy_bypass(network_service="Ethernet"):
|
||||||
@ -309,12 +366,16 @@ def get_proxy_bypass(network_service="Ethernet"):
|
|||||||
|
|
||||||
'''
|
'''
|
||||||
if __grains__['os'] == 'Windows':
|
if __grains__['os'] == 'Windows':
|
||||||
reg_val = __salt__['reg.read_value']('HKEY_CURRENT_USER',
|
reg_val = __salt__['reg.read_value'](
|
||||||
r'SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings',
|
hive='HKEY_CURRENT_USER',
|
||||||
'ProxyOverride')
|
key=r'SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings',
|
||||||
bypass_servers = reg_val['vdata'].replace("<local>", "").split(";")
|
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))
|
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
|
The password to use if required by the server
|
||||||
|
|
||||||
types
|
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
|
bypass_hosts
|
||||||
The hosts that are allowed to by pass the proxy.
|
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']"
|
salt '*' proxy.set_http_proxy example.com 1080 types="['http', 'https']"
|
||||||
'''
|
'''
|
||||||
if __grains__['os'] == 'Windows':
|
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():
|
def get_proxy_win():
|
||||||
|
@ -225,6 +225,7 @@ def list_users(runas=None):
|
|||||||
runas = salt.utils.user.get_user()
|
runas = salt.utils.user.get_user()
|
||||||
res = __salt__['cmd.run_all'](
|
res = __salt__['cmd.run_all'](
|
||||||
[RABBITMQCTL, 'list_users', '-q'],
|
[RABBITMQCTL, 'list_users', '-q'],
|
||||||
|
reset_system_locale=False,
|
||||||
runas=runas,
|
runas=runas,
|
||||||
python_shell=False)
|
python_shell=False)
|
||||||
|
|
||||||
@ -248,6 +249,7 @@ def list_vhosts(runas=None):
|
|||||||
runas = salt.utils.user.get_user()
|
runas = salt.utils.user.get_user()
|
||||||
res = __salt__['cmd.run_all'](
|
res = __salt__['cmd.run_all'](
|
||||||
[RABBITMQCTL, 'list_vhosts', '-q'],
|
[RABBITMQCTL, 'list_vhosts', '-q'],
|
||||||
|
reset_system_locale=False,
|
||||||
runas=runas,
|
runas=runas,
|
||||||
python_shell=False)
|
python_shell=False)
|
||||||
_check_response(res)
|
_check_response(res)
|
||||||
@ -322,6 +324,7 @@ def add_user(name, password=None, runas=None):
|
|||||||
|
|
||||||
res = __salt__['cmd.run_all'](
|
res = __salt__['cmd.run_all'](
|
||||||
cmd,
|
cmd,
|
||||||
|
reset_system_locale=False,
|
||||||
output_loglevel='quiet',
|
output_loglevel='quiet',
|
||||||
runas=runas,
|
runas=runas,
|
||||||
python_shell=python_shell)
|
python_shell=python_shell)
|
||||||
@ -354,6 +357,7 @@ def delete_user(name, runas=None):
|
|||||||
runas = salt.utils.user.get_user()
|
runas = salt.utils.user.get_user()
|
||||||
res = __salt__['cmd.run_all'](
|
res = __salt__['cmd.run_all'](
|
||||||
[RABBITMQCTL, 'delete_user', name],
|
[RABBITMQCTL, 'delete_user', name],
|
||||||
|
reset_system_locale=False,
|
||||||
python_shell=False,
|
python_shell=False,
|
||||||
runas=runas)
|
runas=runas)
|
||||||
msg = 'Deleted'
|
msg = 'Deleted'
|
||||||
@ -389,6 +393,7 @@ def change_password(name, password, runas=None):
|
|||||||
cmd = [RABBITMQCTL, 'change_password', name, password]
|
cmd = [RABBITMQCTL, 'change_password', name, password]
|
||||||
res = __salt__['cmd.run_all'](
|
res = __salt__['cmd.run_all'](
|
||||||
cmd,
|
cmd,
|
||||||
|
reset_system_locale=False,
|
||||||
runas=runas,
|
runas=runas,
|
||||||
output_loglevel='quiet',
|
output_loglevel='quiet',
|
||||||
python_shell=python_shell)
|
python_shell=python_shell)
|
||||||
@ -411,6 +416,7 @@ def clear_password(name, runas=None):
|
|||||||
runas = salt.utils.user.get_user()
|
runas = salt.utils.user.get_user()
|
||||||
res = __salt__['cmd.run_all'](
|
res = __salt__['cmd.run_all'](
|
||||||
[RABBITMQCTL, 'clear_password', name],
|
[RABBITMQCTL, 'clear_password', name],
|
||||||
|
reset_system_locale=False,
|
||||||
runas=runas,
|
runas=runas,
|
||||||
python_shell=False)
|
python_shell=False)
|
||||||
msg = 'Password Cleared'
|
msg = 'Password Cleared'
|
||||||
@ -436,7 +442,7 @@ def check_password(name, password, runas=None):
|
|||||||
runas = salt.utils.user.get_user()
|
runas = salt.utils.user.get_user()
|
||||||
|
|
||||||
try:
|
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)
|
server_version = re.search(r'\{rabbit,"RabbitMQ","(.+)"\}', res)
|
||||||
|
|
||||||
if server_version is None:
|
if server_version is None:
|
||||||
@ -468,6 +474,7 @@ def check_password(name, password, runas=None):
|
|||||||
|
|
||||||
res = __salt__['cmd.run_all'](
|
res = __salt__['cmd.run_all'](
|
||||||
cmd,
|
cmd,
|
||||||
|
reset_system_locale=False,
|
||||||
runas=runas,
|
runas=runas,
|
||||||
output_loglevel='quiet',
|
output_loglevel='quiet',
|
||||||
python_shell=python_shell)
|
python_shell=python_shell)
|
||||||
@ -483,6 +490,7 @@ def check_password(name, password, runas=None):
|
|||||||
|
|
||||||
res = __salt__['cmd.run_all'](
|
res = __salt__['cmd.run_all'](
|
||||||
[RABBITMQCTL, 'eval', cmd],
|
[RABBITMQCTL, 'eval', cmd],
|
||||||
|
reset_system_locale=False,
|
||||||
runas=runas,
|
runas=runas,
|
||||||
output_loglevel='quiet',
|
output_loglevel='quiet',
|
||||||
python_shell=False)
|
python_shell=False)
|
||||||
@ -511,6 +519,7 @@ def add_vhost(vhost, runas=None):
|
|||||||
runas = salt.utils.user.get_user()
|
runas = salt.utils.user.get_user()
|
||||||
res = __salt__['cmd.run_all'](
|
res = __salt__['cmd.run_all'](
|
||||||
[RABBITMQCTL, 'add_vhost', vhost],
|
[RABBITMQCTL, 'add_vhost', vhost],
|
||||||
|
reset_system_locale=False,
|
||||||
runas=runas,
|
runas=runas,
|
||||||
python_shell=False)
|
python_shell=False)
|
||||||
|
|
||||||
@ -532,6 +541,7 @@ def delete_vhost(vhost, runas=None):
|
|||||||
runas = salt.utils.user.get_user()
|
runas = salt.utils.user.get_user()
|
||||||
res = __salt__['cmd.run_all'](
|
res = __salt__['cmd.run_all'](
|
||||||
[RABBITMQCTL, 'delete_vhost', vhost],
|
[RABBITMQCTL, 'delete_vhost', vhost],
|
||||||
|
reset_system_locale=False,
|
||||||
runas=runas,
|
runas=runas,
|
||||||
python_shell=False)
|
python_shell=False)
|
||||||
msg = 'Deleted'
|
msg = 'Deleted'
|
||||||
@ -553,6 +563,7 @@ def set_permissions(vhost, user, conf='.*', write='.*', read='.*', runas=None):
|
|||||||
res = __salt__['cmd.run_all'](
|
res = __salt__['cmd.run_all'](
|
||||||
[RABBITMQCTL, 'set_permissions', '-p',
|
[RABBITMQCTL, 'set_permissions', '-p',
|
||||||
vhost, user, conf, write, read],
|
vhost, user, conf, write, read],
|
||||||
|
reset_system_locale=False,
|
||||||
runas=runas,
|
runas=runas,
|
||||||
python_shell=False)
|
python_shell=False)
|
||||||
msg = 'Permissions Set'
|
msg = 'Permissions Set'
|
||||||
@ -573,6 +584,7 @@ def list_permissions(vhost, runas=None):
|
|||||||
runas = salt.utils.user.get_user()
|
runas = salt.utils.user.get_user()
|
||||||
res = __salt__['cmd.run_all'](
|
res = __salt__['cmd.run_all'](
|
||||||
[RABBITMQCTL, 'list_permissions', '-q', '-p', vhost],
|
[RABBITMQCTL, 'list_permissions', '-q', '-p', vhost],
|
||||||
|
reset_system_locale=False,
|
||||||
runas=runas,
|
runas=runas,
|
||||||
python_shell=False)
|
python_shell=False)
|
||||||
|
|
||||||
@ -593,6 +605,7 @@ def list_user_permissions(name, runas=None):
|
|||||||
runas = salt.utils.user.get_user()
|
runas = salt.utils.user.get_user()
|
||||||
res = __salt__['cmd.run_all'](
|
res = __salt__['cmd.run_all'](
|
||||||
[RABBITMQCTL, 'list_user_permissions', name, '-q'],
|
[RABBITMQCTL, 'list_user_permissions', name, '-q'],
|
||||||
|
reset_system_locale=False,
|
||||||
runas=runas,
|
runas=runas,
|
||||||
python_shell=False)
|
python_shell=False)
|
||||||
|
|
||||||
@ -616,6 +629,7 @@ def set_user_tags(name, tags, runas=None):
|
|||||||
|
|
||||||
res = __salt__['cmd.run_all'](
|
res = __salt__['cmd.run_all'](
|
||||||
[RABBITMQCTL, 'set_user_tags', name] + list(tags),
|
[RABBITMQCTL, 'set_user_tags', name] + list(tags),
|
||||||
|
reset_system_locale=False,
|
||||||
runas=runas,
|
runas=runas,
|
||||||
python_shell=False)
|
python_shell=False)
|
||||||
msg = "Tag(s) set"
|
msg = "Tag(s) set"
|
||||||
@ -636,6 +650,7 @@ def status(runas=None):
|
|||||||
runas = salt.utils.user.get_user()
|
runas = salt.utils.user.get_user()
|
||||||
res = __salt__['cmd.run_all'](
|
res = __salt__['cmd.run_all'](
|
||||||
[RABBITMQCTL, 'status'],
|
[RABBITMQCTL, 'status'],
|
||||||
|
reset_system_locale=False,
|
||||||
runas=runas,
|
runas=runas,
|
||||||
python_shell=False)
|
python_shell=False)
|
||||||
_check_response(res)
|
_check_response(res)
|
||||||
@ -656,6 +671,7 @@ def cluster_status(runas=None):
|
|||||||
runas = salt.utils.user.get_user()
|
runas = salt.utils.user.get_user()
|
||||||
res = __salt__['cmd.run_all'](
|
res = __salt__['cmd.run_all'](
|
||||||
[RABBITMQCTL, 'cluster_status'],
|
[RABBITMQCTL, 'cluster_status'],
|
||||||
|
reset_system_locale=False,
|
||||||
runas=runas,
|
runas=runas,
|
||||||
python_shell=False)
|
python_shell=False)
|
||||||
_check_response(res)
|
_check_response(res)
|
||||||
@ -680,7 +696,7 @@ def join_cluster(host, user='rabbit', ram_node=None, runas=None):
|
|||||||
if runas is None and not salt.utils.platform.is_windows():
|
if runas is None and not salt.utils.platform.is_windows():
|
||||||
runas = salt.utils.user.get_user()
|
runas = salt.utils.user.get_user()
|
||||||
stop_app(runas)
|
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)
|
start_app(runas)
|
||||||
|
|
||||||
return _format_response(res, 'Join')
|
return _format_response(res, 'Join')
|
||||||
@ -700,6 +716,7 @@ def stop_app(runas=None):
|
|||||||
runas = salt.utils.user.get_user()
|
runas = salt.utils.user.get_user()
|
||||||
res = __salt__['cmd.run_all'](
|
res = __salt__['cmd.run_all'](
|
||||||
[RABBITMQCTL, 'stop_app'],
|
[RABBITMQCTL, 'stop_app'],
|
||||||
|
reset_system_locale=False,
|
||||||
runas=runas,
|
runas=runas,
|
||||||
python_shell=False)
|
python_shell=False)
|
||||||
_check_response(res)
|
_check_response(res)
|
||||||
@ -720,6 +737,7 @@ def start_app(runas=None):
|
|||||||
runas = salt.utils.user.get_user()
|
runas = salt.utils.user.get_user()
|
||||||
res = __salt__['cmd.run_all'](
|
res = __salt__['cmd.run_all'](
|
||||||
[RABBITMQCTL, 'start_app'],
|
[RABBITMQCTL, 'start_app'],
|
||||||
|
reset_system_locale=False,
|
||||||
runas=runas,
|
runas=runas,
|
||||||
python_shell=False)
|
python_shell=False)
|
||||||
_check_response(res)
|
_check_response(res)
|
||||||
@ -740,6 +758,7 @@ def reset(runas=None):
|
|||||||
runas = salt.utils.user.get_user()
|
runas = salt.utils.user.get_user()
|
||||||
res = __salt__['cmd.run_all'](
|
res = __salt__['cmd.run_all'](
|
||||||
[RABBITMQCTL, 'reset'],
|
[RABBITMQCTL, 'reset'],
|
||||||
|
reset_system_locale=False,
|
||||||
runas=runas,
|
runas=runas,
|
||||||
python_shell=False)
|
python_shell=False)
|
||||||
_check_response(res)
|
_check_response(res)
|
||||||
@ -760,6 +779,7 @@ def force_reset(runas=None):
|
|||||||
runas = salt.utils.user.get_user()
|
runas = salt.utils.user.get_user()
|
||||||
res = __salt__['cmd.run_all'](
|
res = __salt__['cmd.run_all'](
|
||||||
[RABBITMQCTL, 'force_reset'],
|
[RABBITMQCTL, 'force_reset'],
|
||||||
|
reset_system_locale=False,
|
||||||
runas=runas,
|
runas=runas,
|
||||||
python_shell=False)
|
python_shell=False)
|
||||||
_check_response(res)
|
_check_response(res)
|
||||||
@ -780,7 +800,7 @@ def list_queues(runas=None, *args):
|
|||||||
runas = salt.utils.user.get_user()
|
runas = salt.utils.user.get_user()
|
||||||
cmd = [RABBITMQCTL, 'list_queues', '-q']
|
cmd = [RABBITMQCTL, 'list_queues', '-q']
|
||||||
cmd.extend(args)
|
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)
|
_check_response(res)
|
||||||
return _output_to_dict(res['stdout'])
|
return _output_to_dict(res['stdout'])
|
||||||
|
|
||||||
@ -802,7 +822,7 @@ def list_queues_vhost(vhost, runas=None, *args):
|
|||||||
runas = salt.utils.user.get_user()
|
runas = salt.utils.user.get_user()
|
||||||
cmd = [RABBITMQCTL, 'list_queues', '-q', '-p', vhost]
|
cmd = [RABBITMQCTL, 'list_queues', '-q', '-p', vhost]
|
||||||
cmd.extend(args)
|
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)
|
_check_response(res)
|
||||||
return _output_to_dict(res['stdout'])
|
return _output_to_dict(res['stdout'])
|
||||||
|
|
||||||
@ -825,6 +845,7 @@ def list_policies(vhost="/", runas=None):
|
|||||||
runas = salt.utils.user.get_user()
|
runas = salt.utils.user.get_user()
|
||||||
res = __salt__['cmd.run_all'](
|
res = __salt__['cmd.run_all'](
|
||||||
[RABBITMQCTL, 'list_policies', '-q', '-p', vhost],
|
[RABBITMQCTL, 'list_policies', '-q', '-p', vhost],
|
||||||
|
reset_system_locale=False,
|
||||||
runas=runas,
|
runas=runas,
|
||||||
python_shell=False)
|
python_shell=False)
|
||||||
_check_response(res)
|
_check_response(res)
|
||||||
@ -902,7 +923,7 @@ def set_policy(vhost,
|
|||||||
if apply_to:
|
if apply_to:
|
||||||
cmd.extend(['--apply-to', apply_to])
|
cmd.extend(['--apply-to', apply_to])
|
||||||
cmd.extend([name, pattern, definition])
|
cmd.extend([name, pattern, definition])
|
||||||
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)
|
||||||
log.debug('Set policy: %s', res['stdout'])
|
log.debug('Set policy: %s', res['stdout'])
|
||||||
return _format_response(res, 'Set')
|
return _format_response(res, 'Set')
|
||||||
|
|
||||||
@ -923,6 +944,7 @@ def delete_policy(vhost, name, runas=None):
|
|||||||
runas = salt.utils.user.get_user()
|
runas = salt.utils.user.get_user()
|
||||||
res = __salt__['cmd.run_all'](
|
res = __salt__['cmd.run_all'](
|
||||||
[RABBITMQCTL, 'clear_policy', '-p', vhost, name],
|
[RABBITMQCTL, 'clear_policy', '-p', vhost, name],
|
||||||
|
reset_system_locale=False,
|
||||||
runas=runas,
|
runas=runas,
|
||||||
python_shell=False)
|
python_shell=False)
|
||||||
log.debug('Delete policy: %s', res['stdout'])
|
log.debug('Delete policy: %s', res['stdout'])
|
||||||
@ -960,7 +982,7 @@ def list_available_plugins(runas=None):
|
|||||||
if runas is None and not salt.utils.platform.is_windows():
|
if runas is None and not salt.utils.platform.is_windows():
|
||||||
runas = salt.utils.user.get_user()
|
runas = salt.utils.user.get_user()
|
||||||
cmd = [_get_rabbitmq_plugin(), 'list', '-m']
|
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)
|
_check_response(ret)
|
||||||
return _output_to_list(ret['stdout'])
|
return _output_to_list(ret['stdout'])
|
||||||
|
|
||||||
@ -978,7 +1000,7 @@ def list_enabled_plugins(runas=None):
|
|||||||
if runas is None and not salt.utils.platform.is_windows():
|
if runas is None and not salt.utils.platform.is_windows():
|
||||||
runas = salt.utils.user.get_user()
|
runas = salt.utils.user.get_user()
|
||||||
cmd = [_get_rabbitmq_plugin(), 'list', '-m', '-e']
|
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)
|
_check_response(ret)
|
||||||
return _output_to_list(ret['stdout'])
|
return _output_to_list(ret['stdout'])
|
||||||
|
|
||||||
@ -1011,7 +1033,7 @@ def enable_plugin(name, runas=None):
|
|||||||
if runas is None and not salt.utils.platform.is_windows():
|
if runas is None and not salt.utils.platform.is_windows():
|
||||||
runas = salt.utils.user.get_user()
|
runas = salt.utils.user.get_user()
|
||||||
cmd = [_get_rabbitmq_plugin(), 'enable', name]
|
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')
|
return _format_response(ret, 'Enabled')
|
||||||
|
|
||||||
|
|
||||||
@ -1028,5 +1050,5 @@ def disable_plugin(name, runas=None):
|
|||||||
if runas is None and not salt.utils.platform.is_windows():
|
if runas is None and not salt.utils.platform.is_windows():
|
||||||
runas = salt.utils.user.get_user()
|
runas = salt.utils.user.get_user()
|
||||||
cmd = [_get_rabbitmq_plugin(), 'disable', name]
|
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')
|
return _format_response(ret, 'Disabled')
|
||||||
|
@ -19,6 +19,7 @@ Module to provide redis functionality to Salt
|
|||||||
from __future__ import absolute_import, unicode_literals, print_function
|
from __future__ import absolute_import, unicode_literals, print_function
|
||||||
from salt.ext.six.moves import zip
|
from salt.ext.six.moves import zip
|
||||||
from salt.ext import six
|
from salt.ext import six
|
||||||
|
from salt.utils import clean_kwargs
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
# Import third party libs
|
# Import third party libs
|
||||||
@ -395,7 +396,7 @@ def hmset(key, **fieldsvals):
|
|||||||
database = fieldsvals.pop('db', None)
|
database = fieldsvals.pop('db', None)
|
||||||
password = fieldsvals.pop('password', None)
|
password = fieldsvals.pop('password', None)
|
||||||
server = _connect(host, port, database, password)
|
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):
|
def hset(key, field, value, host=None, port=None, db=None, password=None):
|
||||||
|
@ -37,6 +37,7 @@ def __virtual__():
|
|||||||
'Devuan',
|
'Devuan',
|
||||||
'Arch',
|
'Arch',
|
||||||
'Arch ARM',
|
'Arch ARM',
|
||||||
|
'Manjaro',
|
||||||
'ALT',
|
'ALT',
|
||||||
'SUSE Enterprise Server',
|
'SUSE Enterprise Server',
|
||||||
'SUSE',
|
'SUSE',
|
||||||
|
@ -137,13 +137,15 @@ def renderer(path=None, string=None, default_renderer='jinja|yaml', **kwargs):
|
|||||||
path_or_string = ':string:'
|
path_or_string = ':string:'
|
||||||
kwargs['input_data'] = string
|
kwargs['input_data'] = string
|
||||||
|
|
||||||
return salt.template.compile_template(
|
ret = salt.template.compile_template(
|
||||||
path_or_string,
|
path_or_string,
|
||||||
renderers,
|
renderers,
|
||||||
default_renderer,
|
default_renderer,
|
||||||
__opts__['renderer_blacklist'],
|
__opts__['renderer_blacklist'],
|
||||||
__opts__['renderer_whitelist'],
|
__opts__['renderer_whitelist'],
|
||||||
**kwargs)
|
**kwargs
|
||||||
|
)
|
||||||
|
return ret.read() if __utils__['stringio.is_readable'](ret) else ret
|
||||||
|
|
||||||
|
|
||||||
def _get_serialize_fn(serializer, fn_name):
|
def _get_serialize_fn(serializer, fn_name):
|
||||||
|
@ -29,18 +29,13 @@ from salt.ext.six.moves import zip # pylint: disable=import-error,redefined-bui
|
|||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
DMIDECODER = salt.utils.path.which_bin(['dmidecode', 'smbios'])
|
|
||||||
|
|
||||||
|
|
||||||
def __virtual__():
|
def __virtual__():
|
||||||
'''
|
'''
|
||||||
Only work when dmidecode is installed.
|
Only work when dmidecode is installed.
|
||||||
'''
|
'''
|
||||||
if DMIDECODER is None:
|
return (bool(salt.utils.path.which_bin(['dmidecode', 'smbios'])),
|
||||||
log.debug('SMBIOS: neither dmidecode nor smbios found!')
|
'The smbios execution module failed to load: neither dmidecode nor smbios in the path.')
|
||||||
return (False, 'The smbios execution module failed to load: neither dmidecode nor smbios in the path.')
|
|
||||||
else:
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def get(string, clean=True):
|
def get(string, clean=True):
|
||||||
@ -86,16 +81,12 @@ def get(string, clean=True):
|
|||||||
|
|
||||||
val = _dmidecoder('-s {0}'.format(string)).strip()
|
val = _dmidecoder('-s {0}'.format(string)).strip()
|
||||||
|
|
||||||
# Sometimes dmidecode delivers comments in strings.
|
# Cleanup possible comments in strings.
|
||||||
# Don't.
|
|
||||||
val = '\n'.join([v for v in val.split('\n') if not v.startswith('#')])
|
val = '\n'.join([v for v in val.split('\n') if not v.startswith('#')])
|
||||||
|
if val.startswith('/dev/mem') or clean and not _dmi_isclean(string, val):
|
||||||
|
val = None
|
||||||
|
|
||||||
# handle missing /dev/mem
|
return val
|
||||||
if val.startswith('/dev/mem'):
|
|
||||||
return None
|
|
||||||
|
|
||||||
if not clean or _dmi_isclean(string, val):
|
|
||||||
return val
|
|
||||||
|
|
||||||
|
|
||||||
def records(rec_type=None, fields=None, clean=True):
|
def records(rec_type=None, fields=None, clean=True):
|
||||||
@ -327,7 +318,11 @@ def _dmidecoder(args=None):
|
|||||||
'''
|
'''
|
||||||
Call DMIdecode
|
Call DMIdecode
|
||||||
'''
|
'''
|
||||||
if args is None:
|
dmidecoder = salt.utils.path.which_bin(['dmidecode', 'smbios'])
|
||||||
return salt.modules.cmdmod._run_quiet(DMIDECODER)
|
|
||||||
|
if not args:
|
||||||
|
out = salt.modules.cmdmod._run_quiet(dmidecoder)
|
||||||
else:
|
else:
|
||||||
return salt.modules.cmdmod._run_quiet('{0} {1}'.format(DMIDECODER, args))
|
out = salt.modules.cmdmod._run_quiet('{0} {1}'.format(dmidecoder, args))
|
||||||
|
|
||||||
|
return out
|
||||||
|
@ -602,8 +602,7 @@ def template_str(tem, queue=False, **kwargs):
|
|||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def apply_(mods=None,
|
def apply_(mods=None, **kwargs):
|
||||||
**kwargs):
|
|
||||||
'''
|
'''
|
||||||
.. versionadded:: 2015.5.0
|
.. versionadded:: 2015.5.0
|
||||||
|
|
||||||
@ -743,6 +742,22 @@ def apply_(mods=None,
|
|||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
salt '*' state.apply test localconfig=/path/to/minion.yml
|
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:
|
if mods:
|
||||||
return sls(mods, **kwargs)
|
return sls(mods, **kwargs)
|
||||||
@ -1068,7 +1083,7 @@ def highstate(test=None, queue=False, **kwargs):
|
|||||||
return ret
|
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
|
Execute the states in one or more SLS files
|
||||||
|
|
||||||
@ -1160,6 +1175,17 @@ def sls(mods, test=None, exclude=None, queue=False, **kwargs):
|
|||||||
|
|
||||||
.. versionadded:: 2015.8.4
|
.. 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:
|
CLI Example:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
@ -1223,6 +1249,28 @@ def sls(mods, test=None, exclude=None, queue=False, **kwargs):
|
|||||||
'{0}.cache.p'.format(kwargs.get('cache_name', 'highstate'))
|
'{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.args.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['saltenv']
|
||||||
|
)
|
||||||
|
except KeyError:
|
||||||
|
log.warning(
|
||||||
|
'Invalid custom module type \'%s\', ignoring',
|
||||||
|
module_type
|
||||||
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
st_ = salt.state.HighState(opts,
|
st_ = salt.state.HighState(opts,
|
||||||
pillar_override,
|
pillar_override,
|
||||||
@ -1253,6 +1301,10 @@ def sls(mods, test=None, exclude=None, queue=False, **kwargs):
|
|||||||
high_ = serial.load(fp_)
|
high_ = serial.load(fp_)
|
||||||
return st_.state.call_high(high_, orchestration_jid)
|
return st_.state.call_high(high_, orchestration_jid)
|
||||||
|
|
||||||
|
# If the state file is an integer, convert to a string then to unicode
|
||||||
|
if isinstance(mods, six.integer_types):
|
||||||
|
mods = salt.utils.stringutils.to_unicode(str(mods)) # future lint: disable=blacklisted-function
|
||||||
|
|
||||||
if isinstance(mods, six.string_types):
|
if isinstance(mods, six.string_types):
|
||||||
mods = mods.split(',')
|
mods = mods.split(',')
|
||||||
|
|
||||||
|
@ -2010,7 +2010,7 @@ def snapshot(domain, name=None, suffix=None):
|
|||||||
n_name = ElementTree.SubElement(doc, 'name')
|
n_name = ElementTree.SubElement(doc, 'name')
|
||||||
n_name.text = name
|
n_name.text = name
|
||||||
|
|
||||||
_get_domain(domain).snapshotCreateXML(ElementTree.tostring(doc))
|
_get_domain(domain).snapshotCreateXML(salt.utils.stringutils.to_str(ElementTree.tostring(doc)))
|
||||||
|
|
||||||
return {'name': name}
|
return {'name': name}
|
||||||
|
|
||||||
|
@ -58,8 +58,9 @@ from salt.modules.file import (check_hash, # pylint: disable=W0611
|
|||||||
RE_FLAG_TABLE, blockreplace, prepend, seek_read, seek_write, rename,
|
RE_FLAG_TABLE, blockreplace, prepend, seek_read, seek_write, rename,
|
||||||
lstat, path_exists_glob, write, pardir, join, HASHES, HASHES_REVMAP,
|
lstat, path_exists_glob, write, pardir, join, HASHES, HASHES_REVMAP,
|
||||||
comment, uncomment, _add_flags, comment_line, _regex_to_static,
|
comment, uncomment, _add_flags, comment_line, _regex_to_static,
|
||||||
_get_line_indent, apply_template_on_contents, dirname, basename,
|
_set_line_indent, apply_template_on_contents, dirname, basename,
|
||||||
list_backups_dir, _assert_occurrence, _starts_till)
|
list_backups_dir, _assert_occurrence, _starts_till, _set_line_eol, _get_eol,
|
||||||
|
_insert_line_after, _insert_line_before)
|
||||||
from salt.modules.file import normpath as normpath_
|
from salt.modules.file import normpath as normpath_
|
||||||
|
|
||||||
from salt.utils.functools import namespaced_function as _namespaced_function
|
from salt.utils.functools import namespaced_function as _namespaced_function
|
||||||
@ -116,8 +117,9 @@ def __virtual__():
|
|||||||
global blockreplace, prepend, seek_read, seek_write, rename, lstat
|
global blockreplace, prepend, seek_read, seek_write, rename, lstat
|
||||||
global write, pardir, join, _add_flags, apply_template_on_contents
|
global write, pardir, join, _add_flags, apply_template_on_contents
|
||||||
global path_exists_glob, comment, uncomment, _mkstemp_copy
|
global path_exists_glob, comment, uncomment, _mkstemp_copy
|
||||||
global _regex_to_static, _get_line_indent, dirname, basename
|
global _regex_to_static, _set_line_indent, dirname, basename
|
||||||
global list_backups_dir, normpath_, _assert_occurrence, _starts_till
|
global list_backups_dir, normpath_, _assert_occurrence, _starts_till
|
||||||
|
global _insert_line_before, _insert_line_after, _set_line_eol, _get_eol
|
||||||
|
|
||||||
replace = _namespaced_function(replace, globals())
|
replace = _namespaced_function(replace, globals())
|
||||||
search = _namespaced_function(search, globals())
|
search = _namespaced_function(search, globals())
|
||||||
@ -173,7 +175,11 @@ def __virtual__():
|
|||||||
uncomment = _namespaced_function(uncomment, globals())
|
uncomment = _namespaced_function(uncomment, globals())
|
||||||
comment_line = _namespaced_function(comment_line, globals())
|
comment_line = _namespaced_function(comment_line, globals())
|
||||||
_regex_to_static = _namespaced_function(_regex_to_static, globals())
|
_regex_to_static = _namespaced_function(_regex_to_static, globals())
|
||||||
_get_line_indent = _namespaced_function(_get_line_indent, globals())
|
_set_line_indent = _namespaced_function(_set_line_indent, globals())
|
||||||
|
_set_line_eol = _namespaced_function(_set_line_eol, globals())
|
||||||
|
_get_eol = _namespaced_function(_get_eol, globals())
|
||||||
|
_insert_line_after = _namespaced_function(_insert_line_after, globals())
|
||||||
|
_insert_line_before = _namespaced_function(_insert_line_before, globals())
|
||||||
_mkstemp_copy = _namespaced_function(_mkstemp_copy, globals())
|
_mkstemp_copy = _namespaced_function(_mkstemp_copy, globals())
|
||||||
_add_flags = _namespaced_function(_add_flags, globals())
|
_add_flags = _namespaced_function(_add_flags, globals())
|
||||||
apply_template_on_contents = _namespaced_function(apply_template_on_contents, globals())
|
apply_template_on_contents = _namespaced_function(apply_template_on_contents, globals())
|
||||||
|
@ -2588,7 +2588,9 @@ class _policy_info(object):
|
|||||||
userSid = '{1}\\{0}'.format(userSid[0], userSid[1])
|
userSid = '{1}\\{0}'.format(userSid[0], userSid[1])
|
||||||
else:
|
else:
|
||||||
userSid = '{0}'.format(userSid[0])
|
userSid = '{0}'.format(userSid[0])
|
||||||
|
# TODO: This needs to be more specific
|
||||||
except Exception:
|
except Exception:
|
||||||
|
log.exception('Handle this explicitly')
|
||||||
userSid = win32security.ConvertSidToStringSid(_sid)
|
userSid = win32security.ConvertSidToStringSid(_sid)
|
||||||
usernames.append(userSid)
|
usernames.append(userSid)
|
||||||
return usernames
|
return usernames
|
||||||
@ -2607,7 +2609,9 @@ class _policy_info(object):
|
|||||||
try:
|
try:
|
||||||
sid = win32security.LookupAccountName('', _user)[0]
|
sid = win32security.LookupAccountName('', _user)[0]
|
||||||
sids.append(sid)
|
sids.append(sid)
|
||||||
|
# This needs to be more specific
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
log.exception('Handle this explicitly')
|
||||||
raise CommandExecutionError((
|
raise CommandExecutionError((
|
||||||
'There was an error obtaining the SID of user "{0}". Error '
|
'There was an error obtaining the SID of user "{0}". Error '
|
||||||
'returned: {1}'
|
'returned: {1}'
|
||||||
@ -2760,7 +2764,9 @@ def _processPolicyDefinitions(policy_def_path='c:\\Windows\\PolicyDefinitions',
|
|||||||
except lxml.etree.XMLSyntaxError:
|
except lxml.etree.XMLSyntaxError:
|
||||||
try:
|
try:
|
||||||
xmltree = _remove_unicode_encoding(admfile)
|
xmltree = _remove_unicode_encoding(admfile)
|
||||||
|
# TODO: This needs to be more specific
|
||||||
except Exception:
|
except Exception:
|
||||||
|
log.exception('Handle this explicitly')
|
||||||
log.error('A error was found while processing admx '
|
log.error('A error was found while processing admx '
|
||||||
'file %s, all policies from this file will '
|
'file %s, all policies from this file will '
|
||||||
'be unavailable via this module', admfile)
|
'be unavailable via this module', admfile)
|
||||||
@ -2845,7 +2851,9 @@ def _processPolicyDefinitions(policy_def_path='c:\\Windows\\PolicyDefinitions',
|
|||||||
# see issue #38100
|
# see issue #38100
|
||||||
try:
|
try:
|
||||||
xmltree = _remove_unicode_encoding(adml_file)
|
xmltree = _remove_unicode_encoding(adml_file)
|
||||||
|
# TODO: This needs to be more specific
|
||||||
except Exception:
|
except Exception:
|
||||||
|
log.exception('Handle this explicitly')
|
||||||
log.error('An error was found while processing '
|
log.error('An error was found while processing '
|
||||||
'adml file %s, all policy '
|
'adml file %s, all policy '
|
||||||
'language data from this file will be '
|
'language data from this file will be '
|
||||||
@ -2901,8 +2909,9 @@ def _findOptionValueInSeceditFile(option):
|
|||||||
if _line.startswith(option):
|
if _line.startswith(option):
|
||||||
return True, _line.split('=')[1].strip()
|
return True, _line.split('=')[1].strip()
|
||||||
return True, 'Not Defined'
|
return True, 'Not Defined'
|
||||||
except Exception as e:
|
# TODO: This needs to be more specific
|
||||||
log.debug('error occurred while trying to get secedit data')
|
except Exception:
|
||||||
|
log.exception('error occurred while trying to get secedit data')
|
||||||
return False, None
|
return False, None
|
||||||
|
|
||||||
|
|
||||||
@ -2932,8 +2941,9 @@ def _importSeceditConfig(infdata):
|
|||||||
if __salt__['file.file_exists'](_tInfFile):
|
if __salt__['file.file_exists'](_tInfFile):
|
||||||
_ret = __salt__['file.remove'](_tInfFile)
|
_ret = __salt__['file.remove'](_tInfFile)
|
||||||
return True
|
return True
|
||||||
|
# TODO: This needs to be more specific
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.debug('error occurred while trying to import secedit data')
|
log.exception('error occurred while trying to import secedit data')
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
@ -2995,9 +3005,10 @@ def _addAccountRights(sidObject, user_right):
|
|||||||
user_rights_list = [user_right]
|
user_rights_list = [user_right]
|
||||||
_ret = win32security.LsaAddAccountRights(_polHandle, sidObject, user_rights_list)
|
_ret = win32security.LsaAddAccountRights(_polHandle, sidObject, user_rights_list)
|
||||||
return True
|
return True
|
||||||
|
# TODO: This needs to be more specific
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.error('Error attempting to add account right, exception was %s',
|
log.exception('Error attempting to add account right, exception was %s',
|
||||||
e)
|
e)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
@ -3011,8 +3022,7 @@ def _delAccountRights(sidObject, user_right):
|
|||||||
_ret = win32security.LsaRemoveAccountRights(_polHandle, sidObject, False, user_rights_list)
|
_ret = win32security.LsaRemoveAccountRights(_polHandle, sidObject, False, user_rights_list)
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.error('Error attempting to delete account right, '
|
log.exception('Error attempting to delete account right')
|
||||||
'exception was %s', e)
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
@ -4180,7 +4190,7 @@ def _write_regpol_data(data_to_write,
|
|||||||
try:
|
try:
|
||||||
reg_pol_header = u'\u5250\u6765\x01\x00'
|
reg_pol_header = u'\u5250\u6765\x01\x00'
|
||||||
if not os.path.exists(policy_file_path):
|
if not os.path.exists(policy_file_path):
|
||||||
ret = __salt__['file.makedirs'](policy_file_path)
|
__salt__['file.makedirs'](policy_file_path)
|
||||||
with salt.utils.files.fopen(policy_file_path, 'wb') as pol_file:
|
with salt.utils.files.fopen(policy_file_path, 'wb') as pol_file:
|
||||||
if not data_to_write.startswith(reg_pol_header.encode('utf-16-le')):
|
if not data_to_write.startswith(reg_pol_header.encode('utf-16-le')):
|
||||||
pol_file.write(reg_pol_header.encode('utf-16-le'))
|
pol_file.write(reg_pol_header.encode('utf-16-le'))
|
||||||
@ -4188,11 +4198,12 @@ def _write_regpol_data(data_to_write,
|
|||||||
try:
|
try:
|
||||||
gpt_ini_data = ''
|
gpt_ini_data = ''
|
||||||
if os.path.exists(gpt_ini_path):
|
if os.path.exists(gpt_ini_path):
|
||||||
with salt.utils.files.fopen(gpt_ini_path, 'rb') as gpt_file:
|
with salt.utils.files.fopen(gpt_ini_path, 'r') as gpt_file:
|
||||||
gpt_ini_data = gpt_file.read()
|
gpt_ini_data = gpt_file.read()
|
||||||
if not _regexSearchRegPolData(r'\[General\]\r\n', gpt_ini_data):
|
if not _regexSearchRegPolData(r'\[General\]\r\n', gpt_ini_data):
|
||||||
gpt_ini_data = '[General]\r\n' + gpt_ini_data
|
gpt_ini_data = '[General]\r\n' + gpt_ini_data
|
||||||
if _regexSearchRegPolData(r'{0}='.format(re.escape(gpt_extension)), gpt_ini_data):
|
if _regexSearchRegPolData(r'{0}='.format(re.escape(gpt_extension)),
|
||||||
|
gpt_ini_data):
|
||||||
# ensure the line contains the ADM guid
|
# ensure the line contains the ADM guid
|
||||||
gpt_ext_loc = re.search(r'^{0}=.*\r\n'.format(re.escape(gpt_extension)),
|
gpt_ext_loc = re.search(r'^{0}=.*\r\n'.format(re.escape(gpt_extension)),
|
||||||
gpt_ini_data,
|
gpt_ini_data,
|
||||||
@ -4208,9 +4219,10 @@ def _write_regpol_data(data_to_write,
|
|||||||
general_location = re.search(r'^\[General\]\r\n',
|
general_location = re.search(r'^\[General\]\r\n',
|
||||||
gpt_ini_data,
|
gpt_ini_data,
|
||||||
re.IGNORECASE | re.MULTILINE)
|
re.IGNORECASE | re.MULTILINE)
|
||||||
gpt_ini_data = "{0}{1}={2}\r\n{3}".format(
|
gpt_ini_data = '{0}{1}={2}\r\n{3}'.format(
|
||||||
gpt_ini_data[general_location.start():general_location.end()],
|
gpt_ini_data[general_location.start():general_location.end()],
|
||||||
gpt_extension, gpt_extension_guid,
|
gpt_extension,
|
||||||
|
gpt_extension_guid,
|
||||||
gpt_ini_data[general_location.end():])
|
gpt_ini_data[general_location.end():])
|
||||||
# https://technet.microsoft.com/en-us/library/cc978247.aspx
|
# https://technet.microsoft.com/en-us/library/cc978247.aspx
|
||||||
if _regexSearchRegPolData(r'Version=', gpt_ini_data):
|
if _regexSearchRegPolData(r'Version=', gpt_ini_data):
|
||||||
@ -4225,9 +4237,10 @@ def _write_regpol_data(data_to_write,
|
|||||||
elif gpt_extension.lower() == 'gPCUserExtensionNames'.lower():
|
elif gpt_extension.lower() == 'gPCUserExtensionNames'.lower():
|
||||||
version_nums = (version_nums[0] + 1, version_nums[1])
|
version_nums = (version_nums[0] + 1, version_nums[1])
|
||||||
version_num = struct.unpack(b'>I', struct.pack(b'>2H', *version_nums))[0]
|
version_num = struct.unpack(b'>I', struct.pack(b'>2H', *version_nums))[0]
|
||||||
gpt_ini_data = "{0}{1}={2}\r\n{3}".format(
|
gpt_ini_data = '{0}{1}={2}\r\n{3}'.format(
|
||||||
gpt_ini_data[0:version_loc.start()],
|
gpt_ini_data[0:version_loc.start()],
|
||||||
'Version', version_num,
|
'Version',
|
||||||
|
version_num,
|
||||||
gpt_ini_data[version_loc.end():])
|
gpt_ini_data[version_loc.end():])
|
||||||
else:
|
else:
|
||||||
general_location = re.search(r'^\[General\]\r\n',
|
general_location = re.search(r'^\[General\]\r\n',
|
||||||
@ -4237,20 +4250,26 @@ def _write_regpol_data(data_to_write,
|
|||||||
version_nums = (0, 1)
|
version_nums = (0, 1)
|
||||||
elif gpt_extension.lower() == 'gPCUserExtensionNames'.lower():
|
elif gpt_extension.lower() == 'gPCUserExtensionNames'.lower():
|
||||||
version_nums = (1, 0)
|
version_nums = (1, 0)
|
||||||
gpt_ini_data = "{0}{1}={2}\r\n{3}".format(
|
gpt_ini_data = '{0}{1}={2}\r\n{3}'.format(
|
||||||
gpt_ini_data[general_location.start():general_location.end()],
|
gpt_ini_data[general_location.start():general_location.end()],
|
||||||
'Version',
|
'Version',
|
||||||
int("{0}{1}".format(six.text_type(version_nums[0]).zfill(4), six.text_type(version_nums[1]).zfill(4)), 16),
|
int("{0}{1}".format(six.text_type(version_nums[0]).zfill(4),
|
||||||
|
six.text_type(version_nums[1]).zfill(4)),
|
||||||
|
16),
|
||||||
gpt_ini_data[general_location.end():])
|
gpt_ini_data[general_location.end():])
|
||||||
if gpt_ini_data:
|
if gpt_ini_data:
|
||||||
with salt.utils.files.fopen(gpt_ini_path, 'wb') as gpt_file:
|
with salt.utils.files.fopen(gpt_ini_path, 'w') as gpt_file:
|
||||||
gpt_file.write(salt.utils.stringutils.to_bytes(gpt_ini_data))
|
gpt_file.write(gpt_ini_data)
|
||||||
|
# TODO: This needs to be more specific
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
msg = 'An error occurred attempting to write to {0}, the exception was {1}'.format(
|
msg = 'An error occurred attempting to write to {0}, the exception was {1}'.format(
|
||||||
gpt_ini_path, e)
|
gpt_ini_path, e)
|
||||||
|
log.exception(msg)
|
||||||
raise CommandExecutionError(msg)
|
raise CommandExecutionError(msg)
|
||||||
|
# TODO: This needs to be more specific
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
msg = 'An error occurred attempting to write to {0}, the exception was {1}'.format(policy_file_path, e)
|
msg = 'An error occurred attempting to write to {0}, the exception was {1}'.format(policy_file_path, e)
|
||||||
|
log.exception(msg)
|
||||||
raise CommandExecutionError(msg)
|
raise CommandExecutionError(msg)
|
||||||
|
|
||||||
|
|
||||||
@ -4648,8 +4667,9 @@ def _writeAdminTemplateRegPolFile(admtemplate_data,
|
|||||||
policy_data.gpt_ini_path,
|
policy_data.gpt_ini_path,
|
||||||
policy_data.admx_registry_classes[registry_class]['gpt_extension_location'],
|
policy_data.admx_registry_classes[registry_class]['gpt_extension_location'],
|
||||||
policy_data.admx_registry_classes[registry_class]['gpt_extension_guid'])
|
policy_data.admx_registry_classes[registry_class]['gpt_extension_guid'])
|
||||||
|
# TODO: This needs to be more specific or removed
|
||||||
except Exception:
|
except Exception:
|
||||||
log.error('Unhandled exception %s occurred while attempting to write Adm Template Policy File')
|
log.exception('Unhandled exception %s occurred while attempting to write Adm Template Policy File')
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@ -4671,7 +4691,7 @@ def _getScriptSettingsFromIniFile(policy_info):
|
|||||||
_existingData = deserialize(_existingData.decode('utf-16-le').lstrip('\ufeff'))
|
_existingData = deserialize(_existingData.decode('utf-16-le').lstrip('\ufeff'))
|
||||||
log.debug('Have deserialized data %s', _existingData)
|
log.debug('Have deserialized data %s', _existingData)
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
log.error('An error occurred attempting to deserialize data for %s', policy_info['Policy'])
|
log.exception('An error occurred attempting to deserialize data for %s', policy_info['Policy'])
|
||||||
raise CommandExecutionError(error)
|
raise CommandExecutionError(error)
|
||||||
if 'Section' in policy_info['ScriptIni'] and policy_info['ScriptIni']['Section'].lower() in [z.lower() for z in _existingData.keys()]:
|
if 'Section' in policy_info['ScriptIni'] and policy_info['ScriptIni']['Section'].lower() in [z.lower() for z in _existingData.keys()]:
|
||||||
if 'SettingName' in policy_info['ScriptIni']:
|
if 'SettingName' in policy_info['ScriptIni']:
|
||||||
@ -5540,8 +5560,10 @@ def set_(computer_policy=None, user_policy=None,
|
|||||||
_newModalSetData = dictupdate.update(_existingModalData, _modal_sets[_modal_set])
|
_newModalSetData = dictupdate.update(_existingModalData, _modal_sets[_modal_set])
|
||||||
log.debug('NEW MODAL SET = %s', _newModalSetData)
|
log.debug('NEW MODAL SET = %s', _newModalSetData)
|
||||||
_ret = win32net.NetUserModalsSet(None, _modal_set, _newModalSetData)
|
_ret = win32net.NetUserModalsSet(None, _modal_set, _newModalSetData)
|
||||||
except:
|
# TODO: This needs to be more specific
|
||||||
|
except Exception:
|
||||||
msg = 'An unhandled exception occurred while attempting to set policy via NetUserModalSet'
|
msg = 'An unhandled exception occurred while attempting to set policy via NetUserModalSet'
|
||||||
|
log.exception(msg)
|
||||||
raise CommandExecutionError(msg)
|
raise CommandExecutionError(msg)
|
||||||
if _admTemplateData:
|
if _admTemplateData:
|
||||||
_ret = False
|
_ret = False
|
||||||
|
@ -7,50 +7,56 @@ powercfg.
|
|||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
|
# Set monitor to never turn off on Battery power
|
||||||
salt '*' powercfg.set_monitor_timeout 0 power=dc
|
salt '*' powercfg.set_monitor_timeout 0 power=dc
|
||||||
|
# Set disk timeout to 120 minutes on AC power
|
||||||
salt '*' powercfg.set_disk_timeout 120 power=ac
|
salt '*' powercfg.set_disk_timeout 120 power=ac
|
||||||
'''
|
'''
|
||||||
|
|
||||||
# Import Python Libs
|
# Import Python Libs
|
||||||
from __future__ import absolute_import, unicode_literals, print_function
|
from __future__ import absolute_import, unicode_literals, print_function
|
||||||
import re
|
import re
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
# Import Salt Libs
|
||||||
|
import salt.utils.platform
|
||||||
|
import salt.utils.versions
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
__virtualname__ = "powercfg"
|
__virtualname__ = 'powercfg'
|
||||||
|
|
||||||
|
|
||||||
def __virtual__():
|
def __virtual__():
|
||||||
'''
|
'''
|
||||||
Only work on Windows
|
Only work on Windows
|
||||||
'''
|
'''
|
||||||
if __grains__['os'] == 'Windows':
|
if not salt.utils.platform.is_windows():
|
||||||
return __virtualname__
|
return False, 'PowerCFG: Module only works on Windows'
|
||||||
return (False, 'Module only works on Windows.')
|
return __virtualname__
|
||||||
|
|
||||||
|
|
||||||
def _get_current_scheme():
|
def _get_current_scheme():
|
||||||
cmd = "powercfg /getactivescheme"
|
cmd = 'powercfg /getactivescheme'
|
||||||
out = __salt__['cmd.run'](cmd, python_shell=False)
|
out = __salt__['cmd.run'](cmd, python_shell=False)
|
||||||
matches = re.search(r"GUID: (.*) \(", out)
|
matches = re.search(r'GUID: (.*) \(', out)
|
||||||
return matches.groups()[0].strip()
|
return matches.groups()[0].strip()
|
||||||
|
|
||||||
|
|
||||||
def _get_powercfg_minute_values(scheme, guid, subguid, safe_name):
|
def _get_powercfg_minute_values(scheme, guid, subguid, safe_name):
|
||||||
'''
|
'''
|
||||||
Returns the AC/DC values in an array for a guid and subguid for a the given scheme
|
Returns the AC/DC values in an dict for a guid and subguid for a the given
|
||||||
|
scheme
|
||||||
'''
|
'''
|
||||||
if scheme is None:
|
if scheme is None:
|
||||||
scheme = _get_current_scheme()
|
scheme = _get_current_scheme()
|
||||||
|
|
||||||
if __grains__['osrelease'] == '7':
|
if __grains__['osrelease'] == '7':
|
||||||
cmd = "powercfg /q {0} {1}".format(scheme, guid)
|
cmd = 'powercfg /q {0} {1}'.format(scheme, guid)
|
||||||
else:
|
else:
|
||||||
cmd = "powercfg /q {0} {1} {2}".format(scheme, guid, subguid)
|
cmd = 'powercfg /q {0} {1} {2}'.format(scheme, guid, subguid)
|
||||||
out = __salt__['cmd.run'](cmd, python_shell=False)
|
out = __salt__['cmd.run'](cmd, python_shell=False)
|
||||||
|
|
||||||
split = out.split("\r\n\r\n")
|
split = out.split('\r\n\r\n')
|
||||||
if len(split) > 1:
|
if len(split) > 1:
|
||||||
for s in split:
|
for s in split:
|
||||||
if safe_name in s or subguid in s:
|
if safe_name in s or subguid in s:
|
||||||
@ -59,172 +65,309 @@ def _get_powercfg_minute_values(scheme, guid, subguid, safe_name):
|
|||||||
else:
|
else:
|
||||||
out = split[0]
|
out = split[0]
|
||||||
|
|
||||||
raw_settings = re.findall(r"Power Setting Index: ([0-9a-fx]+)", out)
|
raw_settings = re.findall(r'Power Setting Index: ([0-9a-fx]+)', out)
|
||||||
return {"ac": int(raw_settings[0], 0) / 60, "dc": int(raw_settings[1], 0) / 60}
|
return {'ac': int(raw_settings[0], 0) / 60,
|
||||||
|
'dc': int(raw_settings[1], 0) / 60}
|
||||||
|
|
||||||
|
|
||||||
def _set_powercfg_value(scheme, sub_group, setting_guid, power, value):
|
def _set_powercfg_value(scheme, sub_group, setting_guid, power, value):
|
||||||
'''
|
'''
|
||||||
Sets the value of a setting with a given power (ac/dc) to
|
Sets the AC/DC values of a setting with the given power for the given scheme
|
||||||
the given scheme
|
|
||||||
'''
|
'''
|
||||||
|
salt.utils.versions.warn_until(
|
||||||
|
'Fluorine',
|
||||||
|
'This function now expects the timeout value in minutes instead of '
|
||||||
|
'seconds as stated in the documentation. This warning will be removed '
|
||||||
|
'in Salt Fluorine.')
|
||||||
if scheme is None:
|
if scheme is None:
|
||||||
scheme = _get_current_scheme()
|
scheme = _get_current_scheme()
|
||||||
|
|
||||||
cmd = "powercfg /set{0}valueindex {1} {2} {3} {4}".format(power, scheme, sub_group, setting_guid, value)
|
cmd = 'powercfg /set{0}valueindex {1} {2} {3} {4}' \
|
||||||
return __salt__['cmd.run'](cmd, python_shell=False)
|
''.format(power, scheme, sub_group, setting_guid, value * 60)
|
||||||
|
return __salt__['cmd.retcode'](cmd, python_shell=False) == 0
|
||||||
|
|
||||||
|
|
||||||
def set_monitor_timeout(timeout, power="ac", scheme=None):
|
def set_monitor_timeout(timeout, power='ac', scheme=None):
|
||||||
'''
|
'''
|
||||||
Set the monitor timeout in minutes for the given power scheme
|
Set the monitor timeout in minutes for the given power scheme
|
||||||
|
|
||||||
|
Args:
|
||||||
|
timeout (int):
|
||||||
|
The amount of time in minutes before the monitor will timeout
|
||||||
|
|
||||||
|
power (str):
|
||||||
|
Set the value for AC or DC power. Default is ``ac``. Valid options
|
||||||
|
are:
|
||||||
|
|
||||||
|
- ``ac`` (AC Power)
|
||||||
|
- ``dc`` (Battery)
|
||||||
|
|
||||||
|
scheme (str):
|
||||||
|
The scheme to use, leave as ``None`` to use the current. Default is
|
||||||
|
``None``. This can be the GUID or the Alias for the Scheme. Known
|
||||||
|
Aliases are:
|
||||||
|
|
||||||
|
- ``SCHEME_BALANCED`` - Balanced
|
||||||
|
- ``SCHEME_MAX`` - Power saver
|
||||||
|
- ``SCHEME_MIN`` - High performance
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: ``True`` if successful, otherwise ``False``
|
||||||
|
|
||||||
CLI Example:
|
CLI Example:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
salt '*' powercfg.set_monitor_timeout 30 power=ac
|
# Sets the monitor timeout to 30 minutes
|
||||||
|
salt '*' powercfg.set_monitor_timeout 30
|
||||||
timeout
|
|
||||||
The amount of time in minutes before the monitor will timeout
|
|
||||||
|
|
||||||
power
|
|
||||||
Should we set the value for AC or DC (battery)? Valid options ac,dc.
|
|
||||||
|
|
||||||
scheme
|
|
||||||
The scheme to use, leave as None to use the current.
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
return _set_powercfg_value(scheme, "SUB_VIDEO", "VIDEOIDLE", power, timeout)
|
return _set_powercfg_value(
|
||||||
|
scheme=scheme,
|
||||||
|
sub_group='SUB_VIDEO',
|
||||||
|
setting_guid='VIDEOIDLE',
|
||||||
|
power=power,
|
||||||
|
value=timeout)
|
||||||
|
|
||||||
|
|
||||||
def get_monitor_timeout(scheme=None):
|
def get_monitor_timeout(scheme=None):
|
||||||
'''
|
'''
|
||||||
Get the current monitor timeout of the given scheme
|
Get the current monitor timeout of the given scheme
|
||||||
|
|
||||||
|
Args:
|
||||||
|
scheme (str):
|
||||||
|
The scheme to use, leave as ``None`` to use the current. Default is
|
||||||
|
``None``. This can be the GUID or the Alias for the Scheme. Known
|
||||||
|
Aliases are:
|
||||||
|
|
||||||
|
- ``SCHEME_BALANCED`` - Balanced
|
||||||
|
- ``SCHEME_MAX`` - Power saver
|
||||||
|
- ``SCHEME_MIN`` - High performance
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: A dictionary of both the AC and DC settings
|
||||||
|
|
||||||
CLI Example:
|
CLI Example:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
salt '*' powercfg.get_monitor_timeout
|
salt '*' powercfg.get_monitor_timeout
|
||||||
|
|
||||||
scheme
|
|
||||||
The scheme to use, leave as None to use the current.
|
|
||||||
'''
|
'''
|
||||||
return _get_powercfg_minute_values(scheme, "SUB_VIDEO", "VIDEOIDLE", "Turn off display after")
|
return _get_powercfg_minute_values(
|
||||||
|
scheme=scheme,
|
||||||
|
guid='SUB_VIDEO',
|
||||||
|
subguid='VIDEOIDLE',
|
||||||
|
safe_name='Turn off display after')
|
||||||
|
|
||||||
|
|
||||||
def set_disk_timeout(timeout, power="ac", scheme=None):
|
def set_disk_timeout(timeout, power='ac', scheme=None):
|
||||||
'''
|
'''
|
||||||
Set the disk timeout in minutes for the given power scheme
|
Set the disk timeout in minutes for the given power scheme
|
||||||
|
|
||||||
|
Args:
|
||||||
|
timeout (int):
|
||||||
|
The amount of time in minutes before the disk will timeout
|
||||||
|
|
||||||
|
power (str):
|
||||||
|
Set the value for AC or DC power. Default is ``ac``. Valid options
|
||||||
|
are:
|
||||||
|
|
||||||
|
- ``ac`` (AC Power)
|
||||||
|
- ``dc`` (Battery)
|
||||||
|
|
||||||
|
scheme (str):
|
||||||
|
The scheme to use, leave as ``None`` to use the current. Default is
|
||||||
|
``None``. This can be the GUID or the Alias for the Scheme. Known
|
||||||
|
Aliases are:
|
||||||
|
|
||||||
|
- ``SCHEME_BALANCED`` - Balanced
|
||||||
|
- ``SCHEME_MAX`` - Power saver
|
||||||
|
- ``SCHEME_MIN`` - High performance
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: ``True`` if successful, otherwise ``False``
|
||||||
|
|
||||||
CLI Example:
|
CLI Example:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
|
# Sets the disk timeout to 30 minutes on battery
|
||||||
salt '*' powercfg.set_disk_timeout 30 power=dc
|
salt '*' powercfg.set_disk_timeout 30 power=dc
|
||||||
|
|
||||||
timeout
|
|
||||||
The amount of time in minutes before the disk will timeout
|
|
||||||
|
|
||||||
power
|
|
||||||
Should we set the value for AC or DC (battery)? Valid options ac,dc.
|
|
||||||
|
|
||||||
scheme
|
|
||||||
The scheme to use, leave as None to use the current.
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
return _set_powercfg_value(scheme, "SUB_DISK", "DISKIDLE", power, timeout)
|
return _set_powercfg_value(
|
||||||
|
scheme=scheme,
|
||||||
|
sub_group='SUB_DISK',
|
||||||
|
setting_guid='DISKIDLE',
|
||||||
|
power=power,
|
||||||
|
value=timeout)
|
||||||
|
|
||||||
|
|
||||||
def get_disk_timeout(scheme=None):
|
def get_disk_timeout(scheme=None):
|
||||||
'''
|
'''
|
||||||
Get the current disk timeout of the given scheme
|
Get the current disk timeout of the given scheme
|
||||||
|
|
||||||
|
Args:
|
||||||
|
scheme (str):
|
||||||
|
The scheme to use, leave as ``None`` to use the current. Default is
|
||||||
|
``None``. This can be the GUID or the Alias for the Scheme. Known
|
||||||
|
Aliases are:
|
||||||
|
|
||||||
|
- ``SCHEME_BALANCED`` - Balanced
|
||||||
|
- ``SCHEME_MAX`` - Power saver
|
||||||
|
- ``SCHEME_MIN`` - High performance
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: A dictionary of both the AC and DC settings
|
||||||
|
|
||||||
CLI Example:
|
CLI Example:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
salt '*' powercfg.get_disk_timeout
|
salt '*' powercfg.get_disk_timeout
|
||||||
|
|
||||||
scheme
|
|
||||||
The scheme to use, leave as None to use the current.
|
|
||||||
'''
|
'''
|
||||||
return _get_powercfg_minute_values(scheme, "SUB_DISK", "DISKIDLE", "Turn off hard disk after")
|
return _get_powercfg_minute_values(
|
||||||
|
scheme=scheme,
|
||||||
|
guid='SUB_DISK',
|
||||||
|
subguid='DISKIDLE',
|
||||||
|
safe_name='Turn off hard disk after')
|
||||||
|
|
||||||
|
|
||||||
def set_standby_timeout(timeout, power="ac", scheme=None):
|
def set_standby_timeout(timeout, power='ac', scheme=None):
|
||||||
'''
|
'''
|
||||||
Set the standby timeout in minutes for the given power scheme
|
Set the standby timeout in minutes for the given power scheme
|
||||||
|
|
||||||
|
Args:
|
||||||
|
timeout (int):
|
||||||
|
The amount of time in minutes before the computer sleeps
|
||||||
|
|
||||||
|
power (str):
|
||||||
|
Set the value for AC or DC power. Default is ``ac``. Valid options
|
||||||
|
are:
|
||||||
|
|
||||||
|
- ``ac`` (AC Power)
|
||||||
|
- ``dc`` (Battery)
|
||||||
|
|
||||||
|
scheme (str):
|
||||||
|
The scheme to use, leave as ``None`` to use the current. Default is
|
||||||
|
``None``. This can be the GUID or the Alias for the Scheme. Known
|
||||||
|
Aliases are:
|
||||||
|
|
||||||
|
- ``SCHEME_BALANCED`` - Balanced
|
||||||
|
- ``SCHEME_MAX`` - Power saver
|
||||||
|
- ``SCHEME_MIN`` - High performance
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: ``True`` if successful, otherwise ``False``
|
||||||
|
|
||||||
CLI Example:
|
CLI Example:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
|
# Sets the system standby timeout to 30 minutes on Battery
|
||||||
salt '*' powercfg.set_standby_timeout 30 power=dc
|
salt '*' powercfg.set_standby_timeout 30 power=dc
|
||||||
|
|
||||||
timeout
|
|
||||||
The amount of time in minutes before the computer sleeps
|
|
||||||
|
|
||||||
power
|
|
||||||
Should we set the value for AC or DC (battery)? Valid options ac,dc.
|
|
||||||
|
|
||||||
scheme
|
|
||||||
The scheme to use, leave as None to use the current.
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
return _set_powercfg_value(scheme, "SUB_SLEEP", "STANDBYIDLE", power, timeout)
|
return _set_powercfg_value(
|
||||||
|
scheme=scheme,
|
||||||
|
sub_group='SUB_SLEEP',
|
||||||
|
setting_guid='STANDBYIDLE',
|
||||||
|
power=power,
|
||||||
|
value=timeout)
|
||||||
|
|
||||||
|
|
||||||
def get_standby_timeout(scheme=None):
|
def get_standby_timeout(scheme=None):
|
||||||
'''
|
'''
|
||||||
Get the current standby timeout of the given scheme
|
Get the current standby timeout of the given scheme
|
||||||
|
|
||||||
|
scheme (str):
|
||||||
|
The scheme to use, leave as ``None`` to use the current. Default is
|
||||||
|
``None``. This can be the GUID or the Alias for the Scheme. Known
|
||||||
|
Aliases are:
|
||||||
|
|
||||||
|
- ``SCHEME_BALANCED`` - Balanced
|
||||||
|
- ``SCHEME_MAX`` - Power saver
|
||||||
|
- ``SCHEME_MIN`` - High performance
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: A dictionary of both the AC and DC settings
|
||||||
|
|
||||||
CLI Example:
|
CLI Example:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
salt '*' powercfg.get_standby_timeout
|
salt '*' powercfg.get_standby_timeout
|
||||||
|
|
||||||
scheme
|
|
||||||
The scheme to use, leave as None to use the current.
|
|
||||||
'''
|
'''
|
||||||
return _get_powercfg_minute_values(scheme, "SUB_SLEEP", "STANDBYIDLE", "Sleep after")
|
return _get_powercfg_minute_values(
|
||||||
|
scheme=scheme,
|
||||||
|
guid='SUB_SLEEP',
|
||||||
|
subguid='STANDBYIDLE',
|
||||||
|
safe_name='Sleep after')
|
||||||
|
|
||||||
|
|
||||||
def set_hibernate_timeout(timeout, power="ac", scheme=None):
|
def set_hibernate_timeout(timeout, power='ac', scheme=None):
|
||||||
'''
|
'''
|
||||||
Set the hibernate timeout in minutes for the given power scheme
|
Set the hibernate timeout in minutes for the given power scheme
|
||||||
|
|
||||||
|
Args:
|
||||||
|
timeout (int):
|
||||||
|
The amount of time in minutes before the computer hibernates
|
||||||
|
|
||||||
|
power (str):
|
||||||
|
Set the value for AC or DC power. Default is ``ac``. Valid options
|
||||||
|
are:
|
||||||
|
|
||||||
|
- ``ac`` (AC Power)
|
||||||
|
- ``dc`` (Battery)
|
||||||
|
|
||||||
|
scheme (str):
|
||||||
|
The scheme to use, leave as ``None`` to use the current. Default is
|
||||||
|
``None``. This can be the GUID or the Alias for the Scheme. Known
|
||||||
|
Aliases are:
|
||||||
|
|
||||||
|
- ``SCHEME_BALANCED`` - Balanced
|
||||||
|
- ``SCHEME_MAX`` - Power saver
|
||||||
|
- ``SCHEME_MIN`` - High performance
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: ``True`` if successful, otherwise ``False``
|
||||||
|
|
||||||
CLI Example:
|
CLI Example:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
salt '*' powercfg.set_hibernate_timeout 30 power=pc
|
# Sets the hibernate timeout to 30 minutes on Battery
|
||||||
|
salt '*' powercfg.set_hibernate_timeout 30 power=dc
|
||||||
timeout
|
|
||||||
The amount of time in minutes before the computer hibernates
|
|
||||||
|
|
||||||
power
|
|
||||||
Should we set the value for AC or DC (battery)? Valid options ac,dc.
|
|
||||||
|
|
||||||
scheme
|
|
||||||
The scheme to use, leave as None to use the current.
|
|
||||||
'''
|
'''
|
||||||
return _set_powercfg_value(scheme, "SUB_SLEEP", "HIBERNATEIDLE", power, timeout)
|
return _set_powercfg_value(
|
||||||
|
scheme=scheme,
|
||||||
|
sub_group='SUB_SLEEP',
|
||||||
|
setting_guid='HIBERNATEIDLE',
|
||||||
|
power=power,
|
||||||
|
value=timeout)
|
||||||
|
|
||||||
|
|
||||||
def get_hibernate_timeout(scheme=None):
|
def get_hibernate_timeout(scheme=None):
|
||||||
'''
|
'''
|
||||||
Get the current hibernate timeout of the given scheme
|
Get the current hibernate timeout of the given scheme
|
||||||
|
|
||||||
|
scheme (str):
|
||||||
|
The scheme to use, leave as ``None`` to use the current. Default is
|
||||||
|
``None``. This can be the GUID or the Alias for the Scheme. Known
|
||||||
|
Aliases are:
|
||||||
|
|
||||||
|
- ``SCHEME_BALANCED`` - Balanced
|
||||||
|
- ``SCHEME_MAX`` - Power saver
|
||||||
|
- ``SCHEME_MIN`` - High performance
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: A dictionary of both the AC and DC settings
|
||||||
|
|
||||||
CLI Example:
|
CLI Example:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
salt '*' powercfg.get_hibernate_timeout
|
salt '*' powercfg.get_hibernate_timeout
|
||||||
|
|
||||||
scheme
|
|
||||||
The scheme to use, leave as None to use the current.
|
|
||||||
'''
|
'''
|
||||||
return _get_powercfg_minute_values(scheme, "SUB_SLEEP", "HIBERNATEIDLE", "Hibernate after")
|
return _get_powercfg_minute_values(
|
||||||
|
scheme=scheme,
|
||||||
|
guid='SUB_SLEEP',
|
||||||
|
subguid='HIBERNATEIDLE',
|
||||||
|
safe_name='Hibernate after')
|
||||||
|
@ -705,7 +705,7 @@ def modify(name,
|
|||||||
win32service.SERVICE_QUERY_CONFIG)
|
win32service.SERVICE_QUERY_CONFIG)
|
||||||
except pywintypes.error as exc:
|
except pywintypes.error as exc:
|
||||||
raise CommandExecutionError(
|
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)
|
config_info = win32service.QueryServiceConfig(handle_svc)
|
||||||
|
|
||||||
|
@ -584,6 +584,8 @@ def latest_version(*names, **kwargs):
|
|||||||
status = pkg_info.get('status', '').lower()
|
status = pkg_info.get('status', '').lower()
|
||||||
if status.find('not installed') > -1 or status.find('out-of-date') > -1:
|
if status.find('not installed') > -1 or status.find('out-of-date') > -1:
|
||||||
ret[name] = pkg_info.get('version')
|
ret[name] = pkg_info.get('version')
|
||||||
|
else:
|
||||||
|
ret[name] = ''
|
||||||
|
|
||||||
# Return a string if only one package name passed
|
# Return a string if only one package name passed
|
||||||
if len(names) == 1 and len(ret):
|
if len(names) == 1 and len(ret):
|
||||||
|
@ -203,8 +203,6 @@ import tornado.web
|
|||||||
import tornado.gen
|
import tornado.gen
|
||||||
from tornado.concurrent import Future
|
from tornado.concurrent import Future
|
||||||
# pylint: enable=import-error
|
# pylint: enable=import-error
|
||||||
import salt.utils
|
|
||||||
salt.utils.zeromq.install_zmq()
|
|
||||||
|
|
||||||
# salt imports
|
# salt imports
|
||||||
import salt.ext.six as six
|
import salt.ext.six as six
|
||||||
@ -214,6 +212,7 @@ import salt.utils.event
|
|||||||
import salt.utils.jid
|
import salt.utils.jid
|
||||||
import salt.utils.json
|
import salt.utils.json
|
||||||
import salt.utils.yaml
|
import salt.utils.yaml
|
||||||
|
import salt.utils.zeromq
|
||||||
from salt.utils.event import tagify
|
from salt.utils.event import tagify
|
||||||
import salt.client
|
import salt.client
|
||||||
import salt.runner
|
import salt.runner
|
||||||
@ -224,6 +223,7 @@ from salt.exceptions import (
|
|||||||
EauthAuthenticationError
|
EauthAuthenticationError
|
||||||
)
|
)
|
||||||
|
|
||||||
|
salt.utils.zeromq.install_zmq()
|
||||||
json = salt.utils.json.import_json()
|
json = salt.utils.json.import_json()
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -933,9 +933,11 @@ class SaltAPIHandler(BaseSaltAPIHandler): # pylint: disable=W0223
|
|||||||
# Generate jid before triggering a job to subscribe all returns from minions
|
# Generate jid before triggering a job to subscribe all returns from minions
|
||||||
chunk['jid'] = salt.utils.jid.gen_jid(self.application.opts)
|
chunk['jid'] = salt.utils.jid.gen_jid(self.application.opts)
|
||||||
|
|
||||||
# Subscribe returns from minions before firing a job
|
# start listening for the event before we fire the job to avoid races
|
||||||
minions = set(self.ckminions.check_minions(chunk['tgt'], chunk.get('tgt_type', 'glob')))
|
events = [
|
||||||
future_minion_map = self.subscribe_minion_returns(chunk['jid'], minions)
|
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)
|
f_call = self._format_call_run_job_async(chunk)
|
||||||
# fire a job off
|
# fire a job off
|
||||||
@ -944,88 +946,92 @@ class SaltAPIHandler(BaseSaltAPIHandler): # pylint: disable=W0223
|
|||||||
# if the job didn't publish, lets not wait around for nothing
|
# if the job didn't publish, lets not wait around for nothing
|
||||||
# TODO: set header??
|
# TODO: set header??
|
||||||
if 'jid' not in pub_data:
|
if 'jid' not in pub_data:
|
||||||
for future in future_minion_map:
|
for future in events:
|
||||||
try:
|
try:
|
||||||
future.set_result(None)
|
future.set_result(None)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
raise tornado.gen.Return('No minions matched the target. No command was sent, no jid was assigned.')
|
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
|
# wait syndic a while to avoid missing published events
|
||||||
if self.application.opts['order_masters']:
|
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
|
# 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'],
|
chunk['tgt'],
|
||||||
f_call['kwargs']['tgt_type'],
|
f_call['kwargs']['tgt_type'],
|
||||||
|
minions,
|
||||||
is_finished)
|
is_finished)
|
||||||
|
|
||||||
minion_returns_future = self.sanitize_minion_returns(future_minion_map, pub_data['minions'], is_finished)
|
def more_todo():
|
||||||
|
'''Check if there are any more minions we are waiting on returns from
|
||||||
yield job_not_running_future
|
'''
|
||||||
raise tornado.gen.Return((yield minion_returns_future))
|
return any(x is False for x in six.itervalues(minions))
|
||||||
|
|
||||||
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]
|
|
||||||
|
|
||||||
|
# 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 = {}
|
chunk_ret = {}
|
||||||
while True:
|
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:
|
try:
|
||||||
# When finished entire routine, cleanup other futures and return result
|
# When finished entire routine, cleanup other futures and return result
|
||||||
if f is is_finished:
|
if f is is_finished:
|
||||||
for event in future_minion_map.keys():
|
cancel_inflight_futures()
|
||||||
if not event.done():
|
|
||||||
event.set_result(None)
|
|
||||||
raise tornado.gen.Return(chunk_ret)
|
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()
|
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:
|
except TimeoutException:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# clear finished event future
|
if f == events[0]:
|
||||||
try:
|
events[0] = self.application.event_listener.get_event(self, tag='salt/job/'+chunk['jid'])
|
||||||
minions.remove(future_minion_map[f])
|
else:
|
||||||
del future_minion_map[f]
|
events[1] = self.application.event_listener.get_event(self, tag='syndic/job/'+chunk['jid'])
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if not minions:
|
|
||||||
if not is_finished.done():
|
|
||||||
is_finished.set_result(True)
|
|
||||||
raise tornado.gen.Return(chunk_ret)
|
|
||||||
|
|
||||||
@tornado.gen.coroutine
|
@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
|
Return a future which will complete once jid (passed in) is no longer
|
||||||
running on tgt
|
running on tgt
|
||||||
@ -1051,8 +1057,6 @@ class SaltAPIHandler(BaseSaltAPIHandler): # pylint: disable=W0223
|
|||||||
event = f.result()
|
event = f.result()
|
||||||
except TimeoutException:
|
except TimeoutException:
|
||||||
if not minion_running:
|
if not minion_running:
|
||||||
if not is_finished.done():
|
|
||||||
is_finished.set_result(True)
|
|
||||||
raise tornado.gen.Return(True)
|
raise tornado.gen.Return(True)
|
||||||
else:
|
else:
|
||||||
ping_pub_data = yield self.saltclients['local'](tgt,
|
ping_pub_data = yield self.saltclients['local'](tgt,
|
||||||
@ -1066,6 +1070,8 @@ class SaltAPIHandler(BaseSaltAPIHandler): # pylint: disable=W0223
|
|||||||
# Minions can return, we want to see if the job is running...
|
# Minions can return, we want to see if the job is running...
|
||||||
if event['data'].get('return', {}) == {}:
|
if event['data'].get('return', {}) == {}:
|
||||||
continue
|
continue
|
||||||
|
if event['data']['id'] not in minions:
|
||||||
|
minions[event['data']['id']] = False
|
||||||
minion_running = True
|
minion_running = True
|
||||||
|
|
||||||
@tornado.gen.coroutine
|
@tornado.gen.coroutine
|
||||||
|
@ -1037,6 +1037,11 @@ class Pillar(object):
|
|||||||
decrypt_errors = self.decrypt_pillar(pillar)
|
decrypt_errors = self.decrypt_pillar(pillar)
|
||||||
if decrypt_errors:
|
if decrypt_errors:
|
||||||
pillar.setdefault('_errors', []).extend(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
|
return pillar
|
||||||
|
|
||||||
def decrypt_pillar(self, pillar):
|
def decrypt_pillar(self, pillar):
|
||||||
|
@ -328,7 +328,7 @@ def chconfig(cmd, *args, **kwargs):
|
|||||||
|
|
||||||
'''
|
'''
|
||||||
# Strip the __pub_ keys...is there a better way to do this?
|
# Strip the __pub_ keys...is there a better way to do this?
|
||||||
for k in kwargs:
|
for k in list(kwargs):
|
||||||
if k.startswith('__pub_'):
|
if k.startswith('__pub_'):
|
||||||
kwargs.pop(k)
|
kwargs.pop(k)
|
||||||
|
|
||||||
|
@ -200,7 +200,7 @@ def _walk(path, value, metrics, timestamp, skip):
|
|||||||
to a float. Defaults to `False`.
|
to a float. Defaults to `False`.
|
||||||
'''
|
'''
|
||||||
log.trace(
|
log.trace(
|
||||||
'Carbon return walking path: %s, value: %s, metrics: %s, ',
|
'Carbon return walking path: %s, value: %s, metrics: %s, '
|
||||||
'timestamp: %s', path, value, metrics, timestamp
|
'timestamp: %s', path, value, metrics, timestamp
|
||||||
)
|
)
|
||||||
if isinstance(value, collections.Mapping):
|
if isinstance(value, collections.Mapping):
|
||||||
|
@ -192,14 +192,10 @@ def returner(ret):
|
|||||||
logoption = logoption | getattr(syslog, opt)
|
logoption = logoption | getattr(syslog, opt)
|
||||||
|
|
||||||
# Open syslog correctly based on options and tag
|
# Open syslog correctly based on options and tag
|
||||||
try:
|
if 'tag' in _options:
|
||||||
if 'tag' in _options:
|
syslog.openlog(ident=salt.utils.stringutils.to_str(_options['tag']), logoption=logoption)
|
||||||
syslog.openlog(ident=_options['tag'], logoption=logoption)
|
else:
|
||||||
else:
|
syslog.openlog(logoption=logoption)
|
||||||
syslog.openlog(logoption=logoption)
|
|
||||||
except TypeError:
|
|
||||||
# Python 2.6 syslog.openlog does not accept keyword args
|
|
||||||
syslog.openlog(_options.get('tag', 'salt-minion'), logoption)
|
|
||||||
|
|
||||||
# Send log of given level and facility
|
# Send log of given level and facility
|
||||||
syslog.syslog(facility | level, salt.utils.json.dumps(ret))
|
syslog.syslog(facility | level, salt.utils.json.dumps(ret))
|
||||||
|
@ -164,7 +164,7 @@ def action(func=None,
|
|||||||
instances,
|
instances,
|
||||||
provider,
|
provider,
|
||||||
instance,
|
instance,
|
||||||
**salt.utils.args.clean_kwargs(**kwargs)
|
salt.utils.args.clean_kwargs(**kwargs)
|
||||||
)
|
)
|
||||||
except SaltCloudConfigError as err:
|
except SaltCloudConfigError as err:
|
||||||
log.error(err)
|
log.error(err)
|
||||||
|
@ -153,7 +153,7 @@ def lookup_jid(jid,
|
|||||||
try:
|
try:
|
||||||
# Check if the return data has an 'out' key. We'll use that as the
|
# 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 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):
|
except (StopIteration, AttributeError):
|
||||||
outputter = None
|
outputter = None
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ def generate_token(minion_id, signature, impersonated_by_master=False):
|
|||||||
payload = {
|
payload = {
|
||||||
'policies': _get_policies(minion_id, config),
|
'policies': _get_policies(minion_id, config),
|
||||||
'num_uses': 1,
|
'num_uses': 1,
|
||||||
'metadata': audit_data
|
'meta': audit_data
|
||||||
}
|
}
|
||||||
|
|
||||||
if payload['policies'] == []:
|
if payload['policies'] == []:
|
||||||
|
@ -172,7 +172,9 @@ def init(
|
|||||||
start=True,
|
start=True,
|
||||||
disk='default',
|
disk='default',
|
||||||
saltenv='base',
|
saltenv='base',
|
||||||
enable_vnc=False):
|
enable_vnc=False,
|
||||||
|
seed_cmd='seed.apply',
|
||||||
|
enable_qcow=False):
|
||||||
'''
|
'''
|
||||||
This routine is used to create a new virtual machine. This routines takes
|
This routine is used to create a new virtual machine. This routines takes
|
||||||
a number of options to determine what the newly created virtual machine
|
a number of options to determine what the newly created virtual machine
|
||||||
@ -194,14 +196,14 @@ def init(
|
|||||||
on the salt fileserver, but http, https and ftp can also be used.
|
on the salt fileserver, but http, https and ftp can also be used.
|
||||||
|
|
||||||
hypervisor
|
hypervisor
|
||||||
The hypervisor to use for the new virtual machine. Default is 'kvm'.
|
The hypervisor to use for the new virtual machine. Default is `kvm`.
|
||||||
|
|
||||||
host
|
host
|
||||||
The host to use for the new virtual machine, if this is omitted
|
The host to use for the new virtual machine, if this is omitted
|
||||||
Salt will automatically detect what host to use.
|
Salt will automatically detect what host to use.
|
||||||
|
|
||||||
seed
|
seed
|
||||||
Set to False to prevent Salt from seeding the new virtual machine.
|
Set to `False` to prevent Salt from seeding the new virtual machine.
|
||||||
|
|
||||||
nic
|
nic
|
||||||
The nic profile to use, defaults to the "default" nic profile which
|
The nic profile to use, defaults to the "default" nic profile which
|
||||||
@ -217,6 +219,17 @@ def init(
|
|||||||
|
|
||||||
saltenv
|
saltenv
|
||||||
The Salt environment to use
|
The Salt environment to use
|
||||||
|
|
||||||
|
enable_vnc
|
||||||
|
Whether a VNC screen is attached to resulting VM. Default is `False`.
|
||||||
|
|
||||||
|
seed_cmd
|
||||||
|
If seed is `True`, use this execution module function to seed new VM.
|
||||||
|
Default is `seed.apply`.
|
||||||
|
|
||||||
|
enable_qcow
|
||||||
|
Clone disk image as a copy-on-write qcow2 image, using downloaded
|
||||||
|
`image` as backing file.
|
||||||
'''
|
'''
|
||||||
__jid_event__.fire_event({'message': 'Searching for hosts'}, 'progress')
|
__jid_event__.fire_event({'message': 'Searching for hosts'}, 'progress')
|
||||||
data = query(host, quiet=True)
|
data = query(host, quiet=True)
|
||||||
@ -257,25 +270,29 @@ def init(
|
|||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
cmd_ret = client.cmd_iter(
|
cmd_ret = client.cmd_iter(
|
||||||
host,
|
host,
|
||||||
'virt.init',
|
'virt.init',
|
||||||
[
|
[
|
||||||
name,
|
name,
|
||||||
cpu,
|
cpu,
|
||||||
mem,
|
mem
|
||||||
image,
|
],
|
||||||
nic,
|
timeout=600,
|
||||||
hypervisor,
|
kwarg={
|
||||||
start,
|
'image': image,
|
||||||
disk,
|
'nic': nic,
|
||||||
saltenv,
|
'hypervisor': hypervisor,
|
||||||
seed,
|
'start': start,
|
||||||
install,
|
'disk': disk,
|
||||||
pub_key,
|
'saltenv': saltenv,
|
||||||
priv_key,
|
'seed': seed,
|
||||||
enable_vnc,
|
'install': install,
|
||||||
],
|
'pub_key': pub_key,
|
||||||
timeout=600)
|
'priv_key': priv_key,
|
||||||
|
'seed_cmd': seed_cmd,
|
||||||
|
'enable_vnc': enable_vnc,
|
||||||
|
'enable_qcow': enable_qcow,
|
||||||
|
})
|
||||||
except SaltClientError as client_error:
|
except SaltClientError as client_error:
|
||||||
# Fall through to ret error handling below
|
# Fall through to ret error handling below
|
||||||
print(client_error)
|
print(client_error)
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user