温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

使用salt-api来搭建salt自动化平台

发布时间:2020-08-06 10:29:03 来源:网络 阅读:1426 作者:syklinux 栏目:软件技术

一、介绍

    通常使用saltstack都是在master的服务器上直接命令操作,这个对于运维人员来说不是什么大事,但是也会有出错的时候,而一旦出错,就会有不可挽回的后果。

二、框架

    这里使用django框架,通过对salt-api的封装,传入命令,执行api,将结果返回到页面上显示。注意:为了防止误操作,我们对传入的命令进行了检查,所有被定义的危险命令将不会被执行。(我这里为了简单,所以定义了可以被执行的命令。),前端使用了jquery+ajax的方式来不刷新页面就将结果显示在页面上的方式。

三、salt-api的安装

    网上教程很多,我这里就不再废话了。

四、django代码

   1)、整体结构

        使用salt-api来搭建salt自动化平台


    2)、salt_api.py(这里参照了github上dzhops的代码)

# -*- coding: utf-8 -*- import urllib2, urllib, json import requests import json import ssl ssl._create_default_https_context = ssl._create_unverified_context class 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 ret

     3)、views.py

# -*- coding: utf-8 -*- from __future__ import unicode_literals from django.shortcuts import render from django.shortcuts import HttpResponse,HttpResponseRedirect,render_to_response from models import * from saltapi import salt_api from django.http import JsonResponse import json def 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_literals from 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

<!DOCTYPE html> <html lang="en"> <head>   <meta charset="UTF-8">   <title>salt平台</title>   <script src="/static/jquery-2.1.1.min.js"></script> </head> <body> <form action="/salt/index/" method="POST" id="form"> <div>主机:<input type="text" name="key" value="" id="a" ></div> <div>命令:<input type="text" name="cmd" value="" id="b" ></div> <div><button type="button" id="fb">执行</button></div> <div > <textarea type="text"  disabled="disabled" class="left" name="comment" id="c"></textarea> </div> </form> </body> <script>   $("#fb").click(function () {       $.post("/salt/index/",{         key:$("#a").val(),         cmd: $("#b").val(),       },       function (response,status,xhr) {         $("#c").html('')         $.each(response,function (key,val) {         var c = "\r\n"+key+ ":\r\n" + val;         $("#c").append(c);       })      }      )     }) </script> </html>

五、效果

   1)、单个key执行

     

使用salt-api来搭建salt自动化平台

   2)、多个key执行

  

使用salt-api来搭建salt自动化平台

   3)、当命令不被许可时:

使用salt-api来搭建salt自动化平台

六、总结

写的比较简陋,而且现在这个版本并不支持类似于192.168.1.1+,192.168.1.*这种正则匹配,后续会继续增加。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI