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