saltstack-模块的编写(三)saltstack的插件(四)log
虽然saltstack为我们提供很多模块,但是有时候还想自定义一些模块,那就涉及到模块的编写,在编写模块之前我们先了解一些内容。
一:__salt__变量的理解:如下是官网的解释
1 the variable __salt__ is packed into the modules after they are loaded into the Salt minion. 2 the __salt__ variable is a Python dictionary containing all of the Salt functions. Dictionary keys are strings 3 representing the names of the modules and the values are the functions themselves.
解释:变量__salt__ 当minion端的都加载完modules的时候,会创建(这里的创建可以理解是:所有的模块的名和对应的方法都加入到__salt__变量里。)一个变量__salt__。
__salt__变量是一个python字典,字典的内容包含了所有salt的函数方法。字典的key值是字符串,key值代表了salt的模块和方法的名字,value就是对应的模块的对应函数方法。
为什么要介绍__salt__变量,因为我们自定义的模块有可能使用到salt自身的模块的,通过__salt__字典,我们可以快速进行相关的设置。
二:__virtual__ Function:介绍
官方的介绍:
the __virtual__ function returns either a string, True, False, or False with an error string. If a string is returned then the module is loaded using the name of the string as the virtual name. If True is returned the module is loaded using the current module name. If False is returned the module is not loaded. False lets the module perform system checks and prevent loading if dependencies are not met.
解释:函数__virtual__ 内置函数返回的是:一个字符串、布尔值:True、False或者False和一个错误的字符串值。当返回一个字符串的时候,一个名字为该字符串的模块被加载,如果返回的是True的时候,表示当前使用的模块的名字被加载,如果
返回的是False的时候,表示当前的模块没有被加载,当返回False的时候,会强制让模块系统检查和阻止加载该模块,如果依赖不匹配的。
言外之意:该函数的作用是检测当前加载的模块的是否合法。
三:编写模块,需要知道调用的在命令行传入参数的形式,避免不知道传参的类型,导致问题的发生。
在命令行:
1 salt '*' op_red.con_re 127.0.0.1 6379 dd ok 22
后台解析的命令行:
1 Command details {'tgt_type': 'glob', 'jid': '20161216003357190093', 'tgt': '*', 'ret': '', 'user': 'root', 'arg': ['127.0.0.1', 6379, 'dd', 'ok'], 'fun': 'op_red.con_re'}
换一个字典传入:
1 salt '*' op_red.con_re 127.0.0.1 6379 set {'tom':'cc'}
后台处理的参数详情:注意!!!!!如下标红的不是json串 只是个字符串~~~!!! '{tom:cc}'
1 Command details {'tgt_type': 'glob', 'jid': '20161216004726926447', 'tgt': '*', 'ret': '', 'user': 'root', 'arg': ['127.0.0.1', 6379, 'set', '{tom:cc}'], 'fun': 'op_red.con_re'}
如下例子:
例子1:
''' Cheese execution (or returner/beacon/etc.) module ''' try: import enzymes HAS_ENZYMES = True except ImportError: HAS_ENZYMES = False def __virtual__(): ''' only load cheese if enzymes are available ''' if HAS_ENZYMES: return 'cheese' else: return False, 'The cheese execution module cannot be loaded: enzymes.. ,!unavailable.'
例子2:
''' Cheese state module ''' def __virtual__(): ''' only load cheese if enzymes are available ''' # predicate loading of the cheese state on the corresponding execution module if 'cheese.slice' in __salt__: return 'cheese' else: return False, 'The cheese state module cannot be loaded: enzymes unavailable.'
salt还为我们提供了其他的字典__GRAINS__、__PILLAR__、__CONTEXT__ 详细请看官网:https://docs.saltstack.com/en/latest/topics/development/dunder_dictionaries.html。
有了如上的介绍,我们可以进行自定义的模块的编写:
默认自定义模块文件目录:/srv/salt/_modules
创建该目录:mkdir -pv /srv/salt/_modules
创建自定义模块:
1 [root@localhost _modules]# cat test.py 2 3 def cmd(arg): 4 return __salt__['cmd.run'](arg)
minion端同步自定义模块:
1 [root@localhost _modules]# salt '*' saltutil.sync_modules 2 salt_minion: 3 - modules.test 4 [root@localhost _modules]#
执行自定义模块:
1 [root@localhost _modules]# salt '*' test.cmd w 2 salt_minion: 3 03:55:26 up 1 day, 23 min, 2 users, load average: 0.18, 0.12, 0.14 4 USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT 5 root tty1 - Thu01 12:05m 0.03s 0.03s -bash 6 root pts/0 192.168.217.1 Sun15 6:45 0.05s 0.05s -bash
需要注意的是:交叉调用salt模块的模式:__salt__['模块名字.函数名字'](参数)
__salt__['cmd.run'](arg)
如上是我们定义的参数不为空,当参数为空的时候,不能将()去掉。
[root@localhost _modules]# cat test1.py def cmd(): return __salt__['network.ip_addrs']() [root@localhost _modules]# salt '*' test1.cmd salt_minion: - 192.168.147.129 - 192.168.217.143
[root@localhost _modules]# salt '*' test1.cmd salt_minion: - 192.168.147.129 - 192.168.217.143 [root@localhost _modules]# cat test1.py def __virtual__(): if __grains__.get('os_family','unkown')=='RedHat': return True else: return False def cmd(): return __salt__['network.ip_addrs']()
对于函数有多个参数的时候,可以使用字符串的初始化。来拼凑出__salt__中的需要的参数如下:多个参数在调用模块的时候进行传入 如下例子:
[root@localhost _modules]# cat test1.py def __virtual__(): if __grains__.get('os_family','unkown')=='RedHat': return True else: return False def cmd(x,y): arg='%s %s'%(x,y) return __salt__['cmd.run'](arg) [root@localhost _modules]# salt '*' test1.cmd id root salt_minion: uid=0(root) gid=0(root) groups=0(root)
案例:
因为minon端。环境的不一样,或者一些网络限制。导致一些python安装包无法安装,这时候,minion端想练redis或者zk的情况下,我该如何写模块呢?
需求分析:
1、pip安装不了第三方模块。
2、只能使用python内置模块。
解决方案:
1、用socket 写客户端和服务器端进行连接。
弊端:性能无法保证。
2、既然saltstackmaster和 minion可以进行通信。而本身redis模块或者zk模块内的依赖较少,我们可以打一个python包,在当前master端的默认model路径进行导入,这样既保证性能也能保证需求。
[root@localhost _modules]# tree redis/ redis/ ├── cheng.py ├── client.py ├── client.pyc ├── _compat.py ├── _compat.pyc ├── connection.py ├── connection.pyc ├── evil.py ├── exceptions.py ├── exceptions.pyc ├── foo.py ├── __init__.py ├── __init__.pyc ├── lock.py ├── lock.pyc ├── sentinel.py ├── sentinel.pyc ├── test1.py ├── utils.py └── utils.pyc 0 directories, 20 files
1 [root@localhost _modules]# pwd 2 /srv/salt/_modules
外部调用的模块脚本:
[root@localhost _modules]# cat Operation_redis.py #!/usr/bin/env python #-*-coding:utf-8-*- # author:evil_liu import redis return_msg={'success':None,'fail':None} def con_re(host,port,command,key=None): #check_arg(args) r=redis.Redis(host=host,port=port) if hasattr(r,command): func=getattr(r,command) ret=func(key) return_msg['success']=ret return return_msg else: help_msg_info=''' use module example: salt '*' modulename.func host port command arg ''' return_msg['fail']='your command error!' return_msg.setdefault('help_msg',help_msg_info) return return_msg
使用方法:
1 [root@localhost _modules]# salt '*' Operation_redis.con_re 127.0.0.1 6379 ddd 2 salt_minion: 3 ---------- 4 fail: 5 your command error! 6 help_msg: 7 8 use module example: 9 salt '*' modulename.func host port command arg 10 11 success: 12 None
自定义redis模块支持 hash操作、普通操作:
1 #!/usr/bin/env python 2 #-*-coding:utf-8-*- 3 # author:liumeide 4 import redis 5 import sys 6 7 return_msg={'success':True,'message':None} 8 9 def __virual__(): 10 return 'jd_op_redis' 11 12 13 def chec_env(): 14 ''' 15 检测当前目录是否在sys.path 16 :return:无。 17 ''' 18 if '' in sys.path: 19 pass 20 else: 21 py_pa=sys.path.reverse() 22 py_pa.append('') 23 sys.path=py_pa.reverse() 24 25 def con_re(host,port,command_set): 26 r = redis.Redis(host=host, port=port) 27 if isinstance(command_set,str): 28 command_set=command_set.strip().split() 29 if command_set[-1]=='True':#是hash查询。 30 ret=chec_excu_moth(command_set,r) 31 return ret 32 elif command_set[-1]=='False':#是正常查询 33 ret = command_excu(command_set,r) 34 return ret 35 else: 36 return error_info() 37 else: 38 com_res=command_excu(r,command_set) 39 return com_res 40 41 42 def chec_excu_moth(x,r): 43 ''' 44 功能:该函数主要是hash功能函数,查询用户传入的方法是否有效,如果有效执行,否则返回错误信息。 45 :param x: 传入命令集合 46 :param r: 当前redis连接 47 :return: 返回错误结果或者执行结果。 48 ''' 49 if len(x)==5: 50 if hasattr(r,x[0]): 51 func=getattr(r,x[0]) 52 ret=func(x[1],x[2],x[3]) 53 return_msg['success'] = True 54 return_msg['message'] = ret 55 return return_msg 56 if len(x)==4: 57 if hasattr(r,x[0]): 58 func=getattr(r,x[0]) 59 ret=func(x[1],x[2]) 60 return_msg['success'] = True 61 return_msg['message'] = ret 62 return return_msg 63 else: 64 return error_info() 65 66 67 def command_excu(command_set,r): 68 ''' 69 功能:该函数主要是执行非hash操作。 70 :param command_set: 传入的命令集合。 71 :param r: redis连接。 72 :return: 执行结果。 73 ''' 74 if len(command_set)==4: 75 if hasattr(r, command_set[0]): 76 func = getattr(r, command_set[0]) 77 ret=func(command_set[1],command_set[2]) 78 return_msg['success'] = True 79 return_msg['message'] = ret 80 return return_msg 81 else: 82 return return_msg 83 elif len(command_set)==3: 84 if hasattr(r, command_set[0]): 85 func = getattr(r, command_set[0]) 86 ret = func(command_set[1]) 87 return_msg['success'] = True 88 return_msg['message'] = ret 89 return return_msg 90 else: 91 return return_msg 92 else: 93 return_msg['message'] = 'your command error!' 94 return_msg['success'] = False 95 return return_msg 96 def error_info(): 97 ''' 98 功能:该函数主要是错误信息返回。 99 :return: 返回错误信息。 100 ''' 101 return_msg['message'] = 'your command error!' 102 return_msg['success'] = False 103 return return_msg
saltstack的插件(四)log
一:日志输出:
可以通过loging模块来输出saltstack的日志输出。该日志是写在minion端的日志中。如下是简单的例子:
1 import logging
2 log = logging.getLogger(__name__)
3 log.info('Here is Some Information')
4 log.warning('You Should Not Do That')
5 log.error('It Is Busted')

浙公网安备 33010602011771号