salt-api 使用(福利版)

写在前面的话:

salt-api是一个基于Cherrypy(python的一个web框架)的Rest API程序。

注意:CherryPy版本3.2.5到3.7.x有一个已知的SSL追溯。请使用3.2.3版本或最新的10.x版本。

一、salt认证

依赖:

salt-api依赖的模块是Cherrypy,用于支持websockets的ws4py python模块(可选)

安装及配置:

salt-api 运行在Salt Master程序的机器上。

1. 安装salt-api,需要确保salt-api 与salt版本一致。

2. 安装Cherrypy,ws4py(可选)。

3. 生成自签名证书(可选)。建议使用安全的HTTPS连接,因为salt eauth 身份验证凭证将通过线路发送。

①.安装 pyOpenSSL 包。

②.使用create_self_signed_cert() 执行功能生成自签名证书。

salt-call --local tls.create_self_signed_cert

4. 编辑配置文件添加至少一个外部认证用户或组。详情这里

5. salt-master配置文件添加如下配置来启用rest_cherrypy模块。

rest_cherrypy:
  port: 8000
  ssl_crt: /etc/pki/tls/certs/localhost.crt
  ssl_key: /etc/pki/tls/certs/localhost.key

6. 重启salt-master 进程。

7. 重启salt-api 进程。

二、使用

开始使用之路吧。

首先是服务端认证,通过每个请求传递会话令牌来执行身份验证,token通过Login URL生成。

token认证采用两种方法发送:一种是hearder头添加认证token,另一种作为会话cookie。

用法:

请求主体必须是一组命令。使用此工作流程来构建命令:

1. 选择一个客户端界面。

2. 选择一个功能。

3.填写所选客户端所需的其余参数。

client字段是对Salt的python api中使用的主要python类的引用。

local:向本地发送命令的“本地”使用。等同于salt 命令。

runner:调用master的runner 模块。等同于salt-run命令。

wheel:调用master的wheel模块。wheel没有知己额的CLI命令,它通常广利Master-side资源,例如状态文件,支柱文件,salt配置文件,以及salt-key类似的功能。

 

在执行LocalClient,它需要将命令转发给Minions,所以需要tgt参数来指定minionid.

也需要arg(数组)和kwarg(之前)参数,这些值被发送到minions并用作请求函数的参数。

RunnerClient和WheelClient直接在Master上执行,因此不需要接受这些参数。

header头设置

REST接口在接受什么样的数据格式以及它将返回什么格式(例如,JSON,YAML,urlencoded)方面是灵活的

通过包含Content-type头来指定请求正文中的数据格式。

使用Accept头指定相应主体所需的数据格式。

关于CherryPy的并发

CherryPy服务器是一个生成就绪的线程HTTP服务器,用Python编写。它使用线程池来处理HTTP请求,所以不适合维护大量的并发同步连接,在配置默认设置的中等硬件上,他最高大约30到50个并发连接。

注意:每个salt的命令运行都会启动一个实例化的进程(LocalClient),它将自己的监听器实例化为salt事件总线,并发出自己的周期性salturil.find_job查询来确定Minion是否仍在运行该命令,不完全是一个轻量级操作。

超时

CherryPy还可以设置HTTP超时时间。LocalClient和RunnerClient都可以在顶级关键字(timeout)中设置自己的超时参数。

异步操作

由于性能开销和HTTP超时,长时间运行上述操作,可以使用local_asyn,runner_asyn,wheel_asyn进行异步方式运行更能节省开销。执行结果可以通过 /jobs/<jid> URL 从缓存中获取,也可以使用salt的Rerutner 系统收集到数据存储中。

/events URL专门用户处理长时间运行的HTTP请求,并包含了作业返回的salt事件总线,但该操作具有不同步性。

性能调整

设置thread_pool和socket_queue_size 可以用来增加处理传入请求的rest_cherrypy的能力。设置这些配置时需要留意RAM的使用情况以及可用文件句柄。由于salt-api是基于salt使用,同时还需要考虑salt的性能。

下面福利时间:

下面的代码大概整合了一些经常使用的api,送给大家。

 

未完待续。。。

  1 #!/usr/bin/env python
  2 # -*- coding:utf-8 -*-
  3 __author__ = '40kuai'
  4 __version__ = 'v0.0.1'
  5 """
  6 1. 整合 salt-api 功能
  7 2. 获取token多次使用,发现token过期后重新获取token从当前失败任务重新继续执行
  8 3. 可选:出现接口或服务异常(501),本次操作尝试几次重新执行
  9 arg 为模块需要传入的参数,kwargs为pillar或grains参数。
 10 
 11 分为以下几个类:
 12     1. salt-api 方法类
 13     2. 发送请求的类
 14 """
 15 
 16 from urlparse import urljoin
 17 import requests
 18 
 19 
 20 class Salt_Api():
 21     def __init__(self, url, username, password):
 22         self.url = url
 23         self._username = username
 24         self._password = password
 25         self.get_token()
 26 
 27     def get_token(self, eauth='pam', ):
 28         """获取salt-api使用的token"""
 29         get_token_url = urljoin(self.url, 'login')
 30         json_data = {'username': self._username, 'password': self._password, 'eauth': eauth}
 31         token_obj = requests.post(get_token_url, json=json_data, verify=False)
 32         if token_obj.status_code != 200:
 33             raise Exception(token_obj.status_code)
 34         self.token = token_obj.json()['return'][0]['token']
 35 
 36     def post(self, prefix='/', json_data=None, headers=None):
 37         post_url = urljoin(self.url, prefix)
 38         if headers is None:
 39             headers = {'X-Auth-Token': self.token, 'Accept': 'application/json'}
 40         else:
 41             headers = {'X-Auth-Token': self.token, }.update(headers)
 42         post_requests = requests.post(post_url, json=json_data, headers=headers, verify=False)
 43         return post_requests.json()
 44 
 45     def get(self, prefix='/', json_data=None, headers=None):
 46         post_url = urljoin(self.url, prefix)
 47         if headers is None:
 48             headers = {'X-Auth-Token': self.token, 'Accept': 'application/json'}
 49         else:
 50             headers = {'X-Auth-Token': self.token, }.update(headers)
 51         get_requests = requests.get(post_url, json=json_data, headers=headers, verify=False)
 52         return get_requests.json()
 53 
 54     def get_all_key(self):
 55         """获取所有minion的key"""
 56         json_data = {'client': 'wheel', 'fun': 'key.list_all'}
 57         content = self.post(json_data=json_data)
 58         minions = content['return'][0]['data']['return']['minions']
 59         minions_pre = content['return'][0]['data']['return']['minions_pre']
 60         return minions, minions_pre
 61 
 62     def accept_key(self, minion_id):
 63         """认证minion_id,返回Ture or False"""
 64         json_data = {'client': 'wheel', 'fun': 'key.accept', 'match': minion_id}
 65         content = self.post(json_data=json_data)
 66         return content['return'][0]['data']['success']
 67 
 68     def delete_key(self, node_name):
 69         """删除minion_id,返回Ture or False"""
 70         json_data = {'client': 'wheel', 'fun': 'key.delete', 'match': node_name}
 71         content = self.post(json_data=json_data)
 72         return content['return'][0]['data']['success']
 73 
 74     def host_remote_module(self, tgt, fun, arg=None):
 75         """根据主机执行函数或模块,模块的参数为arg"""
 76         json_data = {'client': 'local', 'tgt': tgt, 'fun': fun, }
 77         if arg:
 78             json_data.update({'arg': arg})
 79         content = self.post(json_data=json_data)
 80         return content['return']
 81 
 82     def group_remote_module(self, tgt, fun, arg=None):
 83         """根据分组执行函数或模块,模块的参数为arg"""
 84         json_data = {'client': 'local', 'tgt': tgt, 'fun': fun, 'expr_form': 'nodegroup'}
 85         if arg:
 86             json_data.update({'arg': arg})
 87         content = self.post(json_data=json_data)
 88         return content['return']
 89 
 90     def host_sls_async(self, tgt, arg):
 91         '''主机异步sls '''
 92         json_data = {'client': 'local_async', 'tgt': tgt, 'fun': 'state.sls', 'arg': arg}
 93         content = self.post(json_data=json_data)
 94         return content['return']
 95 
 96     def group_sls_async(self, tgt, arg):
 97         '''分组异步sls '''
 98         json_data = {'client': 'local_async', 'tgt': tgt, 'fun': 'state.sls', 'arg': arg, 'expr_form': 'nodegroup'}
 99         content = self.post(json_data=json_data)
100         return content['return']
101 
102     def server_hosts_pillar(self, tgt, arg, **kwargs):
103         '''针对主机执行sls and pillar '''
104         print kwargs
105         kwargs = {'pillar': kwargs['kwargs']}
106         json_data = {"client": "local", "tgt": tgt, "fun": "state.sls", "arg": arg, "kwarg": kwargs}
107         content = self.post(json_data=json_data)
108         return content['return']
109 
110     def server_group_pillar(self, tgt, arg, **kwargs):
111         '''分组进行sls and pillar'''
112         kwargs = {'pillar': kwargs['kwargs']}
113         json_data = {'client': 'local', 'tgt': tgt, 'fun': 'state.sls', 'arg': arg, 'expr_form': 'nodegroup',
114                      'kwarg': kwargs}
115         content = self.post(json_data=json_data)
116         return content['return']
117 
118     def jobs_all_list(self):
119         '''打印所有jid缓存'''
120         json_data = {"client": "runner", "fun": "jobs.list_jobs"}
121         content = self.post(json_data=json_data)
122         return content['return']
123 
124     def jobs_jid_status(self, jid):
125         '''查看jid运行状态'''
126         json_data = {"client": "runner", "fun": "jobs.lookup_jid", "jid": jid}
127         content = self.post(json_data=json_data)
128         return content['return']
129 
130     def keys_minion(self, hostname):
131         """Show the list of minion keys or detail on a specific key"""
132         content = self.get('keys/%s' % hostname)
133         return content
134 
135 
136 if __name__ == '__main__':
137     url = 'https://local:8000/'
138     obj = Salt_Api(url, 'username', 'password')
139     print obj.keys_minion('minionid')
salt-api

 


版权声明:本文为u012881331原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。