一、salt-api简介
官方文档
SaltStack官方提供有REST API格式的salt-api项目,将使salt与第三方系统集成变得更加简单。
salt-api有两种方式,一种是函数的形式,有定义好的函数,可以直接调用,直接写Python代码调用函数或者类就可以了。
第二种形式是salt-api有封装好的http协议,需要启动一个服务端,直接启动salt-api就可以通过http协议进行调用。
二、salt-api安装配置
实验
在salt-master端:
1、安装salt-api
yum install salt-api -y
2、自签名证书,生产环境可以购买(说明:如果没有salt-call命令,装上salt-minion即可,依赖于该包)
salt-call --local tls.create_self_signed_cert
3、打开include加载子配置文件,方便管理,需手动添加
vim /etc/salt/master
1233 default_include: master.d/*.conf
4、生成自签名证书(用于ssl)
cd /etc/pki/tls/certs
make testcert
5、此时已经生成证书localhost.crt和密钥localhost.key
6、配置api配置文件,将上面生成的证书写到配置文件
vim /etc/salt/master.d/api.conf
rest_cherrypy:
port: 8000
ssl_crt: /etc/pki/tls/certs/localhost.crt
ssl_key: /etc/pki/tls/private/localhost.key
7、创建认证用户,并设置密码
useradd -M -s /sbin/nologin saltapi
echo 'saltapi' | passwd --stdin saltapi
8、创建认证配置文件
vim /etc/salt/master.d/auth.conf
external_auth:
pam:
saltapi: #saltapi用户可使用以下模块
- .*
- '@wheel'
- '@runner'
- '@jobs'
9、重启salt-master和启动salt-api
systemctl restart salt-master
systemctl start salt-api
10、查看服务开启端口8000
netstat -antuple | grep 8000
11、验证login登录,获取token字符串
curl -sSk https://localhost:8000/login \
> -H 'Accept: application/x-yaml' \
> -d username=saltapi \
> -d password=saltapi \
> -d eauth=pam
return:
- eauth: pam
expire: 1576716959.032581
perms:
- .*
- '@wheel'
- '@runner'
- '@jobs'
start: 1576673759.032578
token: 696da3d2ed5ca00b6cd81d94c5960e6420530ffd
user: saltapi
12、通过api执行test.ping测试连通性
curl -sSk https://172.25.1.1:8000 \
> -H 'Accept: application/x-yaml' \
> -H 'X-Auth-Token:696da3d2ed5ca00b6cd81d94c5960e6420530ffd' \
> -d client=local \
> -d tgt='*' \
> -d fun=test.ping
return:
- server4: true
总结
salt-api必须使用https,生产环境建议使用可信证书
当salt-api服务重启后原token失效
三、编写python脚本请求salt-api接口
自定义一个类,首先初始化时候获得token,然后使用token认证去请求相应的json文件。
salt命令在shell中使用方式是salt 客户端 方法 参数(例子:salt ‘client1’ cmd.run ‘free -m’)。
这里salt命令方法我们已经封装好了,想使用salt的什么方法就传入对应的客户端、方法、参数即可。
代码如下:
python编写异步请求模块
#!/usr/bin/env python
# _*_ coding:utf-8 _*_
__author__ = 'junxi'
import requests
import json
try:
import cookielib
except:
import http.cookiejar as cookielib
# 使用urllib2请求https出错,做的设置
import ssl
context = ssl._create_unverified_context()
# 使用requests请求https出现警告,做的设置
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
salt_api = "https://172.25.1.1:8000/"
class SaltApi:
"""
定义salt api接口的类
初始化获得token
"""
def __init__(self, url):
self.url = url
self.username = "saltapi"
self.password = "saltapi"
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"
# "Content-type": "application/x-yaml"
}
self.params = {'client': 'local', 'fun': '', 'tgt': ''}
# self.params = {'client': 'local', 'fun': '', 'tgt': '', 'arg': ''}
self.login_url = salt_api + "login"
self.login_params = {'username': self.username, 'password': self.password, 'eauth': 'pam'}
self.token = self.get_data(self.login_url, self.login_params)['token']
self.headers['X-Auth-Token'] = self.token
def get_data(self, url, params):
send_data = json.dumps(params)
request = requests.post(url, data=send_data, headers=self.headers, verify=False)
# response = request.text
# response = eval(response) 使用x-yaml格式时使用这个命令把回应的内容转换成字典
# print response
# print request
# print type(request)
response = request.json()
result = dict(response)
# print result
return result['return'][0]
def salt_command(self, tgt, method, arg=None):
"""远程执行命令,相当于salt 'client1' cmd.run 'free -m'"""
if arg:
params = {'client': 'local', 'fun': method, 'tgt': tgt, 'arg': arg}
else:
params = {'client': 'local', 'fun': method, 'tgt': tgt}
print '命令参数: ', params
result = self.get_data(self.url, params)
return result
def main():
print '=================='
print '同步执行命令'
salt = SaltApi(salt_api)
print salt.token
salt_client = '*'
salt_test = 'test.ping'
salt_method = 'cmd.run'
salt_params = 'free -m'
# print salt.salt_command(salt_client, salt_method, salt_params)
# 下面只是为了打印结果好看点
result1 = salt.salt_command(salt_client, salt_test)
for i in result1.keys():
print i, ': ', result1[i]
result2 = salt.salt_command(salt_client, salt_method, salt_params)
for i in result2.keys():
print i
print result2[i]
print
if __name__ == '__main__':
main()
结果:
第一行是请求认证的token。
从结果可以看出来我们请求了两条命令,test.ping和free -m
Saltstack异步执行命令
salt执行命令有时候会有超时的问题,就是命令下发下去了,部分主机没有返回信息,这时候就很难判断命令或任务是否执行成功。因此,salt提供异步执行的功能,发出命令后立即返回一个jid。然后我们就可以根据这个jid来查询任务是否执行成功。
#!/usr/bin/env python
# _*_ coding:utf-8 _*_
__author__ = 'junxi'
import requests
import json
try:
import cookielib
except:
import http.cookiejar as cookielib
# 使用urllib2请求https出错,做的设置
import ssl
context = ssl._create_unverified_context()
# 使用requests请求https出现警告,做的设置
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
salt_api = "https://172.25.1.1:8000/"
class SaltApi:
"""
定义salt api接口的类
初始化获得token
"""
def __init__(self, url):
self.url = url
self.username = "saltapi"
self.password = "saltapi"
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"
# "Content-type": "application/x-yaml"
}
self.params = {'client': 'local', 'fun': '', 'tgt': ''}
# self.params = {'client': 'local', 'fun': '', 'tgt': '', 'arg': ''}
self.login_url = salt_api + "login"
self.login_params = {'username': self.username, 'password': self.password, 'eauth': 'pam'}
self.token = self.get_data(self.login_url, self.login_params)['token']
self.headers['X-Auth-Token'] = self.token
def get_data(self, url, params):
send_data = json.dumps(params)
request = requests.post(url, data=send_data, headers=self.headers, verify=False)
# response = request.text
# response = eval(response) 使用x-yaml格式时使用这个命令把回应的内容转换成字典
# print response
# print request
# print type(request)
response = request.json()
result = dict(response)
# print result
return result['return'][0]
def salt_async_command(self, tgt, method, arg=None): # 异步执行salt命令,根据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(self.url, params)['jid']
return jid
def look_jid(self, jid): # 根据异步执行命令返回的jid查看事件结果
params = {'client': 'runner', 'fun': 'jobs.lookup_jid', 'jid': jid}
print params
result = self.get_data(self.url, params)
return result
def main():
print
print '=================='
print '异步执行命令'
salt1 = SaltApi(salt_api)
salt_client = '*'
salt_test = 'test.ping'
salt_method = 'cmd.run'
salt_params = 'df -hT'
# 下面只是为了打印结果好看点
jid1 = salt1.salt_async_command(salt_client, salt_test)
result1 = salt1.look_jid(jid1)
for i in result1.keys():
print i, ': ', result1[i]
jid2 = salt1.salt_async_command(salt_client, salt_method, salt_params)
result2 = salt1.look_jid(jid2)
for i in result2.keys():
print i
print result2[i]
print
if __name__ == '__main__':
main()
执行结果: