使用salt-api来搭建salt自动化平台
发表于:2026-11-02 作者:千家信息网编辑
千家信息网最后更新 2026年11月02日,一、介绍通常使用saltstack都是在master的服务器上直接命令操作,这个对于运维人员来说不是什么大事,但是也会有出错的时候,而一旦出错,就会有不可挽回的后果。二、框架这里使用django框架,
千家信息网最后更新 2026年11月02日使用salt-api来搭建salt自动化平台
一、介绍
通常使用saltstack都是在master的服务器上直接命令操作,这个对于运维人员来说不是什么大事,但是也会有出错的时候,而一旦出错,就会有不可挽回的后果。
二、框架
这里使用django框架,通过对salt-api的封装,传入命令,执行api,将结果返回到页面上显示。注意:为了防止误操作,我们对传入的命令进行了检查,所有被定义的危险命令将不会被执行。(我这里为了简单,所以定义了可以被执行的命令。),前端使用了jquery+ajax的方式来不刷新页面就将结果显示在页面上的方式。
三、salt-api的安装
网上教程很多,我这里就不再废话了。
四、django代码
1)、整体结构
2)、salt_api.py(这里参照了github上dzhops的代码)
# -*- coding: utf-8 -*-import urllib2, urllib, jsonimport requestsimport jsonimport sslssl._create_default_https_context = ssl._create_unverified_contextclass SaltAPI(object): def __init__(self, url, username, password): self.__url = url.rstrip('/') self.__user = username self.__password = password self.__token_id = self.saltLogin() def saltLogin(self): params = {'eauth': 'pam', 'username': self.__user, 'password': self.__password} encode = urllib.urlencode(params) obj = urllib.unquote(encode) headers = {'X-Auth-Token': ''} url = self.__url + '/login' req = urllib2.Request(url, obj, headers) opener = urllib2.urlopen(req) content = json.loads(opener.read()) try: token = content['return'][0]['token'] return 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 masterToMinionContent(self, tgt, fun, arg): ''' Master控制Minion,返回的结果是内容,不是jid; 目标参数tgt是一个如下格式的字符串:'*' 或 'zhaogb-201' ''' if tgt == '*': params = {'client': 'local', 'tgt': tgt, 'fun': fun, 'arg': arg} else: params = {'client': 'local', 'tgt': tgt, 'fun': fun, 'arg': arg, 'expr_form': 'list'} obj = urllib.urlencode(params) content = self.postRequest(obj) result = content['return'][0] return result def allMinionKeys(self): ''' 返回所有Minion keys; 分别为 已接受、待接受、已拒绝; :return: [u'local', u'minions_rejected', u'minions_denied', u'minions_pre', u'minions'] ''' params = {'client': 'wheel', 'fun': 'key.list_all'} obj = urllib.urlencode(params) content = self.postRequest(obj) minions = content['return'][0]['data']['return']['minions'] minions_pre = content['return'][0]['data']['return']['minions_pre'] minions_rej = content['return'][0]['data']['return']['minions_rejected'] # return minions, minions_pre, minions_rej return minions def actionKyes(self, keystrings, action): ''' 对Minion keys 进行指定处理; :param keystrings: 将要处理的minion id字符串; :param action: 将要进行的处理,如接受、拒绝、删除; :return: {"return": [{"tag": "salt/wheel/20160322171740805129", "data": {"jid": "20160322171740805129", "return": {}, "success": true, "_stamp": "2016-03-22T09:17:40.899757", "tag": "salt/wheel/20160322171740805129", "user": "zhaogb", "fun": "wheel.key.delete"}}]} ''' func = 'key.' + action params = {'client': 'wheel', 'fun': func, 'match': keystrings} obj = urllib.urlencode(params) content = self.postRequest(obj) ret = content['return'][0]['data']['success'] return ret def acceptKeys(self, keystrings): ''' 接受Minion发过来的key; :return: ''' params = {'client': 'wheel', 'fun': 'key.accept', 'match': keystrings} obj = urllib.urlencode(params) content = self.postRequest(obj) ret = content['return'][0]['data']['success'] return ret def deleteKeys(self, keystrings): ''' 删除Minion keys; :param node_name: :return: ''' params = {'client': 'wheel', 'fun': 'key.delete', 'match': keystrings} obj = urllib.urlencode(params) content = self.postRequest(obj) ret = content['return'][0]['data']['success'] return ret3)、views.py
# -*- coding: utf-8 -*-from __future__ import unicode_literalsfrom django.shortcuts import renderfrom django.shortcuts import HttpResponse,HttpResponseRedirect,render_to_responsefrom models import *from saltapi import salt_apifrom django.http import JsonResponseimport jsondef index(request): accect = [] context = accect_cmd.objects.values() for i in context: accect.append(i["command"]) if request.method == "POST": key = request.POST.get('key') cmd = request.POST.get('cmd') if cmd.split( )[0] in accect: spi = salt_api.SaltAPI('https://ip:8000', 'username', 'password') result2 = spi.masterToMinionContent(key, 'cmd.run', cmd) return JsonResponse(result2, safe=False) else: data = {key:"请检查命令是否正确或命令超权限,请联系管理员!"} return JsonResponse(data, safe=False) else: return render_to_response('index.html')4)、models.py
# -*- coding: utf-8 -*-from __future__ import unicode_literalsfrom django.db import models# Create your models here.class accect_cmd(models.Model): command = models.CharField(max_length=50, unique=True, verbose_name=u'命令') status = models.CharField(max_length=20, verbose_name=u'状态') def __unicode__(self): return u'{0} {1}'.format(self.command, self.status)class SaltReturns(models.Model): fun = models.CharField(max_length=50) jid = models.CharField(max_length=255) return_field = models.TextField(db_column='return') success = models.CharField(max_length=10) full_ret = models.TextField() alter_time = models.DateTimeField() class Meta: managed = False db_table = 'salt_returns' def __unicode__(self): return u'%s %s %s' % (self.jid, self.id, self.return_field)class record(models.Model): time = models.DateTimeField(u'时间', auto_now_add=True) comment = models.CharField(max_length=128, blank=True, default='', null=True, verbose_name=u"记录") def __unicode__(self): return u'%s %s' % (self.time, self.comment)5)、index.html
salt平台
五、效果
1)、单个key执行

2)、多个key执行
3)、当命令不被许可时:

六、总结
写的比较简陋,而且现在这个版本并不支持类似于192.168.1.1+,192.168.1.*这种正则匹配,后续会继续增加。
命令
结果
页面
utf-8
处理
代码
字符
字符串
方式
框架
检查
平台
简陋
危险
主机
人员
内容
前端
单个
参数
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
百单网互联网科技有限公司
互联网科技公司排名
华服互联网科技靠谱吗
广州紫鲸互联网科技有限公司
科技互联网产品
科技股互联网
科技创新与互联网经济
互联网是不是新科技
鸠鸠互联网科技
科技与互联网发展
致骋互联网科技
互联网科技排名
丰台科技园 互联网
科技互联网公司logo
互联网科技实习生岗位职责
威龙国际互联网科技公司
工业互联网山东科技大学
富国互联网金融科技混合基金
北京军民互联网科技公司
科技互联网专业工作会议发言稿
科技股互联网
互联网科技有限公司经营范围
互联网金融科技平台
长亮科技互联网金融
顶级互联网科技成果有哪些
武汉健翔互联网络科技有限公司
岳阳华臻互联网科技有限公司
互联网科技革命什么开始
互联网科技产业特征
深圳市优智互联网科技有限公司