Browse Source

实现删除 vlan 功能

James Iter 7 years ago
parent
commit
d3dcafd7e8

+ 102 - 11
jimvc/api/vlan.py

@@ -2,7 +2,8 @@
 # -*- coding: utf-8 -*-
 
 
-from flask import Blueprint, request
+import requests
+from flask import Blueprint, request, url_for
 import json
 import jimit as ji
 
@@ -138,29 +139,117 @@ def r_update(ids):
 
 @Utils.dumps2response
 def r_get(ids):
-    return vlan_base.get(ids=ids, ids_rule=Rules.IDS.value, by_field='id')
+    ret = vlan_base.get(ids=ids, ids_rule=Rules.IDS.value, by_field='id')
+
+    if '200' != ret['state']['code']:
+        return ret
+
+    hosts_url = url_for('api_hosts.r_get_by_filter', _external=True)
+    hosts_ret = requests.get(url=hosts_url, cookies=request.cookies)
+    hosts_ret = json.loads(hosts_ret.content)
+
+    hosts_mapping_by_vlan_bridge = dict()
+    for vlan in ret['data']:
+        vlan_bridge_name = 'vlan' + vlan['vlan_id'].__str__()
+        vlan_bond_name = 'bond0.' + vlan['vlan_id'].__str__()
+
+        if vlan_bridge_name not in hosts_mapping_by_vlan_bridge:
+            hosts_mapping_by_vlan_bridge[vlan_bridge_name] = list()
+
+        for host in hosts_ret['data']:
+            if vlan_bridge_name in host['vlans'] and vlan_bond_name in host['vlans']:
+                hosts_mapping_by_vlan_bridge[vlan_bridge_name].append(host)
+
+    hosts = hosts_ret['data']
+    posts = hosts.__len__()
+
+    for i, vlan in enumerate(ret['data']):
+        vlan_bridge_name = 'vlan' + vlan['vlan_id'].__str__()
+        ret['data'][i]['posts'] = posts
+        ret['data'][i]['arrival'] = hosts_mapping_by_vlan_bridge[vlan_bridge_name].__len__()
+
+    return ret
 
 
 @Utils.dumps2response
 def r_get_by_filter():
-    return vlan_base.get_by_filter()
+    ret = vlan_base.get_by_filter()
+    if '200' != ret['state']['code']:
+        return ret
+
+    hosts_url = url_for('api_hosts.r_get_by_filter', _external=True)
+    hosts_ret = requests.get(url=hosts_url, cookies=request.cookies)
+    hosts_ret = json.loads(hosts_ret.content)
+
+    hosts_mapping_by_vlan_bridge = dict()
+    for vlan in ret['data']:
+        vlan_bridge_name = 'vlan' + vlan['vlan_id'].__str__()
+        vlan_bond_name = 'bond0.' + vlan['vlan_id'].__str__()
+
+        if vlan_bridge_name not in hosts_mapping_by_vlan_bridge:
+            hosts_mapping_by_vlan_bridge[vlan_bridge_name] = list()
+
+        for host in hosts_ret['data']:
+            if vlan_bridge_name in host['vlans'] and vlan_bond_name in host['vlans']:
+                hosts_mapping_by_vlan_bridge[vlan_bridge_name].append(host)
+
+    hosts = hosts_ret['data']
+    posts = hosts.__len__()
+
+    for i, vlan in enumerate(ret['data']):
+        vlan_bridge_name = 'vlan' + vlan['vlan_id'].__str__()
+        ret['data'][i]['posts'] = posts
+        ret['data'][i]['arrival'] = hosts_mapping_by_vlan_bridge[vlan_bridge_name].__len__()
+
+    return ret
 
 
 @Utils.dumps2response
 def r_content_search():
-    return vlan_base.content_search()
+    ret = vlan_base.content_search()
+
+    if '200' != ret['state']['code']:
+        return ret
+
+    hosts_url = url_for('api_hosts.r_get_by_filter', _external=True)
+    hosts_ret = requests.get(url=hosts_url, cookies=request.cookies)
+    hosts_ret = json.loads(hosts_ret.content)
+
+    hosts_mapping_by_vlan_bridge = dict()
+    for vlan in ret['data']:
+        vlan_bridge_name = 'vlan' + vlan['vlan_id'].__str__()
+        vlan_bond_name = 'bond0.' + vlan['vlan_id'].__str__()
+
+        if vlan_bridge_name not in hosts_mapping_by_vlan_bridge:
+            hosts_mapping_by_vlan_bridge[vlan_bridge_name] = list()
+
+        for host in hosts_ret['data']:
+            if vlan_bridge_name in host['vlans'] and vlan_bond_name in host['vlans']:
+                hosts_mapping_by_vlan_bridge[vlan_bridge_name].append(host)
+
+    hosts = hosts_ret['data']
+    posts = hosts.__len__()
+
+    for i, vlan in enumerate(ret['data']):
+        vlan_bridge_name = 'vlan' + vlan['vlan_id'].__str__()
+        ret['data'][i]['posts'] = posts
+        ret['data'][i]['arrival'] = hosts_mapping_by_vlan_bridge[vlan_bridge_name].__len__()
+
+    return ret
 
 
 @Utils.dumps2response
 def r_delete(ids):
+    ret = dict()
+    ret['state'] = ji.Common.exchange_state(20000)
+
     args_rules = [
         Rules.IDS.value
     ]
 
-    request.json['ids'] = ids
-
     try:
-        ji.Check.previewing(args_rules, request.json)
+
+        ji.Check.previewing(args_rules, {'ids': ids})
 
         vlan = VLAN()
 
@@ -169,15 +258,15 @@ def r_delete(ids):
             vlan.id = _id
             vlan.get()
 
-            guests, _ = Guest.get_by_filter(filter_str=':'.join(['vlan_id', 'eq', vlan.vlan_id]))
+            guests, _ = Guest.get_by_filter(filter_str=':'.join(['vlan_id', 'eq', vlan.vlan_id.__str__()]))
 
+            # 检测 vlan 中是否存在 虚拟机,若存在,则拒绝删除操作。
             if guests.__len__() > 0:
 
                 guests_info = ''
                 for guest in guests:
                     guests_info += guest['label'] + ',' + guest['uuid'] + '.'
 
-                ret = dict()
                 ret['state'] = ji.Common.exchange_state(41262)
                 ret['state']['sub']['zh-cn'] = ''.join([
                     ret['state']['sub']['zh-cn'], u': Vlan ID: ', vlan.vlan_id, u': Guests: ', guests_info])
@@ -197,14 +286,16 @@ def r_delete(ids):
                     'uuid': None,
                     'node_id': host['node_id'],
                     'vlan_id': vlan.vlan_id,
-                    'passback_parameters': {'vlan_id': vlan.vlan_id}
+                    'passback_parameters': {'id': vlan.id, 'vlan_id': vlan.vlan_id}
                 }
 
                 Utils.emit_instruction(message=json.dumps(message, ensure_ascii=False))
 
+        return ret
+
     except ji.PreviewingError, e:
         return json.loads(e.message)
 
-    return vlan_base.delete(ids=ids, ids_rule=Rules.IDS.value, by_field='id')
+    # return vlan_base.delete(ids=ids, ids_rule=Rules.IDS.value, by_field='id')
 
 

+ 4 - 4
jimvc/models/__init__.py

@@ -132,14 +132,14 @@ from snapshot_disk_mapping import (
     SnapshotDiskMapping
 )
 
-from event_processor import (
-    EventProcessor
-)
-
 from vlan import (
     VLAN
 )
 
+from event_processor import (
+    EventProcessor
+)
+
 
 __author__ = 'James Iter'
 __date__ = '2017/3/21'

+ 24 - 0
jimvc/models/event_processor.py

@@ -19,6 +19,8 @@ from jimvc.models import ResponseState, GuestState, DiskState
 from jimvc.models import GuestMigrateInfo
 from jimvc.models import GuestCollectionPerformanceDataKind, HostCollectionPerformanceDataKind
 from jimvc.models import HostCPUMemory, HostTraffic, HostDiskUsageIO
+from jimvc.models import Host
+from jimvc.models import VLAN
 
 
 __author__ = 'James Iter'
@@ -33,6 +35,7 @@ class EventProcessor(object):
     guest = Guest()
     guest_migrate_info = GuestMigrateInfo()
     disk = Disk()
+    vlan = VLAN()
     snapshot = Snapshot()
     snapshot_disk_mapping = SnapshotDiskMapping()
     os_template_image = OSTemplateImage()
@@ -371,6 +374,27 @@ class EventProcessor(object):
                 else:
                     pass
 
+        elif _object == 'vlan':
+            if action == 'delete':
+                cls.vlan.id = cls.message['message']['passback_parameters']['id']
+                cls.vlan.get()
+
+                vlan_bridge_name = 'vlan' + cls.vlan.vlan_id.__str__()
+
+                if state == ResponseState.success.value:
+                    hosts = Host.get_all()
+
+                    for host in hosts:
+                        # 如果 vlan 网桥存在于任何一个 计算节点 中(包容离线的计算节点),则拒绝在数据库中删除该 vlan 信息。
+                        # 用户可通过强制删除,避开该逻辑。
+                        if vlan_bridge_name in host['vlans']:
+                            return
+
+                    cls.vlan.delete()
+
+                else:
+                    pass
+
         else:
             pass
 

+ 8 - 7
jimvc/models/host.py

@@ -3,7 +3,7 @@
 
 
 import json
-from flask import g
+import jimit as ji
 
 from jimvc.models import app_config
 from jimvc.models import Database as db
@@ -27,12 +27,13 @@ class Host(object):
         """
 
         coupler_length = 60
+        ts = ji.Common.ts()
 
         if 'timestamp' not in v:
             return v
 
         v['alive'] = False
-        if v['timestamp'] + coupler_length >= g.ts:
+        if v['timestamp'] + coupler_length >= ts:
             v['alive'] = True
 
         if 'threads_status' not in v:
@@ -55,23 +56,23 @@ class Host(object):
             }
 
         v['threads_status']['instruction_process_engine']['alive'] = False
-        if v['threads_status']['instruction_process_engine']['timestamp'] + coupler_length >= g.ts:
+        if v['threads_status']['instruction_process_engine']['timestamp'] + coupler_length >= ts:
             v['threads_status']['instruction_process_engine']['alive'] = True
 
         v['threads_status']['host_state_report_engine']['alive'] = False
-        if v['threads_status']['host_state_report_engine']['timestamp'] + coupler_length >= g.ts:
+        if v['threads_status']['host_state_report_engine']['timestamp'] + coupler_length >= ts:
             v['threads_status']['host_state_report_engine']['alive'] = True
 
         v['threads_status']['guest_creating_progress_report_engine']['alive'] = False
-        if v['threads_status']['guest_creating_progress_report_engine']['timestamp'] + coupler_length >= g.ts:
+        if v['threads_status']['guest_creating_progress_report_engine']['timestamp'] + coupler_length >= ts:
             v['threads_status']['guest_creating_progress_report_engine']['alive'] = True
 
         v['threads_status']['guest_performance_collection_engine']['alive'] = False
-        if v['threads_status']['guest_performance_collection_engine']['timestamp'] + coupler_length >= g.ts:
+        if v['threads_status']['guest_performance_collection_engine']['timestamp'] + coupler_length >= ts:
             v['threads_status']['guest_performance_collection_engine']['alive'] = True
 
         v['threads_status']['host_performance_collection_engine']['alive'] = False
-        if v['threads_status']['host_performance_collection_engine']['timestamp'] + coupler_length >= g.ts:
+        if v['threads_status']['host_performance_collection_engine']['timestamp'] + coupler_length >= ts:
             v['threads_status']['host_performance_collection_engine']['alive'] = True
 
         return v

+ 109 - 7
jimvc/themes/default/templates/config_show.html

@@ -760,6 +760,14 @@
             });
         }
 
+        function exchange_arrival_rate_for_tr(arrival, posts) {
+            if (arrival === posts) {
+                return '<span style="color: #00BB00;">' + '100%' + '</span>';
+            } else {
+                return '<span style="color: #BB0000;">' + arrival + '/' + posts + '</span>';
+            }
+        }
+
         function add_vlan() {
             $('#add_vlan_modal').modal('hide');
 
@@ -843,14 +851,28 @@
                             '               </a>\n' +
                             '       </div>\n' +
                             '    </td>\n' +
-                            '    <td class="text-center"><span style="color: #00BB00;">' + '100%' + '</span></td>\n' +
+                            '    <td class="text-center">' + exchange_arrival_rate_for_tr(v['arrival'], v['posts']) + '</td>\n' +
                             '    <td class="text-center">' + new Date(v['create_time'] / 1000).format('yy-mm-dd HH:MM:ss') + '</td>\n' +
                             '    <td class="text-center">\n' +
-                            '        <a href="javascript:;" style="color: indianred;" data-toggle="modal" data-target="#delete_modal"\n'+
-                            '           onclick="$(\'#os_template_image_id\').val($(this).parent().parent().parent().parent().parent().children()[0].textContent);\n'+
-                            '       $(\'#delete_instance_desc\').text($(this).parent().parent().parent().parent().parent().children()[2].textContent)">\n'+
-                            '            删除\n'+
-                            '        </a>\n'+
+                            '        <div class="dropdown inline-block">\n' +
+                            '            <a href="javascript:;" class="dropdown-toggle" data-toggle="dropdown">更多</a>\n' +
+                            '            <ul class="dropdown-menu">\n' +
+                            '                <li>\n' +
+                            '                    <a href="javascript:;" style="color: indianred;" data-toggle="modal" data-target="#vlan_delete_modal"\n'+
+                            '                       onclick="$(\'#vlan_index_id\').val($(this).parent().parent().parent().parent().parent().data(\'id\'));' +
+                            '                       $(\'#delete_vlan_instance_desc\').text(\'VLAN ID: \' + $(this).parent().parent().parent().parent().parent().data(\'id\') + \' / \' + $(this).parent().parent().parent().parent().parent().children()[0].textContent)">\n'+
+                            '                        删除\n'+
+                            '                    </a>\n'+
+                            '                </li>\n' +
+                            '                <li>\n' +
+                            '                    <a href="javascript:;" style="color: indianred;" data-toggle="modal" data-target="#delete_modal"\n'+
+                            '                       onclick="$(\'#os_template_image_id\').val($(this).parent().parent().parent().parent().parent().children()[0].textContent);\n'+
+                            '                       $(\'#delete_instance_desc\').text($(this).parent().parent().parent().parent().parent().children()[2].textContent)">\n'+
+                            '                        强制删除\n'+
+                            '                    </a>\n'+
+                            '                </li>\n' +
+                            '            </ul>\n' +
+                            '        </div>\n' +
                             '    </td>\n' +
                             '</tr>';
                         $('#vlans_list_table tbody').append(html);
@@ -904,6 +926,50 @@
                 }
             });
         }
+
+        function vlan_delete_at() {
+            $('#vlan_delete_modal').modal('hide');
+
+            var vlan_index_id = $('#vlan_index_id').val();
+
+            $.ajax({
+                url : '/api/vlans/' + vlan_index_id,
+                type : 'DELETE',
+                contentType: "application/json; charset=utf-8",
+                async: false,
+                error : function(data, textStatus, xhr) {
+                    alter_danger(data.responseText);
+                    alter_warning('删除 VLAN 失败!');
+                },
+                success : function(data, textStatus, xhr) {
+                    alter_success('删除 VLAN 成功!');
+                    setTimeout(function() {
+                        refresh();
+                    }, 1000);
+                }
+            });
+        }
+
+        function vlan_force_delete_at() {
+            var vlan_index_id = $('#vlan_index_id').val();
+
+            $.ajax({
+                url : '/api/vlans/_force/' + vlan_index_id,
+                type : 'DELETE',
+                contentType: "application/json; charset=utf-8",
+                async: false,
+                error : function(data, textStatus, xhr) {
+                    alter_danger(data.responseText);
+                    alter_warning('强制删除 VLAN 失败!');
+                },
+                success : function(data, textStatus, xhr) {
+                    alter_success('强制删除 VLAN 成功!');
+                    setTimeout(function() {
+                        refresh();
+                    }, 1000);
+                }
+            });
+        }
     </script>
     <div class="panel">
         <div class="panel-body">
@@ -1055,7 +1121,7 @@
                         </div>
                     </div>
                 </div>
-                <table id="vlans_list_table" class="table table-bordered table-hover" cellspacing="0" width="100%" role="grid" style="width: 100%; margin-bottom: 0; border-bottom-width: 0;">
+                <table id="vlans_list_table" class="table table-bordered table-hover" cellspacing="0" width="100%" role="grid" style="width: 100%; margin-bottom: 0;">
                     <thead>
                     <tr role="row">
                         <th width="180px">名称</th>
@@ -1309,4 +1375,40 @@
         </div>
     </div>
 </div>
+
+<div class="modal" id="vlan_delete_modal" tabindex="-1" role="dialog" style="margin-top: 100px;">
+    <div class="modal-dialog">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h4 class="modal-title">删除 VLAN:</h4>
+            </div>
+            <div class="modal-body">
+                <p>您确定要删除该 VLAN 吗?</p>
+                <h3 style="color: orangered;" id="delete_vlan_instance_desc"></h3>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-sm btn-primary" onclick="vlan_delete_at();">确定</button>
+                <button type="button" class="btn btn-sm btn-default" data-dismiss="modal">取消</button>
+            </div>
+        </div>
+    </div>
+</div>
+
+<div class="modal" id="vlan_force_delete_modal" tabindex="-1" role="dialog" style="margin-top: 100px;">
+    <div class="modal-dialog">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h4 class="modal-title">强制删除 VLAN:</h4>
+            </div>
+            <div class="modal-body">
+                <p>您确定要强制删除该 VLAN 吗?</p>
+                <h3 style="color: orangered;" id="delete_force_instance_desc"></h3>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-sm btn-primary" onclick="vlan_force_delete_at();">确定</button>
+                <button type="button" class="btn btn-sm btn-default" data-dismiss="modal">取消</button>
+            </div>
+        </div>
+    </div>
+</div>
 {% endblock content %}