美文网首页
django 结合ansible api安装常用服务

django 结合ansible api安装常用服务

作者: 梦想做小猿 | 来源:发表于2017-11-08 18:15 被阅读0次

    说明

    工作中经常遇到添加一批机器需要安装软件。云环境没有kickstart之类的自动装机初始化的工具,需要我们手动安装。有人会说可以用ansible、salt之类的工具,但是我们把机器加入我们资产平台后,又要去ansible或salt中去配置主机信息。同样的事情做了2次,这不是做运维该干的事。于是写一个平台,ansible从资产平台中获取机器信息,然后调用api安装服务,局部效果如下:

    ansible_install.png

    代码

    以下代码是测试环境该功能的局部代码

    前端代码

    <html>
        <head>
            <link href="/static/css/bootstrap.min.css" rel="stylesheet">
            <link href="/static/css/select2.min.css" rel="stylesheet">
        </head>
    
        <body>
            <form class="form-horizontal nice-validator n-yellow">
                <div class="form-group">
                    <label class="col-sm-3 control-label">选择主机:</label>
                    <div class="col-sm-4">
                        <select id="hostlist" class="selectpicker show-tick form-control" multiple="multiple" data-live-search="false">
                            {% for hosts in object_list %}
                            <option value={{ hosts.id }}>{{ hosts.hostname }}<{{ hosts.ip }}></option>
                            {% endfor %}     
                        </select>    
                    </div>    
                </div>
    
                <div class="form-group">
                    <label class="col-sm-3 control-label">选择服务:</label>
                    <div class="col-sm-4">
                        <select id="applist" class="selectpicker show-tick form-control" multiple="multiple" data-live-search="false">
                            <option value=0>jdk</option>
                            <option value=1>nginx</option>
                            <option value=2>zookeeper</option>
                        </select>    
                    </div>    
                </div>
                
                <div class="form-group">
                    <div class="col-sm-4 col-sm-offset-4">
                        <button id="button_clean" class="btn btn-white" type="reset">取消</button>
                        <button id="submit_button" class="btn btn-primary">安装</button>
                    </div>
                </div>
            </form>    
    
    
            <script src="/static/js/jquery-3.2.1.min.js"></script>
            <script src="/static/js/bootstrap.min.js"></script>
            <script src="/static/js/select2.min.js"></script>
            <script>
                function select_fun(id){
                    $(id).select2({
                        placeholder: "请选择...",                   
                        page: 2
                    })
                }    
                select_fun("#hostlist");
                select_fun("#applist");
    
                $("#button_clean").click(function(){
                    $("select").val(null).trigger("change");
                })
    
                $("#submit_button").click(function(){
                    var hosts = $("#hostlist").val();
                    var apps = $("#applist").val();
                    //console.log({"host_list": hosts, "app_list": apps});
    
                    $.ajax({
                        type: "POST",
                           url: "/host/installapp/",
                           data: JSON.stringify({"hosts": hosts, "apps": apps}),
                           dataType: "json",
                           success: function(data){
                                console.log(data);
                           }
                    
                    })
                    return false
                })
            </script>
        </body>
    </html>
    

    为了方便,直接将服务列表写死在代码里,生产中应该和主机信息一样,从数据库获取然后在模板中渲染

    后端Django代码

    # -*- coding: utf-8 -*-
    
    from django.views.generic import ListView, TemplateView, View 
    from models import Hosts
    from django.http import JsonResponse
    import json
    from utils.ansible_api import Ansible_api
    # Create your views here.
    
    class InstallApp(ListView):
        template_name = "install_app.html"
        model = Hosts
    
    class InstallAppView(View):
        def post(self, request):
            app_list = json.loads(request.body).get("apps")
            host_list = json.loads(request.body).get("hosts")
    
            host_obj = Hosts.objects.filter(id__in=host_list).values("ip")
            ip_list = []
            for host in host_obj:
                ip_list.append(host.get("ip"))
    
            for app_id in app_list:
                if app_id == "0":
                    Ansible_api(ip_list).run_playbook(["/etc/ansible/roles/jdk.yml"])
                elif app_id == "1":
                    app_name = "nginx"
                elif app_id == "2":
                    app_name = "zookeeper"
    
            return JsonResponse({'test':'test'})
    

    2个类视图,一个是显示安装服务页面,一个处理ajax请求安装对应服务,因为前端直接在代码把服务信息写死,这里为了方便也在代码里写死,正确做法应该和主机信息一样从数据库里获取。

    ansible api 代码

    #!/usr/bin/python
    #coding=utf8
    
    import json
    from collections import namedtuple
    from ansible.parsing.dataloader import DataLoader
    from ansible.vars import VariableManager
    from ansible.inventory import Inventory
    from ansible.playbook.play import Play
    from ansible.executor.task_queue_manager import TaskQueueManager
    from ansible.executor.playbook_executor import PlaybookExecutor
    from ansible.plugins.callback import CallbackBase
    
    class Ansible_api:
        def __init__(self, hosts):
            self.loader = DataLoader()
            self.variable_manager = VariableManager()
            self.inventory = Inventory(loader=self.loader, variable_manager=self.variable_manager, host_list=hosts)
            self.variable_manager.set_inventory(self.inventory)
            Options = namedtuple("Options",['connection', 'forks', 'check', 'module_path', 'passwords', 'become', 'become_method', 'become_user', 'listhosts', 'listtasks', 'listtags', 'syntax'])
            self.options = Options(connection="smart", forks=5, check=False, module_path=None, passwords=None, become=None, become_method=None, become_user=None, listhosts=None, listtasks=None, listtags=None, syntax=None)
    
        def run_adhoc(self, module, args=""):
            play_source = {
                "name": "ansible api run_adhoc",
                "hosts": "all",
                "gather_facts": "no",
                "tasks": [
                    {"action":{"module": module, "args": args}}
                ]
            }
    
            play = Play().load(play_source, variable_manager=self.variable_manager, loader=self.loader)
            tqm = None
            try:
                tqm = TaskQueueManager(
                    inventory = self.inventory,
                    variable_manager = self.variable_manager,
                    loader = self.loader,
                    options = self.options,
                    passwords = None,
                    stdout_callback = "minimal",
                )
           
                result = tqm.run(play)
                print result
            finally:
                if tqm is not None: 
                    tqm.cleanup()
    
        def run_playbook(self, yaml_file_list):
            # 这里extra_vars作用是为playbook yml文件传变量
            #self.variable_manager.extra_vars = {"host": host}
            pb = PlaybookExecutor(
                playbooks=yaml_file_list,
                inventory=self.inventory,
                variable_manager=self.variable_manager,
                loader=self.loader,
                passwords = None,
                options=self.options
            )
            result = pb.run()
            print result
    
    if __name__ == "__main__":
        ansible_api = Ansible_api(["192.168.111.128"])
        #ansible_api.run_adhoc("ping")
        #ansible_api.run_adhoc("shell", "cat /etc/redhat-release")
        ansible_api.run_playbook(["/etc/ansible/roles/jdk.yml"])
    

    这里用的ansible api 2.3.0的版本,最新的api 2.4和2.3有区别,坑了我半天。

    最后声明:这里只是测试代码,主要是提供思路,要改进调整的地方还有很多,比如ansible安装信息返回给前端、前端显示安装进度、ansible playbook相关信息记录到数据库、权限控制等等。

    ansible api 运行模块可以将输出返回给Django,而运行playbook则默认只有标准输出,无法捕获到运行结果,可以参考这个项目对callback重写: https://github.com/welliamcao/OpsManage

    相关文章

      网友评论

          本文标题:django 结合ansible api安装常用服务

          本文链接:https://www.haomeiwen.com/subject/tedymxtx.html