mirror of
https://github.com/valitydev/salt.git
synced 2024-11-08 01:18:58 +00:00
Merge branch '2016.3' of github.com:saltstack/salt into 2016.3
This commit is contained in:
commit
58160ed6c0
@ -4,17 +4,16 @@
|
||||
# Because the location to this file must be explicitly declared when using it,
|
||||
# its actual location on disk is up to the user.
|
||||
|
||||
#fedora_rs:
|
||||
# - fedora1
|
||||
# - fedora2
|
||||
# - fedora3
|
||||
# - fedora4
|
||||
# - fedora5
|
||||
|
||||
fedora_rs:
|
||||
- fedora1
|
||||
- fedora2
|
||||
- fedora3
|
||||
- fedora4
|
||||
- fedora5
|
||||
|
||||
ubuntu_rs:
|
||||
- ubuntu1
|
||||
- ubuntu2
|
||||
- ubuntu3
|
||||
- ubuntu4
|
||||
- ubuntu5
|
||||
#ubuntu_rs:
|
||||
# - ubuntu1
|
||||
# - ubuntu2
|
||||
# - ubuntu3
|
||||
# - ubuntu4
|
||||
# - ubuntu5
|
||||
|
@ -1,23 +1,27 @@
|
||||
base_ec2:
|
||||
provider: my-ec2-config
|
||||
image: ami-e565ba8c
|
||||
size: t1.micro
|
||||
script: python-bootstrap
|
||||
minion:
|
||||
cheese: edam
|
||||
# This file may be used in addition to, or instead of, the files in the
|
||||
# cloud.profiles.d/ directory. The format for this file, and all files in that
|
||||
# directory, is identical.
|
||||
|
||||
ubuntu_rs:
|
||||
provider: my-openstack-rackspace-config
|
||||
image: Ubuntu 12.04 LTS
|
||||
size: 256 server
|
||||
script: Ubuntu
|
||||
minion:
|
||||
cheese: edam
|
||||
#base_ec2:
|
||||
# provider: my-ec2-config
|
||||
# image: ami-e565ba8c
|
||||
# size: t1.micro
|
||||
# script: python-bootstrap
|
||||
# minion:
|
||||
# cheese: edam
|
||||
|
||||
fedora_rs:
|
||||
provider: my-openstack-rackspace-config
|
||||
image: Fedora 17
|
||||
size: 256 server
|
||||
script: Fedora
|
||||
minion:
|
||||
cheese: edam
|
||||
#ubuntu_rs:
|
||||
# provider: my-openstack-rackspace-config
|
||||
# image: Ubuntu 12.04 LTS
|
||||
# size: 256 server
|
||||
# script: Ubuntu
|
||||
# minion:
|
||||
# cheese: edam
|
||||
|
||||
#fedora_rs:
|
||||
# provider: my-openstack-rackspace-config
|
||||
# image: Fedora 17
|
||||
# size: 256 server
|
||||
# script: Fedora
|
||||
# minion:
|
||||
# cheese: edam
|
||||
|
@ -2,115 +2,114 @@
|
||||
|
||||
# Arch Linux
|
||||
# https://wiki.archlinux.org/index.php/Arch_Linux_AMIs_for_Amazon_Web_Services
|
||||
arch_ec2:
|
||||
provider: my-ec2-config
|
||||
image: ami-6ee95107
|
||||
size: t1.micro
|
||||
ssh_username: root
|
||||
location: us-east-1
|
||||
minion:
|
||||
grains:
|
||||
cloud: ec2-us-east-1
|
||||
#arch_ec2:
|
||||
# provider: my-ec2-config
|
||||
# image: ami-6ee95107
|
||||
# size: t1.micro
|
||||
# ssh_username: root
|
||||
# location: us-east-1
|
||||
# minion:
|
||||
# grains:
|
||||
# cloud: ec2-us-east-1
|
||||
|
||||
arch_cloud-init_ec2:
|
||||
provider: my-ec2-config
|
||||
image: ami-596de730
|
||||
size: t1.micro
|
||||
ssh_username: root
|
||||
location: us-east-1
|
||||
minion:
|
||||
grains:
|
||||
cloud: ec2-us-east-1
|
||||
#arch_cloud-init_ec2:
|
||||
# provider: my-ec2-config
|
||||
# image: ami-596de730
|
||||
# size: t1.micro
|
||||
# ssh_username: root
|
||||
# location: us-east-1
|
||||
# minion:
|
||||
# grains:
|
||||
# cloud: ec2-us-east-1
|
||||
|
||||
# Centos 6, available from ec2 marketplace for no-charge
|
||||
# http://wiki.centos.org/Cloud/AWS
|
||||
centos_6:
|
||||
provider: my-ec2-config
|
||||
image: ami-86e15bef
|
||||
size: t1.micro
|
||||
ssh_username: root
|
||||
location: us-east-1
|
||||
minion:
|
||||
grains:
|
||||
cloud: ec2-us-east-1
|
||||
#centos_6:
|
||||
# provider: my-ec2-config
|
||||
# image: ami-86e15bef
|
||||
# size: t1.micro
|
||||
# ssh_username: root
|
||||
# location: us-east-1
|
||||
# minion:
|
||||
# grains:
|
||||
# cloud: ec2-us-east-1
|
||||
|
||||
# official Debian, available at no-charge from ec2 marketplace:
|
||||
# http://wiki.debian.org/Cloud/AmazonEC2Image
|
||||
debian_squeeze_ec2:
|
||||
provider: my-ec2-config
|
||||
image: ami-a121a6c8
|
||||
size: t1.micro
|
||||
ssh_username: admin
|
||||
location: us-east-1
|
||||
minion:
|
||||
grains:
|
||||
cloud: ec2-us-east-1
|
||||
#debian_squeeze_ec2:
|
||||
# provider: my-ec2-config
|
||||
# image: ami-a121a6c8
|
||||
# size: t1.micro
|
||||
# ssh_username: admin
|
||||
# location: us-east-1
|
||||
# minion:
|
||||
# grains:
|
||||
# cloud: ec2-us-east-1
|
||||
|
||||
# Fedora project cloud images
|
||||
# https://fedoraproject.org/wiki/Cloud_images
|
||||
fedora_17_ec2:
|
||||
provider: my-ec2-config
|
||||
image: ami-2ea50247
|
||||
size: t1.micro
|
||||
ssh_username: ec2-user
|
||||
location: us-east-1
|
||||
minion:
|
||||
grains:
|
||||
cloud: ec2-us-east-1
|
||||
#fedora_17_ec2:
|
||||
# provider: my-ec2-config
|
||||
# image: ami-2ea50247
|
||||
# size: t1.micro
|
||||
# ssh_username: ec2-user
|
||||
# location: us-east-1
|
||||
# minion:
|
||||
# grains:
|
||||
# cloud: ec2-us-east-1
|
||||
|
||||
fedora_18_ec2:
|
||||
provider: my-ec2-config
|
||||
image: ami-6145cc08
|
||||
size: t1.micro
|
||||
ssh_username: ec2-user
|
||||
location: us-east-1
|
||||
minion:
|
||||
grains:
|
||||
cloud: ec2-us-east-1
|
||||
#fedora_18_ec2:
|
||||
# provider: my-ec2-config
|
||||
# image: ami-6145cc08
|
||||
# size: t1.micro
|
||||
# ssh_username: ec2-user
|
||||
# location: us-east-1
|
||||
# minion:
|
||||
# grains:
|
||||
# cloud: ec2-us-east-1
|
||||
|
||||
# FreeBSD 9.1
|
||||
# http://www.daemonology.net/freebsd-on-ec2/
|
||||
|
||||
# this t1.micro instance does not auto-populate SSH keys see above link
|
||||
freebsd_91_ec2:
|
||||
provider: my-ec2-config
|
||||
image: ami-5339bb3a
|
||||
size: t1.micro
|
||||
ssh_username: ec2-user
|
||||
location: us-east-1
|
||||
minion:
|
||||
grains:
|
||||
cloud: ec2-us-east-1
|
||||
#freebsd_91_ec2:
|
||||
# provider: my-ec2-config
|
||||
# image: ami-5339bb3a
|
||||
# size: t1.micro
|
||||
# ssh_username: ec2-user
|
||||
# location: us-east-1
|
||||
# minion:
|
||||
# grains:
|
||||
# cloud: ec2-us-east-1
|
||||
|
||||
freebsd_91_4XL_ec2:
|
||||
provider: my-ec2-config
|
||||
image: ami-79088510
|
||||
size: Cluster Compute 4XL
|
||||
ssh_username: ec2-user
|
||||
location: us-east-1
|
||||
minion:
|
||||
grains:
|
||||
cloud: ec2-us-east-1
|
||||
#freebsd_91_4XL_ec2:
|
||||
# provider: my-ec2-config
|
||||
# image: ami-79088510
|
||||
# size: Cluster Compute 4XL
|
||||
# ssh_username: ec2-user
|
||||
# location: us-east-1
|
||||
# minion:
|
||||
# grains:
|
||||
# cloud: ec2-us-east-1
|
||||
|
||||
# Canonical Ubuntu LTS images
|
||||
# http://cloud-images.ubuntu.com/releases/
|
||||
ubuntu_lucid_ec2:
|
||||
provider: my-ec2-config
|
||||
image: ami-21e47148
|
||||
size: t1.micro
|
||||
ssh_username: ubuntu
|
||||
location: us-east-1
|
||||
minion:
|
||||
grains:
|
||||
cloud: ec2-us-east-1
|
||||
|
||||
ubuntu_precise_ec2:
|
||||
provider: my-ec2-config
|
||||
image: ami-0145d268
|
||||
size: t1.micro
|
||||
ssh_username: ubuntu
|
||||
location: us-east-1
|
||||
minion:
|
||||
grains:
|
||||
cloud: ec2-us-east-1
|
||||
#ubuntu_lucid_ec2:
|
||||
# provider: my-ec2-config
|
||||
# image: ami-21e47148
|
||||
# size: t1.micro
|
||||
# ssh_username: ubuntu
|
||||
# location: us-east-1
|
||||
# minion:
|
||||
# grains:
|
||||
# cloud: ec2-us-east-1
|
||||
|
||||
#ubuntu_precise_ec2:
|
||||
# provider: my-ec2-config
|
||||
# image: ami-0145d268
|
||||
# size: t1.micro
|
||||
# ssh_username: ubuntu
|
||||
# location: us-east-1
|
||||
# minion:
|
||||
# grains:
|
||||
# cloud: ec2-us-east-1
|
||||
|
@ -2,105 +2,104 @@
|
||||
|
||||
# Arch Linux
|
||||
# https://wiki.archlinux.org/index.php/Arch_Linux_AMIs_for_Amazon_Web_Services
|
||||
arch_ec2:
|
||||
provider: my-ec2-config
|
||||
image: ami-337d5b76
|
||||
size: t1.micro
|
||||
ssh_username: root
|
||||
location: us-west-1
|
||||
minion:
|
||||
grains:
|
||||
cloud: ec2-us-west-1
|
||||
#arch_ec2:
|
||||
# provider: my-ec2-config
|
||||
# image: ami-337d5b76
|
||||
# size: t1.micro
|
||||
# ssh_username: root
|
||||
# location: us-west-1
|
||||
# minion:
|
||||
# grains:
|
||||
# cloud: ec2-us-west-1
|
||||
|
||||
arch_cloud-init_ec2:
|
||||
provider: my-ec2-config
|
||||
image: ami-6a5f7c2f
|
||||
size: t1.micro
|
||||
ssh_username: root
|
||||
location: us-west-1
|
||||
minion:
|
||||
grains:
|
||||
cloud: ec2-us-west-1
|
||||
#arch_cloud-init_ec2:
|
||||
# provider: my-ec2-config
|
||||
# image: ami-6a5f7c2f
|
||||
# size: t1.micro
|
||||
# ssh_username: root
|
||||
# location: us-west-1
|
||||
# minion:
|
||||
# grains:
|
||||
# cloud: ec2-us-west-1
|
||||
|
||||
# Centos 6, available from ec2 marketplace for no-charge
|
||||
# http://wiki.centos.org/Cloud/AWS
|
||||
centos_6:
|
||||
provider: my-ec2-config
|
||||
image: ami-f61630b3
|
||||
size: t1.micro
|
||||
ssh_username: root
|
||||
location: us-west-1
|
||||
minion:
|
||||
grains:
|
||||
cloud: ec2-us-west-1
|
||||
#centos_6:
|
||||
# provider: my-ec2-config
|
||||
# image: ami-f61630b3
|
||||
# size: t1.micro
|
||||
# ssh_username: root
|
||||
# location: us-west-1
|
||||
# minion:
|
||||
# grains:
|
||||
# cloud: ec2-us-west-1
|
||||
|
||||
# official Debian, available at no-charge from ec2 marketplace:
|
||||
# http://wiki.debian.org/Cloud/AmazonEC2Image
|
||||
debian_squeeze_ec2:
|
||||
provider: my-ec2-config
|
||||
image: ami-2c735269
|
||||
size: t1.micro
|
||||
ssh_username: admin
|
||||
location: us-west-1
|
||||
minion:
|
||||
grains:
|
||||
cloud: ec2-us-west-1
|
||||
#debian_squeeze_ec2:
|
||||
# provider: my-ec2-config
|
||||
# image: ami-2c735269
|
||||
# size: t1.micro
|
||||
# ssh_username: admin
|
||||
# location: us-west-1
|
||||
# minion:
|
||||
# grains:
|
||||
# cloud: ec2-us-west-1
|
||||
|
||||
# Fedora project cloud images
|
||||
# https://fedoraproject.org/wiki/Cloud_images
|
||||
fedora_17_ec2:
|
||||
provider: my-ec2-config
|
||||
image: ami-877e24c2
|
||||
size: t1.micro
|
||||
ssh_username: ec2-user
|
||||
location: us-west-1
|
||||
minion:
|
||||
grains:
|
||||
cloud: ec2-us-west-1
|
||||
#fedora_17_ec2:
|
||||
# provider: my-ec2-config
|
||||
# image: ami-877e24c2
|
||||
# size: t1.micro
|
||||
# ssh_username: ec2-user
|
||||
# location: us-west-1
|
||||
# minion:
|
||||
# grains:
|
||||
# cloud: ec2-us-west-1
|
||||
|
||||
fedora_18_ec2:
|
||||
provider: my-ec2-config
|
||||
image: ami-0899b94d
|
||||
size: t1.micro
|
||||
ssh_username: ec2-user
|
||||
location: us-west-1
|
||||
minion:
|
||||
grains:
|
||||
cloud: ec2-us-west-1
|
||||
#fedora_18_ec2:
|
||||
# provider: my-ec2-config
|
||||
# image: ami-0899b94d
|
||||
# size: t1.micro
|
||||
# ssh_username: ec2-user
|
||||
# location: us-west-1
|
||||
# minion:
|
||||
# grains:
|
||||
# cloud: ec2-us-west-1
|
||||
|
||||
# FreeBSD 9.1
|
||||
# http://www.daemonology.net/freebsd-on-ec2/
|
||||
|
||||
# this t1.micro instance does not auto-populate SSH keys see above link
|
||||
freebsd_91_ec2:
|
||||
provider: my-ec2-config
|
||||
image: ami-4c8baa09
|
||||
size: t1.micro
|
||||
ssh_username: ec2-user
|
||||
location: us-west-1
|
||||
minion:
|
||||
grains:
|
||||
cloud: ec2-us-west-1
|
||||
#freebsd_91_ec2:
|
||||
# provider: my-ec2-config
|
||||
# image: ami-4c8baa09
|
||||
# size: t1.micro
|
||||
# ssh_username: ec2-user
|
||||
# location: us-west-1
|
||||
# minion:
|
||||
# grains:
|
||||
# cloud: ec2-us-west-1
|
||||
|
||||
# Canonical Ubuntu LTS images
|
||||
# http://cloud-images.ubuntu.com/releases/
|
||||
ubuntu_lucid_ec2:
|
||||
provider: my-ec2-config
|
||||
image: ami-e63013a3
|
||||
size: t1.micro
|
||||
ssh_username: ubuntu
|
||||
location: us-west-1
|
||||
minion:
|
||||
grains:
|
||||
cloud: ec2-us-west-1
|
||||
|
||||
ubuntu_precise_ec2:
|
||||
provider: my-ec2-config
|
||||
image: ami-3ed8fb7b
|
||||
size: t1.micro
|
||||
ssh_username: ubuntu
|
||||
location: us-west-1
|
||||
minion:
|
||||
grains:
|
||||
cloud: ec2-us-west-1
|
||||
#ubuntu_lucid_ec2:
|
||||
# provider: my-ec2-config
|
||||
# image: ami-e63013a3
|
||||
# size: t1.micro
|
||||
# ssh_username: ubuntu
|
||||
# location: us-west-1
|
||||
# minion:
|
||||
# grains:
|
||||
# cloud: ec2-us-west-1
|
||||
|
||||
#ubuntu_precise_ec2:
|
||||
# provider: my-ec2-config
|
||||
# image: ami-3ed8fb7b
|
||||
# size: t1.micro
|
||||
# ssh_username: ubuntu
|
||||
# location: us-west-1
|
||||
# minion:
|
||||
# grains:
|
||||
# cloud: ec2-us-west-1
|
||||
|
@ -2,115 +2,114 @@
|
||||
|
||||
# Arch Linux
|
||||
# https://wiki.archlinux.org/index.php/Arch_Linux_AMIs_for_Amazon_Web_Services
|
||||
arch_ec2:
|
||||
provider: my-ec2-config
|
||||
image: ami-bcf77e8c
|
||||
size: t1.micro
|
||||
ssh_username: root
|
||||
location: us-west-2
|
||||
minion:
|
||||
grains:
|
||||
cloud: ec2-us-west-2
|
||||
#arch_ec2:
|
||||
# provider: my-ec2-config
|
||||
# image: ami-bcf77e8c
|
||||
# size: t1.micro
|
||||
# ssh_username: root
|
||||
# location: us-west-2
|
||||
# minion:
|
||||
# grains:
|
||||
# cloud: ec2-us-west-2
|
||||
|
||||
arch_cloud-init_ec2:
|
||||
provider: my-ec2-config
|
||||
image: ami-6a5f7c2f
|
||||
size: t1.micro
|
||||
ssh_username: root
|
||||
location: us-west-2
|
||||
minion:
|
||||
grains:
|
||||
cloud: ec2-us-west-2
|
||||
#arch_cloud-init_ec2:
|
||||
# provider: my-ec2-config
|
||||
# image: ami-6a5f7c2f
|
||||
# size: t1.micro
|
||||
# ssh_username: root
|
||||
# location: us-west-2
|
||||
# minion:
|
||||
# grains:
|
||||
# cloud: ec2-us-west-2
|
||||
|
||||
# Centos 6, available from ec2 marketplace for no-charge
|
||||
# http://wiki.centos.org/Cloud/AWS
|
||||
centos_6:
|
||||
provider: my-ec2-config
|
||||
image: ami-de5bd2ee
|
||||
size: t1.micro
|
||||
ssh_username: root
|
||||
location: us-west-2
|
||||
minion:
|
||||
grains:
|
||||
cloud: ec2-us-west-2
|
||||
#centos_6:
|
||||
# provider: my-ec2-config
|
||||
# image: ami-de5bd2ee
|
||||
# size: t1.micro
|
||||
# ssh_username: root
|
||||
# location: us-west-2
|
||||
# minion:
|
||||
# grains:
|
||||
# cloud: ec2-us-west-2
|
||||
|
||||
# official Debian, available at no-charge from ec2 marketplace:
|
||||
# http://wiki.debian.org/Cloud/AmazonEC2Image
|
||||
debian_squeeze_ec2:
|
||||
provider: my-ec2-config
|
||||
image: ami-e4da52d4
|
||||
size: t1.micro
|
||||
ssh_username: admin
|
||||
location: us-west-2
|
||||
minion:
|
||||
grains:
|
||||
cloud: ec2-us-west-2
|
||||
#debian_squeeze_ec2:
|
||||
# provider: my-ec2-config
|
||||
# image: ami-e4da52d4
|
||||
# size: t1.micro
|
||||
# ssh_username: admin
|
||||
# location: us-west-2
|
||||
# minion:
|
||||
# grains:
|
||||
# cloud: ec2-us-west-2
|
||||
|
||||
# Fedora project cloud images
|
||||
# https://fedoraproject.org/wiki/Cloud_images
|
||||
fedora_17_ec2:
|
||||
provider: my-ec2-config
|
||||
image: ami-8e69e5be
|
||||
size: t1.micro
|
||||
ssh_username: ec2-user
|
||||
location: us-west-2
|
||||
minion:
|
||||
grains:
|
||||
cloud: ec2-us-west-2
|
||||
#fedora_17_ec2:
|
||||
# provider: my-ec2-config
|
||||
# image: ami-8e69e5be
|
||||
# size: t1.micro
|
||||
# ssh_username: ec2-user
|
||||
# location: us-west-2
|
||||
# minion:
|
||||
# grains:
|
||||
# cloud: ec2-us-west-2
|
||||
|
||||
fedora_18_ec2:
|
||||
provider: my-ec2-config
|
||||
image: ami-0266ed32
|
||||
size: t1.micro
|
||||
ssh_username: ec2-user
|
||||
location: us-west-2
|
||||
minion:
|
||||
grains:
|
||||
cloud: ec2-us-west-2
|
||||
#fedora_18_ec2:
|
||||
# provider: my-ec2-config
|
||||
# image: ami-0266ed32
|
||||
# size: t1.micro
|
||||
# ssh_username: ec2-user
|
||||
# location: us-west-2
|
||||
# minion:
|
||||
# grains:
|
||||
# cloud: ec2-us-west-2
|
||||
|
||||
# FreeBSD 9.1
|
||||
# http://www.daemonology.net/freebsd-on-ec2/
|
||||
|
||||
# this t1.micro instance does not auto-populate SSH keys see above link
|
||||
freebsd_91_ec2:
|
||||
provider: my-ec2-config
|
||||
image: ami-aa09819a
|
||||
size: t1.micro
|
||||
ssh_username: ec2-user
|
||||
location: us-west-2
|
||||
minion:
|
||||
grains:
|
||||
cloud: ec2-us-west-2
|
||||
#freebsd_91_ec2:
|
||||
# provider: my-ec2-config
|
||||
# image: ami-aa09819a
|
||||
# size: t1.micro
|
||||
# ssh_username: ec2-user
|
||||
# location: us-west-2
|
||||
# minion:
|
||||
# grains:
|
||||
# cloud: ec2-us-west-2
|
||||
|
||||
freebsd_91_4XL_ec2:
|
||||
provider: my-ec2-config
|
||||
image: ami-66169e56
|
||||
size: Cluster Compute 4XL
|
||||
ssh_username: ec2-user
|
||||
location: us-west-2
|
||||
minion:
|
||||
grains:
|
||||
cloud: ec2-us-west-2
|
||||
#freebsd_91_4XL_ec2:
|
||||
# provider: my-ec2-config
|
||||
# image: ami-66169e56
|
||||
# size: Cluster Compute 4XL
|
||||
# ssh_username: ec2-user
|
||||
# location: us-west-2
|
||||
# minion:
|
||||
# grains:
|
||||
# cloud: ec2-us-west-2
|
||||
|
||||
# Canonical Ubuntu LTS images
|
||||
# http://cloud-images.ubuntu.com/releases/
|
||||
ubuntu_lucid_ec2:
|
||||
provider: my-ec2-config
|
||||
image: ami-6ec8425e
|
||||
size: t1.micro
|
||||
ssh_username: ubuntu
|
||||
location: us-west-2
|
||||
minion:
|
||||
grains:
|
||||
cloud: ec2-us-west-2
|
||||
|
||||
ubuntu_precise_ec2:
|
||||
provider: my-ec2-config
|
||||
image: ami-e0941ed0
|
||||
size: t1.micro
|
||||
ssh_username: ubuntu
|
||||
location: us-west-2
|
||||
minion:
|
||||
grains:
|
||||
cloud: ec2-us-west-2
|
||||
#ubuntu_lucid_ec2:
|
||||
# provider: my-ec2-config
|
||||
# image: ami-6ec8425e
|
||||
# size: t1.micro
|
||||
# ssh_username: ubuntu
|
||||
# location: us-west-2
|
||||
# minion:
|
||||
# grains:
|
||||
# cloud: ec2-us-west-2
|
||||
|
||||
#ubuntu_precise_ec2:
|
||||
# provider: my-ec2-config
|
||||
# image: ami-e0941ed0
|
||||
# size: t1.micro
|
||||
# ssh_username: ubuntu
|
||||
# location: us-west-2
|
||||
# minion:
|
||||
# grains:
|
||||
# cloud: ec2-us-west-2
|
||||
|
12
conf/minion
12
conf/minion
@ -397,7 +397,17 @@
|
||||
# access the master has to the minion.
|
||||
#disable_modules: [cmd,test]
|
||||
#disable_returners: []
|
||||
#
|
||||
|
||||
# This is the reverse of disable_modules. The default, like disable_modules, is the empty list,
|
||||
# but if this option is set to *anything* then *only* those modules will load.
|
||||
# Note that this is a very large hammer and it can be quite difficult to keep the minion working
|
||||
# the way you think it should since Salt uses many modules internally itself. At a bare minimum
|
||||
# you need the following enabled or else the minion won't start.
|
||||
#whitelist_modules:
|
||||
# - cmdmod
|
||||
# - test
|
||||
# - config
|
||||
|
||||
# Modules can be loaded from arbitrary paths. This enables the easy deployment
|
||||
# of third party modules. Modules for returners and minions can be loaded.
|
||||
# Specify a list of extra directories to search for minion modules and
|
||||
|
@ -5,6 +5,11 @@ Salt 2016.3.3 Release Notes
|
||||
Version 2016.3.3 is a bugfix release for :doc:`2016.3.0
|
||||
</topics/releases/2016.3.0>`.
|
||||
|
||||
Known Issues
|
||||
------------
|
||||
|
||||
:issue:`36055`: Salt Cloud events (``salt/cloud``) are not generated on the
|
||||
master event bus when provisioning cloud systems.
|
||||
|
||||
Changes for v2016.3.2..2016.3.3
|
||||
-------------------------------
|
||||
|
@ -91,7 +91,7 @@ the firewall tutorial is available :doc:`here </topics/tutorials/firewall>`.
|
||||
|
||||
Finding the Salt Master
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
When a minion starts, by default it searches for a system that resolves to the ``salt`` hostname`` on the network.
|
||||
When a minion starts, by default it searches for a system that resolves to the ``salt`` hostname on the network.
|
||||
If found, the minion initiates the handshake and key authentication process with the Salt master.
|
||||
This means that the easiest configuration approach is to set internal DNS to resolve the name ``salt`` back to the Salt Master IP.
|
||||
|
||||
|
@ -154,7 +154,10 @@ def prep_trans_tar(file_client, chunks, file_refs, pillar=None, id_=None):
|
||||
for ref in file_refs[saltenv]:
|
||||
for name in ref:
|
||||
short = salt.utils.url.parse(name)[0]
|
||||
try:
|
||||
path = file_client.cache_file(name, saltenv, cachedir=cachedir)
|
||||
except IOError:
|
||||
path = ''
|
||||
if path:
|
||||
tgt = os.path.join(env_root, short)
|
||||
tgt_dir = os.path.dirname(tgt)
|
||||
@ -162,7 +165,10 @@ def prep_trans_tar(file_client, chunks, file_refs, pillar=None, id_=None):
|
||||
os.makedirs(tgt_dir)
|
||||
shutil.copy(path, tgt)
|
||||
continue
|
||||
try:
|
||||
files = file_client.cache_dir(name, saltenv, cachedir=cachedir)
|
||||
except IOError:
|
||||
files = ''
|
||||
if files:
|
||||
for filename in files:
|
||||
fn = filename[filename.find(short) + len(short):]
|
||||
|
@ -24,6 +24,21 @@ Set up the cloud configuration at ``/etc/salt/cloud.providers`` or
|
||||
password: JHGhgsayu32jsa
|
||||
driver: opennebula
|
||||
|
||||
This driver supports accessing new VM instances via DNS entry instead
|
||||
of IP address. To enable this feature, in the provider or profile file
|
||||
add `fqdn_base` with a value matching the base of your fully-qualified
|
||||
domain name. Example:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
my-opennebula-config:
|
||||
[...]
|
||||
fqdn_base: <my.basedomain.com>
|
||||
[...]
|
||||
|
||||
The driver will prepend the hostname to the fqdn_base and do a DNS lookup
|
||||
to find the IP of the new VM.
|
||||
|
||||
.. note:
|
||||
|
||||
Whenever ``data`` is provided as a kwarg to a function and the
|
||||
@ -61,10 +76,7 @@ from salt.exceptions import (
|
||||
SaltCloudNotFound,
|
||||
SaltCloudSystemExit
|
||||
)
|
||||
from salt.utils import is_true
|
||||
|
||||
# Import Salt Cloud Libs
|
||||
import salt.utils.cloud
|
||||
import salt.utils
|
||||
|
||||
# Import Third Party Libs
|
||||
try:
|
||||
@ -322,7 +334,7 @@ def list_nodes_select(call=None):
|
||||
'The list_nodes_full function must be called with -f or --function.'
|
||||
)
|
||||
|
||||
return salt.utils.cloud.list_nodes_select(
|
||||
return __utils__['cloud.list_nodes_select'](
|
||||
list_nodes_full('function'), __opts__['query.selection'], call,
|
||||
)
|
||||
|
||||
@ -747,6 +759,27 @@ def get_template_id(kwargs=None, call=None):
|
||||
return ret
|
||||
|
||||
|
||||
def get_template(vm_):
|
||||
r'''
|
||||
Return the template id for a VM.
|
||||
|
||||
.. versionadded:: Carbon
|
||||
|
||||
vm\_
|
||||
The VM dictionary for which to obtain a template.
|
||||
'''
|
||||
|
||||
vm_template = str(config.get_cloud_config_value(
|
||||
'template', vm_, __opts__, search_global=False
|
||||
))
|
||||
try:
|
||||
return list_templates()[vm_template]['id']
|
||||
except KeyError:
|
||||
raise SaltCloudNotFound(
|
||||
'The specified template, \'{0}\', could not be found.'.format(vm_template)
|
||||
)
|
||||
|
||||
|
||||
def get_vm_id(kwargs=None, call=None):
|
||||
'''
|
||||
Returns a virtual machine's ID from the given virtual machine's name.
|
||||
@ -826,12 +859,28 @@ def create(vm_):
|
||||
vm\_
|
||||
The dictionary use to create a VM.
|
||||
|
||||
Optional vm_ dict options for overwriting template:
|
||||
|
||||
region_id
|
||||
Optional - OpenNebula Zone ID
|
||||
|
||||
memory
|
||||
Optional - In MB
|
||||
|
||||
cpu
|
||||
Optional - Percent of host CPU to allocate
|
||||
|
||||
vcpu
|
||||
Optional - Amount of vCPUs to allocate
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt-cloud -p my-opennebula-profile vm_name
|
||||
|
||||
salt-cloud -p my-opennebula-profile vm_name memory=16384 cpu=2.5 vcpu=16
|
||||
|
||||
'''
|
||||
try:
|
||||
# Check for required profile parameters before sending any API calls.
|
||||
@ -851,20 +900,23 @@ def create(vm_):
|
||||
'event',
|
||||
'starting create',
|
||||
'salt/cloud/{0}/creating'.format(vm_['name']),
|
||||
{
|
||||
args={
|
||||
'name': vm_['name'],
|
||||
'profile': vm_['profile'],
|
||||
'provider': vm_['driver'],
|
||||
},
|
||||
sock_dir=__opts__['sock_dir'],
|
||||
transport=__opts__['transport']
|
||||
)
|
||||
|
||||
log.info('Creating Cloud VM {0}'.format(vm_['name']))
|
||||
kwargs = {
|
||||
'name': vm_['name'],
|
||||
'image_id': get_image(vm_),
|
||||
'template_id': get_template(vm_),
|
||||
'region_id': get_location(vm_),
|
||||
}
|
||||
if 'template' in vm_:
|
||||
kwargs['image_id'] = get_template_id({'name': vm_['template']})
|
||||
|
||||
private_networking = config.get_cloud_config_value(
|
||||
'private_networking', vm_, __opts__, search_global=False, default=None
|
||||
@ -875,20 +927,41 @@ def create(vm_):
|
||||
'event',
|
||||
'requesting instance',
|
||||
'salt/cloud/{0}/requesting'.format(vm_['name']),
|
||||
{'kwargs': kwargs},
|
||||
args={'kwargs': kwargs},
|
||||
sock_dir=__opts__['sock_dir'],
|
||||
)
|
||||
|
||||
region = ''
|
||||
if kwargs['region_id'] is not None:
|
||||
region = 'SCHED_REQUIREMENTS="ID={0}"'.format(kwargs['region_id'])
|
||||
template = []
|
||||
if kwargs.get('region_id'):
|
||||
template.append('SCHED_REQUIREMENTS="ID={0}"'.format(kwargs.get('region_id')))
|
||||
if vm_.get('memory'):
|
||||
template.append('MEMORY={0}'.format(vm_.get('memory')))
|
||||
if vm_.get('cpu'):
|
||||
template.append('CPU={0}'.format(vm_.get('cpu')))
|
||||
if vm_.get('vcpu'):
|
||||
template.append('VCPU={0}'.format(vm_.get('vcpu')))
|
||||
template_args = "\n".join(template)
|
||||
|
||||
try:
|
||||
server, user, password = _get_xml_rpc()
|
||||
auth = ':'.join([user, password])
|
||||
server.one.template.instantiate(auth,
|
||||
int(kwargs['image_id']),
|
||||
cret = server.one.template.instantiate(auth,
|
||||
int(kwargs['template_id']),
|
||||
kwargs['name'],
|
||||
False,
|
||||
region)
|
||||
template_args)
|
||||
if not cret[0]:
|
||||
log.error(
|
||||
'Error creating {0} on OpenNebula\n\n'
|
||||
'The following error was returned when trying to '
|
||||
'instantiate the template: {1}'.format(
|
||||
vm_['name'],
|
||||
cret[1]
|
||||
),
|
||||
# Show the traceback if the debug logging level is enabled
|
||||
exc_info_on_loglevel=logging.DEBUG
|
||||
)
|
||||
return False
|
||||
except Exception as exc:
|
||||
log.error(
|
||||
'Error creating {0} on OpenNebula\n\n'
|
||||
@ -902,6 +975,10 @@ def create(vm_):
|
||||
)
|
||||
return False
|
||||
|
||||
fqdn = vm_.get('fqdn_base')
|
||||
if fqdn is not None:
|
||||
fqdn = '{0}.{1}'.format(vm_['name'], fqdn)
|
||||
|
||||
def __query_node_data(vm_name):
|
||||
node_data = show_instance(vm_name, call='action')
|
||||
if not node_data:
|
||||
@ -913,7 +990,7 @@ def create(vm_):
|
||||
return node_data
|
||||
|
||||
try:
|
||||
data = salt.utils.cloud.wait_for_ip(
|
||||
data = __utils__['cloud.wait_for_ip'](
|
||||
__query_node_data,
|
||||
update_args=(vm_['name'],),
|
||||
timeout=config.get_cloud_config_value(
|
||||
@ -940,10 +1017,15 @@ def create(vm_):
|
||||
)
|
||||
)
|
||||
|
||||
if fqdn:
|
||||
vm_['ssh_host'] = fqdn
|
||||
private_ip = '0.0.0.0'
|
||||
else:
|
||||
try:
|
||||
private_ip = data['private_ips'][0]
|
||||
except KeyError:
|
||||
private_ip = data['template']['nic']['ip']
|
||||
vm_['ssh_host'] = private_ip
|
||||
|
||||
ssh_username = config.get_cloud_config_value(
|
||||
'ssh_username', vm_, __opts__, default='root'
|
||||
@ -951,9 +1033,8 @@ def create(vm_):
|
||||
|
||||
vm_['username'] = ssh_username
|
||||
vm_['key_filename'] = key_filename
|
||||
vm_['ssh_host'] = private_ip
|
||||
|
||||
ret = salt.utils.cloud.bootstrap(vm_, __opts__)
|
||||
ret = __utils__['cloud.bootstrap'](vm_, __opts__)
|
||||
|
||||
ret['id'] = data['id']
|
||||
ret['image'] = vm_['image']
|
||||
@ -974,11 +1055,12 @@ def create(vm_):
|
||||
'event',
|
||||
'created instance',
|
||||
'salt/cloud/{0}/created'.format(vm_['name']),
|
||||
{
|
||||
args={
|
||||
'name': vm_['name'],
|
||||
'profile': vm_['profile'],
|
||||
'provider': vm_['driver'],
|
||||
},
|
||||
sock_dir=__opts__['sock_dir'],
|
||||
)
|
||||
|
||||
return ret
|
||||
@ -1011,7 +1093,8 @@ def destroy(name, call=None):
|
||||
'event',
|
||||
'destroying instance',
|
||||
'salt/cloud/{0}/destroying'.format(name),
|
||||
{'name': name},
|
||||
args={'name': name},
|
||||
sock_dir=__opts__['sock_dir'],
|
||||
)
|
||||
|
||||
server, user, password = _get_xml_rpc()
|
||||
@ -1024,11 +1107,12 @@ def destroy(name, call=None):
|
||||
'event',
|
||||
'destroyed instance',
|
||||
'salt/cloud/{0}/destroyed'.format(name),
|
||||
{'name': name},
|
||||
args={'name': name},
|
||||
sock_dir=__opts__['sock_dir'],
|
||||
)
|
||||
|
||||
if __opts__.get('update_cachedir', False) is True:
|
||||
salt.utils.cloud.delete_minion_cachedir(
|
||||
__utils__['cloud.delete_minion_cachedir'](
|
||||
name,
|
||||
__active_provider_name__.split(':')[0],
|
||||
__opts__
|
||||
@ -1373,7 +1457,7 @@ def image_persistent(call=None, kwargs=None):
|
||||
|
||||
server, user, password = _get_xml_rpc()
|
||||
auth = ':'.join([user, password])
|
||||
response = server.one.image.persistent(auth, int(image_id), is_true(persist))
|
||||
response = server.one.image.persistent(auth, int(image_id), salt.utils.is_true(persist))
|
||||
|
||||
data = {
|
||||
'action': 'image.persistent',
|
||||
@ -1720,7 +1804,7 @@ def show_instance(name, call=None):
|
||||
)
|
||||
|
||||
node = _get_node(name)
|
||||
salt.utils.cloud.cache_node(node, __active_provider_name__, __opts__)
|
||||
__utils__['cloud.cache_node'](node, __active_provider_name__, __opts__)
|
||||
|
||||
return node
|
||||
|
||||
@ -2586,7 +2670,7 @@ def vm_allocate(call=None, kwargs=None):
|
||||
|
||||
server, user, password = _get_xml_rpc()
|
||||
auth = ':'.join([user, password])
|
||||
response = server.one.vm.allocate(auth, data, is_true(hold))
|
||||
response = server.one.vm.allocate(auth, data, salt.utils.is_true(hold))
|
||||
|
||||
ret = {
|
||||
'action': 'vm.allocate',
|
||||
@ -2816,7 +2900,7 @@ def vm_deploy(name, kwargs=None, call=None):
|
||||
response = server.one.vm.deploy(auth,
|
||||
int(vm_id),
|
||||
int(host_id),
|
||||
is_true(capacity_maintained),
|
||||
salt.utils.is_true(capacity_maintained),
|
||||
int(datastore_id))
|
||||
|
||||
data = {
|
||||
@ -3285,8 +3369,8 @@ def vm_migrate(name, kwargs=None, call=None):
|
||||
response = server.one.vm.migrate(auth,
|
||||
vm_id,
|
||||
int(host_id),
|
||||
is_true(live_migration),
|
||||
is_true(capacity_maintained),
|
||||
salt.utils.is_true(live_migration),
|
||||
salt.utils.is_true(capacity_maintained),
|
||||
int(datastore_id))
|
||||
|
||||
data = {
|
||||
@ -3404,7 +3488,7 @@ def vm_resize(name, kwargs=None, call=None):
|
||||
server, user, password = _get_xml_rpc()
|
||||
auth = ':'.join([user, password])
|
||||
vm_id = int(get_vm_id(kwargs={'name': name}))
|
||||
response = server.one.vm.resize(auth, vm_id, data, is_true(capacity_maintained))
|
||||
response = server.one.vm.resize(auth, vm_id, data, salt.utils.is_true(capacity_maintained))
|
||||
|
||||
ret = {
|
||||
'action': 'vm.resize',
|
||||
@ -4336,8 +4420,7 @@ def _list_nodes(full=False):
|
||||
for nic in vm.find('TEMPLATE').findall('NIC'):
|
||||
try:
|
||||
private_ips.append(nic.find('IP').text)
|
||||
except AttributeError:
|
||||
# There is no private IP; skip it
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
vms[name]['id'] = vm.find('ID').text
|
||||
|
@ -1490,7 +1490,6 @@ def os_data():
|
||||
osrelease_info[idx] = int(value)
|
||||
grains['osrelease_info'] = tuple(osrelease_info)
|
||||
grains['osmajorrelease'] = str(grains['osrelease_info'][0]) # This will be an integer in the two releases
|
||||
salt.utils.warn_until('Nitrogen', 'The "osmajorrelease" will be a type of an integer.')
|
||||
os_name = grains['os' if grains.get('os') in (
|
||||
'FreeBSD', 'OpenBSD', 'NetBSD', 'Mac', 'Raspbian') else 'osfullname']
|
||||
grains['osfinger'] = '{0}-{1}'.format(
|
||||
|
@ -1941,7 +1941,6 @@ class Minion(MinionBase):
|
||||
log.debug('Forwarding salt error event tag={tag}'.format(tag=tag))
|
||||
self._fire_master(data, tag)
|
||||
elif package.startswith('salt/auth/creds'):
|
||||
tag, data = salt.utils.event.MinionEvent.unpack(package)
|
||||
key = tuple(data['key'])
|
||||
log.debug('Updating auth data for {0}: {1} -> {2}'.format(
|
||||
key, salt.crypt.AsyncAuth.creds_map.get(key), data['creds']))
|
||||
|
@ -303,6 +303,22 @@ def _run(cmd,
|
||||
'Setting value to an empty string'.format(bad_env_key))
|
||||
env[bad_env_key] = ''
|
||||
|
||||
if _check_loglevel(output_loglevel) is not None:
|
||||
# Always log the shell commands at INFO unless quiet logging is
|
||||
# requested. The command output is what will be controlled by the
|
||||
# 'loglevel' parameter.
|
||||
msg = (
|
||||
'Executing command {0}{1}{0} {2}in directory \'{3}\'{4}'.format(
|
||||
'\'' if not isinstance(cmd, list) else '',
|
||||
cmd,
|
||||
'as user \'{0}\' '.format(runas) if runas else '',
|
||||
cwd,
|
||||
'. Executing command in the background, no output will be '
|
||||
'logged.' if bg else ''
|
||||
)
|
||||
)
|
||||
log.info(log_callback(msg))
|
||||
|
||||
if runas and salt.utils.is_windows():
|
||||
if not password:
|
||||
msg = 'password is a required argument for runas on Windows'
|
||||
@ -368,21 +384,6 @@ def _run(cmd,
|
||||
)
|
||||
)
|
||||
|
||||
if _check_loglevel(output_loglevel) is not None:
|
||||
# Always log the shell commands at INFO unless quiet logging is
|
||||
# requested. The command output is what will be controlled by the
|
||||
# 'loglevel' parameter.
|
||||
msg = (
|
||||
'Executing command {0}{1}{0} {2}in directory \'{3}\'{4}'.format(
|
||||
'\'' if not isinstance(cmd, list) else '',
|
||||
cmd,
|
||||
'as user \'{0}\' '.format(runas) if runas else '',
|
||||
cwd,
|
||||
' in the background, no output will be logged' if bg else ''
|
||||
)
|
||||
)
|
||||
log.info(log_callback(msg))
|
||||
|
||||
if reset_system_locale is True:
|
||||
if not salt.utils.is_windows():
|
||||
# Default to C!
|
||||
@ -680,6 +681,7 @@ def run(cmd,
|
||||
saltenv='base',
|
||||
use_vt=False,
|
||||
bg=False,
|
||||
password=None,
|
||||
**kwargs):
|
||||
r'''
|
||||
Execute the passed command and return the output as a string
|
||||
@ -699,8 +701,8 @@ def run(cmd,
|
||||
:param str runas: User to run script as. If running on a Windows minion you
|
||||
must also pass a password
|
||||
|
||||
:param str password: Windows only. Pass a password if you specify runas.
|
||||
This parameter will be ignored for other OS's
|
||||
:param str password: Windows only. Required when specifying ``runas``. This
|
||||
parameter will be ignored on non-Windows platforms.
|
||||
|
||||
.. versionadded:: 2016.3.0
|
||||
|
||||
@ -848,7 +850,7 @@ def run(cmd,
|
||||
pillarenv=kwargs.get('pillarenv'),
|
||||
pillar_override=kwargs.get('pillar'),
|
||||
use_vt=use_vt,
|
||||
password=kwargs.get('password', None),
|
||||
password=password,
|
||||
bg=bg)
|
||||
|
||||
log_callback = _check_cb(log_callback)
|
||||
@ -888,6 +890,7 @@ def shell(cmd,
|
||||
saltenv='base',
|
||||
use_vt=False,
|
||||
bg=False,
|
||||
password=None,
|
||||
**kwargs):
|
||||
'''
|
||||
Execute the passed command and return the output as a string.
|
||||
@ -906,15 +909,16 @@ def shell(cmd,
|
||||
:param str runas: User to run script as. If running on a Windows minion you
|
||||
must also pass a password
|
||||
|
||||
:param str password: Windows only. Pass a password if you specify runas.
|
||||
This parameter will be ignored for other OS's
|
||||
:param str password: Windows only. Required when specifying ``runas``. This
|
||||
parameter will be ignored on non-Windows platforms.
|
||||
|
||||
.. versionadded:: 2016.3.0
|
||||
|
||||
:param int shell: Shell to execute under. Defaults to the system default
|
||||
shell.
|
||||
|
||||
:param bool bg: If True, run command in background and do not await or deliver it's results
|
||||
:param bool bg: If True, run command in background and do not await or
|
||||
deliver its results
|
||||
|
||||
:param list env: A list of environment variables to be set prior to
|
||||
execution.
|
||||
@ -1053,6 +1057,7 @@ def shell(cmd,
|
||||
use_vt=use_vt,
|
||||
python_shell=python_shell,
|
||||
bg=bg,
|
||||
password=password,
|
||||
**kwargs)
|
||||
|
||||
|
||||
@ -1074,6 +1079,7 @@ def run_stdout(cmd,
|
||||
ignore_retcode=False,
|
||||
saltenv='base',
|
||||
use_vt=False,
|
||||
password=None,
|
||||
**kwargs):
|
||||
'''
|
||||
Execute a command, and only return the standard out
|
||||
@ -1090,8 +1096,8 @@ def run_stdout(cmd,
|
||||
:param str runas: User to run script as. If running on a Windows minion you
|
||||
must also pass a password
|
||||
|
||||
:param str password: Windows only. Pass a password if you specify runas.
|
||||
This parameter will be ignored for other OS's
|
||||
:param str password: Windows only. Required when specifying ``runas``. This
|
||||
parameter will be ignored on non-Windows platforms.
|
||||
|
||||
.. versionadded:: 2016.3.0
|
||||
|
||||
@ -1212,6 +1218,7 @@ def run_stdout(cmd,
|
||||
pillarenv=kwargs.get('pillarenv'),
|
||||
pillar_override=kwargs.get('pillar'),
|
||||
use_vt=use_vt,
|
||||
password=password,
|
||||
**kwargs)
|
||||
|
||||
log_callback = _check_cb(log_callback)
|
||||
@ -1255,6 +1262,7 @@ def run_stderr(cmd,
|
||||
ignore_retcode=False,
|
||||
saltenv='base',
|
||||
use_vt=False,
|
||||
password=None,
|
||||
**kwargs):
|
||||
'''
|
||||
Execute a command and only return the standard error
|
||||
@ -1271,8 +1279,8 @@ def run_stderr(cmd,
|
||||
:param str runas: User to run script as. If running on a Windows minion you
|
||||
must also pass a password
|
||||
|
||||
:param str password: Windows only. Pass a password if you specify runas.
|
||||
This parameter will be ignored for other OS's
|
||||
:param str password: Windows only. Required when specifying ``runas``. This
|
||||
parameter will be ignored on non-Windows platforms.
|
||||
|
||||
.. versionadded:: 2016.3.0
|
||||
|
||||
@ -1394,7 +1402,7 @@ def run_stderr(cmd,
|
||||
saltenv=saltenv,
|
||||
pillarenv=kwargs.get('pillarenv'),
|
||||
pillar_override=kwargs.get('pillar'),
|
||||
password=kwargs.get('password', None))
|
||||
password=password)
|
||||
|
||||
log_callback = _check_cb(log_callback)
|
||||
|
||||
@ -1438,6 +1446,7 @@ def run_all(cmd,
|
||||
saltenv='base',
|
||||
use_vt=False,
|
||||
redirect_stderr=False,
|
||||
password=None,
|
||||
**kwargs):
|
||||
'''
|
||||
Execute the passed command and return a dict of return data
|
||||
@ -1454,8 +1463,8 @@ def run_all(cmd,
|
||||
:param str runas: User to run script as. If running on a Windows minion you
|
||||
must also pass a password
|
||||
|
||||
:param str password: Windows only. Pass a password if you specify runas.
|
||||
This parameter will be ignored for other OS's
|
||||
:param str password: Windows only. Required when specifying ``runas``. This
|
||||
parameter will be ignored on non-Windows platforms.
|
||||
|
||||
.. versionadded:: 2016.3.0
|
||||
|
||||
@ -1587,7 +1596,7 @@ def run_all(cmd,
|
||||
pillarenv=kwargs.get('pillarenv'),
|
||||
pillar_override=kwargs.get('pillar'),
|
||||
use_vt=use_vt,
|
||||
password=kwargs.get('password', None))
|
||||
password=password)
|
||||
|
||||
log_callback = _check_cb(log_callback)
|
||||
|
||||
@ -1629,6 +1638,7 @@ def retcode(cmd,
|
||||
ignore_retcode=False,
|
||||
saltenv='base',
|
||||
use_vt=False,
|
||||
password=None,
|
||||
**kwargs):
|
||||
'''
|
||||
Execute a shell command and return the command's return code.
|
||||
@ -1645,8 +1655,8 @@ def retcode(cmd,
|
||||
:param str runas: User to run script as. If running on a Windows minion you
|
||||
must also pass a password
|
||||
|
||||
:param str password: Windows only. Pass a password if you specify runas.
|
||||
This parameter will be ignored for other OS's
|
||||
:param str password: Windows only. Required when specifying ``runas``. This
|
||||
parameter will be ignored on non-Windows platforms.
|
||||
|
||||
.. versionadded:: 2016.3.0
|
||||
|
||||
@ -1770,7 +1780,7 @@ def retcode(cmd,
|
||||
pillarenv=kwargs.get('pillarenv'),
|
||||
pillar_override=kwargs.get('pillar'),
|
||||
use_vt=use_vt,
|
||||
password=kwargs.get('password', None))
|
||||
password=password)
|
||||
|
||||
log_callback = _check_cb(log_callback)
|
||||
|
||||
@ -1807,6 +1817,7 @@ def _retcode_quiet(cmd,
|
||||
ignore_retcode=False,
|
||||
saltenv='base',
|
||||
use_vt=False,
|
||||
password=None,
|
||||
**kwargs):
|
||||
'''
|
||||
Helper for running commands quietly for minion startup.
|
||||
@ -1829,6 +1840,7 @@ def _retcode_quiet(cmd,
|
||||
ignore_retcode=ignore_retcode,
|
||||
saltenv=saltenv,
|
||||
use_vt=use_vt,
|
||||
password=password,
|
||||
**kwargs)
|
||||
|
||||
|
||||
@ -1851,6 +1863,7 @@ def script(source,
|
||||
saltenv='base',
|
||||
use_vt=False,
|
||||
bg=False,
|
||||
password=None,
|
||||
**kwargs):
|
||||
'''
|
||||
Download a script from a remote location and execute the script locally.
|
||||
@ -1879,8 +1892,8 @@ def script(source,
|
||||
:param str runas: User to run script as. If running on a Windows minion you
|
||||
must also pass a password
|
||||
|
||||
:param str password: Windows only. Pass a password if you specify runas.
|
||||
This parameter will be ignored for other OS's
|
||||
:param str password: Windows only. Required when specifying ``runas``. This
|
||||
parameter will be ignored on non-Windows platforms.
|
||||
|
||||
.. versionadded:: 2016.3.0
|
||||
|
||||
@ -2038,8 +2051,8 @@ def script(source,
|
||||
pillarenv=kwargs.get('pillarenv'),
|
||||
pillar_override=kwargs.get('pillar'),
|
||||
use_vt=use_vt,
|
||||
password=kwargs.get('password', None),
|
||||
bg=bg)
|
||||
bg=bg,
|
||||
password=password)
|
||||
_cleanup_tempfile(path)
|
||||
return ret
|
||||
|
||||
@ -2061,6 +2074,7 @@ def script_retcode(source,
|
||||
output_loglevel='debug',
|
||||
log_callback=None,
|
||||
use_vt=False,
|
||||
password=None,
|
||||
**kwargs):
|
||||
'''
|
||||
Download a script from a remote location and execute the script locally.
|
||||
@ -2093,8 +2107,8 @@ def script_retcode(source,
|
||||
:param str runas: User to run script as. If running on a Windows minion you
|
||||
must also pass a password
|
||||
|
||||
:param str password: Windows only. Pass a password if you specify runas.
|
||||
This parameter will be ignored for other OS's
|
||||
:param str password: Windows only. Required when specifying ``runas``. This
|
||||
parameter will be ignored on non-Windows platforms.
|
||||
|
||||
.. versionadded:: 2016.3.0
|
||||
|
||||
@ -2201,6 +2215,7 @@ def script_retcode(source,
|
||||
output_loglevel=output_loglevel,
|
||||
log_callback=log_callback,
|
||||
use_vt=use_vt,
|
||||
password=password,
|
||||
**kwargs)['retcode']
|
||||
|
||||
|
||||
@ -2348,10 +2363,10 @@ def run_chroot(root,
|
||||
This function runs :mod:`cmd.run_all <salt.modules.cmdmod.run_all>` wrapped
|
||||
within a chroot, with dev and proc mounted in the chroot
|
||||
|
||||
root:
|
||||
root
|
||||
Path to the root of the jail to use.
|
||||
|
||||
cmd:
|
||||
cmd
|
||||
The command to run. ex: 'ls -lart /home'
|
||||
|
||||
cwd
|
||||
@ -2586,6 +2601,7 @@ def powershell(cmd,
|
||||
ignore_retcode=False,
|
||||
saltenv='base',
|
||||
use_vt=False,
|
||||
password=None,
|
||||
**kwargs):
|
||||
'''
|
||||
Execute the passed PowerShell command and return the output as a string.
|
||||
@ -2613,8 +2629,8 @@ def powershell(cmd,
|
||||
:param str runas: User to run script as. If running on a Windows minion you
|
||||
must also pass a password
|
||||
|
||||
:param str password: Windows only. Pass a password if you specify runas.
|
||||
This parameter will be ignored for other OS's
|
||||
:param str password: Windows only. Required when specifying ``runas``. This
|
||||
parameter will be ignored on non-Windows platforms.
|
||||
|
||||
.. versionadded:: 2016.3.0
|
||||
|
||||
@ -2727,6 +2743,7 @@ def powershell(cmd,
|
||||
saltenv=saltenv,
|
||||
use_vt=use_vt,
|
||||
python_shell=python_shell,
|
||||
password=password,
|
||||
**kwargs)
|
||||
|
||||
try:
|
||||
@ -2749,7 +2766,9 @@ def run_bg(cmd,
|
||||
output_loglevel='debug',
|
||||
log_callback=None,
|
||||
reset_system_locale=True,
|
||||
ignore_retcode=False,
|
||||
saltenv='base',
|
||||
password=None,
|
||||
**kwargs):
|
||||
r'''
|
||||
.. versionadded: 2016.3.0
|
||||
@ -2771,6 +2790,11 @@ def run_bg(cmd,
|
||||
:param str runas: User to run script as. If running on a Windows minion you
|
||||
must also pass a password
|
||||
|
||||
:param str password: Windows only. Required when specifying ``runas``. This
|
||||
parameter will be ignored on non-Windows platforms.
|
||||
|
||||
.. versionadded:: 2016.3.0
|
||||
|
||||
:param str shell: Shell to execute under. Defaults to the system default
|
||||
shell.
|
||||
|
||||
@ -2896,12 +2920,11 @@ def run_bg(cmd,
|
||||
log_callback=log_callback,
|
||||
timeout=timeout,
|
||||
reset_system_locale=reset_system_locale,
|
||||
# ignore_retcode=ignore_retcode,
|
||||
ignore_retcode=ignore_retcode,
|
||||
saltenv=saltenv,
|
||||
pillarenv=kwargs.get('pillarenv'),
|
||||
pillar_override=kwargs.get('pillar'),
|
||||
# password=kwargs.get('password', None),
|
||||
)
|
||||
password=password)
|
||||
|
||||
return {
|
||||
'pid': res['pid']
|
||||
|
@ -609,11 +609,10 @@ def agent_join(consul_url=None, address=None, **kwargs):
|
||||
query_params=query_params)
|
||||
if res['res']:
|
||||
ret['res'] = True
|
||||
ret['message'] = ('Agent maintenance mode '
|
||||
'{0}ed.'.format(kwargs['enable']))
|
||||
ret['message'] = 'Agent joined the cluster'
|
||||
else:
|
||||
ret['res'] = False
|
||||
ret['message'] = 'Unable to change maintenance mode for agent.'
|
||||
ret['message'] = 'Unable to join the cluster.'
|
||||
return ret
|
||||
|
||||
|
||||
|
@ -793,7 +793,7 @@ def push(path, keep_symlinks=False, upload_path=None, remove_source=False):
|
||||
load_path_normal = os.path.normpath(load_path)
|
||||
|
||||
# If this is Windows and a drive letter is present, remove it
|
||||
load_path_split_drive = os.path.splitdrive(load_path_normal)[1:]
|
||||
load_path_split_drive = os.path.splitdrive(load_path_normal)[1]
|
||||
|
||||
# Finally, split the remaining path into a list for delivery to the master
|
||||
load_path_list = os.path.split(load_path_split_drive)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -41,8 +41,11 @@ def _check_systemd_salt_config():
|
||||
sysctl_dir = os.path.split(conf)[0]
|
||||
if not os.path.exists(sysctl_dir):
|
||||
os.makedirs(sysctl_dir)
|
||||
with salt.utils.fopen(conf, 'w'):
|
||||
pass
|
||||
try:
|
||||
salt.utils.fopen(conf, 'w').close()
|
||||
except (IOError, OSError):
|
||||
msg = 'Could not create file: {0}'
|
||||
raise CommandExecutionError(msg.format(conf))
|
||||
return conf
|
||||
|
||||
|
||||
|
@ -12,7 +12,6 @@ A module to manage software on Windows
|
||||
|
||||
# Import python libs
|
||||
from __future__ import absolute_import
|
||||
import errno
|
||||
import os
|
||||
import locale
|
||||
import logging
|
||||
@ -28,7 +27,7 @@ except ImportError:
|
||||
# pylint: enable=import-error
|
||||
|
||||
# Import salt libs
|
||||
from salt.exceptions import CommandExecutionError, SaltRenderError
|
||||
from salt.exceptions import SaltRenderError
|
||||
import salt.utils
|
||||
import salt.syspaths
|
||||
from salt.exceptions import MinionError
|
||||
@ -721,9 +720,14 @@ def install(name=None, refresh=False, pkgs=None, saltenv='base', **kwargs):
|
||||
start_in=cache_path,
|
||||
trigger_type='Once',
|
||||
start_date='1975-01-01',
|
||||
start_time='01:00')
|
||||
start_time='01:00',
|
||||
ac_only=False,
|
||||
stop_if_on_batteries=False)
|
||||
# Run Scheduled Task
|
||||
__salt__['task.run_wait'](name='update-salt-software')
|
||||
if not __salt__['task.run_wait'](name='update-salt-software'):
|
||||
log.error('Failed to install {0}'.format(pkg_name))
|
||||
log.error('Scheduled Task failed to run')
|
||||
ret[pkg_name] = {'install status': 'failed'}
|
||||
else:
|
||||
# Build the install command
|
||||
cmd = []
|
||||
@ -957,9 +961,14 @@ def remove(name=None, pkgs=None, version=None, **kwargs):
|
||||
start_in=cache_path,
|
||||
trigger_type='Once',
|
||||
start_date='1975-01-01',
|
||||
start_time='01:00')
|
||||
start_time='01:00',
|
||||
ac_only=False,
|
||||
stop_if_on_batteries=False)
|
||||
# Run Scheduled Task
|
||||
__salt__['task.run_wait'](name='update-salt-software')
|
||||
if not __salt__['task.run_wait'](name='update-salt-software'):
|
||||
log.error('Failed to remove {0}'.format(target))
|
||||
log.error('Scheduled Task failed to run')
|
||||
ret[target] = {'uninstall status': 'failed'}
|
||||
else:
|
||||
# Build the install command
|
||||
cmd = []
|
||||
@ -1051,6 +1060,9 @@ def get_repo_data(saltenv='base'):
|
||||
# return __context__['winrepo.data']
|
||||
repocache_dir = _get_local_repo_dir(saltenv=saltenv)
|
||||
winrepo = 'winrepo.p'
|
||||
if not os.path.exists(os.path.join(repocache_dir, winrepo)):
|
||||
log.debug('No winrepo.p cache file. Refresh pkg db now.')
|
||||
refresh_db(saltenv=saltenv)
|
||||
try:
|
||||
with salt.utils.fopen(
|
||||
os.path.join(repocache_dir, winrepo), 'rb') as repofile:
|
||||
@ -1061,12 +1073,6 @@ def get_repo_data(saltenv='base'):
|
||||
log.exception(exc)
|
||||
return {}
|
||||
except IOError as exc:
|
||||
if exc.errno == errno.ENOENT:
|
||||
# File doesn't exist
|
||||
raise CommandExecutionError(
|
||||
'Windows repo cache doesn\'t exist, pkg.refresh_db likely '
|
||||
'needed'
|
||||
)
|
||||
log.error('Not able to read repo file')
|
||||
log.exception(exc)
|
||||
return {}
|
||||
|
@ -125,7 +125,8 @@ Authentication
|
||||
Authentication is performed by passing a session token with each request.
|
||||
Tokens are generated via the :py:class:`Login` URL.
|
||||
|
||||
The token may be sent in one of two ways:
|
||||
The token may be sent in one of two ways: as a custom header or as a session
|
||||
cookie. The latter is far more convenient for clients that support cookies.
|
||||
|
||||
* Include a custom header named :mailheader:`X-Auth-Token`.
|
||||
|
||||
@ -178,54 +179,204 @@ The token may be sent in one of two ways:
|
||||
Usage
|
||||
-----
|
||||
|
||||
Commands are sent to a running Salt master via this module by sending HTTP
|
||||
requests to the URLs detailed below.
|
||||
This interface directly exposes Salt's :ref:`Python API <python-api>`.
|
||||
Everything possible at the CLI is possible through the Python API. Commands are
|
||||
executed on the Salt Master.
|
||||
|
||||
.. admonition:: Content negotiation
|
||||
The root URL (``/``) is RPC-like in that it accepts instructions in the request
|
||||
body for what Salt functions to execute, and the response contains the result
|
||||
of those function calls.
|
||||
|
||||
This REST interface is flexible in what data formats it will accept as well
|
||||
as what formats it will return (e.g., JSON, YAML, x-www-form-urlencoded).
|
||||
For example:
|
||||
|
||||
* Specify the format of data in the request body by including the
|
||||
:mailheader:`Content-Type` header.
|
||||
* Specify the desired data format for the response body with the
|
||||
:mailheader:`Accept` header.
|
||||
.. code-block:: text
|
||||
|
||||
Data sent in :http:method:`post` and :http:method:`put` requests must be in
|
||||
the format of a list of lowstate dictionaries. This allows multiple commands to
|
||||
be executed in a single HTTP request. The order of commands in the request
|
||||
corresponds to the return for each command in the response.
|
||||
|
||||
Lowstate, broadly, is a dictionary of values that are mapped to a function
|
||||
call. This pattern is used pervasively throughout Salt. The functions called
|
||||
from netapi modules are described in :ref:`Client Interfaces <netapi-clients>`.
|
||||
|
||||
The following example (in JSON format) causes Salt to execute two commands, a
|
||||
command sent to minions as well as a runner function on the master::
|
||||
|
||||
[{
|
||||
% curl -sSi https://localhost:8000 \
|
||||
-H 'Content-type: application/json' \
|
||||
-d '[{
|
||||
"client": "local",
|
||||
"tgt": "*",
|
||||
"fun": "test.fib",
|
||||
"arg": ["10"]
|
||||
"fun": "test.ping"
|
||||
}]'
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: application/json
|
||||
[...snip...]
|
||||
|
||||
{"return": [{"jerry": true}]}
|
||||
|
||||
The request body must be an array of commands. Use this workflow to build a
|
||||
command:
|
||||
|
||||
1. Choose a client interface.
|
||||
2. Choose a function.
|
||||
3. Fill out the remaining parameters needed for the chosen client.
|
||||
|
||||
The ``client`` field is a reference to the main Python classes used in Salt's
|
||||
Python API. Read the full :ref:`client interfaces <netapi-clients>`
|
||||
documentation, but in short:
|
||||
|
||||
* "local" uses :py:class:`LocalClient <salt.client.LocalClient>` which sends
|
||||
commands to Minions. Equivalent to the ``salt`` CLI command.
|
||||
* "runner" uses :py:class:`RunnerClient <salt.runner.RunnerClient>` which
|
||||
invokes runner modules on the Master. Equivalent to the ``salt-run`` CLI
|
||||
command.
|
||||
* "wheel" uses :py:class:`WheelClient <salt.wheel.WheelClient>` which invokes
|
||||
wheel modules on the Master. Wheel modules do not have a direct CLI
|
||||
equivalent but they typically manage Master-side resources such as state
|
||||
files, pillar files, the Salt config files, and the :py:mod:`key wheel module
|
||||
<salt.wheel.key>` exposes similar functionality as the ``salt-key`` CLI
|
||||
command.
|
||||
|
||||
Most clients have variants like synchronous or asyncronous execution as well as
|
||||
others like batch execution. See the :ref:`full list of client interfaces
|
||||
<netapi-clients>`.
|
||||
|
||||
Each client requires different arguments and sometimes has different syntax.
|
||||
For example, ``LocalClient`` requires the ``tgt`` argument because it forwards
|
||||
the command to Minions and the other client interfaces do not. ``LocalClient``
|
||||
also takes ``arg`` (array) and ``kwarg`` (dictionary) arguments because these
|
||||
values are sent to the Minions and used to execute the requested function
|
||||
there. ``RunnerClient`` and ``WheelClient`` are executed directly on the Master
|
||||
and thus do not need or accept those arguments.
|
||||
|
||||
Read the method signatures in the client documentation linked above, but
|
||||
hopefully an example will help illustrate the concept. This example causes Salt
|
||||
to execute two functions -- the :py:func:`test.arg execution function
|
||||
<salt.modules.test.arg>` using ``LocalClient`` and the :py:func:`test.arg
|
||||
runner function <salt.runners.test.arg>` using ``RunnerClient``; note the
|
||||
different structure for each command. The results for both are combined and
|
||||
returned as one response.
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
% curl -b ~/cookies.txt -sSi localhost:8000 \
|
||||
-H 'Content-type: application/json' \
|
||||
-d '
|
||||
[
|
||||
{
|
||||
"client": "local",
|
||||
"tgt": "*",
|
||||
"fun": "test.arg",
|
||||
"arg": ["positional arg one", "positional arg two"],
|
||||
"kwarg": {
|
||||
"keyword arg one": "Hello from a minion",
|
||||
"keyword arg two": "Hello again from a minion"
|
||||
}
|
||||
},
|
||||
{
|
||||
"client": "runner",
|
||||
"fun": "jobs.lookup_jid",
|
||||
"jid": "20130603122505459265"
|
||||
}]
|
||||
"fun": "test.arg",
|
||||
"keyword arg one": "Hello from a master",
|
||||
"keyword arg two": "Runners do not support positional args"
|
||||
}
|
||||
]
|
||||
'
|
||||
HTTP/1.1 200 OK
|
||||
[...snip...]
|
||||
{
|
||||
"return": [
|
||||
{
|
||||
"jerry": {
|
||||
"args": [
|
||||
"positional arg one",
|
||||
"positional arg two"
|
||||
],
|
||||
"kwargs": {
|
||||
"keyword arg one": "Hello from a minion",
|
||||
"keyword arg two": "Hello again from a minion",
|
||||
[...snip...]
|
||||
}
|
||||
},
|
||||
[...snip; other minion returns here...]
|
||||
},
|
||||
{
|
||||
"args": [],
|
||||
"kwargs": {
|
||||
"keyword arg two": "Runners do not support positional args",
|
||||
"keyword arg one": "Hello from a master"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
.. admonition:: x-www-form-urlencoded
|
||||
One more example, this time with more commonly used functions:
|
||||
|
||||
Sending JSON or YAML in the request body is simple and most flexible,
|
||||
however sending data in urlencoded format is also supported with the
|
||||
caveats below. It is the default format for HTML forms, many JavaScript
|
||||
libraries, and the :command:`curl` command.
|
||||
.. code-block:: text
|
||||
|
||||
For example, the equivalent to running ``salt '*' test.ping`` is sending
|
||||
``fun=test.ping&arg&client=local&tgt=*`` in the HTTP request body.
|
||||
curl -b /tmp/cookies.txt -sSi localhost:8000 \
|
||||
-H 'Content-type: application/json' \
|
||||
-d '
|
||||
[
|
||||
{
|
||||
"client": "local",
|
||||
"tgt": "*",
|
||||
"fun": "state.sls",
|
||||
"kwarg": {
|
||||
"mods": "apache",
|
||||
"pillar": {
|
||||
"lookup": {
|
||||
"wwwdir": "/srv/httpd/htdocs"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"client": "runner",
|
||||
"fun": "cloud.create",
|
||||
"provider": "my-ec2-provider",
|
||||
"instances": "my-centos-6",
|
||||
"image": "ami-1624987f",
|
||||
"delvol_on_destroy", true
|
||||
}
|
||||
]
|
||||
'
|
||||
HTTP/1.1 200 OK
|
||||
[...snip...]
|
||||
{
|
||||
"return": [
|
||||
{
|
||||
"jerry": {
|
||||
"pkg_|-install_apache_|-httpd_|-installed": {
|
||||
[...snip full state return here...]
|
||||
}
|
||||
}
|
||||
[...snip other minion returns here...]
|
||||
},
|
||||
{
|
||||
[...snip full salt-cloud output here...]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Caveats:
|
||||
Content negotiation
|
||||
-------------------
|
||||
|
||||
This REST interface is flexible in what data formats it will accept as well
|
||||
as what formats it will return (e.g., JSON, YAML, urlencoded).
|
||||
|
||||
* Specify the format of data in the request body by including the
|
||||
:mailheader:`Content-Type` header.
|
||||
* Specify the desired data format for the response body with the
|
||||
:mailheader:`Accept` header.
|
||||
|
||||
We recommend the JSON format for most HTTP requests. urlencoded data is simple
|
||||
and cannot express complex data structures -- and that is often required for
|
||||
some Salt commands, such as starting a state run that uses Pillar data. Salt's
|
||||
CLI tool can reformat strings passed in at the CLI into complex data
|
||||
structures, and that behavior also works via salt-api, but that can be brittle
|
||||
and since salt-api can accept JSON it is best just to send JSON.
|
||||
|
||||
Here is an example of sending urlencoded data:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
curl -sSik https://localhost:8000 \\
|
||||
-b ~/cookies.txt \\
|
||||
-d client=runner \\
|
||||
-d fun='jobs.lookup_jid' \\
|
||||
-d jid='20150129182456704682'
|
||||
|
||||
.. admonition:: urlencoded data caveats
|
||||
|
||||
* Only a single command may be sent per HTTP request.
|
||||
* Repeating the ``arg`` parameter multiple times will cause those
|
||||
@ -233,9 +384,23 @@ command sent to minions as well as a runner function on the master::
|
||||
|
||||
Note, some popular frameworks and languages (notably jQuery, PHP, and
|
||||
Ruby on Rails) will automatically append empty brackets onto repeated
|
||||
parameters. E.g., ``arg=one``, ``arg=two`` will be sent as ``arg[]=one``,
|
||||
``arg[]=two``. This is not supported; send JSON or YAML instead.
|
||||
query string parameters. E.g., ``?foo[]=fooone&foo[]=footwo``. This is
|
||||
**not** supported; send ``?foo=fooone&foo=footwo`` instead, or send JSON
|
||||
or YAML.
|
||||
|
||||
A note about ``curl``
|
||||
|
||||
The ``-d`` flag to curl does *not* automatically urlencode data which can
|
||||
affect passwords and other data that contains characters that must be
|
||||
encoded. Use the ``--data-urlencode`` flag instead. E.g.:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
curl -ksi http://localhost:8000/login \\
|
||||
-H "Accept: application/json" \\
|
||||
-d username='myapiuser' \\
|
||||
--data-urlencode password='1234+' \\
|
||||
-d eauth='pam'
|
||||
|
||||
.. |req_token| replace:: a session token from :py:class:`~Login`.
|
||||
.. |req_accept| replace:: the desired response format.
|
||||
@ -248,21 +413,6 @@ command sent to minions as well as a runner function on the master::
|
||||
.. |401| replace:: authentication required
|
||||
.. |406| replace:: requested Content-Type not available
|
||||
|
||||
A Note About Curl
|
||||
=================
|
||||
|
||||
When sending passwords and data that might need to be urlencoded, you must set
|
||||
the ``-d`` flag to indicate the content type, and the ``--data-urlencode`` flag
|
||||
to urlencode the input.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
curl -ksi http://localhost:8000/login \\
|
||||
-H "Accept: application/json" \\
|
||||
-d username='myapiuser' \\
|
||||
--data-urlencode password='1234+' \\
|
||||
-d eauth='pam'
|
||||
|
||||
'''
|
||||
# We need a custom pylintrc here...
|
||||
# pylint: disable=W0212,E1101,C0103,R0201,W0221,W0613
|
||||
@ -882,11 +1032,10 @@ class LowDataAdapter(object):
|
||||
.. code-block:: bash
|
||||
|
||||
curl -sSik https://localhost:8000 \\
|
||||
-b ~/cookies.txt \\
|
||||
-H "Accept: application/x-yaml" \\
|
||||
-H "X-Auth-Token: d40d1e1e<...snip...>" \\
|
||||
-d client=local \\
|
||||
-d tgt='*' \\
|
||||
-d fun='test.ping' \\
|
||||
-H "Content-type: application/json" \\
|
||||
-d '[{"client": "local", "tgt": "*", "fun": "test.ping"}]'
|
||||
|
||||
.. code-block:: http
|
||||
|
||||
@ -894,10 +1043,9 @@ class LowDataAdapter(object):
|
||||
Host: localhost:8000
|
||||
Accept: application/x-yaml
|
||||
X-Auth-Token: d40d1e1e
|
||||
Content-Length: 36
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
Content-Type: application/json
|
||||
|
||||
fun=test.ping&client=local&tgt=*
|
||||
[{"client": "local", "tgt": "*", "fun": "test.ping"}]
|
||||
|
||||
**Example response:**
|
||||
|
||||
@ -914,51 +1062,6 @@ class LowDataAdapter(object):
|
||||
ms-2: true
|
||||
ms-3: true
|
||||
ms-4: true
|
||||
|
||||
**Other examples**:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Sending multiple positional args with urlencoded:
|
||||
curl -sSik https://localhost:8000 \\
|
||||
-d client=local \\
|
||||
-d tgt='*' \\
|
||||
-d fun='cmd.run' \\
|
||||
-d arg='du -sh .' \\
|
||||
-d arg='/path/to/dir'
|
||||
|
||||
# Sending positional args and Keyword args with JSON:
|
||||
echo '[
|
||||
{
|
||||
"client": "local",
|
||||
"tgt": "*",
|
||||
"fun": "cmd.run",
|
||||
"arg": [
|
||||
"du -sh .",
|
||||
"/path/to/dir"
|
||||
],
|
||||
"kwarg": {
|
||||
"shell": "/bin/sh",
|
||||
"template": "jinja"
|
||||
}
|
||||
}
|
||||
]' | curl -sSik https://localhost:8000 \\
|
||||
-H 'Content-type: application/json' \\
|
||||
-d@-
|
||||
|
||||
# Calling runner functions:
|
||||
curl -sSik https://localhost:8000 \\
|
||||
-d client=runner \\
|
||||
-d fun='jobs.lookup_jid' \\
|
||||
-d jid='20150129182456704682' \\
|
||||
-d outputter=highstate
|
||||
|
||||
# Calling wheel functions:
|
||||
curl -sSik https://localhost:8000 \\
|
||||
-d client=wheel \\
|
||||
-d fun='key.gen_accept' \\
|
||||
-d id_=dave \\
|
||||
-d keysize=4096
|
||||
'''
|
||||
return {
|
||||
'return': list(self.exec_lowstate(
|
||||
@ -1047,17 +1150,16 @@ class Minions(LowDataAdapter):
|
||||
.. code-block:: bash
|
||||
|
||||
curl -sSi localhost:8000/minions \\
|
||||
-b ~/cookies.txt \\
|
||||
-H "Accept: application/x-yaml" \\
|
||||
-d tgt='*' \\
|
||||
-d fun='status.diskusage'
|
||||
-d '[{"tgt": "*", "fun": "status.diskusage"}]'
|
||||
|
||||
.. code-block:: http
|
||||
|
||||
POST /minions HTTP/1.1
|
||||
Host: localhost:8000
|
||||
Accept: application/x-yaml
|
||||
Content-Length: 26
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
Content-Type: application/json
|
||||
|
||||
tgt=*&fun=status.diskusage
|
||||
|
||||
@ -1473,20 +1575,25 @@ class Login(LowDataAdapter):
|
||||
.. code-block:: bash
|
||||
|
||||
curl -si localhost:8000/login \\
|
||||
-c ~/cookies.txt \\
|
||||
-H "Accept: application/json" \\
|
||||
-d username='saltuser' \\
|
||||
-d password='saltpass' \\
|
||||
-d eauth='pam'
|
||||
-H "Content-type: application/json" \\
|
||||
-d '{
|
||||
"username": "saltuser",
|
||||
"password": "saltuser",
|
||||
"eauth": "auto"
|
||||
}'
|
||||
|
||||
.. code-block:: http
|
||||
|
||||
POST / HTTP/1.1
|
||||
Host: localhost:8000
|
||||
Content-Length: 42
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
Content-Type: application/json
|
||||
Accept: application/json
|
||||
|
||||
username=saltuser&password=saltpass&eauth=pam
|
||||
{"username": "saltuser", "password": "saltuser", "eauth": "auto"}
|
||||
|
||||
|
||||
**Example response:**
|
||||
|
||||
@ -1626,12 +1733,15 @@ class Run(LowDataAdapter):
|
||||
|
||||
curl -sS localhost:8000/run \\
|
||||
-H 'Accept: application/x-yaml' \\
|
||||
-d client='local' \\
|
||||
-d tgt='*' \\
|
||||
-d fun='test.ping' \\
|
||||
-d username='saltdev' \\
|
||||
-d password='saltdev' \\
|
||||
-d eauth='pam'
|
||||
-H 'Content-type: application/json' \\
|
||||
-d '[{
|
||||
"client": "local",
|
||||
"tgt": "*",
|
||||
"fun": "test.ping",
|
||||
"username": "saltdev",
|
||||
"password": "saltdev",
|
||||
"eauth": "auto"
|
||||
}]'
|
||||
|
||||
.. code-block:: http
|
||||
|
||||
@ -1639,9 +1749,9 @@ class Run(LowDataAdapter):
|
||||
Host: localhost:8000
|
||||
Accept: application/x-yaml
|
||||
Content-Length: 75
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
Content-Type: application/json
|
||||
|
||||
client=local&tgt=*&fun=test.ping&username=saltdev&password=saltdev&eauth=pam
|
||||
[{"client": "local", "tgt": "*", "fun": "test.ping", "username": "saltdev", "password": "saltdev", "eauth": "auto"}]
|
||||
|
||||
**Example response:**
|
||||
|
||||
@ -1658,12 +1768,14 @@ class Run(LowDataAdapter):
|
||||
ms-3: true
|
||||
ms-4: true
|
||||
|
||||
The /run enpoint can also be used to issue commands using the salt-ssh subsystem.
|
||||
The /run enpoint can also be used to issue commands using the salt-ssh
|
||||
subsystem.
|
||||
|
||||
When using salt-ssh, eauth credentials should not be supplied. Instad, authentication
|
||||
should be handled by the SSH layer itself. The use of the salt-ssh client does not
|
||||
require a salt master to be running. Instead, only a roster file must be present
|
||||
in the salt configuration directory.
|
||||
When using salt-ssh, eauth credentials should not be supplied. Instad,
|
||||
authentication should be handled by the SSH layer itself. The use of
|
||||
the salt-ssh client does not require a salt master to be running.
|
||||
Instead, only a roster file must be present in the salt configuration
|
||||
directory.
|
||||
|
||||
All SSH client requests are synchronous.
|
||||
|
||||
@ -2176,16 +2288,18 @@ class Webhook(object):
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
curl -sS localhost:8000/hook -d foo='Foo!' -d bar='Bar!'
|
||||
curl -sS localhost:8000/hook \\
|
||||
-H 'Content-type: application/json' \\
|
||||
-d '{"foo": "Foo!", "bar": "Bar!"}'
|
||||
|
||||
.. code-block:: http
|
||||
|
||||
POST /hook HTTP/1.1
|
||||
Host: localhost:8000
|
||||
Content-Length: 16
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
Content-Type: application/json
|
||||
|
||||
foo=Foo&bar=Bar!
|
||||
{"foo": "Foo!", "bar": "Bar!"}
|
||||
|
||||
**Example response**:
|
||||
|
||||
|
115
salt/scripts.py
115
salt/scripts.py
@ -8,7 +8,9 @@ from __future__ import absolute_import, print_function
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import signal
|
||||
import logging
|
||||
import functools
|
||||
import threading
|
||||
import traceback
|
||||
from random import randint
|
||||
@ -38,6 +40,29 @@ def _handle_interrupt(exc, original_exc, hardfail=False, trace=''):
|
||||
raise exc
|
||||
|
||||
|
||||
def _handle_signals(client, signum, sigframe):
|
||||
trace = traceback.format_exc()
|
||||
try:
|
||||
hardcrash = client.options.hard_crash
|
||||
except (AttributeError, KeyError):
|
||||
hardcrash = False
|
||||
_handle_interrupt(
|
||||
SystemExit('\nExiting gracefully on Ctrl-c'),
|
||||
Exception('\nExiting with hard crash Ctrl-c'),
|
||||
hardcrash, trace=trace)
|
||||
|
||||
|
||||
def _install_signal_handlers(client):
|
||||
# Install the SIGINT/SIGTERM handlers if not done so far
|
||||
if signal.getsignal(signal.SIGINT) is signal.SIG_DFL:
|
||||
# No custom signal handling was added, install our own
|
||||
signal.signal(signal.SIGINT, functools.partial(_handle_signals, client))
|
||||
|
||||
if signal.getsignal(signal.SIGTERM) is signal.SIG_DFL:
|
||||
# No custom signal handling was added, install our own
|
||||
signal.signal(signal.SIGINT, functools.partial(_handle_signals, client))
|
||||
|
||||
|
||||
def salt_master():
|
||||
'''
|
||||
Start the salt master.
|
||||
@ -101,7 +126,6 @@ def salt_minion():
|
||||
Auto restart minion on error.
|
||||
'''
|
||||
import signal
|
||||
import functools
|
||||
|
||||
import salt.utils.process
|
||||
salt.utils.process.notify_systemd()
|
||||
@ -298,20 +322,10 @@ def salt_key():
|
||||
Manage the authentication keys with salt-key.
|
||||
'''
|
||||
import salt.cli.key
|
||||
client = None
|
||||
try:
|
||||
client = salt.cli.key.SaltKey()
|
||||
_install_signal_handlers(client)
|
||||
client.run()
|
||||
except KeyboardInterrupt as err:
|
||||
trace = traceback.format_exc()
|
||||
try:
|
||||
hardcrash = client.options.hard_crash
|
||||
except (AttributeError, KeyError):
|
||||
hardcrash = False
|
||||
_handle_interrupt(
|
||||
SystemExit('\nExiting gracefully on Ctrl-c'),
|
||||
err,
|
||||
hardcrash, trace=trace)
|
||||
except Exception as err:
|
||||
sys.stderr.write("Error: {0}\n".format(err.message))
|
||||
|
||||
@ -322,20 +336,9 @@ def salt_cp():
|
||||
master.
|
||||
'''
|
||||
import salt.cli.cp
|
||||
client = None
|
||||
try:
|
||||
client = salt.cli.cp.SaltCPCli()
|
||||
_install_signal_handlers(client)
|
||||
client.run()
|
||||
except KeyboardInterrupt as err:
|
||||
trace = traceback.format_exc()
|
||||
try:
|
||||
hardcrash = client.options.hard_crash
|
||||
except (AttributeError, KeyError):
|
||||
hardcrash = False
|
||||
_handle_interrupt(
|
||||
SystemExit('\nExiting gracefully on Ctrl-c'),
|
||||
err,
|
||||
hardcrash, trace=trace)
|
||||
|
||||
|
||||
def salt_call():
|
||||
@ -346,20 +349,9 @@ def salt_call():
|
||||
import salt.cli.call
|
||||
if '' in sys.path:
|
||||
sys.path.remove('')
|
||||
client = None
|
||||
try:
|
||||
client = salt.cli.call.SaltCall()
|
||||
_install_signal_handlers(client)
|
||||
client.run()
|
||||
except KeyboardInterrupt as err:
|
||||
trace = traceback.format_exc()
|
||||
try:
|
||||
hardcrash = client.options.hard_crash
|
||||
except (AttributeError, KeyError):
|
||||
hardcrash = False
|
||||
_handle_interrupt(
|
||||
SystemExit('\nExiting gracefully on Ctrl-c'),
|
||||
err,
|
||||
hardcrash, trace=trace)
|
||||
|
||||
|
||||
def salt_run():
|
||||
@ -369,20 +361,9 @@ def salt_run():
|
||||
import salt.cli.run
|
||||
if '' in sys.path:
|
||||
sys.path.remove('')
|
||||
client = None
|
||||
try:
|
||||
client = salt.cli.run.SaltRun()
|
||||
_install_signal_handlers(client)
|
||||
client.run()
|
||||
except KeyboardInterrupt as err:
|
||||
trace = traceback.format_exc()
|
||||
try:
|
||||
hardcrash = client.options.hard_crash
|
||||
except (AttributeError, KeyError):
|
||||
hardcrash = False
|
||||
_handle_interrupt(
|
||||
SystemExit('\nExiting gracefully on Ctrl-c'),
|
||||
err,
|
||||
hardcrash, trace=trace)
|
||||
|
||||
|
||||
def salt_ssh():
|
||||
@ -392,20 +373,10 @@ def salt_ssh():
|
||||
import salt.cli.ssh
|
||||
if '' in sys.path:
|
||||
sys.path.remove('')
|
||||
client = None
|
||||
try:
|
||||
client = salt.cli.ssh.SaltSSH()
|
||||
_install_signal_handlers(client)
|
||||
client.run()
|
||||
except KeyboardInterrupt as err:
|
||||
trace = traceback.format_exc()
|
||||
try:
|
||||
hardcrash = client.options.hard_crash
|
||||
except (AttributeError, KeyError):
|
||||
hardcrash = False
|
||||
_handle_interrupt(
|
||||
SystemExit('\nExiting gracefully on Ctrl-c'),
|
||||
err,
|
||||
hardcrash, trace=trace)
|
||||
except SaltClientError as err:
|
||||
trace = traceback.format_exc()
|
||||
try:
|
||||
@ -436,20 +407,9 @@ def salt_cloud():
|
||||
print('salt-cloud is not available in this system')
|
||||
sys.exit(salt.defaults.exitcodes.EX_UNAVAILABLE)
|
||||
|
||||
client = None
|
||||
try:
|
||||
client = salt.cloud.cli.SaltCloud()
|
||||
_install_signal_handlers(client)
|
||||
client.run()
|
||||
except KeyboardInterrupt as err:
|
||||
trace = traceback.format_exc()
|
||||
try:
|
||||
hardcrash = client.options.hard_crash
|
||||
except (AttributeError, KeyError):
|
||||
hardcrash = False
|
||||
_handle_interrupt(
|
||||
SystemExit('\nExiting gracefully on Ctrl-c'),
|
||||
err,
|
||||
hardcrash, trace=trace)
|
||||
|
||||
|
||||
def salt_api():
|
||||
@ -472,20 +432,9 @@ def salt_main():
|
||||
import salt.cli.salt
|
||||
if '' in sys.path:
|
||||
sys.path.remove('')
|
||||
client = None
|
||||
try:
|
||||
client = salt.cli.salt.SaltCMD()
|
||||
_install_signal_handlers(client)
|
||||
client.run()
|
||||
except KeyboardInterrupt as err:
|
||||
trace = traceback.format_exc()
|
||||
try:
|
||||
hardcrash = client.options.hard_crash
|
||||
except (AttributeError, KeyError):
|
||||
hardcrash = False
|
||||
_handle_interrupt(
|
||||
SystemExit('\nExiting gracefully on Ctrl-c'),
|
||||
err,
|
||||
hardcrash, trace=trace)
|
||||
|
||||
|
||||
def salt_spm():
|
||||
|
@ -1809,6 +1809,8 @@ class State(object):
|
||||
tag = _gen_tag(low)
|
||||
if (low.get('failhard', False) or self.opts['failhard']
|
||||
and tag in running):
|
||||
if running[tag]['result'] is None:
|
||||
return False
|
||||
return not running[tag]['result']
|
||||
return False
|
||||
|
||||
|
@ -95,6 +95,7 @@ def extracted(name,
|
||||
if_missing=None,
|
||||
keep=False,
|
||||
trim_output=False,
|
||||
skip_verify=False,
|
||||
source_hash_update=None):
|
||||
'''
|
||||
.. versionadded:: 2014.1.0
|
||||
@ -174,6 +175,13 @@ def extracted(name,
|
||||
|
||||
.. versionadded:: 2016.3.0
|
||||
|
||||
skip_verify:False
|
||||
If ``True``, hash verification of remote file sources (``http://``,
|
||||
``https://``, ``ftp://``) will be skipped, and the ``source_hash``
|
||||
argument will be ignored.
|
||||
|
||||
.. versionadded:: 2016.3.4
|
||||
|
||||
archive_format
|
||||
``tar``, ``zip`` or ``rar``
|
||||
|
||||
@ -324,6 +332,7 @@ def extracted(name,
|
||||
source=source,
|
||||
source_hash=source_hash,
|
||||
makedirs=True,
|
||||
skip_verify=skip_verify,
|
||||
saltenv=__env__)
|
||||
log.debug('file.managed: {0}'.format(file_result))
|
||||
# get value of first key
|
||||
|
@ -487,7 +487,8 @@ def image_present(name,
|
||||
load=None,
|
||||
force=False,
|
||||
insecure_registry=False,
|
||||
client_timeout=CLIENT_TIMEOUT):
|
||||
client_timeout=CLIENT_TIMEOUT,
|
||||
**kwargs):
|
||||
'''
|
||||
Ensure that an image is present. The image can either be pulled from a
|
||||
Docker registry, built from a Dockerfile, or loaded from a saved image.
|
||||
|
@ -105,7 +105,7 @@ def _get_branch_opts(branch, local_branch, all_local_branches,
|
||||
return ret
|
||||
|
||||
|
||||
def _get_local_rev_and_branch(target, user):
|
||||
def _get_local_rev_and_branch(target, user, password):
|
||||
'''
|
||||
Return the local revision for before/after comparisons
|
||||
'''
|
||||
@ -113,6 +113,7 @@ def _get_local_rev_and_branch(target, user):
|
||||
try:
|
||||
local_rev = __salt__['git.revision'](target,
|
||||
user=user,
|
||||
password=password,
|
||||
ignore_retcode=True)
|
||||
except CommandExecutionError:
|
||||
log.info('No local revision for {0}'.format(target))
|
||||
@ -122,6 +123,7 @@ def _get_local_rev_and_branch(target, user):
|
||||
try:
|
||||
local_branch = __salt__['git.current_branch'](target,
|
||||
user=user,
|
||||
password=password,
|
||||
ignore_retcode=True)
|
||||
except CommandExecutionError:
|
||||
log.info('No local branch for {0}'.format(target))
|
||||
@ -205,6 +207,7 @@ def latest(name,
|
||||
target=None,
|
||||
branch=None,
|
||||
user=None,
|
||||
password=None,
|
||||
update_head=True,
|
||||
force_checkout=False,
|
||||
force_clone=False,
|
||||
@ -262,6 +265,12 @@ def latest(name,
|
||||
|
||||
.. versionadded:: 0.17.0
|
||||
|
||||
password
|
||||
Windows only. Required when specifying ``user``. This parameter will be
|
||||
ignored on non-Windows platforms.
|
||||
|
||||
.. versionadded:: 2016.3.4
|
||||
|
||||
update_head : True
|
||||
If set to ``False``, then the remote repository will be fetched (if
|
||||
necessary) to ensure that the commit to which ``rev`` points exists in
|
||||
@ -503,6 +512,8 @@ def latest(name,
|
||||
branch = str(branch)
|
||||
if user is not None and not isinstance(user, six.string_types):
|
||||
user = str(user)
|
||||
if password is not None and not isinstance(password, six.string_types):
|
||||
password = str(password)
|
||||
if remote is not None and not isinstance(remote, six.string_types):
|
||||
remote = str(remote)
|
||||
if identity is not None:
|
||||
@ -564,7 +575,7 @@ def latest(name,
|
||||
return _fail(ret, ('\'rev\' is not compatible with the \'mirror\' and '
|
||||
'\'bare\' arguments'))
|
||||
|
||||
run_check_cmd_kwargs = {'runas': user}
|
||||
run_check_cmd_kwargs = {'runas': user, 'password': password}
|
||||
if 'shell' in __grains__:
|
||||
run_check_cmd_kwargs['shell'] = __grains__['shell']
|
||||
|
||||
@ -588,6 +599,7 @@ def latest(name,
|
||||
heads=False,
|
||||
tags=False,
|
||||
user=user,
|
||||
password=password,
|
||||
identity=identity,
|
||||
https_user=https_user,
|
||||
https_pass=https_pass,
|
||||
@ -682,13 +694,18 @@ def latest(name,
|
||||
check = 'refs' if bare else '.git'
|
||||
gitdir = os.path.join(target, check)
|
||||
comments = []
|
||||
if os.path.isdir(gitdir) or __salt__['git.is_worktree'](target):
|
||||
if os.path.isdir(gitdir) or __salt__['git.is_worktree'](target,
|
||||
user=user,
|
||||
password=password):
|
||||
# Target directory is a git repository or git worktree
|
||||
try:
|
||||
all_local_branches = __salt__['git.list_branches'](
|
||||
target, user=user)
|
||||
all_local_tags = __salt__['git.list_tags'](target, user=user)
|
||||
local_rev, local_branch = _get_local_rev_and_branch(target, user)
|
||||
target, user=user, password=password)
|
||||
all_local_tags = __salt__['git.list_tags'](target,
|
||||
user=user,
|
||||
password=password)
|
||||
local_rev, local_branch = \
|
||||
_get_local_rev_and_branch(target, user, password)
|
||||
|
||||
if not bare and remote_rev is None and local_rev is not None:
|
||||
return _fail(
|
||||
@ -723,6 +740,7 @@ def latest(name,
|
||||
target,
|
||||
branch + '^{commit}',
|
||||
user=user,
|
||||
password=password,
|
||||
ignore_retcode=True)
|
||||
except CommandExecutionError as exc:
|
||||
return _fail(
|
||||
@ -734,12 +752,16 @@ def latest(name,
|
||||
|
||||
remotes = __salt__['git.remotes'](target,
|
||||
user=user,
|
||||
password=password,
|
||||
redact_auth=False)
|
||||
|
||||
revs_match = _revs_equal(local_rev, remote_rev, remote_rev_type)
|
||||
try:
|
||||
local_changes = bool(
|
||||
__salt__['git.diff'](target, 'HEAD', user=user)
|
||||
__salt__['git.diff'](target,
|
||||
'HEAD',
|
||||
user=user,
|
||||
password=password)
|
||||
)
|
||||
except CommandExecutionError:
|
||||
# No need to capture the error and log it, the _git_run()
|
||||
@ -767,6 +789,8 @@ def latest(name,
|
||||
__salt__['git.rev_parse'](
|
||||
target,
|
||||
remote_rev + '^{commit}',
|
||||
user=user,
|
||||
password=password,
|
||||
ignore_retcode=True)
|
||||
except CommandExecutionError:
|
||||
# Local checkout doesn't have the remote_rev
|
||||
@ -787,6 +811,7 @@ def latest(name,
|
||||
target,
|
||||
desired_upstream,
|
||||
user=user,
|
||||
password=password,
|
||||
ignore_retcode=True)
|
||||
except CommandExecutionError:
|
||||
pass
|
||||
@ -806,6 +831,7 @@ def latest(name,
|
||||
target,
|
||||
rev + '^{commit}',
|
||||
user=user,
|
||||
password=password,
|
||||
ignore_retcode=True)
|
||||
except CommandExecutionError:
|
||||
# Shouldn't happen if the tag exists
|
||||
@ -875,6 +901,7 @@ def latest(name,
|
||||
refs=[base_rev, remote_rev],
|
||||
is_ancestor=True,
|
||||
user=user,
|
||||
password=password,
|
||||
ignore_retcode=True)
|
||||
|
||||
if fast_forward is False:
|
||||
@ -903,6 +930,7 @@ def latest(name,
|
||||
base_branch + '@{upstream}',
|
||||
opts=['--abbrev-ref'],
|
||||
user=user,
|
||||
password=password,
|
||||
ignore_retcode=True)
|
||||
except CommandExecutionError:
|
||||
# There is a local branch but the rev-parse command
|
||||
@ -970,6 +998,7 @@ def latest(name,
|
||||
url=name,
|
||||
remote=remote,
|
||||
user=user,
|
||||
password=password,
|
||||
https_user=https_user,
|
||||
https_pass=https_pass)
|
||||
comments.append(
|
||||
@ -1121,6 +1150,7 @@ def latest(name,
|
||||
force=force_fetch,
|
||||
refspecs=refspecs,
|
||||
user=user,
|
||||
password=password,
|
||||
identity=identity,
|
||||
saltenv=__env__)
|
||||
except CommandExecutionError as exc:
|
||||
@ -1136,6 +1166,8 @@ def latest(name,
|
||||
__salt__['git.rev_parse'](
|
||||
target,
|
||||
remote_rev + '^{commit}',
|
||||
user=user,
|
||||
password=password,
|
||||
ignore_retcode=True)
|
||||
except CommandExecutionError as exc:
|
||||
return _fail(
|
||||
@ -1167,7 +1199,8 @@ def latest(name,
|
||||
target,
|
||||
refs=[base_rev, remote_rev],
|
||||
is_ancestor=True,
|
||||
user=user)
|
||||
user=user,
|
||||
password=password)
|
||||
|
||||
if fast_forward is False and not force_reset:
|
||||
return _not_fast_forward(
|
||||
@ -1207,7 +1240,8 @@ def latest(name,
|
||||
checkout_rev,
|
||||
force=force_checkout,
|
||||
opts=checkout_opts,
|
||||
user=user)
|
||||
user=user,
|
||||
password=password)
|
||||
if '-b' in checkout_opts:
|
||||
comments.append(
|
||||
'New branch \'{0}\' was checked out, with {1} '
|
||||
@ -1228,7 +1262,8 @@ def latest(name,
|
||||
__salt__['git.reset'](
|
||||
target,
|
||||
opts=['--hard', remote_rev],
|
||||
user=user
|
||||
user=user,
|
||||
password=password,
|
||||
)
|
||||
ret['changes']['forced update'] = True
|
||||
comments.append(
|
||||
@ -1239,7 +1274,8 @@ def latest(name,
|
||||
__salt__['git.branch'](
|
||||
target,
|
||||
opts=branch_opts,
|
||||
user=user)
|
||||
user=user,
|
||||
password=password)
|
||||
comments.append(upstream_action)
|
||||
|
||||
# Fast-forward to the desired revision
|
||||
@ -1255,6 +1291,8 @@ def latest(name,
|
||||
if __salt__['git.symbolic_ref'](target,
|
||||
'HEAD',
|
||||
opts=['--quiet'],
|
||||
user=user,
|
||||
password=password,
|
||||
ignore_retcode=True):
|
||||
merge_rev = remote_rev if rev == 'HEAD' \
|
||||
else desired_upstream
|
||||
@ -1276,8 +1314,8 @@ def latest(name,
|
||||
target,
|
||||
rev=merge_rev,
|
||||
opts=merge_opts,
|
||||
user=user
|
||||
)
|
||||
user=user,
|
||||
password=password)
|
||||
comments.append(
|
||||
'Repository was fast-forwarded to {0}'
|
||||
.format(remote_loc)
|
||||
@ -1295,8 +1333,8 @@ def latest(name,
|
||||
target,
|
||||
opts=['--hard',
|
||||
remote_rev if rev == 'HEAD' else rev],
|
||||
user=user
|
||||
)
|
||||
user=user,
|
||||
password=password)
|
||||
comments.append(
|
||||
'Repository was reset to {0} (fast-forward)'
|
||||
.format(rev)
|
||||
@ -1311,6 +1349,7 @@ def latest(name,
|
||||
'update',
|
||||
opts=['--init', '--recursive'],
|
||||
user=user,
|
||||
password=password,
|
||||
identity=identity,
|
||||
saltenv=__env__)
|
||||
except CommandExecutionError as exc:
|
||||
@ -1332,6 +1371,7 @@ def latest(name,
|
||||
force=force_fetch,
|
||||
refspecs=refspecs,
|
||||
user=user,
|
||||
password=password,
|
||||
identity=identity,
|
||||
saltenv=__env__)
|
||||
except CommandExecutionError as exc:
|
||||
@ -1349,6 +1389,7 @@ def latest(name,
|
||||
new_rev = __salt__['git.revision'](
|
||||
cwd=target,
|
||||
user=user,
|
||||
password=password,
|
||||
ignore_retcode=True)
|
||||
except CommandExecutionError:
|
||||
new_rev = None
|
||||
@ -1447,6 +1488,7 @@ def latest(name,
|
||||
__salt__['git.clone'](target,
|
||||
name,
|
||||
user=user,
|
||||
password=password,
|
||||
opts=clone_opts,
|
||||
identity=identity,
|
||||
https_user=https_user,
|
||||
@ -1483,7 +1525,7 @@ def latest(name,
|
||||
else:
|
||||
if remote_rev_type == 'tag' \
|
||||
and rev not in __salt__['git.list_tags'](
|
||||
target, user=user):
|
||||
target, user=user, password=password):
|
||||
return _fail(
|
||||
ret,
|
||||
'Revision \'{0}\' does not exist in clone'
|
||||
@ -1493,8 +1535,10 @@ def latest(name,
|
||||
|
||||
if branch is not None:
|
||||
if branch not in \
|
||||
__salt__['git.list_branches'](target,
|
||||
user=user):
|
||||
__salt__['git.list_branches'](
|
||||
target,
|
||||
user=user,
|
||||
password=password):
|
||||
if rev == 'HEAD':
|
||||
checkout_rev = remote_rev
|
||||
else:
|
||||
@ -1504,7 +1548,8 @@ def latest(name,
|
||||
__salt__['git.checkout'](target,
|
||||
checkout_rev,
|
||||
opts=['-b', branch],
|
||||
user=user)
|
||||
user=user,
|
||||
password=password)
|
||||
comments.append(
|
||||
'Branch \'{0}\' checked out, with {1} '
|
||||
'as a starting point'.format(
|
||||
@ -1514,14 +1559,14 @@ def latest(name,
|
||||
)
|
||||
|
||||
local_rev, local_branch = \
|
||||
_get_local_rev_and_branch(target, user)
|
||||
_get_local_rev_and_branch(target, user, password)
|
||||
|
||||
if not _revs_equal(local_rev, remote_rev, remote_rev_type):
|
||||
__salt__['git.reset'](
|
||||
target,
|
||||
opts=['--hard', remote_rev],
|
||||
user=user
|
||||
)
|
||||
user=user,
|
||||
password=password)
|
||||
comments.append(
|
||||
'Repository was reset to {0}'.format(remote_loc)
|
||||
)
|
||||
@ -1532,6 +1577,7 @@ def latest(name,
|
||||
local_branch + '@{upstream}',
|
||||
opts=['--abbrev-ref'],
|
||||
user=user,
|
||||
password=password,
|
||||
ignore_retcode=True)
|
||||
except CommandExecutionError:
|
||||
upstream = False
|
||||
@ -1545,7 +1591,9 @@ def latest(name,
|
||||
branch_opts = _get_branch_opts(
|
||||
branch,
|
||||
local_branch,
|
||||
__salt__['git.list_branches'](target, user=user),
|
||||
__salt__['git.list_branches'](target,
|
||||
user=user,
|
||||
password=password),
|
||||
desired_upstream,
|
||||
git_ver)
|
||||
elif upstream and desired_upstream is False:
|
||||
@ -1568,7 +1616,9 @@ def latest(name,
|
||||
branch_opts = _get_branch_opts(
|
||||
branch,
|
||||
local_branch,
|
||||
__salt__['git.list_branches'](target, user=user),
|
||||
__salt__['git.list_branches'](target,
|
||||
user=user,
|
||||
password=password),
|
||||
desired_upstream,
|
||||
git_ver)
|
||||
else:
|
||||
@ -1578,7 +1628,8 @@ def latest(name,
|
||||
__salt__['git.branch'](
|
||||
target,
|
||||
opts=branch_opts,
|
||||
user=user)
|
||||
user=user,
|
||||
password=password)
|
||||
comments.append(upstream_action)
|
||||
|
||||
if submodules and remote_rev:
|
||||
@ -1587,6 +1638,7 @@ def latest(name,
|
||||
'update',
|
||||
opts=['--init', '--recursive'],
|
||||
user=user,
|
||||
password=password,
|
||||
identity=identity)
|
||||
except CommandExecutionError as exc:
|
||||
return _failed_submodule_update(ret, exc, comments)
|
||||
@ -1595,6 +1647,7 @@ def latest(name,
|
||||
new_rev = __salt__['git.revision'](
|
||||
cwd=target,
|
||||
user=user,
|
||||
password=password,
|
||||
ignore_retcode=True)
|
||||
except CommandExecutionError:
|
||||
new_rev = None
|
||||
@ -1624,7 +1677,8 @@ def present(name,
|
||||
template=None,
|
||||
separate_git_dir=None,
|
||||
shared=None,
|
||||
user=None):
|
||||
user=None,
|
||||
password=None):
|
||||
'''
|
||||
Ensure that a repository exists in the given directory
|
||||
|
||||
@ -1678,6 +1732,12 @@ def present(name,
|
||||
|
||||
.. versionadded:: 0.17.0
|
||||
|
||||
password
|
||||
Windows only. Required when specifying ``user``. This parameter will be
|
||||
ignored on non-Windows platforms.
|
||||
|
||||
.. versionadded:: 2016.3.4
|
||||
|
||||
.. _`git-init(1)`: http://git-scm.com/docs/git-init
|
||||
.. _`worktree`: http://git-scm.com/docs/git-worktree
|
||||
'''
|
||||
@ -1689,7 +1749,7 @@ def present(name,
|
||||
return ret
|
||||
elif not bare and \
|
||||
(os.path.isdir(os.path.join(name, '.git')) or
|
||||
__salt__['git.is_worktree'](name)):
|
||||
__salt__['git.is_worktree'](name, user=user, password=password)):
|
||||
return ret
|
||||
# Directory exists and is not a git repo, if force is set destroy the
|
||||
# directory and recreate, otherwise throw an error
|
||||
@ -1747,7 +1807,8 @@ def present(name,
|
||||
template=template,
|
||||
separate_git_dir=separate_git_dir,
|
||||
shared=shared,
|
||||
user=user)
|
||||
user=user,
|
||||
password=password)
|
||||
|
||||
actions = [
|
||||
'Initialized {0}repository in {1}'.format(
|
||||
@ -1773,6 +1834,7 @@ def detached(name,
|
||||
target=None,
|
||||
remote='origin',
|
||||
user=None,
|
||||
password=None,
|
||||
force_clone=False,
|
||||
force_checkout=False,
|
||||
fetch_remote=True,
|
||||
@ -1811,6 +1873,12 @@ def detached(name,
|
||||
User under which to run git commands. By default, commands are run by
|
||||
the user under which the minion is running.
|
||||
|
||||
password
|
||||
Windows only. Required when specifying ``user``. This parameter will be
|
||||
ignored on non-Windows platforms.
|
||||
|
||||
.. versionadded:: 2016.3.4
|
||||
|
||||
force_clone : False
|
||||
If the ``target`` directory exists and is not a git repository, then
|
||||
this state will fail. Set this argument to ``True`` to remove the
|
||||
@ -1966,18 +2034,24 @@ def detached(name,
|
||||
local_commit_id = None
|
||||
|
||||
gitdir = os.path.join(target, '.git')
|
||||
if os.path.isdir(gitdir) or __salt__['git.is_worktree'](target):
|
||||
if os.path.isdir(gitdir) \
|
||||
or __salt__['git.is_worktree'](target, user=user, password=password):
|
||||
# Target directory is a git repository or git worktree
|
||||
|
||||
local_commit_id = _get_local_rev_and_branch(target, user)[0]
|
||||
local_commit_id = _get_local_rev_and_branch(target, user, password)[0]
|
||||
|
||||
if remote_ref_type is 'hash' and __salt__['git.describe'](target, ref):
|
||||
if remote_ref_type is 'hash' \
|
||||
and __salt__['git.describe'](target,
|
||||
ref,
|
||||
user=user,
|
||||
password=password):
|
||||
# The ref is a hash and it exists locally so skip to checkout
|
||||
hash_exists_locally = True
|
||||
else:
|
||||
# Check that remote is present and set to correct url
|
||||
remotes = __salt__['git.remotes'](target,
|
||||
user=user,
|
||||
password=password,
|
||||
redact_auth=False)
|
||||
|
||||
if remote in remotes and name in remotes[remote]['fetch']:
|
||||
@ -2002,6 +2076,7 @@ def detached(name,
|
||||
url=name,
|
||||
remote=remote,
|
||||
user=user,
|
||||
password=password,
|
||||
https_user=https_user,
|
||||
https_pass=https_pass)
|
||||
comments.append(
|
||||
@ -2073,6 +2148,7 @@ def detached(name,
|
||||
__salt__['git.clone'](target,
|
||||
name,
|
||||
user=user,
|
||||
password=password,
|
||||
opts=clone_opts,
|
||||
identity=identity,
|
||||
https_user=https_user,
|
||||
@ -2119,6 +2195,7 @@ def detached(name,
|
||||
force=True,
|
||||
refspecs=refspecs,
|
||||
user=user,
|
||||
password=password,
|
||||
identity=identity,
|
||||
saltenv=__env__)
|
||||
except CommandExecutionError as exc:
|
||||
@ -2135,7 +2212,7 @@ def detached(name,
|
||||
#get refs and checkout
|
||||
checkout_commit_id = ''
|
||||
if remote_ref_type is 'hash':
|
||||
if __salt__['git.describe'](target, ref):
|
||||
if __salt__['git.describe'](target, ref, user=user, password=password):
|
||||
checkout_commit_id = ref
|
||||
else:
|
||||
return _fail(
|
||||
@ -2147,6 +2224,7 @@ def detached(name,
|
||||
all_remote_refs = __salt__['git.remote_refs'](
|
||||
target,
|
||||
user=user,
|
||||
password=password,
|
||||
identity=identity,
|
||||
https_user=https_user,
|
||||
https_pass=https_pass,
|
||||
@ -2179,8 +2257,8 @@ def detached(name,
|
||||
__salt__['git.reset'](
|
||||
target,
|
||||
opts=['--hard', 'HEAD'],
|
||||
user=user
|
||||
)
|
||||
user=user,
|
||||
password=password)
|
||||
comments.append(
|
||||
'Repository was reset to HEAD before checking out ref'
|
||||
)
|
||||
@ -2202,7 +2280,8 @@ def detached(name,
|
||||
__salt__['git.checkout'](target,
|
||||
checkout_commit_id,
|
||||
force=force_checkout,
|
||||
user=user)
|
||||
user=user,
|
||||
password=password)
|
||||
comments.append(
|
||||
'Commit ID {0} was checked out at {1}'.format(
|
||||
checkout_commit_id,
|
||||
@ -2214,6 +2293,7 @@ def detached(name,
|
||||
new_rev = __salt__['git.revision'](
|
||||
cwd=target,
|
||||
user=user,
|
||||
password=password,
|
||||
ignore_retcode=True)
|
||||
except CommandExecutionError:
|
||||
new_rev = None
|
||||
@ -2223,6 +2303,7 @@ def detached(name,
|
||||
'update',
|
||||
opts=['--init', '--recursive'],
|
||||
user=user,
|
||||
password=password,
|
||||
identity=identity)
|
||||
comments.append(
|
||||
'Submodules were updated'
|
||||
@ -2244,6 +2325,7 @@ def config_unset(name,
|
||||
value_regex=None,
|
||||
repo=None,
|
||||
user=None,
|
||||
password=None,
|
||||
**kwargs):
|
||||
r'''
|
||||
.. versionadded:: 2015.8.0
|
||||
@ -2274,7 +2356,14 @@ def config_unset(name,
|
||||
set. Required unless ``global`` is set to ``True``.
|
||||
|
||||
user
|
||||
Optional name of a user as whom `git config` will be run
|
||||
User under which to run git commands. By default, commands are run by
|
||||
the user under which the minion is running.
|
||||
|
||||
password
|
||||
Windows only. Required when specifying ``user``. This parameter will be
|
||||
ignored on non-Windows platforms.
|
||||
|
||||
.. versionadded:: 2016.3.4
|
||||
|
||||
global : False
|
||||
If ``True``, this will set a global git config option
|
||||
@ -2349,6 +2438,7 @@ def config_unset(name,
|
||||
key=key,
|
||||
value_regex=value_regex,
|
||||
user=user,
|
||||
password=password,
|
||||
ignore_retcode=True,
|
||||
**{'global': global_}
|
||||
)
|
||||
@ -2397,6 +2487,7 @@ def config_unset(name,
|
||||
key=key,
|
||||
value_regex=None,
|
||||
user=user,
|
||||
password=password,
|
||||
ignore_retcode=True,
|
||||
**{'global': global_}
|
||||
)
|
||||
@ -2412,6 +2503,7 @@ def config_unset(name,
|
||||
value_regex=value_regex,
|
||||
all=all_,
|
||||
user=user,
|
||||
password=password,
|
||||
**{'global': global_}
|
||||
)
|
||||
except CommandExecutionError as exc:
|
||||
@ -2434,6 +2526,7 @@ def config_unset(name,
|
||||
key=key,
|
||||
value_regex=None,
|
||||
user=user,
|
||||
password=password,
|
||||
ignore_retcode=True,
|
||||
**{'global': global_}
|
||||
)
|
||||
@ -2453,6 +2546,7 @@ def config_unset(name,
|
||||
key=key,
|
||||
value_regex=value_regex,
|
||||
user=user,
|
||||
password=password,
|
||||
ignore_retcode=True,
|
||||
**{'global': global_}
|
||||
)
|
||||
@ -2474,6 +2568,7 @@ def config_set(name,
|
||||
multivar=None,
|
||||
repo=None,
|
||||
user=None,
|
||||
password=None,
|
||||
**kwargs):
|
||||
'''
|
||||
.. versionadded:: 2014.7.0
|
||||
@ -2504,7 +2599,14 @@ def config_set(name,
|
||||
set. Required unless ``global`` is set to ``True``.
|
||||
|
||||
user
|
||||
Optional name of a user as whom `git config` will be run
|
||||
User under which to run git commands. By default, the commands are run
|
||||
by the user under which the minion is running.
|
||||
|
||||
password
|
||||
Windows only. Required when specifying ``user``. This parameter will be
|
||||
ignored on non-Windows platforms.
|
||||
|
||||
.. versionadded:: 2016.3.4
|
||||
|
||||
global : False
|
||||
If ``True``, this will set a global git config option
|
||||
@ -2614,6 +2716,7 @@ def config_set(name,
|
||||
cwd=repo,
|
||||
key=name,
|
||||
user=user,
|
||||
password=password,
|
||||
ignore_retcode=True,
|
||||
**{'all': True, 'global': global_}
|
||||
)
|
||||
@ -2644,6 +2747,7 @@ def config_set(name,
|
||||
value=value,
|
||||
multivar=multivar,
|
||||
user=user,
|
||||
password=password,
|
||||
**{'global': global_}
|
||||
)
|
||||
except CommandExecutionError as exc:
|
||||
@ -2679,7 +2783,13 @@ def config_set(name,
|
||||
return ret
|
||||
|
||||
|
||||
def config(name, value=None, multivar=None, repo=None, user=None, **kwargs):
|
||||
def config(name,
|
||||
value=None,
|
||||
multivar=None,
|
||||
repo=None,
|
||||
user=None,
|
||||
password=None,
|
||||
**kwargs):
|
||||
'''
|
||||
Pass through to git.config_set and display a deprecation warning
|
||||
'''
|
||||
@ -2693,6 +2803,7 @@ def config(name, value=None, multivar=None, repo=None, user=None, **kwargs):
|
||||
multivar=multivar,
|
||||
repo=repo,
|
||||
user=user,
|
||||
password=password,
|
||||
**kwargs)
|
||||
|
||||
|
||||
|
@ -103,28 +103,38 @@ def mounted(name,
|
||||
device otherwise.
|
||||
|
||||
extra_mount_invisible_options
|
||||
A list of extra options that are not visible through the /proc/self/mountinfo
|
||||
interface. If a option is not visible through this interface it will always
|
||||
remount the device. This Option extends the builtin mount_invisible_options list.
|
||||
A list of extra options that are not visible through the
|
||||
``/proc/self/mountinfo`` interface.
|
||||
|
||||
If a option is not visible through this interface it will always remount
|
||||
the device. This option extends the builtin ``mount_invisible_options``
|
||||
list.
|
||||
|
||||
extra_mount_invisible_keys
|
||||
A list of extra key options that are not visible through the /proc/self/mountinfo
|
||||
interface. If a key option is not visible through this interface it will always
|
||||
remount the device. This Option extends the builtin mount_invisible_keys list.
|
||||
A good example for a key Option is the password Option:
|
||||
A list of extra key options that are not visible through the
|
||||
``/proc/self/mountinfo`` interface.
|
||||
|
||||
If a key option is not visible through this interface it will always
|
||||
remount the device. This option extends the builtin
|
||||
``mount_invisible_keys`` list.
|
||||
|
||||
A good example for a key option is the password option::
|
||||
|
||||
password=badsecret
|
||||
|
||||
extra_ignore_fs_keys
|
||||
A dict of filesystem options which should not force a remount. This will update
|
||||
the internal dictionary. The dict should look like this:
|
||||
the internal dictionary. The dict should look like this::
|
||||
|
||||
{
|
||||
'ramfs': ['size']
|
||||
}
|
||||
|
||||
extra_mount_translate_options
|
||||
A dict of mount options that gets translated when mounted. To prevent a remount
|
||||
add additional Options to the default dictionary. This will update the internal
|
||||
dictionary. The dictionary should look like this:
|
||||
add additional options to the default dictionary. This will update the internal
|
||||
dictionary. The dictionary should look like this::
|
||||
|
||||
{
|
||||
'tcp': 'proto=tcp',
|
||||
'udp': 'proto=udp'
|
||||
|
@ -2274,7 +2274,13 @@ def group_installed(name, skip=None, include=None, **kwargs):
|
||||
if not isinstance(item, six.string_types):
|
||||
include[idx] = str(item)
|
||||
|
||||
try:
|
||||
diff = __salt__['pkg.group_diff'](name)
|
||||
except CommandExecutionError as err:
|
||||
ret['comment'] = ('An error was encountered while installing/updating '
|
||||
'group \'{0}\': {1}.'.format(name, err))
|
||||
return ret
|
||||
|
||||
mandatory = diff['mandatory']['installed'] + \
|
||||
diff['mandatory']['not installed']
|
||||
|
||||
|
@ -39,6 +39,9 @@ def present(dbname, name,
|
||||
name
|
||||
The name of the schema to manage
|
||||
|
||||
owner
|
||||
The database user that will be the owner of the schema
|
||||
|
||||
db_user
|
||||
database username if different from config or default
|
||||
|
||||
@ -99,7 +102,7 @@ def absent(dbname, name,
|
||||
db_user=None, db_password=None,
|
||||
db_host=None, db_port=None):
|
||||
'''
|
||||
Ensure that the named schema is absent
|
||||
Ensure that the named schema is absent.
|
||||
|
||||
dbname
|
||||
The database's name will work on
|
||||
|
@ -1213,7 +1213,7 @@ class Pygit2(GitProvider):
|
||||
self.repo.config.set_multivar(
|
||||
'http.sslVerify',
|
||||
'',
|
||||
self.ssl_verify
|
||||
str(self.ssl_verify).lower()
|
||||
)
|
||||
except os.error:
|
||||
# This exception occurs when two processes are trying to write
|
||||
|
@ -1,6 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Implements the ability to run processes as another user in Windows for salt
|
||||
Run processes as a different user in Windows
|
||||
|
||||
Based on a solution from http://stackoverflow.com/questions/29566330
|
||||
'''
|
||||
from __future__ import absolute_import
|
||||
|
||||
|
@ -108,6 +108,18 @@ def accept_dict(match, include_rejected=False, include_denied=False):
|
||||
match
|
||||
The dictionary of keys to accept.
|
||||
|
||||
include_rejected
|
||||
To include rejected keys in the match along with pending keys, set this
|
||||
to ``True``. Defaults to ``False``.
|
||||
|
||||
.. versionadded:: 2016.3.4
|
||||
|
||||
include_denied
|
||||
To include denied keys in the match along with pending keys, set this
|
||||
to ``True``. Defaults to ``False``.
|
||||
|
||||
.. versionadded:: 2016.3.4
|
||||
|
||||
Example to move a list of keys from the ``minions_pre`` (pending) directory
|
||||
to the ``minions`` (accepted) directory:
|
||||
|
||||
@ -199,6 +211,18 @@ def reject_dict(match, include_accepted=False, include_denied=False):
|
||||
match
|
||||
The dictionary of keys to reject.
|
||||
|
||||
include_accepted
|
||||
To include accepted keys in the match along with pending keys, set this
|
||||
to ``True``. Defaults to ``False``.
|
||||
|
||||
.. versionadded:: 2016.3.4
|
||||
|
||||
include_denied
|
||||
To include denied keys in the match along with pending keys, set this
|
||||
to ``True``. Defaults to ``False``.
|
||||
|
||||
.. versionadded:: 2016.3.4
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> wheel.cmd_async({'fun': 'key.reject_dict',
|
||||
|
BIN
tests/integration/files/file/base/custom.tar.gz
Normal file
BIN
tests/integration/files/file/base/custom.tar.gz
Normal file
Binary file not shown.
110
tests/integration/states/archive.py
Normal file
110
tests/integration/states/archive.py
Normal file
@ -0,0 +1,110 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Tests for the archive state
|
||||
'''
|
||||
# Import python libs
|
||||
from __future__ import absolute_import
|
||||
import os
|
||||
import shutil
|
||||
import threading
|
||||
import tornado.ioloop
|
||||
import tornado.web
|
||||
|
||||
# Import Salt Testing libs
|
||||
from salttesting import TestCase
|
||||
from salttesting.helpers import ensure_in_syspath
|
||||
ensure_in_syspath('../../')
|
||||
|
||||
# Import salt libs
|
||||
import integration
|
||||
import salt.utils
|
||||
|
||||
STATE_DIR = os.path.join(integration.FILES, 'file', 'base')
|
||||
if salt.utils.is_windows():
|
||||
ARCHIVE_DIR = os.path.join("c:/", "tmp")
|
||||
else:
|
||||
ARCHIVE_DIR = '/tmp/archive/'
|
||||
|
||||
PORT = 9999
|
||||
ARCHIVE_TAR_SOURCE = 'http://localhost:{0}/custom.tar.gz'.format(PORT)
|
||||
UNTAR_FILE = ARCHIVE_DIR + 'custom/README'
|
||||
ARCHIVE_TAR_HASH = 'md5=7643861ac07c30fe7d2310e9f25ca514'
|
||||
STATE_DIR = os.path.join(integration.FILES, 'file', 'base')
|
||||
|
||||
|
||||
class SetupWebServer(TestCase):
|
||||
'''
|
||||
Setup and Teardown of Web Server
|
||||
Only need to set this up once not
|
||||
before all tests
|
||||
'''
|
||||
@classmethod
|
||||
def webserver(cls):
|
||||
'''
|
||||
method to start tornado
|
||||
static web app
|
||||
'''
|
||||
application = tornado.web.Application([(r"/(.*)", tornado.web.StaticFileHandler,
|
||||
{"path": STATE_DIR})])
|
||||
application.listen(PORT)
|
||||
tornado.ioloop.IOLoop.instance().start()
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.server_thread = threading.Thread(target=cls.webserver)
|
||||
cls.server_thread.daemon = True
|
||||
cls.server_thread.start()
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
tornado.ioloop.IOLoop.instance().stop()
|
||||
cls.server_thread.join()
|
||||
|
||||
|
||||
class ArchiveTest(SetupWebServer,
|
||||
integration.ModuleCase,
|
||||
integration.SaltReturnAssertsMixIn):
|
||||
'''
|
||||
Validate the archive state
|
||||
'''
|
||||
def _check_ext_remove(self, dir, file):
|
||||
'''
|
||||
function to check if file was extracted
|
||||
and remove the directory.
|
||||
'''
|
||||
# check to see if it extracted
|
||||
check_dir = os.path.isfile(file)
|
||||
self.assertTrue(check_dir)
|
||||
|
||||
# wipe away dir. Can't do this in teardown
|
||||
# because it needs to be wiped before each test
|
||||
shutil.rmtree(dir)
|
||||
|
||||
def test_archive_extracted_skip_verify(self):
|
||||
'''
|
||||
test archive.extracted with skip_verify
|
||||
'''
|
||||
ret = self.run_state('archive.extracted', name=ARCHIVE_DIR,
|
||||
source=ARCHIVE_TAR_SOURCE, archive_format='tar',
|
||||
skip_verify=True)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
|
||||
self._check_ext_remove(ARCHIVE_DIR, UNTAR_FILE)
|
||||
|
||||
def test_archive_extracted_with_source_hash(self):
|
||||
'''
|
||||
test archive.extracted without skip_verify
|
||||
only external resources work to check to
|
||||
ensure source_hash is verified correctly
|
||||
'''
|
||||
ret = self.run_state('archive.extracted', name=ARCHIVE_DIR,
|
||||
source=ARCHIVE_TAR_SOURCE, archive_format='tar',
|
||||
source_hash=ARCHIVE_TAR_HASH)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
|
||||
self._check_ext_remove(ARCHIVE_DIR, UNTAR_FILE)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from integration import run_tests
|
||||
run_tests(ArchiveTest)
|
@ -596,6 +596,35 @@ class PkgTest(integration.ModuleCase,
|
||||
'Package {0} is already up-to-date'.format(target)
|
||||
)
|
||||
|
||||
@requires_system_grains
|
||||
def test_group_installed_handle_missing_package_group(self, grains=None): # pylint: disable=unused-argument
|
||||
'''
|
||||
Tests that a CommandExecutionError is caught and the state returns False when
|
||||
the package group is missing. Before this fix, the state would stacktrace.
|
||||
See Issue #35819 for bug report.
|
||||
'''
|
||||
# Skip test if package manager not available
|
||||
if not pkgmgr_avail(self.run_function, self.run_function('grains.items')):
|
||||
self.skipTest('Package manager is not available')
|
||||
|
||||
# Group install not available message
|
||||
grp_install_msg = 'pkg.group_install not available for this platform'
|
||||
|
||||
# Run the pkg.group_installed state with a fake package group
|
||||
ret = self.run_state('pkg.group_installed', name='handle_missing_pkg_group',
|
||||
skip='foo-bar-baz')
|
||||
ret_comment = ret['pkg_|-handle_missing_pkg_group_|-handle_missing_pkg_group_|-group_installed']['comment']
|
||||
|
||||
# Not all package managers support group_installed. Skip this test if not supported.
|
||||
if ret_comment == grp_install_msg:
|
||||
self.skipTest(grp_install_msg)
|
||||
|
||||
# Test state should return False and should have the right comment
|
||||
self.assertSaltFalseReturn(ret)
|
||||
self.assertEqual(ret_comment, 'An error was encountered while installing/updating group '
|
||||
'\'handle_missing_pkg_group\': Group \'handle_missing_pkg_group\' '
|
||||
'not found.')
|
||||
|
||||
if __name__ == '__main__':
|
||||
from integration import run_tests
|
||||
run_tests(PkgTest)
|
||||
|
@ -8,7 +8,13 @@
|
||||
|
||||
# Import Python libs
|
||||
from __future__ import absolute_import
|
||||
import libcloud.security
|
||||
|
||||
try:
|
||||
import libcloud.security
|
||||
HAS_LIBCLOUD = True
|
||||
except ImportError:
|
||||
HAS_LIBCLOUD = False
|
||||
|
||||
import platform
|
||||
import os
|
||||
|
||||
@ -44,7 +50,7 @@ ON_SUSE = True if 'SuSE' in platform.dist() else False
|
||||
ON_MAC = True if 'Darwin' in platform.system() else False
|
||||
|
||||
if not os.path.exists('/etc/ssl/certs/YaST-CA.pem') and ON_SUSE:
|
||||
if os.path.isfile('/etc/ssl/ca-bundle.pem'):
|
||||
if os.path.isfile('/etc/ssl/ca-bundle.pem') and HAS_LIBCLOUD:
|
||||
libcloud.security.CA_CERTS_PATH.append('/etc/ssl/ca-bundle.pem')
|
||||
else:
|
||||
HAS_CERTS = False
|
||||
|
@ -8,7 +8,13 @@
|
||||
|
||||
# Import Python libs
|
||||
from __future__ import absolute_import
|
||||
import libcloud.security
|
||||
|
||||
try:
|
||||
import libcloud.security
|
||||
HAS_LIBCLOUD = True
|
||||
except ImportError:
|
||||
HAS_LIBCLOUD = False
|
||||
|
||||
import platform
|
||||
import os
|
||||
|
||||
@ -51,7 +57,7 @@ ON_SUSE = True if 'SuSE' in platform.dist() else False
|
||||
ON_MAC = True if 'Darwin' in platform.system() else False
|
||||
|
||||
if not os.path.exists('/etc/ssl/certs/YaST-CA.pem') and ON_SUSE:
|
||||
if os.path.isfile('/etc/ssl/ca-bundle.pem'):
|
||||
if os.path.isfile('/etc/ssl/ca-bundle.pem') and HAS_LIBCLOUD:
|
||||
libcloud.security.CA_CERTS_PATH.append('/etc/ssl/ca-bundle.pem')
|
||||
else:
|
||||
HAS_CERTS = False
|
||||
|
@ -20,6 +20,8 @@ from salt.exceptions import SaltCloudSystemExit, SaltCloudNotFound
|
||||
# Global Variables
|
||||
opennebula.__active_provider_name__ = ''
|
||||
opennebula.__opts__ = {}
|
||||
opennebula.__utils__ = {}
|
||||
opennebula.__utils__['cloud.cache_node'] = MagicMock()
|
||||
VM_NAME = 'my-vm'
|
||||
|
||||
|
||||
@ -761,7 +763,6 @@ class OpenNebulaTestCase(TestCase):
|
||||
|
||||
@patch('salt.cloud.clouds.opennebula._get_node',
|
||||
MagicMock(return_value={'my-vm': {'name': 'my-vm', 'id': 0}}))
|
||||
@patch('salt.utils.cloud.cache_node', MagicMock())
|
||||
def test_show_instance_success(self):
|
||||
'''
|
||||
Tests that the node was found successfully.
|
||||
|
194
tests/unit/conf_test.py
Normal file
194
tests/unit/conf_test.py
Normal file
@ -0,0 +1,194 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Unit tests for the files in the salt/conf directory.
|
||||
'''
|
||||
|
||||
# Import Python libs
|
||||
from __future__ import absolute_import
|
||||
import os
|
||||
|
||||
# Import Salt Testing libs
|
||||
from salttesting import skipIf, TestCase
|
||||
from salttesting.helpers import ensure_in_syspath
|
||||
from salttesting.mock import (
|
||||
NO_MOCK,
|
||||
NO_MOCK_REASON,
|
||||
)
|
||||
|
||||
ensure_in_syspath('../')
|
||||
|
||||
# Import Salt libs
|
||||
import salt.config
|
||||
|
||||
SAMPLE_CONF_DIR = os.path.dirname(os.path.realpath(__file__)).split('tests')[0] + 'conf/'
|
||||
|
||||
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
class ConfTest(TestCase):
|
||||
'''
|
||||
Validate files in the salt/conf directory.
|
||||
'''
|
||||
|
||||
def test_conf_master_sample_is_commented(self):
|
||||
'''
|
||||
The sample config file located in salt/conf/master must be completely
|
||||
commented out. This test checks for any lines that are not commented or blank.
|
||||
'''
|
||||
master_config = SAMPLE_CONF_DIR + 'master'
|
||||
ret = salt.config._read_conf_file(master_config)
|
||||
self.assertEqual(
|
||||
ret,
|
||||
{},
|
||||
'Sample config file \'{0}\' must be commented out.'.format(
|
||||
master_config
|
||||
)
|
||||
)
|
||||
|
||||
def test_conf_minion_sample_is_commented(self):
|
||||
'''
|
||||
The sample config file located in salt/conf/minion must be completely
|
||||
commented out. This test checks for any lines that are not commented or blank.
|
||||
'''
|
||||
minion_config = SAMPLE_CONF_DIR + 'minion'
|
||||
ret = salt.config._read_conf_file(minion_config)
|
||||
self.assertEqual(
|
||||
ret,
|
||||
{},
|
||||
'Sample config file \'{0}\' must be commented out.'.format(
|
||||
minion_config
|
||||
)
|
||||
)
|
||||
|
||||
def test_conf_cloud_sample_is_commented(self):
|
||||
'''
|
||||
The sample config file located in salt/conf/cloud must be completely
|
||||
commented out. This test checks for any lines that are not commented or blank.
|
||||
'''
|
||||
cloud_config = SAMPLE_CONF_DIR + 'cloud'
|
||||
ret = salt.config._read_conf_file(cloud_config)
|
||||
self.assertEqual(
|
||||
ret,
|
||||
{},
|
||||
'Sample config file \'{0}\' must be commented out.'.format(
|
||||
cloud_config
|
||||
)
|
||||
)
|
||||
|
||||
def test_conf_cloud_profiles_sample_is_commented(self):
|
||||
'''
|
||||
The sample config file located in salt/conf/cloud.profiles must be completely
|
||||
commented out. This test checks for any lines that are not commented or blank.
|
||||
'''
|
||||
cloud_profiles_config = SAMPLE_CONF_DIR + 'cloud.profiles'
|
||||
ret = salt.config._read_conf_file(cloud_profiles_config)
|
||||
self.assertEqual(
|
||||
ret,
|
||||
{},
|
||||
'Sample config file \'{0}\' must be commented out.'.format(
|
||||
cloud_profiles_config
|
||||
)
|
||||
)
|
||||
|
||||
def test_conf_cloud_providers_sample_is_commented(self):
|
||||
'''
|
||||
The sample config file located in salt/conf/cloud.providers must be completely
|
||||
commented out. This test checks for any lines that are not commented or blank.
|
||||
'''
|
||||
cloud_providers_config = SAMPLE_CONF_DIR + 'cloud.providers'
|
||||
ret = salt.config._read_conf_file(cloud_providers_config)
|
||||
self.assertEqual(
|
||||
ret,
|
||||
{},
|
||||
'Sample config file \'{0}\' must be commented out.'.format(
|
||||
cloud_providers_config
|
||||
)
|
||||
)
|
||||
|
||||
def test_conf_proxy_sample_is_commented(self):
|
||||
'''
|
||||
The sample config file located in salt/conf/proxy must be completely
|
||||
commented out. This test checks for any lines that are not commented or blank.
|
||||
'''
|
||||
proxy_config = SAMPLE_CONF_DIR + 'proxy'
|
||||
ret = salt.config._read_conf_file(proxy_config)
|
||||
self.assertEqual(
|
||||
ret,
|
||||
{},
|
||||
'Sample config file \'{0}\' must be commented out.'.format(
|
||||
proxy_config
|
||||
)
|
||||
)
|
||||
|
||||
def test_conf_roster_sample_is_commented(self):
|
||||
'''
|
||||
The sample config file located in salt/conf/roster must be completely
|
||||
commented out. This test checks for any lines that are not commented or blank.
|
||||
'''
|
||||
roster_config = SAMPLE_CONF_DIR + 'roster'
|
||||
ret = salt.config._read_conf_file(roster_config)
|
||||
self.assertEqual(
|
||||
ret,
|
||||
{},
|
||||
'Sample config file \'{0}\' must be commented out.'.format(
|
||||
roster_config
|
||||
)
|
||||
)
|
||||
|
||||
def test_conf_cloud_profiles_d_files_are_commented(self):
|
||||
'''
|
||||
All cloud profile sample configs in salt/conf/cloud.profiles.d/* must be completely
|
||||
commented out. This test loops through all of the files in that directory to check
|
||||
for any lines that are not commented or blank.
|
||||
'''
|
||||
cloud_sample_files = os.listdir(SAMPLE_CONF_DIR + 'cloud.profiles.d/')
|
||||
for conf_file in cloud_sample_files:
|
||||
profile_conf = SAMPLE_CONF_DIR + 'cloud.profiles.d/' + conf_file
|
||||
ret = salt.config._read_conf_file(profile_conf)
|
||||
self.assertEqual(
|
||||
ret,
|
||||
{},
|
||||
'Sample config file \'{0}\' must be commented out.'.format(
|
||||
conf_file
|
||||
)
|
||||
)
|
||||
|
||||
def test_conf_cloud_providers_d_files_are_commented(self):
|
||||
'''
|
||||
All cloud profile sample configs in salt/conf/cloud.providers.d/* must be completely
|
||||
commented out. This test loops through all of the files in that directory to check
|
||||
for any lines that are not commented or blank.
|
||||
'''
|
||||
cloud_sample_files = os.listdir(SAMPLE_CONF_DIR + 'cloud.providers.d/')
|
||||
for conf_file in cloud_sample_files:
|
||||
provider_conf = SAMPLE_CONF_DIR + 'cloud.providers.d/' + conf_file
|
||||
ret = salt.config._read_conf_file(provider_conf)
|
||||
self.assertEqual(
|
||||
ret,
|
||||
{},
|
||||
'Sample config file \'{0}\' must be commented out.'.format(
|
||||
conf_file
|
||||
)
|
||||
)
|
||||
|
||||
def test_conf_cloud_maps_d_files_are_commented(self):
|
||||
'''
|
||||
All cloud profile sample configs in salt/conf/cloud.maps.d/* must be completely
|
||||
commented out. This test loops through all of the files in that directory to check
|
||||
for any lines that are not commented or blank.
|
||||
'''
|
||||
cloud_sample_files = os.listdir(SAMPLE_CONF_DIR + 'cloud.maps.d/')
|
||||
for conf_file in cloud_sample_files:
|
||||
map_conf = SAMPLE_CONF_DIR + 'cloud.maps.d/' + conf_file
|
||||
ret = salt.config._read_conf_file(map_conf)
|
||||
self.assertEqual(
|
||||
ret,
|
||||
{},
|
||||
'Sample config file \'{0}\' must be commented out.'.format(
|
||||
conf_file
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from integration import run_tests
|
||||
run_tests(ConfTest, needs_daemon=False)
|
@ -103,6 +103,11 @@ if _has_required_boto():
|
||||
StopLoggingTime=None)
|
||||
|
||||
|
||||
@skipIf(HAS_BOTO is False, 'The boto module must be installed.')
|
||||
@skipIf(_has_required_boto() is False, 'The boto3 module must be greater than'
|
||||
' or equal to version {0}'
|
||||
.format(required_boto3_version))
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
class BotoCloudTrailTestCaseBase(TestCase):
|
||||
conn = None
|
||||
|
||||
@ -128,11 +133,6 @@ class BotoCloudTrailTestCaseMixin(object):
|
||||
pass
|
||||
|
||||
|
||||
@skipIf(HAS_BOTO is False, 'The boto module must be installed.')
|
||||
@skipIf(_has_required_boto() is False, 'The boto3 module must be greater than'
|
||||
' or equal to version {0}'
|
||||
.format(required_boto3_version))
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
class BotoCloudTrailTestCase(BotoCloudTrailTestCaseBase, BotoCloudTrailTestCaseMixin):
|
||||
'''
|
||||
TestCase for salt.modules.boto_cloudtrail module
|
||||
|
@ -103,6 +103,11 @@ if _has_required_boto():
|
||||
ruleDisabled=True)
|
||||
|
||||
|
||||
@skipIf(HAS_BOTO is False, 'The boto module must be installed.')
|
||||
@skipIf(_has_required_boto() is False, 'The boto3 module must be greater than'
|
||||
' or equal to version {0}'
|
||||
.format(required_boto3_version))
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
class BotoIoTTestCaseBase(TestCase):
|
||||
conn = None
|
||||
|
||||
@ -128,11 +133,6 @@ class BotoIoTTestCaseMixin(object):
|
||||
pass
|
||||
|
||||
|
||||
@skipIf(HAS_BOTO is False, 'The boto module must be installed.')
|
||||
@skipIf(_has_required_boto() is False, 'The boto3 module must be greater than'
|
||||
' or equal to version {0}'
|
||||
.format(required_boto3_version))
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
class BotoIoTPolicyTestCase(BotoIoTTestCaseBase, BotoIoTTestCaseMixin):
|
||||
'''
|
||||
TestCase for salt.modules.boto_iot module
|
||||
|
@ -109,6 +109,11 @@ def _has_required_boto():
|
||||
return True
|
||||
|
||||
|
||||
@skipIf(HAS_BOTO is False, 'The boto module must be installed.')
|
||||
@skipIf(_has_required_boto() is False, 'The boto3 module must be greater than'
|
||||
' or equal to version {0}'
|
||||
.format(required_boto3_version))
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
class BotoLambdaTestCaseBase(TestCase):
|
||||
conn = None
|
||||
|
||||
@ -145,11 +150,6 @@ class BotoLambdaTestCaseMixin(object):
|
||||
pass
|
||||
|
||||
|
||||
@skipIf(HAS_BOTO is False, 'The boto module must be installed.')
|
||||
@skipIf(_has_required_boto() is False, 'The boto3 module must be greater than'
|
||||
' or equal to version {0}'
|
||||
.format(required_boto3_version))
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
class BotoLambdaFunctionTestCase(BotoLambdaTestCaseBase, BotoLambdaTestCaseMixin):
|
||||
'''
|
||||
TestCase for salt.modules.boto_lambda module
|
||||
|
@ -205,6 +205,11 @@ if _has_required_boto():
|
||||
}
|
||||
|
||||
|
||||
@skipIf(HAS_BOTO is False, 'The boto module must be installed.')
|
||||
@skipIf(_has_required_boto() is False, 'The boto3 module must be greater than'
|
||||
' or equal to version {0}'
|
||||
.format(required_boto3_version))
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
class BotoS3BucketTestCaseBase(TestCase):
|
||||
conn = None
|
||||
|
||||
@ -230,11 +235,6 @@ class BotoS3BucketTestCaseMixin(object):
|
||||
pass
|
||||
|
||||
|
||||
@skipIf(HAS_BOTO is False, 'The boto module must be installed.')
|
||||
@skipIf(_has_required_boto() is False, 'The boto3 module must be greater than'
|
||||
' or equal to version {0}'
|
||||
.format(required_boto3_version))
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
class BotoS3BucketTestCase(BotoS3BucketTestCaseBase, BotoS3BucketTestCaseMixin):
|
||||
'''
|
||||
TestCase for salt.modules.boto_s3_bucket module
|
||||
|
@ -124,6 +124,13 @@ def _has_required_moto():
|
||||
context = {}
|
||||
|
||||
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
@skipIf(HAS_BOTO is False, 'The boto module must be installed.')
|
||||
@skipIf(HAS_MOTO is False, 'The moto module must be installed.')
|
||||
@skipIf(_has_required_boto() is False, 'The boto module must be greater than'
|
||||
' or equal to version {0}'
|
||||
.format(required_boto_version))
|
||||
@skipIf(_has_required_moto() is False, 'The moto version must be >= to version {0}'.format(required_moto_version))
|
||||
class BotoVpcTestCaseBase(TestCase):
|
||||
def setUp(self):
|
||||
boto_vpc.__context__ = {}
|
||||
@ -249,13 +256,6 @@ class BotoVpcTestCaseMixin(object):
|
||||
return rtbl
|
||||
|
||||
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
@skipIf(HAS_BOTO is False, 'The boto module must be installed.')
|
||||
@skipIf(HAS_MOTO is False, 'The moto module must be installed.')
|
||||
@skipIf(_has_required_boto() is False, 'The boto module must be greater than'
|
||||
' or equal to version {0}'
|
||||
.format(required_boto_version))
|
||||
@skipIf(_has_required_moto() is False, 'The moto version must be >= to version {0}'.format(required_moto_version))
|
||||
class BotoVpcTestCase(BotoVpcTestCaseBase, BotoVpcTestCaseMixin):
|
||||
'''
|
||||
TestCase for salt.modules.boto_vpc module
|
||||
|
@ -84,14 +84,19 @@ class LinuxSysctlTestCase(TestCase):
|
||||
self.assertEqual(linux_sysctl.assign(
|
||||
'net.ipv4.ip_forward', 1), ret)
|
||||
|
||||
@patch('os.path.isfile', MagicMock(return_value=False))
|
||||
def test_persist_no_conf_failure(self):
|
||||
'''
|
||||
Tests adding of config file failure
|
||||
'''
|
||||
asn_cmd = {'pid': 1337, 'retcode': 0,
|
||||
'stderr': "sysctl: permission denied", 'stdout': ''}
|
||||
mock_asn_cmd = MagicMock(return_value=asn_cmd)
|
||||
cmd = "sysctl -w net.ipv4.ip_forward=1"
|
||||
mock_cmd = MagicMock(return_value=cmd)
|
||||
with patch.dict(linux_sysctl.__salt__, {'cmd.run_stdout': mock_cmd,
|
||||
'cmd.run_all': mock_asn_cmd}):
|
||||
with patch('salt.utils.fopen', mock_open()) as m_open:
|
||||
helper_open = m_open()
|
||||
helper_open.write.assertRaises(CommandExecutionError,
|
||||
self.assertRaises(CommandExecutionError,
|
||||
linux_sysctl.persist,
|
||||
'net.ipv4.ip_forward',
|
||||
1, config=None)
|
||||
|
@ -72,8 +72,8 @@ class DarwinSysctlTestCase(TestCase):
|
||||
Tests adding of config file failure
|
||||
'''
|
||||
with patch('salt.utils.fopen', mock_open()) as m_open:
|
||||
helper_open = m_open()
|
||||
helper_open.write.assertRaises(CommandExecutionError,
|
||||
m_open.side_effect = IOError(13, 'Permission denied', '/file')
|
||||
self.assertRaises(CommandExecutionError,
|
||||
mac_sysctl.persist,
|
||||
'net.inet.icmp.icmplim',
|
||||
50, config=None)
|
||||
|
@ -141,10 +141,10 @@ class MountTestCase(TestCase):
|
||||
with patch.dict(mount.__grains__, {'kernel': ''}):
|
||||
with patch.object(mount, 'fstab', mock_fstab):
|
||||
with patch('salt.utils.fopen', mock_open()) as m_open:
|
||||
helper_open = m_open()
|
||||
helper_open.write.assertRaises(CommandExecutionError,
|
||||
m_open.side_effect = IOError(13, 'Permission denied:', '/file')
|
||||
self.assertRaises(CommandExecutionError,
|
||||
mount.rm_fstab,
|
||||
config=None)
|
||||
'name', 'device')
|
||||
|
||||
def test_set_fstab(self):
|
||||
'''
|
||||
@ -180,11 +180,7 @@ class MountTestCase(TestCase):
|
||||
|
||||
mock = MagicMock(return_value={'name': 'name'})
|
||||
with patch.object(mount, 'fstab', mock):
|
||||
with patch('salt.utils.fopen', mock_open()) as m_open:
|
||||
helper_open = m_open()
|
||||
helper_open.write.assertRaises(CommandExecutionError,
|
||||
mount.rm_automaster,
|
||||
'name', 'device')
|
||||
self.assertTrue(mount.rm_automaster('name', 'device'))
|
||||
|
||||
def test_set_automaster(self):
|
||||
'''
|
||||
|
@ -11,7 +11,7 @@ from __future__ import absolute_import
|
||||
# Import Salt Testing libs
|
||||
from salttesting import skipIf, TestCase
|
||||
from salttesting.helpers import ensure_in_syspath
|
||||
from salttesting.mock import NO_MOCK, NO_MOCK_REASON
|
||||
from salttesting.mock import NO_MOCK, NO_MOCK_REASON, MagicMock
|
||||
ensure_in_syspath('../../')
|
||||
|
||||
# Import salt libs
|
||||
@ -20,6 +20,10 @@ from salt.modules import portage_config
|
||||
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
class PortageConfigTestCase(TestCase):
|
||||
class DummyAtom(object):
|
||||
def __init__(self, atom):
|
||||
self.cp, self.repo = atom.split("::") if "::" in atom else (atom, None)
|
||||
|
||||
def test_get_config_file_wildcards(self):
|
||||
pairs = [
|
||||
('*/*::repo', '/etc/portage/package.mask/repo'),
|
||||
@ -29,7 +33,11 @@ class PortageConfigTestCase(TestCase):
|
||||
('cat/pkg::repo', '/etc/portage/package.mask/cat/pkg'),
|
||||
]
|
||||
|
||||
portage_config.portage = MagicMock()
|
||||
for (atom, expected) in pairs:
|
||||
dummy_atom = self.DummyAtom(atom)
|
||||
portage_config.portage.dep.Atom = MagicMock(return_value=dummy_atom)
|
||||
portage_config._p_to_cp = MagicMock(return_value=dummy_atom.cp)
|
||||
self.assertEqual(portage_config._get_config_file('mask', atom), expected)
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
@ -85,10 +85,12 @@ class PuppetTestCase(TestCase):
|
||||
with patch('salt.utils.fopen', mock_open()):
|
||||
self.assertTrue(puppet.disable())
|
||||
|
||||
try:
|
||||
with patch('salt.utils.fopen', mock_open()) as m_open:
|
||||
helper_open = m_open()
|
||||
helper_open.write.assertRaises(CommandExecutionError,
|
||||
puppet.disable)
|
||||
m_open.side_effect = IOError(13, 'Permission denied:', '/file')
|
||||
self.assertRaises(CommandExecutionError, puppet.disable)
|
||||
except StopIteration:
|
||||
pass
|
||||
|
||||
def test_status(self):
|
||||
'''
|
||||
@ -145,9 +147,8 @@ class PuppetTestCase(TestCase):
|
||||
self.assertDictEqual(puppet.summary(), {'resources': 1})
|
||||
|
||||
with patch('salt.utils.fopen', mock_open()) as m_open:
|
||||
helper_open = m_open()
|
||||
helper_open.write.assertRaises(CommandExecutionError,
|
||||
puppet.summary)
|
||||
m_open.side_effect = IOError(13, 'Permission denied:', '/file')
|
||||
self.assertRaises(CommandExecutionError, puppet.summary)
|
||||
|
||||
def test_plugin_sync(self):
|
||||
'''
|
||||
|
@ -326,7 +326,7 @@ class UserAddTestCase(TestCase):
|
||||
'''
|
||||
Test the user information
|
||||
'''
|
||||
self.assertEqual(useradd.info('salt'), {})
|
||||
self.assertEqual(useradd.info('username-that-doesnt-exist'), {})
|
||||
|
||||
mock = MagicMock(return_value=pwd.struct_passwd(('_TEST_GROUP',
|
||||
'*',
|
||||
@ -336,9 +336,7 @@ class UserAddTestCase(TestCase):
|
||||
'/var/virusmails',
|
||||
'/usr/bin/false')))
|
||||
with patch.object(pwd, 'getpwnam', mock):
|
||||
mock = MagicMock(return_value='Group Name')
|
||||
with patch.object(useradd, 'list_groups', mock):
|
||||
self.assertEqual(useradd.info('salt')['name'], '_TEST_GROUP')
|
||||
self.assertEqual(useradd.info('username-that-doesnt-exist')['name'], '_TEST_GROUP')
|
||||
|
||||
# 'list_groups' function tests: 1
|
||||
|
||||
|
@ -54,10 +54,18 @@ include('http')
|
||||
|
||||
extend_template = '''#!pyobjects
|
||||
include('http')
|
||||
|
||||
from salt.utils.pyobjects import StateFactory
|
||||
Service = StateFactory('service')
|
||||
|
||||
Service.running(extend('apache'), watch=[{'file': '/etc/file'}])
|
||||
'''
|
||||
|
||||
map_template = '''#!pyobjects
|
||||
from salt.utils.pyobjects import StateFactory
|
||||
Service = StateFactory('service')
|
||||
|
||||
|
||||
class Samba(Map):
|
||||
__merge__ = 'samba:lookup'
|
||||
|
||||
@ -127,6 +135,9 @@ from salt://password.sls import password
|
||||
'''
|
||||
|
||||
requisite_implicit_list_template = '''#!pyobjects
|
||||
from salt.utils.pyobjects import StateFactory
|
||||
Service = StateFactory('service')
|
||||
|
||||
with Pkg.installed("pkg"):
|
||||
Service.running("service", watch=File("file"), require=Cmd("cmd"))
|
||||
'''
|
||||
|
@ -104,6 +104,11 @@ if _has_required_boto():
|
||||
StopLoggingTime=None)
|
||||
|
||||
|
||||
@skipIf(HAS_BOTO is False, 'The boto module must be installed.')
|
||||
@skipIf(_has_required_boto() is False, 'The boto3 module must be greater than'
|
||||
' or equal to version {0}'
|
||||
.format(required_boto3_version))
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
class BotoCloudTrailStateTestCaseBase(TestCase):
|
||||
conn = None
|
||||
|
||||
@ -124,11 +129,6 @@ class BotoCloudTrailStateTestCaseBase(TestCase):
|
||||
session_instance.client.return_value = self.conn
|
||||
|
||||
|
||||
@skipIf(HAS_BOTO is False, 'The boto module must be installed.')
|
||||
@skipIf(_has_required_boto() is False, 'The boto3 module must be greater than'
|
||||
' or equal to version {0}'
|
||||
.format(required_boto3_version))
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
class BotoCloudTrailTestCase(BotoCloudTrailStateTestCaseBase, BotoCloudTrailTestCaseMixin):
|
||||
'''
|
||||
TestCase for salt.modules.boto_cloudtrail state.module
|
||||
|
@ -103,6 +103,11 @@ if _has_required_boto():
|
||||
principal = 'arn:aws:iot:us-east-1:1234:cert/21fc104aaaf6043f5756c1b57bda84ea8395904c43f28517799b19e4c42514'
|
||||
|
||||
|
||||
@skipIf(HAS_BOTO is False, 'The boto module must be installed.')
|
||||
@skipIf(_has_required_boto() is False, 'The boto3 module must be greater than'
|
||||
' or equal to version {0}'
|
||||
.format(required_boto3_version))
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
class BotoIoTStateTestCaseBase(TestCase):
|
||||
conn = None
|
||||
|
||||
@ -123,11 +128,6 @@ class BotoIoTStateTestCaseBase(TestCase):
|
||||
session_instance.client.return_value = self.conn
|
||||
|
||||
|
||||
@skipIf(HAS_BOTO is False, 'The boto module must be installed.')
|
||||
@skipIf(_has_required_boto() is False, 'The boto3 module must be greater than'
|
||||
' or equal to version {0}'
|
||||
.format(required_boto3_version))
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
class BotoIoTPolicyTestCase(BotoIoTStateTestCaseBase, BotoIoTTestCaseMixin):
|
||||
'''
|
||||
TestCase for salt.modules.boto_iot state.module
|
||||
|
@ -101,6 +101,11 @@ def _has_required_boto():
|
||||
return True
|
||||
|
||||
|
||||
@skipIf(HAS_BOTO is False, 'The boto module must be installed.')
|
||||
@skipIf(_has_required_boto() is False, 'The boto3 module must be greater than'
|
||||
' or equal to version {0}'
|
||||
.format(required_boto3_version))
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
class BotoLambdaStateTestCaseBase(TestCase):
|
||||
conn = None
|
||||
|
||||
@ -121,11 +126,6 @@ class BotoLambdaStateTestCaseBase(TestCase):
|
||||
session_instance.client.return_value = self.conn
|
||||
|
||||
|
||||
@skipIf(HAS_BOTO is False, 'The boto module must be installed.')
|
||||
@skipIf(_has_required_boto() is False, 'The boto3 module must be greater than'
|
||||
' or equal to version {0}'
|
||||
.format(required_boto3_version))
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
class BotoLambdaFunctionTestCase(BotoLambdaStateTestCaseBase, BotoLambdaTestCaseMixin):
|
||||
'''
|
||||
TestCase for salt.modules.boto_lambda state.module
|
||||
|
@ -277,6 +277,11 @@ if _has_required_boto():
|
||||
}
|
||||
|
||||
|
||||
@skipIf(HAS_BOTO is False, 'The boto module must be installed.')
|
||||
@skipIf(_has_required_boto() is False, 'The boto3 module must be greater than'
|
||||
' or equal to version {0}'
|
||||
.format(required_boto3_version))
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
class BotoS3BucketStateTestCaseBase(TestCase):
|
||||
conn = None
|
||||
|
||||
@ -297,11 +302,6 @@ class BotoS3BucketStateTestCaseBase(TestCase):
|
||||
session_instance.client.return_value = self.conn
|
||||
|
||||
|
||||
@skipIf(HAS_BOTO is False, 'The boto module must be installed.')
|
||||
@skipIf(_has_required_boto() is False, 'The boto3 module must be greater than'
|
||||
' or equal to version {0}'
|
||||
.format(required_boto3_version))
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
class BotoS3BucketTestCase(BotoS3BucketStateTestCaseBase, BotoS3BucketTestCaseMixin):
|
||||
'''
|
||||
TestCase for salt.modules.boto_s3_bucket state.module
|
||||
|
@ -20,6 +20,7 @@ def provision_state(module, fixture):
|
||||
|
||||
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
@skipIf(True, 'Skipped: This module has been deprecated.')
|
||||
class DockerStateTestCase(TestCase):
|
||||
def test_docker_run_success(self):
|
||||
from salt.states import dockerio
|
@ -1367,26 +1367,6 @@ class FileTestCase(TestCase):
|
||||
(name, source,
|
||||
preserve=True), ret)
|
||||
|
||||
with patch.object(os.path, 'isdir', mock_t):
|
||||
with patch.dict(filestate.__opts__, {'test': False}):
|
||||
with patch.object(shutil, 'copy',
|
||||
MagicMock(side_effect=[IOError,
|
||||
True])):
|
||||
comt = ('Failed to copy "{0}" to "{1}"'
|
||||
.format(source, name))
|
||||
ret.update({'comment': comt, 'result': False})
|
||||
self.assertDictEqual(filestate.copy
|
||||
(name, source,
|
||||
preserve=True), ret)
|
||||
|
||||
comt = ('Copied "{0}" to "{1}"'.format(source,
|
||||
name))
|
||||
ret.update({'comment': comt, 'result': True,
|
||||
'changes': {name: source}})
|
||||
self.assertDictEqual(filestate.copy
|
||||
(name, source,
|
||||
preserve=True), ret)
|
||||
|
||||
# 'rename' function tests: 1
|
||||
|
||||
def test_rename(self):
|
||||
|
@ -150,16 +150,17 @@ class NetworkTestCase(TestCase):
|
||||
interfaces = network._interfaces_ifconfig(SOLARIS)
|
||||
self.assertEqual(interfaces,
|
||||
{'ilbext0': {'inet': [{'address': '10.10.11.11',
|
||||
'broadcast': '10.10.11.31',
|
||||
'netmask': '255.255.255.224'},
|
||||
{'address': '10.10.11.12',
|
||||
'broadcast': '10.10.11.31',
|
||||
'netmask': '255.255.255.224'}],
|
||||
'inet6': [{'address': '::',
|
||||
'prefixlen': '0'}],
|
||||
'inet6': [],
|
||||
'up': True},
|
||||
'ilbint0': {'inet': [{'address': '10.6.0.11',
|
||||
'broadcast': '10.6.0.255',
|
||||
'netmask': '255.255.255.0'}],
|
||||
'inet6': [{'address': '::',
|
||||
'prefixlen': '0'}],
|
||||
'inet6': [],
|
||||
'up': True},
|
||||
'lo0': {'inet': [{'address': '127.0.0.1',
|
||||
'netmask': '255.0.0.0'}],
|
||||
@ -174,8 +175,7 @@ class NetworkTestCase(TestCase):
|
||||
'up': True},
|
||||
'vpn0': {'inet': [{'address': '10.6.0.14',
|
||||
'netmask': '255.0.0.0'}],
|
||||
'inet6': [{'address': '::',
|
||||
'prefixlen': '0'}],
|
||||
'inet6': [],
|
||||
'up': True}}
|
||||
)
|
||||
|
||||
|
@ -523,11 +523,6 @@ class UtilsTestCase(TestCase):
|
||||
datetime.datetime.now.return_value = now
|
||||
self.assertEqual(now, utils.date_cast(None))
|
||||
self.assertEqual(now, utils.date_cast(now))
|
||||
try:
|
||||
ret = utils.date_cast('Mon Dec 23 10:19:15 MST 2013')
|
||||
expected_ret = datetime.datetime(2013, 12, 23, 10, 19, 15)
|
||||
self.assertEqual(ret, expected_ret)
|
||||
except ImportError:
|
||||
try:
|
||||
ret = utils.date_cast('Mon Dec 23 10:19:15 MST 2013')
|
||||
expected_ret = datetime.datetime(2013, 12, 23, 10, 19, 15)
|
||||
|
Loading…
Reference in New Issue
Block a user