[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: