查看模块
salt '*' sys.list_modules
模块名 | 描述 |
管理aliases file信息 | |
salt.modules.alternatives | |
管理apace模块 | |
APT(Advanced Packaging Tool)支持 | |
压缩(archive)支持 | |
at支持 | |
通过augeas管理配置文件 | |
管理Bluetooth(使用Bluez) | |
Mac OS X的Homebrew支持 | |
指定butter云组件路由 | |
Cassandra NoSQL数据库模块 | |
A module for shelling out | |
返回配置信息 | |
minion端salt-cp支持 | |
cron支持 | |
daemontools服务模块 | |
管理minion本地持久化的数据结构 | |
Debconf支持 | |
Debian系列系统服务支持 | |
管理磁盘信息 | |
管理django站点 | |
管理dnqmasq模块 | |
dns通用管理工具 | |
用于支持DEB 分发版本的包管理 | |
另外一个包管理 | |
eix 支持 | |
Fire events on the minion, events can be fired up to the master | |
管理ex2/3/4文件系统]] | |
管理minion的文件信息,设置或读取文件属组、权限等 | |
管理FreeBSD jail环境 | |
管理FreeBSD 内核 | |
FreeBSD package管理支持 | |
管理FreeBSD服务 | |
FreeBSD sysctl管理支持 | |
管理ruby gem | |
Gentoolkit支持 | |
管理gentoo服务 | |
git SCM支持 | |
Module for handling openstack glance calls. | |
grains数据控制 | |
管理Linux和OpenBSD组 | |
GRUB Legacy支持 | |
通过libguestfs管理虚拟机镜像 | |
Mercurial SCM支持 | |
管理hosts文件 | |
虚拟机镜像管理 | |
iptables支持 | |
posix-like系统键盘管理模块 | |
minion key信息支持 | |
openstack keystone调用管理 | |
Linux内核管理模块 | |
Provide the hyper module for kvm hypervisors | |
Mac OSX launchd/launchctl管理支持 | |
Layman支持 | |
ldap管理支持 | |
Linux文件访问控制支持 | |
Linux LVM2支持 | |
Linux sysctl管理支持 | |
posix-like系统locale支持 | |
locate工具管理 | |
logrotate管理支持 | |
Support for modifying make.conf under Gentoo | |
使用mdadm工具管理RAID arrary | |
mongodb管理支持 | |
monit模块 | |
moosefs管理支持 | |
管理UNIX mount及fstab文件 | |
Run munin plugins/checks from salt and format the output as data | |
mysql管理支持 | |
收集和管理网络信息 | |
NFS3管理模块 | |
nginx管理 | |
openstack nova调用管理 | |
Manage and query NPM packages | |
nzbget支持 | |
OpenBSD包管理 | |
OpenBSD服务管理 | |
Mac OS X implementations of various commands in the "desktop" interface | |
Arch pacman管理 | |
pam管理 | |
posix-like系统分区管理parted支持 | |
PHP pecl扩展支持 | |
minion pillar数据管理 | |
系统python或virtualenv pip管理 | |
pkgng支持 | |
Resources needed by pkg providers | |
Solaris Pkgutil支持 | |
Postgres数据库管理支持 | |
poudriere支持 | |
A salt interface to psutil, a system and process library | |
Publish a command from a minion to a target | |
puppet管理支持 | |
FreeBSD组管理 | |
FreeBSD用户管理 | |
qemu镜像命令管理 | |
qemu命令管理 | |
quotaposix-like系统quota管理 | |
rabbitmq管理 | |
Windows注册表管理 | |
Module to integrate with the returner system and retrieve data sent to a salt | |
RHEL/Fedora网络管理 | |
类RHEL服务管理 | |
rpm支持 | |
Manage ruby installations and gemsets with RVM, the Ruby Version Manager | |
Amazon S3支持 | |
The Saltutil module is used to manage the state of the salt minion itself | |
selinux调用管理 | |
服务管理 | |
管理shadow文件 | |
Solaris 10和11服务管理模块 | |
Solaris组管理 | |
Solaris包管理 | |
Solaris shadow文件管理 | |
Solaris用户管理 | |
solr模块支持 | |
SQLite3支持 | |
管理ssh客户端 | |
管理minion state | |
返回minion各种状态 | |
Provide the service module for supervisord | |
Subversion SCM | |
sysbench支持 | |
he sys module provides information about the available functions on the minion | |
systemd服务管理 | |
支持关机、重启等 | |
Module for running arbitrary tests | |
posix-like系统timezone管理 | |
SSL/TLS模块 | |
tomcat支持 | |
Module for the management of upstart systems | |
libvirt管理支持 | |
创建python virtualenv环境 | |
收集Windows磁盘信息 | |
管理Windows minion文件信息 | |
管理Windows组 | |
管理Windows网络信息 | |
Windows包管理 | |
Windows服务管理 | |
Windows shadow管理 | |
返回Windows minion各种信息 | |
Windows用户管理 | |
YUM支持 | |
YUM支持 | |
ZFS支持 | |
OpenSUSE zypper包管理支持 |
二 模块及api
import salt.client
client = salt.client.LocalClient()
ret = client.cmd('*','test.ping')
print ret
(1) Archive模块
1)功能:实现系统层面的压压缩包调用,支持gunzip,gzip,rar,tar,unrar,unzip等。
2)示例:
(2)cmd模块
1)功能:实现远程的命令行调用执行(默认具备root操作权限,使用时需要评估风险)
2)示例:
复制代码
#获取所有被控主机的内存使用情况
[root@hzbj-salt-020 ~]# salt '*' cmd.run "free -m"
hzbj-tomcat-022:
total used free shared buffers cached
Mem: 980 715 264 0 55 476
-/+ buffers/cache: 184 796
Swap: 1983 0 1983
hzbj-tomcat-021:
total used free shared buffers cached
Mem: 980 884 95 0 25 206
-/+ buffers/cache: 652 327
Swap: 1983 11 1972
#在hzbj-tomcat-022主机运行test.sh脚本,其中scripts/test.sh存放在file_roots指定的目录,
#改命令会做两个动作:首选同步test.sh到minion的cache目录(如同步到/var/cache/salt/ #minion/files/base/script/test.sh):其次运行改脚本
[root@hzbj-salt-020 ~]# salt 'hzbj-tomcat-01' cmd.script salt://script/test.sh
3)API调用
client.cmd('hzbj-tomcat-021','cmd.run',['free -m'])
(3)cp模块
1)功能:实现远程文件,目录的复制,以及下载URL文件等操作
2)示例:
将注服务器file_roots指定位置下的目录复制到被控主机
salt '*' cp.get_dir salt://path/to/dir /minion/dest
将主服务器file_roots指定文职下的文件复制到被控主机
salt '*' cp.get_file salt://path/to/file /minion/dest
下载URL内容到被控主机指定位置
salt '*' cp.get_url http://www.salshdot.org /tmp/index.html
3)API调用
client.cmd('hzbj-tomcat-021','cp.get_file',['salt://path/to/file','/minion/dest'])
(4)cron模块
1)功能:实现被控主机的crontab操作
2)示例
复制代码
查看指定被控主机,root用户的crontab清单
[root@hzbj-salt-020 salt]# salt 'hzbj-tomcat-021' cron.raw_cron root
hzbj-tomcat-021:
*/2 * * * * ntpdate pool.ntp.org &>/dev/null
*/1 * * * * cd /usr/local/gse/; ./cron_gse.sh 1>/dev/null 2>&1
#指定的被控主机,root用户添加/usr/local/weekly任务作业
[root@hzbj-salt-020 salt]# salt 'hzbj-tomcat-021' cron.raw_cron root
hzbj-tomcat-021:
*/2 * * * * ntpdate pool.ntp.org &>/dev/null
*/1 * * * * cd /usr/local/gse/; ./cron_gse.sh 1>/dev/null 2>&1
# Lines below here are managed by Salt, do not edit
* * * * 1 /usr/local/weekly
#删除指定的被控主机,root用户添加/usr/local/weekly任务作业
[root@hzbj-salt-020 salt]# salt 'hzbj-tomcat-021' cron.rm_job root /usr/local/weekly
hzbj-tomcat-021:
removed
注解: 如果需要写入sls文件里面
<span style="font-family: 宋体">/usr/sbin/ntpdate pool.ntp.org >>/dev/null 2>&1:
cron.present:
- user: root
- minute: 10</span>
<span style="font-family: 宋体">minute #分钟
hour #小时
daymonth #日
month #月
dayweek #0~6是周一到周六,周日是7</span>
默认执行用户“root”,时间不填写默认是“*”,周期执行“*/2”,随机执行“random”,identifier 是任务标识符,类似于任务ID,更改任务时指定“标识符”可方便修改
3)API调用
client.cmd('hzbj-tomcat-021','cron.set_job',['root','*','*','*','*','*','/usr/echo'])
(5)dnsutil模块
1)功能:实现被控主机通用DNS相关操作。
2)示例:
[root@hzbj-salt-020 ~]# salt '*' dnsutil.hosts_append /etc/hosts 127.0.0.1 ad1.yuk.com
删除指定被控主机hosts的主机批准
[root@hzbj-salt-020 ~]# salt '*' dnsutil.hosts_remove /etc/hosts ad1.yuk.com
3)API调用
client.cmd('hzbj-tomcat-021','dnsutil.hosts_append',['/etc/hosts','127.0.01','ad1.yuk.co'])
(6)file模块
1)功能:被控主机文件操作,包括文件读写,权限,查找,校验等。
(9)pkg包管理模块
1)功能:被控主机程序包管理,如yum,apt-get
2)示例:
复制代码
#为所有被控主机安装PHP环境,根据不同系统发现版调用不同安装工具进行部署,如redhat
平台的yum,等价于yum -y install php
salt '*' pkg.install php
#卸载所有被控主机的PHP
salt '*' pkg.remove php
#升级所有被控主机的软件包
salt '*' pkg.upgrade
复制代码
3)API调用
client.cmd('hzbj-tomcat-021','pkg.remove',['php'])
(10)Service服务模块
1)功能:被控主机程序包服务管理
2)示例:
复制代码
#开启(enable),禁用(disable)nginx开机自启动服务
salt '*' service.enable nginx
salt '*' service.disable nginx
#针对nginx服务的reload,restart,start,stop,ss操作
salt '*' service.reload nginx
salt '*' service.restart nginx
salt '*' service.start nginx
salt '*' service.stop nginx
salt '*' service.status nginx
3)API调用
client.cmd('hzbj-tomcat-021','service.stop',['nginx'])
(11) User模块
user.present
user.present: 确保指定的账户名存在,并指定其对应的属性. 这些属性包括如下内容:
name: 指定需要管理的账户名.
uid: 指定uid, 如果不设置将配自动分配下一个有效的uid.
gid: 指定默认的组id(group id)
gid_from_name: 如果设置为_True_,默认的组id将自动设置为和本用户同名的组id
groups: 分配给该用户的组列表(a list of groups). 如果组在minion上不存在,则本state会报错. 如果设置会空,将会删除本用户所属的除了默认组之外的其他组
optional_groups: 分配给用户的组列表。 如果组在minion上不存在,则state会忽略它.
home: 关于用户的家目录(home directory).
password: 设置用户hash之后的密码.
enforce_password: 当设置为_False_时,如果设置的_password_与用户原密码不同,将保持原密码不做更改.如果没有设置_password_选项,该选项将自动忽略掉.
shell: 指定用户的login shell。 默认将设置为系统默认shell。
unique: UID唯一,默认为True.
system: 从_FIRST_SYSTEM_UID_和_LAST_SYSTEM_UID_间选择一个随机的UID.
user.absent
本部分为译者依据官方手册进行的补充,原文中并没有相关内容
user.absent 用于删除用户.其有以下选项:
name: 指定需要删除的用户名.
purge: 设置清除用户的文件(家目录)
force: 如果用户当前已登录,则absent state会失败. 设置_force_选项为True时,就算用户当前处于登录状态也会删除本用户.
当管理用户时,至少需要指定_user.present_或_user.absent_。 其他选项是可选的,比如_uid_、gid、_home_等选项没有指定是,将自动使用下一个有效的或者系统默认的.
例子:
如果需要设置密码 首选hash密码
openssl passwd -1 -salt 'cedwards'
创建用户
# cat cedwards.sls
cedwards:
user.present:
- fullname: Christer Edwards
- password: '$1$cedward$KcHcszCMgNJkDwSID7QRH.'
- shell: /bin/bash
- home: /home/cedwards
- uid: 1002
- gid: 1002
- groups:
- wheel
删除用户
# cat userdel.sls
cedwards:
user.absent:
- purge: Ture
- force: Ture
批量创建用户
# cat useradd.sls
{% set users = ['jim','hwg','hyxc'] %}
{% for user in users %}
{{ user }}:
user.present:
- shell: /bin/bash
- home: /home/{{ user }}
- password: '$1$cedwards$Sy0q724HkzgJsIWMsQIkq.'
{% endfor %}
常用模块:cmd, cron, file, mount, ntp, pkg, service, user, group
##先看一个简单的例子:
salt:
pkg.latest:
- name: salt
service.running:
- names: #多个值,一行一个,且为names,复数
- salt-master
- salt-minion
- require:
- pkg: salt
- watch:
- file: /etc/salt/minion
/etc/salt/minion:
file.managed:
- source: salt://salt/minion
- user: root
- group: root
- mode: 644
- require:
- pkg: salt
##一个小的注意:
/dbdata:
file.directory: #如果只有一个函数,这样写是错误的
要改成:
/dbdata:
file:
- directory
cmd模块:
name:要执行的命令,记住该命令将会在salt-minion的路径和权限下执行
onlyif:用于检查的命令,仅当``onlyif``选项指向的命令返回true时才执行name定义的命令
unless:用于检查的命令,仅当``unless``选项指向的命令返回false时才执行name指向的命令
cwd:执行命令时的当前工作目录,默认是/root
user:以指定用户身份运行命令
group:以指定用户组身份运行命令
shell:用于执行命令的shell,默认shell grain
run:运行name后的命令
[root@test81 ~]# cat install.sls
nginx_source:
file.managed:
- name: /tmp/nginx-1.4.5.tar.gz
- unless: test -f /tmp/nginx-1.4.5.tar.gz ##若minion端不存在/tmp/nginx-1.4.5.tar.gz这个文件,才会执行这个file模块
- source: salt://nginx/files/nginx-1.4.5.tar.gz
tar_nginx:
cmd.run:
- cwd: /usr/local/src ##当前工作目录
- name: tar zxvf nginx-1.4.5.tar.gz
- unless: test -d /usr/local/src/nginx-1.4.5 ##若minion端不存在/usr/local/src/nginx-1.4.5 这个目录,才会执行name后命令
- require:
- file: nginx_source
##unless:后面的条件不满足(条件为假)时才会执行
##onlyif:条件为真时执行
ntpdate_cron:
cron:
- present
- name: /usr/sbin/ntpdate pool.ntp.org
- minute: '*/30'
- require:
- cmd: isntp
isntp:
cmd:
- run
- name: yum -y install ntp
- unless: test ! -z `rpm -qa ntp` ##反逗点调用shell命令(tab键上面那个)
cron模块:
minute:分
hour:时
daymonth:日
month:月
dayweek:周
user:用户名
present:创建计划任务
name:计划任务内容
[root@scj cron]# cat cron.sls
mysql_cron:
cron:
- present
- name: cd /tmp/scripts;./mysql_backup.sh
- user: root
- minute: 0
- hour: 1
#- daymonth:
#- month:
#- dayweek:
#- minute: "*/5"
##修改计划任务:
##如上面的例子:
mysql_cron:
cron:
- present
- name: cd /tmp/scripts;./mysql_backup.sh
- user: root
- minute: 0
- hour: 2 #将1改为2
#- daymonth:
#- month:
#- dayweek:
#- minute: "*/5"
注意:以name后面的命令为主
可以理解为name后面的命令是唯一键
若把name后面的命令改了,则是重新创建了一个计划任务
##删除一个计划任务:
##如上面的例子:
mysql_cron:
cron:
- absent ##absent删除计划任务
- name: cd /tmp/scripts;./mysql_backup.sh ##只要保证name后命令不变,能匹配到
- user: root
- minute: 0
- hour: 2
#- daymonth:
#- month:
#- dayweek:
#- minute: "*/5"
file模块:
注意:只有file模块里才可以使用template函数
.sls文件1:
/tmp/salt/:
file:
- directory #目录不存在,则创建目录
- name: /tmp/salt/
- user: nobody
- group: nobody
- file_mode: 644 #与recurse递归函数一起用
- dir_mode: 755 #文件权限644,目录权限755
- makedirs: True
- recurse: #递归目录权限,包括用户和权限
- user #若本来此目录就存在,且此目录下有很多文件,则recurse函数会把此目录和目录下的所有文件的权限都修改(nobody 644 755)
- group
- mode #文件644,目录755,就是上面的file_mode和dir_mode
#- ignore_files #忽略文件
#- ignore_dirs
/tmp/salt/file:
file:
- managed #创建文件
- name: /tmp/salt/file
- source: salt://web/files/httpd.conf
- user: nobody
- group: nobody #若此文件本来就存在,则会修改此文件的权限(nobody 644)
- mode: 644
#- backup: minion
#- template: jinja #调用pillar变量和grains变量
- require:
- file: /tmp/salt/
.sls文件2:
{% set site_user = 'testuser' %} #定义变量
{% set site_name = 'test_site' %}
{% set project_name = 'test_proj' %}
{% set sites_dir = 'test_dir' %}
django-project:
file.recurse:
- name: {{ sites_dir }}/{{ site_name }}/{{ project_name }}
- user: {{ site_user }} #直接调用变量
- dir_mode: 2775
- file_mode: '0644'
- template: jinja #指定template: jinja
- source: salt://project/templates_dir
- include_empty: True
.sls文件3:
/etc/http/conf/http.conf:
file.managed:
- source: salt://apache/http.conf
- user: root
- group: root
- mode: 644
- template: jinja
- defaults: #默认变量,多个一行一个
custom_var: "default value" #这些变量将会在salt://apache/http.conf这个文件里使用
other_var: 123
{% if grains['os'] == 'Ubuntu' %} ##if语句要定格##
- context: #以context下的变量为准,没有时再用defaults下的变量
custom_var: "override" #这里以这个变量为准,defaults里的是无效的
{% endif %}
.sls文件4:
/tmp/dir1/file1:
file:
- managed
- makedirs: True
##若minion端没有dir1目录,使用makedirs函数可以直接创建dir1目录,再创建file1文件
group模块:
absent:删除用户组
name:与absent一起用,则是删除的用户组名
present:管理用户组,不存在则创建;存在则管理其属性
name:与present一起用,则是被管理的用户组名
##下面的属性全都是与present一起用的##
gid:组ID分配给命名组;如果留空,那么下一个可用的组ID将被分配
system:命名组是否是一个系统组,这本质上是groupadd“-r”选项
addusers:添加更多的用户列表作为组成员
delusers:确保这些用户从组成员中删除
members:用新成员的名单替换现有组成员。
##注:选项'members'和'adduser/delusers'是相互排斥的,不能一起使用
cheese:
group.present: #用户组不存在,则创建;若存在,则管理,包括将用户添加到此组中或将用户从组中移除
- gid: 7648
- system: True
- addusers:
- user1 #将user1添加到组中
- users2
- delusers:
- foo
cheese:
group.present:
- gid: 7648
- system: True
- members: #只有这4个用户属于这个组
- foo
- bar
- user1
- user2
iptables模块:
http://docs.saltstack.cn/zh_CN/latest/ref/states/all/salt.states.iptables.html#module-salt.states.iptables
lvm模块:
/dev/sda:
lvm:
- pv_present #创建pv
#-name: /dev/sda
my_vg:
lvm.vg_present: #创建vg
- devices: /dev/sda #指定pv
lvroot:
lvm.lv_present:
- vgname: my_vg #指定vg
- name: lvroot
- size: 10G
#- stripes: 5
#- stripesize: 8K
mount模块:
/mnt/sdb: #标识,没有name函数则表示挂载点
mount.mounted:
- device: /dev/sdb1 #挂载的设备名
#- name: /mnt/sdb #挂载点
- fstype: ext4
- mkmnt: True #挂载点不存在则自动创建,最好将其设置为True
- opts:
- defaults
/srv/bigdata:
mount:
- mounted:
- device: UUID=066e0200-2867-4ebe-b9e6-f30026ca2314
- fstype: xfs
- opts: nobootwait,noatime,nodiratime,nobarrier,logbufs=8
#- dump: 0 #默认是0
#- pass_num: 2 #默认是0
#- persist: True #是不是将其写入/etc/fstab文件里,默认是True,写入
- mkmnt: True
##dump: The dump value to be passed into the fstab, Default is 0
##pass_num: The pass value to be passed into the fstab, Default is 0
pkg模块:
mypkgs:
pkg.installed:
- pkgs: #安装多个软件包,用pkgs函数,一行一个
- gcc
- cmake
- make
#- name: httpd #安装的软件包名,与pkgs一起用时,此函数将被忽略
##installed:安装软件包
##latest:将软件更新到最新
##removed:卸载软件包
##pkgs:安装多个软件包时,一次全部安装(推荐)
##names:安装多个软件包时,一次安装一个,需安装多次(不推荐)
service模块:
httpd:
service:
- running #使服务处于运行状态
- enable: True #设置开机自动启动
- reload: True #watch函数下监控的/etc/httpd/conf/httpd.conf文件发生变化,则会重新加载reload;若reload函数不存在或reload值为False,则会重新启动restart
- watch:
- file: /etc/httpd/conf/httpd.conf
- require:
- pkg: httpd
##dead:使服务处于stop状态
##reload值为True:
ID: httpd
Function: service.running
Result: True
Comment: Service reloaded ##reload服务
Started: 14:56:31.920445
Duration: 1702.923 ms
Changes:
----------
httpd:
True
##不存在reload函数或reload值为False:
ID: httpd
Function: service.running
Result: True
Comment: Service restarted ##restart服务
Started: 14:58:05.723261
Duration: 1193.026 ms
Changes:
----------
httpd:
True
user模块:
user1:
user:
- present
#- name: user1
#- home: /home/user1
#- shell: /bin/bash
- uid: 600
- gid: 600
- system: True #设置为系统用户
- groups: #设置用户的所属组
- nobody #把user1用户加入到nobody组中,且仅属于nobody组;如果用户原本在jeff组中,执行后用户只在nobody组中,不再属于jeff组了
#- group1
##absent:删除用户
##force:强制删除用户(即便用户正在登陆)
实例:
公司来新的员工,需要在所有的服务器上添加一个普通账号:
##先创建MD5加密密码
[root@dbm133 ~]# openssl passwd -1 -salt 'shencj' ##用户名,如这个shencj用户可以不存在;但是必须和下面创建的新用户对应
Password: ##输入密码
$1$shencj$i3JtzHYM7hFcNP63VLK..1 ##生成的加密密码
##定义pillar变量
[root@dbm133 ~]# cat /srv/pillar/user/init.sls
username: shencj
password: '$1$shencj$i3JtzHYM7hFcNP63VLK..1'
##创建state的.sls文件
[root@dbm133 ~]#cat /srv/salt/user/adduser.sls
{{ pillar['username'] }}:
user:
- present
# - uid: 1001
# - gid: 1001
- password: {{ pillar['password'] }}
- groups:
- nobody
/home/{{ pillar['username'] }}/.ssh:
file:
- directory
- require:
- user: {{ pillar['username'] }}
/home/{{ pillar['username'] }}/.ssh/authorized_keys:
file:
- managed
- source: salt://files/authorized_keys
- mode: 400
- user: {{ pillar['username'] }}
- group: {{ pillar['username'] }}
- require:
- file: /home/{{ pillar['username'] }}/.ssh
##master端数据推送
[root@dbm133 ~]# salt '*' state.sls user.adduser
salt数据同步方式
方式一:
minion自动向master进行数据同步:
默认是60秒自动同步一次数据
自动同步时间间隔由参数loop_interval来决定(minion端)
[root@scj salt]# grep loop_interval /etc/salt/minion
# The loop_interval sets how long in seconds the minion will wait between
#loop_interval: 60
如果我们想让minion永远不要自动同步,可以把这个参数值改大一点
loop_interval: 3153600000 (设置100年同步一次)
方式二:
master端通过执行命令进行数据同步:
检测配置是否正确,并没有真正的推送数据:
salt '*' state.highstate -v test=true
salt '*' state.highstate -v test=True
注意:远程执行命令时 -v test=true 参数是不起作用的
salt "*" cmd.run "yum -y install man" -v test=true (minion机仍然会安装man软件包,远程执行命令时没有必要检测)
向所有minion推送所有数据:
salt '*' state.highstate
向某一台minion推送所有数据:
salt '192.168.186.129' state.highstate
向某一个分组推送所有数据:
salt -N 'BJwebgroup' state.highstate
向所有minion只推送web这个模块目录的数据
salt '*' state.sls web
注意:
[root@scj salt]# cat top.sls
base:
'BJwebgroup':
- match: nodegroup
- web
向所有minion只推送web模块下面的httpd.sls文件:
salt '*' state.sls web.httpd
注意:
[root@scj web]# pwd
/srv/salt/web
[root@scj web]# ls
files httpd.sls init.sls
向所有minion只推送web模块下面php目录下面的conf.sls文件:
salt '*' state.sls web.php.conf
注意:
[root@scj php]# pwd
/srv/salt/web/php
[root@scj php]# ls
conf.sls
向所有minion直接执行某个命令:
salt "*" cmd.run "yum -y install man"
附加:
salt常用命令:
salt '*' grains.ls 查看grains所有分类
salt '*' grains.items 查看grains所有信息
salt '*' grains.item os 查看grains某个分类信息
salt '*' pillar.items 查看pillar所有信息
salt '*' pillar.item users 查看pillar某个信息
[root@scj salt]# salt '*' grains.item os
192.168.186.129:
----------
os:
CentOS
[root@scj salt]# salt '*' grains.item fqdn
192.168.186.129:
----------
fqdn:
scj.51.com
[root@scj salt]# salt '*' grains.item host
192.168.186.129:
----------
host:
scj
salt '匹配正则' state.highstate
匹配正则
[root@scj salt]# salt '*' state.highstate
salt -N 'GroupName' state.highstate
指定某个组
[root@scj salt]#salt -N 'BJwebgroup' state.highstate
salt -L 'minion1,minion2,minion3' state.highstate 指定多个minion
[root@scj salt]# salt -L '192.168.186.129,192.168.186.128' state.sls web.php.conf
salt -G 'os:CentOS' test.ping 指定操作系统是CentOS的所有minion
salt-cp "*" /root/file1 /tmp/ (远程复制:将master机上 /root/file1 复制到minion机的 /tmp/ 目录下)
salt '*' cmd.script /usr/local/script/iptables.sh (执行某个脚本,这个脚本在master机上)
salt '*' cmd.run 'hostname' (对minion机远程执行某个命令)
[root@dbm133 ~]# salt '*' cp.get_file salt://web/httpd/httpd.sls /tmp/httpd.sls
[root@dbm133 ~]# salt '*' cp.get_dir salt://web/httpd /tmp/ ##把httpd目录拷贝到/tmp下
cp.get_file可以用来在minion端下载master上的文件。
salt '*' cp.get_file salt://vimrc /etc/vimrc
这个会通知所有的minion客户端来下载vimrc文件到/etc/vimrc
salt '*' cp.get_file "salt://{{grains.os}}/vimrc" /etc/vimrc template=jinja
也可以用模版,表示只在OS系统名称一样的机器上下载文件
salt '*' cp.get_file salt://vimrc /etc/vimrc gzip=5
salt在传输大文件时还支持压缩:压缩比率是1-9
salt '*' cp.get_file salt://vimrc /etc/vim/vimrc makedirs=True
cp.get_file默认是不会创建目的端的目录的,如果该目录不存在的时候。要改变这种情况可以使用mkaedirs参数
salt '*' cp.get_dir salt://etc/apache2 /etc
salt '*' cp.get_dir salt://etc/{{pillar.webserver}} /etc gzip=5 template=jinja
cp.get_dir和cp.get_file一样,不过get_dir是用来下载整个目录的,也支持模版和压缩
注意:使用cp.get_file从master拷贝文件到客户端,使用cp.get_dir拷贝目录到客户端
拷贝的文件或目录必须在salt配置的根目录下,即:/srv/salt
把文件拷到客户端/tmp目录下,必须写成/tmp/httpd.sls,完整路径文件
第一部分:
file_roots配置管理的目录结构:
前提:
使用配置管理的目录结构,首先要在配置文件里配置:
vi /etc/salt/master
找到file_roots,大约在31行
添加:
file_roots:
base:
- /srv/salt
mkdir -p /srv/salt
/etc/init.d/salt-master restart
注意:由上面的配置可以看出,配置管理的根目录是/srv/salt
分析:
下面分析配置管理/srv/salt的目录结构:
[root@scj salt]# cd /srv/salt
[root@scj salt]# tree
.
├── top.sls
└── web
├── httpd.sls
├── init.sls
└── php
└── conf.sls
1、 入口文件top.sls:
在/srv/salt/目录下面有个入口文件top.sls,当master服务启动后,master进程会首先去读取这个入口文件
[root@scj salt]# cat top.sls
base:
'*':
- web
第一行:是top.sls文件的固定写法
第二行:指定要管理的minion机,*代表所有的minion机(一定要用引号引起来),若只管理一台minion机,则可以指定其ip,如:'192.168.186.129'
第三行:指定要读取的模板,定义一个web模板(即在/srv/salt/目录下创建一个web目录),可以定义多个模板目录
注意:第一行和第二行后面有冒号
第二行指定要管理的minion机,可以通过正则,grain模块或分组名来进行匹配,如下:
通过正则进行匹配:
base:
'*':
- web
通过分组进行匹配:必须要有 - match: nodegroup
base:
'BJwebgroup':
- match: nodegroup
- web
通过grain模块匹配:必须要有- match: grain
base:
'os:CentOS':
- match: grain
- web
2、 模块目录:
在入口文件top.sls定义了一个web模块目录,因此我们要创建一个web目录:
[root@scj salt]# pwd
/srv/salt
[root@scj salt]# mkdir web
[root@scj salt]# cd web/
[root@scj web]# vi init.sls
include:
- web.httpd
- web.php.conf
注意:init.sls文件可以简单的看作是模块的入口文件
在调用模块时会首先读取这个init.sls文件,因此一定要创建这个init.sls文件
第一行:固定用法,指:调用下面定义的文件
第二行:调用web模块目录下面的httpd.sls文件(因此在web目录下有个httpd.sls文件)
第三行:调用web模块目录下php目录下面的conf.sls文件(因此在web目录下有个php目录,在php目录下有个conf.sls文件)
[root@scj web]# pwd
/srv/salt/web
[root@scj web]# ls
httpd.sls init.sls php
如上:我们需要创建一个httpd.sls文件,mkdir一个php目录
例子1:
[root@dbm133 salt]# tree
.
├── web
│?? └── httpd
│?? └── httpd.sls
├── top.sls
[root@dbm133 salt]# cat top.sls
base:
'*':
- web.httpd.httpd
首先读取top.sls文件,去找配置根目录下web目录下httpd目录下的httpd.sls文件,
(没有httpd.sls文件,再去找配置根目录下web目录下httpd目录下httpd目录下的init.sls文件)
都没有则报错
例子2:
[root@dbm133 salt]# tree
.
├── top.sls
└── web
├── httpd
│?? └── httpd.sls
└── init.sls
[root@dbm133 salt]# cat top.sls
base:
'*':
- web
[root@dbm133 salt]# cat web/init.sls
include:
- web.httpd.httpd
读取top.sls文件,先去找配置根目录下的web.sls文件;
若没有web.sls文件,则再去找配置根目录下web目录下的init.sls文件,
若init.sls文件不存在则报错
例子3:
[root@dbm133 salt]# tree
.
├── db
│?? └── db
│?? └── db.sls
├── top.sls
└── web
├── httpd
│?? └── httpd.sls
└── init.sls
[root@dbm133 salt]# cat top.sls
base:
'*':
- web
[root@dbm133 salt]# cat web/init.sls
include:
- web.httpd.httpd
- db.db.db
例子4:
[root@dbm133 salt]# tree
.
├── db
│?? └── db
│?? └── db.sls
├── top.sls
└── web
├── httpd
│?? └── httpd.sls
└── init.sls
[root@dbm133 salt]# cat top.sls
base:
'*':
- web
[root@dbm133 salt]# cat web/init.sls
include:
- web.httpd.httpd
[root@dbm133 salt]# cat web/httpd/httpd.sls
include:
- db.db.db
/tmp/scj/file3:
file:
- managed
通过入口文件top.sls文件,init.sls文件和include关键字,把所有的.sls文件结合了起来;
注意文件的读取顺序
第二部分:
pillar_roots的目录结构:
pillar的目录结构与上面state的file_roots的目录结构一模一样
3、 简单看下几个.sls文件的内容:
[root@scj web]# cat httpd.sls
httpd:
pkg:
- installed
httpd:
service:
- running
- reload: True
- enable: True
- watch:
- file: /tmp/salt/httpd.conf
- require:
- pkg: httpd
/tmp/salt/httpd.conf:
file:
- managed
- source: salt://web/files/httpd.conf
- require:
- pkg: httpd
pillar:
salt一个非常重要的组件,它用于给特定的minion定义任何你需要的数据(数据是动态的),这些数据可以被Salt的其他组件(如:state)使用
可以根据需求自定义pillar变量,如:用户和uid相关的变量,操作系统与软件包相关的变量等等;在pillar中定义变量,每个变量对应一个值,就像python中的字典一样,一个键对应一个值,我们可以通过指定自定义的pillar变量名,来获取pillar变量对应的值{{ pillar['key']['key'] }} ,pillar里面也有类似嵌套
pillar 存储位置:master端,数据类型:动态数据 ,数据采集方式:
在master端定义,指定给对应的minion。可以使用saltuitl.refresh_pillar刷新。
应用:存储master指定的数据。只有指定的minion可以看到。用于敏感数据保存。
###salt '*' pillar.items
###默认是没有显示的,需在打开配置选项,我们演示完后,把这一项还原回来
###vim /etc/salt/master
###552行,pillar_opts: True
###重启服务/etc/init.d/salt-master restart
###再次执行salt '*' pillar.items 就会有显示啦
########################定义pillar数据#######################################
vim /etc/salt/master
打开下面三行:
pillar_roots:
base:
- /srv/pillar
保存退出
mkdir /srv/pillar
/etc/init.d/salt-master restart
#################################################################################
vim /srv/pillar/apache.sls
{% if grains['os'] == 'CentOS' %}
apache: httpd
{% elif grains['os'] == 'Debian' %}
apache: apache2
{% endif %}
##################################################################################
vim /srv/pillar/top.sls
base:
'*':
- apache
######################################################################################
salt '*' saltutil.refresh_pillar #刷新一下
salt '*' pillar.items
######################################pillar定位主机 ##############################
salt -I 'apache:httpd' test.ping
grains:
主要负责搜集minion端一些基本信息,如:主机名,ip,接口,操作系统等等,这些信息都是静态的 grains可以自定义,可以在minion端自定义,然后minion端搜集本地信息发送给master端;也可以在master端自定义,然后master端把自定义的grains推送到minion端,去采集minion端相关信息
grains 存储位置minion端,数据类型:静态数据,数据采集更新方式:
minion启动时采集,也可以使用saltutil.sync_grains 进行刷新。
应用:存储minion基本数据,比如用于匹配minion,自身数据可以用来做资 产管理。
grains收集信息:
salt '*' grains.ls
salt 'web13*' grains.items
也可以单个显示
salt '*' grains.item fqdn
salt '*' grains.item server_id
salt '*' grains.get ip_interfaces:eth0
grains匹配minion
#比如查看所有centos的机器上执行uptime命令:
salt -G os:centos cmd.run 'uptime'
web12.limingyu.com:
02:24:36 up 5:45, 1 user, load average: 0.06, 0.11, 0.08
web13.limingyu.com:
02:24:37 up 5:45, 1 user, load average: 0.19, 0.09, 0.06
#自定义grains:
vim /etc/salt/minion
#打下面几行
88 grains:
89 roles:
90 - webserver
91 - memcache
保存退出,重启minion
/etc/init.d/salt-minion restart
salt -G 'roles:memcache' cmd.run 'echo hehe'
或者
vim /etc/salt/grains
web: nginx
保存退出,重启minion
salt '*' grains.item web
web12.limingyu.com:
----------
web:
nginx
web13.limingyu.com:
----------
web:
salt -G web:nginx cmd.run 'echo hehe'
web12.limingyu.com:
hehe
在top.sls里匹配:
vim /srv/salt/top.sls
base:
'web:nginx' :
- match: grain
- apache
保存,重启服务
salt -G web:nginx cmd.run 'w'
区别:
1、grains是静态、不常变化的;pillar则是动态的
2、grains是存储在minion本地,而pillar存储在master本地
3、minion有权限操作自己的grains值,如增加、删除,但minion只能查看自己的pillar,无权修改
那么我们就可以得到一个大致的判断,如果你想定义的属性值是经常变化的,那请采用pillar,如果是很固定、不易变的那请用grains
我通常会把pillar或grains看成是一个大的字典,字典名就是pillar或grains;在grains字典中会有许多个键值对,每个键对应一个值,如:{{ grains['os'] }} 的值就是CentOS
pillar:
命令:
salt '*' pillar.items #查看pillar所有信息
salt '*' pillar.item users #查看pillar某个信息
定义pillar变量;
##创建pillar目录:
[root@dbm133 ~]# mkdir /srv/pillar/
##pillar目录树:
[root@dbm133 ~]# cd /srv/pillar/
[root@dbm133 pillar]# tree
.
├── file
│ └── init.sls
└── top.sls
##pillar入口文件:
[root@dbm133 pillar]# cat top.sls
base:
'*':
- file
##pillar的.sls文件
[root@dbm133 pillar]# cd file/
[root@dbm133 file]# ll
total 4
-rw-r--r-- 1 root root 29 Jul 21 13:40 init.sls
[root@dbm133 file]# cat init.sls
files:
file1: /tmp/scj/file10 ##pillar变量格式就是键值对,key:value;此处是嵌套
name: jeff
##当pillar数据在master变更时,minions需要刷新本地数据,可以通过saltutil.refresh_pillar函数完成
salt '*' saltutil.refresh_pillar ##所有minion刷新本地数据
调用pillar变量:
##创建.sls文件:
[root@dbm133 httpd]# pwd
/srv/salt/web/httpd
[root@dbm133 httpd]# cat conf.sls
{{ pillar['files']['file1'] }}: ##调用pillar变量,两个花括号;可以改成{{ pillar.get('files:file1','') }}
file:
- managed
- source: salt://web/files/file1
- template: jinja ##一定要指定template: jinja,只有这样才会去找pillar变量
##配置salt://web/files/file1文件:
[root@dbm133 files]# pwd
/srv/salt/web/files
[root@dbm133 files]# cat file1
hello {{ pillar['name'] }} ##调用pillar变量,两个花括号,调用pillar字典中name键所对应的值
###在.sls文件和配置文件里都可以调用pillar变量和grains变量
推送到minion:
[root@dbm133 httpd]# salt zszz_192.168.186.132 state.highstate
zszz_192.168.186.132:
----------
ID: /tmp/scj/file10
Function: file.managed
Result: True
Comment: File /tmp/scj/file10 updated
Started: 16:11:14.772045
Duration: 30.101 ms
Changes:
----------
diff:
New file
mode:
0644
Summary
------------
Succeeded: 1 (changed=1)
Failed: 0
------------
Total states run: 1
minion端查看是否调用成功:
[root@dbm132 scj]# ll /tmp/scj/file10
-rw-r--r-- 1 root root 11 Jul 22 16:11 /tmp/scj/file10
[root@dbm132 scj]# cat /tmp/scj/file10
hello jeff ##文件名和文件内容都对
更复杂的调用pillar变量:
http://docs.saltstack.cn/zh_CN/latest/topics/tutorials/pillar.html
{% if pillar.get('webserver_role', '') %} #键不存在则为空,''可改为{}
/var/www/foobarcom:
file.recurse:
- source: salt://webserver/src/foobarcom
- env: {{ pillar['webserver_role'] }}
- user: www
- group: www
- dir_mode: 755
- file_mode: 644
{% endif %}
{% for user,uid in pillar.get('users',{}).items() %} ##pillar.get('users',{})可用pillar['users']代替,前者在没有得到值的情况下,则为空;后者没有得到值则会报错
{{ user }}:
user.present:
- uid: {{ uid }}
{% endfor %}
grains:
命令:
salt '*' grains.ls 查看grains所有分类
salt '*' grains.items 查看grains所有信息
salt '*' grains.item os 查看grains某个分类信息
自定义grains:
方法一:在minion端自定义(不常用)
[root@dbm132 ~]#vi /etc/salt/minion
将#default_include: minion.d/*.conf,注释去掉
[root@dbm132 ~]#cd /etc/salt/minion.d/
[root@dbm132 minion.d]# vi grains1.conf
grains: #必须声明是grains
name: jeff #键值对
age: 25
id: #多个值,每行一个
- 100
- 101
[root@dbm132 minion.d]# /etc/init.d/salt-minion restart
Stopping salt-minion daemon: [ OK ]
Starting salt-minion daemon: [ OK ]
master端查看:
[root@dbm133 ~]# salt 'zszz_192.168.186.132' grains.item name age id
zszz_192.168.186.132:
----------
age:
25
id:
- 100
- 101
name:
jeff
方法二:在master端定义:
##在master端定义,需要用python去编写
##创建_grains目录
[root@dbm133 ~]# mkdir /srv/salt/_grains #必须是_grains目录
[root@dbm133 ~]# cd /srv/salt/_grains
[root@dbm133 _grains]# vi mygrains.py
#!/usr/bin/python
#encoding:utf-8
def mygrain():
grain1={} #需要定义一个字典,因为grains就是一个大的字典
grain1['company']='chengmeng'
grain1['zhiwei']='yunwei'
return grain1
##把自定义grains推送到minion端:
[root@dbm133 ~]# salt '*' saltutil.sync_all
zszz_192.168.186.135:
----------
beacons:
grains:
- grains.mygrains ##mygrains 即:python脚本名
modules:
outputters:
renderers:
returners:
states:
utils:
zszz_192.168.186.132:
----------
beacons:
grains:
- grains.mygrains
modules:
outputters:
renderers:
returners:
states:
utils:
##测试:
[root@dbm133 ~]# salt 'zszz_192.168.186.132' grains.item company zhiwei
zszz_192.168.186.132:
----------
company:
chengmeng
zhiwei:
yunwei
##继续深入方法二:
[root@dbm133 _grains]# ll
total 8
-rw-r--r-- 1 root root 202 Jul 22 17:30 mygrains1.py
-rw-r--r-- 1 root root 226 Jul 22 17:14 mygrains.py
[root@dbm133 _grains]# cat mygrains1.py ##再创建一个python脚本
#!/usr/bin/python
#encoding:utf-8
def mygrains():
grain1={} #需要定义一个字典,因为grains就是一个大的字典
grain1['bumen']={'zhiwei':'yunwei'} ##字典嵌套
return grain1
##推送到minion端:
[root@dbm133 pillar]# salt '*' saltutil.sync_all
zszz_192.168.186.132:
----------
beacons:
grains:
- grains.mygrains1
modules:
outputters:
renderers:
returners:
states:
utils:
zszz_192.168.186.135:
----------
beacons:
grains:
- grains.mygrains1
modules:
outputters:
renderers:
returners:
states:
utils:
##测试:
[root@dbm133 ~]# salt 'zszz_192.168.186.132' grains.item bumen
zszz_192.168.186.132:
----------
bumen:
----------
zhiwei:
yunwei ##字典嵌套
##其他例子
cat /srv/salt/_grains/fc.py
#!/usr/bin/python
import os,commands,math
def fc():
fc = {}
fc['role'] = 'cpisfc_web'
fc['disks'] = commands.getoutput('df -m| grep "/data/cache" | awk \' { print $NF } \' ')
fc['disk_size'] = commands.getoutput('df -m| grep "/data/cache" | tail -n 1 | awk \' { print $2 } \' ')
fc['disk_size_per'] = int(math.floor(float(fc['disk_size'])/100000))*1000
fc['node'] = commands.getoutput('hostname | cut -c1-8')
return fc
###注意:grains获取的是minion端的相关信息
[root@dbm133 _grains]# vi mygrains.py
#!/usr/bin/python
#encoding:utf-8
import commands
def mygrains():
grain1={} #需要定义一个字典,因为grains就是一个大的字典
grain1['company']='chengmeng'
grain1['zhiwei']='yunwei'
grain1['myip']=commands.getoutput("ifconfig | grep Bcast | awk '{print $2}' | awk -F':' '{print $2}'") ##获取minion端的ip
return grain1
[root@dbm133 ~]# salt '*' saltutil.sync_all
[root@dbm133 ~]# salt 'zszz_192.168.186.132' grains.item myip
zszz_192.168.186.132:
----------
myip:
192.168.186.132 ##获取的的确是132的ip
调用grains变量:
在state模块.sls文件,pillar的.sls文件和配置文件里都可以调用grains变量
1、配置文件里调用grains变量:
##定义.sls文件
[root@dbm133 httpd]# pwd
/srv/salt/web/httpd
[root@dbm133 httpd]# cat conf.sls
{{ pillar['files']['file1'] }}:
file:
- managed
- source: salt://web/files/file1
- template: jinja ##一定要指定template: jinja
##定义salt://web/files/file1配置文件:
[root@dbm133 files]# pwd
/srv/salt/web/files
[root@dbm133 files]# cat file1
hello {{ pillar['name'] }}
worker_processes {{ grains['num_cpus'] }} ##调用grains变量,两个花括号;获取minion的cpu个数
##同步数据:
[root@dbm133 ~]# salt 'zszz_192.168.186.132' state.sls web.httpd.conf
zszz_192.168.186.132:
----------
ID: /tmp/scj/file10
Function: file.managed
Result: True
Comment: File /tmp/scj/file10 updated
Started: 09:17:42.690891
Duration: 320.077 ms
Changes:
----------
diff:
---
+++
@@ -1,1 +1,2 @@
hello jeff
+worker_processes 1
Summary
------------
Succeeded: 1 (changed=1)
Failed: 0
------------
Total states run: 1
##minion端
[root@dbm132 scj]# ll /tmp/scj/file10
-rw-r--r-- 1 root root 30 Jul 23 09:17 /tmp/scj/file10
[root@dbm132 scj]# cat /tmp/scj/file10
hello jeff
worker_processes 1 ##调用成功
2、pillar的.sls文件里调用grains变量:
##定义pillar的.sls文件:
[root@dbm133 file]# cat /srv/pillar/file/init.sls
files:
file1: /tmp/scj/file10
name: jeff
xingming:
{% if grains['os'] == 'CentOS' %} #####调用grains变量####
name: jeff ##定义pillar变量
{% elif grains['os'] == 'RedHat' %}
name: scj
{% else %}
name: other
{% endif %}
##创建state的.sls文件:
[root@dbm133 file]# cat /srv/salt/web/httpd/conf.sls
{{ pillar['files']['file1'] }}:
file:
- managed
- source: salt://web/files/file1
- template: jinja ##一定要指定template: jinja
##创建salt://web/files/file1配置文件,调用pillar变量:
[root@dbm133 files]# cat /srv/salt/web/files/file1
hello {{ pillar['name'] }}
worker_processes {{ grains['num_cpus'] }}
welcome {{ pillar['xingming']['name'] }} ##调用pillar变量
##同步数据到minion:
[root@dbm133 ~]# salt 'zszz_192.168.186.132' state.sls web.httpd.conf
zszz_192.168.186.132:
----------
ID: /tmp/scj/file10
Function: file.managed
Result: True
Comment: File /tmp/scj/file10 updated
Started: 09:32:20.510124
Duration: 197.122 ms
Changes:
----------
diff:
---
+++
@@ -1,2 +1,3 @@
hello jeff
worker_processes 1
+welcome jeff
Summary
------------
Succeeded: 1 (changed=1)
Failed: 0
------------
Total states run: 1
##minion查看:
[root@dbm132 scj]# ll /tmp/scj/file10
-rw-r--r-- 1 root root 43 Jul 23 09:32 /tmp/scj/file10
[root@dbm132 scj]# cat /tmp/scj/file10
hello jeff
worker_processes 1
welcome jeff ##正常
3、state的.sls文件里调用grains变量:
##创建state的.sls文件
[root@dbm133 httpd]# cat /srv/salt/web/httpd/conf.sls
{{ pillar['files']['file1'] }}:
file:
- managed
- source: salt://web/files/file1
- template: jinja
{% set myos = grains['os'] %} ##调用grains变量,定义一个本地myos变量;可以改成{% set myos = grains.get('os','') %}
{% if myos == 'CentOS' %}
/tmp/scj/file11: ##虽然if语句要求严格缩进,但是.sls文件的标识必须顶格
file:
- managed
- template: jinja
{% endif %}
##同步数据:
[root@dbm133 ~]# salt 'zszz_192.168.186.132' state.sls web.httpd.conf
zszz_192.168.186.132:
----------
ID: /tmp/scj/file10
Function: file.managed
Result: True
Comment: File /tmp/scj/file10 is in the correct state
Started: 09:58:24.923975
Duration: 101.966 ms
Changes:
----------
ID: /tmp/scj/file11
Function: file.managed
Result: True
Comment: Empty file
Started: 09:58:25.031602
Duration: 1.758 ms
Changes:
----------
new:
file /tmp/scj/file11 created
Summary
------------
Succeeded: 2 (changed=1)
Failed: 0
------------
Total states run: 2
##minion端
[root@dbm132 scj]# ll /tmp/scj/file11
-rw-r--r-- 1 root root 0 Jul 23 09:58 /tmp/scj/file11