從零開始搭建Salt Web之封裝salt-api接口

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

相關文章
相關標籤/搜索