使用salt-api来搭建salt自动化平台
一、介紹
? ? 通常使用saltstack都是在master的服務(wù)器上直接命令操作,這個(gè)對(duì)于運(yùn)維人員來說不是什么大事,但是也會(huì)有出錯(cuò)的時(shí)候,而一旦出錯(cuò),就會(huì)有不可挽回的后果。
二、框架
? ? 這里使用django框架,通過對(duì)salt-api的封裝,傳入命令,執(zhí)行api,將結(jié)果返回到頁面上顯示。注意:為了防止誤操作,我們對(duì)傳入的命令進(jìn)行了檢查,所有被定義的危險(xiǎn)命令將不會(huì)被執(zhí)行。(我這里為了簡(jiǎn)單,所以定義了可以被執(zhí)行的命令。),前端使用了jquery+ajax的方式來不刷新頁面就將結(jié)果顯示在頁面上的方式。
三、salt-api的安裝
? ? 網(wǎng)上教程很多,我這里就不再?gòu)U話了。
四、django代碼
? ?1)、整體結(jié)構(gòu)
? ??????
??? 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,返回的結(jié)果是內(nèi)容,不是jid; ????????目標(biāo)參數(shù)tgt是一個(gè)如下格式的字符串:'*'?或?'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): ?????''' ?????對(duì)Minion?keys?進(jìn)行指定處理; ????:param?keystrings:?將要處理的minion?id字符串; ?????:param?action:?將要進(jìn)行的處理,如接受、拒絕、刪除; ?????: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發(fā)過來的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?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:"請(qǐng)檢查命令是否正確或命令超權(quán)限,請(qǐng)聯(lián)系管理員!"} ??????????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'狀態(tài)') ????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'時(shí)間',?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平臺(tái)</title> ??<script?src="/static/jquery-2.1.1.min.js"></script> </head> <body> <form?action="/salt/index/"?method="POST"?id="form"> <div>主機(jī):<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">執(zhí)行</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)、單個(gè)key執(zhí)行
? ? ?
?? 2)、多個(gè)key執(zhí)行
??
? ?3)、當(dāng)命令不被許可時(shí):
六、總結(jié)
寫的比較簡(jiǎn)陋,而且現(xiàn)在這個(gè)版本并不支持類似于192.168.1.1+,192.168.1.*這種正則匹配,后續(xù)會(huì)繼續(xù)增加。
本文轉(zhuǎn)自 sykmiao 51CTO博客,原文鏈接:http://blog.51cto.com/syklinux/1981943,如需轉(zhuǎn)載請(qǐng)自行聯(lián)系原作者
總結(jié)
以上是生活随笔為你收集整理的使用salt-api来搭建salt自动化平台的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 正则相关说明
- 下一篇: JS设置浏览器URL,任意定制,安全可靠