James Iter 7 лет назад
Родитель
Сommit
d3dcafd7e8

+ 102 - 11
jimvc/api/vlan.py

@@ -2,7 +2,8 @@
 # -*- coding: utf-8 -*-
 # -*- coding: utf-8 -*-
 
 
 
 
-from flask import Blueprint, request
+import requests
+from flask import Blueprint, request, url_for
 import json
 import json
 import jimit as ji
 import jimit as ji
 
 
@@ -138,29 +139,117 @@ def r_update(ids):
 
 
 @Utils.dumps2response
 @Utils.dumps2response
 def r_get(ids):
 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
 @Utils.dumps2response
 def r_get_by_filter():
 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
 @Utils.dumps2response
 def r_content_search():
 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
 @Utils.dumps2response
 def r_delete(ids):
 def r_delete(ids):
+    ret = dict()
+    ret['state'] = ji.Common.exchange_state(20000)
+
     args_rules = [
     args_rules = [
         Rules.IDS.value
         Rules.IDS.value
     ]
     ]
 
 
-    request.json['ids'] = ids
-
     try:
     try:
-        ji.Check.previewing(args_rules, request.json)
+
+        ji.Check.previewing(args_rules, {'ids': ids})
 
 
         vlan = VLAN()
         vlan = VLAN()
 
 
@@ -169,15 +258,15 @@ def r_delete(ids):
             vlan.id = _id
             vlan.id = _id
             vlan.get()
             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:
             if guests.__len__() > 0:
 
 
                 guests_info = ''
                 guests_info = ''
                 for guest in guests:
                 for guest in guests:
                     guests_info += guest['label'] + ',' + guest['uuid'] + '.'
                     guests_info += guest['label'] + ',' + guest['uuid'] + '.'
 
 
-                ret = dict()
                 ret['state'] = ji.Common.exchange_state(41262)
                 ret['state'] = ji.Common.exchange_state(41262)
                 ret['state']['sub']['zh-cn'] = ''.join([
                 ret['state']['sub']['zh-cn'] = ''.join([
                     ret['state']['sub']['zh-cn'], u': Vlan ID: ', vlan.vlan_id, u': Guests: ', guests_info])
                     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,
                     'uuid': None,
                     'node_id': host['node_id'],
                     'node_id': host['node_id'],
                     'vlan_id': vlan.vlan_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))
                 Utils.emit_instruction(message=json.dumps(message, ensure_ascii=False))
 
 
+        return ret
+
     except ji.PreviewingError, e:
     except ji.PreviewingError, e:
         return json.loads(e.message)
         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
     SnapshotDiskMapping
 )
 )
 
 
-from event_processor import (
-    EventProcessor
-)
-
 from vlan import (
 from vlan import (
     VLAN
     VLAN
 )
 )
 
 
+from event_processor import (
+    EventProcessor
+)
+
 
 
 __author__ = 'James Iter'
 __author__ = 'James Iter'
 __date__ = '2017/3/21'
 __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 GuestMigrateInfo
 from jimvc.models import GuestCollectionPerformanceDataKind, HostCollectionPerformanceDataKind
 from jimvc.models import GuestCollectionPerformanceDataKind, HostCollectionPerformanceDataKind
 from jimvc.models import HostCPUMemory, HostTraffic, HostDiskUsageIO
 from jimvc.models import HostCPUMemory, HostTraffic, HostDiskUsageIO
+from jimvc.models import Host
+from jimvc.models import VLAN
 
 
 
 
 __author__ = 'James Iter'
 __author__ = 'James Iter'
@@ -33,6 +35,7 @@ class EventProcessor(object):
     guest = Guest()
     guest = Guest()
     guest_migrate_info = GuestMigrateInfo()
     guest_migrate_info = GuestMigrateInfo()
     disk = Disk()
     disk = Disk()
+    vlan = VLAN()
     snapshot = Snapshot()
     snapshot = Snapshot()
     snapshot_disk_mapping = SnapshotDiskMapping()
     snapshot_disk_mapping = SnapshotDiskMapping()
     os_template_image = OSTemplateImage()
     os_template_image = OSTemplateImage()
@@ -371,6 +374,27 @@ class EventProcessor(object):
                 else:
                 else:
                     pass
                     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:
         else:
             pass
             pass
 
 

+ 8 - 7
jimvc/models/host.py

@@ -3,7 +3,7 @@
 
 
 
 
 import json
 import json
-from flask import g
+import jimit as ji
 
 
 from jimvc.models import app_config
 from jimvc.models import app_config
 from jimvc.models import Database as db
 from jimvc.models import Database as db
@@ -27,12 +27,13 @@ class Host(object):
         """
         """
 
 
         coupler_length = 60
         coupler_length = 60
+        ts = ji.Common.ts()
 
 
         if 'timestamp' not in v:
         if 'timestamp' not in v:
             return v
             return v
 
 
         v['alive'] = False
         v['alive'] = False
-        if v['timestamp'] + coupler_length >= g.ts:
+        if v['timestamp'] + coupler_length >= ts:
             v['alive'] = True
             v['alive'] = True
 
 
         if 'threads_status' not in v:
         if 'threads_status' not in v:
@@ -55,23 +56,23 @@ class Host(object):
             }
             }
 
 
         v['threads_status']['instruction_process_engine']['alive'] = False
         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']['instruction_process_engine']['alive'] = True
 
 
         v['threads_status']['host_state_report_engine']['alive'] = False
         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']['host_state_report_engine']['alive'] = True
 
 
         v['threads_status']['guest_creating_progress_report_engine']['alive'] = False
         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_creating_progress_report_engine']['alive'] = True
 
 
         v['threads_status']['guest_performance_collection_engine']['alive'] = False
         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']['guest_performance_collection_engine']['alive'] = True
 
 
         v['threads_status']['host_performance_collection_engine']['alive'] = False
         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
             v['threads_status']['host_performance_collection_engine']['alive'] = True
 
 
         return v
         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() {
         function add_vlan() {
             $('#add_vlan_modal').modal('hide');
             $('#add_vlan_modal').modal('hide');
 
 
@@ -843,14 +851,28 @@
                             '               </a>\n' +
                             '               </a>\n' +
                             '       </div>\n' +
                             '       </div>\n' +
                             '    </td>\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">' + new Date(v['create_time'] / 1000).format('yy-mm-dd HH:MM:ss') + '</td>\n' +
                             '    <td class="text-center">\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' +
                             '    </td>\n' +
                             '</tr>';
                             '</tr>';
                         $('#vlans_list_table tbody').append(html);
                         $('#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>
     </script>
     <div class="panel">
     <div class="panel">
         <div class="panel-body">
         <div class="panel-body">
@@ -1055,7 +1121,7 @@
                         </div>
                         </div>
                     </div>
                     </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>
                     <thead>
                     <tr role="row">
                     <tr role="row">
                         <th width="180px">名称</th>
                         <th width="180px">名称</th>
@@ -1309,4 +1375,40 @@
         </div>
         </div>
     </div>
     </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 %}
 {% endblock content %}