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

简介:

一、介绍

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

二、框架

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

三、salt-api的安装

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

四、django代码

   1)、整体结构

        92d5cb02ff19097972c6a09fe3c6e7ea.png


    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( )[ 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

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 . 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

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执行

     

b00370281eeb3e02f9dec5550f58ddfa.png

   2)、多个key执行

  

bfd4459cc59293d3241aca01ec7c23df.png

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

d0739d9709be059332ae66d14187ec98.png

六、总结

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



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

相关文章
|
2月前
|
资源调度 测试技术 Linux
一款接口自动化神器—开源接口测试平台Lim(Less is More)
一款接口自动化神器—开源接口测试平台Lim(Less is More)
126 2
|
2月前
|
JSON 关系型数据库 测试技术
Eolink神技之五、API自动化——定时任务
Eolink神技之五、API自动化——定时任务
44 0
|
3月前
|
前端开发 测试技术 API
UI自动化与API自动化已经开始互斥了吗?
UI自动化与API自动化已经开始互斥了吗?
|
3月前
|
Go 数据处理 Docker
elk stack部署自动化日志收集分析平台
elk stack部署自动化日志收集分析平台
79 0
|
5月前
|
供应链 搜索推荐 数据挖掘
淘宝详情API接口:实现营销自动化的黄金通道
在当今的数字化时代,电子商务正在迅速发展,其中淘宝作为中国最大的电商平台之一,拥有着巨大的用户群体和丰富的商品资源。对于许多卖家来说,如何在这个巨大的市场中脱颖而出,营销策略是至关重要的。而淘宝详情API接口则为卖家提供了一个实现营销自动化的黄金通道。
|
4月前
|
敏捷开发 API
【sgCreateAPI】自定义小工具:敏捷开发→自动化生成API接口脚本(接口代码生成工具)
【sgCreateAPI】自定义小工具:敏捷开发→自动化生成API接口脚本(接口代码生成工具)
|
7月前
|
SQL 监控 搜索推荐
自动化测试平台V1.0版本正式上线啦!
自动化测试平台V1.0版本正式上线啦!
137 0
|
1月前
|
JSON 测试技术 API
Postman Newman 实现 API 自动化测试的快速指南
Newman 是一款专为 Postman 打造的命令行工具,旨在通过自动运行 Postman 集合和环境,实现 API 测试的自动化。它使得开发者无需打开 Postman 图形界面,即可直接在命令行中执行测试用例。
|
2月前
|
数据采集 数据挖掘 API
通过API接口实现自动化数据同步
在当今数字化的世界中,API(应用程序编程接口)作为数据交换的桥梁,对于电商企业来说尤为重要。它们允许企业从丰富的数据源中提取必要的信息,为商业决策提供数据支持。本文将围绕如何高效地利用API进行数据采集展开讨论,并提供一些实用的代码示例。
|
7月前
|
JSON 测试技术 API
深聊性能测试,从入门到放弃之:Locust性能自动化(五)API汇总整理(下)
深聊性能测试,从入门到放弃之:Locust性能自动化(五)API汇总整理(下)
87 0

热门文章

最新文章