寫在前面的話:html
salt-api是一個基於Cherrypy(python的一個web框架)的Rest API程序。node
注意:CherryPy版本3.2.5到3.7.x有一個已知的SSL追溯。請使用3.2.3版本或最新的10.x版本。python
依賴:git
salt-api依賴的模塊是Cherrypy,用於支持websockets的ws4py python模塊(可選)github
安裝及配置:
web
salt-api 運行在Salt Master程序的機器上。json
1. 安裝salt-api,須要確保salt-api 與salt版本一致。api
2. 安裝Cherrypy,ws4py(可選)。數組
3. 生成自簽名證書(可選)。建議使用安全的HTTPS鏈接,由於salt eauth 身份驗證憑證將經過線路發送。緩存
①.安裝 pyOpenSSL 包。
②.使用create_self_signed_cert()
執行功能生成自簽名證書。
salt-call --local tls.create_self_signed_cert
4. 編輯配置文件添加至少一個外部認證用戶或組。詳情這裏。
5. salt-master配置文件添加以下配置來啓用rest_cherrypy模塊。
rest_cherrypy: port: 8000 ssl_crt: /etc/pki/tls/certs/localhost.crt ssl_key: /etc/pki/tls/certs/localhost.key
6. 重啓salt-master 進程。
7. 重啓salt-api 進程。
開始使用之路吧。
首先是服務端認證,經過每一個請求傳遞會話令牌來執行身份驗證,token經過Login URL生成。
token認證採用兩種方法發送:一種是hearder頭添加認證token,另外一種做爲會話cookie。
用法:
請求主體必須是一組命令。使用此工做流程來構建命令:
1. 選擇一個客戶端界面。
2. 選擇一個功能。
3.填寫所選客戶端所需的其他參數。
client字段是對Salt的python api中使用的主要python類的引用。
local:向本地發送命令的「本地」使用。等同於salt 命令。
runner:調用master的runner 模塊。等同於salt-run命令。
wheel:調用master的wheel模塊。wheel沒有知己額的CLI命令,它一般廣利Master-side資源,例如狀態文件,支柱文件,salt配置文件,以及salt-key相似的功能。
在執行LocalClient,它須要將命令轉發給Minions,因此須要tgt參數來指定minionid.
也須要arg(數組)和kwarg(以前)參數,這些值被髮送到minions並用做請求函數的參數。
RunnerClient和WheelClient直接在Master上執行,所以不須要接受這些參數。
header頭設置:
REST接口在接受什麼樣的數據格式以及它將返回什麼格式(例如,JSON,YAML,urlencoded)方面是靈活的
經過包含Content-type頭來指定請求正文中的數據格式。
使用Accept頭指定相應主體所需的數據格式。
關於CherryPy的併發:
CherryPy服務器是一個生成就緒的線程HTTP服務器,用Python編寫。它使用線程池來處理HTTP請求,因此不適合維護大量的併發同步鏈接,在配置默認設置的中等硬件上,他最高大約30到50個併發鏈接。
注意:每一個salt的命令運行都會啓動一個實例化的進程(LocalClient),它將本身的監聽器實例化爲salt事件總線,併發出本身的週期性salturil.find_job查詢來肯定Minion是否仍在運行該命令,不徹底是一個輕量級操做。
超時:
CherryPy還能夠設置HTTP超時時間。LocalClient和RunnerClient均可以在頂級關鍵字(timeout)中設置本身的超時參數。
異步操做:
因爲性能開銷和HTTP超時,長時間運行上述操做,可使用local_asyn,runner_asyn,wheel_asyn進行異步方式運行更能節省開銷。執行結果能夠經過 /jobs/<jid> URL 從緩存中獲取,也可使用salt的Rerutner 系統收集到數據存儲中。
/events URL專門用戶處理長時間運行的HTTP請求,幷包含了做業返回的salt事件總線,但該操做具備不一樣步性。
性能調整:
設置thread_pool和socket_queue_size 能夠用來增長處理傳入請求的rest_cherrypy的能力。設置這些配置時須要留意RAM的使用狀況以及可用文件句柄。因爲salt-api是基於salt使用,同時還須要考慮salt的性能。
下面福利時間:
下面的代碼大概整合了一些常用的api,送給你們。
未完待續。。。
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 __author__ = '40kuai' 4 __version__ = 'v0.0.1' 5 """ 6 1. 整合 salt-api 功能 7 2. 獲取token屢次使用,發現token過時後從新獲取token從當前失敗任務從新繼續執行 8 3. 可選:出現接口或服務異常(501),本次操做嘗試幾回從新執行 9 arg 爲模塊須要傳入的參數,kwargs爲pillar或grains參數。 10 11 分爲如下幾個類: 12 1. salt-api 方法類 13 2. 發送請求的類 14 """ 15 16 from urlparse import urljoin 17 import requests 18 19 20 class Salt_Api(): 21 def __init__(self, url, username, password): 22 self.url = url 23 self._username = username 24 self._password = password 25 self.get_token() 26 27 def get_token(self, eauth='pam', ): 28 """獲取salt-api使用的token""" 29 get_token_url = urljoin(self.url, 'login') 30 json_data = {'username': self._username, 'password': self._password, 'eauth': eauth} 31 token_obj = requests.post(get_token_url, json=json_data, verify=False) 32 if token_obj.status_code != 200: 33 raise Exception(token_obj.status_code) 34 self.token = token_obj.json()['return'][0]['token'] 35 36 def post(self, prefix='/', json_data=None, headers=None): 37 post_url = urljoin(self.url, prefix) 38 if headers is None: 39 headers = {'X-Auth-Token': self.token, 'Accept': 'application/json'} 40 else: 41 headers = {'X-Auth-Token': self.token, }.update(headers) 42 post_requests = requests.post(post_url, json=json_data, headers=headers, verify=False) 43 return post_requests.json() 44 45 def get(self, prefix='/', json_data=None, headers=None): 46 post_url = urljoin(self.url, prefix) 47 if headers is None: 48 headers = {'X-Auth-Token': self.token, 'Accept': 'application/json'} 49 else: 50 headers = {'X-Auth-Token': self.token, }.update(headers) 51 get_requests = requests.get(post_url, json=json_data, headers=headers, verify=False) 52 return get_requests.json() 53 54 def get_all_key(self): 55 """獲取全部minion的key""" 56 json_data = {'client': 'wheel', 'fun': 'key.list_all'} 57 content = self.post(json_data=json_data) 58 minions = content['return'][0]['data']['return']['minions'] 59 minions_pre = content['return'][0]['data']['return']['minions_pre'] 60 return minions, minions_pre 61 62 def accept_key(self, minion_id): 63 """認證minion_id,返回Ture or False""" 64 json_data = {'client': 'wheel', 'fun': 'key.accept', 'match': minion_id} 65 content = self.post(json_data=json_data) 66 return content['return'][0]['data']['success'] 67 68 def delete_key(self, node_name): 69 """刪除minion_id,返回Ture or False""" 70 json_data = {'client': 'wheel', 'fun': 'key.delete', 'match': node_name} 71 content = self.post(json_data=json_data) 72 return content['return'][0]['data']['success'] 73 74 def host_remote_module(self, tgt, fun, arg=None): 75 """根據主機執行函數或模塊,模塊的參數爲arg""" 76 json_data = {'client': 'local', 'tgt': tgt, 'fun': fun, } 77 if arg: 78 json_data.update({'arg': arg}) 79 content = self.post(json_data=json_data) 80 return content['return'] 81 82 def group_remote_module(self, tgt, fun, arg=None): 83 """根據分組執行函數或模塊,模塊的參數爲arg""" 84 json_data = {'client': 'local', 'tgt': tgt, 'fun': fun, 'expr_form': 'nodegroup'} 85 if arg: 86 json_data.update({'arg': arg}) 87 content = self.post(json_data=json_data) 88 return content['return'] 89 90 def host_sls_async(self, tgt, arg): 91 '''主機異步sls ''' 92 json_data = {'client': 'local_async', 'tgt': tgt, 'fun': 'state.sls', 'arg': arg} 93 content = self.post(json_data=json_data) 94 return content['return'] 95 96 def group_sls_async(self, tgt, arg): 97 '''分組異步sls ''' 98 json_data = {'client': 'local_async', 'tgt': tgt, 'fun': 'state.sls', 'arg': arg, 'expr_form': 'nodegroup'} 99 content = self.post(json_data=json_data) 100 return content['return'] 101 102 def server_hosts_pillar(self, tgt, arg, **kwargs): 103 '''針對主機執行sls and pillar ''' 104 print kwargs 105 kwargs = {'pillar': kwargs['kwargs']} 106 json_data = {"client": "local", "tgt": tgt, "fun": "state.sls", "arg": arg, "kwarg": kwargs} 107 content = self.post(json_data=json_data) 108 return content['return'] 109 110 def server_group_pillar(self, tgt, arg, **kwargs): 111 '''分組進行sls and pillar''' 112 kwargs = {'pillar': kwargs['kwargs']} 113 json_data = {'client': 'local', 'tgt': tgt, 'fun': 'state.sls', 'arg': arg, 'expr_form': 'nodegroup', 114 'kwarg': kwargs} 115 content = self.post(json_data=json_data) 116 return content['return'] 117 118 def jobs_all_list(self): 119 '''打印全部jid緩存''' 120 json_data = {"client": "runner", "fun": "jobs.list_jobs"} 121 content = self.post(json_data=json_data) 122 return content['return'] 123 124 def jobs_jid_status(self, jid): 125 '''查看jid運行狀態''' 126 json_data = {"client": "runner", "fun": "jobs.lookup_jid", "jid": jid} 127 content = self.post(json_data=json_data) 128 return content['return'] 129 130 def keys_minion(self, hostname): 131 """Show the list of minion keys or detail on a specific key""" 132 content = self.get('keys/%s' % hostname) 133 return content 134 135 136 if __name__ == '__main__': 137 url = 'https://local:8000/' 138 obj = Salt_Api(url, 'username', 'password') 139 print obj.keys_minion('minionid')