saltstack(七)返回值
一、自定义创建模块
|
1
2
3
4
5
6
7
8
|
[root@localhost:]# tree -L 3 saltsalt├── etc├── _grains│ ├── dmp_scribe.py│ └── zabbix_conf.py├── _modules│ └── ip.py |
通过上图可以看到已经创建了一个名为ip.py文件,看看相关内容:
|
1
2
3
4
5
6
7
8
9
10
|
#!/usr/bin/env pythonimport commandsdef eth1(): ip={} cmd = "ifconfig eth1|grep inet|awk '{print $2}'|awk -F : '{print $2}'" ip2=commands.getoutput(cmd).strip() ip['ip']=ip2 return ip |
定义模块我们没有在/srv/salt/top.sls文件中新增模块名,现在把写好的模块同步到你需要执行的机器上,可以全部同步,也可以针对性的同步
这里只演示同步一台
|
1
2
3
|
salt '192.168.10.128' saltutil.sync_modules192.168.10.128: - modules.ip |
在master执行编写的模块,由于不依赖state.sls文件,所以执行时命令也有变化,在主要命令后面跟模块名●函数名
|
1
2
3
4
5
|
[root@localhost _modules]# salt '192.168.10.128' ip.eth1192.168.10.128: ---------- ip: 192.168.10.128 |
二、屏幕返回值输出到指定的位置
saltstack执行命令时默认的返回值都是打印在当前屏幕上的,如果一次执行多台机器,怎么查看这些记录,为了更方便的查看这些返回结果的信息,这就用到了salt的returners功能了。关于详细介绍请参考官网地址:http://docs.saltstack.cn/ref/returners/index.html?highlight=returners
在/srv/salt目录下创建_returners目录,将自己编写的模块都可以存放在该目录下。
|
1
2
3
4
5
|
├── _returners│ ├── local_return.py #输出到文件│ ├── mysql_log.py #输出到数据库│ ├── nohup.out│ ├── salt_event_to_mysql.py |
在_returners目录下创建了两个文件,一个是local_return.py:表示把执行结果存在在本地
一个是mysql_log.py:表示把结果存放在mysql数据库中
1、返回结果存放到本地
|
1
2
3
4
5
6
7
8
|
#coding:utf-8def __virtual__(): '''调用时的名字''' return "local_return"def returner(ret): f=open('/var/log/salt/local_returner.log','a+') f.write(str(ret)[1:-1]+'\n') f.close() |
和自建模块一样,在编写完returners之后,也要同步到客户端的,同步的规则和自建模块一样。
|
1
|
salt '192.168.10.128' saltutil.sync_returners |
在执行完上面的语句后,执行salt ‘192.168.10.128’cmd.run 'uptime' --return local_return
验证结果是否已经输出到文件中
2、返回结果存放在mysql中
官方默认returners中已经包含了mysql的returners,我们先直接利用官方原生的mysql returners,里面有创建相关表的语句。
官方的mysql returners源码在https://github.com/saltstack/salt/blob/develop/salt/returners/mysql.py
mysql服务器192.168.10.129:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
#在mysql服务器上创建表CREATE DATABASE `salt` DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci; USE `salt`; -- -- Table structure for table `jids` -- DROP TABLE IF EXISTS `jids`; CREATE TABLE `jids` ( `jid` varchar(255) NOT NULL, `load` mediumtext NOT NULL, UNIQUE KEY `jid` (`jid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- -- Table structure for table `salt_returns` -- DROP TABLE IF EXISTS `salt_returns`; CREATE TABLE `salt_returns` ( `fun` varchar(50) NOT NULL, `jid` varchar(255) NOT NULL, `return` mediumtext NOT NULL, `id` varchar(255) NOT NULL, `success` varchar(10) NOT NULL, `full_ret` mediumtext NOT NULL, `alter_time` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, KEY `id` (`id`), KEY `jid` (`jid`), KEY `fun` (`fun`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; |
给相关salt表赋予访问权限:
|
1
|
GRANT ALL PRIVILEGES ON salt.* TO 'salt'@localhost IDENTIFIED BY 'saltt'; |
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
mysql> show databases;+--------------------+| Database |+--------------------+| information_schema || salt |+--------------------+2 rows in set (0.00 sec)mysql> use saltmysql> show tables;+----------------------------+| Tables_in_salt |+----------------------------+| jids || salt_returners |+----------------------------+ |
因为要把客户端执行命令的结果直接返回给mysql服务器,所以客户端也要配置mysql信息的,我们以192.168.10.128为例,在salt的配置文件中加入如下信息,你也可以把它单独写在一个文件中。为了方便管理推荐写在单独文件中:
|
1
2
3
4
5
6
|
#/etc/salt/minion.d/mysql.confmysql.host: '192.168.1.204'mysql.user: 'salt'mysql.pass: 'salt'mysql.db: 'salt'mysql.port: 3306 |
然后在master上执行命令,如下:
|
1
2
|
salt '192.168.10.128' cmd.run 'uptime' --return local_returnsalt '192,168.10.128' cmd.run 'uptime' --return mysql |
注意这里用的是salt官网原生的mysql returners,并没有使用自己定义的mysql_log returners ,我们看看数据库中的记录:(图片是借鉴大神的图片)

第一句是刚创建好表时的结果,可以看到数据库中已经有一条记录了,下面自己定义一个mysql_log returners来试试:
|
1
|
salt '192.168.10.128' cmd.run 'hostname' --return mysql_log |
我们来数据库中查看一下记录:

下面附上定义的mysql_log.py:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
|
#/usr/bin/python#coding:utf-8from contextlib import contextmanagerimport sysimport jsonimport logging# Import third party libstry: import MySQLdb HAS_MYSQL = Trueexcept ImportError: HAS_MYSQL = Falselog = logging.getLogger(__name__)def __virtual__(): if not HAS_MYSQL: return False return "mysql_log"def _get_options(): ''' Returns options used for the MySQL connection. ''' defaults = {'host': '192.168.1.204', 'user': 'salt', 'pass': 'salt', 'db': 'salt', 'port': 3306} _options = {} # Ensure port is an int for attr in defaults: _attr = __salt__['config.option']('mysql.{0}'.format(attr)) if not _attr: log.debug('Using default for MySQL {0}'.format(attr)) _options[attr] = defaults[attr] continue _options[attr] = _attr return _options@contextmanagerdef _get_serv(commit=False): ''' Return a mysql cursor ''' _options = _get_options() conn = MySQLdb.connect(host=_options['host'], user=_options['user'], passwd=_options['pass'], db=_options['db'], port=_options['port']) cursor = conn.cursor() try: yield cursor except MySQLdb.DatabaseError as err: error, = err.args sys.stderr.write(str(error)) cursor.execute("ROLLBACK") raise err else: if commit: cursor.execute("COMMIT") else: cursor.execute("ROLLBACK") finally: conn.close()def returner(ret): ''' Return data to a mysql server ''' with _get_serv(commit=True) as cur: sql = '''INSERT INTO `salt_returns` (`fun`, `jid`, `return`, `id`, `success`, `full_ret` ) VALUES (%s, %s, %s, %s, %s, %s)''' cur.execute(sql, (ret['fun'], ret['jid'], str(ret['return']), ret['id'], ret['success'], json.dumps(ret))) |
三、基于Salt Event系统构建Master端returner
上面我们介绍Saltstack的returner是由minion端主动连接returners完成执行结果的存储,在部分场景下并不能满足需求,由于salt底层已构建了一套Event系统,所有的操作均会产生event,因此基于Salt Event系统构建Master端returner成为一种可能。
SaltStack Event 系统 官网地址:http://docs.saltstack.com/en/latest/topics/event/index.html
SaltStack Event 系统监听events测试:http://pengyao.org/saltstack_event_system_listen_events.html
环境说明:
-
测试结构:Master/Minions结构
-
Salt Version:2015.8.8.2
-
本次测试结果将存放在mysql中
前置配置:
安装Mysqldb依赖: yum -y install MySQL-Python
配置本次测试需要使用的数据库及用户:
|
1
2
3
4
5
6
|
# 创建salt数据库mysql -e 'create database salt'# 创建用于连接salt数据库的用户mysql -e '"grant all on salt.* to salt@localhost identified by "salt_pass';# 将数据库配置添加至master配置文件中echo -e "\n\n# MySQL\nmysql.host: 'localhost'\nmysql.user: 'salt'\nmysql.pass: 'salt_pass'\nmysql.db: 'salt'\nmysql.port: 3306" >> /etc/salt/master |
为了与salt自带的mysql returners兼容,本次直接使用mysql returners对应的数据库表结构:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
USE `salt`;---- Table structure for table `jids`--DROP TABLE IF EXISTS `jids`;CREATE TABLE `jids` ( `jid` varchar(255) NOT NULL, `load` mediumtext NOT NULL, UNIQUE KEY `jid` (`jid`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;---- Table structure for table `salt_returns`--DROP TABLE IF EXISTS `salt_returns`;CREATE TABLE `salt_returns` ( `fun` varchar(50) NOT NULL, `jid` varchar(255) NOT NULL, `return` mediumtext NOT NULL, `id` varchar(255) NOT NULL, `success` varchar(10) NOT NULL, `full_ret` mediumtext NOT NULL, `alter_time` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, KEY `id` (`id`), KEY `jid` (`jid`), KEY `fun` (`fun`)) ENGINE=InnoDB DEFAULT CHARSET=utf8; |
编写returners:salt_event_to_mysql.py
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
#!/bin/env python#coding=utf8# Import python libsimport json# Import salt modulesimport salt.configimport salt.utils.event# Import third party libsimport MySQLdb__opts__ = salt.config.client_config('/etc/salt/master')# Create MySQL connectconn = MySQLdb.connect(host=__opts__['mysql.host'], user=__opts__['mysql.user'], passwd=__opts__['mysql.pass'], db=__opts__['mysql.db'], port=__opts__['mysql.port'])cursor = conn.cursor()# Listen Salt Master Event Systemevent = salt.utils.event.MasterEvent(__opts__['sock_dir'])for eachevent in event.iter_events(full=True): ret = eachevent['data'] if "salt/job/" in eachevent['tag']: # Return Event if ret.has_key('id') and ret.has_key('return'): # Igonre saltutil.find_job event if ret['fun'] == "saltutil.find_job": continue sql = '''INSERT INTO `salt_returns` (`fun`, `jid`, `return`, `id`, `success`, `full_ret` ) VALUES (%s, %s, %s, %s, %s, %s)''' cursor.execute(sql, (ret['fun'], ret['jid'], json.dumps(ret['return']), ret['id'], ret['success'], json.dumps(ret))) cursor.execute("COMMIT") # Other Event else: pass |
运行编写的returner: Python salt_event_to_mysql.py
测试:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
salt '*' test.ping #开启一个终端,运行salt指令#输出为:salt-minion-01.example.com: True#检查mysql数据库,查询salt_returns表数据:mysql salt -e "select * from salt_returns\G"#输出为:*************************** 1. row *************************** fun: test.ping jid: 20140417161103569310 return: true id: salt-minion-01.example.com success: 1 full_ret: {"fun_args": [], "jid": "20140417161103569310", "return": true, "retcode": 0, "success": true, "cmd": "_return", "_stamp": "2014-04-17T16:11:03.584859", "fun": "test.ping", "id": "salt-minion-01.example.com"} alter_time: 2014-04-17 16:11:03#入库成功 |

浙公网安备 33010602011771号