美文网首页运维驿站python自动化运维DevOPS
授之以渔-运维平台应用模块一(应用树篇)

授之以渔-运维平台应用模块一(应用树篇)

作者: 大Q的梦想 | 来源:发表于2018-02-09 17:18 被阅读556次

    写在片头:干的是运维工作,爱好动手。纯属个人项目,身兼业务需求人员,产品经理,前端,后端,测试于一体,代码层面会有逻辑问题,请各位看官见谅,下文只是记录我一个10手码农在前端踩过的坑和一些思路。

    应用树: 为了方便管理以业务为单位的服务集群,利用树形结构建立起了一种服务组织关系,方便运维日常管理。先上一张效果图:

    一、 Jstree

    看过XX公司的运维平台的应用树后,从此不能自拔,励志也要写出一样效果的东东。采用的jsTree,是基于javascript的一个跨浏览器树控件树行,功能强大,最重要的是免费,
    左侧的树列表的生成因为会用到mysql的group by,所以采用了redis存储,需要的时候才更新服务树,减少对数据库的压力,项目用到了根据选择树节点点击事件功能。
    既点击项目名称的红色图标时,会加载整个项目涉及到的服务器,效果图:

    image.png
    点击项目下单个主机时,会加载这个服务器的应用情况,效果图:
    image.png

    代码如下:

    ("changed.jstree", function (e, data) {
                    var items = data.node.text;
                    var icon = data.node.icon;
                    if (icon == "fa fa-building-o font-blue"){
                        document.getElementById("group1").style.display="none";
                        document.getElementById("group2").style.display="block";
                        $.ajax({
                            type: "GET",
                            url: "../cmdb_app_info_ajax/?ip="+items,
                            dataType:'json',
                            async: false,
                            beforeSend:function(){
                                Metronic.blockUI({animate: true});
                            },
                            complete: function() {
                                Metronic.unblockUI();
                            },
                            success: function(data){
                               var  sOut= '';
                                    sOut += '<tr>'
                                    sOut += '<td>' + data['设备PHP版本号:'] + '</td>';
                                    sOut += '<td>' + data['设备PHP路径:'] + '</td>';
                                    sOut += '<td>' + data['设备PHP端口号:'] + '</td>';
                                    sOut += '<tr>'
                                    sOut += '<th><b>TOMCAT版本号</b></th>';
                                    sOut += '<th><b>TOMCAT路径</b></th>';
                                    sOut += '<th><b>TOMCAT端口号</b></th>';
                                    sOut += '</tr>'
                                    sOut += '<td>' + data['设备TOMCAT版本号:'] + '</td>';
                                    sOut += '<td>' + data['设备TOMCAT路径:'] + '</td>';
                                    sOut += '<td>' + data['设备TOMCAT端口号:'] + '</td>';
                                    sOut += '<tr>'
                                    sOut += '<th><b>NGINX版本号</b></th>';
                                    sOut += '<th><b>NGINX路径</b></th>';
                                    sOut += '<th><b>NGINX端口号</b></th>';
                                    sOut += '</tr>'
                                    sOut += '<td>' + data['设备NGINX版本号:'] + '</td>';
                                    sOut += '<td>' + data['设备NGINX路径:'] + '</td>';
                                    sOut += '<td>' + data['设备NGINX端口号:'] + '</td>';
                                    sOut += '<tr>'
                                    sOut += '<th><b>MYSQL版本号</b></th>';
                                    sOut += '<th><b>MYSQL路径</b></th>';
                                    sOut += '<th><b>MYSQL端口号</b></th>';
                                    sOut += '<th><b>MYSQL数据库</b></th>';
                                    sOut += '</tr>'
                                    sOut += '<td>' + data['设备MYSQL版本号:'] + '</td>';
                                    sOut += '<td>' + data['设备MYSQL路径:'] + '</td>';
                                    sOut += '<td>' + data['设备MYSQL端口号:'] + '</td>';
                                    sOut += '<td>' + data['设备MYSQL数据库:'] + '</td>';
                                    sOut += '<tr>'
                                    sOut += '<th><b>定时任务</b></th>';
                                    sOut += '</tr>'
                                    sOut += '<td>' + data['设备定时任务:'] + '</td>';
                                    sOut += '</tr>'
    
                                $("#cmdb_app_info_get").html(sOut);
    
                                },
                            error: function (data) {
                                toastr.error('没有数据可以加载')
                            }
                        });
                    }else if (icon == "fa fa-folder icon-state-warning icon-lg"){
                        document.getElementById("group1").style.display="block";
                        document.getElementById("group2").style.display="none";
                        $.ajax({
                            type: "GET",
                            url: "../cmdb_subtitle_info_ajax/?subtitle="+items,
                            dataType:'json',
                            async: false,
                            beforeSend:function(){
                                Metronic.blockUI({animate: true});
                            },
                            complete: function() {
                                Metronic.unblockUI();
                            },
                            success: function(data){
                                if ($('#product_tree').hasClass('dataTable')) {
                                    console.log('重新加载datatable,准备初始化................')
                                    $('#product_tree').dataTable().fnClearTable(false) //清空一下table
                                    $('#product_tree').dataTable().fnDestroy();//还原初始化datatable
                                }
                                $("#cmdb_subtitle_info_get").html("");
                                $.each(data,function() {
                                var  sOut= '';
                                    sOut += '<tr>'
                                    sOut += '<td><input type="checkbox" class="checkboxes" value="1"/></td>'
                                    sOut += '<td id='+this['fields']['unit_title']+'>' + '<a href="../cmdb_assets_list/?place=&status=&year=&type=&model=&search='+ this['fields']['unit_ip'] +'">' + this['fields']['unit_title'] + '</a>' + '</td>';
                                    sOut += '<td>' + this['fields']['unit_subtitle'] + '</td>';
                                    sOut += '<td id='+this['fields']['unit_ip']+'>' + this['fields']['unit_ip'] + '</td>';
                                    sOut += '<td>' + this['fields']['unit_use_type'] + '</td>';                            
                                    sOut += '<td><a class="fa fa-eye" href="#responsives" data-toggle="modal"></a></td>';
                                    sOut += '</tr>'
                                    $("#cmdb_subtitle_info_get").append(sOut);
    
                                });
                            },
                            error: function (data) {
                                toastr.error('没有数据可以加载')
                            }
                        });
                    }
                    $(document).ready(function(){
                        eyeClick();
                        TableManaged.init() //初始化datatables
                    })
    
                }
    

    捡一些重要的说:

    var items = data.node.text;  //获取图标名称
    var icon = data.node.icon;  //获取图标
    

    我是通过判断图标的样式来获取用户点击的是哪里,没办法,谁叫咱是10手码农。同时有group1和gourp2两个tables,选择哪个图标就弹出哪个tables,隐藏另外的,在通过ajax后台获取数据,利用each循环获得的结果,构建出一个tr的内容,最后在添加到tables里,以此实现“山寨版”的数据加载。

    这里踩过的坑:

    因为我要先加载完数据,然后才是初始化datatables表格。当点击到别的业务图标时,又要经历一次加载数据,然后初始化表格。结果datatables报错了....cannot reinitialise datatable,大概意思就是datatables不能重复初始化。
    最后只能通过判断加载后的tables是否被加载后,如果加载过,先销毁,在初始化。

    if ($('#product_tree').hasClass('dataTable')) {
        console.log('重新加载datatable,准备初始化................')
        $('#product_tree').dataTable().fnClearTable(false) //清空一下table
        $('#product_tree').dataTable().fnDestroy();//还原初始化datatable
    }
    

    二、 Datatable

    右边就是数据展示采用datatables,可以将任何HTML表格添加高级的交互功能,这里用到了checkbox的单选和多选。
    datatables代码如下:

    var TableManaged = function () {
    
        var initTable2 = function () {
    
            var table = $('#product_tree');
            table.dataTable({
                "bDestroy": true,
                "language": {
                    "aria": {
                        "sortAscending": ": activate to sort column ascending",
                        "sortDescending": ": activate to sort column descending"
                    },
                    "emptyTable": "未有相关数据",
                    "info": "当前显示 _START_ 到 _END_ 条,共 _TOTAL_ 条记录。",
                    "infoEmpty": "当前显示0到0条,共0条记录",
                    "infoFiltered": "(数据库中共为 _MAX_ 条记录)",
                    "lengthMenu": "显示 _MENU_ 记录",
                    "search": "模糊查询:",
                    "zeroRecords": "对不起,查询不到任何相关数据",
                    "oPaginate": {
                        "sFirst": "首页",
                        "sPrevious": " 上一页 ",
                        "sNext": " 下一页 ",
                        "sLast": " 尾页 "
                    }
                },
    
                "bStateSave": true, // save datatable state(pagination, sort, etc) in cookie.
    
                "lengthMenu": [
                    [5, 15, 20, -1],
                    [5, 15, 20, "All"] // change per page values here
                ],
                // set the initial value
                "pageLength": 5,
    
                "columnDefs": [{  // set default column settings
                    'orderable': false,
                    'targets': [0]
                }, {
                    "searchable": false,
                    "targets": [0]
                }],
                "order": [
                    [1, "asc"]
                ] // set first column as a default sort by asc
            });
    
            var tableWrapper = jQuery('#product_tree_wrapper');
    
            var host_list = [];
            var release_build_job = '';
    
            //全选
            table.find('.group-checkable').change(function () {
                var set = jQuery(this).attr("data-set");
                var checked = jQuery(this).is(":checked");
                host_list.length = 0;
                jQuery(set).each(function () {
                    if (checked) {
                        $(this).attr("checked", true);
                        var hosts = $(this).parent().parent().find('td').eq(1).attr("id");
                        host_list.push(hosts);
                        document.getElementById("group3").style.display="block";
                    } else {
                        $(this).attr("checked", false);
                        host_list.length = 0;
                        document.getElementById("group3").style.display="none";
                    }
                });
                jQuery.uniform.update(set);
    
            });
    
    
            //单选
            table.on('change', 'tbody tr .checkboxes', function () {
                var hosts = $(this).parent().parent().find('td').eq(1).attr("id");
                var checked = jQuery(this).is(":checked");
                if (checked) {
                    $(this).attr("checked", true);
                    host_list.push(hosts);
                    if (host_list.length > 1) {
                        document.getElementById("group3").style.display="block";
                    }else {
                        document.getElementById("group3").style.display="none";
                    }
                } else {
                    $(this).attr("checked", false);
                    host_list.pop(hosts);
                    if (host_list.length > 1) {
                        document.getElementById("group3").style.display="block";
                    }else {
                        document.getElementById("group3").style.display="none";
                    }
                }
    
            });
    
            tableWrapper.find('.dataTables_length select').select2(); // initialize select2 dropdown
      
        return {
    
            //main function to initiate the module
            init: function () {
                if (!jQuery().dataTable) {
                    return;
                }
    
                initTable2();
            }
    
        };
    
    }();
    

    捡一些重要的说:

    if (host_list.length > 1) {
        document.getElementById("group3").style.display="block";
    }else {
        document.getElementById("group3").style.display="none";
    }
    

    判断了checkbox选择的数量,大于1个的话,弹出gourp3(一个批量绘图按钮),效果图如下:


    image.png

    三、 Multiselect

    接上文,这里平台是结合了openfalcon做的监控,点击上文的监控指标项按钮,会弹出一个multiselect层,用过openfalcon的都知道,监控指标多是他的特色之一,所以在选型的时候第一个就想到得需要一个带filter功能的select控件,效果图如下:

    image.png
    代码如下:
                $('#get_hostlist_counter_select').multiselect({
                        buttonWidth: '500px',//按钮宽度
                        nonSelectedText: '---- 请选择监控指标 ----',
                        nSelectedText: '个被选中',
                        enableCaseInsensitiveFiltering: true,//不区分大小写
                        filterPlaceholder: '模糊查询',
                        enableFiltering: true,
                        onDropdownShow: function(event) {
                            get_hostlist_counter()
                        },
                        onChange: function (option, checked, select) {
                            var selectedOptions = $('#get_hostlist_counter_select option:selected');
                            if (selectedOptions.length >= 6) {
                                // 禁用选项
                                toastr.error('监控指标最多同时选取6个')
                                var nonSelectedOptions = $('#get_hostlist_counter_select option').filter(function() {
                                return !$(this).is(':selected');
                                });
    
                                nonSelectedOptions.each(function() {
                                var input = $('input[value="' + $(this).val() + '"]');
                                input.prop('disabled', true);
                                input.parent('li').addClass('disabled');
                                });
                            }
                            else {
                                // 启动选项
                                $('#get_hostlist_counter_select option').each(function() {
                                var input = $('input[value="' + $(this).val() + '"]');
                                input.prop('disabled', false);
                                input.parent('li').addClass('disabled');
                                });
                            }
                        }
                });
    

    捡重要的说:
    用到了multiselectonDropdownShowonChange两个回调函数,onDropdownShow可以理解成就是点击菜单下拉事件,触发了get_hostlist_counter()通过ajax取数据填充options,代码如下:

            function get_hostlist_counter(){
                    var options_list = []
                    var obj2 = new Object();
                    var jsonData ={
                        'unit_title': host_list.join(','),
                    };
                    $("#get_hostlist_counter_select").empty();
    
                    $.ajax({
                        async: false,
                        type: "POST",
                        url : "../openfalcon_get_endpoint_counter_ajax/",
                        data: jsonData,
                        cache: false,
                        dataType: "json",
                        beforeSend:function(){
                            Metronic.blockUI({animate: true});
                        },
                        complete: function() {
                            Metronic.unblockUI();
                        },
                        success: function(obj) {
                            if (obj['counter'] == ''){
                                toastr.error('获取监控指标为空或者异常')
                            }else{
                                for (var id in obj['counter']){
                                        obj2 = {
                                              label : obj['counter'][id],
                                              value : obj['counter'][id],
                                          };
                                    options_list.push(obj2)
                                    }
                                $('#get_hostlist_counter_select').multiselect('dataprovider', options_list);
                                }
                                }
                            });
                }
    

    onChange可以理解成点击事件,监控指标这块还是怕传多了,压垮了openfalcongraph的,所以限制最多传6个,超过的话会禁用所有选项。

    四、 绘图

    最后就是一些绘图了,结合着openfalcon的API做的,下篇文章再议,效果图:

    image.png

    相关文章

      网友评论

      • 老肖:楼主 其实做的是个简易版的CMDB:+1:

      本文标题:授之以渔-运维平台应用模块一(应用树篇)

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