[saltstack]常用命令和函数-迁
命令行
帮助
# 查看相关函数
sys.list_functions cmd
- cmd.exec_code
- cmd.has_exec
- cmd.retcode
- cmd.run
# 查看所有module列表
sys.list_modules
- aliases
- apache
- at
- blockdev
# 查看使用方法
sys.doc cmd
# 查看states 支持的模块列表
sys.list_state_modules
# states 支持的函数列表
sys.list_state_functions file
# states 支持的函数用法
sys.state_doc file.managed
匹配规则
#匹配nodegroup
salt -N group1
#minions列表匹配
salt -L 'platapp2,platapp1'
#匹配正则表达式
salt -E 'nljkapp[1-3]'
#IP地址匹配[192.168.1.0/24],貌似只能用 /16 /24 之类的段
salt -S '172.23.4.57'
salt -S '192.168.100.0/24'
#复合匹配: compound matchers
salt -C 'P@max_open_file:[0-9]{4}$ and S@192.168.100.0/24'
# 复合匹配在nodegroup中的写法
phy_linux: '* and not E@KQ-* and G@virtual:physical'
# 在指定数量或百分比的机器上执行命令。
salt \* -b 10 test.ping # 每次执行10%
salt -G 'os:RedHat' --batch-size 25% apache.signal restart
第一条命令在所有的客户端上执行test.ping,但同一时间只有10台机器运行此命令,
当有minion返回执行结果是,再让下一个minion执行。 第二条命令在系统是RedHat的客户端中重启apache服务,
但同一时间只有25%的机器执行重启,直到所有目标机器执行完成。
Batch Size并不减少总的数量,只是限制同时执行任务的机器数量。这非常有用,
比如,在负载均衡web集群中,可以只用一条命令分批的重启web服务。
#匹配 grains定义值 ,正则 grains :P, Grains PCRE
salt -G 'osrelease:6*'
#匹配pillar定义的值
salt -I 'flow:maxconn:30000'
# 需要先在/etc/pillar/top.sls 中定义范围:
cat /srv/pillar/top.sls
base:
'webcall':
- match: nodegroup
- data
# 结合pillar和nodegroup 会比较灵活
# 注意下 match,不要直接写 'N@webcall'
全局命令
# 列出详细输出,当Minions运行命令超时无返回结果时会显示"Minion did not return" salt -v 'vnljkapp2' test.ping --out=json # 更多的 salt例子可以使用以下命令查看: salt '*' sys.doc | grep "salt '*'" #把文件传输到服务器上去(但是注意只能传文件) salt-cp 'KQ-172.23.4.219' win.bat D:/ salt-cp -N lvs /var/www/html/soft/lvs/install_lvs.sh /tmp/install_lvs.sh
salt-ssh
/etc/salt/roster 192.168.21.4: host: 192.168.21.4 user: root password: redhat
salt-ssh 192.168.21.1 --roster-file /etc/salt/roster -r 'uptime' 192.168.21.1: ---------- retcode: 0 stderr: stdout: 10:35:04 up 19:50, 0 users, load average: 0.12, 0.10, 0.06
可以不装客户端 或者装不上的情况,用这个方式
salt-ssh -L "192.100.2.2" -r "/root/salt_tomcatManager.sh /usr/local/tomcatawo status"
-i 默认全部接收auth key,貌似是用auth key 来做互信的
salt-ssh '*' -i --roster-file /etc/salt/roster -r 'uptime'
#打印出日志来,看到是一个很复杂的ssh命令
salt-ssh -i 172.23.4.80 --roster-file /etc/salt/roster -r 'uptime' -l all mylog [DEBUG ] Executing command: ssh 172.23.4.80 -o KbdInteractiveAuthentication=no -o GSSAPIAuthentication=no -o PasswordAuthentication=no -o ConnectTimeout=75 -o StrictHostKeyChecking=no -o Port=22 -o IdentityFile=/etc/salt/pki/master/ssh/salt-ssh.rsa -o User=root 'uptime mylog'
通过把 /etc/salt/pki/master/ssh/salt-ssh.rsa.pub 手动烤过去,authorized_keys
文档:
https://docs.saltstack.com/en/latest/topics/ssh/
问题:
{'_error': 'Failed to return clean data'}
salt.client.ssh.wrapper.FunctionWrapper(
salt-ssh ‘test85′ -key-deploy test.ping
当调用master模块时,并加上参数 –key-deploy 即可在minions生成keys,下次开始就不使用密码
This – let's call it a workaround – "fixes" the issue. The main disadvantage is, that it breaks current configuration.
--- ./returners/mysql.py.orig 2017-02-23 00:32:57.628630209 +0100
+++ ./returners/mysql.py 2017-02-23 00:33:03.173848441 +0100
@@ -178,7 +178,7 @@
Returns options used for the MySQL connection.
'''
defaults = {'host': 'salt',
- 'user': 'salt',
+ 'dbuser': 'salt',
'pass': 'salt',
'db': 'salt',
'port': 3306,
@@ -187,7 +187,7 @@
'ssl_key': None}
attrs = {'host': 'host',
- 'user': 'user',
+ 'user': 'dbuser',
'pass': 'pass',
'db': 'db',
'port': 'port',
# master.d/mysql.conf
master_job_cache: mysql
event_return: mysql
mysql.host: '192.168.255.1'
#mysql.user: 'salt-master'
mysql.dbuser: 'salt-master'
mysql.pass: 'mypassword'
mysql.db: 'salt'
mysql.port: 3306
salt-run
salt-run 只能在master上使用!
这个runners就是给salt-run 命令写的 你如果写了一个 runners 脚本名字叫cpis.py 里面在定义几个函数
这个时候 你就可以直接运行salt-run cpis.某个函数名称 就能实现 脚本内函数的功能
官方提供的一些模块,作为一些自定义的模块功能,作为扩展,其实ConfigManage 也可以写成runner
https://github.com/saltstack/salt/tree/develop/salt/runners
比如 控制dns network fileserver等等服务,以后可以钻研一下!
先设定 /etc/salt/master
runner_dirs: ['/src/salt/_runner']
重启服务
mkdir -p /src/salt/_runner ; cd /src/salt/_runner
#可以查询在线的服务器 salt-run manage.status / salt-run manage.down / salt-run manage.up down: - vapp1 up: - IMHDCL - NEWDB1 .... #查询未完成的jobs salt-run jobs.lookup_jid 20150311110102979290
salt-run manage.up 查看存活的minion salt-run manage.down 查看死掉的minion salt-run manage.down removekeys=True 查看down掉的minion,并将其删除 salt-run manage.status 查看minion的相关状态 salt-run manage.versions 查看slat的所有master和minion的版本信息
salt-call
salt-call 是客户端(minion)自我调用时用到的命令,注意: 使用时还是会连接master,加上--local后就可以without master了
本地测试 stat 是否正确
salt-call state.sls logstash.test saltenv='prod'
local:
----------
ID: envtest
Function: cmd.run
Name: echo '[prod]' env
Result: True
Comment: Command "echo '[prod]' env" run
window
直接下载安装版本,修改salt-master ID keepalive
#查询在线用户 salt 'KQ-172.23.4.219' cmd.run 'query user' #重启系统 salt 'KQ-172.23.4.219' system.reboot
#管理用户 salt 'WIN_IP' user.add ADD_USER_NAME PASSWORD salt 'WIN_IP' user.setpassword ADD_USER_NAME PASSWORD salt 'WIN_IP' user.delete USER_NAME salt 'WIN_IP' user.list_users salt 'WIN_IP' user.addgroup ADD_USER_NAME Administrators salt 'WIN_IP' group.info administrators # 使用win自带命令 salt 'KQ-172.23.4.219' cmd.run 'net user' KQ-172.23.4.219: User accounts for \\ ------------------------------------------------------------------------------- Administrator ecp Guest huhk huli lilian linxw tanxg wangc wangxj xiaoxm xud yangxj yingl zhangjm zhongsh The command completed with one or more errors. # salt 'KQ-172.23.4.219' user.delete 'xud' KQ-172.23.4.219: True # salt 'KQ-172.23.4.219' cmd.run 'net user zgt DLwfg8 /add' KQ-172.23.4.219: The command completed successfully. #修改用户密码 salt 'TEST-192.168.38.224' cmd.run 'net user wuhh J4pZ0w' #查询账号密码 规则 'net accounts' #将zgt添加到 Remote Desktop Users 内 'net localgroup "Remote Desktop Users" zgt /add' #将zgt从 组中删去 'net localgroup "Remote Desktop Users" zgt /del' #zgt 提升为admin组 'net localgroup "Administrators" zgt /add'
模块
grains
# 查看grains分类
salt '*' grains.ls
# 查看 grains所有信息
salt '*' grains.items
# 查看 grains某个信息
salt '*' grains.item osrelease
salt -N group1 grains.item osrelease
platapp6:
osrelease: 6.4
# 匹配6.*的系统版本
salt -G 'osrelease:6*' cmd.run 'ls /etc/yum.repos.d/'
# 查询cpu
salt -L 'platapp2' grains.item cpu_model
platapp2:
cpu_model: Intel(R) Xeon(R) CPU E7- 4807 @ 1.87GHz
# 查ip地址的方式
salt 'website1' grains.item fqdn_ip4
用正则的方式,来实现<10000,--grain-pcre用正则表达式
salt --grain-pcre 'max_open_file:[0-9]{4}$' grains.item id max_open_file runas='ecp'
ommoniter:
id: ommoniter
max_open_file: 1024
testit:
id: testit
max_open_file: 1024
grains目录优先级
grains可以保持在minion端、通过master端下发等多个方式来分发。但不同的方法有不同的优先级的: 1. /etc/salt/grains # minion端 2. /etc/salt/minion # minion端 3. /srv/salt/_grains/ # master端_grains目录下 通过master下发的grains优先级是最高的可,/etc/salt/minion次之,/etc/salt/grains最低 minion上的目录 /var/cache/salt/minion/extmods/grains /var/cache/salt/minion/files/base/_grains/
自定义grains的下发
saltutil.clear_cache 清理缓存 saltutil.sync_grains 下发 本地grains配置 saltutil.sync_all 批量下发master配置的grains pillar return等 切记所有在_grains目录下的所有自定义grains值都会下发到minion,这是“血”的教训。 -- 如果脚本错误,会引起minion无法启动!(minion启动先检测一遍脚本)
可以放一些不改变配置的脚本,如果有设置的脚本,需要用固定放在Minion端的配置文件中可以通过file manager
的方法去批量
1. 通过state.highstate 下发的grains好处是无须重启minion即可生效,但通过下发/etc/salt/grains文件下发的grains值则必须重启minion端服务才可以生效。
2. 自定义的_grains每次在highstate调用的时候就会自动下发、刷新,而/etc/salt/grains文件的则不会。
现在在master里面设置好 file_roots ,新建一个_grains 文件夹,然后编写脚本
将 /srv/salt/_grains 中的文件直接同步到minion中
/var/cache/salt/minion/files/base/_grains /var/cache/salt/minion/extmods/grains
注意: salt-ssh 中也会同步到,位置在/tmp目录下
举个栗子:
salt/_grains/abc.py
import sys
def abc():
return {'abc': '00000000000000000'}
salt "50bb1d42d8f869501d9f5c2f4430060f" grains.item abc
50bb1d42d8f869501d9f5c2f4430060f:
----------
abc:
00000000000000000
salt 'website1' grains.item nets website1: nets: 192.168.100.122 work_dir: /usr/local work_disk_per: 37.01 % work_disk_size: 19.84 G
通过grains模块定义grains
salt 'ywjk' grains.append saltbool 'verycool'
saltbool 将写在minion端的 /etc/salt/grains 里面,如果有重复的item将会替换成新的
可以使用grains.setvals 设置更多的grains
salt 'ywjk' grains.setvals "{'salt':'good','saltbool':'True'}"
跟pillar比的对比
1.grains存储的是静态、不常变化的内容,pillar则相反
2.grains是存储在minion本地,而pillar存储在master本地
3.minion有权限操作自己的grains值,如增加、删除,但minion只能查看自己的pillar,无权修改
pillar
就是将一些指定的配置,通过pillar设置到对应的服务器上,这样做的好处就是我可以指定服务器执行及带入我设置的变量
说白了就是根据不同的服务器来配置,这个配置是放在服务端的,可是这样nodegroup确实鸡肋了
设置 pillar_roots: 设置 pillar_opts: True saltutil.refresh_pillar 同步到minion上去(貌似有自动同步的机制,只要配置上去,就直接在master查到)
# 提取pillar数据 salt 'website1' pillar.data flow # 指定pillar选择器 salt -I 'flow:maxconn:30000'
pillar.item和pillar.get的不同get 会把相关的都搜索出来
比如提取 master上配置
salt website1 pillar.get master:nodegroups
item 只匹配
多环境pillarenv和saltenv
pillar_roots:
base:
- /srv/pillar/base
live:
- /srv/pillar/live
# 执行
salt-call state.sls logstash.test saltenv='base' pillarenv='live'
local:
----------
ID: envtest
Function: cmd.run
Name: echo 'pillar [live]' base env
Result: True
Comment: Command "echo 'pillar [live]' base env" run
Started: 14:43:27.608350
Duration: 5.733 ms
Changes:
----------
pid:
31256
retcode:
0
stderr:
stdout:
pillar [live] base env
Summary for local
------------
Succeeded: 1 (changed=1)
Failed: 0
------------
Total states run: 1
Total run time: 5.733 ms
schedule
schedule 是配置在master上的
cat /srv/pillar/top.sls base: 'webcall': - match: nodegroup - data 'mykvm1': - schedule
举例1
cat schedule.sls schedule: #自动执行highstate highstate: function: state.highstate minutes: 10
举例2
schedule:
zabbix-agent-monitor:
function: state.sls
minutes: 10
args:
- base.init.zabbix.service
kwargs:
stateful: True
pillarenv: dev
auto-clean-log:
functioin: cmd.script
source: salt://script/auto_clean.sh
statefull: False
shell: /bin/bash
minutes: 10
执行任务
testcase:
function: cmd.run
seconds: 5
args:
- 'echo 1>> /tmp/test.cmd.log'
kwargs:
stateful: False
shell: /bin/bash -- 不要写True之类的bool值
# 创建完文件之后执行下面的命令把pillar的修改刷到minion端去,_returner也会传到客户端
salt '*' saltutil.refresh_pillar
# 想查看minion端都有哪些计划任务可以用
salt gotonecore-98-9 pillar.item schedule(在schedule.sls下的函数)
#所有schedule全部enable/disable schedule.enable/disable # 针对job进行 enable/disable schedule.enable_job/disable_job testcase # 删除job schedule.delete job_name schedule.purge == 删除所有job # 获取minion端的schedule信息 salt 'message-1-1' schedule.list show_all=True pillar.get schedule # 获取minion端的schedule信息 -- master本地的 salt '*' config.option schedule
salt 'mongodb-1-1' config.option schedule
mongodb-1-1:
----------
__mine_interval:
----------
enabled:
True
function:
mine.update
jid_include:
True
maxrunning:
2
minutes:
60
name:
__mine_interval
return_job:
False
om-agent-monitor:
----------
args:
- base.init.om_monitor_agent.install
function:
state.sls
jid_include:
True
kwargs:
----------
stateful:
True
maxrunning:
1
minutes:
10
name:
om-agent-monitor
cron
本身会在minion上创建一条crontab任务
cron.present:
- name: /root/PatrolAgent.sh
- identifier: PatrolAgent_monitor
- comment: salt_PatrolAgent_monitor
- user: root
- minute: 5 // 每小时 05 分的时候执行
- require:
- file: PatrolAgent
- onlyif: test -f /root/PatrolAgent.sh
salt 'website1' cron.list_tab root pre: //说明是在# Lines 这句comment下面的 - 05 0 * * 1 /usr/sbin/logrotate -f /etc/logrotate.d/f
添加,注意后面加上'',不加参数错误,加了其他内容不能remove
salt 'website1' cron.set_job root '*/10' '*' '*' '*' '*' '/usr/sbin/ntpdate 134.98.5.80' ''
删除
salt 'sjkr14' cron.rm_job root '/usr/sbin/ntpdate -s 210.72.145.44'
注意需要添加 # Lines below here are managed by Salt, do not edit 不然只能加不能删
salt '*' cmd.run 'sed -i "1 i # Lines below here are managed by Salt, do not edit" /var/spool/cron/root'
salt '*' cmd.run 'ps -ef|grep ./agent_mobilelocalxd|grep -v grep|awk "{print \$2}"|xargs kill -9'
salt '*' cmd.run 'ps -ef|grep java|grep target|grep -v grep|awk "{print \"cat /proc/\"\$2\"/oom_score\"}"' # 带变量的awk
salt-ssh -L pointcore-1-6,pointcore-1-5,dns-1-1,bops-1-1,pointcore-1-7,pointcore-1-8 -i -r "ps -ef|grep salt|grep python|awk '{print \$2}'|xargs sudo kill -9"
sysctl
vm.overcommit_memory: sysctl.present: - value: 1
service
# 检查是否在chkconfig 启动列表
salt '*' service.available sshd
# 获取所有
salt '*' service.get_all
# Disable the named service to start at boot
service.disable
# Check to see if the named service is disabled to start on boot
service.disabled
# Enable the named service to start at boot
service.enable
# Check to see if the named service is enabled to start on boot
service.enabled
#管理服务
salt '*' service.restart/status/start/stop <service name>
# cat httpd.sls
apache:
service:
- name: httpd
- running
- reload: True
- watch:
- file: /etc/httpd/conf/httpd.conf
/etc/httpd/conf/httpd.conf:
file:
- managed
- source: salt://httpd/httpd.conf
- backup: minion
客户端的备份目录:
/var/cache/salt/minion/file_backup/usr/local/yixinb_tomcat/webapps/ROOT/common/js
cmd
exec_code
salt 'server' cmd.exec_code bash 'if [ -f "/tmp/lixc" ];then echo yes;else echo no;fi'
salt-minion:
no
cmd.script
salt -N website cmd.script salt://MyScript.sh args='-o' 要把绝对路径写进去 salt 'nljkapp1' cmd.script salt://script/salt_tomcatManager.sh args='/home/ecp/tomcatzgt start' runas='ecp' shell='/bin/bash' 可以支持runas 的有cmd.retcode (执行shell命令返回状态码), cmd.run(执行命令,输出), cmd.run_all(执行命令,结果以字典的形式返回,包含状态码及返回结果) salt -N 'website' cmd.script salt://script/salt_tomcatDeploy.sh args='/usr/local/yixinb_tomcat /home/ecp/yixin-guan.war' runas='ecp' shell='/bin/bash'
cmd.run_stderr(执行命令,返回标准错误输出) cmd.run_stdout(执行命令,返回标准输出), cmd.script(从远端下载脚本,然后本地运行), cmd.script_retcode(从远端下载脚本,然后本地运行,返回状态码 salt -N 'website' cp.get_file salt://file/website/yixin-guan.war /home/ecp/yixin-guan.war
salt newtxl1 cmd.run 'sh /etc/salt/check_salt.sh 1>/dev/null 2>/dev/null &'
salt "walle-1-1" cmd.run 'sed -i "s/1-1.yum/yum.ops.net/" `ls /etc/yum.repos.d/*`'
salt 'gotonecore-1-1' cmd.run template=jinja 'sed -i "/^id:/c id: live-{{grains.id}}" /etc/salt/minion'
# 带变量表达式的命令写法
salt '*' cmd.run 'sed -i "s/^#tcp_keepalive/tcp_keepalive/" /etc/salt/minion'
salt -N oradb cmd.run 'multipath -l|awk "{x++}END{if(x>1)print a,\": exist multipath\"}" a=`hostname`'
return 储存接口
return 接口只能加在minion端,用于异步返回 sys.list_returners - carbon - couchdb - etcd - hipchat - local - local_cache - multi_returner - mysql - slack - smtp - sqlite3 - syslog salt-call test.ping --return redis_pub
https://docs.saltstack.com/en/latest/ref/returners/
salt/_returners/redis_pub.py
# -*- coding: utf-8 -*-
import salt.utils.json
import time
try:
import redis
HAS_REDIS = True
except ImportError:
HAS_REDIS = False
__virtualname__ = 'redis_pub'
def __virtual__():
if not HAS_REDIS:
return (False, "Please install the redis package.")
return __virtualname__
def returner(ret):
'''
Return data to redis
'''
retry = 3
r = redis.Redis(host='salt-redis.xxxxxx.cn', port=16379, db=0, password='xxxxxxxxxxxx')
pipeline = r.pipeline(transaction=False)
minion, jid = ret['id'], ret['jid']
pipeline.hset('ret:{0}'.format(jid), minion, salt.utils.json.dumps(ret))
pipeline.expire('ret:{0}'.format(jid), 86400)
pipeline.execute()
sub_num = r.publish('ret:' + ret['jid'], salt.utils.json.dumps(ret))
while sub_num == 0 and retry > 0:
retry -= 1
time.sleep(1)
sub_num = r.publish('ret:' + ret['jid'], salt.utils.json.dumps(ret))
其他
# 查询磁盘使用情况 disk.usage # 删除用户 user.delete # 用户操作 在windows下不行,用net命令解决 user.add user.list_users user.list_groups # 修改密码 还是用 echo xxx|passwd zgt --stdin # 将文件从master传输到minion salt 'jkcj' cp.cache_file salt://zgt # 将文件从master传输到minion并改名 salt 'jkcj' cp.get_file salt://zgt /tmp/123 #将minion文件 传输到master,注意打开recv_file cp.push /etc/passwd /var/cache/salt/master/minions/files/jkcj/files/etc/passwd -- master端 #将monitor_agent目录推送到服务器/usr/local目录 cp.get_dir salt://monitor_agent '/usr/local' #修改文件属性 file.chown /tmp/123 ecp ecp #修改文件属性 chmod file.set_mode /etc/passwd 0644 # 命令行创建超链接 file.symlink /usr/log_bak /home/ecp/logs/log_bak # 查询版本 pkg.version vim-common # 软件安装 pkg.install ntp #安装多个文件 pkg.install "gettext gettext-devel libXft libXft-devel libXpm libXpm-devel autoconf "
#启动一个定时任务--实用 salt 'website1' at.at 'now + 1 minutes' '/etc/init.d/salt-minion restart'
state.sls
语法
使用state的优势在于可以写执行脚本,注意top.sls文件里面
如果用了 '*' ,执行 salt '*' state.highstate 那就全执行了一遍,如果有危险操作请注意
cat top.sls base: '*': --- 这里可以写一些基础的设置和配置 - mypkg - one # 引用one.sls 或者 one/init.sls states文件 - update_zmq.update - update_zmq.at 'platapp1': -- 这里可以设置服务器分类,比如应用、数据库、redis、测试等等类别 - appplat.nginx 'platapp2': - appplat.nginx 'website[1-3]': - website.b_yixin_im # 命令行执行 salt -E 'nljkapp[1-3]' state.sls update_zmq.update #将所有的执行命令都下发下去 salt '*' state.sls mypkg
top.sls文件
创建一个 top.sls文件,这个也是入口文件,也就是说,你执行相关命令的时候,会先检测
这个文件,这文件提供了其它文件的映射,可以用于作为其它服务器的基础配置文件。 [http://my.oschina.net/u/877567/blog/183959] sls文件解读
base: 'jkcj': - httpd.httpd
include
include:
- prod.jdk.install_1.7.20_60 // 这样是找不到的,
可以把 dot转义一下 prod.jdk.install_{{jdk_version.replace(".","_")}}
这样就能用了
state逻辑关系列表
match -> require -> watch -> order
require: 依赖某个state,在运行此state前,先运行依赖的state,依赖可以有多个 match: 配模某个模块,比如 match: grain match: nodegroup require: 依赖某个state,在运行此state前,先运行依赖的state,依赖可以有多个 只是执行那个state,不管是不是成功或者匹配到unless ifonly,即使unless 也成功返回
watch: 在某个state变化时运行此模块,watch除具备require功能外,还增了关注状态的功能,比如配置改了后,后续动作
redis:
pkg:
- latest
file.managed:
- source: salt://redis/redis.conf
- name: /etc/redis.conf
- require:
- pkg: redis
service.running:
- enable: True
- watch:
- file: /etc/redis.conf
- pkg: redis
order: 优先级比require和watch低,有order指定的state比没有order指定的优先级高 vim: pkg.installed: - order: 1 想让某个state最后一个运行,可以用last
unless: unless: test -d /usr/local/nginx 如果结果为 False,才执行该 state,True 则跳过
只能写一个 unless,如果写两会有先后顺序,最下面那个来判断是否执行,unless execution succeeded,命令就不执行下去
使用复合表达:
cmd.run:
- name: mkdir /tmp/zgt
- unless: test -d /home/nginx
- unless: test -d /home/ecp/nginx
例1
- unless:
- test -d /usr/local/jdk1.7.0_60 || java -version
例2
- unless:
- rpm -q vim-enhanced
- ls /usr/bin/vim
# 判断系统环境变量
test "{{ fqdn }}" = "$(hostname)"
onlyif:
- onlyif: ps -ef|grep -v grep|grep PatrolAgent // 返回True 则执行
echo-ok:
cmd.run:
- name: "echo ok"
- onlyif: ps -C java -f --width 1000|grep jboss|grep -vE "grep|salt|ssh"
yaml和jinja语法
1 FILE 状态使用template参数
- template: jinja
2 模板文件里面变量使用{{ PORT }}
3 FILE 状态模块要指定变量列表
- defaults: PORT: 8080
pillar数据
cat /srv/pillar/base/top.sls
base:
'*':
- prod_env
cat /srv/pillar/live/top.sls
live:
'*':
- prod_env
match 貌似只能用list,用nodegroup就找不到servers了
base:
'website1,website2,website3':
- match: list
- data
'udbxh1,udbxh2':
- match: list
- data_udb
'yxqdgk1,yxqdgk2':
- match: list
- data_yxqdgk
数据格式
字典:
test:
wojiushikk: test666
多层字典
salt-minion:
tmp: {'name': 'lixc', 'remove': 'True'}
{% set size=salt['grains.get']('tmp:remove', '') %}
{% if size %}
....
{% endif %}
列表:
test:
- nni
- sddd
- wddd
获取pillar变量
# 获取变量
{{ pillar['user'] }}
{{ pillar.get('user',{}) }} # 更好
将参数带入到state中渲染
salt/mypkg.sls:
packages:
pkg:
- installed
- pkgs: {{ salt['pillar.get']('packages') }}
salt '*' state.sls package-list pillar='{packages: [foo, bar, baz]}'
pillar.get() vs salt['pillar.get']()
用 : 可以快速地找 dict 中的值,注意参数要加 '' 引号
# /srv/salt/apache/conf.sls
{% from "apache/map.jinja" import apache with context %}
apache_conf:
file:
- managed
- name: {{ salt['pillar.get']('apache:lookup:name') }}
- source: {{ salt['pillar.get']('apache:lookup:config:tmpl') }}
grains数据
# cat nginx.sls
{% if grains['nodename'].startswith('website') %}
toms:
tom1: gjdx_tomcat
tom2: tomcatecp
tom3: yixinb_tomcat
tom4: tomcatecp
{% endif %}
在 jinja中的调用 :
{{ grains['ipinfo'][0]['IP'] }}
正则表达式
现在jinja支持的表达式不多,很多应用暂时无解
{% if grains['osrelease'].startswith('6') %}
{{ grains['nodename'].split("-")[0] }}
判断
{% if grains['osrelease'] < '6' %}
- name: /etc/yum.repos.d/epel5.repo
- source: salt://base/init/repo/files/epel5.repo
{% else %}
- name: /etc/yum.repos.d/epel6.repo
- source: salt://base/init/repo/files/epel6.repo
{% endif %}
{% if grains['os'] in ('RedHat','CentOS') %}
salt-test:
cmd.run:
- name: echo "oko"
{% endif %}
# 判读目录是否存在
{% if salt['file.directory_exists']('/etc/logrotate.d') and not salt['file.file_exists']('/etc/logrotate.d/nginx') %}
{% endif %}
字符串操作
# 变量修改,加上字符
{% set value='/home' %}
{% set ecp='/ecp' %}
{% if salt['file.directory_exists'](value+"/"+ecp) %}
# jinja 使用执行模块
{{ salt['network.hw_addr']('eth0') }}
# 赋值
{% set slave_ip = '172.23.4.43' %}
# 如果是多级字典
{{ pillar['user']['user'] }}
# 两种都可以
{{ foo.bar }}
{{ foo['bar'] }}
# 取值,如果为 None,用默认值
{{ foo.bar | default('zoo') }}
# 获取变量后替换字符串
{% set mystr = grains['cpu_model'] | replace("CPU","GGG") %}
循环操作
pillar/data/toms.sls
tom1:
8081
tom2:
8082
{% for item in pillar['toms'].items() %} # for 循环
# item的类型是(tuple) = ('tom1',8081)
# item[1] = 8081
tom-tar-{{ item[1] }}: ==> tom-tar-8081
cmd.run:
- name: echo {{item[1]}} >> /tmp/foo
{% endfor %}
{% for item in pillar['vhost'] %}
{{ item['name'] }}:
cmd.run:
- name: echo "{{ item['source'] }}" > /tmp/bar
{% endfor %}
{% for i in pillar.get('user',{}).items %}
{{ i }}
{% endfor %}
文件操作
# 添加内容
/srv/salt/test/file.sls
/tmp/a.txt:
file.append:
- text:
- 'this is append line1' #注意用单引号或双引号
- 'this is append line2'
file.append:
- text:
- local3.* /var/log/keepalived.log
- unless: cat /etc/rsyslog.conf|grep keepalived
# 可以追加模板
/etc/motd:
file:
- append
- template: jinja
- sources:
- salt://motd/devops-messages.tmpl
- salt://motd/hr-messages.tmpl
- salt://motd/general-messages.tmpl
# 修改内容:
/etc/sysconfig/network
file.replace:
- pattern: HOSTNAME=
- repl: HOSTNAME={{ fqdn }}
/etc/yum.repos.d/epel.repo:
file.sed:
- before: 1
- after: 0
- limit: ^enabled=
# 文件管理
/usr/local/src/nginx-1.9.2.tar.gz
file.managed:
- source: salt://prod/nginx/files/nginx-1.9.2.tar.gz
- user: root
- group: root
- mode: 755
- unless: test -f /usr/local/src/nginx-1.9.2.tar.gz
# 创建目录
file.mkdir /usr/log_bak
haproxy-config-dir:
file.directory:
- name: /etc/haproxy
- mode: 755
- user: root
- group: root
用户操作
ecp-user-group:
group.present:
- name: ecp
- gid: 550
user.present:
- name: ecp
- fullname: ecp
- shell: /bin/bash
- uid: 550
- gid: 550
- password: $6$SALTsalt$UiZikbV3VeeBPsg8./Q5DAfq9aj7CVZMDU6ffBiBLgUEpxv7LMXKbcZ9JSZnYDrZQftdG319XkbLVMvWcF/Vr/
- enforce_password: True
# password生成方法
python -c "import crypt; print crypt.crypt('password', '\$6\$SALTsalt\$')"
或者用openssl (用这个靠谱),不加盐的话每次生成的字符串都不一样,但是反解出来是一样的密码。
加了盐之后生成的字符串每次都一样了
$ openssl passwd -1 -salt "SALT"
Password:
$1$SALT$3ATlhGooo9OTS0VrH2L0y0
环境变量
cmd.run:
- env:
- PATH: "JAVA_HOME:/usr/local/jdk1.6.0_32"
- name: cd /usr/local/monitor_agent && /usr/bin/nohup ./monitor-agent start &
- unless: ps -ef|grep -v grep|grep "appname=MonitorAgent"
salt://scripts/bar.sh: cmd.script: - env: "PATH=/some/path:$PATH"
{% set current_path = salt['environ.get']('PATH', '/bin:/usr/bin') %}
mycommand:
cmd.run:
- name: ls -l /
- env:
- PATH: {{ [current_path, '/my/special/bin']|join(':') }} //按 : 表达
cmd
echo-ok:
cmd.script:
- source: salt://script/auto_clean.sh
- shell: '/bin/bash'
cmd.run:
- env:
- CFLAGS:"-fPIC" // 设置环境环境变量
- names:
- cd /usr/local/s
常遇错误
1 编写错误
2 tab键错误Illegal tab character(jinja不支持tab)
3 key后面要空格 mode: 644 -- 注意空格: 不然会 报错:Too many functions declared in state "file"
4 注意要顶格写,不然会报格式错误
{% if <statment1> %}
{% if <statment2> %}
/etc/logrotate.d/nginx:
file.append:

浙公网安备 33010602011771号