Python3安裝使用SaltStack以及salt-api詳解

序言

  最近在使用salt-api作主機批量管理部署,整理一下文檔。以前使用saltstack 多用於命令行管理,本身作web版的自動化管理平臺時,發現命令行的些許侷限性,接觸到salt-api,找到了替代方式。本文使用的saltstack 版本是2018.3.0最新版本,這個版本中官方作了更多python3的支持,使用utf-8,修補了許多與文件I/O和str/bytes不匹配的問題。以前在使用salt時都是用的Python2版本,如今使用的架構是python3版本的,畢竟將來python3纔是趨勢。所在在此探討下python3使用saltstack以及salt-api的一些方式方法。node

 

系統環境:

  CentOS7 + python3.6 + saltstack2018.3.0python

 

Centos7 Python2升級Python3

# 首先安裝python3
# 能夠不安裝Python3, 默認安裝py3版本的salt,它會本身安裝一個python3.4版本,全部的salt操做都是在這個python3.4版本上運行的,只不過我本身的項目須要python3,因此本身安裝了一個。特此說明

    1. tar zxvf Python-3.6.1.tgz   
    2. cd  Python-3.6.1        
    3. ./configure
    4. make
    5. make install
    6. mv  /usr/bin/python /usr/bin/python2 # 若是是軟鏈接,能夠直接刪除
    7. ln -s /usr/local/bin/python3.6 /usr/bin/python
    8. vim /usr/bin/yum   # 修改Yum,使yum依然有效,yum依靠老版本的python
    9. #!/usr/bin/python 修改成#!/usr/bin/python2
        
# 修改完/usr/bin/yum 依然還有問題,能夠嘗試修改/usr/libexec/urlgrabber-ext-down的文件python擡頭

# 使用Python3直接啓動salt,由於默認環境已經切換的python3, 因此直接啓動便可

 

 

saltstack 安裝:

# 更新yum
yum update

# Centos7 - Python3 - salt 安裝源
yum install -y https://repo.saltstack.com/py3/redhat/salt-py3-repo-latest-2.el7.noarch.rpm 

yum clean expire-cache
# 安裝必要軟件(mariadb是mysql,用於存儲salt命令執行結果和jobid,可不安裝)
yum -y install mariadb mariadb-devel mariadb-server wget  python-devel gcc c++ make openssl openssl-devel passwd libffi libffi-devel
# 安裝salt
yum install salt-master salt-minion salt-ssh salt-syndic salt-cloud salt-api

# Centos7/6  -Python2 安裝源
yum install https://repo.saltstack.com/yum/redhat/salt-repo-latest-2.el7.noarch.rpm
yum install https://repo.saltstack.com/yum/redhat/salt-repo-latest-2.el6.noarch.rpm

 

# yum install salt-master salt-minion salt-ssh salt-syndic salt-cloud salt-api

===================
salt-api
salt-cloud
salt-master
salt-minion
salt-ssh
salt-syndic
-----------------------------------
libsodium 
libtomcrypt
libtommath
openpgm 
python34
python34-PyYAML
python34-backports_abc
python34-cherrypy
python34-crypto
python34-jinja2
python34-libcloud 
python34-libs
python34-markupsafe
python34-msgpack
python34-psutil
python34-pycurl
python34-setuptools 
python34-six
python34-tornado
python34-zmq
salt
zeromq 
yum 安裝的依賴包

salt-api 安裝:

# 上一步已經安裝了,寫下單獨安裝的命令
# yum install salt-api  -y

# 建立證書
[root@centos7 ~]# cd /etc/pki/tls/certs/
# 生成自簽名證書,用於ssl
[root@centos7 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:       # 輸入加密密語,4到8191個字符
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 -set_serial 0
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) []:Shanghai  # 選填,可不填寫直接回車
Locality Name (eg, city) [Default City]:Shanghai  # 選填,可不填寫直接回車
Organization Name (eg, company) [Default Company Ltd]: # 選填,可不填寫直接回車
Organizational Unit Name (eg, section) []: # 選填,可不填寫直接回車
Common Name (eg, your name or your server's hostname) []: # 選填,可不填寫直接回車
Email Address []: # 選填,可不填寫直接回車
[root@centos7 certs]# cd ../private/
# 解密key文件,生成無密碼的key文件, 過程當中須要輸入key密碼,該密碼爲以前生成證書時設置的密碼
[root@centos7 private]# openssl rsa -in localhost.key -out localhost_nopass.key
Enter pass phrase for localhost.key:
writing RSA key
[root@centos7 private]# ls
localhost.key  localhost_nopass.key
# 備註
	若是make testcert出現錯誤,則刪除/etc/pki/tls/private/localhost.key文件,而後再make testcert
# 建立用戶(用於salt-api認證)
useradd -M -s /sbin/nologin saltapi && echo "password"|/usr/bin/passwd saltapi --stdin

 

 # 單獨安裝pip的方式
    wget https://bootstrap.pypa.io/get-pip.py
    python get-pip.py

# 升級下pip
    pip install --upgrade pip

# pip 安裝salt-api所需軟件,最新版本中默認yum已經安裝,無需安裝
    pip install pyOpenSSL   
    pip install cherrypy   
pip 安裝與升級

 

salt-api 配置文件編寫:

# 添加配置文件,能夠把eauth.conf和api.conf合二爲一爲api.conf
[root@centos7 ~]# mkdir -p /etc/salt/master.d/        
# 這個目錄默認不存在,須要手動建立,在/etc/salt/master主配置文件中有指定,相似include
[root@centos7 ~]# vim /etc/salt/master.d/eauth.conf   
# 處於安全因素,通常只給特定模塊的使用權限,這裏給saltapi用戶全部模塊的使用權限       
external_auth:
  pam:
    saltapi:
      - .*
      - '@wheel'
      - '@runner'
       
[root@centos7 ~]# vim /etc/salt/master.d/api.conf 
rest_cherrypy:
  port: 8000                       #  salt-api 監聽端口
  ssl_crt: /etc/pki/tls/certs/localhost.crt          # ssl認證的證書
  ssl_key: /etc/pki/tls/private/localhost_nopass.key

# 備註:
    注意全部的縮進都是兩個空格,要注意':'後面都有一個空格

  

# salt-api 配置文件詳解
port : 必須填寫,salt-api啓動的端口
host :默認啓動於0.0.0.0,能夠不填寫
debug : 默認爲False,True開啓後,會輸出debug日誌
log_access_file : HTTP訪問日誌的路徑,在2016.11.0版本添加的
log_error_file : HTTP錯誤日誌路徑,在2016.11.0版本添加的
ssl_crt : SSL證書的絕對路徑
ssl_key: SSK證書的私鑰絕對路徑
ssl_chain : 在使用PyOpenSSL時可選參數,將證書出遞給' Context.load_verify_locations '
disable_ssl : 禁用SSL標識。認證證書將會被送進clear
webhook_disable_auth : False
webhook_url : /hook
thread_pool : 100
socket_queue_size : 30
expire_responses : True
max_request_body_size : 1048576
collect_stats : False
stats_disable_auth : False
更多詳細參數請見:https://github.com/saltstack/salt/blob/develop/salt/netapi/rest_cherrypy/app.py
# 啓動
systemctl start salt-master
systemctl start salt-minion
systemctl start salt-api

  

Salt-Api使用

Salt-Api 的使用,啓動master, minion , api後,測試經過https操做saltstackmysql

# salt-api 使用
# 登錄認證獲取token
[root@aliyuntest ~]#  curl -sSk https://localhost:8000/login -H 'Accept: application/x-yaml' -d username=saltapi -d password=password -d eauth=pam
return:
- eauth: pam
  expire: 1511805994.166656
  perms:
  - .*
  - '@wheel'
  - '@runner'
  start: 1511762794.166655
  token: 1bc26f7a595eb08c70780352c5724180d5062876  # 關鍵
  user: saltapi
# 使用獲取的token進行命令操做
[root@aliyuntest ~]# curl -sSk https://localhost:8000 -H 'Accept: application/x-yaml' -H 'X-Auth-Token: 12ff12468f7ae98d4880fd9a627bf8ef87942d5a' -d client=local  -d tgt='*' -d fun=test.ping
return:
- minion: true

參數解釋:
client : 模塊,python處理salt-api的主要模塊,‘client interfaces <netapi-clients>’
	local : 使用‘LocalClient <salt.client.LocalClient>’ 發送命令給受控主機,等價於saltstack命令行中的'salt'命令
	local_async : 和local不一樣之處在於,這個模塊是用於異步操做的,即在master端執行命令後返回的是一個jobid,任務放在後臺運行,經過產看jobid的結果來獲取命令的執行結果。
	runner : 使用'RunnerClient<salt.runner.RunnerClient>' 調用salt-master上的runner模塊,等價於saltstack命令行中的'salt-run'命令
	runner_async : 異步執行runner模塊
	wheel : 使用'WheelClient<salt.wheel.WheelClient>', 調用salt-master上的wheel模塊,wheel模塊沒有在命令行端等價的模塊,但它一般管理主機資源,好比文件狀態,pillar文件,salt配置文件,以及關鍵模塊<salt.wheel.key>功能相似於命令行中的salt-key。
	wheel_async : 異步執行wheel模塊
	備註:通常狀況下local模塊,須要tgt和arg(數組),kwarg(字典),由於這些值將被髮送到minions並用於執行所請求的函數。而runner和wheel都是直接應用於master,不須要這些參數。
tgt : minions
fun : 函數
arg : 參數
expr_form : tgt的匹配規則
	'glob' - Bash glob completion - Default
	'pcre' - Perl style regular expression
	'list' - Python list of hosts
	'grain' - Match based on a grain comparison
	'grain_pcre' - Grain comparison with a regex
	'pillar' - Pillar data comparison
	'nodegroup' - Match on nodegroup
	'range' - Use a Range server for matching
	'compound' - Pass a compound match string

 

salt-api 常見錯誤nginx

啓動後經過curl方式測試鏈接salt-api 報錯401
#####################################
       <h2>401 Unauthorized</h2>
        <p>Could not authenticate using provided credentials</p>
        <pre id="traceback">Traceback (most recent call last):
  File "/usr/lib/python3.4/site-packages/cherrypy/_cprequest.py", line 670, in respond
    response.body = self.handler()
  File "/usr/lib/python3.4/site-packages/cherrypy/lib/encoding.py", line 217, in __call__
    self.body = self.oldhandler(*args, **kwargs)
  File "/usr/lib/python3.4/site-packages/salt/netapi/rest_cherrypy/app.py", line 858, in hypermedia_handler
    ret = cherrypy.serving.request._hypermedia_inner_handler(*args, **kwargs)
  File "/usr/lib/python3.4/site-packages/cherrypy/_cpdispatch.py", line 60, in __call__
    return self.callable(*self.args, **self.kwargs)
  File "/usr/lib/python3.4/site-packages/salt/netapi/rest_cherrypy/app.py", line 1863, in POST
    'Could not authenticate using provided credentials')
cherrypy._cperror.HTTPError: (401, 'Could not authenticate using provided credentials')
#########################################
401問題產生緣由:用戶認證異常。
一般是salt-api的兩個配置文件寫錯了(好比少了空格之類的);
可是我產生的緣由是salt-api配置啓動前,salt-master已經運行了,致使salt-master未能找到saltapi用戶,重啓salt-master解決。
401 錯誤

 

Class SaltApi

  如今全部的操做仍是基於命令行模式,在項目中不能這麼使用,咱們能夠寫一個基於salt-api的類,方便項目代碼的調用。在這裏特別附上python二、python3兩個版本的salt-api class, 在使用中發現,python3版本的salt-api class 是能夠直接去請求管理python2版本下的saltstack,這樣就解決了一些跨python版本的問題,畢竟如今主流操做系統默認安裝的仍是python2,避免了手動升級python3, 可讓saltstack在python2下繼續運行,而咱們能夠經過python3去管理saltstack。c++

# -*- coding: utf-8 -*-

import urllib2,urllib
import time
import ssl
ssl._create_default_https_context = ssl._create_unverified_context
try:
    import json
except ImportError:
    import simplejson as json

class SaltAPI(object):
    __token_id = ''
    def __init__(self,url,username,password):
        self.__url = url.rstrip('/')
        self.__user = username
        self.__password = password

    def token_id(self):
        ''' user login and get token id '''
        params = {'eauth': 'pam', 'username': self.__user, 'password': self.__password}
        encode = urllib.urlencode(params)
        obj = urllib.unquote(encode)
        content = self.postRequest(obj,prefix='/login')
        try:
                self.__token_id = content['return'][0]['token']
        except KeyError:
                raise KeyError

    def postRequest(self,obj,prefix='/'):
        url = self.__url + prefix
        headers = {'X-Auth-Token'   : self.__token_id}
        req = urllib2.Request(url, obj, headers)
        opener = urllib2.urlopen(req)
        content = json.loads(opener.read())
        return content

    def list_all_key(self):
        '''
        獲取包括認證、未認證salt主機
        '''
        params = {'client': 'wheel', 'fun': 'key.list_all'}
        obj = urllib.urlencode(params)
        self.token_id()
        content = self.postRequest(obj)
        minions = content['return'][0]['data']['return']['minions']
        minions_pre = content['return'][0]['data']['return']['minions_pre']
        return minions,minions_pre

    def delete_key(self,node_name):
        '''
        拒絕salt主機,刪除主機
        '''
        params = {'client': 'wheel', 'fun': 'key.delete', 'match': node_name}
        obj = urllib.urlencode(params)
        self.token_id()
        content = self.postRequest(obj)
        ret = content['return'][0]['data']['success']
        return ret

    def accept_key(self,node_name):
        '''
        接受salt主機
        '''
        params = {'client': 'wheel', 'fun': 'key.accept', 'match': node_name}
        obj = urllib.urlencode(params)
        self.token_id()
        content = self.postRequest(obj)
        ret = content['return'][0]['data']['success']
        return ret

    def remote_noarg_execution(self,tgt,fun):
        ''' 
        執行命令沒有參數
        tgt:目標主機
        fun: 執行模塊,例如「test.ping」
        '''
        params = {'client': 'local', 'tgt': tgt, 'fun': fun}
        obj = urllib.urlencode(params)
        self.token_id()
        content = self.postRequest(obj)
        ret = content['return'][0].values()
        return ret

    def remote_execution(self,tgt,fun,arg):
        ''' 執行命令有參數 '''
        params = {'client': 'local', 'tgt': tgt, 'fun': fun, 'arg': arg}
        obj = urllib.urlencode(params)
        self.token_id()
        content = self.postRequest(obj)
        ret = content['return'][0][tgt]
        return ret

    def target_remote_execution(self,tgt,fun,arg):
        ''' 異步執行遠程命令,執行模塊 '''
        params = {'client': 'local', 'tgt': tgt, 'fun': fun, 'arg': arg, 'expr_form': 'nodegroup'}
        obj = urllib.urlencode(params)
        self.token_id()
        content = self.postRequest(obj)
        jid = content['return'][0]['jid']
        return jid

    def deploy(self,tgt,arg):
        ''' 狀態管理 '''
        params = {'client': 'local', 'tgt': tgt, 'fun': 'state.sls', 'arg': arg}
        obj = urllib.urlencode(params)
        self.token_id()
        content = self.postRequest(obj)
        return content

    def async_deploy(self,tgt,arg):
        ''' 異步狀態管理 '''
        params = {'client': 'local_async', 'tgt': tgt, 'fun': 'state.sls', 'arg': arg}
        obj = urllib.urlencode(params)
        self.token_id()
        content = self.postRequest(obj)
        jid = content['return'][0]['jid']
        return jid


def main():
    sapi = SaltAPI(url='https://192.168.11.12:8000',username='saltapi',password='123qwe')
    sapi.token_id()
    #print sapi.list_all_key()
    #sapi.delete_key('test-01')
    #sapi.accept_key('test-01')
    #sapi.deploy('test-01','nginx')
    #print sapi.remote_noarg_execution('buzhidao','grains.items')

if __name__ == '__main__':
    main()
Python2版本
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# author : wangyongcun

import urllib,json
import urllib.request
import urllib.parse
import ssl
from SOPS import settings
ssl._create_default_https_context = ssl._create_unverified_context


class SaltAPI(object):
    __token_id = ''

    def __init__(self):
        self.__url = settings.SALT_API['url']
        self.__user = settings.SALT_API['user']
        self.__password = settings.SALT_API['password']

    def token_id(self):
        """
            用戶登錄和獲取token
        :return:
        """
        params = {'eauth': 'pam', 'username': self.__user, 'password': self.__password}
        encode = urllib.parse.urlencode(params)
        obj = urllib.parse.unquote(encode).encode('utf-8')
        content = self.postRequest(obj, prefix='/login')
        try:
            self.__token_id = content['return'][0]['token']
        except KeyError:
            raise KeyError

    def postRequest(self,obj,prefix='/'):
        url = self.__url + prefix
        headers = {'X-Auth-Token': self.__token_id}
        req = urllib.request.Request(url, obj, headers)
        opener = urllib.request.urlopen(req)
        content = json.loads(opener.read())
        return content

    def list_all_key(self):
        """
            獲取包括認證、未認證salt主機
        """

        params = {'client': 'wheel', 'fun': 'key.list_all'}
        obj = urllib.parse.urlencode(params).encode('utf-8')
        self.token_id()
        content = self.postRequest(obj)
        minions = content['return'][0]['data']['return']['minions']
        minions_pre = content['return'][0]['data']['return']['minions_pre']
        return minions, minions_pre

    def delete_key(self, node_name):
        '''
            拒絕salt主機
        '''

        params = {'client': 'wheel', 'fun': 'key.delete', 'match': node_name}
        obj = urllib.parse.urlencode(params).encode('utf-8')
        self.token_id()
        content = self.postRequest(obj)
        ret = content['return'][0]['data']['success']
        return ret

    def accept_key(self,node_name):
        '''
            接受salt主機
        '''

        params = {'client': 'wheel', 'fun': 'key.accept', 'match': node_name}
        obj = urllib.parse.urlencode(params).encode('utf-8')
        self.token_id()
        content = self.postRequest(obj)
        ret = content['return'][0]['data']['success']
        return ret

    def salt_get_jid_ret(self,jid):
        """
            經過jid獲取執行結果
        :param jid: jobid
        :return: 結果
        """
        params = {'client':'runner', 'fun':'jobs.lookup_jid', 'jid': jid}
        obj = urllib.parse.urlencode(params).encode('utf-8')
        self.token_id()
        content = self.postRequest(obj)
        ret = content['return'][0]
        return ret

    def salt_running_jobs(self):
        """
            獲取運行中的任務
        :return: 任務結果
        """
        params = {'client':'runner', 'fun': 'jobs.active'}
        obj = urllib.parse.urlencode(params).encode('utf-8')
        self.token_id()
        content = self.postRequest(obj)
        ret = content['return'][0]
        return ret

    def remote_noarg_execution_sigle(self, tgt, fun):
        """
            單臺minin執行命令沒有參數
        :param tgt: 目標主機
        :param fun:  執行模塊
        :return: 執行結果
        """
        params = {'client': 'local', 'tgt': tgt, 'fun': fun}
        obj = urllib.parse.urlencode(params).encode('utf-8')
        self.token_id()
        content = self.postRequest(obj)
        # print(content)
        # {'return': [{'salt-master': True}]}
        ret = content['return'][0]
        return ret

    def remote_execution_single(self, tgt, fun, arg):
        """
            單臺minion遠程執行,有參數
        :param tgt: minion
        :param fun: 模塊
        :param arg: 參數
        :return: 執行結果
        """
        params = {'client': 'local', 'tgt': tgt, 'fun': fun, 'arg': arg}
        obj = urllib.parse.urlencode(params).encode('utf-8')
        self.token_id()
        content = self.postRequest(obj)
        # print(content)
        # {'return': [{'salt-master': 'root'}]}
        ret = content['return']
        return ret

    def remote_async_execution_module(self, tgt, fun, arg):
        """
            遠程異步執行模塊,有參數
        :param tgt: minion list
        :param fun: 模塊
        :param arg: 參數
        :return: jobid
        """
        params = {'client': 'local_async', 'tgt': tgt, 'fun': fun, 'arg': arg, 'expr_form': 'list'}
        obj = urllib.parse.urlencode(params).encode('utf-8')
        self.token_id()
        content = self.postRequest(obj)
        # print(content)
        # {'return': [{'jid': '20180131173846594347', 'minions': ['salt-master', 'salt-minion']}]}
        jid = content['return'][0]['jid']
        return jid

    def remote_execution_module(self, tgt, fun, arg):
        """
            遠程執行模塊,有參數
        :param tgt: minion list
        :param fun: 模塊
        :param arg: 參數
        :return: dict, {'minion1': 'ret', 'minion2': 'ret'}
        """
        params = {'client': 'local', 'tgt': tgt, 'fun': fun, 'arg': arg, 'expr_form': 'list'}
        obj = urllib.parse.urlencode(params).encode('utf-8')
        self.token_id()
        content = self.postRequest(obj)
        # print(content)
        # {'return': [{'salt-master': 'root', 'salt-minion': 'root'}]}
        ret = content['return'][0]
        return ret

    def salt_state(self, tgt, arg, expr_form):
        '''
        sls文件
        '''
        params = {'client': 'local', 'tgt': tgt, 'fun': 'state.sls', 'arg': arg, 'expr_form': expr_form}
        obj = urllib.parse.urlencode(params).encode('utf-8')
        self.token_id()
        content = self.postRequest(obj)
        ret = content['return'][0]
        return ret

    def salt_alive(self, tgt):
        '''
        salt主機存活檢測
        '''
        params = {'client': 'local', 'tgt': tgt, 'fun': 'test.ping'}
        obj = urllib.parse.urlencode(params).encode('utf-8')
        self.token_id()
        content = self.postRequest(obj)
        ret = content['return'][0]
        return ret


if __name__ == '__main__':
        salt = SaltAPI()
        # minions, minions_pre = salt.list_all_key()
        # 說明若是'expr_form': 'list',表示minion是以主機列表形式執行時,須要把list拼接成字符串,以下所示
        minions = ['salt-master', 'salt-minion']
        hosts = map(str, minions)
        hosts = ",".join(hosts)
        ret = salt.remote_noarg_execution_sigle('salt-master', 'test.ping')
        print(ret)
        # print(type(ret))
Python3 版本salt-api class

  上面的版本基本功能實現,可是未實現運行多參數命令的問題,緣由未找到,若是有讀者發現了,能夠告訴我,感謝~!提供一個基於requests的版本,實現了多參數的執行。git

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# author : wangyongcun

import requests
import copy

SALT_API = {
    "url": "https://192.168.11.12:8000",
    "user": "saltapi",
    "password": "password",
}


class SaltApi(object):

    def __init__(self):
        self.__user = SALT_API["user"]
        self.__passwd = SALT_API["password"]
        self.url = SALT_API["url"]
        self.headers = {
            'Content-Type': 'application/json',
            'Accept': 'application/json'
        }
        self.__base_data = dict(
            username=self.__user,
            password=self.__passwd,
            eauth='pam'
        )
        self.__token = self.get_token()

    def get_token(self):
        """  login salt-api and get token_id """
        params = copy.deepcopy(self.__base_data)
        requests.packages.urllib3.disable_warnings()  # close ssl warning, py3 really can do it!
        ret = requests.post(url=self.url + '/login', verify=False, headers=self.headers, json=params)
        ret_json = ret.json()
        token = ret_json["return"][0]["token"]
        return token

    def __post(self, **kwargs):
        """  custom post interface, headers contains X-Auth-Token """
        headers_token = {'X-Auth-Token': self.__token}
        headers_token.update(self.headers)
        requests.packages.urllib3.disable_warnings()
        ret = requests.post(url=self.url, verify=False, headers=headers_token, **kwargs)
        ret_code, ret_data = ret.status_code, ret.json()
        return (ret_code, ret_data)

    def list_all_keys(self):
        """  show all keys, minions have been certified, minion_pre not certification """
        params = {'client': 'wheel', 'fun': 'key.list_all'}
        r = self.__post(json=params)
        minions = r[1]['return'][0]['data']['return']['minions']
        minions_pre = r[1]['return'][0]['data']['return']['minions_pre']
        return minions, minions_pre

    def delete_key(self, tgt):
        """ delete a key """
        params = {'client': 'wheel', 'fun': 'key.delete', 'match': tgt}
        r = self.__post(json=params)
        return r[1]['return'][0]['data']['success']

    def accept_key(self, tgt):
        """  accept a key """
        params = {'client': 'wheel', 'fun': 'key.accept', 'match': tgt}
        r = self.__post(json=params)
        return r[1]['return'][0]['data']['success']

    def lookup_jid_ret(self, jid):
        """  depend on jobid to find result """
        params = {'client': 'runner', 'fun': 'jobs.lookup_jid', 'jid': jid}
        r = self.__post(json=params)
        return r[1]['return'][0]

    def salt_running_jobs(self):
        """ show all running jobs """
        params = {'client': 'runner', 'fun': 'jobs.active'}
        r = self.__post(json=params)
        return r[1]['return'][0]

    def run(self, params):
        """ remote common interface, you need custom data dict
            for example:
                params = {
                    'client': 'local',
                    'fun': 'grains.item',
                    'tgt': '*',
                    'arg': ('os', 'id', 'host' ),
                    'kwargs': {},
                    'expr_form': 'glob',
                    'timeout': 60
                }
         """
        r = self.__post(json=params)
        return r[1]['return'][0]

    def remote_execution(self, tgt, fun, arg, ex='glob'):
        """ remote execution, command will wait result
            arg must be a tuple, eg: arg = (a, b)
            expr_form : tgt m

        """
        params = {'client': 'local', 'tgt': tgt, 'fun': fun, 'arg': arg, 'expr_form': ex}
        r = self.__post(json=params)
        return r[1]['return'][0]

    def async_remote_execution(self, tgt, fun, arg, ex='glob'):
        """ async remote exection, it will return a jobid
            tgt model is list, but not python list, just like 'node1, node2, node3' as a string.
         """
        params = {'client': 'local_async', 'tgt': tgt, 'fun': fun, 'arg': arg, 'expr_form': ex}
        r = self.__post(json=params)
        return r[1]['return'][0]['jid']

    def salt_state(self, tgt, arg, ex='list'):
        """  salt state.sls """
        params = {'client': 'local', 'tgt': tgt, 'fun': 'state.sls', 'arg': arg, 'expr_form': ex}
        r = self.__post(json=params)
        return r[1]['return'][0]

    def salt_alive(self, tgt, ex='glob'):
        """ salt test.ping """
        params = {'client': 'local', 'tgt': tgt, 'fun': 'test.ping', 'expr_form': ex}
        r = self.__post(json=params)
        return r[1]['return'][0]


if __name__ == '__main__':
    data = {
        'client': 'local',
        'fun': 'grains.item',
        'tgt': '*',
        'arg': ('os', 'id', 'host' ),
        'kwargs': {},
        'expr_form': 'glob',
        'timeout': 60
    }
    obj = SaltApi()
    # ret = obj.list_all_keys()
    # ret = obj.accept_key('windows-test')
    # ret = obj.delete_key('windows-test')
    # ret = obj.lookup_jid_ret('20180612111505161780')
    # ret = obj.salt_running_jobs()
    # ret = obj.remote_execution('*', 'grains.item', ('os', 'id'))
    # ret = obj.async_remote_execution('*', 'grains.item', ('os', 'id'))
    # ret = obj.salt_alive('*', 'glob')
    ret = obj.run(data)
    print(ret)
Python 自定義salt-api 類(requests版本)
相關文章
相關標籤/搜索