Saltstack 的学习总结
Saltstack 的学习总结
一 、Saltstack的简介
SaltStack采用 C/S模式,server端就是salt的master,client端就是minion,minion与master之间通过ZeroMQ消息队列通信。minion上线后先与master端联系,把自己的pub
key发过去,这时master端通过salt-key-L命令就会看到minion的key,接受该minion-key后,也就是master与minion已经互信。master可以发送任何指令让minion执行了,salt有很多可执行模块,比如说cmd模块,在安装minion的时候已经自带了,它们通常位于你的python库中,locate
salt | grep/apps/ns1/python/bin/salt
可以看到salt自带的所有东西。这些模块是python写成的文件,里面会有好多函数,如cmd.run,当我们执行/apps/ns1/python/bin/salt'*'
cmd.run 'uptime'
的时候,master下发任务匹配到的minion上去,minion执行模块函数,并返回结果。master监听4505和4506端口,4505对应的是ZMQ的PUBsystem,用来发送消息,4506对应的是REPsystem是来接受消息的。
具体步骤如下
1. Saltstack的Master与Minion之间通过ZeroMq进行消息传递,使用了ZeroMq的发布-订阅模式,连接方式包括tcp,ipc
2. salt命令,将cmd.runls
命令从salt.client.LocalClient.cmd_cli
发布到master,获取一个Jodid,根据jobid获取命令执行结果。
3. master接收到命令后,将要执行的命令发送给客户端minion。
4. minion从消息总线上接收到要处理的命令,交给minion._handle_aes
处理
5. minion._handle_aes
发起一个本地线程调用cmdmod执行ls命令。线程执行完ls后,调用minion._return_pub
方法,将执行结果通过消息总线返回给master
6. master接收到客户端返回的结果,调用master._handle_aes
方法,将结果写的文件中
7. salt.client.LocalClient.cmd_cli
通过轮询获取Job执行结果,将结果输出到终端。
二、saltstack 的安装
(略)
三、Salt常用命令(远程执行命令)
1、salt该命令执行salt的执行模块,通常在master端运行,也是我们最常用到的命令
salt [options]'<target>'<function>[arguments]
如: /apps/ns1/python/bin/salt '*' test.ping
2、salt-run 该命令执行runner(salt带的或者自定义的,runner以后会讲),通常在master端执行,比如经常用到的manage
/apps/ns1/python/bin/salt-run [options] [runner.func]
/apps/ns1/python/bin/salt-run manage.status ##查看所有minion状态
/apps/ns1/python/bin/salt-run manage.down ##查看所有没在线minion
/apps/ns1/python/bin/salt-run manged.up ##查看所有在线minion
3、salt-key **管理,通常在master端执行
/apps/ns1/python/bin/salt-key [options]
/apps/ns1/python/bin/salt-key -L ##查看所有minion-key
/apps/ns1/python/bin/salt-key -a<key-name> ##接受某个minion-key
/apps/ns1/python/bin/salt-key -d<key-name> ##删除某个minion-key
/apps/ns1/python/bin/salt-key -A ##接受所有的minion-key
/apps/ns1/python/bin/salt-key -D ##删除所有的minion-key
4、salt-call 该命令通常在minion上执行,minion自己执行可执行模块,不是通过master下发job
salt-call [options] <function> [arguments]
salt-call test.ping ##自己执行test.ping命令
salt-call cmd.run 'ifconfig' ##自己执行cmd.run函数
5、salt-cp 分发文件到minion上,不支持目录分发,通常在master运行
salt-cp [options] '<target>' SOURCEDEST
salt-cp '*' testfile.html /tmp
salt-cp 'test*' index.html /tmp/a.html
6、salt-master master运行命令
salt-master [options]
salt-master ##前台运行master
salt-master -d ##后台运行master
salt-master -l debug ##前台debug输出
7、 salt-minion minion运行命令
salt-minion [options]
salt-minion ##前台运行
salt-minion -d ##后台运行
salt-minion -l debug ##前台debug输出
四、saltstack 的常用模块以及API
简介
Saltstack 提供了十分丰富的功能模块,涉及操作系统的基础信息、常用工具支持等。可以参看更多模块的相关信息:
https://docs.saltstack.com/en/latest/ref/modules/all/index.html
可以通过/apps/ns1/python/bin/salt ‘*’ sys.list_modules 参看当前版本系统支持的相关模块。
以下是运行/apps/ns1/python/bin/salt ‘*’ sys.list_modules命令后的部分截图
接下来是saltstack的十大常用模块以及对应API的介绍
Saltstack –API的简介
API的原理是调用master client 模块,创建LocalClient对象,在调用cmd()方法来实现。
示例:通过API实现test.ping
Importsalt.client
client= salt.client.LoaclClient()
ret= client.cmd(‘*’,’test.ping’)
printret
运行后的结果如下:
Archive 模块
1) 功能:实现系统层面的压缩包调用,支持gunzip、gzip、rar、tar、unrar、unzip等
2) 示例
利用gunzip 对/apps/file/soucrefile.txt.gz 解压
/apps/ns1/python/bin/salt ‘*’ archive.gunzip /apps/file/soucrefile.txt.gz
利用gzip 对/apps/file/soucrefile.txt 解压
/apps/ns1/python/bin/salt ‘*’ archive.gzip /apps/file/soucrefile.txt
3) API 调用示例:利用gunzip 对/apps/file/soucrefile.txt.gz 解压
Import salt.client
client = salt.client.LocalClient()
ret = client.cmd(‘*’,’archive.gzip’,[‘/apps/file/soucrefile.txt.gz’])
cmd 模块
1) 功能:实现远程的命令行调用执行(默认具备root操作权限)
2) 示例:
获取所有被控主机的内存使用情况
/apps/ns1/python/bin/salt ‘*’ cmd.run “free -m”
3)API 调用示例: 获取所有被控主机的内存使用情况
#!_INSX/python/bin/python
# -*- coding:UTF-8 -*-
Import salt.client
Client = salt.client.LocalClient()
Ret = Client.cmd(‘*’,’cmd.run’,[‘free –m’])
cp模块
1) 实现远程文件、目录的复制,以及下载url 文件操作等
2) 示例
将指定被控主机的/etc/hosts 文件复制到被控制主机本地的file 目录下(/apps/file)
/apps/ns1/python/bin/salt ‘*’ cp.cache_local_file /etc/hosts
将主服务器file_roots指定位置下的目录复制到被控主机
/apps/ns1/python/bin/salt ‘*’ cp.get_dir salt://path/to/dir/ /minion/dest
下载URL内容到被控主机指定位置
/apps/ns1/python/bin/salt ‘*’ cp.get_url http://www.slashdot.org /tmp/index.html
3) API调用示例:下载URL内容到被控主机指定位置
#!_INSX/python/bin/python
# -*- coding:UTF-8 -*-
Import salt.client
Client = salt.client.LocalClient()
Ret = Client.cmd(‘*’,’cp.get_url’,[‘http://www.slashdot.org’,’ /tmp/index.html’])
cron模块
1) 功能:控主机的crontab操作
2) 示例:
查看指定被控主机、root用户的crontab清单
/apps/ns1/python/bin/salt ‘*’ cron.row_cron root
为指定的被控主机、root用户添加/usr/local/weekly任务作业
/apps/ns1/python/bin/salt ‘*’ cron.set_job root ‘*’ ‘*’ ‘*’‘*’ 1 /usr/local/weekly
删除指定的被控主机、root用户crontab的/usr/local/weekly任务作业
/apps/ns1/python/bin/salt ‘*’ cron.rm_job root/usr/local/weekly
3) API调用:删除指定的被控主机、root用户crontab的/usr/local/weekly任务作业
#!_INSX/python/bin/python
# -*- coding:UTF-8 -*-
Import salt.client
Client = salt.client.LocalClient()
Ret = Client.cmd(‘*’,’cron.rm_job’,[‘root’,’/usr/local/weekly’])
dnsutil模块
1) 功能:实现被控主机通用DNS相关操作
2) 示例:
添加指定被控主机hosts的主机配置项
/apps/ns1/python/bin/salt ‘*’ dnsutil.hosts_append/etc/hosts 127.0.01 ad1.yuk.com ,d2.yuk.com
删除指定被控主机hosts的主机配置项
/apps/ns1/python/bin/salt ‘*’ dnsutil.hosts_remove/etc/hosts ad1.yuk.com
3) API 调用:删除指定被控主机hosts的主机配置项
#!_INSX/python/bin/python
# -*- coding:UTF-8 -*-
Import salt.client
Client = salt.client.LoaclClient()
Ret = Client.cmd(‘*’,’dnsutil.hosts_remove’,[‘/etc/hosts’,’ad1.yuk.com’])
file模块
1) 功能:被控主机文件常见操作,包括文件读写、权限、查找、校验等
2) 示例:
校验所有被控主机/etc/fstab文件的md5是否为6254e84e2f6ffa54e0c8d9cb230f5505,一致则返回True
/apps/ns1/python/bin/salt ‘*’ ilechenk_hash
/etc/fstab d5=6254e84e2f6ffa54e0c8d9cb230f5505
复制本地所有被控主机本地 /path/to/src 文件到本地的/path/to/dat文件
/apps/ns1/python/bin/salt ‘*’ file.copy /path/to/src /path/to/dat
获取所有被控主机/etc/passwd 的stats 信息
/apps/ns1/python/bin/salt ‘*’ ile.stats /etc/passwd
获取所有被控主机/etc/passwd的权限mode,如755,644
/apps/ns1/python/bin/salt ‘*’ file.get_mode /etc/passwd
修改所有被控主机/etc/passwd的权限mode为0644
/apps/ns1/python/bin/salt ‘*’ file.set_mode /etc/passwd0644
在所有被控主机创建/opt/test目录
/apps/ns1/python/bin/salt ‘*’ file.mkdir /opt/test
给所有被控主机的/tmp/test/testc.onf 文件追加内容”maxclient 100”
/apps/ns1/python/bin/salt ‘*’ file.append/tmp/test/testc.onf ”maxclient 100”
删除所有被控主机的/tmp/foo文件
/apps/ns1/python/bin/salt ‘*’ file.remove /tmp/foo
3)API调用:删除所有被控主机的/tmp/foo文件
#!_INSX/python/bin/python
Import salt.client
Client = salt.client.LocalClient()
Ret = Client.cmd(‘*’,’file.remove’,[‘/tmp/foo’])
Iptables模块
1) 功能:被控主机iptables支持
2) 示例:
在所有被控端主机追加(append)、插入(insert)iptables规则,其中INPUT为输入链
Salt ‘*’ iptables.append filter INPUT rule = ‘-m state –stateRELATED,ESTABLISHED –J ACCEPT’
保存所有被控端主机规则到本地硬盘(/etc/sysconfig/iptales)
/apps/ns1/python/bin/salt ‘*’ iptables.save etc/sysconfig/iptales
3)API调用:在所有被控端主机追加(append)iptables规则,其中INPUT为输入链
#!_INSX/python/bin/python
Import salt.client
Client = salt.client.LocalClient()
Ret = Client.cmd(‘*’,’iptables.append’,[‘filter’,’INPUT’, ‘rule= \’-m state ELATED,ESTABLISHED –J ACCEPT\’’])
Network模块
1) 功能:返回被控主机网络信息
2) 示例:
获取所有被控主机的MAC地址
/apps/ns1/python/bin/salt ‘*’ network.hwaddrs eth0
获取所有被控主机的网卡配置信息
/apps/ns1/python/bin/salt ‘*’ network.interfaces
获取所有被控主机的IP地址配置信息
/apps/ns1/python/bin/salt ‘*’ network.ip_addrs
获取指定被控主机的子网信息
/apps/ns1/python/bin/salt ‘*’ network.subnets
3) API调用:获取指定被控主机的子网信息
#!_INSX/python/bin/python
Import salt.client
Client =salt.client.LocalClient()
Ret = Client.cmd(‘*’,’network.subnets’)
Pkg包管理模块
1) 功能:被控主机程序包管理,如yum、apt-get等
2) 示例:
为所有被控主机安装php环境
/apps/ns1/python/bin/salt ‘*’ pkg.install php
卸载所有被控主机的php环境
/apps/ns1/python/bin/salt ‘*’ pkg.remove php
升级所有被控主机的软件包
/apps/ns1/python/bin/salt ‘*’ pkg.upgrade
3)API 调用:卸载所有被控主机的php环境
#!_INSX/python/bin/python
Import salt.client
Client =salt.client.LocalClient()
Ret = Client.cmd(‘*’,’pkg.remove’,[‘php’])
Service服务模块
1) 功能:被控主机程序包服务管理
2) 示例:
开启(enable)、禁用(disables)nginx开机自启动服务
/apps/ns1/python/bin/salt ‘*’ service.enable nginx
/apps/ns1/python/bin/salt ‘*’ service.disable nginx
针对nginx服务的reload、restart、start、stop、status操作
/apps/ns1/python/bin/salt ‘*’ service.reload nginx
/apps/ns1/python/bin/salt ‘*’ service.restart nginx
/apps/ns1/python/bin/salt ‘*’ service.start nginx
/apps/ns1/python/bin/salt ‘*’ service.stop nginx
/apps/ns1/python/bin/salt ‘*’ service.status nginx
3) API调用:针对niginx服务的reload操作
#!_INSX/python/bin/python
Import salt.client
Client = salt.client.LocalClient()
Ret = Client.cmd(‘*’,’service.reload’,[‘nginx’])
Grains组件
Grains是Saltstack最重要的组件之一,grians的作用是收集被控主机的基本信息,这些信息通常都是一些静态类型的数据,包括被控主机的CPU、内核、操作系统、虚拟化等信息。
Grains常用操作命令
示例1:匹配内版本为2.6.32-358.14.1e16.x86_64的主机
/apps/ns1/python/bin/salt–G ‘kernelrelease:2.6.32-358.14.1e16.x86_64’ cmd.run ‘uname –a’
示例2:获取所有主机的grains项信息
/apps/ns1/python/bin/salt ‘*’ grains.ls
示例3:获取被控主机单项数据
/apps/ns1/python/bin/salt ‘*’ grains.itemos
定义Grains数据
定义grains数据有两种,其中一种为在被控主机定制配置文件,这种比较方便,但有局限性;另一种是通过主控端扩展模块API来实现,用Python编程动态定义。
被控端主机定制grains数据
通过手动更新被控主机的grains文件、让master进行采集
1) 在每台被控主机上新建/etc/salt/minion.d/hostinfo.conf文件
Grains:
Roles:
---webserver
2) 重启salt-minion服务
(1) Cp/apps/ns1/utils
(2) ./salt-minion restart
通过主控端master扩展API来实现
首先,需要明确master上的bash目录,可以到/etc/salt/master配置文件的file_roots处查看,默认为/srv/salt
1) 新建一个_grains目录
Install –d /apps/ns1/srv/salt/_grains
2) 在_grains目录下新建一个py文件(例如)
[/srv/salt/_grains/sysprocesss.py]
#!_INSX/python/bin/python
# -*- coding:UTF-8 -*-
import os
import sys
import commands
def Grains_openfile():
"""
:return: os max open file ofgrains value
"""
grains = {}
# init default value
_open_file = 65536
try:
getulimit =commands.getstatusoutput('source /etc/profile;ulimit -n')
except Exception
as e:
pass
if getulimit[0] ==
0:
_open_file = int(getulimit[1])
grains['max_open_file'] = _open_file
print grains
return grains
3) 新建文件之后,需要分发到所有Minion上
/apps/ns1/python/bin/salt ‘*’ saltutil.sync_all
4) 刷新模块
/apps/ns1/python/bin/salt ‘*’ sys.reload_modules
5) 收集数据
/apps/ns1/python/bin/salt ‘*’ grains.item max_open_file
6) 运行结果
Pillar组件
Pillar简介
Pliiar也是Saltstack最重要的组件之一,其主要作用是定义与被控主机相关的任何数据,定义好的的数据可以被其他组件使用,如模板、state、API等,在pillar定义的数据与不同业务特性的被控主机相关联,这样不同被控主机只能看到自己匹配的数据,因此pillar安全性很高,适用于一些比较敏感的数据,这是区别于grains的最关键的一点。
Pillar的定义
主配置文件定义
Saltstack默认将主控端配置文件中的所有数据都定义到pillar中,而且对所有被控主机开放。可以通过修改/etc/salt/master配置中的pillar_opts:True 或False来定义是否开启或者禁用这项功能。
运行:/apps/ns1/python/bin/salt‘*’ pillar.data 命令来查看效果
SLS文件定义
Pillar 支持在sls文件中定义数据,格式必须符合YAML规范,与SaltStack的组件十分相似。两者文件的配置格式、入口文件top.sls都是一致的。
1) 定义pillar 的主要目录
修改主配置文件/etc/salt/master的参数,定义pillar的主目录,格式如下:
Pillar_roots:
Base:
---/srv/pillar
同时创建pillar目录,执行命令
Install -d /apps/ns1/srv/pillar
2) 定义入口文件top.sls
入口文件的作用一般是定义pillar的数据覆盖别控主机的有效域范围,‘*’代表任意主机,其中包括一个data.sls文件,具体内容如下:
[/srv/pillar/top.sls]
Base:
‘*’:
— data
[/srv/pillar/data.sls]
Appname: website
Flow:
Maxconn: 30000
Maxmem: 6G
3) 校验pillar
(1) 刷新被控制主机的pillar 信息,执行如下命令。
/apps/ns1/python/bin/salt '*' saltutil.refresh_pillar
(2) 查看定义的data.sls数据,执行如下命令。
/apps/ns1/python/bin/salt '*' pillar.data appname flow
(3) 运行结果:
Pillar的使用
完成pilllar配置后,接下来简单介绍使用方法。可以在state、模板文件中引用,模板格式为“{{ pillar 变量}}”,例如:
{{pillar[‘appname’] }} (一级字典)
{{pillar[‘flow][‘maxconn’] }}(二级字典)或者{{ salt[‘pillar.get’] (‘flow’:’maxconn’,{}) }}
Python API格式如下:
Pillar[‘flow’][‘maxconn’]
Pillar.get(‘flow:appname’, {})
操作目标主机
通过 –I 选项来使用Pillar 来配置被控主机
/apps/ns1/python/bin/salt-I 'appname:website' test.ping
结合grains处理数据的差异性
首先通过结合grains的id信息来区分不同id的maxcpu的值,其次进行引用观察匹配的信息。我还是延伸‘pillar的定义’的例子将data.sls 修改成如下形式,其中,“if … else …endif”为jinja2的模块语法,jinja2语法可参考:http://jinja.pocoo.org/docs/2.10/templates/
[/srv/salt/data.sls]
Appname: website
Flow:
Maxconn: 3000
Maxmem: 6G
{% if grains[‘id’] == ‘172.30.154.60’ %}
Maxcpu: 8
{% else %}
Maxcpu: 4
{% endif %}
编写好data.sls文件后。执行以下步骤:
(1) 刷新被控制主机的pillar 信息,执行如下命令。
/apps/ns1/python/bin/salt '*' saltutil.refresh_pillar
(2) 查看定义的data.sls数据,执行如下命令。
/apps/ns1/python/bin/salt '*' pillar.data appname flow
(3) 运行结果:
State介绍
State是Saltstack最核心的功能,通过预先定制好的sls(salt state file)文件对被控主机进行状态管理,支持包括程序包(pkg)、文件(file)、网络配置(network)、系统服务(service)、系统用户(user)等。更多状态对象见 :
https://docs.saltstack.com/en/latest/ref/states/all/index.html
state的定义
state的定义是通过sls文件进行描述的。支持YAML语法,定义的规则如下:
$ID:
$State:
—$state: states
其中:
$ID,定义state的名称,通常采用与描述的对象保存一致的方法,如apache、nginx等。
$State,管理对象的类型,,看参考:
https://docs.saltstack.com/en/latest/ref/states/all/index.html
$state: states,定制对象的状态
如下例子:
Apache:
Pkg:
—installed
Service:
—running
—require:
—pkg: apache
注意:第6行是关键字require,它确保了apache服务只有在成功安装软件包后才会启动
State的使用
State的入口文件和pillar一样,文件名称都是top.sls,但是state要求文件必须存放在saltstack base目录下,默认为/srv/salt。State描述配置.sls支持jinja模块、grains以及pillar引用等。在state的逻辑层次定义完成后,再通过 salt ‘*’ state.highstate 执行生效。
定义pillar
[/srv/pillar/top.sls]
Base:
“*”:
—apache
在top.sls中引用二级配置有两种方式:一是直接引用,二是创建apache目录,在引用目录中的init.sls文件。
先执行如下命令:
Install -d /srv/pillar/apache 或者mkdir/srv/pillar/apache
[/srv/pillar/apache/init.sls]
Pkgs:
{% if grains[‘os_family’]== ‘Debian’ %}
Apache: apache2
{% elif grains[‘os_family’] == ‘RedHat’ %}
Apache: httpd
{% elif grains[‘os_family’] == ‘Arch’ %}
Apache: apache
{% endif %}
编写好init.sls文件后。执行以下步骤:
(1) 刷新被控制主机的pillar 信息,执行如下命令。
/apps/ns1/python/bin/salt '*' saltutil.refresh_pillar
(2) 查看定义的data.sls数据,执行如下命令。
/apps/ns1/python/bin/salt '*' pillar.data pkgs
定义state
[/srv/salt/top.sls]
Base:
‘*”:
—apache
[/srv/salt/apache/init.sls]
Apache:
Pkg:
—installed
—name: {{ pillar[‘pkgs’][‘apache’] }}
Sevice:
—name: {{ pillar[‘pkgs’][‘apache’] }}
—require:
—pkg: {{pillar[‘pkgs’][apache’] }}
执行state
/apps/ns1/python/bin/salt'*' state.highstate
Saltstack事件系统与反应系统(event and reacter system)
简介
Master和Minion是基于ZMQ通信的。它们通信的消息队列就是一些事件。反应系统就是基于事件系统的。一条消息其实就是一个事件,事件通常是一个字典数据,这个字典数据通常包含tag,这个tag是用来区分用途过滤消息的。
事件系统(event system)
捕捉事件(list event)
事件代码
官方网给的事件捕捉程序eventlisten 可见:
https://github.com/saltstack/salt/blob/develop/tests/eventlisten.py
打开网址,复制下载,不要直接wget
运行程序
Master: python eventlisten.py ##捕捉master端的event直接运行即可
Minion: python eventlisten.py -n minion <minion-id> ##捕捉minion端的需要额外参数,minion-id是该Minion的id
发送事件(fire event)
Matert 发给minion
salt '*'event.fire "{'data': 'some message'}""tag" ##前面必须是字符串包住的字典,后面是tag,如果你的minion在监听event,你会看到这条event的
Minion发给minion
salt-call event.fire_master 'some message''tag' ##前面数据类型没有要求,后面是tag,去master那看看收到了没有
Minion发给自己
salt-call event.fire "{'data': 'some message'}"'tag'##前面必须是字符串包住的字典,后面是tag
用code来捕捉,并发送event
捕捉事件
Master:
# python2.6
>>> import salt.utils.event
>>> event = salt.utils.event.SaltEvent('master', '/var/run/salt/master')
##master表明是在master端监听,/var/run/salt/master是你master的sock_dir
>>> data = event.get_event()
>>> print(data) ##查看内容
>>> data = event.get_event(wait=10, tag='auth') ##wait是指timeout时间,默认5s,用tag来过滤事件,可省略
>>> print(data)
>>> for data inevent.iter_events(tag='auth'): ##用迭代器一直查看事件
>>> print(data)
Minion:
#python2.6
>>> import salt.utils.event
>>> event = salt.utils.event.SaltEvent('minion', '/var/run/salt/minion',id='minion_id')
##minion代表是在minion端监听,/var/run/salt/minion是minion端的sock_dir,minion_id是该Minion的id
>>> data = event.get_event()
>>> print(data)
>>> for data inevent.iter_events(tag='auth'): ##用迭代器一直查看事件
>>> print(data)
发送事件:
Master:
>>> import salt.utils.event
>>> event = salt.utils.event.SaltEvent('master', '/var/run/salt/minion')
>>> event.fire_event({'hello': 'world'}, 'hello')
反应系统(reacter system)
反应系统是基于事件系统的,它的作用是当master收到来自minion的特殊事件后就触发某些动作,比如minion上线后发送一个init事件,master收到后,对其应用init的状态文件,minion没有反应系统,事情就是这样的。
配置reactor
修改master配置文件或者在/etc/salt/master.d/中建立reactor.conf,内容
reactor:
- 'testtag': ##接收到的tag
- /srv/reactor/start.sls
- /srv/reactor/monitor.sls
- 'test1*tag': ##接收到的tag,支持通配符
- /srv/reactor/other.sls
建立reactor响应sls文件
[/srv/reacter/start.sls]
{% if data['id'] == 'mysql1' %}
delete_file:
cmd.cmd.run:
- tgt: '[email protected]:CentOS'
- expr_form: compound
- arg:
- rm -rf /tmp/*
{% endif %}
[/srv/reactor/other.sls]:
{% if data['data']['state'] == 'refresh' %}
overstate_run:
runner.state.over
{% endif %}
下面来解释一下这两个文件,reacter的sls文件是支持jinja的,所以第一行是通过jinja来判断,reacter的sls支持两个变量data和tag, data是接受事件的那个字典,tag就是事件的tag,所以第一行的判断就很好理解了,第二行是id,可以随意起,第三行是要运行的执行模块或者runner,如果是执行模块,以cmd.开始,如果是runner则以runner.开始,可执行模块执行需要target,所以- tat:后面跟的就是可执行模块的target,- expr_form指的target的匹配方式,- arg是只执行模块函数的参数,runner一般不需要这些。所以第一个示例相当于执行了salt -C '[email protected]'cmd.run 'rm -rf /tmp/*' 第二个相当于执行了 salt-run state.over
Returners
默认所有minion返回的值都会发送到master端,我们可以看到,returner就是让Minion把返回的值发给其它地方,如redis,MySQL,或者一个文本下面我们来自定义一个returner:
1.建立自定义returner
mkdir -p /srv/salt/_returners;
vim mysql.py ##就用官方给的例子吧,修改其中mysql的Host,user和pass
内容见https://github.com/saltstack/salt/blob/develop/salt/returners/mysql.py
2.建立需要的数据库
见https://github.com/saltstack/salt/blob/develop/salt/returners/mysql.py注释里的见表语句
3.授权其他主机用户可写该表
>grant all on salt.* to 'user_in_returner'@'%'identified by 'passwd_in_returner';
4.同步
salt '*' saltutil.sync_all ##同步到minion上去
5.测试
salt '*' test.ping --return mysql ##数据返回到mysql上去,打开mysql查看
扩展salt
扩展salt简述
通过自定义各个模块来扩展salt,常见自定义模块有:
可执行模块 Execution Modules
如我们常用的cmd.run ,test.ping这样的可执行模块
Grains
扩展grains,grains是一些静态信息,可能好多我们需要的没有,我们可以通过编写grains模块自定义grains
状态模块 State Module
如我们常用的pkg.install,file.managed
Returners
我们可以自定义returner,将返回的数据发送到其他存储,只要符合固定的格式就行了
Runner
Runner是在master端快速执行的模块,自定义很方便
自定义可执行模块
所有可执行module见https://github.com/saltstack/salt/tree/develop/salt/modules,或http://docs.saltstack.com/ref/modules/all/index.html?highlight=full%20list%20builtin
建立自定义模块目录,通常所有自定义模块放在该目录下
mkdir /srv/salt/_modules
编写模块
vim test.py
#!_INSX/python/bin/python
# -*- coding:UTF-8 -*-
'''
support for yum of RedHat family!
'''
def __virtual__():
'''
Only RedHat family os can use it.
'''
if __grains__.get('os_family',
'unkown') ==
'RedHat':
return 'yum'
else:
return False
def install(rpm):
cmd = 'yum -y install {0}'.format(rpm)
ret = __salt__['cmd.run'](cmd)
return ret
说明:__virtual__
函数通常用来匹配是否满足该模块的环境,如果满足return出来的字符串作为该模块的名字而不是文件名,如果return的是False代表的此模块无效,不能使用。在自定义模块中可以中__grains__
是一个包含了minion
所有grains的字典,__pillar__
是包含了所有Pillar的grains字典,__salt__
是所有可执行函数对象的字典,通常最常使用的就是这三个变量了。再往下面是定义了函数install,在salt中一般不用’%s’
%var这种格式化形式,而是使用字符串的format方法,具体使用见百度。下面就是通过__salt__
执行了cmd.run这个函数来运行yum命令,很简单吧,最后把结果返回回去。
测试
salt '*' yum.install ftp ##查看返回值
自定义grains
自定义的grains也是由Python写成的,通常放在/srv/salt/_grains下,grains需要返回一个字典,__salt__,__grains__,__pillar__也是可以在grains中使用的。前面已经介绍过写简单自定义grains了,复杂就就参照https://github.com/saltstack/salt/blob/develop/salt/grains/core.py官方这个吧
自定义returner
前面已经看过官方的mysql的returner了,今天来说说自定义returner需要注意的,来个例子吧。/srv/salt/_returners/file.py内容
#!_INSX/python/bin/python
# -*- coding:UTF-8 -*-
def __virtual__():
return 'file'
def returner(ret):
'''
Return information to/tmp/returns.txt.
'''
# open a file
result_file = '/tmp/returns.txt'
f = open(result_file,
'a+')
f.write(str(ret))
f.close()
程序编好后分别执行以下命令
salt '*' saltutil.sync_all ##同步模块
salt '*' test.ping --return file ##测试
cat /tmp/returns.txt ##在minion上查看
{'jid': '20131227153001246117', 'return': True, 'retcode': 0, 'success': True,'fun': 'test.ping', 'id': 'test1'}
说明:通过这个简单的例子我们了解返回的值是个字典,字典包括的项就是上面我们看到的,以后写其它returner时,也就是把这个字典的值写到不同的地方而已。这个returner的意思就是把返回的值写到各个minion的/tmp/returns.txt中。
应用实例
saltstack 远程触发文件备份、回滚
创建模块方法文件
mkdir /srv/salt/_modules
默认没有此文件,自己生成一个
下面的py文件自己定义,下面是我写的两个方法:
#!_INSX/python/bin/python
# -*- coding:UTF-8 -*-
import sys,
string,
shutil
import os,
tarfile
import datetime,
time
tn = datetime.datetime.today()
time_now = tn.strftime("%Y-%m-%d")
data_bak = '/data/databak'
data_tmp = '/data/databak/tmp/%s'
% time_now
com_f = "%s/%s"% (data_bak,
time_now)
if not os.path.exists(com_f):
os.makedirs(com_f)
def CpFile():
id = sys.argv[1]
dir = sys.argv[2]
# 传入两个变量,任务自动生成的id与要替换的文件
filename = '%s/%s.tar'
% (com_f,
id)
mode = 'w:tar'
os.chdir(data_bak)
w_file = open("/tmp/tmp.list",
'w')
w_file.write(id + " " + dir) #
记录每次备份的id与相对应的备份目录或文件的路径
w_file.close()
file = tarfile.open(filename, mode)
file.add('/tmp/tmp.list')
file.add(dir)
file.close()
return 'ok' #
测试过程,就先让返回ok吧,之后再做判断
def RollBack():
id = sys.argv[1]
# 想要回滚到的版本id
if not os.path.exists(data_tmp):
os.makedirs(data_tmp)
filename = '%s/%s.tar' % (com_f,
id)
tar = tarfile.open("%s" % filename)
for b
in tar:
tar.extract(b, path="%s"
% data_tmp)
tar.close()
for line
in open('%s/tmp/tmp.list'
% data_tmp):
id = line.split(" ")[:1][0]
dir = line.split(" ")[1:][0] #
读取备份时的路径
backup_dir = '%s/%s'
% (data_tmp,
dir)
os.system('\cp -rp %s %s' % (backup_dir,
dir))
return 'ok'
测试
master上同步方法脚本到节点
salt '*' saltutil.sync_all
然后先测试备份方法
salt ‘*’ cp_bakfile.CpFile 1234 /tmp/test #id + 路径上节点服务器上查看,存在
把/tmp/test下内容删除,测试回滚操作
salt '*' cp_bakfile.RollBack 1234
参考
[1] 刘天斯. Python自动化运维:技术与最佳实践[M].北京.机械工业出版社.2014.11 169-186
[2] http://outofmemory.cn/saltstack/salt