salt-api如今已经正常运行,接下来则是实现经过调用salt-api来执行salt命令。json
调用salt-api执行命令时,记得携带c_path参数api
由于salt中自带了tornado这个库,因此决定基于tornado.httpclient来封装HTTP请求。app
交互模式:dom
>>> import json >>> from tornado.httpclient import HTTPClient, HTTPRequest >>> client = HTTPClient() # 请求头中声明经过json提交内容 >>> headers = {'Content-Type': 'application/json'} >>> body1 = {'username': 'salttest', 'password': 'password', 'eauth': 'pam'} >>> url = 'https://localhost:8090/' # 这里指定需指定validate_vert=False, 不然HTTPClient没法访问https >>> request1 = HTTPRequest(url=url+'login', method='POST', headers=headers, body=json.dumps(body), validate_cert=False) >>> response1 = client.fetch(request1) >>> response1.body '{"return": [{"perms": [".*"], "start": 1488443323.968138, "token": "0daf377b4611db***8419f515d18744338", "expire": 1488486523.968139, "user": "uyun", "eauth": "pam"}]}' >>> headers['X-Auth-Token'] = '0daf377b4611db***8419f515d18744338' >>> body2 = {'client': 'local', 'tgt': '*', 'fun': 'test.ping', 'c_path': '/root/SaltWeb/conf'} >>> request2 = HTTPRequest(url=url, method='POST', headers=headers, body=json.dumps(body), validate_cert=False) >>> response2 = client.fetch(request2) >>> response2.body '{"return": [{"10.1.240.213": "localhost.localdomain"}]}'
以上就是大体流程,接下来对操做进行简单的封装。tornado
# coding: utf-8 import json from urlparse import urljoin from tornado.httpclient import HTTPClient, HTTPRequest, HTTPError class SaltClient(object): def __init__(self, url, username, password, c_path=None): self._url = url self._un = username self._pw = password self._cpath = c_path self._token = None @property def headers(self): headers = {'Content-Type': 'application/json', 'Accept': 'application/json'} if self._token: headers['X-Auth-Token'] = self._token return headers def get_token(self): url = urljoin(self._url, 'login') params = {'username': self._un, 'password': self._pw, 'eauth': 'pam'} response = self.post(url, params) return response['return'][0]['token'] def _request(self, url, method, body, validate_cert=False, **kwargs): return HTTPRequest(url=url, method=method, headers=self.headers, body=json.dumps(body), validate_cert=validate_cert, **kwargs) def post(self, url, params): client = HTTPClient() try: request = self._request(url, 'POST', params) response = client.fetch(request).body except HTTPError as e: if e.code == 401: self._token = self.get_token() response = self.post(url, params) else: raise if isinstance(response, str): response = json.loads(response) return response def cmd(self, client, tgt, fun, arg=None, **kwargs): params = {'client': client, 'tgt': tgt, 'fun': fun} if arg: params['arg'] = arg if self._cpath: params['c_path'] = self._cpath ret = self.post(self._url, params) return ret['return']
逻辑很简单,主要经过调用cmd()方法执行命令,由于token存在时效性,当token过时时,
调用命令会抛出401错误受权的异常,捕获到以后从新获取一次token,依次循环。post