First, Introduction
Usually the use of Saltstack is in the master's server directly command operation, this is not a major event for operators, but there will be errors, and once the error, there will be irreversible consequences.
Second, the framework
The Django framework is used here, through the encapsulation of Salt-api, by passing in commands, executing the API, and returning the results to the page display. Note: In order to prevent misoperation, we have checked the incoming command and all defined dangerous commands will not be executed. (I'm here for simplicity, so I define a command that can be executed.) ), the front end uses a jquery+ajax way to display the results on the page without refreshing the page.
Third, the installation of SALT-API
There are a lot of tutorials online, I don't have any nonsense here.
Iv. Django Code
1), the overall structure
650) this.width=650; "title=" 2.png "alt=" 92d5cb02ff19097972c6a09fe3c6e7ea.png "src=" https://s3.51cto.com/oss/ 201711/15/92d5cb02ff19097972c6a09fe3c6e7ea.png "/>
2), salt_api.py (refer to the Dzhops code on GitHub)
# -*- 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}     &NBSp;req = urllib2. Request (url, obj, headers) opener = urllib2.urlopen (req ) content = json.loads (Opener.read ()) return content def mastertominioncontent (Self, tgt, fun, arg): ' master control Minion, the returned result is the content , not the jid; target parameter TGT is a string in the following format: ' * ' or ' 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): " return all minion keys; to accepted, accepted, rejected; :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 for the designated processing; : param keystrings: the Minion id string that will be processed; :p aram action: The processing to be carried out, such as acceptance, refusal, deletion; :return: {"return": [{"Tag": "salt/wheel/20160322171740805129", "Data": {"Jid": "20160322171740805129", "return": {}, "Success": true,&nbsP; " _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): " accept Minion's 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): " Delete minion keys; :p aram 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_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: "Please check whether the command is correct or the command is hyper-privileged, Please contact the Administrator! "} 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 ' command ') status = Models. Charfield (max_length=20, verbose_name=u ' state ') 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 ' time ', auto_now_add=true) comment = models. Charfield (max_length=128, blank=true, default= ", null=true, verbose_name=u" records ") def __unicode__ (self): return u '%s %s ' % (self.time, self.comment)
5), index.html
<! Doctype html>Five, the effect
1), single key execution
650) this.width=650; "title=" 3.png "src=" Https://s4.51cto.com/oss/201711/15/b00370281eeb3e02f9dec5550f58ddfa.png " alt= "B00370281eeb3e02f9dec5550f58ddfa.png"/>
2), multiple key execution
650) this.width=650; "title=" 4.png "style=" Float:none; "src=" https://s1.51cto.com/oss/201711/15/ Bfd4459cc59293d3241aca01ec7c23df.png "alt=" Bfd4459cc59293d3241aca01ec7c23df.png "/>
3), when the command is not permitted:
650) this.width=650; "title=" 5.png "style=" Float:none; "src=" https://s1.51cto.com/oss/201711/15/ D0739d9709be059332ae66d14187ec98.png "alt=" D0739d9709be059332ae66d14187ec98.png "/>
Vi. Summary
It is relatively simple to write, and now this version does not support a regular match similar to 192.168.1.1+,192.168.1.*, and subsequent additions will continue.
This article from the "Linux" blog, reproduced please contact the author!
Use SALT-API to build salt automation platform