Index: /branches/amp_3_7_2/extensions/license_server/license_server/index.html
===================================================================
--- /branches/amp_3_7_2/extensions/license_server/license_server/index.html	(revision 2996)
+++ /branches/amp_3_7_2/extensions/license_server/license_server/index.html	(working copy)
@@ -48,9 +48,9 @@
     document.feactl.SWMaintenance.checked = true;
 
 
-    // document.feactl.memory_nolimit.checked = false;
-    document.feactl.cpu_nolimit.checked = false;
-    document.feactl.bandwidth_nolimit.checked = false;
+    document.feactl.memoryNolimit.checked = false;
+    document.feactl.cpuNolimit.checked = false;
+    document.feactl.bandwidthNolimit.checked = false;
 }
 
 //-->
Index: /branches/amp_3_7_2/extensions/license_server/license_server/server/http_server.c
===================================================================
--- /branches/amp_3_7_2/extensions/license_server/license_server/server/http_server.c	(revision 2996)
+++ /branches/amp_3_7_2/extensions/license_server/license_server/server/http_server.c	(working copy)
@@ -799,6 +799,12 @@
             for (i = 0; i < assign_result; i++) {
                 int index = resource_table[i].resource_id - 1;
                 char *column_name = resource_db_mapping[index].occupied_col;
+                /* Never propagate a negative quantity. device2.perbw defaults to -1
+                   (unassigned); if that ever reaches a device it is cast to uint64 and
+                   shows as a bogus ~1.8e10 Gbps bandwidth limit. Clamp to 0 (restricted). */
+                if (resource_table[i].quantity < 0) {
+                    resource_table[i].quantity = 0;
+                }
                 sprintf(resource_str, "%s = %d", column_name, resource_table[i].quantity);
                 char heartbeat_sql[100];
                 sprintf(heartbeat_sql, "update device2 set %s where id = '%s';", resource_str, device_host);
Index: /branches/amp_3_7_2/extensions/license_server/license_server_db.py
===================================================================
--- /branches/amp_3_7_2/extensions/license_server/license_server_db.py	(revision 2996)
+++ /branches/amp_3_7_2/extensions/license_server/license_server_db.py	(working copy)
@@ -95,9 +95,13 @@
                               PRIMARY KEY (name)
                             )'''
         self.execute_sql(create_table_sql)
-        # Ensure the cpu/memory columns exist on already-created license tables (upgrades).
-        self.execute_sql("ALTER TABLE license ADD COLUMN IF NOT EXISTS cpu INTEGER DEFAULT 0;")
-        self.execute_sql("ALTER TABLE license ADD COLUMN IF NOT EXISTS memory INTEGER DEFAULT 0;")
+        # CREATE TABLE IF NOT EXISTS never alters an already-existing table, so on an
+        # upgrade these columns are added by the ALTERs below, not by the CREATE above.
+        # Run each via the ignore-exception helper so one failing statement rolls back
+        # cleanly instead of poisoning the connection's transaction and silently
+        # skipping the remaining migrations.
+        self.execute_sql_ingnore_exception("ALTER TABLE license ADD COLUMN IF NOT EXISTS cpu INTEGER DEFAULT 0;")
+        self.execute_sql_ingnore_exception("ALTER TABLE license ADD COLUMN IF NOT EXISTS memory INTEGER DEFAULT 0;")
 
     def create_table_device2(self):
         print('Creating table device2(for licensing)...')
@@ -124,8 +128,11 @@
                             )'''
         self.execute_sql(create_table_sql)
         # Per-device CPU/RAM assigned from the volume license (added alongside perbw).
-        self.execute_sql("ALTER TABLE device2 ADD COLUMN IF NOT EXISTS permem INTEGER DEFAULT 0;")
-        self.execute_sql("ALTER TABLE device2 ADD COLUMN IF NOT EXISTS percpu INTEGER DEFAULT 0;")
+        # As above: CREATE IF NOT EXISTS won't add these to an existing device2 table,
+        # so the ALTERs are the actual upgrade path. Use the ignore-exception helper so
+        # a single failure can't abort the rest of the migration.
+        self.execute_sql_ingnore_exception("ALTER TABLE device2 ADD COLUMN IF NOT EXISTS permem INTEGER DEFAULT 0;")
+        self.execute_sql_ingnore_exception("ALTER TABLE device2 ADD COLUMN IF NOT EXISTS percpu INTEGER DEFAULT 0;")
 
     def create_table_discover_device(self):
         print('Creating table discover device...')
Index: /branches/amp_3_7_2/extensions/license_server/webui/client/device/device_default.html
===================================================================
--- /branches/amp_3_7_2/extensions/license_server/webui/client/device/device_default.html	(revision 2996)
+++ /branches/amp_3_7_2/extensions/license_server/webui/client/device/device_default.html	(working copy)
@@ -26,10 +26,10 @@
                             <th st-sort="license" style="cursor: pointer;">{{'License'|T}}</th>
                             <th st-sort="status" style="cursor: pointer;">{{'Status'|T}}</th>
                             <th st-sort="auto_bw" style="cursor: pointer;">{{'Bandwidth Mode'|T}}</th>
-                            <th st-sort="assigned_bandwidth" style="cursor: pointer;">{{'Assigned Bandwidth'|T}}</th>
+                            <th st-sort="bw_limit" style="cursor: pointer;">{{'Assigned Bandwidth'|T}}</th>
                             <th st-sort="percpu" style="cursor: pointer;">{{'Assigned CPU'|T}}</th>
                             <th st-sort="permem" style="cursor: pointer;">{{'Assigned RAM'|T}}</th>
-                            <th st-sort="applied_bandwidth" style="cursor: pointer;">{{'Applied Bandwidth'|T}}</th>
+                            <th st-sort="perbw" style="cursor: pointer;">{{'Applied Bandwidth'|T}}</th>
                             <th st-sort="realtime_bandwidth" style="cursor: pointer;">{{'Real-time Bandwidth'|T}}</th>
                             <th>{{'Action'|T}}</th>
                         </tr>
@@ -76,9 +76,9 @@
                             </td>
                             <td>{{row.auto_bw ? 'Auto' : 'Manually'}}</td>
                             <td>{{row.bw_limit ? row.bw_limit + ' Mbps' : 'N/A'}}</td>
-                            <td>{{row.perbw}}</td>
                             <td>{{row.percpu}}</td>
                             <td>{{row.permem}}</td>
+                            <td>{{row.perbw}}</td>
                             <td>Current: {{row.rel_bandwith.current}}<br>Dropped: {{row.rel_bandwith.dropped}}<br>Limitation:
                                 {{row.rel_bandwith.limitation}}
                             </td>
Index: /branches/amp_3_7_2/extensions/license_server/webui/client/license/license.html
===================================================================
--- /branches/amp_3_7_2/extensions/license_server/webui/client/license/license.html	(revision 2996)
+++ /branches/amp_3_7_2/extensions/license_server/webui/client/license/license.html	(working copy)
@@ -27,7 +27,7 @@
                             <th st-sort="available_bw">{{'Available bandwidth'|T}}</th>
                             <th st-sort="used_bw">{{'Allocated bandwidth'|T}}</th>
                             <th st-sort="capacity" style="cursor: pointer;">{{'vAPV Capacity'|T}}</th>
-                            <th st-sort="memory_control">{{'Memory'|T}}</th>
+                            <th st-sort="memory_control">{{'RAM'|T}}</th>
                             <th st-sort="cpu">{{'CPU Control'|T}}</th>
                             <th>{{'Action'|T}}</th>
                         </tr>
@@ -44,7 +44,7 @@
                             <td>{{row.available_bw}} Mbps</td>
                             <td>{{row.used_bw}} Mbps</td>
                             <td>{{row.capacity}}</td>
-                            <td>{{row.memory_control}}</td>
+                            <td>{{row.memory ? row.memory : 'N/A'}}</td>
                             <td>{{row.cpu ? row.cpu : 'N/A'}}</td>
                             <td>
                                 <a class="icon-box" style="cursor:pointer" title="{{'Delete'|T}}" ng-click="table.delete(row)"><i class="array-delete"></i></a>
Index: /branches/amp_3_7_2/extensions/license_server/webui/client/locales/en.json
===================================================================
--- /branches/amp_3_7_2/extensions/license_server/webui/client/locales/en.json	(revision 2996)
+++ /branches/amp_3_7_2/extensions/license_server/webui/client/locales/en.json	(working copy)
@@ -4,9 +4,8 @@
     "Generation Date": "Generation Date",
     "Bandwith Limitation": "Bandwith Limitation",
     "vAPV Capacity": "vAPV Capacity",
-    "Memory Control": "Memory Control",
+    "RAM": "RAM",
     "CPU Control": "CPU Control",
-    "Memory": "Memory",
     "Max available bandwidth": "Max available bandwidth",
     "Failed to delete the volume license!": "Failed to delete the volume license!",
     "Failed to import the volume license key!": "Failed to import the volume license key!",
Index: /branches/amp_3_7_2/extensions/license_server/webui/client/locales/zh-cn.json
===================================================================
--- /branches/amp_3_7_2/extensions/license_server/webui/client/locales/zh-cn.json	(revision 2996)
+++ /branches/amp_3_7_2/extensions/license_server/webui/client/locales/zh-cn.json	(working copy)
@@ -4,9 +4,8 @@
     "Generation Date": "生成时间",
     "Bandwith Limitation": "带宽限制",
     "vAPV Capacity": "vAPV容量",
-    "Memory Control": "内存控制",
+    "RAM": "内存",
     "CPU Control": "CPU控制",
-    "Memory": "内存",
     "Max available bandwidth": "最大可用带宽",
     "Failed to delete the volume license!": "删除批量许可证失败！",
     "Failed to import the volume license key!": "无法导入批量许可证密钥！",
Index: /branches/amp_3_7_2/extensions/license_server/webui/model/cm_device/__init__.py
===================================================================
--- /branches/amp_3_7_2/extensions/license_server/webui/model/cm_device/__init__.py	(revision 2996)
+++ /branches/amp_3_7_2/extensions/license_server/webui/model/cm_device/__init__.py	(working copy)
@@ -153,11 +153,21 @@
     class Manager(CLIManager):
         def _get_query_set(self):
             db = DB.get_connected_db()
+            # Select columns explicitly and in the exact order of `key` below. Using
+            # `select d1.*` made the row->dict mapping depend on device2's physical
+            # column order; when permem/percpu were added the positions drifted and
+            # bandwidth values were silently zipped into the percpu/permem keys (i.e.
+            # bandwidth showing in the CPU/RAM columns). An explicit list keeps the
+            # value<->name mapping stable no matter how the table was migrated.
             fetchall_sql = '''
-                select d1.*, l3.used_bw, l3.total_bw from device2 as d1 left join 
-	            (select l2.name, l1.used_bw, l2.bandwidth as total_bw from license as l2 left join 
-	            (select license_name, sum(perbw) as used_bw from device2 group by device2.license_name) l1 
-	            on l1.license_name = l2.name) l3 on d1.license_name = l3.name;                
+                select d1.id, d1.ip, d1.restapi_port, d1.restapi_username, d1.restapi_password,
+                       d1.connection, d1.status, d1.version, d1.license_name, d1.perbw,
+                       d1.error_msg, d1.rel_bandwith, d1.perbw_limit as bw_limit, d1.auto as auto_bw,
+                       d1.restapi_protocol, d1.permem, d1.percpu, l3.used_bw, l3.total_bw
+                from device2 as d1 left join
+	            (select l2.name, l1.used_bw, l2.bandwidth as total_bw from license as l2 left join
+	            (select license_name, sum(perbw) as used_bw from device2 group by device2.license_name) l1
+	            on l1.license_name = l2.name) l3 on d1.license_name = l3.name;
             '''
             data = db.fetchall(fetchall_sql)
             db.close()
Index: /branches/amp_3_7_2/extensions/license_server/webui/model/license/__init__.py
===================================================================
--- /branches/amp_3_7_2/extensions/license_server/webui/model/license/__init__.py	(revision 2996)
+++ /branches/amp_3_7_2/extensions/license_server/webui/model/license/__init__.py	(working copy)
@@ -48,7 +48,22 @@
     class Manager(CLIManager):
         def _get_query_set(self):
             db = DB.get_connected_db()
-            fetchall_sql = '''select license.*, dl.used_bw from license left join (select license_name, sum(perbw) as used_bw from device2 group by device2.license_name) dl on license.name = dl.license_name;'''
+            # Select columns explicitly, in the exact order of `key` below. `select
+            # license.*` returned them in physical table order, which does NOT match
+            # `key` (the table stores bwlimit before bandwidth; the key list has the
+            # reverse) -- a latent swap that only hid because bwlimit == bandwidth today.
+            # Listing columns by name keeps every value mapped to the right key,
+            # including memory_resource_control / cpu / memory.
+            fetchall_sql = '''
+                select license.name, license.license, license.company_name, license.generation_date,
+                       license.expiration_date, license.bandwidth, license.bwlimit, license.capacity,
+                       license.memory_resource_control, license.res_memory_num_2g, license.res_memory_num_4g,
+                       license.res_memory_num_6g, license.res_memory_num_8g, license.res_memory_num_16g,
+                       license.cpu, license.memory, dl.used_bw
+                from license left join
+                (select license_name, sum(perbw) as used_bw from device2 group by device2.license_name) dl
+                on license.name = dl.license_name;
+            '''
             data = db.fetchall(fetchall_sql)
             db.close()
             key = ['name', 'license', 'company_name', 'generation_date', 'expiration_date', 'bandwidth', 'bwlimit', 'capacity', 'memory_resource_control'] + memory_control_column + ['cpu', 'memory', 'used_bw']
@@ -57,14 +72,18 @@
                 for key, value in each.items():
                     if key == 'bandwidth':
                         each['bandwidth'] = str(each['bandwidth'])+' Mbps'
-                # Single Memory column: a license encodes RAM either as per-device-type
-                # counts (memory_resource_control) or as one generic limit (memory) --
-                # never both -- so show whichever applies.
+                # Single Memory column: prefer the per-device-type breakdown
+                # (memory_resource_control), but fall back to the generic RAM limit
+                # (memory) when no per-type counts are set. A license can carry both a
+                # memory_resource_control flag and a generic memory value, in which case
+                # the old "if control: else memory" logic produced an empty breakdown and
+                # hid the real RAM number (showed N/A despite memory > 0).
+                m_c = []
                 if each["memory_resource_control"]:
-                    m_c = []
                     for item in memory_control_column:
                         if each[item]:
                             m_c.append("%s: %d" % (item.split("_")[-1].upper(), each[item]))
+                if m_c:
                     each["memory_control"] = (", ").join(m_c)
                 elif each.get("memory"):
                     each["memory_control"] = str(each["memory"])
