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 2992)
+++ /branches/amp_3_7_2/extensions/license_server/license_server/index.html	(working copy)
@@ -101,19 +101,13 @@
             Number of Licensed vAPVs:
                         <input name="va_capacity" type="number" min="1" max="128"/>
             <BR>
-                Memory Resource Limit: 
+                Memory Resource Limit (number of vAPVs per RAM type; leave 0 for none):
                 <BR>
-                &nbsp;&nbsp;Device Type:
-                <SELECT name="res_memory_type" id="res_memory_type" onChange="check_defaults(this)">
-                    <OPTION value=""> Please Select
-                    <OPTION value="2"> 2 G
-                    <OPTION value="4"> 4 G
-                    <OPTION value="6"> 6 G
-                    <OPTION value="8"> 8 G
-                    <OPTION value="16"> 16 G
-                </SELECT>
-                Number:
-                <input name="res_memory_num" type="res_memory_num" min="1" max="512"/>
+                &nbsp;&nbsp;2 G:&nbsp;<input name="res_memory_num_2g" type="number" min="0" max="512" value="0"/>
+                &nbsp;&nbsp;4 G:&nbsp;<input name="res_memory_num_4g" type="number" min="0" max="512" value="0"/>
+                &nbsp;&nbsp;6 G:&nbsp;<input name="res_memory_num_6g" type="number" min="0" max="512" value="0"/>
+                &nbsp;&nbsp;8 G:&nbsp;<input name="res_memory_num_8g" type="number" min="0" max="512" value="0"/>
+                &nbsp;&nbsp;16 G:&nbsp;<input name="res_memory_num_16g" type="number" min="0" max="512" value="0"/>
             <BR>
             Enabled Features:
             <BR>
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 2992)
+++ /branches/amp_3_7_2/extensions/license_server/license_server/server/http_server.c	(working copy)
@@ -18,14 +18,14 @@
 #include <sqlite3.h>
 #include <pthread.h>
 #include "../lib/cjson/cJSON.h"
-#include "http_client.h"
-#include "license_manager.h"
-
-cJSON *license_info_root = NULL;
-
-void check_volume_license(struct evhttp_request *req, void *arg)
-{
-    license_info_t license_info_table;
+#include "http_client.h"
+#include "license_manager.h"
+
+cJSON *license_info_root = NULL;
+
+void check_volume_license(struct evhttp_request *req, void *arg)
+{
+    license_info_t license_info_table;
     struct  evbuffer *buff = NULL;
     char    *req_data = NULL;
     char    *license_key = NULL;
@@ -33,18 +33,18 @@
     char    *response = NULL;
     char    gendate[BLOCK_LEN];
     char    expdate[BLOCK_LEN];
-    char    action_name[] = "Check License";
-    char    log_device[] = "CM Server";
-    cJSON   *cjson_license_key = NULL;
-    cJSON   *cjson_upgrade = NULL;
-    cJSON   *cjson_license_name = NULL;
-    size_t  check_result = 0;
-    size_t  len = 0;
-    size_t  license_len = 0;
-    int     upgrade_flag = 0;
-
-    /* get the event POST body */
-    buff = evhttp_request_get_input_buffer(req);
+    char    action_name[] = "Check License";
+    char    log_device[] = "CM Server";
+    cJSON   *cjson_license_key = NULL;
+    cJSON   *cjson_upgrade = NULL;
+    cJSON   *cjson_license_name = NULL;
+    size_t  check_result = 0;
+    size_t  len = 0;
+    size_t  license_len = 0;
+    int     upgrade_flag = 0;
+
+    /* get the event POST body */
+    buff = evhttp_request_get_input_buffer(req);
     len = evbuffer_get_length(buff);
     req_data = malloc(len + 1);
     if (req_data == NULL) {
@@ -68,25 +68,25 @@
 
     if (!(cJSON_HasObjectItem(root_json, "license_key") && cJSON_HasObjectItem(root_json, "license_name"))) {
         response = make_response_json(FAILURE_STATUS, "The request body error.", NULL, action_name, log_device);
-        goto end;
-    }
-
-    /* check license upgrade mode */
-    if (cJSON_HasObjectItem(root_json, "upgrade")) {
-        cjson_upgrade = cJSON_GetObjectItem(root_json, "upgrade");
-        if (cJSON_IsBool(cjson_upgrade)) {
-            if (cJSON_IsTrue(cjson_upgrade)) {
-                upgrade_flag = 1;
-            }
-        } else {
-            response = make_response_json(FAILURE_STATUS, "The filed upgrade is not bool format.", NULL, action_name, log_device);
-            goto end;
-        }
-    }
-
-    cjson_license_key = cJSON_GetObjectItem(root_json, "license_key");
-    license_key       = cjson_license_key->valuestring;
-    if (!cJSON_IsString(cjson_license_key) || !(strlen(license_key))) {
+        goto end;
+    }
+
+    /* check license upgrade mode */
+    if (cJSON_HasObjectItem(root_json, "upgrade")) {
+        cjson_upgrade = cJSON_GetObjectItem(root_json, "upgrade");
+        if (cJSON_IsBool(cjson_upgrade)) {
+            if (cJSON_IsTrue(cjson_upgrade)) {
+                upgrade_flag = 1;
+            }
+        } else {
+            response = make_response_json(FAILURE_STATUS, "The filed upgrade is not bool format.", NULL, action_name, log_device);
+            goto end;
+        }
+    }
+
+    cjson_license_key = cJSON_GetObjectItem(root_json, "license_key");
+    license_key       = cjson_license_key->valuestring;
+    if (!cJSON_IsString(cjson_license_key) || !(strlen(license_key))) {
         response = make_response_json(FAILURE_STATUS, "License key is not string.", NULL, action_name, log_device);
         goto end;
     }
@@ -107,22 +107,22 @@
 
     if (strlen(license_name) > LICENSE_NAME_LEN) {
         response = make_response_json(FAILURE_STATUS, "The length of license name is more than 32 characters.", NULL, action_name, log_device);
-        goto end;
-    }
-
-    /* check the license name & licnese key existence. */
-    if (!upgrade_flag) {
-        if (!check_license_name_exist(license_name)) {
-            response = make_response_json(FAILURE_STATUS, "The license name has been imported, please check it.", NULL, action_name, log_device);
-            goto end;
-        }
-    }
-    if (!check_license_key_exist(license_key)) {
-        response = make_response_json(FAILURE_STATUS, "The license key has been imported, please check it.", NULL, action_name, log_device);
-        goto end;
-    }
-
-    /* check the generation date and expire date. */
+        goto end;
+    }
+
+    /* check the license name & licnese key existence. */
+    if (!upgrade_flag) {
+        if (!check_license_name_exist(license_name)) {
+            response = make_response_json(FAILURE_STATUS, "The license name has been imported, please check it.", NULL, action_name, log_device);
+            goto end;
+        }
+    }
+    if (!check_license_key_exist(license_key)) {
+        response = make_response_json(FAILURE_STATUS, "The license key has been imported, please check it.", NULL, action_name, log_device);
+        goto end;
+    }
+
+    /* check the generation date and expire date. */
     strncpy(expdate, &license_key[license_len + 1 - BLOCK_LEN], sizeof(expdate));
     strncpy(gendate, &license_key[license_len + 1 - BLOCK_LEN * 2], sizeof(gendate));
 
@@ -135,19 +135,19 @@
 
     if (check_date(expdate) == 0) {
         response = make_response_json(FAILURE_STATUS, "The license is expired.", NULL, action_name, log_device);
-        goto end;
-    }
-
-    /* start to call function check_license to check the validation of license key. */
-    check_result = check_license(license_key, license_name, &license_info_table);
-
-    if(!check_result) {
-        /* store the license struct to DB. */
-        int store_result = store_license_info(&license_info_table, upgrade_flag);
-        reload_license_info_root();
-
-        if(!store_result) {
-            response = make_response_json(SUCCESS_STATUS, "Check the license successfully.", NULL, action_name, log_device);
+        goto end;
+    }
+
+    /* start to call function check_license to check the validation of license key. */
+    check_result = check_license(license_key, license_name, &license_info_table);
+
+    if(!check_result) {
+        /* store the license struct to DB. */
+        int store_result = store_license_info(&license_info_table, upgrade_flag);
+        reload_license_info_root();
+
+        if(!store_result) {
+            response = make_response_json(SUCCESS_STATUS, "Check the license successfully.", NULL, action_name, log_device);
         } else { /* here need more else to clear the failure type. */
             response = make_response_json(FAILURE_STATUS, "Failed to store the license information.", NULL, action_name, log_device);
         }
@@ -238,20 +238,20 @@
         goto end;
     }
 
-    cjson_device_list = cJSON_GetObjectItem(root_json, "device_id");
-
-    /* 
-       This result array will append each device activate result. 
-       each device activate result is also a cJSON object like:
-       {
-       "device_id": "device1",
-       "status": 1,
-       "msg": ""
-       }
-       */
-    cJSON *result = cJSON_CreateArray();
-    // cJSON_ArrayForEach(device, cjson_device_list) {
-    for (i = 0; i < cJSON_GetArraySize(cjson_device_list); i++) {
+    cjson_device_list = cJSON_GetObjectItem(root_json, "device_id");
+
+    /* 
+       This result array will append each device activate result. 
+       each device activate result is also a cJSON object like:
+       {
+       "device_id": "device1",
+       "status": 1,
+       "msg": ""
+       }
+       */
+    cJSON *result = cJSON_CreateArray();
+    // cJSON_ArrayForEach(device, cjson_device_list) {
+    for (i = 0; i < cJSON_GetArraySize(cjson_device_list); i++) {
         device_id = cJSON_GetArrayItem(cjson_device_list, i)->valuestring;
 
         /* then check the device status and connection. */
@@ -316,15 +316,15 @@
     if (license_check) {
         free(license_check);
     }
-    if(response) {
-        free(response);
-    }
-    if (req_data) {
-        free(req_data);
-    }
-}
-
-void deactivate_device(struct evhttp_request *req, void *arg)
+    if(response) {
+        free(response);
+    }
+    if (req_data) {
+        free(req_data);
+    }
+}
+
+void deactivate_device(struct evhttp_request *req, void *arg)
 {
 
     int     i = 0;
@@ -420,15 +420,15 @@
     if (root_json) {
         cJSON_Delete(root_json);
     }
-    if(response) {
-        free(response);
-    }   
-    if (req_data) {
-        free(req_data);
-    }
-}
-
-void get_license_info(struct evhttp_request *req, void *arg)
+    if(response) {
+        free(response);
+    }   
+    if (req_data) {
+        free(req_data);
+    }
+}
+
+void get_license_info(struct evhttp_request *req, void *arg)
 {
     struct evbuffer *buff;
     int     i = 0;
@@ -585,13 +585,13 @@
     } else {
         response = make_response_json(FAILURE_STATUS, "Request body format error.", NULL, action_name, log_device);
         goto end;
-    }
-
-    delete_result = delete_license_info(license_name_list);
-    reload_license_info_root();
-
-    if (delete_result) {
-        response = make_response_json(SUCCESS_STATUS, delete_result, NULL, action_name, log_device);
+    }
+
+    delete_result = delete_license_info(license_name_list);
+    reload_license_info_root();
+
+    if (delete_result) {
+        response = make_response_json(SUCCESS_STATUS, delete_result, NULL, action_name, log_device);
     } else {
         response = make_response_json(FAILURE_STATUS, "Failed to delete license info because of internal error.", NULL, action_name, log_device);
     }
@@ -625,13 +625,13 @@
 void device_heartbeat(struct evhttp_request *req, void *arg)
 {
     int i = 0;
-    int device_status = 0;
-    int assign_result = 0;
-    int memory = 0;
-    int retry_time = 0;
-    char *req_data = NULL;
-    char *response = NULL;
-    char *license_name = NULL;
+    int device_status = 0;
+    int assign_result = 0;
+    int memory = 0;
+    int retry_time = 0;
+    char *req_data = NULL;
+    char *response = NULL;
+    char *license_name = NULL;
     char *device_id = NULL;
     char *host = NULL;
     char update_sql[2048];
@@ -756,13 +756,15 @@
 
             /* update device set license_name, resources, status*/      
             char resource_str[1024];
+            int rs_len = 0;
+            resource_str[0] = '\0';
 
             for(i = 0; i < RESOURCES_NUM; i++) {
                 if (resource_db_mapping[i].resource_id && resource_db_mapping[i].active) {
-                    sprintf(resource_str, ", %s = %d", resource_db_mapping[i].occupied_col, (i != 2) ? 1 : 0);
+                    rs_len += sprintf(resource_str + rs_len, ", %s = %d", resource_db_mapping[i].occupied_col, 0);
                 }
             }
-            char sql_update[100];
+            char sql_update[256];
             sprintf(sql_update, "update device2 set status = 'new', license_name = NULL%s  where id = '%s';", resource_str, device_host);
 
             db_execute(sql_update);
@@ -842,24 +844,24 @@
     if (license_key) {
         free(license_key);
     }
-    if (serial_number) {
-        free(serial_number);
-    }
-
-    if (req_data) {
-        free(req_data);
-    }
-}
-
-void check_timer(int fd, short event, void *arg)
-{
-    /* 
-       loop the time record from HEARTBEAT_TIMER_PATH and compare the timestamp each device recorded with current timestamp.
-       if the time interval is over 60s, set the connection is unconnected and make every resource that occupied empty.
-       */
-    int     nCount = 0;
-    int     i = 0;
-    int     j = 0;
+    if (serial_number) {
+        free(serial_number);
+    }
+
+    if (req_data) {
+        free(req_data);
+    }
+}
+
+void check_timer(int fd, short event, void *arg)
+{
+    /* 
+       loop the time record from HEARTBEAT_TIMER_PATH and compare the timestamp each device recorded with current timestamp.
+       if the time interval is over 60s, set the connection is unconnected and make every resource that occupied empty.
+       */
+    int     nCount = 0;
+    int     i = 0;
+    int     j = 0;
     int     connection = 0;
     double  timestamp;
     double  cur_timestamp;
@@ -871,14 +873,14 @@
     cJSON   *timer_json = NULL;
     cJSON   *device_json = NULL;
 
-    if (!access(HEARTBEAT_TIMER_PATH, R_OK)) {
-        /* remove the device which has been delete. */
-        check_and_update_timer(HEARTBEAT_TIMER_PATH);
-
-        timer_str = get_all_text_from_file(HEARTBEAT_TIMER_PATH, TIMER_RECORD_LOCK);
-        if (timer_str) {
-            timer_json = cJSON_Parse(timer_str);
-
+    if (!access(HEARTBEAT_TIMER_PATH, R_OK)) {
+        /* remove the device which has been delete. */
+        check_and_update_timer(HEARTBEAT_TIMER_PATH);
+
+        timer_str = get_all_text_from_file(HEARTBEAT_TIMER_PATH, TIMER_RECORD_LOCK);
+        if (timer_str) {
+            timer_json = cJSON_Parse(timer_str);
+
             nCount = cJSON_GetArraySize(timer_json);
 
             for (i = 0; i < nCount; i++) {
@@ -892,17 +894,19 @@
 
                 if (cur_timestamp - timestamp > 60) {
                     /* set all resource empty for this device and set connection unconnected. */
-
-                    for(j = 0; j < RESOURCES_NUM; j++) {
-                        if (resource_db_mapping[j].resource_id && resource_db_mapping[j].active) {
-                            sprintf(resource_str, ", %s = %d", resource_db_mapping[j].occupied_col, (resource_db_mapping[j].resource_id == 1) ? 1 : 0);
-                        }
-                    }
-
-                    sprintf(update_sql, "update device2 set connection = 'unconnected'%s where id = '%s';", resource_str, device_id);
-
-                } else {
-                    /* set the connection of device is connected */
+                    int rs_len = 0;
+                    resource_str[0] = '\0';
+
+                    for(j = 0; j < RESOURCES_NUM; j++) {
+                        if (resource_db_mapping[j].resource_id && resource_db_mapping[j].active) {
+                            rs_len += sprintf(resource_str + rs_len, ", %s = %d", resource_db_mapping[j].occupied_col, 0);
+                        }
+                    }
+
+                    sprintf(update_sql, "update device2 set connection = 'unconnected'%s where id = '%s';", resource_str, device_id);
+
+                } else {
+                    /* set the connection of device is connected */
                     sprintf(update_sql, "update device2 set connection = 'connected' where id = '%s';", device_id);
                 }
 
@@ -927,13 +931,13 @@
     evtimer_set(ev, check_timer, evbase);
     event_base_set(evbase, ev);
     evtimer_add(ev, &tv);
-}
-
-
-    int
-main(int argc, char **argv)
-{
-    int i;
+}
+
+
+    int
+main(int argc, char **argv)
+{
+    int i;
     struct evconnlistener *listener;
     struct event_base *evbase;
     struct sockaddr_in sin;
@@ -946,16 +950,16 @@
     sin.sin_port = htons(HTTPS_PORT);
     sin.sin_addr.s_addr = htonl(0x00000000); /* 0.0.0.0 */
     // sin.sin_addr.s_addr = htonl(0x7f000001); /* 127.0.0.1 */
-
-    evbase = event_base_new();
-    listener = evconnlistener_new_bind(
-            evbase, NULL, NULL,
-            LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE, 1024,
-            (struct sockaddr *)&sin, sizeof(sin)
-            );
-
-    struct evhttp *http_server = evhttp_new(evbase);
-    if(!http_server) {
+
+    evbase = event_base_new();
+    listener = evconnlistener_new_bind(
+            evbase, NULL, NULL,
+            LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE, 1024,
+            (struct sockaddr *)&sin, sizeof(sin)
+            );
+
+    struct evhttp *http_server = evhttp_new(evbase);
+    if(!http_server) {
         fprintf(stderr, "http_server init failed.\n");
     }
 
@@ -963,26 +967,26 @@
     if(ret != 0) {
         fprintf(stderr, "evhttp_bind_socket failed.\n");
     } else {
-        fprintf(stderr, "http server start OK! \n");
-    }
-
-    /* load the license info */
-    license_i license_info;
-    memset(&license_info, 0, sizeof(license_info));
-    load_license_info(&license_info);
-    license_info_root = license_info.root;
-
-    evhttp_set_cb(http_server, "/cm/get_license_info", get_license_info, NULL);
-    evhttp_set_cb(http_server, "/cm/delete_license_info", delete_license, NULL);
-    evhttp_set_cb(http_server, "/cm/check_license", check_volume_license, NULL);
+        fprintf(stderr, "http server start OK! \n");
+    }
+
+    /* load the license info */
+    license_i license_info;
+    memset(&license_info, 0, sizeof(license_info));
+    load_license_info(&license_info);
+    license_info_root = license_info.root;
+
+    evhttp_set_cb(http_server, "/cm/get_license_info", get_license_info, NULL);
+    evhttp_set_cb(http_server, "/cm/delete_license_info", delete_license, NULL);
+    evhttp_set_cb(http_server, "/cm/check_license", check_volume_license, NULL);
     evhttp_set_cb(http_server, "/cm/activate_device", activate_device, NULL);
-    evhttp_set_cb(http_server, "/cm/deactivate_device", deactivate_device, NULL);
-    evhttp_set_cb(http_server, "/cm/device_heartbeat", device_heartbeat, NULL);
-
-
-    /* set a timer for event lisener loop. */
-    struct timeval tv;
-    struct event *ev;
+    evhttp_set_cb(http_server, "/cm/deactivate_device", deactivate_device, NULL);
+    evhttp_set_cb(http_server, "/cm/device_heartbeat", device_heartbeat, NULL);
+
+
+    /* set a timer for event lisener loop. */
+    struct timeval tv;
+    struct event *ev;
     ev = malloc(sizeof(struct event));
     tv.tv_sec = 5;
     tv.tv_usec = 0;
Index: /branches/amp_3_7_2/extensions/license_server/license_server/server/license_kernel.h
===================================================================
--- /branches/amp_3_7_2/extensions/license_server/license_server/server/license_kernel.h	(revision 2992)
+++ /branches/amp_3_7_2/extensions/license_server/license_server/server/license_kernel.h	(working copy)
@@ -76,8 +76,8 @@
 } device_info_t;
 
 static resource_db_m resource_db_mapping[RESOURCES_NUM] = {
-    {1, "memory", "permem", "memlimit", "permem_limit", "memauto", 0},
-    {2, "cpu", "percpu", "cpulimit", "percpu_limit", "cpuauto", 0},
+    {1, "memory", "permem", "memlimit", "permem_limit", "memauto", 1},
+    {2, "cpu", "percpu", "cpulimit", "percpu_limit", "cpuauto", 1},
     {3, "bandwidth", "perbw", "bwlimit", "perbw_limit", "auto", 1},
 };
 static non_fea_resource_t non_feature_resource[RESOURCES_NUM] = {
Index: /branches/amp_3_7_2/extensions/license_server/license_server/server/license_kernel.c
===================================================================
--- /branches/amp_3_7_2/extensions/license_server/license_server/server/license_kernel.c	(revision 2992)
+++ /branches/amp_3_7_2/extensions/license_server/license_server/server/license_kernel.c	(working copy)
@@ -490,6 +490,7 @@
     status_t status_table;
 
     status_table.status = 0;
+    resource_str[0] = '\0';
 
     expire_date = get_license_value(license_name, "expiration_date");
 
@@ -519,10 +520,12 @@
             char *column_name = resource_db_mapping[index].occupied_col;
             int auto_num = get_auto_num(3, license_name);
             int resource_limit = get_license_fea_or_res(license_name, resource_db_mapping[index].resource_name);
-            if (auto_num && resource_table[i].quantity == resource_limit) {
+            /* Only bandwidth (resource_id == 3) is a shared pool that gets divided
+               across auto devices; CPU/RAM are per-instance caps passed through as-is. */
+            if (resource_table[i].resource_id == 3 && auto_num && resource_table[i].quantity == resource_limit) {
                 resource_table[i].quantity = resource_table[i].quantity / (auto_num + 1);
-            } 
-            buff_len = sprintf(resource_str + buff_len, ", %s = %d", column_name, resource_table[i].quantity);
+            }
+            buff_len += sprintf(resource_str + buff_len, ", %s = %d", column_name, resource_table[i].quantity);
         }
     } else if (a_res == -1) {
         status_table.msg = "Cannot enable this device because the license does not manage this memory type or the number of management has reached the upper limit.";
@@ -546,12 +549,16 @@
 {
     /* before enable check the license is exsit. */
     int  i;
+    int  buff_len = 0;
     char resource_str[1024];
     status_t status_table;
 
+    resource_str[0] = '\0';
+    /* Append (not overwrite) so every active resource column is reset; with CPU
+       and RAM now active alongside bandwidth, all per-device allocations clear. */
     for(i = 0; i < RESOURCES_NUM; i++) {
         if (resource_db_mapping[i].resource_id && resource_db_mapping[i].active) {
-            sprintf(resource_str, ", %s = %d", resource_db_mapping[i].occupied_col, (i != 2) ? 1 : 0);
+            buff_len += sprintf(resource_str + buff_len, ", %s = %d", resource_db_mapping[i].occupied_col, 0);
         }
     }
 
@@ -615,6 +622,16 @@
         }
         int resource_limit = get_license_fea_or_res(license_name, resource_db_mapping[j - 1].resource_name);
         if (resource_limit) {
+            if (j != 3) {
+                /* CPU (j==2) and RAM (j==1) are per-instance caps for a vAPV:
+                   pass the full licensed value through to every device rather
+                   than dividing a shared pool (which only fits bandwidth, j==3). */
+                resource_table[i].resource_id = j;
+                resource_table[i].quantity = resource_limit;
+                resource_table[i].resource_name = resource_db_mapping[j - 1].resource_name;
+                i++;
+                continue;
+            }
             int auto_mode = get_assign_mode(device_id, j);
             int manually_resource_sum = get_manually_resource_sum(j, license_name);
             int auto_rest_resource_num = resource_limit - manually_resource_sum;
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 2992)
+++ /branches/amp_3_7_2/extensions/license_server/license_server_db.py	(working copy)
@@ -90,9 +90,14 @@
                               res_memory_num_6g INTEGER DEFAULT 0,
                               res_memory_num_8g INTEGER DEFAULT 0,
                               res_memory_num_16g INTEGER DEFAULT 0,
+                              cpu INTEGER DEFAULT 0,
+                              memory INTEGER DEFAULT 0,
                               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;")
 
     def create_table_device2(self):
         print('Creating table device2(for licensing)...')
@@ -112,10 +117,15 @@
                               perbw_limit INTEGER DEFAULT 0,
                               auto INTEGER DEFAULT 1,
                               restapi_protocol varchar(20) DEFAULT 'https',
+                              permem INTEGER DEFAULT 0,
+                              percpu INTEGER DEFAULT 0,
                               PRIMARY KEY (id),
                               FOREIGN KEY (license_name) REFERENCES license(name) ON DELETE SET NULL
                             )'''
         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;")
 
     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 2992)
+++ /branches/amp_3_7_2/extensions/license_server/webui/client/device/device_default.html	(working copy)
@@ -27,6 +27,8 @@
                             <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="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="realtime_bandwidth" style="cursor: pointer;">{{'Real-time Bandwidth'|T}}</th>
                             <th>{{'Action'|T}}</th>
@@ -75,6 +77,8 @@
                             <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>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 2992)
+++ /branches/amp_3_7_2/extensions/license_server/webui/client/license/license.html	(working copy)
@@ -27,7 +27,8 @@
                             <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 Control'|T}}</th>
+                            <th st-sort="memory_control">{{'Memory'|T}}</th>
+                            <th st-sort="cpu">{{'CPU Control'|T}}</th>
                             <th>{{'Action'|T}}</th>
                         </tr>
                         </thead>
@@ -44,6 +45,7 @@
                             <td>{{row.used_bw}} Mbps</td>
                             <td>{{row.capacity}}</td>
                             <td>{{row.memory_control}}</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>
                             </td>
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 2992)
+++ /branches/amp_3_7_2/extensions/license_server/webui/client/locales/en.json	(working copy)
@@ -5,6 +5,8 @@
     "Bandwith Limitation": "Bandwith Limitation",
     "vAPV Capacity": "vAPV Capacity",
     "Memory Control": "Memory Control",
+    "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!",
@@ -33,6 +35,8 @@
     "Serial Name": "Serial Name",
     "Bandwidth Mode": "Bandwidth Mode",
     "Assigned Bandwidth": "Assigned Bandwidth",
+    "Assigned CPU": "Assigned CPU",
+    "Assigned RAM": "Assigned RAM",
     "Applied Bandwidth": "Applied Bandwidth",
     "Real-time Bandwidth": "Real-time Bandwidth",
     "Edit Resource Mode": "Edit Resource Mode",
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 2992)
+++ /branches/amp_3_7_2/extensions/license_server/webui/client/locales/zh-cn.json	(working copy)
@@ -5,6 +5,8 @@
     "Bandwith Limitation": "带宽限制",
     "vAPV Capacity": "vAPV容量",
     "Memory Control": "内存控制",
+    "CPU Control": "CPU控制",
+    "Memory": "内存",
     "Max available bandwidth": "最大可用带宽",
     "Failed to delete the volume license!": "删除批量许可证失败！",
     "Failed to import the volume license key!": "无法导入批量许可证密钥！",
@@ -33,6 +35,8 @@
     "Serial Name": "序列名称",
     "Bandwidth Mode": "带宽模式",
     "Assigned Bandwidth": "分配的带宽",
+    "Assigned CPU": "分配的CPU",
+    "Assigned RAM": "分配的内存",
     "Applied Bandwidth": "应用的带宽",
     "Real-time Bandwidth": "实时带宽",
     "Edit Resource Mode": "编辑资源模式",
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 2992)
+++ /branches/amp_3_7_2/extensions/license_server/webui/model/cm_device/__init__.py	(working copy)
@@ -22,6 +22,8 @@
 
     product_name = CharField(verbose_name="Product Name", editable=False, configurable=False, optional=True)
     perbw = CharField(verbose_name="Assigned Bandwidth", editable=False, configurable=False, optional=True)
+    percpu = CharField(verbose_name="Assigned CPU", editable=False, configurable=False, optional=True)
+    permem = CharField(verbose_name="Assigned RAM", editable=False, configurable=False, optional=True)
     used_bw = CharField(verbose_name="Used Bandwidth", editable=False, configurable=False, optional=True)
     total_bw = CharField(verbose_name="Total Bandwidth", editable=False, configurable=False, optional=True)
     connection = CharField(verbose_name="Connection", editable=False, configurable=False, optional=True, custom_display=lambda val: '<span class="text-running"><i class="fa fa-check-circle"></i>&nbsp;</span>' if str(val) == 'connected' else '<span class="text-false"><i class="fa fa-times-circle"></i>&nbsp;</span>')
@@ -142,6 +144,8 @@
                 {'name':'status'},
                 {'name': 'auto_bw'},
                 {'name': 'perbw'},
+                {'name': 'percpu'},
+                {'name': 'permem'},
                 {'name': 'rel_bandwith'},
                 ]}
         help_text = _("Please make sure RESTful API service has been turned on 'https' on target devices and a RESTful API account has already been configured as well. If not, please refer to CLI handbook, using command 'restapi on https [port]' and 'user [user_name] [password] api' to configure them first." )
@@ -158,7 +162,7 @@
             data = db.fetchall(fetchall_sql)
             db.close()
             result = []
-            key = ['id', 'ip', 'restapi_port', 'restapi_username', 'restapi_password', 'connection', 'status', 'version', 'license_name', 'perbw', 'error_msg', 'rel_bandwith', 'bw_limit', 'auto_bw', 'restapi_protocol', 'used_bw', 'total_bw']
+            key = ['id', 'ip', 'restapi_port', 'restapi_username', 'restapi_password', 'connection', 'status', 'version', 'license_name', 'perbw', 'error_msg', 'rel_bandwith', 'bw_limit', 'auto_bw', 'restapi_protocol', 'permem', 'percpu', 'used_bw', 'total_bw']
             result = [dict(zip(key, each)) for each in data]
             # result = [
             #     {
@@ -180,6 +184,9 @@
             #     }
             # ]
             for each in result:
+                # Per-device CPU/RAM passed through from the volume license (0 = unassigned).
+                each['percpu'] = 'N/A' if each.get('percpu') in [None, 0] else str(each['percpu'])
+                each['permem'] = 'N/A' if each.get('permem') in [None, 0] else str(each['permem'])
                 if each['perbw'] in [-1, 0, 1]:
                     each['perbw'] = 'Restricted'
                     each['rel_bandwith'] = {'limitation': 'Restricted', 'current': 'Restricted', 'dropped': 'Restricted'}
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 2992)
+++ /branches/amp_3_7_2/extensions/license_server/webui/model/license/__init__.py	(working copy)
@@ -14,7 +14,8 @@
     license = CharField(verbose_name='License key')
     bwlimit = IntegerField(verbose_name="Max available bandwidth", configurable=False, optional=True, editable=True, unit_name=__('Mbps'))
     capacity = IntegerField(verbose_name="vAPV Capacity", configurable=False, optional=True, editable=True)
-    memory_control = CharField(verbose_name="vAPV Memory Type Number", configurable=False, optional=True, editable=True)
+    memory_control = CharField(verbose_name="vAPV Memory", configurable=False, optional=True, editable=True)
+    cpu = IntegerField(verbose_name="vAPV CPU Number", configurable=False, optional=True, editable=True)
     available_bw = IntegerField(verbose_name="Available bandwidth", configurable=False, optional=True, editable=True,
                                 unit_name=__('Mbps'))
     used_bw = IntegerField(verbose_name="Used bandwidth", configurable=False, optional=True, editable=True,
@@ -50,22 +51,28 @@
             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;'''
             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 + ['used_bw']
+            key = ['name', 'license', 'company_name', 'generation_date', 'expiration_date', 'bandwidth', 'bwlimit', 'capacity', 'memory_resource_control'] + memory_control_column + ['cpu', 'memory', 'used_bw']
             result = [dict(zip(key, each)) for each in data]
             for each in result:
                 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.
                 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]))
                     each["memory_control"] = (", ").join(m_c)
+                elif each.get("memory"):
+                    each["memory_control"] = str(each["memory"])
                 else:
                     each["memory_control"] = "N/A"
 
                 del each["memory_resource_control"]
+                del each["memory"]
                 for index in memory_control_column:
                     del each[index]
                 each['available_bw'] = (0 if each['bwlimit'] is None else each['bwlimit']) - (0 if each['used_bw'] is None else each['used_bw'])
@@ -102,6 +109,12 @@
             for each in license["data"]:
                 if each["license_name"] == data['name']:
                     license_data = each
+            # CPU and generic memory(RAM) are generic resource limits; they are only
+            # present in the decoded license when a number was encoded, so default to 0.
+            # (Generic "memory" is emitted only when memory_resource_control == 0;
+            #  the per-device-type res_memory_num_* path is handled separately above.)
+            cpu_val = int(license_data.get("cpu", 0))
+            memory_val = int(license_data.get("memory", 0))
             # insert the res_memory_num_xg into license too.
             if license_data["memory_resource_control"]:
                 memory_control_list = [str(license_data[each]) if each in license_data else "0" for each in memory_control_column]
@@ -115,7 +128,9 @@
                     bwlimit, \
                     capacity, \
                     memory_resource_control, \
-                    %s) values " % (", ").join(memory_control_column) + "('%s', '%s', '%s', '%s', '%s', %d, %d, %d, 1, %s)" % (\
+                    cpu, \
+                    memory, \
+                    %s) values " % (", ").join(memory_control_column) + "('%s', '%s', '%s', '%s', '%s', %d, %d, %d, 1, %d, %d, %s)" % (\
                         license_data["license_name"],
                         license_data["license"],
                         license_data["company_name"],
@@ -124,10 +139,12 @@
                         license_data["bandwidth"],
                         license_data["bandwidth"],
                         license_data["capacity"],
+                        cpu_val,
+                        memory_val,
                         (", ").join(memory_control_list)
                     )
             else:
-                save_sql = "INSERT INTO license(name, license, company_name, generation_date, expiration_date, bandwidth, bwlimit, capacity, memory_resource_control) values " + "('%(license_name)s', '%(license)s', '%(company_name)s', '%(generation_date)s', '%(expiration_date)s', '%(bandwidth)s', '%(bandwidth)s', '%(capacity)s', 0)" % license_data
+                save_sql = ("INSERT INTO license(name, license, company_name, generation_date, expiration_date, bandwidth, bwlimit, capacity, memory_resource_control, cpu, memory) values " + "('%(license_name)s', '%(license)s', '%(company_name)s', '%(generation_date)s', '%(expiration_date)s', '%(bandwidth)s', '%(bandwidth)s', '%(capacity)s', 0, " + str(cpu_val) + ", " + str(memory_val) + ")") % license_data
             db = DB.get_connected_db()
             db.execute_sql(save_sql)
             db.close()
