python saltstack_saltstack python API(二)

总的构想:

通过saltstack的LocalClient的run_job异步执行任务方法,返回任务jid,并存于数据库中,前端通过ajax异步请求数据库,查看后台任务是否执行完成。

一:salts  opts  dictionary

有些客户端需要访问salts  opts  dictionary(一个字典包含master和minion的配置文件)

通常字典的信息匹配通过环境变量如果做了设置的话,如果没有做设置,会读取默认配置文件进行读取。

语法结构:

1 salt.config.client_config(path,env_var='SALT_CLIENT_CONFIG';default=None)

1 # cat salt_pots.py2 import salt.config3 master_ops=salt.config.client_config('/etc/salt/master')4 print(master_ops)

内容:

如上是获取saltmaster的配置信息,同样可以获取minion的配置信息。需要运行在minon端。唯一改变只是配置文件。

1 [root@localhost python]# cat python.py2 import salt.config3 master_ops=salt.config.client_config('/etc/salt/minion')4 print(master_ops)

以上获取master或者minion端的配置信息。

二:Salt's Client Interfaces    salt客户端api。通过调用salt API 直接让minion端执行命令。

首先我们看下类:LocalClient源码:下面是主要方法,详细的介绍请参考官网:https://docs.saltstack.com/en/latest/ref/clients/index.html

1 class LocalClient(object):2 '''3 The interfaceused by the :command:`salt` CLI tool on the Salt Master4

5 ``LocalClient`` isused to send a command to Salt minions to execute6 :ref:`execution modules ` and returnthe results to the7 Salt Master.8

9 Importing and using ``LocalClient`` must be done on the same machine asthe10 Salt Master and it must be done using the same user that the Salt Master is

11 running as. (Unless :conf_master:`external_auth` isconfigured and12 authentication credentials are included inthe execution).13   该类主要是saltmaster端向minion端发送命令,接口。

14 .. code-block:: python15   例子:

16 import salt.client17

18 local =salt.client.LocalClient()19 local.cmd('*', 'test.fib', [10])20 '''21 def __init__(self,22 c_path=os.path.join(syspaths.CONFIG_DIR, 'master'),23 mopts=None, skip_perm_errors=False):24 ifmopts:25 self.opts =mopts26 else:27 ifos.path.isdir(c_path):28 log.warning(29 '{0} expects a file path not a directory path({1}) to'

30 'it\'s \'c_path\' keyword argument'.format(31 self.__class__.__name__, c_path32 )33 )34 self.opts =salt.config.client_config(c_path)35 self.serial =salt.payload.Serial(self.opts)36 self.salt_user =salt.utils.get_specific_user()37 self.skip_perm_errors =skip_perm_errors38 self.key =self.__read_master_key()39 self.event = salt.utils.event.get_event(40 'master',41 self.opts['sock_dir'],42 self.opts['transport'],43 opts=self.opts,44 listen=not self.opts.get('__worker', False))45 self.functions =salt.loader.minion_mods(self.opts)46 self.returners =salt.loader.returners(self.opts, self.functions)47

48 def run_job(49 self,50 tgt,51 fun,52 arg=(),53 expr_form='glob',54 ret='',55 timeout=None,56 jid='',57 kwarg=None,58 **kwargs):59 '''60 Asynchronously send a command to connected minions61      异步向客户端发送命令,并返回我们想要的信息比如jid。

62 Prep the job directory and publish a command to any targeted minions.63

64 :return: A dictionary of (validated) ``pub_data`` or an empty65 dictionary on failure. The ``pub_data`` contains the job ID and a66 list of all minions that are expected to returndata.67

68 .. code-block:: python69       返回数据的格式。

70 >>> local.run_job('*', 'test.sleep', [300])71 {'jid': '20131219215650131543', 'minions': ['jerry']}72 '''73 arg =salt.utils.args.condition_input(arg, kwarg)74

75 try:76 pub_data =self.pub(77 tgt,78 fun,79 arg,80 expr_form,81 ret,82 jid=jid,83 timeout=self._get_timeout(timeout),84 **kwargs)85 except SaltClientError:86 # Re-raise error with specific message87 raise SaltClientError(88 'The salt master could not be contacted. Is master running?'

89 )90 except Exception asgeneral_exception:91 # Convert to generic client error and pass along mesasge92 raise SaltClientError(general_exception)93

94 return self._check_pub_data(pub_data)

salt源码做的真心不错,他在介绍类和方法的同事给咱们提供相应的例子,如上,我们可以调用相应的方法在salt-minion端进行执行。主要接口的执行是在master端(如果你提供了相应的master数据,可以不在master端执行,如上的一内容的master-ops的字典形式内容),因为我们在创建对象的时候,进行如下配置的读取:

1 def __init__(self,2 c_path=os.path.join(syspaths.CONFIG_DIR, 'master'),3 mopts=None, skip_perm_errors=False):4 ifmopts:5 self.opts =mopts6 else:7 ifos.path.isdir(c_path):8 log.warning(9 '{0} expects a file path not a directory path({1}) to'

10 'it\'s \'c_path\' keyword argument'.format(11 self.__class__.__name__, c_path12 )13 )14 self.opts =salt.config.client_config(c_path)15 self.serial =salt.payload.Serial(self.opts)16 self.salt_user =salt.utils.get_specific_user()17 self.skip_perm_errors =skip_perm_errors18 self.key =self.__read_master_key()19 self.event = salt.utils.event.get_event(20 'master',21 self.opts['sock_dir'],22 self.opts['transport'],23 opts=self.opts,24 listen=not self.opts.get('__worker', False))25 self.functions =salt.loader.minion_mods(self.opts)26 self.returners = salt.loader.returners(self.opts, self.functions)

我们实现一个简单的模块命令执行:

1 >>>import salt.client2 >>> cli=salt.clinet.LocalClient()3 >>> ret=cli.cmd('*','test.ping')4 >>>print ret5 {'salt_minion': True}

返回命令的执行结果。注意:cmd执行不异步执行,他会等所有的minion端执行完之后,才把所有的结果返回回来。这个也可以设置超时时间。这个超时间不是执行任务超时时间,官方解释如下:

:param timeout: Seconds to wait after the last minion returns but  before all minions return. 等待最后一个minion端返回结果的超时时间在所有数据返回之前。

也可以直接给模块传入参数,

1 >>> cli.cmd('*','cmd.run',['whoami'])2 {'salt_minion': 'root'}

我们也可以执行多个模块命令,传入多个参数,其中需要注意的是:如果有的模块不需要参数,但是需要传入空的列表,否则报错。

1 >>> cli.cmd('*',['cmd.run','test.ping'],[['whoami'],[]])2 {'salt_minion': {'test.ping': True, 'cmd.run': 'root'}}

需要注意的是:参数是一个列表套列表。而模块是一个列表中,以字符形式传入函数种。

该类还提供一个cmd_async,命令以异步的方式进行执行。如下:

1 def cmd_async(2 self,3 tgt,4 fun,5 arg=(),6 expr_form='glob',7 ret='',8 jid='',9 kwarg=None,10 **kwargs):11 '''12 Asynchronously send a command to connected minions13

14 The function signature is the same as:py:meth:`cmd` with the15 following exceptions.16

17 :returns: A job ID or 0on failure.18

19 .. code-block:: python20

21 >>> local.cmd_async('*', 'test.sleep', [300])22 '20131219215921857715'

23 '''24 arg =salt.utils.args.condition_input(arg, kwarg)25 pub_data =self.run_job(tgt,26 fun,27 arg,28 expr_form,29 ret,30 jid=jid,31 **kwargs)32 try:33 return pub_data['jid']34 except KeyError:35 return 0

但是如果在函数返回的时候,如果pub_data中即返回的数据中不包含key值为'jid'的将不会返回jid值。直接返回0.jid这个值比较重要,一会我们会说为什么要这个值。

1 >>> cli.cmd_async('*',['cmd.run','test.ping'],[['whoami'],[]])2 '20161211061247439244'

然后我们根据master的配置文件中,找到:cachedir: /var/cache/salt/master从该配置文件读取我们这个任务的执行情况:

可以查找对应的任务返回情况。/var/cache/salt/master是minion返回任务执行结果的目录,一般缓存24小时:

1 # Set the number of hours to keep old job information inthe job cache:2 #keep_jobs: 24

这个是默认值,我们可以进行修改。

然后我接下来研究LocalClient()的run_job的方法:

1 def run_job(2 self,3 tgt,4 fun,5 arg=(),6 expr_form='glob',7 ret='',8 timeout=None,9 jid='',10 kwarg=None,11 **kwargs):12 '''13 Asynchronously send a command to connected minions14

15 Prep the job directory and publish a command to any targeted minions.16

17 :return: A dictionary of (validated) ``pub_data`` or an empty18 dictionary on failure. The ``pub_data`` contains the job ID and a19 list of all minions that are expected to returndata.20        给master端返回一个字典,里面包含一个jid和其他一些信息。

21 .. code-block:: python22

23 >>> local.run_job('*', 'test.sleep', [300])24 {'jid': '20131219215650131543', 'minions': ['jerry']}25 '''26 arg =salt.utils.args.condition_input(arg, kwarg)27

28 try:29 pub_data =self.pub(30 tgt,31 fun,32 arg,33 expr_form,34 ret,35 jid=jid,36 timeout=self._get_timeout(timeout),37 **kwargs)38 except SaltClientError:39 # Re-raise error with specific message40 raise SaltClientError(41 'The salt master could not be contacted. Is master running?'

42 )43 except Exception asgeneral_exception:44 # Convert to generic client error and pass along mesasge45 raise SaltClientError(general_exception)46

47 return self._check_pub_data(pub_data)

我看下如果我现在一个minion端挂掉,看看返回的结果是什么?

如果执行结果没有返回的时候,返回如下结果:

1 >>>import salt.client2 >>> cli=salt.client.LocalClient()3 >>> ret=cli.run_job('*','test.ping')4 >>>print ret5 {'jid': '20161211062720119556', 'minions': ['salt_minion']}

同样我可以去master端缓存的目录查看下:

查看相应的目录的,并没有执行结果返回:

我们把minion端启动起来:

1 >>>import salt.client2 >>> cli=salt.client.LocalClient()3 >>>

4 >>> ret=cli.run_job('*','test.ping')5 >>>print ret6 {'jid': '20161211063245061096', 'minions': ['salt_minion']}

有结果的返回的:

重点:

为什么我们一直强调这个jid,在saltstack中这个jid做为一个任务的唯一标识,所以当我们给大量的minion端推送数据的时候,需要关注以下问题:

1、任务执行需要异步非阻塞执行。

2、如果异步之后,我们怎么去master设置的job缓存中去找我们想要的任务内容呢?

3、所以这个时候jid显得格外重要,所以我们上面篇幅讨论那么多,尤其原因就是在找异步、jid的方法。

既然方法找到了,那下一步是将我们minion端返回的执行结果捕获,在saltstack默认情况下,是将job任务缓存到我们的本地:/var/cache/salt/master中jobs。

但是这个方案我们不想使用,那么接下来就是将执行结果返回给到数据库。

但是返回数据方式有如下2种形式:

(一):Master Job Cache - Master-Side Returner

如上图(一):表示master发送的命令给minion端,然后minion端将结果返回给db、redis、等。

这种方式,只需要在master端进行简单配置即可,minion端不需要进行什么配置。

(二):External Job Cache - Minion-Side Returner

如图(2),是master端,将命令发送给minion端,然后由minion端将数据分别写入redis、mysql等。

这种方式,需要在minion端安装相应的模块(python-mysqldb),还需要配置相应的db数据库信息(账号、密码等),配置较为麻烦,最主要是不安全。

综上所述:我们采用一的模式:Master Job Cache - Master-Side Returner

master配置文件需要添加如下:

1 mysql.host: 'salt'

2 mysql.user: 'salt'

3 mysql.pass: 'salt'

4 mysql.db: 'salt'

5 mysql.port: 3306

需要注意的是:salt需要能被解析在master端

修改master端job缓存:修改配置文件:/etc/salt/master

1 master_job_cache: mysql

如果在传输过程不需要证书认证的话需要往:/etc/salt/master 加入如下配置:

1 mysql.ssl_ca: None2 mysql.ssl_cert: None3 mysql.ssl_key: None

修改完如上配置重启salt-master:

1 /etc/init.d/salt-master restart

创建数据库:

1 yum install -y mysql-server.x86_64

创建相应的数据库:

1 CREATE DATABASE `salt`2 DEFAULT CHARACTER SET utf83 DEFAULT COLLATE utf8_general_ci;4

5 USE `salt`;

创建表结构:

1 --

2 -- Table structure fortable `jids`3 --

4

5 DROP TABLE IF EXISTS `jids`;6 CREATE TABLE `jids` (7 `jid` varchar(255) NOT NULL,8 `load` mediumtext NOT NULL,9 UNIQUE KEY `jid` (`jid`)10 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;11 CREATE INDEX jid ON jids(jid) USING BTREE;12

13 --

14 -- Table structure fortable `salt_returns`15 --

16

17 DROP TABLE IF EXISTS `salt_returns`;18 CREATE TABLE `salt_returns` (19 `fun` varchar(50) NOT NULL,20 `jid` varchar(255) NOT NULL,21 `return` mediumtext NOT NULL,22 `id` varchar(255) NOT NULL,23 `success` varchar(10) NOT NULL,24 `full_ret` mediumtext NOT NULL,25 `alter_time` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,26 KEY `id` (`id`),27 KEY `jid` (`jid`),28 KEY `fun` (`fun`)29 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;30

31 --

32 -- Table structure fortable `salt_events`33 --

34

35 DROP TABLE IF EXISTS `salt_events`;36 CREATE TABLE `salt_events` (37 `id` BIGINT NOT NULL AUTO_INCREMENT,38 `tag` varchar(255) NOT NULL,39 `data` mediumtext NOT NULL,40 `alter_time` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,41 `master_id` varchar(255) NOT NULL,42 PRIMARY KEY (`id`),43 KEY `tag` (`tag`)44 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

给salt用户授权访问:

1 grant all on salt.* to salt@'%' identified by 'salt';

注意:%不包括localhost。

由于master和mysql数据在同一台服务器:所以需要授权给localhost。

1 grant all on salt.* to salt@'localhost' identified by 'salt';

另外master端需要安装连接mysql的API。注意是:MySQL-python.x86_64 。注意名字!!在python2版本中。

1 yum install -y MySQL-python.x86_64

然后我们做个测试:

1 >>>import salt.client2 >>> cli=salt.client.LocalClient()3 >>> ret=cli.run_job('*','test.ping')4 >>> ret=cli.run_job('*','cmd.run',['w'])5 >>>print ret6 {'jid': '20161211175654153286', 'minions': ['salt_minion']}

然后我查看数据库:

1 mysql> select full_ret from salt_returns where jid='20161211175654153286';2 +-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

3 | full_ret |

4 +-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

5 | {"fun_args": ["w"], "jid": "20161211175654153286", "return": "17:56:54 up 14:24, 2 users, load average: 0.20, 0.13, 0.11\nUSER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT\nroot tty1 - Thu01 2:06m 0.03s 0.03s -bash\nroot pts/0 192.168.217.1 15:50 2:05m 0.01s 0.01s -bash", "retcode": 0, "success": true, "cmd": "_return", "_stamp": "2016-12-12T01:56:54.256049", "fun": "cmd.run", "id": "salt_minion"} |

6 +-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

7 1 row in set (0.00 sec)

cheers!!有结果了!搞定!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值