使用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,如需转载请自行联系原作者

相关文章
|
3月前
|
机器学习/深度学习 人工智能 供应链
唯品会 API 赋能,唯品会平台母婴商品用户需求洞察
在电商竞争激烈的环境下,唯品会作为中国领先品牌折扣平台,母婴类目正快速增长。通过开放API赋能,平台实现对母婴用户需求的深度洞察,涵盖数据整合、智能分析与个性化推荐。本文解析API如何驱动需求预测、情感分析与用户细分,助力平台提升运营效率与用户满意度,展望未来结合AI技术的潜力。
128 2
|
3月前
|
数据采集 人工智能 监控
唯品会 API 助力,唯品会平台美妆商品营销效果评估
在电商竞争激烈的环境下,唯品会作为领先特卖平台,其美妆品类的营销效果评估至关重要。通过唯品会 API,商家可实时获取商品、销售及用户行为数据,精准计算 ROI、转化率等关键指标,实现数据驱动的营销优化。本文介绍 API 的应用方法,并结合案例说明如何提升营销效率与销售表现。
134 0
|
4月前
|
人工智能 安全 小程序
面向开发者的API平台设计与选型建议【附源码示例】
在软件开发日益模块化的今天,API平台作为连接技术与应用的枢纽,正重塑产品开发方式。它聚合各类能力接口,如支付、AI绘图、图像识别等,助力开发者高效构建系统。本文详解API平台定义、优势、应用场景及选型指南,揭示其如何降低门槛、加速创新,并展望其未来发展趋势。
|
2月前
|
API 调度 虚拟化
VMware Cloud Foundation Automation 9.0.1.0 发布 - 私有云自动化平台
VMware Cloud Foundation Automation 9.0.1.0 发布 - 私有云自动化平台
194 3
VMware Cloud Foundation Automation 9.0.1.0 发布 - 私有云自动化平台
|
3月前
|
缓存 运维 监控
API 别乱跑:自动化运维里的流量管理秘籍
API 别乱跑:自动化运维里的流量管理秘籍
201 9
|
3月前
|
人工智能 数据可视化 测试技术
AI 时代 API 自动化测试实战:Postman 断言的核心技巧与实战应用
AI 时代 API 自动化测试实战:Postman 断言的核心技巧与实战应用
536 11
|
3月前
|
JSON 搜索推荐 API
唯品会 API 接口:唯品会平台促销活动订单转化率提升
在电商中,促销活动是提升销量的重要手段。唯品会作为领先的品牌折扣平台,通过限时抢购、优惠券等方式吸引用户,但如何提升订单转化率仍是关键挑战。本文分析了用户决策延迟、信息不对称、个性化不足等问题,并介绍如何利用唯品会 API 接口实现数据驱动优化。通过实时数据同步、个性化推荐和自动化处理,API 可帮助开发者提升转化率,案例显示优化后转化率平均提升 20%-30%。同时,自动化流程降低了运营成本,增强了用户体验。集成唯品会 API,是实现高效促销、提升用户粘性的重要路径。
154 3
|
4月前
|
数据挖掘 API 数据安全/隐私保护
小红书电商 API 接口:小红书平台电商活动话题热度监测
小红书作为领先社交电商平台,通过API接口实现电商话题热度监测,助力品牌实时掌握用户兴趣与互动趋势,提升运营效率与营销精准度。
266 1
|
4月前
|
数据采集 监控 搜索推荐
小红书电商 API 助力,小红书平台电商笔记营销效果量化
在数字化营销时代,小红书凭借用户生成内容推动电商转化,但营销效果常因数据碎片化难以衡量。本文探讨如何借助小红书电商 API,精准量化曝光量、点击率、转化率等关键指标,提升营销效率与投资回报率。
151 1
|
4月前
|
人工智能 JSON 算法
抖音电商 API 赋能,抖音平台达人合作数据精准对接
抖音电商API为品牌与达人合作提供精准数据对接,提升匹配效率与营销精准度,助力电商生态智能化升级。
338 1

热门文章

最新文章