一、介绍

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

二、框架

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

三、salt-api的安装

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

四、django代码

1)、整体结构

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# -*- 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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# -*- 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 in context:
      accect.append(i["command"])
  if request.method == "POST":
      key = request.POST.get('key')
      cmd = request.POST.get('cmd')
      if cmd.split( )[0in 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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# -*- 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.idself.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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<!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" style="width: 200px"></div>
<div>命令:<input type="text" name="cmd" value="" id="b" style="width: 200px"></div>
<div><button type="button" id="fb">执行</button></div>
<div style="height: 300px;margin-top: 15px;">
<textarea type="text" style="width: 60%;height: 300px" 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执行

2)、多个key执行

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

六、总结

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

本文转自 sykmiao 51CTO博客,原文链接:http://blog.51cto.com/syklinux/1981943,如需转载请自行联系原作者

使用salt-api来搭建salt自动化平台相关推荐

  1. 利用Node-js搭建前端自动化平台

    我们在前面< Node.js的本质 >一文中初步了解Node.js后,发现它功能很多呀,这么牛逼的东西赶紧学习.然而我一直翻看网上各种的教程,文档,都是什么学习node内核呀,API呀,n ...

  2. 使用 Railway 和 Supabase 零成本搭建 n8n 自动化平台

    在前文使用自动化工作流聚合信息摄入和输出中,我介绍了如何在 NAS 提供的 Docker 环境安装 n8n,以及 n8n workflow 的使用方式.经过 3 个月的使用,我有了一些新的体会和尝试, ...

  3. 第八届中国R语言会议(上海会场)精彩演讲视频 《借助API快速搭建自然语言处理平台》

    雪晴数据网 [演讲摘要] 如今,很多实验室和机构开放了自然语言处理方面的API.用户借助这些API,可以快速开发NLP方面的产品.NLPApiTools包将整合这些平台的计算资源,提供R语言的借口和扩 ...

  4. 构建MySQL自动化平台思路

    本人在日常工作中,用Python写了一个DB平台. 下面简单地嗦一嗦目前的主要思路和未来展望吧~ 目前主要功能支持: 下一个迭代版本: 高可用模块:打算使用(??和MGR),作者不想用MHA,无理由. ...

  5. 网课搜题API接口搭建教程

    网课搜题API接口搭建教程 本平台优点: 多题库查题.独立后台.响应速度快.全网平台可查.功能最全! 1.想要给自己的公众号获得查题接口,只需要两步! 2.题库: 查题校园题库:查题校园题库后台(点击 ...

  6. 搭建or部署接口自动化平台从零到一的过程

    接口自动化部署or搭建目录 前言 搭建 前端环境 后端环境 部署 部署环境 前端部署 后端部署 第一种方式后端部署 第二种方式后端部署 前言 首先感谢cheeath大佬的支持和帮助,自动化平台成功在服 ...

  7. 编写shell脚本实现自动化搭建安装LNMP平台全过程配置详解

    注意:如果是输入的是字母的或者是输入等于0时,则会出现以下两种情况!!! 查看端口: 进到Nginx根目录查看创建好的测试网页: 注意:关闭防火墙或者设置防火墙规则!!! 访问Nginx网页: 访问P ...

  8. 手把手教你搭建数据库服务器平台 | DBA VS 自动化运维,究竟谁与争锋?

    现代化的程度越高,对数据库的依赖性越大.数据安全性和系统的安全性也就越大,比如公司业务系统.数据库是直接的存储地方,宕机带来的损失可能是按分钟或者秒算的.而谁对这些数据库负责--DBA.所以很多公司, ...

  9. uni-app实战之社区交友APP(11)API环境搭建和登录API开发

    文章目录 前言 一.后端API环境搭建 1.后端线上环境部署 2.Postman安装使用 3.PyCharm和数据库管理 4.创建项目 5.数据库创建和配置 二.API开发准备 1.数据表设计 2.封 ...

  10. python测试开发自学教程-自动化平台测试开发:Python测试开发实战_PDF电子书

    因资源下载地址容易失效,请加微信号359049049直接领取,直接发最新下载地址. 前言 ======================================================= ...

最新文章

  1. 【跃迁之路】【552天】程序员高效学习方法论探索系列(实验阶段309-2018.08.11)...
  2. python判断括号有效,在Python中检查括号是否平衡
  3. 求封闭曲线面积vc代码_圆锥曲线综合5个类型,逐一突破
  4. python中RabbitMQ的使用(路由键模糊匹配)
  5. EntityFramework Core自动返回SQL语句
  6. firefox 和 ie 事件处理的细节,研究,再研究-----书写同时兼容ie和ff的事件处理代码...
  7. yii2 html编辑器,浅析Yii2集成富文本编辑器redactor实例教程
  8. 程序中使用log4J打印信息的两种方式
  9. List的ToLookup 分组方法
  10. 升级到Firefox 3.0后解决扩展版本不兼容的方法
  11. 将编译器的代码快速转存为图片
  12. import sys
  13. java——获取网页源代码
  14. <!DOCTYPE>解读
  15. MOSFET开关管的结构以及在MATLAB中的连接
  16. KS检验、qq图、Scalability可扩展性
  17. PHP程序员需要注意的代码规范PSR有哪些?
  18. Joy Catalog
  19. OpenGL ES之三——绘制纯色背景
  20. 平面设计师都在用的素材网站(素材灵感一步到位)

热门文章

  1. 2 datax mysql 和 mysql之间相互导入
  2. 十三: 悲观锁乐观锁:解决丢失更新问题
  3. NCBI SRA数据库使用详解
  4. node执行cmd命令方法
  5. tesseract 4.0 编译安装(CentOS)
  6. java-------------华为-----------字符串链接最长路径查询
  7. 【Java】Calendar获取年、月、日、时间
  8. codility上的问题(26) Hydrogenium 2013
  9. LPTSTR、LPCSTR、LPCTSTR、LPSTR的含义
  10. 超全机器学习术语词汇表