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,依次循环。
来源: http://www.cnblogs.com/agnewee/p/6492887.html