SaltStack簡介
SaltStack做爲開源的自動化批量管理工具,功能很強大,在生產環境中也有不少的企業/公司使用,那麼若是每次執行都在SaltStack Master上去經過Salt命令執行sls文件或者Salt的其它命令就顯得很麻煩,那麼咱們可使用Salt提供的API,那麼它的API分爲local_client和REST API 兩種html
兩種api的區別node
再次聲明爲什麼使用RESTful API?
local_client必須依賴於python去調用,必須還得把該python腳本放到salt master本地執行,可是RESTful API支持任意語言調用,由於它是基於https,七層協議python
基於rest_cherry RESTful_API官網linux
注意:本文選擇使用rest_cherry模塊來實現SaltStack的HTTP APIjson
一、Salt_Master 安裝和設置salt-apiapi
1.安裝salt-api,並設置開機啓動安全
[root@linux-node1 ~]# yum -y install salt-api pyOpenSSL [root@linux-node1 ~]# systemctl enable salt-api
2.配置自簽名證書bash
[root@linux-node1 ~]# cd /etc/pki/tls/certs/ [root@linux-node1 certs]# make testcert umask 77 ; \ /usr/bin/openssl genrsa -aes128 2048 > /etc/pki/tls/private/localhost.key Generating RSA private key, 2048 bit long modulus .......+++ ................................+++ e is 65537 (0x10001) Enter pass phrase: # 輸入加密密碼,這裏我使用123456 Verifying - Enter pass phrase: # 確認加密密碼 umask 77 ; \ /usr/bin/openssl req -utf8 -new -key /etc/pki/tls/private/localhost.key -x509 -days 365 -out /etc/pki/tls/certs/localhost.crt Enter pass phrase for /etc/pki/tls/private/localhost.key: You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [XX]:CN State or Province Name (full name) []:Guangdong Locality Name (eg, city) [Default City]:guangzhou Organization Name (eg, company) [Default Company Ltd]: Organizational Unit Name (eg, section) []: Common Name (eg, your name or your server's hostname) []: Email Address []: // 解密key文件,生成無密碼的key文件, 過程當中須要輸入key密碼,該密碼爲以前生成證書時設置的密碼 [root@linux-node1 ~]# cd /etc/pki/tls/private/ [root@linux-node1 private]# openssl rsa -in localhost.key -out localhost_nopass.key
2.建立普通用戶app
[root@linux-node1 ~]# useradd saltapi -M -s /sbin/nologin // 爲新建的saltapi用戶設置密碼 [root@linux-node1 ~]# echo "salt123456" |passwd --stdin saltapi
3.修改/etc/salt/master文件curl
[root@linux-node1 ~]# sed -i '/#default_include/s/#default/default/g' /etc/salt/master
4.建立/etc/salt/master.d/目錄
[root@linux-node1 ~]# mkdir -p /etc/salt/master.d/ [root@linux-node1 ~]# cd /etc/salt/master.d/ [root@linux-node1 ~]# touch eauth.conf && touch api.conf
5.編輯eauth.conf,添加下面內容
external_auth: pam: # 可插入式驗證模塊 saltapi: # 用戶 - .* # 該配置文件給予saltapi用戶全部模塊使用權限,出於安全考慮通常只給予特定模塊使用權限 - '@wheel' # 查看salt-key權限 - '@runner' # 查看minion是否存活權限
6.編輯api.conf,添加下面內容
rest_cherrypy: port: 8001 ssl_crt: /etc/pki/tls/certs/localhost.crt ssl_key: /etc/pki/tls/private/localhost_nopass.key
7.啓動salt-api
# systemctl restart salt-master # systemctl start salt-api # ps -ef|grep salt-api # netstat -lnput|grep 8001
8.請求salt-api的token
curl -k https://10.0.0.170:8001/login \ -H 'Accept: application/x-yaml' \ -d username=saltapi \ -d password=salt123456 \ -d eauth=pam return: - eauth: pam expire: 1556680076.98615 perms: - .* - '@wheel' - '@runner' start: 1556636876.986149 token: 8b3d2a0d9b7708a599173ecd072834321c9d4187 user: saltapi
二、基於python調用REST API
import requests import json # 使用urllib2請求https出錯,作的設置 import ssl context = ssl._create_unverified_context() # 移除https警告 requests.packages.urllib3.disable_warnings() salt_api = "https://10.0.0.170:8001/" class SaltApi: """ 定義salt api接口的類 初始化得到token """ def __init__(self, url): self.url = url self.username = "saltapi" self.password = "salt123456" self.headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36", "Content-type": "application/json" } self.params = {'client': 'local', 'fun': '', 'tgt': ''} self.login_url = salt_api + "login" # https://10.0.0.170:8001/login # 將salt api的用戶名和密碼,認證方式封裝到get參數裏 self.login_params = {'username': self.username, 'password': self.password, 'eauth': 'pam'} # 將salt url以及封裝的參數,傳給get_data函數執行,並獲取token self.token = self.get_data(self.login_url, self.login_params).get('token') # 將token值添加到headers裏的X-Auth-Token字段(每次對象執行的時候都會先獲取到token,將其賦值給 self.headers['X-Auth-Token'] ) self.headers['X-Auth-Token'] = self.token def get_data(self, url, params): ''' 執行post或get請求,並返回執行結果 :param url: api url地址 :param params: post傳入的參數 :return: ''' # 必須將 params 攜帶的參數轉換成json格式,才能得到到json格式的返回結果(這是salt的規定) if params: # params 不爲空執行post方法 send_data = json.dumps(params) request = requests.post(url, data=send_data, headers=self.headers, verify=False) response = request.json() result = dict(response) return result['return'][0] # 返回結果 elif params is None: # params 爲空執行get方法 request = requests.get(url, headers=self.headers, verify=False) response = request.json() result = dict(response) return result['return'][0] # 返回結果 def get_jobs(self,jid): ''' get方法去獲取對應jid的任務執行結果 :param jid: 接收任務ID/jobs ID :return: ''' jobs_url = self.url + "jobs/" +jid result = self.get_data(jobs_url,params=None) return result def salt_command(self, tgt, method, arg=None): """ 直接執行salt命令, 遠程執行命令,至關於salt 'client1' cmd.run 'free -m', :param tgt: 目標主機 例如(linux-node1 / linux-* / *) :param method: 執行的模塊 例如(test.ping / cmd.run) :param arg: 執行的模塊參數 例如(cmd.run -m "df -h") :return: """ if arg: params = {'client': 'local', 'fun': method, 'tgt': tgt, 'arg': arg} else: params = {'client': 'local', 'fun': method, 'tgt': tgt} result = self.get_data(self.url, params) return result def salt_sls(self,tgt,mods,pillar=None,saltenv='base'): """ 執行salt的sls文件,支持pillar變量和純sls文件 :param tgt: 目標主機 :param mods: sls文件名,(test.sls == > test),去掉結尾的sls :param pillar: 傳給文件的pillar變量值 :param saltenv: sls的環境變量,這裏默認爲base,若是你有dev、test等,就能夠本身傳入 :return: """ if pillar: # 若是pillar傳了參數,則執行下面的代碼 data = { 'mods': mods, 'saltenv': saltenv, 'pillar': pillar, "concurrent": True } elif pillar is None: # 若是pillar 爲None,則執行下面代碼 data = { 'mods': mods, 'saltenv': saltenv, "concurrent": True } params = {'client': 'local', 'fun': 'state.sls', 'tgt':tgt,'kwarg':data} result = self.get_data(self.url, params) return result def salt_async_command(self, tgt, method, arg=None): """ 異步執行salt命令,只會返回任務id 即jid """ if arg: params = {'client': 'local_async', 'fun': method, 'tgt': tgt, 'arg': arg} else: params = {'client': 'local_async', 'fun': method, 'tgt': tgt} # 將返回的jid傳給 self.get_data 函數執行並獲取該jid的執行結果 jid_result = self.get_data(self.url, params) jid = jid_result['jid'] result = self.get_jobs(jid) return result def salt_async_sls(self,tgt,mods,pillar=None,saltenv='base'): """ 異步執行salt的sls文件,返回jib """ if pillar: # 若是pillar傳了參數,則執行下面的代碼 data = { 'mods': mods, 'saltenv': saltenv, 'pillar': pillar, "concurrent": True } elif pillar is None: # 若是pillar 爲None,則執行下面代碼 data = { 'mods': mods, 'saltenv': saltenv, "concurrent": True } params = {'client': 'local_async', 'fun': 'state.sls', 'tgt':tgt,'kwarg':data} # 將返回的jid傳給 self.get_data 函數執行並獲取該jid的執行結果 jid_result = self.get_data(self.url, params) jid = jid_result['jid'] result = self.get_jobs(jid) return result def get_minion_status(self): """ 判斷當前sallt管理的minion是否存活,並獲取返回結果 :return: """ method = "manage.status" params = {'client': 'runner','fun': method,} result = self.get_data(self.url, params) return result def get_grains(self,tgt, arg=None): """ 執行grains """ if arg: # 若是arg傳入參數,執行下面代碼,獲取到對應的grains結果 method = "grains.get" params = {'client': 'local', 'fun': method, 'tgt': tgt, 'arg': arg} elif arg is None: # 若是arg爲None,執行下面代碼,獲取到grains的全部結果 method = "grains.items" params = {'client': 'local', 'fun': method, 'tgt': tgt} result = self.get_data(self.url, params) return result def salt_evens(self): """ salt事件監聽, :return: """ events_url = self.url + "/events" result = self.get_data(events_url,params=None) print(self.url) return result def salt_main(): try: salt = SaltApi(salt_api) return salt except Exception as e: raise print('saltstack api鏈接異常') # 實例化 salt = salt_main() # 執行sls命令 def x1(): result = salt.salt_command('*','cmd.run','df -h') print(result) # 檢測已添加的minion是否存活 def x2(): result = salt.get_minion_status() print(result) # 測試salt執行sls def x3(): pillar = {'name':'ok'} result = salt.salt_sls('*', 't2',pillar) # result = salt.salt_sls('*','t2') print(result) # 執行grains def x4(): # result = salt.get_grains('*','ip_interfaces') # 獲取全部主機指定的grains信息 result = salt.get_grains('*') # 獲取全部主機的grains信息 print(result) # 異步 執行salt命令 def x5(): result = salt.salt_async_command('*', 'cmd.run', 'df -h') print(result) # 異步 執行salt sls def x6(): pillar = {'name':'ok'} result = salt.salt_async_sls('*', 't2',pillar) # result = salt.salt_sls('*','t2') print(result) # 執行salt事件監聽 def x7(): result = salt.salt_evens() print(result)