saltstack-REST_CHERRYPYI接口
https://docs.saltstack.com/en/latest/ref/netapi/all/salt.netapi.rest_cherrypy.html#rest-cherrypy
安装:
以下步骤都是在 Salt Master daemon上执行。
yum install pyOpenSSL -y yum install salt-api -y salt-call tls.create_self_signed_cert #安装SSL,API,生成cert证书
[root@webmaster master.d]# cat /etc/salt/master.d/api.conf rest_cherrypy: port: 8080 ssl_crt: /etc/pki/tls/certs/localhost.crt ssl_key: /etc/pki/tls/certs/localhost.key external_auth: pam: saltapi: - .* - '@wheel' - '@runner' #配置api接口
useradd -M -s /sbin/nologin saltapi echo 'saltapi_password'|passwd saltapi --stdin systemctl start salt-api #创建账户,启动api
systemctl restart salt-master #重启salt
认证:
认证就是每个请求传递一个session token。token由login URl产生。
使用自定义请求头传递token,名为:X-Auth-Token
[root@webmaster master.d]# curl -k https://192.168.10.10:8080/login -H "Accept: application/x-yaml" -d username='saltapi' -d password='saltapi_password' -d eauth='pam' return: - eauth: pam expire: 1544643349.771802 perms: - .* - '@wheel' - '@runner' start: 1544600149.771802 token: 431584acdd199e5d1013f853a6066a896b177ed7 user: saltapi #连接测试 #生成token
调用API
逻辑是,先使用用户名和密码拿到一个token,然后拿这个token去调用api
curl -k https://192.168.10.10:8080 -H "Accept: application/x-yaml" -H "X-Auth-Token: f6e4e2313a9ab06153fc5c4e065cb9e9e94a86b9" -d client='local' -d tgt='192.168.10.10' -d fun='cmd.run' -d arg='netstat -lntp| wc -l'
saltapi.py
#python3x import urllib,json import urllib.request import urllib.parse import ssl ssl._create_default_https_context = ssl._create_unverified_context class SaltAPI(object): __token_id = '' def __init__(self,url,username,password): self.__url = url.rstrip('/') self.__user = username self.__password = password def token_id(self): """ 用户登陆和获取token :return: """ params = {'eauth': 'pam', 'username': self.__user, 'password': self.__password} encode = urllib.parse.urlencode(params) obj = urllib.parse.unquote(encode).encode('utf-8') content = self.postRequest(obj, prefix='/login') try: self.__token_id = content['return'][0]['token'] except KeyError: raise KeyError def postRequest(self,obj,prefix='/'): url = self.__url + prefix headers = {'X-Auth-Token': self.__token_id} req = urllib.request.Request(url, obj, headers) opener = urllib.request.urlopen(req) content = json.loads(opener.read().decode('utf-8')) return content def list_all_key(self): """ 获取包括认证、未认证salt主机 """ params = {'client': 'wheel', 'fun': 'key.list_all'} obj = urllib.parse.urlencode(params).encode('utf-8') self.token_id() content = self.postRequest(obj) minions = content['return'][0]['data']['return']['minions'] minions_pre = content['return'][0]['data']['return']['minions_pre'] return minions, minions_pre def delete_key(self, node_name): ''' 拒绝salt主机 ''' params = {'client': 'wheel', 'fun': 'key.delete', 'match': node_name} obj = urllib.parse.urlencode(params).encode('utf-8') self.token_id() content = self.postRequest(obj) ret = content['return'][0]['data']['success'] return ret def accept_key(self,node_name): ''' 接受salt主机 ''' params = {'client': 'wheel', 'fun': 'key.accept', 'match': node_name} obj = urllib.parse.urlencode(params).encode('utf-8') self.token_id() content = self.postRequest(obj) ret = content['return'][0]['data']['success'] return ret def salt_get_jid_ret(self,jid): """ 通过jid获取执行结果 :param jid: jobid :return: 结果 """ params = {'client':'runner', 'fun':'jobs.lookup_jid', 'jid': jid} obj = urllib.parse.urlencode(params).encode('utf-8') self.token_id() content = self.postRequest(obj) ret = content['return'][0] return ret def salt_running_jobs(self): """ 获取运行中的任务 :return: 任务结果 """ params = {'client':'runner', 'fun': 'jobs.active'} obj = urllib.parse.urlencode(params).encode('utf-8') self.token_id() content = self.postRequest(obj) ret = content['return'][0] return ret def remote_noarg_execution_sigle(self, tgt, fun): """ 单台minin执行命令没有参数 :param tgt: 目标主机 :param fun: 执行模块 :return: 执行结果 """ params = {'client': 'local', 'tgt': tgt, 'fun': fun} obj = urllib.parse.urlencode(params).encode('utf-8') self.token_id() content = self.postRequest(obj) # print(content) # {'return': [{'salt-master': True}]} ret = content['return'][0] return ret def remote_execution_single(self, tgt, fun, arg): """ 单台minion远程执行,有参数 :param tgt: minion :param fun: 模块 :param arg: 参数 :return: 执行结果 """ params = {'client': 'local', 'tgt': tgt, 'fun': fun, 'arg': arg} obj = urllib.parse.urlencode(params).encode('utf-8') self.token_id() content = self.postRequest(obj) # print(content) # {'return': [{'salt-master': 'root'}]} ret = content['return'] return ret def remote_async_execution_module(self, tgt, fun, arg): """ 远程异步执行模块,有参数 :param tgt: minion list :param fun: 模块 :param arg: 参数 :return: jobid """ params = {'client': 'local_async', 'tgt': tgt, 'fun': fun, 'arg': arg, 'expr_form': 'list'} obj = urllib.parse.urlencode(params).encode('utf-8') self.token_id() content = self.postRequest(obj) # print(content) # {'return': [{'jid': '20180131173846594347', 'minions': ['salt-master', 'salt-minion']}]} jid = content['return'][0]['jid'] return jid def remote_execution(self, tgt, fun, arg): """ 远程执行模块,有参数 :param tgt: minion list :param fun: 模块 :param arg: 参数 :return: dict, {'minion1': 'ret', 'minion2': 'ret'} """ params = {'client': 'local', 'tgt': tgt, 'fun': fun, 'arg': arg, 'expr_form': 'list'} obj = urllib.parse.urlencode(params).encode('utf-8') self.token_id() content = self.postRequest(obj) # print(content) # {'return': [{'salt-master': 'root', 'salt-minion': 'root'}]} ret = content['return'][0] return ret def salt_state(self, tgt, arg, expr_form): ''' sls文件 ''' params = {'client': 'local', 'tgt': tgt, 'fun': 'state.sls', 'arg': arg, 'expr_form': expr_form} obj = urllib.parse.urlencode(params).encode('utf-8') self.token_id() content = self.postRequest(obj) ret = content['return'][0] return ret def salt_alive(self, tgt): ''' salt主机存活检测 ''' params = {'client': 'local', 'tgt': tgt, 'fun': 'test.ping'} obj = urllib.parse.urlencode(params).encode('utf-8') self.token_id() content = self.postRequest(obj) ret = content['return'][0] return ret def main(): sapi = SaltAPI(url='ip:port',username='username',password='password') # name = sapi.remote_execution('*','cmd.run','df') # # print(name) if __name__ == '__main__': main()