diff --git a/src/sunstone/models/SunstoneServer.rb b/src/sunstone/models/SunstoneServer.rb index 828382c147..509d053c86 100644 --- a/src/sunstone/models/SunstoneServer.rb +++ b/src/sunstone/models/SunstoneServer.rb @@ -265,7 +265,7 @@ class SunstoneServer # ############################################################################ - def get_log(resource,id,config,monitor_res,history_length) + def get_log(resource,id,config,monitor_resources,history_length) log_file_prefix = case resource when "vm","VM" config[:host_log_file] @@ -279,32 +279,46 @@ class SunstoneServer log_file = "#{log_file_prefix}_#{id}.csv" - first_line = `head -1 #{log_file}` + first_line = `head -1 #{log_file}`.chomp if $?.exitstatus != 0 - then error = Error.new("Cannot open log file") return [500, error.to_json] end - fields = first_line.split(',') - - poll_time_pos = fields.index("time") - resource_pos = fields.index(monitor_res) - id_pos = fields.index("id") - - graph = [] - tail = `tail -#{history_length} #{log_file}` - - tail.each_line do | line | - line_arr = line.delete('"').split(',') - if (line_arr[id_pos].to_i == id.to_i) - then - graph << [ line_arr[poll_time_pos].to_i*1000, line_arr[resource_pos].to_i ] - end + n_lines = `wc -l #{log_file} | cut -d' ' -f 1`.to_i + if n_lines <= history_length.to_i + history_length = n_lines-1 end - return graph.to_json + fields = first_line.split(',') + poll_time_pos = fields.index("time") + id_pos = fields.index("id") + + if !id_pos or !poll_time_pos + error = Error.new("It seems poll_time or id information cannot be read from log file") + return [500, error.to_json] + end + + series = [] #will hold several graphs + tail = `tail -#{history_length} #{log_file}` + + monitor_resources.split(',').each do | resource | + + graph = [] + resource_pos = fields.index(resource) + + tail.each_line do | line | + line_arr = line.delete('"').split(',') + if (line_arr[id_pos].to_i == id.to_i) + graph << [ line_arr[poll_time_pos].to_i*1000, line_arr[resource_pos].to_i ] + end + end + + series << graph + end + + return series.to_json end ############################################################################ diff --git a/src/sunstone/public/css/application.css b/src/sunstone/public/css/application.css index f318adfb7e..d068cbef4a 100644 --- a/src/sunstone/public/css/application.css +++ b/src/sunstone/public/css/application.css @@ -362,7 +362,7 @@ tr.even:hover{ vertical-align:top; } -.info_table th,h3 { +.info_table > thead th,h3 { border-bottom: 2px solid #353735; color: #353735; font-size: 14px; @@ -371,7 +371,7 @@ tr.even:hover{ } -.info_table td{ +.info_table > tbody > tr > td{ border-bottom: 1px solid #CCCCCC; color: #353735; padding-top: 6px; diff --git a/src/sunstone/public/js/plugins/hosts-tab.js b/src/sunstone/public/js/plugins/hosts-tab.js index c952f6f600..b29eb412e3 100644 --- a/src/sunstone/public/js/plugins/hosts-tab.js +++ b/src/sunstone/public/js/plugins/hosts-tab.js @@ -17,6 +17,22 @@ /*Host tab plugin*/ var HOST_HISTORY_LENGTH = 40; +var host_graphs = [ + { + title : "CPU Monitoring information", + monitor_resources : "cpu_usage,used_cpu,max_cpu", + humanize_figures : false, + history_length : HOST_HISTORY_LENGTH + }, + { + title: "Memory monitoring information", + monitor_resources : "mem_usage,used_mem,max_mem", + humanize_figures : true, + history_length : HOST_HISTORY_LENGTH + } +] + + var hosts_tab_content = '
\ @@ -205,14 +221,9 @@ var host_actions = { type: "monitor", call : OpenNebula.Host.monitor, callback: function(req,response) { - var info = req.request.data[0]; - var label = info.monitor.monitor_res; - - //remove spinner - $('#host_monitoring_tab .loading_img').parent().remove(); - + var info = req.request.data[0].monitor; plot_graph(response,'#host_monitoring_tab', - 'host_monitor_'+label,label); + 'host_monitor_',info); }, error: onError }, @@ -583,7 +594,7 @@ function updateHostInfo(request,host){ var monitor_tab = { title: "Monitoring information", - content : generateMonitoringDivs(["cpu_usage","mem_usage"],"host_monitor_") + content : generateMonitoringDivs(host_graphs,"host_monitor_") } //Sunstone.updateInfoPanelTab(info_panel_name,tab_name, new tab object); @@ -593,8 +604,9 @@ function updateHostInfo(request,host){ Sunstone.popUpInfoPanel("host_info_panel"); //pop up panel while we retrieve the graphs - Sunstone.runAction("Host.monitor",host_info.ID,{history_length: HOST_HISTORY_LENGTH, monitor_res: "cpu_usage"}); - Sunstone.runAction("Host.monitor",host_info.ID,{history_length: HOST_HISTORY_LENGTH, monitor_res: "mem_usage"}); + for (var i=0; i\
\ @@ -305,13 +331,7 @@ var vm_actions = { colored_log += line + "\n"; } - var log_tab = { - title: "VM log", - content: '
'+colored_log+'
' - } - Sunstone.updateInfoPanelTab("vm_info_panel","vm_log_tab",log_tab); - Sunstone.popUpInfoPanel("vm_info_panel",0); - + $('#vm_log_tab#').html('
'+colored_log+'
') }, error: function(request,error_json){ $("#vm_log pre").html(''); @@ -333,6 +353,17 @@ var vm_actions = { callback: null, error: onError, notify: true + }, + + "VM.monitor" : { + type: "monitor", + call : OpenNebula.VM.monitor, + callback: function(req,response) { + var info = req.request.data[0].monitor; + plot_graph(response,'#vm_monitoring_tab', + 'vm_monitor_',info); + }, + error: onError } } @@ -624,30 +655,36 @@ function updateVMInfo(request,vm){ \ ' } - + var template_tab = { title: "VM Template", content: '\ '+ prettyPrintJSON(vm_info.TEMPLATE)+ - '
VM template
' + '' } - + var log_tab = { title: "VM log", - content: '
'+spinner+'
' + content: '
'+spinner+'
' } - - Sunstone.updateInfoPanelTab("vm_info_panel","vm_info_tab",info_tab); + + var monitoring_tab = { + title: "Monitoring information", + content: generateMonitoringDivs(vm_graphs,"vm_monitor_") + } + + Sunstone.updateInfoPanelTab("vm_info_panel","vm_info_tab",info_tab); Sunstone.updateInfoPanelTab("vm_info_panel","vm_template_tab",template_tab); Sunstone.updateInfoPanelTab("vm_info_panel","vm_log_tab",log_tab); - - - //Here it is special, as we will let the callback from the VM.log - //action popUp the info panel again when the info is received. + Sunstone.updateInfoPanelTab("vm_info_panel","vm_monitoring_tab",monitoring_tab); + + //Pop up the info panel and asynchronously get vm_log and stats Sunstone.popUpInfoPanel("vm_info_panel"); Sunstone.runAction("VM.log",vm_info.ID); - + for (var i=0; i'; - var width = ($(window).width()-129)*40/100; - $.each(labels,function(){ - str+='
'; +function generateMonitoringDivs(graphs, id_prefix){ + var str = ""; + //40% of the width of the screen minus + //129px (left menu size) + var width = ($(window).width()-129)*45/100; + var id_suffix=""; + var label=""; + + $.each(graphs,function(){ + label = this.monitor_resources; + id_suffix=label.replace(/,/g,'_'); + id = id_prefix+id_suffix; + str+='\ +\ +\ +
'+this.title+'
\ +
'+spinner+'
\ +
'; }); return str; } -function plot_graph(data,context,id,label){ +function plot_graph(data,context,id_prefix,info){ + var labels = info.monitor_resources; + var humanize = info.humanize_figures ? humanize_size : function(val){return val}; + var labels_arr = labels.split(','); + var id_suffix = labels.replace(/,/g,'_'); + var series = []; + var serie = null; - var serie = { - label : label, - data : data + for (var i = 0; i< labels_arr.length; i++) { + serie = { + label: labels_arr[i], + data: data[i] + }; + series.push(serie); }; var options = { - legend : { show : true }, - xaxis : { mode: "time", timeformat: "%h:%M" }, - yaxis : { labelWidth: 30 } + legend : { show : true, + noColumns: labels_arr.length, + container: $('#legend_'+id_suffix) + }, + xaxis : { mode: "time", + timeformat: "%h:%M" + }, + yaxis : { labelWidth: 40, + tickFormatter: function(val, axis) { + return humanize(val); + } + } } - $.plot($('#'+id, context),[serie],options); + id = id_prefix + id_suffix; + $.plot($('#'+id, context),series,options); } //functions that used as true and false conditions for testing mainly diff --git a/src/sunstone/share/OneMonitor/HostMonitor.rb b/src/sunstone/share/OneMonitor/HostMonitor.rb index 42914d80c2..348dc63067 100644 --- a/src/sunstone/share/OneMonitor/HostMonitor.rb +++ b/src/sunstone/share/OneMonitor/HostMonitor.rb @@ -1,7 +1,7 @@ require 'OneMonitor' class HostMonitor < OneMonitor - #:time label is mandatory and must be first + #:time, :id labels HOST_MONITORING_ELEMS = { :time => "LAST_MON_TIME", :id => "ID", @@ -33,4 +33,12 @@ class HostMonitor < OneMonitor def snapshot super HostPool end + + def active (host_hash) + host_hash[:state].to_i < 3 + end + + def error (host_hash) + host_hash[:state].to_i == 3 + end end diff --git a/src/sunstone/share/OneMonitor/OneMonitor.rb b/src/sunstone/share/OneMonitor/OneMonitor.rb index d3f3068ed6..b7798dae15 100644 --- a/src/sunstone/share/OneMonitor/OneMonitor.rb +++ b/src/sunstone/share/OneMonitor/OneMonitor.rb @@ -35,7 +35,7 @@ class OneMonitor def snapshot(poolClass) #init global results - rc = monitor + rc = monitor #calling the extending class method rc = save if rc if rc @results = [] @@ -64,7 +64,11 @@ class OneMonitor end @results << hash add_to_global(hash) + @n_active += 1 if active(hash) + @n_error += 1 if error(hash) + @n_total += 1 end + end def reinit_global_results @@ -72,6 +76,7 @@ class OneMonitor @monitoring_elems.each do | key,value | @global_results[key] = 0 end + @n_active = @n_error = @n_total = 0 end def add_to_global(hash) diff --git a/src/sunstone/share/OneMonitor/OneMonitorUtils.rb b/src/sunstone/share/OneMonitor/OneMonitorUtils.rb index b9b2765874..270d58f217 100644 --- a/src/sunstone/share/OneMonitor/OneMonitorUtils.rb +++ b/src/sunstone/share/OneMonitor/OneMonitorUtils.rb @@ -39,11 +39,11 @@ module OneMonitorCSV if !File.size?(global_log_file) then - header = csv_header + header = csv_header+",active,error,total" global_file.puts(header) end - csv = hash_to_csv(@global_results) + csv = hash_to_csv(@global_results)+%&,"#{@n_active}","#{@n_error}","#{@n_total}"& global_file.puts(csv) global_file.close return 0 diff --git a/src/sunstone/share/OneMonitor/VMMonitor.rb b/src/sunstone/share/OneMonitor/VMMonitor.rb index f524b4a71a..1df49a7cf2 100644 --- a/src/sunstone/share/OneMonitor/VMMonitor.rb +++ b/src/sunstone/share/OneMonitor/VMMonitor.rb @@ -7,6 +7,7 @@ class VMMonitor < OneMonitor :id => "ID", :name => "NAME", :lcm_state => "LCM_STATE", + :state => "STATE", :memory => "MEMORY", :cpu => "CPU", :net_tx => "NET_TX", @@ -24,4 +25,12 @@ class VMMonitor < OneMonitor def snapshot super VirtualMachinePool end + + def active (vm_hash) + vm_hash[:state].to_i == 3 + end + + def error (vm_hash) + vm_hash[:state].to_i == 7 + end end diff --git a/src/sunstone/share/OneMonitor/runOneMontitor.rb b/src/sunstone/share/OneMonitor/runOneMontitor.rb index f5be39e321..03e146a08a 100755 --- a/src/sunstone/share/OneMonitor/runOneMontitor.rb +++ b/src/sunstone/share/OneMonitor/runOneMontitor.rb @@ -1,6 +1,6 @@ #!/usr/bin/env ruby -MONITOR_INTERVAL= ARGV[1]? ARGV[1].to_i : 60 #secs +MONITOR_INTERVAL= ARGV[1]? ARGV[1].to_i : 10 #secs $: << File.dirname(__FILE__) diff --git a/src/sunstone/sunstone-server.rb b/src/sunstone/sunstone-server.rb index 1c06d28a2e..a19a16c06e 100755 --- a/src/sunstone/sunstone-server.rb +++ b/src/sunstone/sunstone-server.rb @@ -166,7 +166,7 @@ get '/:resource/monitor' do end get '/:resource/:id/monitor' do - @SunstoneServer.get_log(params[:resource],params[:id],settings.config,params['monitor_res'],params['history_length']) + @SunstoneServer.get_log(params[:resource],params[:id],settings.config,params['monitor_resources'],params['history_length']) end