Django+redis+websocket+ansible实现自动化发布,djangoredis


Django+redis+websocket+ansible实现自动化发布

之前已经发布过一个版本就是通过ajax的异步调用实现自动化发布 并将结果返回到web,但是这样有个缺点就是无法查看实时的过程,部署过程进行到什么地步了,并且报错的步骤是那一部分。所以我优化了下代码,使部署过程可视化的实时的显示在web端,我这里是使用redis作为中间件,当然你也可以选择mq作为中间件,都无所谓。

效果如图:当点击部署的时候会实时显示部署过程

首先是前端代码 我这里也只是写ajax调用部分,其余的自己考量

用于实时显示数据的ajax

<script src="http://code.jquery.com/jquery-1.11.1.min.js"></script>
<script type="text/javascript">//<![CDATA[
$(function () {
    $('#send_message').click(function () {   //点击id号send_message 触发事件
        $('#messagecontainer').html("");  //messagecontainer div id号用于显示数据
        var socket = new WebSocket("ws://" + window.location.host + "/echo_once/");

        socket.onopen = function () {
            console.log('WebSocket open');//成功连接上Websocket
        };
        socket.onmessage = function (e) {
            console.log('message: ' + e.data);//打印服务端返回的数据
            $('#messagecontainer').append('<p>' + e.data + '</p>');
        };
    });
});

//]]></script>
用于触发部署的异步ajax
$("#send_message").on('click',function(){
  $.ajax({
    url:"/Get_data",
    type:"POST",
    data:{
      hosts:$("#hosts").val(),
      software:$("#software").val()
    },
    success:function(data){  //以下是返回结果 当然可以选择不写
      var obj=JSON.parse(data)
      $('#dict_result').html(JSON.stringify(obj.result.success))  
      $('#dict_result1').html(JSON.stringify(obj.result.failed))
      $('#dict_result2').html(JSON.stringify(obj.result.unreachable))
      $('#loading').hide();
    }
  })
})
</script>

views部分:
Get_data负责执行ansible API接口
ansible负责渲染ansible部署页面
echo_once 负责实时输出结果
下面有一大部分是前面讲过的 这里就不提了,主要是echo_once 函数我这里提一下
funredis 模块:
import redis
class RedisHelper:

    def __init__(self):
        self.__conn = redis.Redis(host='127.0.0.1')
        self.chan_sub = 'ansible'
        self.chan_pub = 'ansible'

    def public(self, msg):
        self.__conn.publish(self.chan_pub, msg)
        return True

    def subscribe(self):
        pub = self.__conn.pubsub()
        pub.subscribe(self.chan_sub)
        pub.parse_response()
        return pub
def Get_data(request):
    import os,re
    from itertools import islice
#    ip = request.POST('ip')
    ip=str(request.POST.getlist('hosts'))

    software=request.POST.getlist('software')
    os.system('chmod 600 wls/static/gitlabilanni.gitlabilanni')
    License = 'wls/static/gitlabilanni.gitlabilanni'
    InventoryFile='wls/static/hosts'
    if ip != [] and software != []:
        installfile = 'wls/static/yaml/%s' % (software[0])
        a=ansinstall.MyRunner(InventoryFile,ip,installfile,License)
        result=a.Install()
        wo=a.get_result()
    else:
        wo=''
    return HttpResponse(json.dumps({
        'result':wo
    }))

def ansible(request):
    import os,re
    from itertools import islice

    InventoryFile='wls/static/hosts'
    f=open(InventoryFile)
    hosts=[]
    for line in f.readlines():
        if re.match(r'\[.*\]',line):
            pass
        else:
            hosts.append(line)
    f.close()
    softwares = []
    for root, dirs, files in os.walk('wls/static/yaml/'):
        for i in files:
            if  re.match(r'.*\.retry',i):
                pass
            else:
                softwares.append(i)
    return render(request, 'form/ansible.html', {
        'softwares':softwares,
        'hosts':hosts
    })
from . import funredis   #这个是我自己写的一个模块 上面提过
obj = funredis.RedisHelper() #以下是redis的订阅功能,不懂可以看下文档
redis_sub = obj.subscribe()
@require_websocket   #该装饰符功能:是下面连接只接受websocket 不接收http连接
def echo_once(request): #接收端
    while True: #循环取出数据到websocket 因为每次调用该接口都会执行while循环,并且不会结束,所以我做了判断在什么情况下结束该循环(PS:这里我想了很多方法都行不通,想了想就这个比较合适,所以我这里先用这个) 
        msg = redis_sub.parse_response()   
        if msg[2] == b'error' or msg[2] == b'pass' or msg[2] == b'end':
            request.websocket.send(msg[2])
            print('stop')
            break
        else:
            request.websocket.send(msg[2])
生产者:
from . import funredis

def pro(res_obj):
    STD = ['stdout', 'stderr', 'msg']
    res=res_obj._result 获取ansible的结果

    info = ""
    if type(res) == type(dict()):
        for field in STD:
            if field in res.keys() and len(res[field]) > 0:
                info = u'{0}:{1}'.format(field, res[field])
    log_info = u'{0}: {1}\n{2}'.format(res_obj._host, res_obj._task, info) #获取host名 task名 以及info信息
    errornum=''
    if str(res_obj._task)=='TASK: end':
        log_info = u'end'
    if res['rc'] !=0:
        errornum=u'error'
    if res['rc'] =='':
        errornum=u'pass'
    obj = funredis.RedisHelper()
    if errornum !='':
        obj.public(errornum)
    else:
        obj.public(log_info)
下面是可选项 我用来生成日志文件的地方:
loader = DataLoader()
FIELDS = ['cmd', 'command', 'start', 'end', 'delta', 'msg', 'stdout', 'stderr']
STD = ['stdout', 'stderr', 'msg']
logger = logging.getLogger('ansible')
fh = logging.FileHandler('/var/log/ansible.log')
logger.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(message)s')
fh.setFormatter(formatter)
logger.addHandler(fh)
def ansible_log(res_obj):
    res=res_obj._result
    info = ""
    if type(res) == type(dict()):
        for field in STD:
            if field in res.keys() and len(res[field]) > 0:
                info = u'{0}:{1}'.format(field, res[field])
    log_info = u'{0}: {1} {2}'.format(res_obj._host, res_obj._task, info)
    print(log_info)
    logger.info(log_info)
日志文件大概是这个样子的:

相关内容

    暂无相关文章