matthewalanpenning 1 yıl önce
ebeveyn
işleme
d25c685760

+ 3 - 1
CHANGELOG.md

@@ -3,7 +3,9 @@
  - Converted containers and virtual-machines endpoints to instances endpoint
  - Combined containers and virtual-machines pages to instances page
  - Datatable errors now display on console.log rather than the default alert
- - Handled 404 Error on new virtual machine without logs
+ - Handled 404 error for logs on a new virtual machine
+ - Fixed several undefined value errors that may occur
+ - Updated virtual-machine cpu and memory functions to no longer use sleep
 
 # 0.3.0
  - Improved Dockerfile for quicker builds

+ 16 - 8
lxconsole/api/access_controls.py

@@ -40,6 +40,8 @@ def privilege_check(privilege, server_id = 0):
       #'change_cluster_member_state',
       #'change_instance_state',
       #'copy_instance',
+      'copy_instance_proc_meminfo',
+      'copy_instance_proc_stat',
       #'create_instance_backup',
       #'create_instance_snapshot_instance',
       #'create_instance_snapshot',
@@ -82,13 +84,13 @@ def privilege_check(privilege, server_id = 0):
       'get_server_resources',
       'get_server_warnings',
       'get_server',
-      'get_instance_cpu_percentage',
       'get_instance_cpu_usage',
       'get_instance_disk_devices',
       'get_instance_gpu_devices',
       'get_instance_interfaces',
-      'get_instance_memory_percentage',
       'get_instance_network_devices',
+      'get_instance_proc_meminfo',
+      'get_instance_proc_stat',
       'get_instance_proxy_devices',
       'get_instance_state',
       'get_instance_unix_devices',
@@ -206,6 +208,8 @@ def privilege_check(privilege, server_id = 0):
       'change_cluster_member_state',
       'change_instance_state',
       'copy_instance',
+      'copy_instance_proc_meminfo',
+      'copy_instance_proc_stat',
       'create_instance_backup',
       'create_instance_snapshot_instance',
       'create_instance_snapshot',
@@ -248,13 +252,13 @@ def privilege_check(privilege, server_id = 0):
       'get_server_resources',
       'get_server_warnings',
       'get_server',
-      'get_instance_cpu_percentage',
       'get_instance_cpu_usage',
       'get_instance_disk_devices',
       'get_instance_gpu_devices',
       'get_instance_interfaces',
-      'get_instance_memory_percentage',
       'get_instance_network_devices',
+      'get_instance_proc_meminfo',
+      'get_instance_proc_stat',
       'get_instance_proxy_devices',
       'get_instance_state',
       'get_instance_unix_devices',
@@ -372,6 +376,8 @@ def privilege_check(privilege, server_id = 0):
       'change_cluster_member_state',
       'change_instance_state',
       'copy_instance',
+      'copy_instance_proc_meminfo',
+      'copy_instance_proc_stat',
       'create_instance_backup',
       'create_instance_snapshot_instance',
       'create_instance_snapshot',
@@ -414,13 +420,13 @@ def privilege_check(privilege, server_id = 0):
       'get_server_resources',
       'get_server_warnings',
       'get_server',
-      'get_instance_cpu_percentage',
       'get_instance_cpu_usage',
       'get_instance_disk_devices',
       'get_instance_gpu_devices',
       'get_instance_interfaces',
-      'get_instance_memory_percentage',
       'get_instance_network_devices',
+      'get_instance_proc_meminfo',
+      'get_instance_proc_stat',
       'get_instance_proxy_devices',
       'get_instance_state',
       'get_instance_unix_devices',
@@ -538,6 +544,8 @@ def privilege_check(privilege, server_id = 0):
       'change_cluster_member_state',
       'change_instance_state',
       'copy_instance',
+      'copy_instance_proc_meminfo',
+      'copy_instance_proc_stat',
       'create_instance_backup',
       'create_instance_snapshot_instance',
       'create_instance_snapshot',
@@ -580,13 +588,13 @@ def privilege_check(privilege, server_id = 0):
       'get_server_resources',
       'get_server_warnings',
       'get_server',
-      'get_instance_cpu_percentage',
       'get_instance_cpu_usage',
       'get_instance_disk_devices',
       'get_instance_gpu_devices',
       'get_instance_interfaces',
-      'get_instance_memory_percentage',
       'get_instance_network_devices',
+      'get_instance_proc_meminfo',
+      'get_instance_proc_stat',
       'get_instance_proxy_devices',
       'get_instance_state',
       'get_instance_unix_devices',

+ 46 - 84
lxconsole/api/instance.py

@@ -614,7 +614,7 @@ def api_instance_endpoint(endpoint):
     return jsonify(results.json())
   
   # Virtual Machine only
-  if endpoint == 'get_instance_cpu_percentage':
+  if endpoint == 'copy_instance_proc_stat':
     id = request.args.get('id')
     project = request.args.get('project')
     server = Server.query.filter_by(id=id).first()
@@ -622,15 +622,11 @@ def api_instance_endpoint(endpoint):
     client_cert = get_client_crt()
     client_key = get_client_key()
 
-    first_cpu_time = 0
-    first_idle_time = 0
-    second_cpu_time = 0
-    second_idle_time = 0
-
     # Unable to read /proc/stat directly on virtual machines use lxd files api...getting an EOF error
     # So we will copy /proc/stat to /tmp/stat and then read that file as a work around
     data = {}
-    data.update({'command': ['cp', '/proc/stat', '/tmp/stat1']})
+    #data.update({'command': ['/bin/sh', '-c', 'cat /proc/stat \u003e /tmp/stat' ]})
+    data.update({'command': ['cp', '/proc/stat', '/tmp/stat']})
     data.update({'wait-for-websocket': False})
     data.update({'interactive': False})
     data.update({'width': 80 })
@@ -643,12 +639,19 @@ def api_instance_endpoint(endpoint):
     
     url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + name + '/exec?project=' + project
     results = requests.post(url, verify=server.ssl_verify, cert=(client_cert, client_key), json=data)
-  
-    # Sleep to allow time for copy to complete
-    time.sleep(.5)
+    return jsonify(results.json())
+
+  # Virtual Machine only
+  if endpoint == 'get_instance_proc_stat':
+    id = request.args.get('id')
+    project = request.args.get('project')
+    server = Server.query.filter_by(id=id).first()
+    name = request.args.get('name')    
+    client_cert = get_client_crt()
+    client_key = get_client_key()
 
-    #Get first /proc/stat information but from /tmp/stat
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + name + '/files?project=' + project + '&path=/tmp/stat1'
+    #Get /proc/stat information but from /tmp/stat
+    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + name + '/files?project=' + project + '&path=/tmp/stat'
     results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
     if 'cpu' in results.text:
       results = results.text.split('\n')
@@ -658,15 +661,23 @@ def api_instance_endpoint(endpoint):
           user_time = int(stats[1])
           system_time= int(stats[3])
           idle_time = int(stats[4])
-          first_cpu_time = user_time + system_time + idle_time
-          first_idle_time = idle_time
+          return jsonify({'user_time':user_time, 'system_time':system_time, 'idle_time':idle_time})
+    return jsonify({'user_time':0, 'system_time':0, 'idle_time':1})
 
-    # Sleep a second between reads
-    time.sleep(1)
+  # Virtual Machine only
+  if endpoint == 'copy_instance_proc_meminfo':
+    id = request.args.get('id')
+    project = request.args.get('project')
+    server = Server.query.filter_by(id=id).first()
+    name = request.args.get('name')    
+    client_cert = get_client_crt()
+    client_key = get_client_key()
 
-    # Copy /proc/stat to /tmp/stat and then read that file as a work around
+    # Unable to read /proc/stat directly on virtual machines use lxd files api...getting an EOF error
+    # So we will copy /proc/stat to /tmp/stat and then read that file as a work around
     data = {}
-    data.update({'command': ['cp', '/proc/stat', '/tmp/stat2']})
+    #data.update({'command': ['/bin/sh', '-c', 'cat /proc/meminfo \u003e /tmp/meminfo' ]})
+    data.update({'command': ['cp', '/proc/meminfo', '/tmp/meminfo']})
     data.update({'wait-for-websocket': False})
     data.update({'interactive': False})
     data.update({'width': 80 })
@@ -679,35 +690,30 @@ def api_instance_endpoint(endpoint):
     
     url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + name + '/exec?project=' + project
     results = requests.post(url, verify=server.ssl_verify, cert=(client_cert, client_key), json=data)
+    return jsonify(results.json())
 
-    # Sleep to allow time for copy to complete
-    time.sleep(.5)
+  # Virtual Machine only
+  if endpoint == 'get_instance_proc_meminfo':
+    id = request.args.get('id')
+    project = request.args.get('project')
+    server = Server.query.filter_by(id=id).first()
+    name = request.args.get('name')    
+    client_cert = get_client_crt()
+    client_key = get_client_key()
 
-    #Get second /proc/stat information
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + name + '/files?project=' + project + '&path=/tmp/stat2'
+    #Get /proc/meminfo information but from /tmp/meminfo
+    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + name + '/files?project=' + project + '&path=/tmp/meminfo'
     results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
-    if 'cpu' in results.text:
+    if 'MemTotal' in results.text:
       results = results.text.split('\n')
-      for result in results:
-        stats = result.split()
-        if 'cpu' in stats:
-          user_time = int(stats[1])
-          system_time= int(stats[3])
-          idle_time = int(stats[4])
-          second_cpu_time = user_time + system_time + idle_time
-          second_idle_time = idle_time
-
-    #Get CPU percentage
-    idle_time = second_idle_time - first_idle_time
-    total_time = second_cpu_time - first_cpu_time
-    if total_time == 0:
-      return jsonify({'percentage': 0, 'cpu1': first_cpu_time, 'cpu2': second_cpu_time, 'idle1': first_idle_time, 'idle2': second_idle_time})
-    percentage = 100 * (1 - idle_time / total_time)
-    return jsonify({'percentage': percentage, 'cpu1': first_cpu_time, 'cpu2': second_cpu_time, 'idle1': first_idle_time, 'idle2': second_idle_time})
+      mem_total = results[0].split()
+      mem_available = results[2].split()
+      percentage = 100 * ( 1 - ( int(mem_available[1]) / int(mem_total[1]) ) )
+      return jsonify({'mem_total':int(mem_total[1]), 'mem_available':int(mem_available[1]), 'percentage':percentage})
+    return jsonify({'mem_total':0, 'mem_available':0, 'percentage':0})
 
 
   if endpoint == 'get_instance_cpu_usage':
-
     id = request.args.get('id')
     project = request.args.get('project')
     server = Server.query.filter_by(id=id).first()
@@ -875,50 +881,6 @@ def api_instance_endpoint(endpoint):
           interfaces.append(interface)
     return jsonify({ 'data': interfaces })
 
-  # Virtual Machine only
-  if endpoint == 'get_instance_memory_percentage':
-    id = request.args.get('id')
-    project = request.args.get('project')
-    server = Server.query.filter_by(id=id).first()
-    name = request.args.get('name')    
-    client_cert = get_client_crt()
-    client_key = get_client_key()
-
-    percentage = 0
-    mem_total = 0
-    mem_available = 0
-
-    # Unable to read /proc/meminfo directly on virtual machines use lxd files api...getting an EOF error
-    # So we will copy /proc/meminfo to /tmp/meminfo and then read that file as a work around
-    data = {}
-    data.update({'command': ['cp', '/proc/meminfo', '/tmp/meminfo']})
-    data.update({'wait-for-websocket': False})
-    data.update({'interactive': False})
-    data.update({'width': 80 })
-    data.update({'height': 24 })
-    data.update({'user': 0 })
-    data.update({'group': 0 })
-    data.update({'cwd': "/" })
-    data.update({'record-output': False })
-    data.update({'environment': {} })
-    
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + name + '/exec?project=' + project
-    results = requests.post(url, verify=server.ssl_verify, cert=(client_cert, client_key), json=data)
-  
-    # Sleep a second to give time to copy file
-    time.sleep(1)
-
-    #Get /proc/meminfo information but from /tmp/meminfo
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + name + '/files?project=' + project + '&path=/tmp/meminfo'
-    results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
-    if 'MemTotal' in results.text:
-      results = results.text.split('\n')
-      mem_total = results[0].split()
-      mem_available = results[2].split()
-      percentage = 100 * ( 1 - ( int(mem_available[1]) / int(mem_total[1]) ) )
-
-    return jsonify({'percentage': percentage, 'mem_total': mem_total, 'mem_available': mem_available})
-
 
   if endpoint == 'get_instance_network_devices':
     id = request.args.get('id')

+ 2 - 1
lxconsole/api/instances.py

@@ -193,7 +193,8 @@ def api_instances_endpoint(endpoint):
 
         # Set disk information if exists
         if 'disk' in instance['state'].keys():
-          if 'root' in instance['state']['disk'].keys():
+          # instance['state']['disk'] may exists but have have any .keys()
+          if instance['state']['disk'] and 'root' in instance['state']['disk'].keys():
             if 'usage' in instance['state']['disk']['root'].keys():
               disk = instance['state']['disk']['root']['usage']
               if disk:  

+ 73 - 18
lxconsole/templates/instance.html

@@ -713,6 +713,9 @@
       //Load Instance State Data and Configuration
       loadInstanceStateData()
 
+      sessionStorage.removeItem("instance_user_time");
+      sessionStorage.removeItem("instance_system_time");
+      sessionStorage.removeItem("instance_idle_time");
       loadCpuPercentage()
 
       //Load Home Tab Tables
@@ -762,6 +765,70 @@
 
     }
 
+    function getInstanceProcMeminfo() {
+      $.get("../api/instance/get_instance_proc_meminfo?id="+serverId+"&project="+project+"&name="+instance, function (data) {
+        if (data.mem_total > 0){
+          percentage = parseFloat(100 * ( 1 - parseInt(data.mem_available) / parseInt(data.mem_total))).toFixed(2)
+        }
+        else {
+          percentage = parseFloat(0).toFixed(2)
+        }
+
+        //Update Memory progress bar
+        $('#memPercentage').text(percentage)
+        $('#memPercentageBar').css('width', percentage + '%');
+        $('#memPercentageBar').attr('aria-valuenow', percentage + '%');
+        if (percentage > 90.00)
+          $('#memPercentageBar').attr('class', 'progress-bar bg-danger');
+        else
+          $('#memPercentageBar').attr('class', 'progress-bar bg-primary');
+      });
+    }
+    
+    function getInstanceProcStat() {
+      $.get("../api/instance/get_instance_proc_stat?id="+serverId+"&project="+project+"&name="+instance, function (data) {
+
+        session_user_time = sessionStorage.getItem('instance_user_time')
+        session_system_time = sessionStorage.getItem('instance_system_time')
+        session_idle_time = sessionStorage.getItem('instance_idle_time')
+
+        // If we have existing session values, find the difference else just use data values
+        if (session_user_time + session_system_time + session_idle_time > 0){
+          // If difference between data and session values is greater than zero then calculate
+          if (data.user_time - session_user_time + data.system_time - session_system_time + data.idle_time - session_idle_time > 0) {
+            percentage = parseFloat(100 * (1 - (data.idle_time - session_idle_time) / (data.user_time - session_user_time + data.system_time - session_system_time + data.idle_time - session_idle_time))).toFixed(2)
+          }
+          else {
+            percentage = parseFloat(0).toFixed(2)
+          }
+        }
+        else {
+          //If data values are greating than zero then calculate
+          if (data.user_time + data.system_time + data.idle_time > 0){
+            percentage = parseFloat(100 * ( 1 - data.idle_time / (data.user_time + data.system_time + data.idle_time))).toFixed(2)
+          }
+          else {
+            percentage = parseFloat(0).toFixed(2)
+          }
+        }
+
+        //Store stats for page reload
+        sessionStorage.setItem('instance_user_time', data.user_time)
+        sessionStorage.setItem('instance_system_time', data.system_time)
+        sessionStorage.setItem('instance_idle_time', data.idle_time)
+
+        //Update CPU progress bar
+        $('#cpuPercentage').text(percentage)
+        $('#cpuPercentageBar').css('width', percentage + '%');
+        $('#cpuPercentageBar').attr('aria-valuenow', percentage + '%');
+        if (percentage > 90.00)
+          $('#cpuPercentageBar').attr('class', 'progress-bar bg-danger');
+        else
+          $('#cpuPercentageBar').attr('class', 'progress-bar bg-primary');
+      });
+
+    }
+
     // Loads the CPU bar for container or virtual-machine
     function loadCpuPercentage() {
       if (instanceType == "container"){
@@ -829,15 +896,9 @@
         })
       }
       if (instanceType == "virtual-machine"){
-        $.get("../api/instance/get_instance_cpu_percentage?id="+serverId+"&project="+project+"&name="+instance, function (data) {
-          percentage = parseFloat(data.percentage).toFixed(2);
-          $('#cpuPercentage').text(percentage)
-          $('#cpuPercentageBar').css('width', percentage + '%');
-          $('#cpuPercentageBar').attr('aria-valuenow', percentage + '%');
-          if (percentage > 90.00)
-            $('#cpuPercentageBar').attr('class', 'progress-bar bg-danger');
-          else
-            $('#cpuPercentageBar').attr('class', 'progress-bar bg-primary');
+        $.get("../api/instance/copy_instance_proc_stat?id="+serverId+"&project="+project+"&name="+instance, function (data) {
+          // Get instance /proc/stat data
+          setTimeout(() => { getInstanceProcStat(); }, reloadTime / 2);
         });
       }
 
@@ -985,15 +1046,9 @@
           }
         }
         if (instanceType == 'virtual-machine') {
-          $.get("../api/instance/get_instance_memory_percentage?id="+serverId+"&project="+project+"&name="+instance, function (data) {
-            percentage = parseFloat(data.percentage).toFixed(2);
-            $('#memPercentage').text(percentage)
-            $('#memPercentageBar').css('width', percentage + '%');
-            $('#memPercentageBar').attr('aria-valuenow', percentage + '%');
-            if (percentage > 90.00)
-              $('#memPercentageBar').attr('class', 'progress-bar bg-danger');
-            else
-              $('#memPercentageBar').attr('class', 'progress-bar bg-primary');
+          $.get("../api/instance/copy_instance_proc_meminfo?id="+serverId+"&project="+project+"&name="+instance, function (data) {
+            //Get instance /proc/meminfo
+            setTimeout(() => { getInstanceProcMeminfo(); }, reloadTime / 2);
           });
         }
       });

+ 3 - 3
lxconsole/templates/main.html

@@ -163,13 +163,13 @@
                 // Many of the operations will indicate which resource the operation is being perfomed on
                 if (data.metadata.running[i].hasOwnProperty('resources') && data.metadata.running[i].resources != null) {
                   if (data.metadata.running[i].resources.hasOwnProperty('instances') && data.metadata.running[i].resources.instances != null) {
-                    notification += " " + data.metadata.running[i].resources.instances[i].replace("/1.0/instances/","")
+                    notification += " " + data.metadata.running[i].resources.instances[0].replace("/1.0/instances/","")
                   }
                   else if (data.metadata.running[i].resources.hasOwnProperty('containers') && data.metadata.running[i].resources.containers != null) {
-                    notification += " " + data.metadata.running[i].resources.containers[i].replace("/1.0/containers/","")
+                    notification += " " + data.metadata.running[i].resources.containers[0].replace("/1.0/containers/","")
                   }
                   else if (data.metadata.running[i].resources.hasOwnProperty('virtual-machines') && data.metadata.running[i].resources.virtual-machines != null) {
-                    notification += " " + data.metadata.running[i].resources.virtual-machines[i].replace("/1.0/virtual-machines/","")
+                    notification += " " + data.metadata.running[i].resources.virtual-machines[0].replace("/1.0/virtual-machines/","")
                   }
                 }
 

+ 1 - 1
lxconsole/templates/server.html

@@ -367,7 +367,7 @@
         $("#totalMemory").text(memory + ' ' + unit + ' MEMORY');
         $('#memoryPercentageProgressBar').css('width', memoryPercentage + '%');
         $('#memoryPercentageProgressBar').attr('aria-valuenow', memoryPercentage + '%');
-        if (memory > 90.00)
+        if (memoryPercentage > 90)
           $('#memoryPercentageProgressBar').attr('class', 'progress-bar bg-danger');
         else
           $('#memoryPercentageProgressBar').attr('class', 'progress-bar bg-primary');