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


salt-api現在已經正常運行,接下來則是實現通過調用salt-api來執行salt命令。

調用salt-api執行命令時,記得攜帶c_path參數

因為salt中自帶了tornado這個庫,所以決定基於tornado.httpclient來封裝HTTP請求。

交互模式:

>>> 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"}]}'

以上就是大致流程,接下來對操作進行簡單的封裝。

# 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,依次循環。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM